Skip to content

Commit 7a3fd9f

Browse files
committed
Fix bugs only
1 parent c338b2f commit 7a3fd9f

File tree

5 files changed

+241
-76
lines changed

5 files changed

+241
-76
lines changed

expect/_assertions_test.ts

+159-42
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,181 @@
11
// Copyright 2018-2025 the Deno authors. MIT license.
22

33
import { describe, it, test } from "@std/testing/bdd";
4+
import * as path from "@std/path";
5+
import { assertStringIncludes } from "@std/assert";
46
import { expect } from "./expect.ts";
57

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-
});
12-
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");
8+
Deno.test("expect.hasAssertions() API", async () => {
9+
const tempDirPath = await Deno.makeTempDir({
10+
prefix: "deno_std_has_assertions_",
2211
});
12+
try {
13+
const tempFilePath = path.join(tempDirPath, "has_assertions_test.ts");
14+
await Deno.writeTextFile(
15+
tempFilePath,
16+
`import { describe, it, test } from "@std/testing/bdd";
17+
import { expect } from "@std/expect";
2318
24-
// FIXME(eryue0220): This test should through `toThrowErrorMatchingSnapshot`
25-
test("test suite should throw an error", () => {
19+
describe("describe suite", () => {
20+
it("describe should throw an error", () => {
2621
expect.hasAssertions();
2722
});
2823
29-
test("test suite should pass", () => {
24+
it("describe should pass", () => {
3025
expect.hasAssertions();
3126
expect("a").toEqual("a");
3227
});
3328
});
3429
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-
});
30+
it("it() suite should throw an error", () => {
31+
expect.hasAssertions();
32+
});
4133
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-
});
34+
it("it() suite should pass", () => {
35+
expect.hasAssertions();
36+
expect("a").toEqual("a");
37+
});
4838
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-
});
39+
test("test suite should throw an error", () => {
40+
expect.hasAssertions();
41+
});
42+
43+
test("test suite should pass", () => {
44+
expect.hasAssertions();
45+
expect("a").toEqual("a");
46+
});
47+
`,
48+
);
49+
50+
const command = new Deno.Command(Deno.execPath(), {
51+
args: ["test", "--no-lock", tempDirPath],
52+
});
53+
const { stdout } = await command.output();
54+
const errorMessage = new TextDecoder().decode(stdout);
55+
56+
assertStringIncludes(
57+
errorMessage,
58+
"describe should throw an error ... FAILED",
59+
);
60+
assertStringIncludes(errorMessage, "describe should pass ... ok");
61+
assertStringIncludes(
62+
errorMessage,
63+
"it() suite should throw an error ... FAILED",
64+
);
65+
assertStringIncludes(errorMessage, "it() suite should pass ... ok");
66+
assertStringIncludes(
67+
errorMessage,
68+
"test suite should throw an error ... FAILED",
69+
);
70+
assertStringIncludes(errorMessage, "test suite should pass ... ok");
71+
72+
assertStringIncludes(
73+
errorMessage,
74+
"error: AssertionError: Expected at least one assertion to be called but received none",
75+
);
76+
} finally {
77+
await Deno.remove(tempDirPath, { recursive: true });
78+
}
79+
});
5580

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

internal/assertion_state.ts

+13
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

+37-10
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

+16-12
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

+16-12
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)