Skip to content

Commit 86e9162

Browse files
committed
refactor: add setup instead
1 parent 09b2cad commit 86e9162

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

src/fixtures/file-system.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,13 @@ export class FileSystem {
6868
return this._instance.fs.rm(path);
6969
}
7070

71-
async export(path = "./", options = { excludes: [], includes: [] }) {
72-
return await this._instance.export(path, { ...options, format: "binary" });
71+
/** @internal */
72+
async export() {
73+
return await this._instance.export("./", { format: "binary" });
7374
}
7475

76+
/** @internal */
7577
async restore(snapshot: Uint8Array) {
76-
return await this._instance.mount(snapshot);
78+
return await this._instance.mount(new Uint8Array(snapshot));
7779
}
7880
}

src/fixtures/index.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import { WebContainer } from "./webcontainer";
66
export interface TestContext {
77
preview: Preview;
88
webcontainer: WebContainer;
9+
setup: (callback: () => Promise<void>, timers?: boolean) => Promise<void>;
10+
11+
/** @internal */
12+
_internalState: { current: Uint8Array | undefined };
913
}
1014

1115
/**
@@ -30,6 +34,9 @@ export interface TestContext {
3034
* ```
3135
*/
3236
export const test = base.extend<TestContext>({
37+
/** @internal */
38+
_internalState: { current: undefined },
39+
3340
preview: async ({ webcontainer }, use) => {
3441
await webcontainer.wait();
3542

@@ -60,4 +67,29 @@ export const test = base.extend<TestContext>({
6067

6168
await webcontainer.teardown();
6269
},
70+
71+
setup: async ({ _internalState, webcontainer }, use) => {
72+
await use(async (callback, timers = false) => {
73+
const start = timers ? performance.now() : 0;
74+
75+
if (_internalState.current) {
76+
await webcontainer.restore(_internalState.current);
77+
78+
if (timers) {
79+
console.log(`[restore] ${(performance.now() - start).toFixed(2)}ms`);
80+
}
81+
82+
return;
83+
}
84+
85+
await callback();
86+
87+
// save current state in fixture
88+
_internalState.current = await webcontainer.export();
89+
90+
if (timers) {
91+
console.log(`[setup] ${(performance.now() - start).toFixed(2)}ms`);
92+
}
93+
});
94+
},
6395
});

test/setup.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { beforeEach, expect } from "vitest";
2+
import { test, type TestContext } from "../src";
3+
4+
const counts = { setup: 0, beforeEach: 0 };
5+
6+
beforeEach<TestContext>(async ({ setup, webcontainer }) => {
7+
await setup(async () => {
8+
await webcontainer.writeFile("./example", "Hello world");
9+
counts.setup++;
10+
11+
expect(counts.setup).toBe(1);
12+
});
13+
14+
counts.beforeEach++;
15+
});
16+
17+
test.for([1, 2, 3])("state is restored %d", async (count, { webcontainer }) => {
18+
await expect(webcontainer.readFile("example")).resolves.toBe("Hello world");
19+
20+
// setup should always be called just once as it's cached
21+
expect(counts.setup).toBe(1);
22+
23+
// hook itself is called each time
24+
expect(counts.beforeEach).toBe(count);
25+
});

0 commit comments

Comments
 (0)