-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
fix(browser): take failure screenshot if toMatchScreenshot can't capture a stable screenshot
#9847
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6aeb2aa
05bb520
4d7acce
e272d74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| import type { TestFsStructure } from '../../test-utils' | ||
| import { describe, expect, test } from 'vitest' | ||
| import { runInlineTests } from '../../test-utils' | ||
| import utilsContent from '../fixtures/expect-dom/utils?raw' | ||
| import { instances, provider } from '../settings' | ||
|
|
||
| const testFilename = 'basic.test.ts' | ||
|
|
||
| async function runBrowserTests( | ||
| structure: TestFsStructure, | ||
| ) { | ||
| return runInlineTests({ | ||
| ...structure, | ||
| 'vitest.config.js': ` | ||
| import { ${provider.name} } from '@vitest/browser-${provider.name}' | ||
| export default { | ||
| test: { | ||
| browser: { | ||
| enabled: true, | ||
| screenshotFailures: true, | ||
| provider: ${provider.name}(), | ||
| ui: false, | ||
| headless: true, | ||
| instances: ${JSON.stringify(instances.slice(0, 1) /* logic not bound to browser instance */)}, | ||
| }, | ||
| reporters: ['verbose'], | ||
| update: 'new', | ||
| }, | ||
| }`, | ||
| }) | ||
| } | ||
|
|
||
| describe('failure screenshots', () => { | ||
| describe('`toMatchScreenshot`', () => { | ||
| test('usually does NOT produce a failure screenshot', async () => { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should technically control all exit paths of the assertion, but I don't think it's worth the added time in each CI run. It might be easier to just test the cases that expect the opposite (like the one below) as the condition is quite straightforward. Edit: since the line this comment is talking about is not clear in the UI, the subject is the test with the |
||
| const { stderr } = await runBrowserTests( | ||
| { | ||
| [testFilename]: /* ts */` | ||
| import { page } from 'vitest/browser' | ||
| import { test } from 'vitest' | ||
| import { render } from './utils' | ||
|
|
||
| test('screenshot-initial', async ({ expect }) => { | ||
| render('<div data-testid="el">Test</div>') | ||
| await expect(page.getByTestId('el')).toMatchScreenshot() | ||
| }) | ||
| `, | ||
| 'utils.ts': utilsContent, | ||
| }, | ||
| ) | ||
|
|
||
| expect(stderr).toContain('No existing reference screenshot found; a new one was created.') | ||
| expect(stderr).not.toContain('Failure screenshot:') | ||
| }) | ||
|
|
||
| test('unstable screenshot fails produces a failure screenshot', async () => { | ||
| const { stderr } = await runBrowserTests( | ||
| { | ||
| [testFilename]: /* ts */` | ||
| import { page } from 'vitest/browser' | ||
| import { test } from 'vitest' | ||
| import { render } from './utils' | ||
|
|
||
| test('screenshot-unstable', async ({ expect }) => { | ||
| render('<div data-testid="el">Test</div>') | ||
| await expect(page.getByTestId('el')).toMatchScreenshot({ timeout: 1 }) | ||
| }) | ||
| `, | ||
| 'utils.ts': utilsContent, | ||
| }, | ||
| ) | ||
|
|
||
| expect(stderr).toContain('Could not capture a stable screenshot within 1ms.') | ||
| expect(stderr).toContain('Failure screenshot:') | ||
| }) | ||
|
|
||
| test('`expect.soft` produces a failure screenshot', async () => { | ||
| const { stderr } = await runBrowserTests( | ||
| { | ||
| [testFilename]: /* ts */` | ||
| import { page } from 'vitest/browser' | ||
| import { test } from 'vitest' | ||
| import { render } from './utils' | ||
|
|
||
| test('screenshot-soft-then-fail', async ({ expect }) => { | ||
| render('<div data-testid="el">Test</div>') | ||
| await expect.soft(page.getByTestId('el')).toMatchScreenshot() | ||
| expect(1).toBe(2) | ||
| }) | ||
| `, | ||
| 'utils.ts': utilsContent, | ||
| }, | ||
| ) | ||
|
|
||
| expect(stderr).toContain('No existing reference screenshot found; a new one was created.') | ||
| expect(stderr).toContain('expected 1 to be 2') | ||
| expect(stderr).toContain('Failure screenshot:') | ||
| }) | ||
| }) | ||
| }) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is the best way to accomplish this, but I didn't find other ways to check source/origin of an error and to attach additional data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, but one question. Is
assertionhere andexpectAssertionNameavailable inJestExtendPluginalways same?vitest/packages/expect/src/jest-extend.ts
Line 80 in fea46b3
We could always add assertion as error metadata in the plugin level, then move properties like
JestExtendError.contenxt: { assertionName, meta }.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could definitely do that — I wasn't sure if it made sense to add it to all errors, but I guess it might be useful in the future 👍🏼