Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 913c3cafe8 | |||
| 9ec2c8b6eb | |||
| 286030a08d | |||
| 46f0a5a8cf | |||
| ae59b7adf2 | |||
| 2b81e8e5aa | |||
| c9950d31ac | |||
| d6f657a46a |
1
.serena/.gitignore
vendored
1
.serena/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/cache
|
||||
@@ -1,68 +0,0 @@
|
||||
# language of the project (csharp, python, rust, java, typescript, go, cpp, or ruby)
|
||||
# * For C, use cpp
|
||||
# * For JavaScript, use typescript
|
||||
# Special requirements:
|
||||
# * csharp: Requires the presence of a .sln file in the project folder.
|
||||
language: typescript
|
||||
|
||||
# whether to use the project's gitignore file to ignore files
|
||||
# Added on 2025-04-07
|
||||
ignore_all_files_in_gitignore: true
|
||||
# list of additional paths to ignore
|
||||
# same syntax as gitignore, so you can use * and **
|
||||
# Was previously called `ignored_dirs`, please update your config if you are using that.
|
||||
# Added (renamed) on 2025-04-07
|
||||
ignored_paths: []
|
||||
|
||||
# whether the project is in read-only mode
|
||||
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
|
||||
# Added on 2025-04-18
|
||||
read_only: false
|
||||
|
||||
|
||||
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
|
||||
# Below is the complete list of tools for convenience.
|
||||
# To make sure you have the latest list of tools, and to view their descriptions,
|
||||
# execute `uv run scripts/print_tool_overview.py`.
|
||||
#
|
||||
# * `activate_project`: Activates a project by name.
|
||||
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
|
||||
# * `create_text_file`: Creates/overwrites a file in the project directory.
|
||||
# * `delete_lines`: Deletes a range of lines within a file.
|
||||
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
|
||||
# * `execute_shell_command`: Executes a shell command.
|
||||
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
|
||||
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
|
||||
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
|
||||
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
|
||||
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
|
||||
# * `initial_instructions`: Gets the initial instructions for the current project.
|
||||
# Should only be used in settings where the system prompt cannot be set,
|
||||
# e.g. in clients you have no control over, like Claude Desktop.
|
||||
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
|
||||
# * `insert_at_line`: Inserts content at a given line in a file.
|
||||
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
|
||||
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
|
||||
# * `list_memories`: Lists memories in Serena's project-specific memory store.
|
||||
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
|
||||
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
|
||||
# * `read_file`: Reads a file within the project directory.
|
||||
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
|
||||
# * `remove_project`: Removes a project from the Serena configuration.
|
||||
# * `replace_lines`: Replaces a range of lines within a file with new content.
|
||||
# * `replace_symbol_body`: Replaces the full definition of a symbol.
|
||||
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
|
||||
# * `search_for_pattern`: Performs a search for a pattern in the project.
|
||||
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
|
||||
# * `switch_modes`: Activates modes by providing a list of their names
|
||||
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
|
||||
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
|
||||
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
|
||||
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
|
||||
excluded_tools: []
|
||||
|
||||
# initial prompt for the project. It will always be given to the LLM upon activating the project
|
||||
# (contrary to the memories, which are loaded on demand).
|
||||
initial_prompt: ""
|
||||
|
||||
project_name: "tstest"
|
||||
33
changelog.md
33
changelog.md
@@ -1,5 +1,38 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-01-19 - 3.1.6 - fix(logging)
|
||||
handle mid-line streaming output in test logger and add streaming tests
|
||||
|
||||
- Introduce isOutputMidLine flag to track when streaming output does not end with a newline
|
||||
- Only prepend the visual prefix at the start of a line and append segments to the last buffered entry when mid-line
|
||||
- Write consistent output to log files for both complete lines and raw streaming segments
|
||||
- Add tests to exercise streaming behavior: test/tstest/test.gap-debug.ts and test/tstest/test.gap-debug2.ts
|
||||
|
||||
## 2026-01-19 - 3.1.5 - fix(tstest)
|
||||
preserve streaming console output and correctly buffer incomplete TAP lines
|
||||
|
||||
- Reworked TapParser._processLog to buffer incomplete lines and only parse complete TAP protocol lines
|
||||
- Added TapParser.lineBuffer and _looksLikeTapStart() to detect and buffer starts of TAP messages
|
||||
- Added TapParser._handleConsoleOutput() to centralize console output handling and snapshot parsing; flushes buffered content on process exit
|
||||
- Added TapTestResult.addLogLineRaw() to append streaming text without adding newlines
|
||||
- Added TsTestLogger.testConsoleOutputStreaming() and logToTestFileRaw() to preserve streaming output formatting in both console and logfile
|
||||
|
||||
## 2025-12-30 - 3.1.4 - fix(webhelpers)
|
||||
improve browser test fixture to append element and await custom element upgrade and Lit update completion; add generic return type; update npm packaging release config; remove pnpm onlyBuiltDependencies
|
||||
|
||||
- ts_tapbundle/webhelpers.ts: make fixture generic and return T; append created element to document; await customElements.whenDefined for custom elements and await updateComplete for Lit/async components to ensure stable rendering in tests
|
||||
- npmextra.json: add @git.zone/cli module metadata and release.registries/accessLevel; add @ship.zone/szci entry
|
||||
- pnpm-workspace.yaml: remove onlyBuiltDependencies entries
|
||||
|
||||
## 2025-11-21 - 3.1.3 - fix(docs)
|
||||
Update package author and expand license/legal and issue-reporting information in tapbundle docs
|
||||
|
||||
- Update package.json author field to Task Venture Capital GmbH
|
||||
- Add expanded License and Legal Information to ts_tapbundle/readme.md (clarifies MIT license scope and trademark guidance)
|
||||
- Add expanded License and Legal Information to ts_tapbundle_protocol/readme.md (clarifies MIT license scope and trademark guidance)
|
||||
- Add Issue Reporting and Security section to ts_tapbundle_protocol/readme.md pointing users to the community hub for bug/security reports
|
||||
- Include company information and trademark usage guidance in readmes
|
||||
|
||||
## 2025-11-21 - 3.1.2 - fix(docs)
|
||||
Update README: add issue reporting/security guidance and expanded changelog (3.1.1/3.1.0)
|
||||
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"target": "ES2022"
|
||||
},
|
||||
"nodeModulesDir": true,
|
||||
"version": "3.1.2"
|
||||
"version": "3.1.6"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{
|
||||
"npmci": {
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public"
|
||||
},
|
||||
"gitzone": {
|
||||
"@git.zone/cli": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "code.foss.global",
|
||||
@@ -12,6 +8,16 @@
|
||||
"description": "a test utility to run tests that match test/**/*.ts",
|
||||
"npmPackagename": "@git.zone/tstest",
|
||||
"license": "MIT"
|
||||
},
|
||||
"release": {
|
||||
"registries": [
|
||||
"https://verdaccio.lossless.digital",
|
||||
"https://registry.npmjs.org"
|
||||
],
|
||||
"accessLevel": "public"
|
||||
}
|
||||
},
|
||||
"@ship.zone/szci": {
|
||||
"npmGlobalTools": []
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@git.zone/tstest",
|
||||
"version": "3.1.2",
|
||||
"version": "3.1.6",
|
||||
"private": false,
|
||||
"description": "a test utility to run tests that match test/**/*.ts",
|
||||
"exports": {
|
||||
@@ -10,7 +10,7 @@
|
||||
"./tapbundle_protocol": "./dist_ts_tapbundle_protocol/index.js"
|
||||
},
|
||||
"type": "module",
|
||||
"author": "Lossless GmbH",
|
||||
"author": "Task Venture Capital GmbH",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"tstest": "./cli.js"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
onlyBuiltDependencies:
|
||||
- esbuild
|
||||
- mongodb-memory-server
|
||||
- puppeteer
|
||||
@@ -445,4 +445,49 @@ The protocol parser was fixed to correctly handle inline timing metadata:
|
||||
- Changed condition from `!simpleMatch[1].includes(':')` to check for simple key:value pairs
|
||||
- Excludes prefixed formats (META:, SKIP:, TODO:, EVENT:) while parsing simple formats like `time:250`
|
||||
|
||||
This ensures timing metadata is correctly extracted and displayed in test results.
|
||||
This ensures timing metadata is correctly extracted and displayed in test results.
|
||||
|
||||
## Streaming Console Output (Fixed)
|
||||
|
||||
### Problem
|
||||
When tests use `process.stdout.write()` for streaming output (without newlines), each write was appearing on a separate line. This happened because:
|
||||
1. Child process stdout data events arrive as separate chunks
|
||||
2. `TapParser._processLog()` split on `\n` and processed each segment
|
||||
3. `testConsoleOutput()` used `console.log()` which added a newline to each call
|
||||
|
||||
### Solution
|
||||
The streaming behavior is now preserved by:
|
||||
1. **Line buffering for TAP parsing**: Only buffer content that looks like TAP protocol messages
|
||||
2. **True streaming for console output**: Use `process.stdout.write()` instead of `console.log()` for partial lines
|
||||
3. **Intelligent detection**: `_looksLikeTapStart()` checks if content could be a TAP protocol message
|
||||
|
||||
### Implementation Details
|
||||
|
||||
**TapParser changes:**
|
||||
- Added `lineBuffer` property to buffer incomplete TAP protocol lines
|
||||
- Rewrote `_processLog()` to handle streaming correctly:
|
||||
- Complete lines (with newline) are processed through protocol parser
|
||||
- Incomplete lines that look like TAP are buffered
|
||||
- Incomplete lines that don't look like TAP are streamed immediately
|
||||
- Added `_looksLikeTapStart()` helper to detect TAP protocol patterns
|
||||
- Added `_handleConsoleOutput()` to handle console output with proper streaming
|
||||
- Buffer is flushed on process exit
|
||||
|
||||
**TsTestLogger changes:**
|
||||
- Added `testConsoleOutputStreaming()` method that uses `process.stdout.write()` in verbose mode
|
||||
- Added `logToTestFileRaw()` for writing to log files without adding newlines
|
||||
- In non-verbose mode, streaming content is appended to the last buffered entry
|
||||
|
||||
**TapTestResult changes:**
|
||||
- Added `addLogLineRaw()` method that doesn't append newlines
|
||||
|
||||
### Usage
|
||||
Tests can now use streaming output naturally:
|
||||
```typescript
|
||||
process.stdout.write("Loading");
|
||||
process.stdout.write(".");
|
||||
process.stdout.write(".");
|
||||
process.stdout.write(".\n");
|
||||
```
|
||||
|
||||
This will correctly display as `Loading...` on a single line in verbose mode.
|
||||
12
test/tstest/test.gap-debug.ts
Normal file
12
test/tstest/test.gap-debug.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { tap, expect } from '../../ts_tapbundle/index.js';
|
||||
|
||||
tap.test('check for gaps in streaming', async () => {
|
||||
// This should print "ABCD" with no gaps
|
||||
process.stdout.write("A");
|
||||
process.stdout.write("B");
|
||||
process.stdout.write("C");
|
||||
process.stdout.write("D\n");
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
14
test/tstest/test.gap-debug2.ts
Normal file
14
test/tstest/test.gap-debug2.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { tap, expect } from '../../ts_tapbundle/index.js';
|
||||
|
||||
tap.test('streaming with delays', async (tools) => {
|
||||
// Simulate real streaming with delays
|
||||
process.stdout.write("Progress: [");
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await tools.delayFor(50);
|
||||
process.stdout.write("=");
|
||||
}
|
||||
process.stdout.write("]\n");
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@git.zone/tstest',
|
||||
version: '3.1.2',
|
||||
version: '3.1.6',
|
||||
description: 'a test utility to run tests that match test/**/*.ts'
|
||||
}
|
||||
|
||||
@@ -18,11 +18,12 @@ export class TapParser {
|
||||
receivedTests: number = 0;
|
||||
|
||||
activeTapTestResult: TapTestResult;
|
||||
|
||||
|
||||
private logger: TsTestLogger;
|
||||
private protocolParser: ProtocolParser;
|
||||
private protocolVersion: string | null = null;
|
||||
private startTime: number;
|
||||
private lineBuffer: string = '';
|
||||
|
||||
/**
|
||||
* the constructor for TapParser
|
||||
@@ -71,42 +72,99 @@ export class TapParser {
|
||||
if (Buffer.isBuffer(logChunk)) {
|
||||
logChunk = logChunk.toString();
|
||||
}
|
||||
const logLineArray = logChunk.split('\n');
|
||||
if (logLineArray[logLineArray.length - 1] === '') {
|
||||
logLineArray.pop();
|
||||
|
||||
// Prepend any buffered content from previous incomplete line
|
||||
const fullChunk = this.lineBuffer + logChunk;
|
||||
this.lineBuffer = '';
|
||||
|
||||
// Split into segments by newline
|
||||
const segments = fullChunk.split('\n');
|
||||
const lastIndex = segments.length - 1;
|
||||
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
const segment = segments[i];
|
||||
const isLastSegment = (i === lastIndex);
|
||||
const hasNewline = !isLastSegment; // All segments except last had a newline after them
|
||||
|
||||
if (hasNewline) {
|
||||
// Complete line - check if it's a TAP protocol message
|
||||
const messages = this.protocolParser.parseLine(segment);
|
||||
|
||||
if (messages.length > 0) {
|
||||
// Handle protocol messages
|
||||
for (const message of messages) {
|
||||
this._handleProtocolMessage(message, segment);
|
||||
}
|
||||
} else {
|
||||
// Non-protocol complete line - handle as console output
|
||||
this._handleConsoleOutput(segment, true);
|
||||
}
|
||||
} else if (segment) {
|
||||
// Last segment without newline - could be:
|
||||
// 1. Partial console output (stream immediately)
|
||||
// 2. Start of a TAP message (need to buffer for protocol parsing)
|
||||
|
||||
// Check if it looks like the start of a TAP protocol message
|
||||
if (this._looksLikeTapStart(segment)) {
|
||||
// Buffer it for complete line parsing
|
||||
this.lineBuffer = segment;
|
||||
} else {
|
||||
// Stream immediately as console output (no newline)
|
||||
this._handleConsoleOutput(segment, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if text could be the start of a TAP protocol message
|
||||
*/
|
||||
private _looksLikeTapStart(text: string): boolean {
|
||||
return (
|
||||
text.startsWith('ok ') ||
|
||||
text.startsWith('not ok ') ||
|
||||
text.startsWith('1..') ||
|
||||
text.startsWith('# ') ||
|
||||
text.startsWith('TAP version ') ||
|
||||
text.startsWith('⟦TSTEST:') ||
|
||||
text.startsWith('Bail out!')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle console output from test, preserving streaming behavior
|
||||
*/
|
||||
private _handleConsoleOutput(text: string, hasNewline: boolean) {
|
||||
// Check for snapshot communication (legacy)
|
||||
const snapshotMatch = text.match(/###SNAPSHOT###(.+)###SNAPSHOT###/);
|
||||
if (snapshotMatch) {
|
||||
const base64Data = snapshotMatch[1];
|
||||
try {
|
||||
const snapshotData = JSON.parse(Buffer.from(base64Data, 'base64').toString());
|
||||
this.handleSnapshot(snapshotData);
|
||||
} catch (error: any) {
|
||||
if (this.logger) {
|
||||
this.logger.testConsoleOutput(`Error parsing snapshot data: ${error.message}`);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Process each line through the protocol parser
|
||||
for (const logLine of logLineArray) {
|
||||
const messages = this.protocolParser.parseLine(logLine);
|
||||
|
||||
if (messages.length > 0) {
|
||||
// Handle protocol messages
|
||||
for (const message of messages) {
|
||||
this._handleProtocolMessage(message, logLine);
|
||||
}
|
||||
// Add to test result buffer
|
||||
if (this.activeTapTestResult) {
|
||||
if (hasNewline) {
|
||||
this.activeTapTestResult.addLogLine(text);
|
||||
} else {
|
||||
// Not a protocol message, handle as console output
|
||||
if (this.activeTapTestResult) {
|
||||
this.activeTapTestResult.addLogLine(logLine);
|
||||
}
|
||||
|
||||
// Check for snapshot communication (legacy)
|
||||
const snapshotMatch = logLine.match(/###SNAPSHOT###(.+)###SNAPSHOT###/);
|
||||
if (snapshotMatch) {
|
||||
const base64Data = snapshotMatch[1];
|
||||
try {
|
||||
const snapshotData = JSON.parse(Buffer.from(base64Data, 'base64').toString());
|
||||
this.handleSnapshot(snapshotData);
|
||||
} catch (error: any) {
|
||||
if (this.logger) {
|
||||
this.logger.testConsoleOutput(`Error parsing snapshot data: ${error.message}`);
|
||||
}
|
||||
}
|
||||
} else if (this.logger) {
|
||||
// This is console output from the test file
|
||||
this.logger.testConsoleOutput(logLine);
|
||||
}
|
||||
this.activeTapTestResult.addLogLineRaw(text);
|
||||
}
|
||||
}
|
||||
|
||||
// Output to logger with streaming support
|
||||
if (this.logger) {
|
||||
if (hasNewline) {
|
||||
this.logger.testConsoleOutput(text);
|
||||
} else {
|
||||
this.logger.testConsoleOutputStreaming(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -417,6 +475,11 @@ export class TapParser {
|
||||
this._processLog(data);
|
||||
});
|
||||
childProcessArg.on('exit', async () => {
|
||||
// Flush any remaining buffered content
|
||||
if (this.lineBuffer) {
|
||||
this._handleConsoleOutput(this.lineBuffer, false);
|
||||
this.lineBuffer = '';
|
||||
}
|
||||
await this.evaluateFinalResult();
|
||||
done.resolve();
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ export class TapTestResult {
|
||||
constructor(public id: number) {}
|
||||
|
||||
/**
|
||||
* adds a logLine to the log buffer of the test
|
||||
* adds a logLine to the log buffer of the test (with newline appended)
|
||||
* @param logLine
|
||||
*/
|
||||
addLogLine(logLine: string) {
|
||||
@@ -19,6 +19,15 @@ export class TapTestResult {
|
||||
this.testLogBuffer = Buffer.concat([this.testLogBuffer, logLineBuffer]);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds raw text to the log buffer without appending newline (for streaming output)
|
||||
* @param text
|
||||
*/
|
||||
addLogLineRaw(text: string) {
|
||||
const logLineBuffer = Buffer.from(text);
|
||||
this.testLogBuffer = Buffer.concat([this.testLogBuffer, logLineBuffer]);
|
||||
}
|
||||
|
||||
setTestResult(testOkArg: boolean) {
|
||||
this.testOk = testOkArg;
|
||||
this.testSettled = true;
|
||||
|
||||
@@ -44,6 +44,7 @@ export class TsTestLogger {
|
||||
private currentTestLogFile: string | null = null;
|
||||
private currentTestLogs: string[] = []; // Buffer for current test logs
|
||||
private currentTestFailed: boolean = false;
|
||||
private isOutputMidLine: boolean = false; // Track whether we're mid-line for streaming output
|
||||
|
||||
constructor(options: LogOptions = {}) {
|
||||
this.options = options;
|
||||
@@ -189,6 +190,7 @@ export class TsTestLogger {
|
||||
// Reset test-specific state
|
||||
this.currentTestLogs = [];
|
||||
this.currentTestFailed = false;
|
||||
this.isOutputMidLine = false;
|
||||
|
||||
// Only set up test log file if --logfile option is specified
|
||||
if (this.options.logFile) {
|
||||
@@ -348,21 +350,73 @@ export class TsTestLogger {
|
||||
}
|
||||
}
|
||||
|
||||
// Console output from test files (non-TAP output)
|
||||
// Console output from test files (non-TAP output) - complete lines
|
||||
testConsoleOutput(message: string) {
|
||||
if (this.options.json) return;
|
||||
|
||||
|
||||
const prefix = ' ';
|
||||
// In verbose mode, show console output immediately
|
||||
if (this.options.verbose) {
|
||||
this.log(this.format(` ${message}`, 'dim'));
|
||||
// Only add prefix if we're starting a new line
|
||||
const output = this.isOutputMidLine ? message : prefix + message;
|
||||
this.log(this.format(output, 'dim'));
|
||||
} else {
|
||||
// In non-verbose mode, buffer the logs
|
||||
this.currentTestLogs.push(message);
|
||||
if (this.isOutputMidLine && this.currentTestLogs.length > 0) {
|
||||
// Append to the last buffered entry since we're mid-line
|
||||
this.currentTestLogs[this.currentTestLogs.length - 1] += message;
|
||||
} else {
|
||||
this.currentTestLogs.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reset mid-line state since we just output a complete line
|
||||
this.isOutputMidLine = false;
|
||||
|
||||
// Always log to test file if --logfile is specified
|
||||
if (this.currentTestLogFile) {
|
||||
this.logToTestFile(` ${message}`);
|
||||
this.logToTestFile(`${prefix}${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Streaming console output (preserves original formatting, no newline added)
|
||||
testConsoleOutputStreaming(message: string) {
|
||||
if (this.options.json) return;
|
||||
|
||||
const prefix = ' ';
|
||||
// Only add prefix if we're starting a new line (not mid-line)
|
||||
const output = this.isOutputMidLine ? message : prefix + message;
|
||||
|
||||
if (this.options.verbose) {
|
||||
// Use process.stdout.write to preserve streaming without adding newlines
|
||||
process.stdout.write(this.format(output, 'dim'));
|
||||
} else {
|
||||
// Buffer mode: append to last entry if mid-line
|
||||
if (this.isOutputMidLine && this.currentTestLogs.length > 0) {
|
||||
this.currentTestLogs[this.currentTestLogs.length - 1] += message;
|
||||
} else {
|
||||
this.currentTestLogs.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
// Log to test file without adding newline
|
||||
if (this.currentTestLogFile) {
|
||||
this.logToTestFileRaw(output);
|
||||
}
|
||||
|
||||
// We're now mid-line (no newline was written)
|
||||
this.isOutputMidLine = true;
|
||||
}
|
||||
|
||||
private logToTestFileRaw(message: string) {
|
||||
try {
|
||||
// Remove ANSI color codes for file logging
|
||||
const cleanMessage = message.replace(/\u001b\[[0-9;]*m/g, '');
|
||||
|
||||
// Append to test log file without adding newline
|
||||
fs.appendFileSync(this.currentTestLogFile, cleanMessage);
|
||||
} catch (error) {
|
||||
// Silently fail to avoid disrupting the test run
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ pnpm install --save-dev @git.zone/tstest
|
||||
|
||||
## Issue Reporting and Security
|
||||
|
||||
For reporting bugs, issues, or security vulnerabilities, please visit https://community.foss.global/. This is the central community hub for all issue reporting. Developers who want to sign a contribution agreement and go through identification can also get a code.foss.global account to submit Pull Requests directly.
|
||||
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who want to sign a contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -613,8 +613,21 @@ tap.test('should use context', async (tapTools) => {
|
||||
});
|
||||
```
|
||||
|
||||
## Legal
|
||||
## License and Legal Information
|
||||
|
||||
This project is licensed under MIT.
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](../license) file within this repository.
|
||||
|
||||
© 2025 Task Venture Capital GmbH. All rights reserved.
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
||||
@@ -22,10 +22,24 @@ class WebHelpers {
|
||||
|
||||
// Initialize fixture function based on environment
|
||||
if (smartenv.isBrowser) {
|
||||
this.fixture = async (htmlString: string): Promise<HTMLElement> => {
|
||||
this.fixture = async <T extends HTMLElement>(htmlString: string): Promise<T> => {
|
||||
const container = document.createElement('div');
|
||||
container.innerHTML = htmlString.trim();
|
||||
const element = container.firstChild as HTMLElement;
|
||||
const element = container.firstElementChild as T;
|
||||
|
||||
// Append to document so custom elements upgrade and lifecycle hooks fire
|
||||
document.body.appendChild(element);
|
||||
|
||||
// Wait for custom element definition if it's a custom element
|
||||
if (element.localName.includes('-')) {
|
||||
await customElements.whenDefined(element.localName).catch(() => {});
|
||||
}
|
||||
|
||||
// Wait for Lit/async components to finish rendering
|
||||
if ((element as any).updateComplete) {
|
||||
await (element as any).updateComplete;
|
||||
}
|
||||
|
||||
return element;
|
||||
};
|
||||
} else {
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
pnpm install --save-dev @git.zone/tstest
|
||||
```
|
||||
|
||||
## Issue Reporting and Security
|
||||
|
||||
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who want to sign a contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
||||
|
||||
## Overview
|
||||
|
||||
`@git.zone/tstest/tapbundle_protocol` implements Protocol V2, an enhanced version of the Test Anything Protocol (TAP) with support for structured metadata, real-time events, error diffs, and isomorphic operation. This protocol enables rich communication between test runners and test consumers while maintaining backward compatibility with standard TAP parsers.
|
||||
@@ -580,8 +584,21 @@ This module works in all JavaScript environments:
|
||||
|
||||
No runtime-specific APIs are used, making it truly portable.
|
||||
|
||||
## Legal
|
||||
## License and Legal Information
|
||||
|
||||
This project is licensed under MIT.
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](../license) file within this repository.
|
||||
|
||||
© 2025 Task Venture Capital GmbH. All rights reserved.
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
||||
Reference in New Issue
Block a user