diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15a35fe..f8ac123 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: run: pnpm typecheck - name: Install Playwright Dependencies - run: pnpm exec playwright install chromium firefox --with-deps + run: pnpm exec playwright install chromium firefox --with-deps --only-shell - name: Test run: pnpm test @@ -48,7 +48,7 @@ jobs: uses: actions/upload-artifact@v4 if: failure() with: - name: vitest-screenshots + name: vitest-screenshots-${{ matrix.node-version }} path: test/__screenshots__ retention-days: 30 diff --git a/src/fixtures/webcontainer.ts b/src/fixtures/webcontainer.ts index df2a274..9b97512 100644 --- a/src/fixtures/webcontainer.ts +++ b/src/fixtures/webcontainer.ts @@ -1,5 +1,6 @@ import { commands } from "@vitest/browser/context"; import { + type BufferEncoding, type FileSystemTree, WebContainer as WebContainerApi, } from "@webcontainer/api"; @@ -50,6 +51,9 @@ export class WebContainer { async teardown() { await Promise.all(this._onExit.map((fn) => fn())); + // @ts-ignore -- internal + await this._instance._instance.teardown(); + this._instance.teardown(); this._instancePromise = undefined; } @@ -81,4 +85,28 @@ export class WebContainer { return output.trim(); } + + async readFile(path: string, encoding: BufferEncoding = "utf8") { + return this._instance.fs.readFile(path, encoding); + } + + async writeFile(path: string, data: string, encoding = "utf8") { + return this._instance.fs.writeFile(path, data, { encoding }); + } + + async rename(oldPath: string, newPath: string) { + return this._instance.fs.rename(oldPath, newPath); + } + + async mkdir(path: string) { + return this._instance.fs.mkdir(path); + } + + async readdir(path: string) { + return this._instance.fs.readdir(path); + } + + async rm(path: string) { + return this._instance.fs.rm(path); + } } diff --git a/test/file-system.test.ts b/test/file-system.test.ts new file mode 100644 index 0000000..90dd6c4 --- /dev/null +++ b/test/file-system.test.ts @@ -0,0 +1,42 @@ +import { expect } from "vitest"; +import { test } from "../src"; + +test("user can create files and folders into webcontainer", async ({ + webcontainer, +}) => { + await webcontainer.writeFile("/example", "Hello world"); + await webcontainer.mkdir("/folder"); + + await expect(webcontainer.readdir("/")).resolves.toStrictEqual([ + "example", + "folder", + ]); + await expect(webcontainer.readFile("/example")).resolves.toBe("Hello world"); +}); + +test("user can rename files and folders in webcontainer", async ({ + webcontainer, +}) => { + await webcontainer.writeFile("/example", "Hello world"); + await webcontainer.mkdir("/folder"); + + await webcontainer.rename("/example", "/example-2"); + await webcontainer.rename("/folder", "/folder-2"); + + await expect(webcontainer.readdir("/")).resolves.toStrictEqual([ + "example-2", + "folder-2", + ]); +}); + +test("user can remove files from webcontainer", async ({ webcontainer }) => { + await webcontainer.writeFile("/first", "1"); + await webcontainer.writeFile("/second", "2"); + await webcontainer.writeFile("/third", "3"); + + await webcontainer.rm("/second"); + await expect(webcontainer.readdir("/")).resolves.toStrictEqual([ + "first", + "third", + ]); +}); diff --git a/test/preview.test.ts b/test/preview.test.ts index 5fee135..dbf0fe9 100644 --- a/test/preview.test.ts +++ b/test/preview.test.ts @@ -11,3 +11,24 @@ test("user can see server output in preview", async ({ await preview.getByRole("heading", { level: 1, name: "Hello Vite!" }); }); + +test("user can see HMR changes in preview", async ({ + webcontainer, + preview, +}) => { + await webcontainer.mount("test/fixtures/starter-vite"); + + await webcontainer.runCommand("npm", ["install"]); + void webcontainer.runCommand("npm", ["run", "dev"]); + + await preview.getByRole("heading", { level: 1, name: "Hello Vite!" }); + + const content = await webcontainer.readFile("/src/main.js"); + + await webcontainer.writeFile( + "/src/main.js", + content.replace("Hello Vite!", "Modified title!"), + ); + + await preview.getByRole("heading", { level: 1, name: "Modified title!" }); +});