I will preface that I'm using Svelte through a non svelte-kit framework called Primate.run, if you're using svelte-kit, you don't need to do any of this, it is already setup out of the box.
With that out of the way, you may be using @testing-library/svelte along with @testing-library/user-event to fire events in a jsdom or happydom environment. This probably will work fine for you. So why consider using playwright in the first place? The "why" is covered extensively here so feel free to give that a quick glance.
The first thing you're going to need is to install a couple packages
The quick way is (although I haven't tested this):
npx vitest init browser
Or you can manually add the packages:
# @vitest/ui is optional
pnpm add -D vitest @vitest/browser vitest-browser-svelte @vitest/browser-playwright @sveltejs/vite-plugin-svelte @vitest/ui
Create a vitest.config.ts
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { playwright } from "@vitest/browser-playwright";
import { defineConfig } from "vitest/config";
export default defineConfig({
plugins: [
svelte({
compilerOptions: {
dev: true,
},
}),
],
test: {
include: [
"**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
],
browser: {
enabled: true,
provider: playwright(),
instances: [{ browser: "chromium" }],
},
setupFiles: ["./vitest-setup-client.ts"],
},
});
Create the setup file to get matchers in your test files
vitest-setup-client.ts
/// <reference types="@vitest/browser/matchers" />
Add the following scripts to your package.json scripts property:
"scripts": {
"test": "vitest run",
"test:ui": "vitest --ui", //if you added @vitest/ui
"test:watch": "vitest",
// ... other scripts
}
And create your first test file that tests a svelte component, here's an example of a simple component I have called step-header.svelte
<script lang="ts">
let { children }: { children: any } = $props();
</script>
<div
class="flex items-center justify-between relative bg-gray-100 dark:bg-[#242424] py-8"
>
{@render children?.()}
</div>
This is an arbitrary demonstration simply to show you how to add children as its not immediately obvious:
step-header.svelte.test.js
import { expect, test } from "vitest";
import { render } from "vitest-browser-svelte";
import { createChildrenSnippet } from "../../../../lib/test/utils.ts";
import StepHeader from "./step-header.svelte";
test("should display the step header", async () => {
const screen = render(StepHeader, {
children: createRawSnippet(() => ({
render: () => "Step Header",
setup: () => {},
}));
});
const element = screen.getByText("Step Header");
await expect.element(element).toBeInTheDocument();
});
Obviously its quite verbose to have to use createRawSnippet each time so you can extract it to a separate createChildrenSnippet function like so:
utils.ts
import { createRawSnippet } from "svelte";
export const createChildrenSnippet = (content: any) =>
createRawSnippet(() => ({
render: () => content,
setup: () => {},
}));
And here's the final test file:
import { expect, test } from "vitest";
import { render } from "vitest-browser-svelte";
import { createChildrenSnippet } from "../../../../lib/test/utils.ts";
import StepHeader from "./step-header.svelte";
test("should display the step header", async () => {
const screen = render(StepHeader, {
children: createChildrenSnippet("Step Header"),
});
const element = screen.getByText("Step Header");
await expect.element(element).toBeInTheDocument();
});
And that's it! Hope this helps someone.
Sources:
Top comments (0)