Source code
Revision control
Copy as Markdown
Other Tools
/* 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');
});