Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 64 additions & 72 deletions docs/src/test-components-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,12 @@ pnpm dlx create-playwright --ct
```

</TabItem>

</Tabs>

This step creates several files in your workspace:

#### `playwright/index.html`

This file defines an html file that will be used to render components during testing.
It must contain element with `id="root"`, that's where components are mounted. It must
also link the script called `playwright/index.{js,ts,jsx,tsx}`.

```html
```html title="playwright/index.html"
<html lang="en">
<body>
<div id="root"></div>
Expand All @@ -93,12 +87,14 @@ also link the script called `playwright/index.{js,ts,jsx,tsx}`.
</html>
```

#### `playwright/index.ts`
This file defines an html file that will be used to render components during testing.
It must contain element with `id="root"`, that's where components are mounted. It must
also link the script called `playwright/index.{js,ts,jsx,tsx}`.

You can include stylesheets, apply theme and inject code into the page where
component is mounted using this script. It can be either a `.js`, `.ts`, `.jsx` or `.tsx` file.

```js
```js title="playwright/index.ts"
// Apply theme here, add anything your component needs at runtime here.
```

Expand Down Expand Up @@ -150,7 +146,7 @@ declare module '*.vue';
```

</TabItem>

<TabItem value="svelte">

```js
Expand Down Expand Up @@ -199,11 +195,7 @@ Refer to [Playwright config](./test-configuration.md) for configuring your proje

## Hooks

You can use `beforeMount` and `afterMount` hooks to configure your app. This lets you setup things like your app router, fake server etc. giving you the flexibility you need. You can also pass custom configuration from the `mount` call from a test, which is accessible from the `hooksConfig` fixture.

#### `playwright/index.{js,ts,jsx,tsx}`

This includes any config that needs to be run before or after mounting the component. An example of configuring a router is provided below:
You can use `beforeMount` and `afterMount` hooks to configure your app. This lets you setup things like your app router, fake server etc. giving you the flexibility you need. You can also pass custom configuration from the `mount` call from a test, which is accessible from the `hooksConfig` fixture. This includes any config that needs to be run before or after mounting the component. An example of configuring a router is provided below:

<Tabs
defaultValue="react"
Expand All @@ -230,8 +222,6 @@ This includes any config that needs to be run before or after mounting the compo
});
```

#### In your test file:

```js title="src/pages/ProductsPage.spec.tsx"
import { test, expect } from '@playwright/experimental-ct-react';
import type { HooksConfig } from '@playwright/test';
Expand Down Expand Up @@ -263,8 +253,6 @@ This includes any config that needs to be run before or after mounting the compo
});
```

#### In your test file:

```js title="src/pages/ProductsPage.spec.tsx"
import { test, expect } from '@playwright/experimental-ct-solid';
import type { HooksConfig } from '@playwright/test';
Expand Down Expand Up @@ -296,8 +284,6 @@ This includes any config that needs to be run before or after mounting the compo
});
```

#### In your test file:

```js title="src/pages/ProductsPage.spec.ts"
import { test, expect } from '@playwright/experimental-ct-vue';
import type { HooksConfig } from '@playwright/test';
Expand All @@ -314,7 +300,7 @@ This includes any config that needs to be run before or after mounting the compo
</TabItem>

<TabItem value="vue2">

```js title="playwright/index.ts"
import { beforeMount, afterMount } from '@playwright/experimental-ct-vue2/hooks';
import Router from 'vue-router';
Expand All @@ -331,7 +317,6 @@ This includes any config that needs to be run before or after mounting the compo
}
});
```
#### In your test file:

```js title="src/pages/ProductsPage.spec.ts"
import { test, expect } from '@playwright/experimental-ct-vue2';
Expand Down Expand Up @@ -363,29 +348,9 @@ Here is how this is achieved:

Playwright is using [Vite](https://vitejs.dev/) to create the components bundle and serve it.

## Known issues and limitations
## Frequently asked questions

### Q) I can't import anything other than the components from TSX/JSX/Component files

As per above, you can only import your components from your test file. If you have utility methods or constants in your TSX files, it is advised to extract them into the TS files and import those utility methods and constants from your component files and from your test files. That allows us to not load any of the component code in the Node-based test runner and keep Playwright fast at executing your tests.

### Q) I have a project that already uses Vite. Can I reuse the config?

At this point, Playwright is bundler-agnostic, so it is not reusing your existing Vite config. Your config might have a lot of things we won't be able to reuse. So for now, you would copy your path mappings and other high level settings into the `ctViteConfig` property of Playwright config.

```js
import { defineConfig } from '@playwright/experimental-ct-react';

export default defineConfig({
use: {
ctViteConfig: {
// ...
},
},
});
```

### Q) What's the difference between `@playwright/test` and `@playwright/experimental-ct-{react,svelte,vue,solid}`?
### What's the difference between `@playwright/test` and `@playwright/experimental-ct-{react,svelte,vue,solid}`?

```js
test('…', async ({ mount, page, context }) => {
Expand Down Expand Up @@ -439,7 +404,7 @@ test('should work', async ({ mount }) => {
```

</TabItem>

<TabItem value="svelte">

```js
Expand Down Expand Up @@ -483,33 +448,22 @@ Additionally, it adds some config options you can use in your `playwright-ct.con
Finally, under the hood, each test re-uses the `context` and `page` fixture as a speed optimization for Component Testing.
It resets them in between each test so it should be functionally equivalent to `@playwright/test`'s guarantee that you get a new, isolated `context` and `page` fixture per-test.

### Q) Can I use `@playwright/test` and `@playwright/experimental-ct-{react,svelte,vue,solid}`?

Yes. Use a Playwright Config for each and follow their respective guides ([E2E Playwright Test](https://playwright.dev/docs/intro), [Component Tests](https://playwright.dev/docs/test-components))
### I have a project that already uses Vite. Can I reuse the config?

### Q) Why can't I pass a variable to mount?

This is a [known issue](https://github.com/microsoft/playwright/issues/14401). The following pattern does not work:
At this point, Playwright is bundler-agnostic, so it is not reusing your existing Vite config. Your config might have a lot of things we won't be able to reuse. So for now, you would copy your path mappings and other high level settings into the `ctViteConfig` property of Playwright config.

```js
const app = <App />;
await mount(app);
```

results in

```txt
undefined: TypeError: Cannot read properties of undefined (reading 'map')
```

while this works:
import { defineConfig } from '@playwright/experimental-ct-react';

```js
await mount(<App />);
export default defineConfig({
use: {
ctViteConfig: {
// ...
},
},
});
```

### Q) How can I use Vite plugins?

You can specify plugins via Vite config for testing settings. Note that once you start specifying plugins, you are responsible for specifying the framework plugin as well, `vue()` in this case:

```js
Expand Down Expand Up @@ -557,7 +511,47 @@ export default defineConfig({
});
```

### Q) how can i test components that uses Pinia?
### How can I use router?

```js title="playwright/index.tsx"
import { beforeMount, afterMount } from '@playwright/experimental-ct-react/hooks';
import { BrowserRouter } from 'react-router-dom';
import '../src/assets/index.css';

export type HooksConfig = {
routing?: boolean;
}

beforeMount<HooksConfig>(async ({ hooksConfig, App }) => {
console.log(`Before mount: ${JSON.stringify(hooksConfig)}`);

if (hooksConfig?.routing)
return <BrowserRouter><App /></BrowserRouter>;
});

afterMount<HooksConfig>(async () => {
console.log(`After mount`);
});
```

```js title="src/test.spec.tsx"
import { test, expect } from '@playwright/experimental-ct-react';
import App from '@/App';
import type { HooksConfig } from '../playwright';

test('navigate to a page by clicking a link', async ({ page, mount }) => {
const component = await mount<HooksConfig>(<App />, {
hooksConfig: { routing: true },
});
await expect(component.getByRole('main')).toHaveText('Login');
await expect(page).toHaveURL('/');
await component.getByRole('link', { name: 'Dashboard' }).click();
await expect(component.getByRole('main')).toHaveText('Dashboard');
await expect(page).toHaveURL('/dashboard');
});
```

### How can I test components that uses Pinia?

Pinia needs to be initialized in `playwright/index.{js,ts,jsx,tsx}`. If you do this inside a `beforeMount` hook, the `initialState` can be overwritten on a per-test basis:

Expand Down Expand Up @@ -587,8 +581,6 @@ beforeMount<HooksConfig>(async ({ hooksConfig }) => {
});
```

#### In your test file:

```js title="src/pinia.spec.ts"
import { test, expect } from '@playwright/experimental-ct-vue';
import type { HooksConfig } from '@playwright/test';
Expand All @@ -597,7 +589,7 @@ import Store from './Store.vue';
test('override initialState ', async ({ mount }) => {
const component = await mount<HooksConfig>(Store, {
hooksConfig: {
store: { name: 'override initialState' }
store: { name: 'override initialState' }
}
});
await expect(component).toContainText('override initialState');
Expand Down