test_group.spec.ts (10311B)
1 /* eslint-disable @typescript-eslint/require-await */ 2 export const description = ` 3 Unit tests for TestGroup. 4 `; 5 6 import { Fixture } from '../common/framework/fixture.js'; 7 import { makeTestGroup } from '../common/framework/test_group.js'; 8 import { TestQueryMultiFile } from '../common/internal/query/query.js'; 9 import { kQueryMaxLength, makeTestGroupForUnitTesting } from '../common/internal/test_group.js'; 10 import { assert } from '../common/util/util.js'; 11 12 import { TestGroupTest } from './test_group_test.js'; 13 import { UnitTest } from './unit_test.js'; 14 15 export const g = makeTestGroup(TestGroupTest); 16 17 g.test('UnitTest_fixture').fn(async t0 => { 18 let seen = 0; 19 function count(_t: Fixture): void { 20 seen++; 21 } 22 23 const g = makeTestGroupForUnitTesting(UnitTest); 24 25 g.test('test').fn(count); 26 g.test('testp') 27 .paramsSimple([{ a: 1 }]) 28 .fn(count); 29 30 await t0.run(g); 31 t0.expect(seen === 2); 32 }); 33 34 g.test('custom_fixture').fn(async t0 => { 35 let seen = 0; 36 class Counter extends UnitTest { 37 count(): void { 38 seen++; 39 } 40 } 41 42 const g = makeTestGroupForUnitTesting(Counter); 43 44 g.test('test').fn(t => { 45 t.count(); 46 }); 47 g.test('testp') 48 .paramsSimple([{ a: 1 }]) 49 .fn(t => { 50 t.count(); 51 }); 52 53 await t0.run(g); 54 t0.expect(seen === 2); 55 }); 56 57 g.test('stack').fn(async t0 => { 58 const g = makeTestGroupForUnitTesting(UnitTest); 59 60 const doNestedThrow1 = () => { 61 throw new Error('goodbye'); 62 }; 63 64 const doNestedThrow2 = () => doNestedThrow1(); 65 66 g.test('fail').fn(t => { 67 t.fail(); 68 }); 69 g.test('throw').fn(_t => { 70 throw new Error('hello'); 71 }); 72 g.test('throw_nested').fn(_t => { 73 doNestedThrow2(); 74 }); 75 76 const res = await t0.run(g); 77 78 const search = /unittests[/\\]test_group\.spec\.[tj]s/; 79 t0.expect(res.size > 0); 80 for (const { logs } of res.values()) { 81 assert(logs !== undefined, 'expected logs'); 82 t0.expect(logs.some(l => search.test(l.toJSON()))); 83 t0.expect(search.test(logs[logs.length - 1].toJSON())); 84 } 85 }); 86 87 g.test('no_fn').fn(t => { 88 const g = makeTestGroupForUnitTesting(UnitTest); 89 90 g.test('missing'); 91 92 t.shouldThrow('Error', () => { 93 g.validate(new TestQueryMultiFile('s', ['f'])); 94 }); 95 }); 96 97 g.test('duplicate_test_name').fn(t => { 98 const g = makeTestGroupForUnitTesting(UnitTest); 99 g.test('abc').fn(() => {}); 100 101 t.shouldThrow('Error', () => { 102 g.test('abc').fn(() => {}); 103 }); 104 }); 105 106 g.test('duplicate_test_params,none').fn(() => { 107 { 108 const g = makeTestGroupForUnitTesting(UnitTest); 109 g.test('abc') 110 .paramsSimple([]) 111 .fn(() => {}); 112 g.validate(new TestQueryMultiFile('s', ['f'])); 113 } 114 115 { 116 const g = makeTestGroupForUnitTesting(UnitTest); 117 g.test('abc').fn(() => {}); 118 g.validate(new TestQueryMultiFile('s', ['f'])); 119 } 120 121 { 122 const g = makeTestGroupForUnitTesting(UnitTest); 123 g.test('abc') 124 .paramsSimple([ 125 { a: 1 }, // 126 ]) 127 .fn(() => {}); 128 g.validate(new TestQueryMultiFile('s', ['f'])); 129 } 130 }); 131 132 g.test('duplicate_test_params,basic').fn(t => { 133 { 134 const g = makeTestGroupForUnitTesting(UnitTest); 135 const builder = g.test('abc'); 136 t.shouldThrow('Error', () => { 137 builder.paramsSimple([ 138 { a: 1 }, // 139 { a: 1 }, 140 ]); 141 g.validate(new TestQueryMultiFile('s', ['f'])); 142 }); 143 } 144 { 145 const g = makeTestGroupForUnitTesting(UnitTest); 146 g.test('abc') 147 .params(u => 148 u.expandWithParams(() => [ 149 { a: 1 }, // 150 { a: 1 }, 151 ]) 152 ) 153 .fn(() => {}); 154 t.shouldThrow('Error', () => { 155 g.validate(new TestQueryMultiFile('s', ['f'])); 156 }); 157 } 158 { 159 const g = makeTestGroupForUnitTesting(UnitTest); 160 g.test('abc') 161 .paramsSimple([ 162 { a: 1, b: 3 }, // 163 { b: 3, a: 1 }, 164 ]) 165 .fn(() => {}); 166 t.shouldThrow('Error', () => { 167 g.validate(new TestQueryMultiFile('s', ['f'])); 168 }); 169 } 170 }); 171 172 g.test('duplicate_test_params,with_different_private_params').fn(t => { 173 { 174 const g = makeTestGroupForUnitTesting(UnitTest); 175 const builder = g.test('abc'); 176 t.shouldThrow('Error', () => { 177 builder.paramsSimple([ 178 { a: 1, _b: 1 }, // 179 { a: 1, _b: 2 }, 180 ]); 181 }); 182 } 183 { 184 const g = makeTestGroupForUnitTesting(UnitTest); 185 g.test('abc') 186 .params(u => 187 u.expandWithParams(() => [ 188 { a: 1, _b: 1 }, // 189 { a: 1, _b: 2 }, 190 ]) 191 ) 192 .fn(() => {}); 193 t.shouldThrow('Error', () => { 194 g.validate(new TestQueryMultiFile('s', ['f'])); 195 }); 196 } 197 }); 198 199 g.test('invalid_test_name').fn(t => { 200 const g = makeTestGroupForUnitTesting(UnitTest); 201 202 const badChars = Array.from('"`~@#$+=\\|!^&*[]<>{}-\'. '); 203 for (const char of badChars) { 204 const name = 'a' + char + 'b'; 205 t.shouldThrow( 206 'Error', 207 () => { 208 g.test(name).fn(() => {}); 209 }, 210 { message: name } 211 ); 212 } 213 }); 214 215 g.test('long_test_query,long_test_name').fn(t => { 216 const g = makeTestGroupForUnitTesting(UnitTest); 217 218 const long = Array(kQueryMaxLength - 5).join('a'); 219 220 const fileQuery = new TestQueryMultiFile('s', ['f']); 221 g.test(long).unimplemented(); 222 g.validate(fileQuery); 223 224 g.test(long + 'a').unimplemented(); 225 t.shouldThrow( 226 'Error', 227 () => { 228 g.validate(fileQuery); 229 }, 230 { message: long } 231 ); 232 }); 233 234 g.test('long_case_query,long_test_name').fn(t => { 235 const g = makeTestGroupForUnitTesting(UnitTest); 236 237 const long = Array(kQueryMaxLength - 5).join('a'); 238 239 const fileQuery = new TestQueryMultiFile('s', ['f']); 240 g.test(long).fn(() => {}); 241 g.validate(fileQuery); 242 243 g.test(long + 'a').fn(() => {}); 244 t.shouldThrow( 245 'Error', 246 () => { 247 g.validate(fileQuery); 248 }, 249 { message: long } 250 ); 251 }); 252 253 g.test('long_case_query,long_case_name').fn(t => { 254 const g = makeTestGroupForUnitTesting(UnitTest); 255 256 const long = Array(kQueryMaxLength - 9).join('a'); 257 258 const fileQuery = new TestQueryMultiFile('s', ['f']); 259 g.test('t') 260 .paramsSimple([{ x: long }]) 261 .fn(() => {}); 262 g.validate(fileQuery); 263 264 g.test('u') 265 .paramsSimple([{ x: long + 'a' }]) 266 .fn(() => {}); 267 t.shouldThrow( 268 'Error', 269 () => { 270 g.validate(fileQuery); 271 }, 272 { message: long } 273 ); 274 }); 275 276 g.test('param_value,valid').fn(() => { 277 const g = makeTestGroup(UnitTest); 278 g.test('a').paramsSimple([{ x: JSON.stringify({ a: 1, b: 2 }) }]); 279 }); 280 281 g.test('param_value,invalid').fn(t => { 282 for (const badChar of ';=*') { 283 const g = makeTestGroupForUnitTesting(UnitTest); 284 const builder = g.test('a'); 285 t.shouldThrow('Error', () => { 286 builder.paramsSimple([{ badChar }]); 287 }); 288 } 289 }); 290 291 g.test('subcases').fn(async t0 => { 292 const g = makeTestGroupForUnitTesting(UnitTest); 293 g.test('a') 294 .paramsSubcasesOnly(u => 295 u // 296 .combineWithParams([{ a: 1 }]) 297 ) 298 .fn(t => { 299 t.expect(t.params.a === 1, 'a must be 1'); 300 }); 301 302 function* gen({ a, b }: { a?: number; b?: number }) { 303 if (b === 2) { 304 yield { ret: 2 }; 305 } else if (a === 1) { 306 yield { ret: 1 }; 307 } else { 308 yield { ret: -1 }; 309 } 310 } 311 g.test('b') 312 .params(u => 313 u 314 .combineWithParams([{ a: 1 }, { b: 2 }]) 315 .beginSubcases() 316 .expandWithParams(gen) 317 ) 318 .fn(t => { 319 const { a, b, ret } = t.params; 320 t.expect((a === 1 && ret === 1) || (b === 2 && ret === 2)); 321 }); 322 323 const result = await t0.run(g); 324 t0.expect(Array.from(result.values()).every(v => v.status === 'pass')); 325 }); 326 327 g.test('subcases,skip') 328 .desc( 329 'If all tests are skipped then status is "skip". If at least one test passed, status is "pass"' 330 ) 331 .params(u => u.combine('allSkip', [false, true])) 332 .fn(async t0 => { 333 const { allSkip } = t0.params; 334 const g = makeTestGroupForUnitTesting(UnitTest); 335 g.test('a') 336 .params(u => u.beginSubcases().combine('do', ['pass', 'skip', 'pass'])) 337 .fn(t => { 338 t.skipIf(allSkip || t.params.do === 'skip'); 339 }); 340 const result = await t0.run(g); 341 const values = Array.from(result.values()); 342 t0.expect(values.length === 1); 343 const expectedStatus = allSkip ? 'skip' : 'pass'; 344 t0.expect( 345 values[0].status === expectedStatus, 346 `expect: ${values[0].status} === ${expectedStatus}, allSkip: ${allSkip}` 347 ); 348 }); 349 350 g.test('exceptions') 351 .params(u => 352 u 353 .combine('useSubcases', [false, true]) // 354 .combine('useDOMException', [false, true]) 355 ) 356 .fn(async t0 => { 357 const { useSubcases, useDOMException } = t0.params; 358 const g = makeTestGroupForUnitTesting(UnitTest); 359 360 const b1 = g.test('a'); 361 let b2; 362 if (useSubcases) { 363 b2 = b1.paramsSubcasesOnly(u => u); 364 } else { 365 b2 = b1.params(u => u); 366 } 367 b2.fn(_t => { 368 if (useDOMException) { 369 throw new DOMException('Message!', 'Name!'); 370 } else { 371 throw new Error('Message!'); 372 } 373 }); 374 375 const result = await t0.run(g); 376 const values = Array.from(result.values()); 377 t0.expect(values.length === 1); 378 t0.expect(values[0].status === 'fail'); 379 }); 380 381 g.test('throws').fn(async t0 => { 382 const g = makeTestGroupForUnitTesting(UnitTest); 383 384 g.test('a').fn(_t => { 385 throw new Error(); 386 }); 387 388 const result = await t0.run(g); 389 const values = Array.from(result.values()); 390 t0.expect(values.length === 1); 391 t0.expect(values[0].status === 'fail'); 392 }); 393 394 g.test('shouldThrow').fn(async t0 => { 395 t0.shouldThrow('TypeError', () => { 396 throw new TypeError(); 397 }); 398 399 const g = makeTestGroupForUnitTesting(UnitTest); 400 401 g.test('a').fn(t => { 402 t.shouldThrow('Error', () => { 403 throw new TypeError(); 404 }); 405 }); 406 407 const result = await t0.run(g); 408 const values = Array.from(result.values()); 409 t0.expect(values.length === 1); 410 t0.expect(values[0].status === 'fail'); 411 }); 412 413 g.test('shouldReject').fn(async t0 => { 414 t0.shouldReject( 415 'TypeError', 416 (async () => { 417 throw new TypeError(); 418 })() 419 ); 420 421 const g = makeTestGroupForUnitTesting(UnitTest); 422 423 g.test('a').fn(t => { 424 t.shouldReject( 425 'Error', 426 (async () => { 427 throw new TypeError(); 428 })() 429 ); 430 }); 431 432 const result = await t0.run(g); 433 // Fails even though shouldReject doesn't fail until after the test function ends 434 const values = Array.from(result.values()); 435 t0.expect(values.length === 1); 436 t0.expect(values[0].status === 'fail'); 437 });