Compare commits

...

2 Commits

Author SHA1 Message Date
Jarred Sumner
5566676360 Add a test, turns out it doesn't work properly 2024-05-15 02:43:19 -07:00
Jarred Sumner
1de53665c8 [bun:test] Implement beforeEachFile and afterEachFile hooks 2024-05-12 19:05:52 -07:00
4 changed files with 141 additions and 4 deletions

View File

@@ -267,6 +267,14 @@ declare module "bun:test" {
* @param fn the function to run
*/
export function beforeEach(fn: (() => void | Promise<unknown>) | ((done: (err?: unknown) => void) => void)): void;
/**
*
* Run a function before each file. Equivalent to `beforeAll` except that it runs before each file instead of each test.
*
* @param fn the function to run
*/
export function beforeEachFile(fn: (() => void | Promise<unknown>) | ((done: (err?: unknown) => void) => void)): void;
/**
* Runs a function, once, after all the tests.
*
@@ -293,6 +301,14 @@ declare module "bun:test" {
* @param fn the function to run
*/
export function afterEach(fn: (() => void | Promise<unknown>) | ((done: (err?: unknown) => void) => void)): void;
/**
*
* Run a function after each file. Equivalent to `afterAll` except that it runs before each file instead of each test.
*
* @param fn the function to run
*/
export function afterEachFile(fn: (() => void | Promise<unknown>) | ((done: (err?: unknown) => void) => void)): void;
export interface TestOptions {
/**
* Sets the timeout for the test in milliseconds.

View File

@@ -88,8 +88,10 @@ pub const TestRunner = struct {
global_callbacks: struct {
beforeAll: std.ArrayListUnmanaged(JSC.JSValue) = .{},
beforeEachFile: std.ArrayListUnmanaged(JSC.JSValue) = .{},
beforeEach: std.ArrayListUnmanaged(JSC.JSValue) = .{},
afterEach: std.ArrayListUnmanaged(JSC.JSValue) = .{},
afterEachFile: std.ArrayListUnmanaged(JSC.JSValue) = .{},
afterAll: std.ArrayListUnmanaged(JSC.JSValue) = .{},
} = .{},
@@ -315,7 +317,7 @@ pub const Jest = struct {
else
.{ TestScope, DescribeScope };
const module = JSC.JSValue.createEmptyObject(globalObject, 13);
const module = JSC.JSValue.createEmptyObject(globalObject, 15);
const test_fn = JSC.NewFunction(globalObject, ZigString.static("test"), 2, ThisTestScope.call, false);
module.put(
@@ -407,8 +409,8 @@ pub const Jest = struct {
describe,
);
inline for (.{ "beforeAll", "beforeEach", "afterAll", "afterEach" }) |name| {
const function = if (outside_of_test)
inline for (.{ "beforeAll", "beforeEachFile", "beforeEach", "afterAll", "afterEachFile", "afterEach" }) |name| {
const function = if (comptime outside_of_test or strings.eqlComptime(name, "beforeEachFile") or strings.eqlComptime(name, "afterEachFile"))
JSC.NewFunction(globalObject, null, 1, globalHook(name), false)
else
JSC.NewRuntimeFunction(
@@ -845,6 +847,8 @@ pub const DescribeScope = struct {
beforeEach,
afterEach,
afterAll,
beforeEachFile,
afterEachFile,
};
pub threadlocal var active: ?*DescribeScope = null;
@@ -966,6 +970,7 @@ pub const DescribeScope = struct {
pub fn runGlobalCallbacks(globalThis: *JSC.JSGlobalObject, comptime hook: LifecycleHook) ?JSValue {
// global callbacks
var hooks = &@field(Jest.runner.?.global_callbacks, @tagName(hook));
defer {
if (comptime hook == .beforeAll or hook == .afterAll) {
hooks.clearAndFree(getAllocator(globalThis));

View File

@@ -1074,6 +1074,11 @@ pub const TestCommand = struct {
vm.onUnhandledRejectionCtx = null;
vm.onUnhandledRejection = jest.TestRunnerTask.onUnhandledRejection;
if (module.tests.items.len > 0) {
if (jest.DescribeScope.runGlobalCallbacks(vm.global, .beforeEachFile)) |err| {
_ = vm.uncaughtException(vm.global, err, true);
}
}
module.runTests(vm.global);
vm.eventLoop().tick();
@@ -1098,6 +1103,16 @@ pub const TestCommand = struct {
}
}
if (jest.Jest.runner.?.global_callbacks.afterEachFile.items.len > 0) {
if (jest.DescribeScope.runGlobalCallbacks(vm.global, .afterEachFile)) |err| {
_ = vm.uncaughtException(vm.global, err, true);
}
while (vm.active_tasks > 0) : (vm.eventLoop().flushImmediateQueue()) {
vm.eventLoop().tick();
}
}
vm.eventLoop().flushImmediateQueue();
switch (vm.aggressive_garbage_collection) {

View File

@@ -3,7 +3,7 @@ import { spawn, spawnSync } from "bun";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, test } from "bun:test";
import { mkdirSync, realpathSync, rmSync, writeFileSync, copyFileSync } from "fs";
import { mkdtemp, rm, writeFile } from "fs/promises";
import { bunEnv, bunExe } from "harness";
import { bunEnv, bunExe, tempDirWithFiles } from "harness";
import { tmpdir } from "os";
import { join, dirname } from "path";
@@ -654,3 +654,104 @@ describe("empty", () => {
await rm(test_dir, { force: true, recursive: true });
}
});
test.only("test afterEachFile & beforeEachFile", async () => {
const dir = tempDirWithFiles("test-hooks-beforeEachFile", {
"package.json": /* json */ `
{
"name": "test-hooks-beforeEachFile",
"version": "1.0.0",
"type": "module",
"scripts": {
"test": "bun test"
}
}
`,
"1.test.js": /* jsx */ `
import { test, expect } from "bun:test";
test("inner test in file #1", () => {
console.log("inner test");
});
`,
"2.test.js": /* jsx */ `
import { test, expect } from "bun:test";
test("inner test in file #2", () => {
console.log("inner test");
});
`,
"3.test.js": /* jsx */ `
import { test, expect } from "bun:test";
test("inner test in file #3", () => {
console.log("inner test");
});
`,
"4.empty.test.js": /* jsx */ `
import { test, expect } from "bun:test";
`,
"preload.js": /* js */ `
import { beforeEachFile, afterEachFile, beforeAll, beforeEach, afterEach, afterAll } from "bun:test";
beforeEachFile && beforeEachFile(() => {
console.log("beforeEachFile");
});
afterEachFile && afterEachFile(() => {
console.log("afterEachFile");
});
beforeAll(() => {
console.log("beforeAll");
});
beforeEach(() => {
console.log("beforeEach");
});
afterEach(() => {
console.log("afterEach");
});
afterAll(() => {
console.log("afterAll");
});
`,
});
const { stdout, exitCode } = spawnSync({
cmd: [bunExe(), "test", "--preload=./preload.js"],
cwd: dir,
env: bunEnv,
stdio: ["ignore", "pipe", "inherit"],
});
const lines = stdout
.toString()
.trim()
.split("\n")
.map(a => a.trim());
expect(lines).toStrictEqual([
"beforeEachFile",
"beforeAll",
"beforeEach",
"inner test",
"afterEach",
"afterEachFile",
"beforeEachFile",
"beforeEach",
"inner test",
"afterEach",
"afterEachFile",
"beforeEachFile",
"beforeEach",
"inner test",
"afterEach",
"afterEachFile",
"afterAll",
]);
expect(exitCode).toBe(0);
});