playwright/utils/testrunner/test/testrunner.spec.js
2020-07-02 11:05:38 -07:00

1053 lines
34 KiB
JavaScript

const { TestRunner } = require('../TestRunner');
const { TestCollector, FocusedFilter, Repeater } = require('../TestCollector');
const { TestExpectation, Environment } = require('../Test');
class Runner {
constructor(options = {}) {
this._options = options;
this._filter = new FocusedFilter();
this._repeater = new Repeater();
this._collector = new TestCollector(options);
this._collector.addSuiteAttribute('only', s => this._filter.focusSuite(s));
this._collector.addTestAttribute('only', t => this._filter.focusTest(t));
this._collector.addSuiteAttribute('skip', s => s.setSkipped(true));
this._collector.addTestAttribute('skip', t => t.setSkipped(true));
this._collector.addTestAttribute('fail', t => t.setExpectation(t.Expectations.Fail));
this._collector.addSuiteModifier('repeat', (s, count) => this._repeater.repeat(s, count));
this._collector.addTestModifier('repeat', (t, count) => this._repeater.repeat(t, count));
const api = this._collector.api();
for (const [key, value] of Object.entries(api))
this[key] = value;
this.fdescribe = api.describe.only;
this.xdescribe = api.describe.skip;
this.fit = api.it.only;
this.xit = api.it.skip;
this.Expectations = { ...TestExpectation };
}
createTestRuns() {
return this._repeater.createTestRuns(this._filter.filter(this._collector.tests()));
}
run() {
this._testRunner = new TestRunner();
return this._testRunner.run(this.createTestRuns(), this._options);
}
tests() {
return this._collector.tests();
}
parallel() {
return this._options.parallel || 1;
}
focusedTests() {
return this._filter.focusedTests(this._collector.tests());
}
suites() {
return this._collector.suites();
}
focusedSuites() {
return this._filter.focusedSuites(this._collector.suites());
}
terminate() {
this._testRunner.terminate();
}
}
module.exports.addTests = function({describe, fdescribe, xdescribe, it, xit, fit, expect}) {
describe('TestRunner.it', () => {
it('should declare a test', async() => {
const t = new Runner();
t.it('uno', () => {});
expect(t.tests().length).toBe(1);
const test = t.tests()[0];
expect(test.name()).toBe('uno');
expect(test.fullName()).toBe('uno');
expect(test.skipped()).toBe(false);
expect(test.location().filePath()).toEqual(__filename);
expect(test.location().fileName()).toEqual('testrunner.spec.js');
expect(test.location().lineNumber()).toBeTruthy();
expect(test.location().columnNumber()).toBeTruthy();
});
it('should run a test', async() => {
const t = new Runner();
t.it('uno', () => {});
const result = await t.run();
expect(result.runs.length).toBe(1);
expect(result.runs[0].test()).toBe(t.tests()[0]);
expect(result.runs[0].result()).toBe('ok');
});
});
describe('TestRunner.xit', () => {
it('should declare a skipped test', async() => {
const t = new Runner();
t.xit('uno', () => {});
expect(t.tests().length).toBe(1);
const test = t.tests()[0];
expect(test.name()).toBe('uno');
expect(test.fullName()).toBe('uno');
expect(test.skipped()).toBe(true);
});
it('should not run a skipped test', async() => {
const t = new Runner();
t.xit('uno', () => {});
const result = await t.run();
expect(result.runs.length).toBe(1);
expect(result.runs[0].test()).toBe(t.tests()[0]);
expect(result.runs[0].result()).toBe('skipped');
});
});
describe('TestRunner.fit', () => {
it('should declare a focused test', async() => {
const t = new Runner();
t.fit('uno', () => {});
expect(t.tests().length).toBe(1);
const test = t.tests()[0];
expect(test.name()).toBe('uno');
expect(test.fullName()).toBe('uno');
expect(test.skipped()).toBe(false);
expect(t.focusedTests()[0]).toBe(test);
});
it('should run a focused test', async() => {
const t = new Runner();
t.fit('uno', () => {});
const result = await t.run();
expect(result.runs.length).toBe(1);
expect(result.runs[0].test()).toBe(t.tests()[0]);
expect(result.runs[0].result()).toBe('ok');
});
it('should run a failed focused test', async() => {
const t = new Runner();
let run = false;
t.it.only.fail('uno', () => {
run = true; throw new Error('failure');
});
expect(t.focusedTests().length).toBe(1);
expect(t.tests()[0].expectation()).toBe(t.Expectations.Fail);
const result = await t.run();
expect(run).toBe(true);
expect(result.runs.length).toBe(1);
expect(result.runs[0].test()).toBe(t.tests()[0]);
expect(result.runs[0].result()).toBe('failed');
});
});
describe('TestRunner.describe', () => {
it('should declare a suite', async() => {
const t = new Runner();
t.describe('suite', () => {
t.it('uno', () => {});
});
expect(t.tests().length).toBe(1);
const test = t.tests()[0];
expect(test.name()).toBe('uno');
expect(test.fullName()).toBe('suite uno');
expect(test.skipped()).toBe(false);
expect(test.suite().name()).toBe('suite');
expect(test.suite().fullName()).toBe('suite');
expect(test.suite().skipped()).toBe(false);
});
});
describe('TestRunner.xdescribe', () => {
it('should declare a skipped suite', async() => {
const t = new Runner();
t.xdescribe('suite', () => {
t.it('uno', () => {});
});
expect(t.tests().length).toBe(1);
const test = t.tests()[0];
expect(test.skipped()).toBe(false);
expect(test.suite().skipped()).toBe(true);
});
it('focused tests inside a skipped suite are not run', async() => {
const t = new Runner();
let run = false;
t.xdescribe('suite', () => {
t.fit('uno', () => { run = true; });
});
const result = await t.run();
expect(run).toBe(false);
expect(result.runs.length).toBe(1);
expect(result.runs[0].test()).toBe(t.tests()[0]);
expect(result.runs[0].result()).toBe('skipped');
});
});
describe('TestRunner.fdescribe', () => {
it('should declare a focused suite', async() => {
const t = new Runner();
t.fdescribe('suite', () => {
t.it('uno', () => {});
});
expect(t.tests().length).toBe(1);
const test = t.tests()[0];
expect(test.skipped()).toBe(false);
expect(t.focusedSuites()[0]).toBe(test.suite());
expect(test.suite().skipped()).toBe(false);
});
it('skipped tests inside a focused suite should not be run', async() => {
const t = new Runner();
t.fdescribe('suite', () => {
t.xit('uno', () => {});
});
const result = await t.run();
expect(result.runs.length).toBe(1);
expect(result.runs[0].test()).toBe(t.tests()[0]);
expect(result.runs[0].result()).toBe('skipped');
});
it('should run all "run" tests inside a focused suite', async() => {
const log = [];
const t = new Runner();
t.it('uno', () => log.push(1));
t.fdescribe('suite1', () => {
t.it('dos', () => log.push(2));
t.it('tres', () => log.push(3));
});
t.it('cuatro', () => log.push(4));
await t.run();
expect(log.join()).toBe('2,3');
});
it('should run only "focus" tests inside a focused suite', async() => {
const log = [];
const t = new Runner();
t.it('uno', () => log.push(1));
t.fdescribe('suite1', () => {
t.fit('dos', () => log.push(2));
t.it('tres', () => log.push(3));
});
t.it('cuatro', () => log.push(4));
await t.run();
expect(log.join()).toBe('2');
});
it('should run both "run" tests in focused suite and non-descendant focus tests', async() => {
const log = [];
const t = new Runner();
t.it('uno', () => log.push(1));
t.fdescribe('suite1', () => {
t.it('dos', () => log.push(2));
t.it('tres', () => log.push(3));
});
t.fit('cuatro', () => log.push(4));
await t.run();
expect(log.join()).toBe('2,3,4');
});
});
describe('TestRunner attributes', () => {
it('should work', async() => {
const t = new Runner({timeout: 123});
const log = [];
t._collector.addTestModifier('foo', (t, ...args) => {
log.push('foo');
expect(t.skipped()).toBe(false);
expect(t.Expectations.Ok).toBeTruthy();
expect(t.Expectations.Fail).toBeTruthy();
expect(t.expectation()).toBe(t.Expectations.Ok);
expect(t.timeout()).toBe(123);
expect(args.length).toBe(2);
expect(args[0]).toBe('uno');
expect(args[1]).toBe('dos');
t.setExpectation(t.Expectations.Fail);
t.setTimeout(234);
});
t._collector.addTestAttribute('bar', t => {
log.push('bar');
t.setSkipped(true);
expect(t.skipped()).toBe(true);
expect(t.expectation()).toBe(t.Expectations.Fail);
expect(t.timeout()).toBe(234);
});
t.it.foo('uno', 'dos').bar('test', () => { });
expect(log).toEqual(['foo', 'bar']);
});
});
describe('TestRunner hooks', () => {
it('should run all hooks in proper order', async() => {
const log = [];
const t = new Runner();
const e = {
name() { return 'env'; },
beforeAll() { log.push('env:beforeAll'); },
afterAll() { log.push('env:afterAll'); },
beforeEach() { log.push('env:beforeEach'); },
afterEach() { log.push('env:afterEach'); },
};
const e2 = {
name() { return 'env2'; },
beforeAll() { log.push('env2:beforeAll'); },
afterAll() { log.push('env2:afterAll'); },
};
t.beforeAll(() => log.push('root:beforeAll'));
t.beforeEach(() => log.push('root:beforeEach'));
t.it('uno', () => log.push('test #1'));
t.describe('suite1', () => {
t.beforeAll(() => log.push('suite:beforeAll'));
t.beforeEach(() => log.push('suite:beforeEach'));
t.it('dos', () => log.push('test #2'));
t.it('tres', () => log.push('test #3'));
t.afterEach(() => log.push('suite:afterEach'));
t.afterAll(() => log.push('suite:afterAll'));
});
t.it('cuatro', () => log.push('test #4'));
t.tests()[t.tests().length - 1].addEnvironment(e);
t.tests()[t.tests().length - 1].addEnvironment(e2);
t.describe('no hooks suite', () => {
t.describe('suite2', () => {
t.beforeAll(() => log.push('suite2:beforeAll'));
t.afterAll(() => log.push('suite2:afterAll'));
t.describe('no hooks suite 2', () => {
t.it('cinco', () => log.push('test #5'));
});
});
});
t.suites()[t.suites().length - 1].addEnvironment(e);
t.suites()[t.suites().length - 1].addEnvironment(e2);
t.afterEach(() => log.push('root:afterEach'));
t.afterAll(() => log.push('root:afterAll'));
await t.run();
expect(log).toEqual([
'root:beforeAll',
'root:beforeEach',
'test #1',
'root:afterEach',
'suite:beforeAll',
'root:beforeEach',
'suite:beforeEach',
'test #2',
'suite:afterEach',
'root:afterEach',
'root:beforeEach',
'suite:beforeEach',
'test #3',
'suite:afterEach',
'root:afterEach',
'suite:afterAll',
'env:beforeAll',
'env2:beforeAll',
'root:beforeEach',
'env:beforeEach',
'test #4',
'env:afterEach',
'root:afterEach',
'suite2:beforeAll',
'root:beforeEach',
'env:beforeEach',
'test #5',
'env:afterEach',
'root:afterEach',
'suite2:afterAll',
'env2:afterAll',
'env:afterAll',
'root:afterAll',
]);
});
it('should remove environment', async() => {
const log = [];
const t = new Runner();
const e = {
name() { return 'env'; },
beforeAll() { log.push('env:beforeAll'); },
afterAll() { log.push('env:afterAll'); },
beforeEach() { log.push('env:beforeEach'); },
afterEach() { log.push('env:afterEach'); },
};
const e2 = {
name() { return 'env2'; },
beforeAll() { log.push('env2:beforeAll'); },
afterAll() { log.push('env2:afterAll'); },
beforeEach() { log.push('env2:beforeEach'); },
afterEach() { log.push('env2:afterEach'); },
};
t.it('uno', () => log.push('test #1'));
t.tests()[0].addEnvironment(e).addEnvironment(e2).removeEnvironment(e);
await t.run();
expect(log).toEqual([
'env2:beforeAll',
'env2:beforeEach',
'test #1',
'env2:afterEach',
'env2:afterAll',
]);
});
it('should have the same state object in hooks and test', async() => {
const states = [];
const t = new Runner();
t.beforeEach(state => states.push(state));
t.afterEach(state => states.push(state));
t.beforeAll(state => states.push(state));
t.afterAll(state => states.push(state));
t.it('uno', state => states.push(state));
await t.run();
expect(states.length).toBe(5);
for (let i = 1; i < states.length; ++i)
expect(states[i]).toBe(states[0]);
});
it('should unwind hooks properly when terminated', async() => {
const log = [];
const t = new Runner({timeout: 10000});
t.beforeAll(() => log.push('beforeAll'));
t.beforeEach(() => log.push('beforeEach'));
t.afterEach(() => log.push('afterEach'));
t.afterAll(() => log.push('afterAll'));
t.it('uno', () => {
log.push('terminating...');
t.terminate();
});
await t.run();
expect(log).toEqual([
'beforeAll',
'beforeEach',
'terminating...',
'afterEach',
'afterAll',
]);
});
it('should report as terminated even when hook crashes', async() => {
const t = new Runner({timeout: 10000});
t.afterEach(() => { throw new Error('crash!'); });
t.it('uno', () => { t.terminate(); });
const result = await t.run();
expect(result.runs[0].result()).toBe('terminated');
});
it('should report as terminated when terminated during hook', async() => {
const t = new Runner({timeout: 10000});
t.afterEach(() => { t.terminate(); });
t.it('uno', () => { });
const result = await t.run();
expect(result.runs[0].result()).toBe('terminated');
});
it('should unwind hooks properly when crashed', async() => {
const log = [];
const t = new Runner({timeout: 10000});
t.beforeAll(() => log.push('root beforeAll'));
t.beforeEach(() => log.push('root beforeEach'));
t.describe('suite', () => {
t.beforeAll(() => log.push('suite beforeAll'));
t.beforeEach(() => log.push('suite beforeEach'));
t.it('uno', () => log.push('uno'));
t.afterEach(() => {
log.push('CRASH >> suite afterEach');
throw new Error('crash!');
});
t.afterAll(() => log.push('suite afterAll'));
});
t.afterEach(() => log.push('root afterEach'));
t.afterAll(() => log.push('root afterAll'));
await t.run();
expect(log).toEqual([
'root beforeAll',
'suite beforeAll',
'root beforeEach',
'suite beforeEach',
'uno',
'CRASH >> suite afterEach',
'root afterEach',
'suite afterAll',
'root afterAll'
]);
});
});
describe('globalSetup & globalTeardwon', () => {
it('should run globalSetup and globalTeardown in proper order', async() => {
const t = new Runner({timeout: 10000});
const tracer = new TestTracer(t);
tracer.traceAllHooks();
tracer.addTest('', 'test1');
await t.run();
expect(tracer.trace()).toEqual([
'globalSetup',
'beforeAll',
'beforeEach',
'test1',
'afterEach',
'afterAll',
'globalTeardown',
]);
});
it('should run globalSetup and globalTeardown in proper order if parallel', async() => {
const t = new Runner({timeout: 10000, parallel: 2});
const tracer = new TestTracer(t);
tracer.traceAllHooks('', async (hookName) => {
// slowdown globalsetup to see the rest hooks awaiting this one
if (hookName === 'globalSetup')
await new Promise(x => setTimeout(x, 50));
});
tracer.addTest('', 'test1');
tracer.addTest('', 'test2');
await t.run();
expect(tracer.trace()).toEqual([
'<_global_> globalSetup',
'<worker 1> beforeAll',
'<worker 2> beforeAll',
'<worker 1> beforeEach',
'<worker 2> beforeEach',
'<worker 1> test1',
'<worker 2> test2',
'<worker 1> afterEach',
'<worker 2> afterEach',
'<worker 1> afterAll',
'<worker 2> afterAll',
'<_global_> globalTeardown',
]);
});
it('should support globalSetup/globalTeardown in nested suites', async() => {
const t = new Runner({timeout: 10000, parallel: 2});
const tracer = new TestTracer(t);
tracer.traceAllHooks('');
t.describe('suite', () => {
tracer.traceAllHooks(' ');
tracer.addTest(' ', 'test1');
tracer.addTest(' ', 'test2');
tracer.addTest(' ', 'test3');
});
await t.run();
expect(tracer.trace()).toEqual([
'<_global_> globalSetup',
'<worker 1> beforeAll',
'<worker 2> beforeAll',
' <_global_> globalSetup',
' <worker 1> beforeAll',
' <worker 2> beforeAll',
'<worker 1> beforeEach',
'<worker 2> beforeEach',
' <worker 1> beforeEach',
' <worker 2> beforeEach',
' <worker 1> test1',
' <worker 2> test2',
' <worker 1> afterEach',
' <worker 2> afterEach',
'<worker 1> afterEach',
'<worker 2> afterEach',
' <worker 2> afterAll',
'<worker 1> beforeEach',
'<worker 2> afterAll',
' <worker 1> beforeEach',
' <worker 1> test3',
' <worker 1> afterEach',
'<worker 1> afterEach',
' <worker 1> afterAll',
' <_global_> globalTeardown',
'<worker 1> afterAll',
'<_global_> globalTeardown',
]);
});
it('should report as crashed when global hook crashes', async() => {
const t = new Runner({timeout: 10000});
t.globalSetup(() => { throw new Error('crash!'); });
t.it('uno', () => { });
const result = await t.run();
expect(result.result).toBe('crashed');
});
it('should terminate and unwind hooks if globalSetup fails', async() => {
const t = new Runner({timeout: 10000});
const tracer = new TestTracer(t);
tracer.traceAllHooks();
t.describe('suite', () => {
tracer.traceAllHooks(' ', (hookName) => {
if (hookName === 'globalSetup') {
tracer.log(' !! CRASH !!');
throw new Error('crash');
}
});
tracer.addTest(' ', 'test1');
});
await t.run();
expect(tracer.trace()).toEqual([
'globalSetup',
'beforeAll',
' globalSetup',
' !! CRASH !!',
' afterAll',
' globalTeardown',
'afterAll',
'globalTeardown',
]);
});
it('should not run globalSetup / globalTeardown if all tests are skipped', async() => {
const t = new Runner({timeout: 10000});
const tracer = new TestTracer(t);
tracer.traceAllHooks();
t.describe('suite', () => {
tracer.addSkippedTest(' ', 'test1');
});
await t.run();
expect(tracer.trace()).toEqual([
]);
});
it('should properly run globalTeardown if some tests are not run', async() => {
const t = new Runner({timeout: 10000});
const tracer = new TestTracer(t);
tracer.traceAllHooks();
t.describe('suite', () => {
tracer.addSkippedTest(' ', 'test1');
tracer.addFailingTest(' ', 'test2');
tracer.addTest(' ', 'test3');
});
await t.run();
expect(tracer.trace()).toEqual([
'globalSetup',
'beforeAll',
'beforeEach',
' test3',
'afterEach',
'afterAll',
'globalTeardown',
]);
});
});
describe('TestRunner.run', () => {
it('should run a test', async() => {
const t = new Runner();
let ran = false;
t.it('uno', () => ran = true);
await t.run();
expect(ran).toBe(true);
});
it('should handle repeat', async() => {
const t = new Runner();
let suite = 0;
let test = 0;
let beforeAll = 0;
let beforeEach = 0;
t.describe.repeat(2)('suite', () => {
suite++;
t.beforeAll(() => beforeAll++);
t.beforeEach(() => beforeEach++);
t.it.repeat(3)('uno', () => test++);
});
await t.run();
expect(suite).toBe(1);
expect(beforeAll).toBe(1);
expect(beforeEach).toBe(6);
expect(test).toBe(6);
});
it('should repeat without breaking test order', async() => {
const t = new Runner();
const log = [];
t.describe.repeat(2)('suite', () => {
t.it('uno', () => log.push(1));
t.it.repeat(2)('dos', () => log.push(2));
});
t.it('tres', () => log.push(3));
await t.run();
expect(log.join()).toBe('1,2,2,1,2,2,3');
});
it('should run tests if some fail', async() => {
const t = new Runner();
const log = [];
t.it('uno', () => log.push(1));
t.it('dos', () => { throw new Error('bad'); });
t.it('tres', () => log.push(3));
await t.run();
expect(log.join()).toBe('1,3');
});
it('should run tests if some timeout', async() => {
const t = new Runner({timeout: 1});
const log = [];
t.it('uno', () => log.push(1));
t.it('dos', async() => new Promise(() => {}));
t.it('tres', () => log.push(3));
await t.run();
expect(log.join()).toBe('1,3');
});
it('should break on first failure if configured so', async() => {
const log = [];
const t = new Runner({breakOnFailure: true});
t.it('test#1', () => log.push('test#1'));
t.it('test#2', () => log.push('test#2'));
t.it('test#3', () => { throw new Error('crash'); });
t.it('test#4', () => log.push('test#4'));
await t.run();
expect(log).toEqual([
'test#1',
'test#2',
]);
});
it('should pass a state and a test as a test parameters', async() => {
const log = [];
const t = new Runner();
t.beforeEach(state => state.FOO = 42);
t.it('uno', (state, testRun) => {
log.push('state.FOO=' + state.FOO);
log.push('test=' + testRun.test().name());
});
await t.run();
expect(log.join()).toBe('state.FOO=42,test=uno');
});
it('should run async test', async() => {
const t = new Runner();
let ran = false;
t.it('uno', async() => {
await new Promise(x => setTimeout(x, 10));
ran = true;
});
await t.run();
expect(ran).toBe(true);
});
it('should run async tests in order of their declaration', async() => {
const log = [];
const t = new Runner();
t.it('uno', async() => {
await new Promise(x => setTimeout(x, 30));
log.push(1);
});
t.it('dos', async() => {
await new Promise(x => setTimeout(x, 20));
log.push(2);
});
t.it('tres', async() => {
await new Promise(x => setTimeout(x, 10));
log.push(3);
});
await t.run();
expect(log.join()).toBe('1,2,3');
});
it('should run multiple tests', async() => {
const log = [];
const t = new Runner();
t.it('uno', () => log.push(1));
t.it('dos', () => log.push(2));
await t.run();
expect(log.join()).toBe('1,2');
});
it('should NOT run a skipped test', async() => {
const t = new Runner();
let ran = false;
t.xit('uno', () => ran = true);
await t.run();
expect(ran).toBe(false);
});
it('should run ONLY non-skipped tests', async() => {
const log = [];
const t = new Runner();
t.it('uno', () => log.push(1));
t.xit('dos', () => log.push(2));
t.it('tres', () => log.push(3));
await t.run();
expect(log.join()).toBe('1,3');
});
it('should run ONLY focused tests', async() => {
const log = [];
const t = new Runner();
t.it('uno', () => log.push(1));
t.xit('dos', () => log.push(2));
t.fit('tres', () => log.push(3));
await t.run();
expect(log.join()).toBe('3');
});
it('should run tests in order of their declaration', async() => {
const log = [];
const t = new Runner();
t.it('uno', () => log.push(1));
t.describe('suite1', () => {
t.it('dos', () => log.push(2));
t.it('tres', () => log.push(3));
});
t.it('cuatro', () => log.push(4));
await t.run();
expect(log.join()).toBe('1,2,3,4');
});
it('should respect total timeout', async() => {
const t = new Runner({timeout: 10000, totalTimeout: 1});
t.it('uno', async () => { await new Promise(() => {}); });
const result = await t.run();
expect(result.runs[0].result()).toBe('terminated');
expect(result.message).toContain('Total timeout');
});
});
describe('TestRunner.run result', () => {
it('should return OK if all tests pass', async() => {
const t = new Runner();
t.it('uno', () => {});
const result = await t.run();
expect(result.result).toBe('ok');
});
it('should return FAIL if at least one test fails', async() => {
const t = new Runner();
t.it('uno', () => { throw new Error('woof'); });
const result = await t.run();
expect(result.result).toBe('failed');
});
it('should return FAIL if at least one test times out', async() => {
const t = new Runner({timeout: 1});
t.it('uno', async() => new Promise(() => {}));
const result = await t.run();
expect(result.result).toBe('failed');
});
it('should return TERMINATED if it was terminated', async() => {
const t = new Runner({timeout: 1000000});
t.it('uno', async() => new Promise(() => {}));
const [result] = await Promise.all([
t.run(),
t.terminate(),
]);
expect(result.result).toBe('terminated');
});
it('should return CRASHED if it crashed', async() => {
const t = new Runner({timeout: 1});
t.it('uno', async() => new Promise(() => {}));
t.afterAll(() => { throw new Error('woof');});
const result = await t.run();
expect(result.result).toBe('crashed');
});
});
describe('TestRunner parallel', () => {
it('should run tests in parallel', async() => {
const log = [];
const t = new Runner({parallel: 2});
t.it('uno', async state => {
log.push(`Worker #${state.parallelIndex} Starting: UNO`);
await Promise.resolve();
log.push(`Worker #${state.parallelIndex} Ending: UNO`);
});
t.it('dos', async state => {
log.push(`Worker #${state.parallelIndex} Starting: DOS`);
await Promise.resolve();
log.push(`Worker #${state.parallelIndex} Ending: DOS`);
});
await t.run();
expect(log).toEqual([
'Worker #0 Starting: UNO',
'Worker #1 Starting: DOS',
'Worker #0 Ending: UNO',
'Worker #1 Ending: DOS',
]);
});
});
describe('TestRunner.hasFocusedTestsOrSuitesOrFiles', () => {
it('should work', () => {
const t = new Runner();
t.it('uno', () => {});
expect(t._filter.hasFocusedTestsOrSuitesOrFiles()).toBe(false);
});
it('should work #2', () => {
const t = new Runner();
t.fit('uno', () => {});
expect(t._filter.hasFocusedTestsOrSuitesOrFiles()).toBe(true);
});
it('should work #3', () => {
const t = new Runner();
t.describe('suite #1', () => {
t.fdescribe('suite #2', () => {
t.describe('suite #3', () => {
t.it('uno', () => {});
});
});
});
expect(t._filter.hasFocusedTestsOrSuitesOrFiles()).toBe(true);
});
});
describe('TestRunner result', () => {
it('should work for both throwing and timeouting tests', async() => {
const t = new Runner({timeout: 1});
t.it('uno', () => { throw new Error('boo');});
t.it('dos', () => new Promise(() => {}));
const result = await t.run();
expect(result.runs[0].result()).toBe('failed');
expect(result.runs[1].result()).toBe('timedout');
});
it('should report crashed tests', async() => {
const t = new Runner();
t.beforeEach(() => { throw new Error('woof');});
t.it('uno', () => {});
const result = await t.run();
expect(result.runs[0].result()).toBe('crashed');
});
it('skipped should work for both throwing and timeouting tests', async() => {
const t = new Runner({timeout: 1});
t.xit('uno', () => { throw new Error('boo');});
const result = await t.run();
expect(result.runs[0].result()).toBe('skipped');
});
it('should return OK', async() => {
const t = new Runner();
t.it('uno', () => {});
const result = await t.run();
expect(result.runs[0].result()).toBe('ok');
});
it('should return TIMEDOUT', async() => {
const t = new Runner({timeout: 1});
t.it('uno', async() => new Promise(() => {}));
const result = await t.run();
expect(result.runs[0].result()).toBe('timedout');
});
it('should return SKIPPED', async() => {
const t = new Runner();
t.xit('uno', () => {});
const result = await t.run();
expect(result.runs[0].result()).toBe('skipped');
});
it('should return FAILED', async() => {
const t = new Runner();
t.it('uno', async() => Promise.reject('woof'));
const result = await t.run();
expect(result.runs[0].result()).toBe('failed');
});
it('should return TERMINATED', async() => {
const t = new Runner();
t.it('uno', async() => t.terminate());
const result = await t.run();
expect(result.runs[0].result()).toBe('terminated');
});
it('should return CRASHED', async() => {
const t = new Runner();
t.it('uno', () => {});
t.afterEach(() => {throw new Error('foo');});
const result = await t.run();
expect(result.runs[0].result()).toBe('crashed');
});
});
describe('TestRunner delegate', () => {
it('should call delegate methods in proper order', async() => {
const log = [];
const t = new Runner({
onStarted: () => log.push('E:started'),
onTestRunStarted: () => log.push('E:teststarted'),
onTestRunFinished: () => log.push('E:testfinished'),
onFinished: () => log.push('E:finished'),
});
t.beforeAll(() => log.push('beforeAll'));
t.beforeEach(() => log.push('beforeEach'));
t.it('test#1', () => log.push('test#1'));
t.afterEach(() => log.push('afterEach'));
t.afterAll(() => log.push('afterAll'));
await t.run();
expect(log).toEqual([
'E:started',
'beforeAll',
'E:teststarted',
'beforeEach',
'test#1',
'afterEach',
'E:testfinished',
'afterAll',
'E:finished',
]);
});
it('should call onFinished with result', async() => {
let onFinished;
const finishedPromise = new Promise(f => onFinished = f);
const [result] = await Promise.all([
finishedPromise,
new TestRunner().run([], { onFinished }),
]);
expect(result.result).toBe('ok');
});
it('should crash when onStarted throws', async() => {
const t = new Runner({
onStarted: () => { throw 42; },
});
const result = await t.run();
expect(result.ok()).toBe(false);
expect(result.message).toBe('INTERNAL ERROR: 42');
});
it('should crash when onFinished throws', async() => {
const t = new Runner({
onFinished: () => { throw new Error('42'); },
});
const result = await t.run();
expect(result.ok()).toBe(false);
expect(result.message).toBe('INTERNAL ERROR');
expect(result.result).toBe('crashed');
});
});
};
class TestTracer {
constructor(testRunner) {
this._testRunner = testRunner;
this._trace = [];
}
addSkippedTest(prefix, testName, callback) {
this._testRunner.it.skip(testName, async(...args) => {
if (callback)
await callback(...args);
this._trace.push(prefix + this._workerPrefix(args[0]) + testName);
});
}
addFailingTest(prefix, testName, callback) {
this._testRunner.it.fail(testName, async(...args) => {
if (callback)
await callback(...args);
this._trace.push(prefix + this._workerPrefix(args[0]) + testName);
});
}
addTest(prefix, testName, callback) {
this._testRunner.it(testName, async(...args) => {
if (callback)
await callback(...args);
this._trace.push(prefix + this._workerPrefix(args[0]) + testName);
});
}
traceHooks(hookNames, prefix = '', callback) {
for (const hookName of hookNames) {
this._testRunner[hookName].call(this._testRunner, async (state) => {
this._trace.push(prefix + this._workerPrefix(state) + hookName);
if (callback)
await callback(hookName);
});
}
}
_workerPrefix(state) {
if (this._testRunner.parallel() === 1)
return '';
return state && (typeof state.parallelIndex !== 'undefined') ? `<worker ${state.parallelIndex + 1}> ` : `<_global_> `;
}
traceAllHooks(prefix = '', callback) {
this.traceHooks(['globalSetup', 'globalTeardown', 'beforeAll', 'afterAll', 'beforeEach', 'afterEach'], prefix, callback);
}
log(text) {
this._trace.push(text);
}
trace() {
return this._trace;
}
}