Repository navigation
bun test: --timings for duration-balanced --shard/--parallel, docs for --parallel & --isolate #36814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
bun test: --timings for duration-balanced --shard/--parallel, docs for --parallel & --isolate #36814
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
acf4225
bun test: --timings/--update-timings for duration-balanced --shard an…
Jarred-Sumner 1252f99
Address review: reserve a file per remaining shard, write empty table…
Jarred-Sumner b7c1f6f
timings: always write the merged table so later --shard reads stay co…
Jarred-Sumner 47cc330
test: assert the merged-table property directly instead of chaining a…
Jarred-Sumner 646e5db
docs: qualify chunk locality wording; write merged timings via tmp + …
Jarred-Sumner e0cd81a
bun test: accept --timings more than once and merge them; --update-ti…
Jarred-Sumner cb652c0
timings: treat `updated: []` as 'nothing measured' rather than absent…
Jarred-Sumner d345938
timings: drop `updated`; under --shard, --update-timings writes only …
Jarred-Sumner ca704be
bun test --parallel --no-isolate: let a worker keep one global/module…
Jarred-Sumner d313e37
bench: scope app suite configs (bunfig/jest/vitest + preload) under b…
Jarred-Sumner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,6 @@ | ||
| suite/ | ||
| node_modules/ | ||
| app/src/ | ||
| app/tests/ | ||
| app/preload.ts | ||
| app/*.json |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| [test] | ||
| preload = ["./preload.ts"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| /** @type {import('jest').Config} */ | ||
| module.exports = { | ||
| testEnvironment: "node", | ||
| roots: ["<rootDir>/tests"], | ||
| transform: { "^.+\\.tsx?$": ["@swc/jest"] }, | ||
| setupFilesAfterEnv: ["<rootDir>/preload.ts"], | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| // Generates a small "app": src/ modules that pull in zod, date-fns and lodash, | ||
| // plus N test files that each import the app barrel and run a handful of | ||
| // cheap assertions. Per-file cost is dominated by loading the module graph, | ||
| // which is the common shape for unit-test suites. The test files use global | ||
| // describe/test/expect so the identical suite runs under bun, vitest and jest. | ||
| import { mkdirSync, rmSync, writeFileSync } from "node:fs"; | ||
|
|
||
| const FILES = Number(process.argv[2] ?? 64); | ||
| const TESTS_PER_FILE = 8; | ||
| const ITEMS = Number(process.argv[3] ?? 200); | ||
| for (const [name, v, lo, hi] of [ | ||
| ["files", FILES, 1, 10_000], | ||
| ["items", ITEMS, 2, 1_000_000], | ||
| ] as const) { | ||
| if (!Number.isSafeInteger(v) || v < lo || v > hi) | ||
| throw new Error(`${name} must be an integer in [${lo}, ${hi}], got ${v}`); | ||
| } | ||
| const MODULES = 24; | ||
| const root = import.meta.dir; | ||
|
|
||
| rmSync(root + "/src", { recursive: true, force: true }); | ||
| rmSync(root + "/tests", { recursive: true, force: true }); | ||
| rmSync(root + "/preload.ts", { force: true }); | ||
| mkdirSync(root + "/src", { recursive: true }); | ||
| mkdirSync(root + "/tests", { recursive: true }); | ||
|
|
||
| for (let m = 0; m < MODULES; m++) { | ||
| writeFileSync( | ||
| `${root}/src/inventory${m}.ts`, | ||
| `import { z } from "zod"; | ||
| import { addDays, differenceInCalendarDays, parseISO } from "date-fns"; | ||
| import groupBy from "lodash/groupBy"; | ||
| import sortBy from "lodash/sortBy"; | ||
|
|
||
| export const Item${m} = z.object({ | ||
| id: z.string().uuid(), | ||
| name: z.string().min(1).max(64), | ||
| tags: z.array(z.string()).default([]), | ||
| price: z.number().nonnegative(), | ||
| createdAt: z.string().datetime(), | ||
| }); | ||
| export type Item${m} = z.infer<typeof Item${m}>; | ||
|
|
||
| export function make${m}(i: number): Item${m} { | ||
| return Item${m}.parse({ | ||
| id: "00000000-0000-4000-8000-" + String(i).padStart(12, "0"), | ||
| name: "item-" + i, | ||
| tags: i % 2 ? ["odd", "m${m}"] : ["even"], | ||
| price: i * 1.5, | ||
| createdAt: addDays(parseISO("2024-01-01T00:00:00Z"), i).toISOString(), | ||
| }); | ||
| } | ||
|
|
||
| export function summarize${m}(items: Item${m}[]) { | ||
| const byTag = groupBy(items, it => it.tags[0]); | ||
| const sorted = sortBy(items, it => -it.price); | ||
| const spanDays = items.length | ||
| ? differenceInCalendarDays(parseISO(items[items.length - 1].createdAt), parseISO(items[0].createdAt)) | ||
| : 0; | ||
| return { tags: Object.keys(byTag).sort(), top: sorted[0]?.name ?? null, spanDays }; | ||
| } | ||
| `, | ||
| ); | ||
| } | ||
|
|
||
| let barrel = ""; | ||
| for (let m = 0; m < MODULES; m++) barrel += `export * from "./inventory${m}";\n`; | ||
| writeFileSync(`${root}/src/index.ts`, barrel); | ||
|
|
||
| for (let f = 0; f < FILES; f++) { | ||
| const m = f % MODULES; | ||
| let body = `import { Item${m}, make${m}, summarize${m} } from "../src";\n\n`; | ||
| body += `describe("inventory${m} (file ${f})", () => {\n`; | ||
| for (let t = 0; t < TESTS_PER_FILE; t++) { | ||
| body += ` test("case ${t}", () => { | ||
| const items = Array.from({ length: ${ITEMS + t} }, (_, i) => make${m}(i)); | ||
| const s = summarize${m}(items); | ||
| expect(s.top).toBe("item-${ITEMS - 1 + t}"); | ||
| expect(s.spanDays).toBe(${ITEMS - 1 + t}); | ||
| expect(s.tags).toEqual(["even", "odd"]); | ||
| expect(Item${m}.safeParse({ id: "nope" }).success).toBe(false); | ||
| (expect(items[0]) as any).toBeItemNamed("item-0"); | ||
| expect((globalThis as any).__fixture).toBeDefined(); | ||
| });\n`; | ||
| } | ||
| body += `});\n`; | ||
| writeFileSync(`${root}/tests/inventory${String(f).padStart(4, "0")}.test.ts`, body); | ||
| } | ||
|
|
||
| // A setup file every runner loads before each test file (bun --preload, | ||
| // jest setupFilesAfterEnv, vitest setupFiles): a custom matcher + a global hook. | ||
| writeFileSync( | ||
| `${root}/preload.ts`, | ||
| `import { make0 } from "./src"; | ||
|
|
||
| expect.extend({ | ||
| toBeItemNamed(received: unknown, name: string) { | ||
| const pass = typeof received === "object" && received !== null && (received as any).name === name; | ||
| return { pass, message: () => \`expected \${JSON.stringify(received)} to be an item named \${name}\` }; | ||
| }, | ||
| }); | ||
|
|
||
| let made = 0; | ||
| beforeEach(() => { | ||
| made++; | ||
| (globalThis as any).__fixture = make0(made); | ||
| }); | ||
| afterEach(() => { | ||
| (globalThis as any).__fixture = undefined; | ||
| }); | ||
| `, | ||
| ); | ||
|
|
||
| console.log(`wrote ${MODULES} src modules, preload.ts and ${FILES} test files × ${TESTS_PER_FILE} tests to ${root}`); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import { defineConfig } from "vitest/config"; | ||
|
|
||
| export default defineConfig({ | ||
| test: { | ||
| globals: true, | ||
| environment: "node", | ||
| include: ["tests/**/*.test.ts"], | ||
| setupFiles: ["./preload.ts"], | ||
| }, | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.