/* eslint-disable @typescript-eslint/require-await */ export const description = ` Unit tests for TestGroup. `; import { Fixture } from '../common/framework/fixture.js'; import { makeTestGroup } from '../common/framework/test_group.js'; import { TestQueryMultiFile } from '../common/internal/query/query.js'; import { kQueryMaxLength, makeTestGroupForUnitTesting } from '../common/internal/test_group.js'; import { assert } from '../common/util/util.js'; import { TestGroupTest } from './test_group_test.js'; import { UnitTest } from './unit_test.js'; export const g = makeTestGroup(TestGroupTest); g.test('UnitTest_fixture').fn(async t0 => { let seen = 0; function count(_t: Fixture): void { seen++; } const g = makeTestGroupForUnitTesting(UnitTest); g.test('test').fn(count); g.test('testp') .paramsSimple([{ a: 1 }]) .fn(count); await t0.run(g); t0.expect(seen === 2); }); g.test('custom_fixture').fn(async t0 => { let seen = 0; class Counter extends UnitTest { count(): void { seen++; } } const g = makeTestGroupForUnitTesting(Counter); g.test('test').fn(t => { t.count(); }); g.test('testp') .paramsSimple([{ a: 1 }]) .fn(t => { t.count(); }); await t0.run(g); t0.expect(seen === 2); }); g.test('stack').fn(async t0 => { const g = makeTestGroupForUnitTesting(UnitTest); const doNestedThrow1 = () => { throw new Error('goodbye'); }; const doNestedThrow2 = () => doNestedThrow1(); g.test('fail').fn(t => { t.fail(); }); g.test('throw').fn(_t => { throw new Error('hello'); }); g.test('throw_nested').fn(_t => { doNestedThrow2(); }); const res = await t0.run(g); const search = /unittests[/\\]test_group\.spec\.[tj]s/; t0.expect(res.size > 0); for (const { logs } of res.values()) { assert(logs !== undefined, 'expected logs'); t0.expect(logs.some(l => search.test(l.toJSON()))); t0.expect(search.test(logs[logs.length - 1].toJSON())); } }); g.test('no_fn').fn(t => { const g = makeTestGroupForUnitTesting(UnitTest); g.test('missing'); t.shouldThrow('Error', () => { g.validate(new TestQueryMultiFile('s', ['f'])); }); }); g.test('duplicate_test_name').fn(t => { const g = makeTestGroupForUnitTesting(UnitTest); g.test('abc').fn(() => {}); t.shouldThrow('Error', () => { g.test('abc').fn(() => {}); }); }); g.test('duplicate_test_params,none').fn(() => { { const g = makeTestGroupForUnitTesting(UnitTest); g.test('abc') .paramsSimple([]) .fn(() => {}); g.validate(new TestQueryMultiFile('s', ['f'])); } { const g = makeTestGroupForUnitTesting(UnitTest); g.test('abc').fn(() => {}); g.validate(new TestQueryMultiFile('s', ['f'])); } { const g = makeTestGroupForUnitTesting(UnitTest); g.test('abc') .paramsSimple([ { a: 1 }, // ]) .fn(() => {}); g.validate(new TestQueryMultiFile('s', ['f'])); } }); g.test('duplicate_test_params,basic').fn(t => { { const g = makeTestGroupForUnitTesting(UnitTest); const builder = g.test('abc'); t.shouldThrow('Error', () => { builder.paramsSimple([ { a: 1 }, // { a: 1 }, ]); g.validate(new TestQueryMultiFile('s', ['f'])); }); } { const g = makeTestGroupForUnitTesting(UnitTest); g.test('abc') .params(u => u.expandWithParams(() => [ { a: 1 }, // { a: 1 }, ]) ) .fn(() => {}); t.shouldThrow('Error', () => { g.validate(new TestQueryMultiFile('s', ['f'])); }); } { const g = makeTestGroupForUnitTesting(UnitTest); g.test('abc') .paramsSimple([ { a: 1, b: 3 }, // { b: 3, a: 1 }, ]) .fn(() => {}); t.shouldThrow('Error', () => { g.validate(new TestQueryMultiFile('s', ['f'])); }); } }); g.test('duplicate_test_params,with_different_private_params').fn(t => { { const g = makeTestGroupForUnitTesting(UnitTest); const builder = g.test('abc'); t.shouldThrow('Error', () => { builder.paramsSimple([ { a: 1, _b: 1 }, // { a: 1, _b: 2 }, ]); }); } { const g = makeTestGroupForUnitTesting(UnitTest); g.test('abc') .params(u => u.expandWithParams(() => [ { a: 1, _b: 1 }, // { a: 1, _b: 2 }, ]) ) .fn(() => {}); t.shouldThrow('Error', () => { g.validate(new TestQueryMultiFile('s', ['f'])); }); } }); g.test('invalid_test_name').fn(t => { const g = makeTestGroupForUnitTesting(UnitTest); const badChars = Array.from('"`~@#$+=\\|!^&*[]<>{}-\'. '); for (const char of badChars) { const name = 'a' + char + 'b'; t.shouldThrow( 'Error', () => { g.test(name).fn(() => {}); }, { message: name } ); } }); g.test('long_test_query,long_test_name').fn(t => { const g = makeTestGroupForUnitTesting(UnitTest); const long = Array(kQueryMaxLength - 5).join('a'); const fileQuery = new TestQueryMultiFile('s', ['f']); g.test(long).unimplemented(); g.validate(fileQuery); g.test(long + 'a').unimplemented(); t.shouldThrow( 'Error', () => { g.validate(fileQuery); }, { message: long } ); }); g.test('long_case_query,long_test_name').fn(t => { const g = makeTestGroupForUnitTesting(UnitTest); const long = Array(kQueryMaxLength - 5).join('a'); const fileQuery = new TestQueryMultiFile('s', ['f']); g.test(long).fn(() => {}); g.validate(fileQuery); g.test(long + 'a').fn(() => {}); t.shouldThrow( 'Error', () => { g.validate(fileQuery); }, { message: long } ); }); g.test('long_case_query,long_case_name').fn(t => { const g = makeTestGroupForUnitTesting(UnitTest); const long = Array(kQueryMaxLength - 9).join('a'); const fileQuery = new TestQueryMultiFile('s', ['f']); g.test('t') .paramsSimple([{ x: long }]) .fn(() => {}); g.validate(fileQuery); g.test('u') .paramsSimple([{ x: long + 'a' }]) .fn(() => {}); t.shouldThrow( 'Error', () => { g.validate(fileQuery); }, { message: long } ); }); g.test('param_value,valid').fn(() => { const g = makeTestGroup(UnitTest); g.test('a').paramsSimple([{ x: JSON.stringify({ a: 1, b: 2 }) }]); }); g.test('param_value,invalid').fn(t => { for (const badChar of ';=*') { const g = makeTestGroupForUnitTesting(UnitTest); const builder = g.test('a'); t.shouldThrow('Error', () => { builder.paramsSimple([{ badChar }]); }); } }); g.test('subcases').fn(async t0 => { const g = makeTestGroupForUnitTesting(UnitTest); g.test('a') .paramsSubcasesOnly(u => u // .combineWithParams([{ a: 1 }]) ) .fn(t => { t.expect(t.params.a === 1, 'a must be 1'); }); function* gen({ a, b }: { a?: number; b?: number }) { if (b === 2) { yield { ret: 2 }; } else if (a === 1) { yield { ret: 1 }; } else { yield { ret: -1 }; } } g.test('b') .params(u => u .combineWithParams([{ a: 1 }, { b: 2 }]) .beginSubcases() .expandWithParams(gen) ) .fn(t => { const { a, b, ret } = t.params; t.expect((a === 1 && ret === 1) || (b === 2 && ret === 2)); }); const result = await t0.run(g); t0.expect(Array.from(result.values()).every(v => v.status === 'pass')); }); g.test('subcases,skip') .desc( 'If all tests are skipped then status is "skip". If at least one test passed, status is "pass"' ) .params(u => u.combine('allSkip', [false, true])) .fn(async t0 => { const { allSkip } = t0.params; const g = makeTestGroupForUnitTesting(UnitTest); g.test('a') .params(u => u.beginSubcases().combine('do', ['pass', 'skip', 'pass'])) .fn(t => { t.skipIf(allSkip || t.params.do === 'skip'); }); const result = await t0.run(g); const values = Array.from(result.values()); t0.expect(values.length === 1); const expectedStatus = allSkip ? 'skip' : 'pass'; t0.expect( values[0].status === expectedStatus, `expect: ${values[0].status} === ${expectedStatus}}, allSkip: ${allSkip}` ); }); g.test('exceptions') .params(u => u .combine('useSubcases', [false, true]) // .combine('useDOMException', [false, true]) ) .fn(async t0 => { const { useSubcases, useDOMException } = t0.params; const g = makeTestGroupForUnitTesting(UnitTest); const b1 = g.test('a'); let b2; if (useSubcases) { b2 = b1.paramsSubcasesOnly(u => u); } else { b2 = b1.params(u => u); } b2.fn(_t => { if (useDOMException) { throw new DOMException('Message!', 'Name!'); } else { throw new Error('Message!'); } }); const result = await t0.run(g); const values = Array.from(result.values()); t0.expect(values.length === 1); t0.expect(values[0].status === 'fail'); }); g.test('throws').fn(async t0 => { const g = makeTestGroupForUnitTesting(UnitTest); g.test('a').fn(_t => { throw new Error(); }); const result = await t0.run(g); const values = Array.from(result.values()); t0.expect(values.length === 1); t0.expect(values[0].status === 'fail'); }); g.test('shouldThrow').fn(async t0 => { t0.shouldThrow('TypeError', () => { throw new TypeError(); }); const g = makeTestGroupForUnitTesting(UnitTest); g.test('a').fn(t => { t.shouldThrow('Error', () => { throw new TypeError(); }); }); const result = await t0.run(g); const values = Array.from(result.values()); t0.expect(values.length === 1); t0.expect(values[0].status === 'fail'); }); g.test('shouldReject').fn(async t0 => { t0.shouldReject( 'TypeError', (async () => { throw new TypeError(); })() ); const g = makeTestGroupForUnitTesting(UnitTest); g.test('a').fn(t => { t.shouldReject( 'Error', (async () => { throw new TypeError(); })() ); }); const result = await t0.run(g); // Fails even though shouldReject doesn't fail until after the test function ends const values = Array.from(result.values()); t0.expect(values.length === 1); t0.expect(values[0].status === 'fail'); });