Skip to content

Commit a654f32

Browse files
committed
Fix bugs only
1 parent c338b2f commit a654f32

File tree

5 files changed

+241
-78
lines changed

5 files changed

+241
-78
lines changed

expect/_assertions_test.ts

Lines changed: 159 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,179 @@
11
// Copyright 2018-2025 the Deno authors. MIT license.
22

3-
import { describe, it, test } from "@std/testing/bdd";
4-
import { expect } from "./expect.ts";
5-
6-
Deno.test("expect.hasAssertions() API", () => {
7-
describe("describe suite", () => {
8-
// FIXME(eryue0220): This test should through `toThrowErrorMatchingSnapshot`
9-
it("should throw an error", () => {
10-
expect.hasAssertions();
11-
});
3+
import * as path from "@std/path";
4+
import { assertStringIncludes } from "@std/assert";
125

13-
it("should pass", () => {
14-
expect.hasAssertions();
15-
expect("a").toEqual("a");
16-
});
17-
});
18-
19-
it("it() suite should pass", () => {
20-
expect.hasAssertions();
21-
expect("a").toEqual("a");
6+
Deno.test("expect.hasAssertions() API", async () => {
7+
const tempDirPath = await Deno.makeTempDir({
8+
prefix: "deno_std_has_assertions_",
229
});
10+
try {
11+
const tempFilePath = path.join(tempDirPath, "has_assertions_test.ts");
12+
await Deno.writeTextFile(
13+
tempFilePath,
14+
`import { describe, it, test } from "@std/testing/bdd";
15+
import { expect } from "@std/expect";
2316
24-
// FIXME(eryue0220): This test should through `toThrowErrorMatchingSnapshot`
25-
test("test suite should throw an error", () => {
17+
describe("describe suite", () => {
18+
it("describe should throw an error", () => {
2619
expect.hasAssertions();
2720
});
2821
29-
test("test suite should pass", () => {
22+
it("describe should pass", () => {
3023
expect.hasAssertions();
3124
expect("a").toEqual("a");
3225
});
3326
});
3427
35-
Deno.test("expect.assertions() API", () => {
36-
test("should pass", () => {
37-
expect.assertions(2);
38-
expect("a").not.toBe("b");
39-
expect("a").toBe("a");
40-
});
28+
it("it() suite should throw an error", () => {
29+
expect.hasAssertions();
30+
});
4131
42-
// FIXME(eryue0220): This test should through `toThrowErrorMatchingSnapshot`
43-
test("should throw error", () => {
44-
expect.assertions(1);
45-
expect("a").not.toBe("b");
46-
expect("a").toBe("a");
47-
});
32+
it("it() suite should pass", () => {
33+
expect.hasAssertions();
34+
expect("a").toEqual("a");
35+
});
4836
49-
it("redeclare different assertion count", () => {
50-
expect.assertions(3);
51-
expect("a").not.toBe("b");
52-
expect("a").toBe("a");
53-
expect.assertions(2);
54-
});
37+
test("test suite should throw an error", () => {
38+
expect.hasAssertions();
39+
});
40+
41+
test("test suite should pass", () => {
42+
expect.hasAssertions();
43+
expect("a").toEqual("a");
44+
});
45+
`,
46+
);
47+
48+
const command = new Deno.Command(Deno.execPath(), {
49+
args: ["test", "--no-lock", tempDirPath],
50+
});
51+
const { stdout } = await command.output();
52+
const errorMessage = new TextDecoder().decode(stdout);
53+
54+
assertStringIncludes(
55+
errorMessage,
56+
"describe should throw an error ... FAILED",
57+
);
58+
assertStringIncludes(errorMessage, "describe should pass ... ok");
59+
assertStringIncludes(
60+
errorMessage,
61+
"it() suite should throw an error ... FAILED",
62+
);
63+
assertStringIncludes(errorMessage, "it() suite should pass ... ok");
64+
assertStringIncludes(
65+
errorMessage,
66+
"test suite should throw an error ... FAILED",
67+
);
68+
assertStringIncludes(errorMessage, "test suite should pass ... ok");
5569

56-
test("expect no assertions", () => {
57-
expect.assertions(0);
70+
assertStringIncludes(
71+
errorMessage,
72+
"error: AssertionError: Expected at least one assertion to be called but received none",
73+
);
74+
} finally {
75+
await Deno.remove(tempDirPath, { recursive: true });
76+
}
77+
});
78+
79+
Deno.test("expect.assertions() API", async () => {
80+
const tempDirPath = await Deno.makeTempDir({
81+
prefix: "deno_std_has_assertions_",
5882
});
83+
try {
84+
const tempFilePath = path.join(tempDirPath, "has_assertions_test.ts");
85+
await Deno.writeTextFile(
86+
tempFilePath,
87+
`import { describe, it, test } from "@std/testing/bdd";
88+
import { expect } from "@std/expect";
5989
60-
// FIXME(eryue0220): This test should through `toThrowErrorMatchingSnapshot`
61-
it("should throw an error", () => {
62-
expect.assertions(2);
90+
test("should pass", () => {
91+
expect.assertions(2);
92+
expect("a").not.toBe("b");
93+
expect("a").toBe("a");
94+
});
95+
96+
test("should throw error", () => {
97+
expect.assertions(1);
98+
expect("a").not.toBe("b");
99+
expect("a").toBe("a");
100+
});
101+
102+
it("redeclare different assertion count", () => {
103+
expect.assertions(3);
104+
expect("a").not.toBe("b");
105+
expect("a").toBe("a");
106+
expect.assertions(2);
107+
});
108+
109+
test("expect no assertions", () => {
110+
expect.assertions(0);
111+
});
112+
113+
it("should throw an error", () => {
114+
expect.assertions(2);
115+
});
116+
`,
117+
);
118+
119+
const command = new Deno.Command(Deno.execPath(), {
120+
args: ["test", "--no-lock", tempDirPath],
121+
});
122+
const { stdout } = await command.output();
123+
const errorMessage = new TextDecoder().decode(stdout);
124+
125+
assertStringIncludes(errorMessage, "should pass ... ok");
126+
assertStringIncludes(errorMessage, "should throw error ... FAILED");
127+
assertStringIncludes(
128+
errorMessage,
129+
"redeclare different assertion count ... ok",
130+
);
131+
assertStringIncludes(errorMessage, "expect no assertions ... ok");
132+
assertStringIncludes(errorMessage, "should throw an error ... FAILED");
133+
134+
assertStringIncludes(
135+
errorMessage,
136+
"error: AssertionError: Expected exactly 1 assertion to be called, but received 2",
137+
);
138+
assertStringIncludes(
139+
errorMessage,
140+
"error: AssertionError: Expected exactly 2 assertions to be called, but received 0",
141+
);
142+
} finally {
143+
await Deno.remove(tempDirPath, { recursive: true });
144+
}
145+
});
146+
147+
Deno.test("expect assertions reset after errored tests", async () => {
148+
const tempDirPath = await Deno.makeTempDir({
149+
prefix: "deno_std_assertions_reset_",
63150
});
151+
try {
152+
const tempFilePath = path.join(tempDirPath, "assertion_reset_test.ts");
153+
await Deno.writeTextFile(
154+
tempFilePath,
155+
`import { it } from "@std/testing/bdd";
156+
import { expect } from "@std/expect";
157+
it("should fail", () => {
158+
expect.assertions(2);
159+
expect(1).toBe(1);
160+
});
161+
it("should pass", () => {
162+
expect.assertions(0);
163+
});
164+
`,
165+
);
166+
167+
const command = new Deno.Command(Deno.execPath(), {
168+
args: ["test", "--no-lock", tempDirPath],
169+
});
170+
const { stdout } = await command.output();
171+
const errorMessage = new TextDecoder().decode(stdout);
172+
173+
assertStringIncludes(errorMessage, "should fail ... FAILED");
174+
// Previously "should fail" failing caused "should pass" to fail
175+
assertStringIncludes(errorMessage, "should pass ... ok");
176+
} finally {
177+
await Deno.remove(tempDirPath, { recursive: true });
178+
}
64179
});

internal/assertion_state.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ export class AssertionState {
2626
assertionTriggered: false,
2727
assertionTriggeredCount: 0,
2828
};
29+
30+
// If any checks were registered, `validateAndReset` should have been called
31+
// to reset and deregister the checks
32+
globalThis.addEventListener("unload", () => {
33+
if (
34+
this.#state.assertionCheck ||
35+
this.#state.assertionCount !== undefined
36+
) {
37+
throw new Error(
38+
"AssertionCounter was not cleaned up: If tests are not otherwise failing, ensure `expect.hasAssertion` and `expect.assertions` are only run in bdd tests",
39+
);
40+
}
41+
});
2942
}
3043

3144
/**

internal/assertion_state_test.ts

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,55 @@
11
// Copyright 2018-2025 the Deno authors. MIT license.
22

3-
import { assertEquals } from "@std/assert";
3+
import { assertEquals, assertStringIncludes } from "@std/assert";
44
import { AssertionState } from "./assertion_state.ts";
55

66
Deno.test("AssertionState checkAssertionErrorState pass", () => {
77
const assertionState = new AssertionState();
8-
assertionState.setAssertionTriggered(true);
9-
10-
assertEquals(assertionState.checkAssertionErrorState(), false);
8+
try {
9+
assertionState.setAssertionTriggered(true);
10+
assertEquals(assertionState.checkAssertionErrorState(), false);
11+
} finally {
12+
assertionState.resetAssertionState();
13+
}
1114
});
1215

1316
Deno.test("AssertionState checkAssertionErrorState pass", () => {
1417
const assertionState = new AssertionState();
15-
assertionState.setAssertionTriggered(true);
18+
try {
19+
assertionState.setAssertionTriggered(true);
1620

17-
assertEquals(assertionState.checkAssertionErrorState(), false);
21+
assertEquals(assertionState.checkAssertionErrorState(), false);
1822

19-
assertionState.setAssertionCheck(true);
20-
assertEquals(assertionState.checkAssertionErrorState(), false);
23+
assertionState.setAssertionCheck(true);
24+
assertEquals(assertionState.checkAssertionErrorState(), false);
25+
} finally {
26+
assertionState.resetAssertionState();
27+
}
2128
});
2229

2330
Deno.test("AssertionState checkAssertionErrorState fail", () => {
2431
const assertionState = new AssertionState();
25-
assertionState.setAssertionCheck(true);
32+
try {
33+
assertionState.setAssertionCheck(true);
34+
assertEquals(assertionState.checkAssertionErrorState(), true);
35+
} finally {
36+
assertionState.resetAssertionState();
37+
}
38+
});
2639

27-
assertEquals(assertionState.checkAssertionErrorState(), true);
40+
Deno.test("AssertionState throws if not cleaned up", async () => {
41+
const command = new Deno.Command(Deno.execPath(), {
42+
args: [
43+
"eval",
44+
`
45+
import { AssertionState } from "@std/internal/assertion-state";
46+
const assertionState = new AssertionState();
47+
assertionState.setAssertionCount(0);
48+
`,
49+
],
50+
});
51+
const { stderr } = await command.output();
52+
const errorMessage = new TextDecoder().decode(stderr);
53+
// TODO(WWRS): Test for the expected message when Deno displays it instead of "Uncaught null"
54+
assertStringIncludes(errorMessage, "error: Uncaught");
2855
});

testing/_test_suite.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -429,19 +429,23 @@ export class TestSuiteInternal<T> implements TestSuite<T> {
429429
await fn.call(context, t);
430430
}
431431

432-
if (assertionState.checkAssertionErrorState()) {
433-
throw new AssertionError(
434-
"Expected at least one assertion to be called but received none",
435-
);
436-
}
432+
try {
433+
if (assertionState.checkAssertionErrorState()) {
434+
throw new AssertionError(
435+
"Expected at least one assertion to be called but received none",
436+
);
437+
}
437438

438-
if (assertionState.checkAssertionCountSatisfied()) {
439-
throw new AssertionError(
440-
`Expected at least ${assertionState.assertionCount} assertion to be called, ` +
441-
`but received ${assertionState.assertionTriggeredCount}`,
442-
);
439+
if (assertionState.checkAssertionCountSatisfied()) {
440+
throw new AssertionError(
441+
`Expected exactly ${assertionState.assertionCount} ${
442+
assertionState.assertionCount === 1 ? "assertion" : "assertions"
443+
} to be called, ` +
444+
`but received ${assertionState.assertionTriggeredCount}`,
445+
);
446+
}
447+
} finally {
448+
assertionState.resetAssertionState();
443449
}
444-
445-
assertionState.resetAssertionState();
446450
}
447451
}

testing/bdd.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -600,20 +600,24 @@ export function it<T>(...args: ItArgs<T>) {
600600
TestSuiteInternal.runningCount--;
601601
}
602602

603-
if (assertionState.checkAssertionErrorState()) {
604-
throw new AssertionError(
605-
"Expected at least one assertion to be called but received none",
606-
);
607-
}
603+
try {
604+
if (assertionState.checkAssertionErrorState()) {
605+
throw new AssertionError(
606+
"Expected at least one assertion to be called but received none",
607+
);
608+
}
608609

609-
if (assertionState.checkAssertionCountSatisfied()) {
610-
throw new AssertionError(
611-
`Expected at least ${assertionState.assertionCount} assertion to be called, ` +
612-
`but received ${assertionState.assertionTriggeredCount}`,
613-
);
610+
if (assertionState.checkAssertionCountSatisfied()) {
611+
throw new AssertionError(
612+
`Expected exactly ${assertionState.assertionCount} ${
613+
assertionState.assertionCount === 1 ? "assertion" : "assertions"
614+
} to be called, ` +
615+
`but received ${assertionState.assertionTriggeredCount}`,
616+
);
617+
}
618+
} finally {
619+
assertionState.resetAssertionState();
614620
}
615-
616-
assertionState.resetAssertionState();
617621
},
618622
};
619623
if (ignore !== undefined) {

0 commit comments

Comments
 (0)