Skip to content

Commit 74f62f4

Browse files
feat: make __helpers available in all before hooks (#505)
1 parent 188da1e commit 74f62f4

File tree

4 files changed

+118
-9
lines changed

4 files changed

+118
-9
lines changed

packages/dom-evaluator/src/dom-test-evaluator.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ const READY_MESSAGE: ReadyEvent["data"] = { type: "ready" };
3131
declare global {
3232
var __FakeTimers: typeof FakeTimers;
3333
var assert: typeof chaiAssert;
34+
var __helpers: typeof helpers;
3435
}
3536

3637
// @ts-expect-error jQuery cannot be declared.
3738
globalThis.$ = jQuery;
3839
globalThis.__FakeTimers = FakeTimers;
3940
globalThis.assert = chaiAssert;
41+
globalThis.__helpers = helpers;
4042

4143
// Local storage is not accessible in a sandboxed iframe, so we need to mock it
4244
Object.defineProperty(globalThis, "localStorage", {
@@ -116,8 +118,6 @@ export class DOMTestEvaluator implements TestEvaluator {
116118
return o;
117119
};
118120

119-
const __helpers = helpers;
120-
121121
let Enzyme;
122122
if (opts.loadEnzyme) {
123123
let Adapter16;
@@ -135,10 +135,11 @@ export class DOMTestEvaluator implements TestEvaluator {
135135
this.#runTest = async function (rawTest: string): Promise<Fail | Pass> {
136136
this.#proxyConsole.on();
137137
try {
138-
const test = createAsyncIife(rawTest);
138+
const testWithBefore = `${opts.hooks?.beforeEach ?? ""};
139+
${rawTest}`;
140+
const test = createAsyncIife(testWithBefore);
139141

140-
await eval(`${opts.hooks?.beforeEach ?? ""}
141-
${test}`);
142+
await eval(test);
142143

143144
return { pass: true, ...this.#proxyConsole.flush() };
144145
} catch (err) {

packages/javascript-evaluator/src/javascript-test-evaluator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export class JavascriptTestEvaluator implements TestEvaluator {
6969
// eslint-disable-next-line @typescript-eslint/no-unused-vars
7070
const editableContents = opts.code?.editableContents ?? "";
7171
try {
72-
await eval(`${opts.hooks?.beforeEach ?? ""}
72+
await eval(`${opts.hooks?.beforeEach ?? ""};
7373
${opts.source};
7474
__userCodeWasExecuted = true;
7575
${test};`);

packages/python-evaluator/src/python-test-evaluator.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ import { format } from "../../shared/src/format";
2222
import { ProxyConsole } from "../../shared/src/proxy-console";
2323
import { createAsyncIife } from "../../shared/src/async-iife";
2424

25+
declare global {
26+
var __helpers: typeof helpers;
27+
}
28+
29+
globalThis.__helpers = helpers;
30+
2531
type EvaluatedTeststring = {
2632
test: () => Promise<unknown>;
2733
};
@@ -65,14 +71,13 @@ class PythonTestEvaluator implements TestEvaluator {
6571
const pyodide = await this.#setupPyodide();
6672
eval(opts.hooks?.beforeAll ?? "");
6773

68-
this.#runTest = async (testString): Promise<Pass | Fail> => {
74+
this.#runTest = async (rawTestString): Promise<Pass | Fail> => {
6975
this.#proxyConsole.on();
7076
const code = (opts.code?.contents ?? "").slice();
7177
/* eslint-disable @typescript-eslint/no-unused-vars */
7278
const editableContents = (opts.code?.editableContents ?? "").slice();
7379

7480
const { assert } = chai;
75-
const __helpers = helpers;
7681

7782
// Create fresh globals for each test
7883
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
@@ -111,7 +116,8 @@ input = __fake_input
111116
`);
112117

113118
try {
114-
eval(opts.hooks?.beforeEach ?? "");
119+
const testString = `${opts.hooks?.beforeEach ?? ""};
120+
${rawTestString}`;
115121
// Eval test string to get the test property
116122

117123
let evaluatedTestString;

packages/tests/integration-tests/index.test.ts

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-lines */
12
import "vitest-environment-puppeteer";
23
import { compileForTests } from "../../shared/tooling/webpack-compile";
34
import type { FCCTestRunner } from "../../main/src/index";
@@ -312,6 +313,21 @@ for(let i = 0; i < 3; i++) {
312313
});
313314
});
314315

316+
it("should handle beforeEach expressions without trailing semicolons", async () => {
317+
const result = await page.evaluate(async (type) => {
318+
const runner = await window.FCCTestRunner.createTestRunner({
319+
type,
320+
hooks: {
321+
beforeEach: "let x = 1;Array()",
322+
},
323+
});
324+
const one = await runner.runTest("(assert.equal(x, 1))");
325+
return one;
326+
}, type);
327+
328+
expect(result).toEqual({ pass: true });
329+
});
330+
315331
it("should evaluate the beforeEach hook before each test", async () => {
316332
const result = await page.evaluate(async (type) => {
317333
const runner = await window.FCCTestRunner.createTestRunner({
@@ -1146,6 +1162,27 @@ checkBtn.click();
11461162

11471163
expect(result).toEqual({ pass: true });
11481164
});
1165+
1166+
it("should make __helpers available in before hooks", async () => {
1167+
const result = await page.evaluate(async () => {
1168+
const runner = await window.FCCTestRunner.createTestRunner({
1169+
type: "dom",
1170+
hooks: {
1171+
beforeEach:
1172+
"const before = __helpers.removeJSComments('before // this')",
1173+
beforeAll:
1174+
"const beforeall = __helpers.removeJSComments('before all // this')",
1175+
},
1176+
});
1177+
1178+
return runner.runAllTests([
1179+
"assert.equal(before, 'before ')",
1180+
"assert.equal(beforeall, 'before all ')",
1181+
]);
1182+
});
1183+
1184+
expect(result).toEqual([{ pass: true }, { pass: true }]);
1185+
});
11491186
});
11501187

11511188
describe("Javascript evaluator", () => {
@@ -1221,6 +1258,49 @@ checkBtn.click();
12211258
},
12221259
});
12231260
});
1261+
1262+
it("should make __helpers available in before hooks", async () => {
1263+
const result = await page.evaluate(async () => {
1264+
const runner = await window.FCCTestRunner.createTestRunner({
1265+
type: "javascript",
1266+
hooks: {
1267+
beforeEach:
1268+
"const before = __helpers.removeJSComments('before // this')",
1269+
beforeAll:
1270+
"globalThis.beforeall = __helpers.removeJSComments('before all // this')",
1271+
},
1272+
});
1273+
1274+
return runner.runAllTests([
1275+
"assert.equal(before, 'before ')",
1276+
"assert.equal(globalThis.beforeall, 'before all ')",
1277+
]);
1278+
});
1279+
1280+
expect(result).toEqual([{ pass: true }, { pass: true }]);
1281+
});
1282+
1283+
// Weird edge case, but if the user code starts with an opening bracket and
1284+
// the beforeEach hook does not end with a semicolon, the combination of the
1285+
// two could be interpreted as a function call. In this case
1286+
// Array()( { key: 'value' }) )
1287+
// and that's a TypeError.
1288+
it("should handle user code with leading brackets", async () => {
1289+
const source = `({ key: 'value' })`;
1290+
const result = await page.evaluate(async (source) => {
1291+
const runner = await window.FCCTestRunner.createTestRunner({
1292+
source,
1293+
code: { contents: source },
1294+
type: "javascript",
1295+
hooks: {
1296+
beforeEach: "Array()",
1297+
},
1298+
});
1299+
return runner.runTest("(assert.equal(code, '({ key: \\'value\\' })'))");
1300+
}, source);
1301+
1302+
expect(result).toEqual({ pass: true });
1303+
});
12241304
});
12251305

12261306
describe("Python evaluator", () => {
@@ -1530,5 +1610,27 @@ pattern = re.compile('l+')`;
15301610

15311611
expect(result).toEqual({ pass: true });
15321612
});
1613+
1614+
it("should make __helpers available in before hooks", async () => {
1615+
const result = await page.evaluate(async () => {
1616+
const runner = await window.FCCTestRunner.createTestRunner({
1617+
type: "python",
1618+
hooks: {
1619+
beforeEach:
1620+
"const before = __helpers.removeJSComments('before // this'); await ''",
1621+
beforeAll:
1622+
"globalThis.beforeall = __helpers.removeJSComments('before all // this')",
1623+
},
1624+
});
1625+
1626+
return runner.runAllTests([
1627+
"assert.equal(before, 'before ')",
1628+
"({test: () => { assert.equal(before, 'before ')}})",
1629+
"assert.equal(globalThis.beforeall, 'before all ')",
1630+
]);
1631+
});
1632+
1633+
expect(result).toEqual([{ pass: true }, { pass: true }, { pass: true }]);
1634+
});
15331635
});
15341636
});

0 commit comments

Comments
 (0)