Skip to content

Commit e8acbcb

Browse files
authored
fix: attach a stable testid to default baseElement and container (#44)
1 parent 8b122d2 commit e8acbcb

File tree

7 files changed

+71
-3
lines changed

7 files changed

+71
-3
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"@types/react-dom": "^19.0.0",
8484
"@vitejs/plugin-react": "^4.3.3",
8585
"@vitest/browser-playwright": "^4.0.0-beta.15",
86+
"@vitest/utils": "^4.0.17",
8687
"bumpp": "^9.4.2",
8788
"changelogithub": "^0.13.9",
8889
"eslint": "^9.8.0",

pnpm-lock.yaml

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/pure.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
import type { Locator, LocatorSelectors, PrettyDOMOptions } from 'vitest/browser'
2-
import { page, utils } from 'vitest/browser'
2+
import { page, server, utils } from 'vitest/browser'
33
import React from 'react'
44
import type { Container } from 'react-dom/client'
55
import ReactDOMClient from 'react-dom/client'
6+
import { nanoid } from '@vitest/utils/helpers'
67

78
const { debug, getElementLocatorSelectors } = utils
89

10+
function getTestIdAttribute() {
11+
return server.config.browser.locators.testIdAttribute
12+
}
13+
14+
function ensureTestIdAttribute(element: HTMLElement) {
15+
if (!element.hasAttribute(getTestIdAttribute())) {
16+
element.setAttribute(getTestIdAttribute(), nanoid())
17+
}
18+
}
19+
920
let activeActs = 0
1021

1122
function setActEnvironment(env: boolean | undefined): void {
@@ -80,6 +91,11 @@ export async function render(
8091
container = baseElement.appendChild(document.createElement('div'))
8192
}
8293

94+
// Ensuring testid attributes exists so that the generated locators will be stable
95+
// https://github.com/vitest-community/vitest-browser-react/issues/42
96+
ensureTestIdAttribute(baseElement)
97+
ensureTestIdAttribute(container)
98+
8399
let root: ReactRoot
84100

85101
if (!mountedContainers.has(container)) {

test/__snapshots__/render.test.tsx.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

33
exports[`renders simple component 1`] = `
4-
<div>
4+
<div
5+
data-testid="stable-snapshot"
6+
>
57
<div>
68
Hello World
79
</div>

test/render-selector.test.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { expect, test } from 'vitest'
2+
import { render } from 'vitest-browser-react'
3+
import { page, server } from 'vitest/browser'
4+
5+
test('should apply and use a unique testid as the root selector when it does not exists', async () => {
6+
const screen = await render(<div>Render</div>)
7+
const selector = page.elementLocator(screen.baseElement).selector
8+
9+
expect(selector).toMatch(/^internal:testid=\[[^\]]*\]$/)
10+
})
11+
12+
test('should apply and use a unique testid as the locator selector when using default container', async () => {
13+
const screen = await render(<div>Render</div>)
14+
15+
expect(screen.locator.selector).toMatch(/^internal:testid=\[[^\]]*\]$/)
16+
})
17+
18+
test('should not override testid attribute if already set', async () => {
19+
document.body.setAttribute(server.config.browser.locators.testIdAttribute, 'custom-id')
20+
21+
const screen = await render(<div>Render</div>)
22+
const selector = page.elementLocator(screen.baseElement).selector
23+
24+
expect(selector).toBe(`internal:testid=[${server.config.browser.locators.testIdAttribute}="custom-id"s]`)
25+
})

test/render.test.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test, vi } from 'vitest'
2-
import { page, userEvent } from 'vitest/browser'
2+
import { page, server, userEvent } from 'vitest/browser'
33
import { Button } from 'react-aria-components'
44
import { Suspense } from 'react'
55
import { render } from 'vitest-browser-react'
@@ -10,6 +10,8 @@ import { SuspendedHelloWorld } from './fixtures/SuspendedHelloWorld'
1010
test('renders simple component', async () => {
1111
const screen = await render(<HelloWorld />)
1212
await expect.element(page.getByText('Hello World')).toBeVisible()
13+
14+
screen.container.setAttribute(server.config.browser.locators.testIdAttribute, 'stable-snapshot')
1315
expect(screen.container).toMatchSnapshot()
1416
})
1517

vitest.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export default defineConfig({
1616
test: { name: 'dev' },
1717
resolve: { conditions: ['vdev'] },
1818
},
19+
{
20+
extends: true,
21+
test: { name: 'selector-custom-attr', include: ['test/render-selector.test.tsx'], browser: { locators: { testIdAttribute: 'data-custom-test-id' } } },
22+
},
1923
],
2024
printConsoleTrace: true,
2125
browser: {

0 commit comments

Comments
 (0)