测试
Nuxt 通过 @nuxt/test-utils
为你的 Nuxt 应用提供一流的端到端和单元测试支持。@nuxt/test-utils
是一个测试实用程序和配置库,目前支持 我们在 Nuxt 本身上使用的测试 并在整个模块生态系统中进行测试。
¥Nuxt offers first-class support for end-to-end and unit testing of your Nuxt application via @nuxt/test-utils
, a library of test utilities and configuration that currently powers the tests we use on Nuxt itself and tests throughout the module ecosystem.
安装
¥Installation
为了允许你管理其他测试依赖,@nuxt/test-utils
附带了各种可选的对等依赖。例如:
¥In order to allow you to manage your other testing dependencies, @nuxt/test-utils
ships with various optional peer dependencies. For example:
- 你可以选择
happy-dom
或jsdom
作为 Nuxt 运行时环境。 - 你可以选择
vitest
、cucumber
、jest
和playwright
作为端到端测试运行器。 - 仅当你希望使用内置浏览器测试实用程序(并且不使用
@playwright/test
作为测试运行器)时才需要playwright-core
。
npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
yarn add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
pnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
bun add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
单元测试
¥Unit Testing
我们目前提供了一个需要 Nuxt 运行时环境的单元测试代码环境。它目前仅支持 vitest
(尽管欢迎贡献以添加其他运行时)。
¥We currently ship an environment for unit testing code that needs a Nuxt runtime environment. It currently only has support for vitest
(although contribution to add other runtimes would be welcome).
设置
¥Setup
- 将
@nuxt/test-utils/module
添加到你的nuxt.config
文件(可选)。它将 Vitest 集成添加到你的 Nuxt DevTools,以支持在开发环境中运行单元测试。export default defineNuxtConfig({ modules: [ '@nuxt/test-utils/module' ] })
- 创建一个包含以下内容的
vitest.config.ts
:import { defineVitestConfig } from '@nuxt/test-utils/config' export default defineVitestConfig({ // any custom Vitest config you require })
@nuxt/test-utils
时,需要在 package.json
中指定 "type": "module"
,或者适当地重命名 vitest 配置文件。例如 vitest.config.m{ts,js}
。.env.test
文件设置用于测试的环境变量。使用 Nuxt 运行时环境
¥Using a Nuxt Runtime Environment
默认情况下,@nuxt/test-utils
不会更改你的默认 Vitest 环境,因此你可以进行细粒度的选择加入,并将 Nuxt 测试与其他单元测试一起运行。
¥By default, @nuxt/test-utils
will not change your default Vitest environment, so you can do fine-grained opt-in and run Nuxt tests together with other unit tests.
你可以通过在测试文件的名称中添加 .nuxt.
(例如 my-file.nuxt.test.ts
或 my-file.nuxt.spec.ts
)或在测试文件中直接添加 @vitest-environment nuxt
作为注释来选择加入 Nuxt 环境。
¥You can opt in to a Nuxt environment by adding .nuxt.
to the test file's name (for example, my-file.nuxt.test.ts
or my-file.nuxt.spec.ts
) or by adding @vitest-environment nuxt
as a comment directly in the test file.
// @vitest-environment nuxt
import { test } from 'vitest'
test('my test', () => {
// ... test with Nuxt environment!
})
你也可以在 Vitest 配置中设置 environment: 'nuxt'
,以便为所有测试启用 Nuxt 环境。
¥You can alternatively set environment: 'nuxt'
in your Vitest configuration to enable the Nuxt environment for all tests.
// vitest.config.ts
import { fileURLToPath } from 'node:url'
import { defineVitestConfig } from '@nuxt/test-utils/config'
export default defineVitestConfig({
test: {
environment: 'nuxt',
// you can optionally set Nuxt-specific environment options
// environmentOptions: {
// nuxt: {
// rootDir: fileURLToPath(new URL('./playground', import.meta.url)),
// domEnvironment: 'happy-dom', // 'happy-dom' (default) or 'jsdom'
// overrides: {
// // other Nuxt config you want to pass
// }
// }
// }
}
})
如果你已默认设置 environment: 'nuxt'
,则可以根据需要选择退出每个测试文件的 默认环境。
¥If you have set environment: 'nuxt'
by default, you can then opt out of the default environment per test file as needed.
// @vitest-environment node
import { test } from 'vitest'
test('my test', () => {
// ... test without Nuxt environment!
})
happy-dom
或 jsdom
环境中运行。在测试运行之前,会初始化一个全局的 Nuxt 应用(例如,运行你在 app.vue
中定义的任何插件或代码)。¥When you run your tests within the Nuxt environment, they will be running in a happy-dom
or jsdom
environment. Before your tests run, a global Nuxt app will be initialized (including, for example, running any plugins or code you've defined in your app.vue
).这意味着你应该特别注意不要在测试中改变全局状态(或者,如果需要,请在测试结束后重置它)。¥This means you should take particular care not to mutate the global state in your tests (or, if you need to, to reset it afterwards).🎭 内置模拟
¥🎭 Built-In Mocks
@nuxt/test-utils
为 DOM 环境提供了一些内置模拟。
¥@nuxt/test-utils
provides some built-in mocks for the DOM environment.
intersectionObserver
默认 true
会创建一个不包含 IntersectionObserver API 任何功能的虚拟类。
¥Default true
, creates a dummy class without any functionality for the IntersectionObserver API
indexedDB
默认 false
使用 fake-indexeddb
创建 IndexedDB API 的功能模拟。
¥Default false
, uses fake-indexeddb
to create a functional mock of the IndexedDB API
这些可以在 vitest.config.ts
文件的 environmentOptions
部分进行配置:
¥These can be configured in the environmentOptions
section of your vitest.config.ts
file:
import { defineVitestConfig } from '@nuxt/test-utils/config'
export default defineVitestConfig({
test: {
environmentOptions: {
nuxt: {
mock: {
intersectionObserver: true,
indexedDb: true,
}
}
}
}
})
🛠️ 助手
¥🛠️ Helpers
@nuxt/test-utils
提供了许多辅助函数,使 Nuxt 应用的测试更加轻松。
¥@nuxt/test-utils
provides a number of helpers to make testing Nuxt apps easier.
mountSuspended
mountSuspended
允许你在 Nuxt 环境中挂载任何 Vue 组件,从而允许异步设置并从你的 Nuxt 插件访问注入。
¥mountSuspended
allows you to mount any Vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins.
mountSuspended
内部封装了 @vue/test-utils
中的 mount
,因此你可以查看 the Vue Test Utils documentation 来了解更多关于可以传递的选项以及如何使用此实用程序的信息。例如:
¥For example:
// tests/components/SomeComponents.nuxt.spec.ts
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { SomeComponent } from '#components'
it('can mount some component', async () => {
const component = await mountSuspended(SomeComponent)
expect(component.text()).toMatchInlineSnapshot(
'"This is an auto-imported component"'
)
})
// tests/components/SomeComponents.nuxt.spec.ts
import { mountSuspended } from '@nuxt/test-utils/runtime'
import App from '~/app.vue'
// tests/App.nuxt.spec.ts
it('can also mount an app', async () => {
const component = await mountSuspended(App, { route: '/test' })
expect(component.html()).toMatchInlineSnapshot(`
"<div>This is an auto-imported component</div>
<div> I am a global component </div>
<div>/</div>
<a href="/test"> Test link </a>"
`)
})
renderSuspended
renderSuspended
允许你使用 @testing-library/vue
在 Nuxt 环境中渲染任何 Vue 组件,从而允许异步设置和访问 Nuxt 插件的注入。
¥renderSuspended
allows you to render any Vue component within the Nuxt environment using @testing-library/vue
, allowing async setup and access to injections from your Nuxt plugins.
此设置应与测试库中的实用程序(例如 screen
和 fireEvent
)一起使用。在你的项目中安装 @testing-library/vue 即可使用这些资源。
¥This should be used together with utilities from Testing Library, e.g. screen
and fireEvent
. Install @testing-library/vue in your project to use these.
此外,测试库还依赖于测试全局变量进行清理。你应该在 Vitest 配置 中启用这些功能。
¥Additionally, Testing Library also relies on testing globals for cleanup. You should turn these on in your Vitest config.
传入的组件将在 <div id="test-wrapper"></div>
中渲染。
¥The passed in component will be rendered inside a <div id="test-wrapper"></div>
.
示例:
¥Examples:
// tests/components/SomeComponents.nuxt.spec.ts
import { renderSuspended } from '@nuxt/test-utils/runtime'
import { SomeComponent } from '#components'
import { screen } from '@testing-library/vue'
it('can render some component', async () => {
await renderSuspended(SomeComponent)
expect(screen.getByText('This is an auto-imported component')).toBeDefined()
})
// tests/App.nuxt.spec.ts
import { renderSuspended } from '@nuxt/test-utils/runtime'
import App from '~/app.vue'
it('can also render an app', async () => {
const html = await renderSuspended(App, { route: '/test' })
expect(html).toMatchInlineSnapshot(`
"<div id="test-wrapper">
<div>This is an auto-imported component</div>
<div> I am a global component </div>
<div>Index page</div><a href="/test"> Test link </a>
</div>"
`)
})
mockNuxtImport
mockNuxtImport
允许你模拟 Nuxt 的自动导入功能。例如,要模拟 useStorage
,你可以这样做:
¥mockNuxtImport
allows you to mock Nuxt's auto import functionality. For example, to mock useStorage
, you can do so like this:
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport('useStorage', () => {
return () => {
return { value: 'mocked storage' }
}
})
// your tests here
如果你需要模拟 Nuxt 导入并在测试之间提供不同的实现,你可以使用 vi.hoisted
创建并公开模拟,然后在 mockNuxtImport
中使用这些模拟。然后,你就可以访问模拟导入,并可以在测试之间更改实现。在每次测试之前或之后,请务必使用 恢复模拟 来撤消运行期间模拟状态的更改。
¥If you need to mock a Nuxt import and provide different implementations between tests, you can do it by creating and exposing your mocks using vi.hoisted
, and then use those mocks in mockNuxtImport
. You then have access to the mocked imports, and can change the implementation between tests. Be careful to restore mocks before or after each test to undo mock state changes between runs.
import { vi } from 'vitest'
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
const { useStorageMock } = vi.hoisted(() => {
return {
useStorageMock: vi.fn(() => {
return { value: 'mocked storage'}
})
}
})
mockNuxtImport('useStorage', () => {
return useStorageMock
})
// Then, inside a test
useStorageMock.mockImplementation(() => {
return { value: 'something else' }
})
mockComponent
mockComponent
允许你模拟 Nuxt 的组件。第一个参数可以是采用帕斯卡命名法 (PascalCase) 的组件名称,也可以是组件的相对路径。第二个参数是一个工厂函数,它返回模拟组件。
¥mockComponent
allows you to mock Nuxt's component.
The first argument can be the component name in PascalCase, or the relative path of the component.
The second argument is a factory function that returns the mocked component.
例如,要模拟 MyComponent
,你可以:
¥For example, to mock MyComponent
, you can:
import { mockComponent } from '@nuxt/test-utils/runtime'
mockComponent('MyComponent', {
props: {
value: String
},
setup(props) {
// ...
}
})
// relative path or alias also works
mockComponent('~/components/my-component.vue', async () => {
// or a factory function
return defineComponent({
setup(props) {
// ...
}
})
})
// or you can use SFC for redirecting to a mock component
mockComponent('MyComponent', () => import('./MockComponent.vue'))
// your tests here
注意:你无法在工厂函数中引用局部变量,因为它们会被提升。如果你需要访问 Vue API 或其他变量,则需要在工厂函数中导入它们。
¥Note: You can't reference local variables in the factory function since they are hoisted. If you need to access Vue APIs or other variables, you need to import them in your factory function.
import { mockComponent } from '@nuxt/test-utils/runtime'
mockComponent('MyComponent', async () => {
const { ref, h } = await import('vue')
return defineComponent({
setup(props) {
const counter = ref(0)
return () => h('div', null, counter.value)
}
})
})
registerEndpoint
registerEndpoint
允许你创建返回模拟数据的 Nitro 端点。如果你想测试一个向 API 发出请求以显示某些数据的组件,它会非常方便。
¥registerEndpoint
allows you create Nitro endpoint that returns mocked data. It can come in handy if you want to test a component that makes requests to API to display some data.
第一个参数是端点名称(例如 /test/
)。第二个参数是一个工厂函数,它返回模拟数据。
¥The first argument is the endpoint name (e.g. /test/
).
The second argument is a factory function that returns the mocked data.
例如,要模拟 /test/
端点,你可以执行以下操作:
¥For example, to mock /test/
endpoint, you can do:
import { registerEndpoint } from '@nuxt/test-utils/runtime'
registerEndpoint('/test/', () => ({
test: 'test-field'
}))
默认情况下,你的请求将使用 GET
方法发出。你可以使用另一种方法,将对象而不是函数设置为第二个参数。
¥By default, your request will be made using the GET
method. You may use another method by setting an object as the second argument instead of a function.
import { registerEndpoint } from '@nuxt/test-utils/runtime'
registerEndpoint('/test/', {
method: 'POST',
handler: () => ({ test: 'test-field' })
})
注意:如果你在组件中的请求发送到外部 API,你可以使用
baseURL
,然后使用 Nuxt 环境覆盖配置($test
)将其清空,这样你的所有请求都将发送到 Nitro 服务器。¥Note: If your requests in a component go to an external API, you can use
baseURL
and then make it empty using Nuxt Environment Override Config ($test
) so all your requests will go to Nitro server.
与端到端冲突测试
¥Conflict with End-To-End Testing
@nuxt/test-utils/runtime
和 @nuxt/test-utils/e2e
需要在不同的测试环境中运行,因此不能在同一个文件中使用。
¥@nuxt/test-utils/runtime
and @nuxt/test-utils/e2e
need to run in different testing environments and so can't be used in the same file.
如果你希望同时使用 @nuxt/test-utils
的端到端和单元测试功能,你可以将测试拆分成单独的文件。然后,你可以使用特殊的 // @vitest-environment nuxt
注释为每个文件指定一个测试环境,或者使用 .nuxt.spec.ts
扩展名命名你的运行时单元测试文件。
¥If you would like to use both the end-to-end and unit testing functionality of @nuxt/test-utils
, you can split your tests into separate files. You then either specify a test environment per-file with the special // @vitest-environment nuxt
comment, or name your runtime unit test files with the .nuxt.spec.ts
extension.
app.nuxt.spec.ts
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport('useStorage', () => {
return () => {
return { value: 'mocked storage' }
}
})
app.e2e.spec.ts
import { setup, $fetch } from '@nuxt/test-utils/e2e'
await setup({
setupTimeout: 10000,
})
// ...
@vue/test-utils
使用
¥Using @vue/test-utils
如果你更喜欢在 Nuxt 中单独使用 @vue/test-utils
进行单元测试,并且你只测试不依赖于 Nuxt 可组合项、自动导入或上下文的组件,则可以按照以下步骤进行设置。
¥If you prefer to use @vue/test-utils
on its own for unit testing in Nuxt, and you are only testing components which do not rely on Nuxt composables, auto-imports or context, you can follow these steps to set it up.
- 安装所需的依赖
npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue
yarn add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue
pnpm add -D vitest @vue/test-utils happy-dom @vitejs/plugin-vue
bun add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue
- 创建一个包含以下内容的
vitest.config.ts
:import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], test: { environment: 'happy-dom', }, });
- 在你的
package.json
中添加一个新命令进行测试"scripts": { "build": "nuxt build", "dev": "nuxt dev", ... "test": "vitest" },
- 创建一个简单的
<HelloWorld>
组件components/HelloWorld.vue
,其内容如下:<template> <p>Hello world</p> </template>
- 为这个新创建的组件
~/components/HelloWorld.spec.ts
创建一个简单的单元测试import { describe, it, expect } from 'vitest' import { mount } from '@vue/test-utils' import HelloWorld from './HelloWorld.vue' describe('HelloWorld', () => { it('component renders Hello world properly', () => { const wrapper = mount(HelloWorld) expect(wrapper.text()).toContain('Hello world') }) })
- 运行 vitest 命令
npm run test
yarn test
pnpm run test
bun run test
恭喜,你已准备好在 Nuxt 中使用 @vue/test-utils
进行单元测试!祝你测试愉快!
¥Congratulations, you're all set to start unit testing with @vue/test-utils
in Nuxt! Happy testing!
端到端测试
¥End-To-End Testing
对于端到端测试,我们支持 Vitest、Jest、Cucumber 和 Playwright 作为测试运行器。
¥For end-to-end testing, we support Vitest, Jest, Cucumber and Playwright as test runners.
设置
¥Setup
在每个使用 @nuxt/test-utils/e2e
辅助方法的 describe
块中,你都需要在开始之前设置测试上下文。
¥In each describe
block where you are taking advantage of the @nuxt/test-utils/e2e
helper methods, you will need to set up the test context before beginning.
import { describe, test } from 'vitest'
import { setup, $fetch } from '@nuxt/test-utils/e2e'
describe('My test', async () => {
await setup({
// test context options
})
test('my test', () => {
// ...
})
})
在后台,setup
会在 beforeAll
、beforeEach
、afterEach
和 afterAll
中执行一系列任务,以正确设置 Nuxt 测试环境。
¥Behind the scenes, setup
performs a number of tasks in beforeAll
, beforeEach
, afterEach
and afterAll
to set up the Nuxt test environment correctly.
请使用以下选项作为 setup
方法。
¥Please use the options below for the setup
method.
Nuxt 配置
¥Nuxt Config
rootDir
:要测试的 Nuxt 应用所在目录的路径。- 类型:
string
- 默认:
'.'
- 类型:
configFile
:配置文件的名称。- 类型:
string
- 默认:
'nuxt.config'
- 类型:
时间
¥Timings
setupTimeout
:setupTest
完成其工作所需的时间(以毫秒为单位)(这可能包括为 Nuxt 应用构建或生成文件,具体取决于传递的选项)。- 类型:
number
- 默认:
60000
- 类型:
功能
¥Features
build
:是否运行单独的构建步骤。- 类型:
boolean
- 默认:
true
(如果browser
或server
被禁用,或者提供了host
,则为false
)
- 类型:
server
:是否启动服务器以响应测试套件中的请求。- 类型:
boolean
- 默认:
true
(如果提供了host
,则为false
)
- 类型:
port
:如果提供,则将启动的测试服务器端口设置为该值。- 类型:
number | undefined
- 默认:
undefined
- 类型:
host
:如果提供,则提供一个用作测试目标的 URL,而不是构建和运行新的服务器。用于针对已部署的应用版本或已运行的本地服务器(这可以显著缩短测试执行时间)运行 "real" 端到端测试。参见 目标主机端到端示例如下。- 类型:
string
- 默认:
undefined
- 类型:
browser
:Nuxt 测试工具内部使用playwright
进行浏览器测试。如果设置了此选项,将启动浏览器,并可在后续测试套件中进行控制。- 类型:
boolean
- 默认:
false
- 类型:
browserOptions
- 类型:
object
具有以下属性type
:要启动的浏览器类型 -chromium
、firefox
或webkit
launch
:启动浏览器时将传递给 playwright 的选项object
模块。请参阅 完整的 API 参考。
- 类型:
runner
:指定测试套件的运行器。目前推荐使用 Vitest。- 类型:
'vitest' | 'jest' | 'cucumber'
- 默认:
'vitest'
- 类型:
Target host
端到端示例
¥Target host
end-to-end example
端到端测试的一个常见用例是针对在通常用于生产的相同环境中运行的已部署应用运行测试。
¥A common use-case for end-to-end testing is running the tests against a deployed application running in the same environment typically used for Production.
对于本地开发或自动部署管道,使用单独的本地服务器进行测试可能更高效,并且通常比允许测试框架在测试之间重建更快。
¥For local development or automated deploy pipelines, testing against a separate local server can be more efficient and is typically faster than allowing the test framework to rebuild between tests.
要使用单独的目标主机进行端到端测试,只需为 setup
函数的 host
属性提供所需的 URL。
¥To utilize a separate target host for end-to-end tests, simply provide the host
property of the setup
function with the desired URL.
import { setup, createPage } from '@nuxt/test-utils/e2e'
import { describe, it, expect } from 'vitest'
describe('login page', async () => {
await setup({
host: 'http://localhost:8787',
})
it('displays the email and password fields', async () => {
const page = await createPage('/login')
expect(await page.getByTestId('email').isVisible()).toBe(true)
expect(await page.getByTestId('password').isVisible()).toBe(true)
})
})
APIs
$fetch(url)
从上下文中获取 Nuxt 实例。
¥Get the HTML of a server-rendered page.
import { $fetch } from '@nuxt/test-utils/e2e'
const html = await $fetch('/')
fetch(url)
根据上述示例,使用以下命令获取 :
¥Get the response of a server-rendered page.
import { fetch } from '@nuxt/test-utils/e2e'
const res = await fetch('/')
const { body, headers } = res
url(path)
获取服务器渲染页面的响应。
¥Get the full URL for a given page (including the port the test server is running on.)
import { url } from '@nuxt/test-utils/e2e'
const pageUrl = url('/page')
// 'http://localhost:6840/page'
在浏览器中测试
¥Testing in a Browser
我们在 @nuxt/test-utils
中使用 Playwright 提供内置支持,可以通过编程方式或通过 Playwright 测试运行器进行测试。
¥We provide built-in support using Playwright within @nuxt/test-utils
, either programmatically or via the Playwright test runner.
createPage(url)
在 vitest
、jest
或 cucumber
中,你可以使用 createPage
创建已配置的 Playwright 浏览器实例,并(可选)将其指向正在运行的服务器的路径。你可以了解有关 在 Playwright 中文档 中可用的 API 方法的更多信息。
¥Within vitest
, jest
or cucumber
, you can create a configured Playwright browser instance with createPage
, and (optionally) point it at a path from the running server. You can find out more about the API methods available from in the Playwright documentation.
import { createPage } from '@nuxt/test-utils/e2e'
const page = await createPage('/page')
// you can access all the Playwright APIs from the `page` variable
使用 Playwright Test Runner 进行测试
¥Testing with Playwright Test Runner
我们还提供在 Playwright 测试运行器 中测试 Nuxt 的优质支持。
¥We also provide first-class support for testing Nuxt within the Playwright test runner.
npm i --save-dev @playwright/test @nuxt/test-utils
yarn add --dev @playwright/test @nuxt/test-utils
pnpm add -D @playwright/test @nuxt/test-utils
bun add --dev @playwright/test @nuxt/test-utils
你可以提供全局 Nuxt 配置,其配置细节与本节前面提到的 setup()
函数相同。
¥You can provide global Nuxt configuration, with the same configuration details as the setup()
function mentioned earlier in this section.
import { fileURLToPath } from 'node:url'
import { defineConfig, devices } from '@playwright/test'
import type { ConfigOptions } from '@nuxt/test-utils/playwright'
export default defineConfig<ConfigOptions>({
use: {
nuxt: {
rootDir: fileURLToPath(new URL('.', import.meta.url))
}
},
// ...
})
:
::
然后,你的测试文件应该直接从 @nuxt/test-utils/playwright
使用 expect
和 test
:
¥Your test file should then use expect
and test
directly from @nuxt/test-utils/playwright
:
import { expect, test } from '@nuxt/test-utils/playwright'
test('test', async ({ page, goto }) => {
await goto('/', { waitUntil: 'hydration' })
await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!')
})
你也可以直接在测试文件中配置 Nuxt 服务器:
¥You can alternatively configure your Nuxt server directly within your test file:
import { expect, test } from '@nuxt/test-utils/playwright'
test.use({
nuxt: {
rootDir: fileURLToPath(new URL('..', import.meta.url))
}
})
test('test', async ({ page, goto }) => {
await goto('/', { waitUntil: 'hydration' })
await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!')
})