Skip to content

Commit

Permalink
feat: create and observe test runs on TestRunManager
Browse files Browse the repository at this point in the history
  • Loading branch information
ph-fritsche committed Dec 20, 2023
1 parent 70e4698 commit 9352ac2
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 2 deletions.
40 changes: 38 additions & 2 deletions src/conductor/TestRunManager.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,48 @@
import { TestSuite } from './TestRun'
import { TestFile, TestRunStack, TestSuite, createTestRun } from './TestRun'
import os from 'node:os'
import events from 'node:events'
import { EventEmitter, getEventDispatch } from '../event'
import { TestConductor } from './TestConductor'

type TestRunManagerEventMap = {
create: {run: TestRunStack}
complete: {run: TestRunStack}
abort: {run: TestRunStack}
done: {run: TestRunStack}
}

export class TestRunManager extends EventEmitter<TestRunManagerEventMap> {
constructor() {
super()
}

export class TestRunManager {
maxParallel = os.availableParallelism()

protected abortController?: AbortController

private dispatch = getEventDispatch(this)

async run(
conductors: Iterable<TestConductor>,
testFiles: Iterable<TestFile>,
testRunIterator: (run: TestRunStack) => Generator<TestSuite>,
filterSuites?: RegExp,
filterTests?: RegExp,
) {
const run = createTestRun(conductors, testFiles)

this.dispatch('create', {run})

try {
await this.exec(testRunIterator(run), filterSuites, filterTests)
this.dispatch('complete', {run})
} catch(e) {
this.dispatch('abort', {run})
} finally {
this.dispatch('done', { run })
}
}

async exec(
suites: Iterable<TestSuite>,
filterSuites?: RegExp,
Expand Down
54 changes: 54 additions & 0 deletions test/conductor/TestRunManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { TestConductor } from '#src/conductor/TestConductor'
import { TestRunInstance, createTestRun } from '#src/conductor/TestRun'
import { TestRunStack } from '#src/conductor/TestRun/TestRun'
import { TestRunIterator } from '#src/conductor/TestRunIterator'
import { TestRunManager } from '#src/conductor/TestRunManager'
import { promise } from '#src/util/promise'
import { observePromise } from '#test/_util'
Expand Down Expand Up @@ -194,3 +197,54 @@ test('subsequent `exec` call aborts previous run', async () => {
'test://f.js': 'pending',
})
})

test('run test files', async () => {
const manager = new TestRunManager()
const execMock = mock.fn<TestRunManager['exec']>(() => Promise.resolve())
Reflect.set(manager, 'exec', execMock)

const listener = mock.fn<(e: {type: string, run: TestRunStack}) => void>()
manager.addListener('create', listener)
manager.addListener('abort', listener)
manager.addListener('complete', listener)
manager.addListener('done', listener)

const conductor = {} as TestConductor
const filterSuites = new RegExp('')
const filterTests = new RegExp('')
const runA = observePromise(manager.run([conductor], [
{url: 'test://a.js', title: 'a'},
{url: 'test://b.js', title: 'b'},
], TestRunIterator.iterateConductorsBySuites, filterSuites, filterTests))

expect(listener).toHaveBeenNthCalledWith(1, {type: 'create', run: expect.any(TestRunStack)})
const runARun = listener.mock.lastCall![0].run
expect(execMock).toBeCalledTimes(1)
const suites = Array.from(execMock.mock.lastCall![0])
expect(suites[0].run.conductor).toBe(conductor)
expect(suites[1].run.conductor).toBe(conductor)
expect(execMock.mock.lastCall![1]).toBe(filterSuites)
expect(execMock.mock.lastCall![2]).toBe(filterTests)

await nextTick()

expect(listener).toHaveBeenNthCalledWith(2, {type: 'complete', run: runARun})
expect(listener).toHaveBeenNthCalledWith(3, {type: 'done', run: runARun})
expect(runA.state).toBe('resolved')

execMock.mockImplementation(() => Promise.reject())
const runB = observePromise(manager.run([conductor], [
{url: 'test://a.js', title: 'a'},
{url: 'test://b.js', title: 'b'},
], TestRunIterator.iterateConductorsBySuites))

expect(listener).toHaveBeenNthCalledWith(4, {type: 'create', run: expect.any(TestRunStack)})
const runBRun = listener.mock.lastCall![0].run
expect(execMock).toBeCalledTimes(2)

await nextTick()

expect(listener).toHaveBeenNthCalledWith(5, {type: 'abort', run: runBRun})
expect(listener).toHaveBeenNthCalledWith(6, {type: 'done', run: runBRun})
expect(runB.state).toBe('resolved')
})

0 comments on commit 9352ac2

Please sign in to comment.