-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expose internal events for custom reporters via config #3247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
041a41c
84dba1d
f174798
74eee67
4d55422
9296944
7b0c55b
78f9d37
18f0cd3
b7c8053
1d4de13
e15de69
f10831b
fdca2ed
a9eac47
96e6ca5
ecef15a
11d9049
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = {}; | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./internal" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./internal" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import type {StateChangeEvent} from '../types/state-change-events.d.cts'; | ||
|
||
export type RunEvent = { | ||
type: 'stateChange'; | ||
stateChange: StateChangeEvent; | ||
} | { | ||
type: 'run'; | ||
plan: { | ||
bailWithoutReporting: boolean; | ||
debug: boolean; | ||
failFastEnabled: boolean; | ||
filePathPrefix: string; | ||
files: string[]; | ||
matching: boolean; | ||
previousFailures: number; | ||
runOnlyExclusive: boolean; | ||
firstRun: boolean; | ||
}; | ||
codetheweb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
export type {StateChangeEvent} from '../types/state-change-events.d.cts'; | ||
|
||
export type Run = { | ||
codetheweb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
events: AsyncIterableIterator<RunEvent>; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export {}; | ||
codetheweb marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// For compatibility with resolution algorithms other than Node16. | ||
|
||
export * from './entrypoints/internal.cjs'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import {on} from 'node:events'; | ||
|
||
export async function * asyncEventIteratorFromApi(api) { | ||
for await (const [plan] of on(api, 'run')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there a scenario where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, just in watch mode. May be helpful for the callback function to know that watch mode is active though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 might be good to add as a future enhancement |
||
yield { | ||
type: 'run', | ||
plan, | ||
}; | ||
|
||
for await (const [stateChange] of on(plan.status, 'stateChange')) { | ||
codetheweb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
yield { | ||
type: 'stateChange', | ||
stateChange, | ||
}; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
internal-events.json |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import fs from 'node:fs/promises'; | ||
|
||
const internalEvents = []; | ||
|
||
export default { | ||
files: [ | ||
'test.js', | ||
], | ||
nonSemVerExperiments: { | ||
observeRunsFromConfig: true, | ||
}, | ||
async observeRun(run) { | ||
for await (const event of run.events) { | ||
internalEvents.push(event); | ||
|
||
if (event.type === 'stateChange' && event.stateChange.type === 'end') { | ||
await fs.writeFile('internal-events.json', JSON.stringify(internalEvents)); | ||
} | ||
} | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"type": "module" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import test from 'ava'; | ||
|
||
test('placeholder', t => { | ||
t.pass(); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import fs from 'node:fs/promises'; | ||
import {fileURLToPath} from 'node:url'; | ||
|
||
import test from '@ava/test'; | ||
|
||
import {fixture} from '../helpers/exec.js'; | ||
|
||
test('internal events are emitted', async t => { | ||
await fixture(); | ||
|
||
const result = JSON.parse(await fs.readFile(fileURLToPath(new URL('fixtures/internal-events.json', import.meta.url)))); | ||
|
||
t.like(result[0], { | ||
type: 'run', | ||
plan: { | ||
files: [ | ||
fileURLToPath(new URL('fixtures/test.js', import.meta.url)), | ||
], | ||
}, | ||
}); | ||
|
||
const testPassedEvent = result.find(event => event.type === 'stateChange' && event.stateChange.type === 'test-passed'); | ||
t.like(testPassedEvent, { | ||
type: 'stateChange', | ||
stateChange: { | ||
type: 'test-passed', | ||
title: 'placeholder', | ||
testFile: fileURLToPath(new URL('fixtures/test.js', import.meta.url)), | ||
}, | ||
}); | ||
|
||
t.like(result[result.length - 1], { | ||
type: 'stateChange', | ||
stateChange: { | ||
type: 'end', | ||
}, | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
type ErrorSource = { | ||
isDependency: boolean | ||
isWithinProject: boolean | ||
file: string | ||
line: number | ||
} | ||
|
||
type SerializedErrorBase = { | ||
message: string | ||
name: string, | ||
originalError: unknown, | ||
stack: string | ||
} | ||
|
||
type AggregateSerializedError = SerializedErrorBase & { | ||
type: "aggregate" | ||
errors: SerializedError[] | ||
} | ||
|
||
type NativeSerializedError = SerializedErrorBase & { | ||
type: "native" | ||
source: ErrorSource | null | ||
} | ||
|
||
type AVASerializedError = SerializedErrorBase & { | ||
type: "ava" | ||
assertion: string | ||
improperUsage: unknown | null | ||
formattedCause: unknown | null | ||
formattedDetails: unknown | unknown[] | ||
source: ErrorSource | null | ||
} | ||
|
||
type SerializedError = AggregateSerializedError | NativeSerializedError | AVASerializedError | ||
|
||
export type StateChangeEvent = { | ||
type: "starting", | ||
testFile: string | ||
} | { | ||
type: "stats", | ||
stats: { | ||
byFile: Map<string, { | ||
declaredTests: number | ||
failedHooks: number, | ||
failedTests: number, | ||
internalErrors: number | ||
remainingTests: number, | ||
passedKnownFailingTests: number, | ||
passedTests: number, | ||
selectedTests: number, | ||
selectingLines: boolean, | ||
skippedTests: number, | ||
todoTests: number, | ||
uncaughtExceptions: number, | ||
unhandledRejections: number, | ||
}> | ||
declaredTests: number | ||
failedHooks: number, | ||
failedTests: number, | ||
failedWorkers: number, | ||
files: number, | ||
parallelRuns: { | ||
currentIndex: number, | ||
totalRuns: number | ||
} | null | ||
finishedWorkers: number, | ||
internalErrors: number | ||
remainingTests: number, | ||
passedKnownFailingTests: number, | ||
passedTests: number, | ||
selectedTests: number, | ||
sharedWorkerErrors: number, | ||
skippedTests: number, | ||
timedOutTests: number, | ||
timeouts: number, | ||
todoTests: number, | ||
uncaughtExceptions: number, | ||
unhandledRejections: number, | ||
} | ||
} | { | ||
type: "declared-test" | ||
title: string | ||
knownFailing: boolean | ||
todo: boolean | ||
testFile: string | ||
} | { | ||
type: "selected-test" | ||
title: string | ||
knownFailing: boolean | ||
skip: boolean | ||
todo: boolean | ||
testFile: string | ||
} | { | ||
type: "test-register-log-reference" | ||
title: string | ||
logs: string[] | ||
testFile: string | ||
} | { | ||
type: "test-passed", | ||
title: string | ||
duration: number | ||
knownFailing: boolean | ||
logs: string[] | ||
testFile: string | ||
} | { | ||
type: "test-failed", | ||
title: string | ||
err: SerializedError, | ||
duration: number | ||
knownFailing: boolean | ||
logs: string[] | ||
testFile: string | ||
} | { | ||
type: "worker-finished", | ||
forcedExit: boolean, | ||
testFile: string | ||
} | { | ||
type: "worker-failed", | ||
nonZeroExitCode?: boolean, | ||
signal?: string, | ||
err?: SerializedError | ||
} | { | ||
type: "touched-files", | ||
files: { | ||
changedFiles: string[], | ||
temporaryFiles: string[] | ||
} | ||
} | { | ||
type: 'worker-stdout', | ||
chunk: Uint8Array | ||
testFile: string | ||
} | { | ||
type: 'worker-stderr', | ||
chunk: Uint8Array | ||
testFile: string | ||
} | { | ||
type: "timeout", | ||
period: number, | ||
pendingTests: Map<string, Set<string>> | ||
} | ||
| { | ||
type: "end" | ||
} |
Uh oh!
There was an error while loading. Please reload this page.