···8080 }>
8181 screenshot(options?: ScreenshotOptions): Promise<string>
8282 /**
8383+ * Add a trace marker when browser tracing is enabled.
8484+ */
8585+ mark(name: string, options?: { stack?: string }): Promise<void>
8686+ /**
8787+ * Group multiple operations under a trace marker when browser tracing is enabled.
8888+ */
8989+ mark<T>(name: string, body: () => T | Promise<T>, options?: { stack?: string }): Promise<T>
9090+ /**
8391 * Extend default `page` object with custom methods.
8492 */
8593 extend(methods: Partial<BrowserPage>): BrowserPage
···114122::: warning WARNING <Version>3.2.0</Version>
115123Note that `screenshot` will always return a base64 string if `save` is set to `false`.
116124The `path` is also ignored in that case.
125125+:::
126126+127127+### mark
128128+129129+```ts
130130+function mark(name: string, options?: { stack?: string }): Promise<void>
131131+function mark<T>(
132132+ name: string,
133133+ body: () => T | Promise<T>,
134134+ options?: { stack?: string },
135135+): Promise<T>
136136+```
137137+138138+Adds a named marker to the trace timeline for the current test.
139139+140140+Pass `options.stack` to override the callsite location in trace metadata. This is useful for wrapper libraries that need to preserve the end-user source location.
141141+142142+If you pass a callback, Vitest creates a trace group with this name, runs the callback, and closes the group automatically.
143143+144144+```ts
145145+import { page } from 'vitest/browser'
146146+147147+await page.mark('before submit')
148148+await page.getByRole('button', { name: 'Submit' }).click()
149149+await page.mark('after submit')
150150+151151+await page.mark('submit flow', async () => {
152152+ await page.getByRole('textbox', { name: 'Email' }).fill('john@example.com')
153153+ await page.getByRole('button', { name: 'Submit' }).click()
154154+})
155155+```
156156+157157+::: tip
158158+This method is useful only when [`browser.trace`](/config/browser/trace) is enabled.
117159:::
118160119161### frameLocator
+24
docs/api/browser/locators.md
···820820The `path` is also ignored in that case.
821821:::
822822823823+### mark
824824+825825+```ts
826826+function mark(name: string, options?: { stack?: string }): Promise<void>
827827+```
828828+829829+Adds a named marker to the trace timeline and uses the current locator as marker context.
830830+831831+Pass `options.stack` to override the callsite location in trace metadata. This is useful for wrapper libraries that need to preserve the end-user source location.
832832+833833+```ts
834834+import { page } from 'vitest/browser'
835835+836836+const submitButton = page.getByRole('button', { name: 'Submit' })
837837+838838+await submitButton.mark('before submit')
839839+await submitButton.click()
840840+await submitButton.mark('after submit')
841841+```
842842+843843+::: tip
844844+This method is useful only when [`browser.trace`](/config/browser/trace) is enabled.
845845+:::
846846+823847### query
824848825849```ts
+59-2
docs/guide/browser/trace-view.md
···57575858The traces are available in reporters as [annotations](/guide/test-annotations). For example, in the HTML reporter, you can find the link to the trace file in the test details.
59596060+## Trace markers
6161+6262+You can add explicit named markers to make the trace timeline easier to read:
6363+6464+```ts
6565+import { page } from 'vitest/browser'
6666+6767+document.body.innerHTML = `
6868+ <button type="button">Sign in</button>
6969+`
7070+7171+await page.getByRole('button', { name: 'Sign in' }).mark('sign in button rendered')
7272+```
7373+7474+Both `page.mark(name)` and `locator.mark(name)` are available.
7575+7676+You can also group multiple operations under one marker with `page.mark(name, callback)`:
7777+7878+```ts
7979+await page.mark('sign in flow', async () => {
8080+ await page.getByRole('textbox', { name: 'Email' }).fill('john@example.com')
8181+ await page.getByRole('textbox', { name: 'Password' }).fill('secret')
8282+ await page.getByRole('button', { name: 'Sign in' }).click()
8383+})
8484+```
8585+8686+You can also wrap reusable helpers with [`vi.defineHelper()`](/api/vi#vi-defineHelper) so trace entries point to where the helper is called, not its internals:
8787+8888+```ts
8989+import { vi } from 'vitest'
9090+import { page } from 'vitest/browser'
9191+9292+const myRender = vi.defineHelper(async (content: string) => {
9393+ document.body.innerHTML = content
9494+ await page.elementLocator(document.body).mark('render helper')
9595+})
9696+9797+test('renders content', async () => {
9898+ await myRender('<button>Hello</button>') // trace points to this line
9999+})
100100+```
101101+60102## Preview
6110362104To open the trace file, you can use the Playwright Trace Viewer. Run the following command in your terminal:
···6911170112Alternatively, you can open the Trace Viewer in your browser at https://trace.playwright.dev and upload the trace file there.
711137272-## Limitations
114114+## Source Location
731157474-At the moment, Vitest cannot populate the "Sources" tab in the Trace Viewer. This means that while you can see the actions and screenshots captured during the test, you won't be able to view the source code of your tests directly within the Trace Viewer. You will need to refer back to your code editor to see the test implementation.
116116+When you open a trace, you'll notice that Vitest groups browser interactions and links them back to the exact line in your test that triggered them. This happens automatically for:
117117+118118+- `expect.element(...)` assertions
119119+- Interactive actions like `click`, `fill`, `type`, `hover`, `selectOptions`, `upload`, `dragAndDrop`, `tab`, `keyboard`, `wheel`, and screenshots
120120+121121+Under the hood, Playwright still records its own low-level action events as usual. Vitest wraps them with source-location groups so you can jump straight from the trace timeline to the relevant line in your test.
122122+123123+Keep in mind that plain assertions like `expect(value).toBe(...)` run in Node, not the browser, so they won't show up in the trace.
124124+125125+For anything not covered automatically, you can use `page.mark()` or `locator.mark()` to add your own trace groups — see [Trace markers](#trace-markers) above.
126126+127127+::: warning
128128+129129+Currently a source view of a trace can be only displayed properly when viewing it on the machine generated a trace with `playwright show-trace` CLI. This is expected to be fixed soon (see https://github.com/microsoft/playwright/pull/39307).
130130+131131+:::
···11# Browser Tests
2233+```sh
44+# run full test with all providers and all browsers
55+pnpm run test
66+77+# run only playwright provider + all browsers
88+pnpm run test:playwright
99+1010+# run only playwright provider + chromium
1111+BROWSER=chromium pnpm run test:playwright
1212+1313+# run specific fixture (default is playwright provider + all browsers)
1414+pnpm run test-fixtures --root ./fixtures/locators
1515+1616+# run specific fixture with selected provider and browser
1717+PROVIDER=webdriverio BROWSER=firefox pnpm run test-fixtures --root ./fixtures/locators
1818+```
1919+320## Using docker playwright
421522Some test suites don't support running it remotely (`fixtures/inspect` and `fixtures/insecure-context`).
···926pnpm docker up -d
10271128# Run tests with BROWSER_WS_ENDPOINT
1212-BROWSER_WS_ENDPOINT=ws://127.0.0.1:6677/ pnpm test:playwright
2929+BROWSER_WS_ENDPOINT=ws://127.0.0.1:6677/ pnpm run test:playwright
1330```