mirror of
https://github.com/oven-sh/bun
synced 2026-02-12 03:48:56 +00:00
This implements the missing done callback feature in Bun's node:test implementation. When a test or hook function has a length >= 2 (for tests) or >= 1 (for hooks), it is treated as using the legacy Node.js error-first callback pattern. Key changes: - Added createDeferredCallback() utility to manage callback state - Updated createTest() to check fn.length and pass done callback when >= 2 - Updated createHook() to check fn.length and pass done callback when >= 1 - Added error detection for mixed callback+Promise usage - Added multiple invocation protection for done callback - Updated TypeScript types to support both callback and Promise signatures - Fixed missing kDefaultFilePath constant Tests: - Added 06-done-callback.js with passing tests for done callback usage - Added 07-done-callback-errors.js to verify error conditions - All existing node:test tests continue to pass Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
92 lines
3.0 KiB
TypeScript
92 lines
3.0 KiB
TypeScript
import { spawn } from "bun";
|
|
import { describe, expect, test } from "bun:test";
|
|
import { bunEnv, bunExe } from "harness";
|
|
import { join } from "node:path";
|
|
|
|
describe("node:test", () => {
|
|
test("should run basic tests", async () => {
|
|
const { exitCode, stderr } = await runTests(["01-harness.js"]);
|
|
expect({ exitCode, stderr }).toMatchObject({
|
|
exitCode: 0,
|
|
stderr: expect.stringContaining("0 fail"),
|
|
});
|
|
});
|
|
|
|
test("should run hooks in the right order", async () => {
|
|
const { exitCode, stderr } = await runTests(["02-hooks.js"]);
|
|
expect({ exitCode, stderr }).toMatchObject({
|
|
exitCode: 0,
|
|
stderr: expect.stringContaining("0 fail"),
|
|
});
|
|
});
|
|
|
|
test("should run tests with different variations", async () => {
|
|
const { exitCode, stderr } = await runTests(["03-test-variations.js"]);
|
|
expect({ exitCode, stderr }).toMatchObject({
|
|
exitCode: 0,
|
|
stderr: expect.stringContaining("0 fail"),
|
|
});
|
|
});
|
|
|
|
test("should run async tests", async () => {
|
|
const { exitCode, stderr } = await runTests(["04-async-tests.js"]);
|
|
expect({ exitCode, stderr }).toMatchObject({
|
|
exitCode: 0,
|
|
stderr: expect.stringContaining("0 fail"),
|
|
});
|
|
});
|
|
|
|
test("should run all tests from multiple files", async () => {
|
|
const { exitCode, stderr } = await runTests(["01-harness.js", "02-hooks.js"]);
|
|
expect({ exitCode, stderr }).toMatchObject({
|
|
exitCode: 0,
|
|
// 32 from 01-harness + 3 from 02-hooks
|
|
stderr: expect.stringContaining("35 pass"),
|
|
});
|
|
});
|
|
|
|
test("should throw NotImplementedError if you call test() or describe() inside another test()", async () => {
|
|
const { exitCode, stderr } = await runTests(["05-test-in-test.js"]);
|
|
expect({ exitCode, stderr }).toMatchObject({
|
|
exitCode: 0,
|
|
stderr: expect.stringContaining("0 fail"),
|
|
});
|
|
});
|
|
|
|
test("should support done callback for tests and hooks", async () => {
|
|
const { exitCode, stderr } = await runTests(["06-done-callback.js"]);
|
|
expect({ exitCode, stderr }).toMatchObject({
|
|
exitCode: 0,
|
|
stderr: expect.stringContaining("0 fail"),
|
|
});
|
|
});
|
|
|
|
test("should handle done callback error conditions", async () => {
|
|
const { exitCode, stderr } = await runTests(["07-done-callback-errors.js"]);
|
|
// Two tests should fail (error and promise+callback), one should pass (multiple calls is caught)
|
|
expect({ exitCode, stderr }).toMatchObject({
|
|
exitCode: 1,
|
|
stderr: expect.stringContaining("2 fail"),
|
|
});
|
|
});
|
|
});
|
|
|
|
async function runTests(filenames: string[]) {
|
|
const testPaths = filenames.map(filename => join(import.meta.dirname, "fixtures", filename));
|
|
const {
|
|
exited,
|
|
stdout: stdoutStream,
|
|
stderr: stderrStream,
|
|
} = spawn({
|
|
cmd: [bunExe(), "test", ...testPaths],
|
|
env: bunEnv,
|
|
stderr: "pipe",
|
|
});
|
|
const [exitCode, stdout, stderr] = await Promise.all([
|
|
exited,
|
|
new Response(stdoutStream).text(),
|
|
new Response(stderrStream).text(),
|
|
]);
|
|
return { exitCode, stdout, stderr };
|
|
}
|