Skip to content

Commit 9d1fdfa

Browse files
committed
decent place, some things still broken
1 parent 77d8f8a commit 9d1fdfa

File tree

2 files changed

+97
-31
lines changed

2 files changed

+97
-31
lines changed

interfaces/vitest-plugin.mjs

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,11 @@ function registerExitHandlers() {
321321
/**
322322
* TestDriver Vitest Plugin
323323
*
324-
* Use this in the `plugins` array to inject console log forwarding.
325-
* For the reporter functionality, use `testDriverReporter` in the `reporters` array.
324+
* This function works in both contexts:
325+
* - As a Vite plugin (in `plugins` array) - injects console log forwarding
326+
* - As a Vitest reporter (in `reporters` array) - handles test lifecycle tracking
327+
*
328+
* The function detects which context it's being used in and returns the appropriate object.
326329
*/
327330
export default function testDriverPlugin(options = {}) {
328331
// Initialize plugin state with options
@@ -345,34 +348,38 @@ export default function testDriverPlugin(options = {}) {
345348
logger.debug("Global TestDriver options:", testDriverOptions);
346349
}
347350

348-
// Return a Vite plugin object that injects console log forwarding
349-
return {
350-
name: 'testdriver-plugin',
351-
352-
// Inject onConsoleLog into Vitest config to forward logs to sandbox
353-
config() {
354-
return {
355-
test: {
356-
onConsoleLog(log, type) {
357-
// Forward to active sandbox if available
358-
const sandbox = globalThis.__testdriverActiveSandbox;
359-
if (sandbox?.instanceSocketConnected) {
360-
try {
361-
sandbox.send({
362-
type: "output",
363-
output: Buffer.from(log, "utf8").toString("base64"),
364-
});
365-
} catch {
366-
// Ignore errors when forwarding logs
367-
}
351+
// Return an object that works as BOTH a Vite plugin AND a Vitest reporter
352+
// Vite plugins need: name, config(), etc.
353+
// Vitest reporters need: onInit(), onTestCaseResult(), etc.
354+
// We return the TestDriverReporter class which has both!
355+
const reporter = new TestDriverReporter(options);
356+
357+
// Add Vite plugin properties to the reporter instance
358+
reporter.name = 'testdriver-plugin';
359+
reporter.config = function() {
360+
return {
361+
test: {
362+
onConsoleLog(log, type) {
363+
// Forward to active sandbox if available
364+
const sandbox = globalThis.__testdriverActiveSandbox;
365+
if (sandbox?.instanceSocketConnected) {
366+
try {
367+
sandbox.send({
368+
type: "output",
369+
output: Buffer.from(log, "utf8").toString("base64"),
370+
});
371+
} catch {
372+
// Ignore errors when forwarding logs
368373
}
369-
// Return true to still print the log
370-
return true;
371-
},
374+
}
375+
// Return true to still print the log
376+
return true;
372377
},
373-
};
374-
},
378+
},
379+
};
375380
};
381+
382+
return reporter;
376383
}
377384

378385
/**
@@ -463,6 +470,23 @@ class TestDriverReporter {
463470
process.env.TD_TEST_RUN_DB_ID = pluginState.testRun.data?.id || "";
464471
process.env.TD_TEST_RUN_TOKEN = pluginState.token;
465472

473+
// Write test run info to file for cross-process communication
474+
// Worker processes can read this to get the test run ID
475+
const resultsDir = path.join(os.tmpdir(), "testdriver-results");
476+
if (!fs.existsSync(resultsDir)) {
477+
fs.mkdirSync(resultsDir, { recursive: true });
478+
}
479+
const testRunInfoFile = path.join(resultsDir, "test-run-info.json");
480+
fs.writeFileSync(testRunInfoFile, JSON.stringify({
481+
testRunId: pluginState.testRunId,
482+
testRunDbId: pluginState.testRun.data?.id || null,
483+
token: pluginState.token,
484+
apiKey: pluginState.apiKey,
485+
apiRoot: pluginState.apiRoot,
486+
startTime: pluginState.startTime,
487+
}, null, 2));
488+
logger.debug(`Wrote test run info to ${testRunInfoFile}`);
489+
466490
// Also store in shared state module (won't work across processes but good for main)
467491
setTestRunInfo({
468492
testRun: pluginState.testRun,

src/vitest/hooks.mjs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,38 @@ const fileInstances = new Map(); // filePath -> testdriver instance
6161
// Track test IDs for file-level instances
6262
const fileTestIds = new Map(); // filePath -> Set of { testId, testFile }
6363

64-
// Track test run ID for this session
64+
// Track test run ID for this session (read from plugin's shared file)
6565
let currentTestRunId = null;
6666

67+
/**
68+
* Get the test run ID from the plugin's shared file
69+
* Will retry a few times if file doesn't exist yet (timing issue with worker startup)
70+
* @returns {Promise<string|null>} The test run ID or null if not found
71+
*/
72+
async function getTestRunIdFromFile() {
73+
const testRunInfoFile = path.join(os.tmpdir(), 'testdriver-results', 'test-run-info.json');
74+
75+
// Try up to 10 times with 100ms delay (1 second total)
76+
for (let i = 0; i < 10; i++) {
77+
try {
78+
if (fs.existsSync(testRunInfoFile)) {
79+
const info = JSON.parse(fs.readFileSync(testRunInfoFile, 'utf-8'));
80+
if (info.testRunId) {
81+
return info.testRunId;
82+
}
83+
}
84+
} catch (error) {
85+
// File may be being written, retry
86+
}
87+
88+
// Wait 100ms before retry
89+
await new Promise(resolve => setTimeout(resolve, 100));
90+
}
91+
92+
console.warn('[testdriver] Test run info file not found after retries');
93+
return null;
94+
}
95+
6796
/**
6897
* Record test case start to the API
6998
* @param {TestDriver} testdriver - TestDriver instance
@@ -77,9 +106,15 @@ async function recordTestCaseStart(testdriver, context, startTime) {
77106
await testdriver.__connectionPromise;
78107
}
79108

80-
// Get or create test run ID
109+
// Get test run ID from plugin's shared file (not generated locally)
110+
if (!currentTestRunId) {
111+
currentTestRunId = await getTestRunIdFromFile();
112+
}
113+
114+
// If still no test run ID, skip recording (plugin may not be configured)
81115
if (!currentTestRunId) {
82-
currentTestRunId = `vitest-${Date.now()}-${Math.random().toString(36).substring(7)}`;
116+
console.log(`[testdriver] Skipping test case recording - no test run ID found`);
117+
return;
83118
}
84119

85120
const task = context.task;
@@ -119,8 +154,15 @@ async function recordTestCaseEnd(testdriver, context, startTime, status, error =
119154
await testdriver.__connectionPromise;
120155
}
121156

157+
// Get test run ID from plugin's shared file (not generated locally)
158+
if (!currentTestRunId) {
159+
currentTestRunId = await getTestRunIdFromFile();
160+
}
161+
162+
// If still no test run ID, skip recording (plugin may not be configured)
122163
if (!currentTestRunId) {
123-
currentTestRunId = `vitest-${Date.now()}-${Math.random().toString(36).substring(7)}`;
164+
console.log(`[testdriver] Skipping test case recording - no test run ID found`);
165+
return;
124166
}
125167

126168
const task = context.task;

0 commit comments

Comments
 (0)