All files / shared / test-context.ts

92.86% Branches 26/28
100.00% Functions 6/6
98.77% Lines 80/81
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
 
 
 
x4
x4
 
x4
x375
x375
x375
x375
x375
x375
x375
x375
x375
 
x375
 
x375
x375
x4
 
x4
x375
x254
x254
x254
x254
x254
x375
 
 
 
x4
x257
x9
x9
x9
 
x257
x2
x2
x2
x2
x2
 
x257
x257
 
x4
x246
x246
x246
x246
x246
 
x4
x249
x247
x1
x1
x1
x1
x1
x1
x247
x247
x247
x247
x247
 
x1
x1
x1
x1
x1
x1
x245
x1
x1
x1
x1
x1
x1
x244
x1
x1
x1
x1
x1
x1
x1
x249
x4






































I



I


















































import type Assert from './assert.ts';
import type ModuleContext from './module-context.ts';

export default class TestContext {
  static Assert: typeof Assert;

  name: string | undefined;
  module: ModuleContext | undefined;
  asyncOps: Promise<void>[] = [];
  assert: Assert | undefined;
  timeout: number | undefined;
  steps: string[] = [];
  stepsCount = 0;
  expectedAssertionCount: number | undefined;
  totalExecutedAssertions = 0;
  userContext: Record<string, unknown> = {};
  /** Set when the runner calls the test. One it never starts (filtered out by `only`) is not checked. */
  started = false;

  rejectTimeout: ((err: Error) => void) | undefined;
  #timeoutHandle: ReturnType<typeof setTimeout> | undefined;
  #timedOut = false;

  constructor(name?: string, moduleContext?: ModuleContext) {
    if (moduleContext) {
      this.name = `${moduleContext.name} | ${name}`;
      this.module = moduleContext;
      this.module.tests.push(this);
      this.assert = new TestContext.Assert(moduleContext, this);
    }
  }

  // 0 fires on the next macrotask: a synchronous test has finished by then, and any
  // other fails, which is what QUnit's `assert.timeout(0)` means.
  setTimeoutDuration(ms: number) {
    if (this.#timeoutHandle !== undefined) {
      clearTimeout(this.#timeoutHandle);
      this.#timeoutHandle = undefined;
    }
    if (!this.rejectTimeout) return;
    this.#timeoutHandle = setTimeout(() => {
      this.#timedOut = true;
      this.rejectTimeout!(new Error(
        ms === 0
          ? 'Test did not finish synchronously even though assert.timeout( 0 ) was used.'
          : `Test took longer than ${ms}ms; test timed out.`,
      ));
    }, ms);
  }

  clearTimeoutHandle() {
    if (this.#timeoutHandle !== undefined) {
      clearTimeout(this.#timeoutHandle);
      this.#timeoutHandle = undefined;
    }
  }

  finish() {
    if (!this.started || this.#timedOut) return;
    if (this.steps.length > 0) {
      this.assert!.pushResult({
        result: false,
        actual: this.steps,
        expected: [],
        message: `Expected assert.verifySteps() to be called before end of test after using assert.step(). Unverified steps: ${this.steps.join(', ')}`,
      });
    } else if (
      this.expectedAssertionCount !== undefined &&
      this.stepsCount > 0 &&
      this.expectedAssertionCount === this.totalExecutedAssertions + this.stepsCount
    ) {
      // The count QUnit 2 would have expected, which counted every assert.step() as well.
      this.assert!.pushResult({
        result: false,
        actual: this.totalExecutedAssertions,
        expected: this.expectedAssertionCount,
        message: `Expected ${this.expectedAssertionCount} assertions, but ${this.totalExecutedAssertions} were run for test: ${this.name}\nIt looks like you are upgrading from QUnit 2. Steps no longer count as separate assertions. https://qunitjs.com/api/assert/expect/`,
      });
    } else if (this.expectedAssertionCount !== undefined && this.expectedAssertionCount !== this.totalExecutedAssertions) {
      this.assert!.pushResult({
        result: false,
        actual: this.totalExecutedAssertions,
        expected: this.expectedAssertionCount,
        message: `Expected ${this.expectedAssertionCount} assertions, but ${this.totalExecutedAssertions} were run for test: ${this.name}`,
      });
    } else if (this.expectedAssertionCount === undefined && this.totalExecutedAssertions === 0) {
      this.assert!.pushResult({
        result: false,
        actual: this.totalExecutedAssertions,
        expected: '> 0',
        message: `Expected at least one assertion to be run for test: ${this.name}. Call assert.expect(0) to accept zero assertions.`,
      });
    }
  }
}