Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1664,7 +1664,7 @@ Will call [`vi.unstubAllGlobals`](/api/vi#vi-unstuballglobals) before each test.

- **Type:** `PrettyFormatOptions`

Format options for snapshot testing. These options are passed down to [`pretty-format`](https://www.npmjs.com/package/pretty-format).
Format options for snapshot testing. These options are passed down to our fork of [`pretty-format`](https://www.npmjs.com/package/pretty-format). In addition to the `pretty-format` options we support `printShadowRoot: boolean`.

::: tip
Beware that `plugins` field on this object will be ignored.
Expand Down
33 changes: 33 additions & 0 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,39 @@ export default defineConfig({
})
```

### Snapshots using custom elements print the shadow root

In Vitest 4.0 snapshots that include custom elements will print the shadow root contents. To restore the previous behavior, set the [`printShadowRoot` option](/config/#snapshotformat) to `false`.

```js
// before Vite 4.0
exports[`custom element with shadow root 1`] = `
"<body>
<div>
<custom-element />
</div>
</body>"
`

// after Vite 4.0
exports[`custom element with shadow root 1`] = `
"<body>
<div>
<custom-element>
#shadow-root
<span
class="some-name"
data-test-id="33"
id="5"
>
hello
</span>
</custom-element>
</div>
</body>"
`
```

### Deprecated APIs are Removed

Vitest 4.0 removes some deprecated APIs, including:
Expand Down
2 changes: 2 additions & 0 deletions packages/pretty-format/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ export const DEFAULT_OPTIONS: Options = {
plugins: [],
printBasicPrototype: true,
printFunctionName: true,
printShadowRoot: true,
theme: DEFAULT_THEME,
} satisfies Options

Expand Down Expand Up @@ -519,6 +520,7 @@ function getConfig(options?: OptionsReceived): Config {
plugins: options?.plugins ?? DEFAULT_OPTIONS.plugins,
printBasicPrototype: options?.printBasicPrototype ?? true,
printFunctionName: getPrintFunctionName(options),
printShadowRoot: options?.printShadowRoot ?? true,
spacingInner: options?.min ? ' ' : '\n',
spacingOuter: options?.min ? '' : '\n',
}
Expand Down
6 changes: 5 additions & 1 deletion packages/pretty-format/src/plugins/DOMElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
printElement,
printElementAsLeaf,
printProps,
printShadowRoot,
printText,
} from './lib/markup'

Expand Down Expand Up @@ -109,7 +110,10 @@ export const serialize: NewPlugin['serialize'] = (
refs,
printer,
),
printChildren(
((nodeIsFragment(node) || !node.shadowRoot)
? ''
: printShadowRoot(Array.prototype.slice.call(node.shadowRoot.children), config, indentation + config.indent, depth, refs, printer))
+ printChildren(
Array.prototype.slice.call(node.childNodes || node.children),
config,
indentation + config.indent,
Expand Down
17 changes: 17 additions & 0 deletions packages/pretty-format/src/plugins/lib/markup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@ export function printChildren(children: Array<unknown>, config: Config, indentat
.join('')
}

export function printShadowRoot(children: Array<unknown>, config: Config, indentation: string, depth: number, refs: Refs, printer: Printer): string {
if (config.printShadowRoot === false) {
return ''
}
return [
`${config.spacingOuter + indentation}#shadow-root`,
printChildren(
children,
config,
indentation + config.indent,
depth,
refs,
printer,
),
].join('')
}

export function printText(text: string, config: Config): string {
const contentColor = config.colors.content
return contentColor.open + escapeHTML(text) + contentColor.close
Expand Down
2 changes: 2 additions & 0 deletions packages/pretty-format/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface PrettyFormatOptions {
min?: boolean
printBasicPrototype?: boolean
printFunctionName?: boolean
printShadowRoot?: boolean
compareKeys?: CompareKeys
plugins?: Plugins
}
Expand All @@ -67,6 +68,7 @@ export interface Config {
plugins: Plugins
printBasicPrototype: boolean
printFunctionName: boolean
printShadowRoot: boolean
spacingInner: string
spacingOuter: string
}
Expand Down
25 changes: 25 additions & 0 deletions test/browser/test/__snapshots__/utils.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ exports[`prints the element with attributes 1`] = `
</body>"
`;

exports[`should be able to opt out of shadow DOM content 1`] = `
"<body>
<div>
<no-shadow-root />
</div>
</body>"
`;

exports[`should handle DOM content bigger than maxLength 1`] = `
"<body>
<div>
Expand All @@ -45,3 +53,20 @@ exports[`should handle DOM content bigger than maxLength 1`] = `
</div>
</body>..."
`;

exports[`should handle shadow DOM content 1`] = `
"<body>
<div>
<custom-element>
#shadow-root
<span
class="some-name"
data-test-id="33"
id="5"
>
hello
</span>
</custom-element>
</div>
</body>"
`;
42 changes: 42 additions & 0 deletions test/browser/test/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,45 @@ test('should handle DOM content bigger than maxLength', async () => {
document.body.appendChild(parentDiv)
expect(await commands.stripVTControlCharacters(prettyDOM(undefined, maxContent))).toMatchSnapshot()
})

test('should handle shadow DOM content', async () => {
class CustomElement extends HTMLElement {
connectedCallback() {
const shadowRoot = this.attachShadow({ mode: 'open' })
const span = document.createElement('span')
span.classList.add('some-name')
span.setAttribute('data-test-id', '33')
span.setAttribute('id', '5')
span.textContent = 'hello'
shadowRoot.appendChild(span)
}
}
customElements.define('custom-element', CustomElement)

const div = document.createElement('div')
div.innerHTML = '<custom-element></custom-element>'
document.body.append(div)

expect(await commands.stripVTControlCharacters(prettyDOM())).toMatchSnapshot()
})

test('should be able to opt out of shadow DOM content', async () => {
class CustomElement extends HTMLElement {
connectedCallback() {
const shadowRoot = this.attachShadow({ mode: 'open' })
const span = document.createElement('span')
span.classList.add('some-name')
span.setAttribute('data-test-id', '33')
span.setAttribute('id', '5')
span.textContent = 'hello'
shadowRoot.appendChild(span)
}
}
customElements.define('no-shadow-root', CustomElement)

const div = document.createElement('div')
div.innerHTML = '<no-shadow-root></no-shadow-root>'
document.body.append(div)

expect(await commands.stripVTControlCharacters(prettyDOM(undefined, undefined, { printShadowRoot: false }))).toMatchSnapshot()
})
Loading