From c322752dd8fea1ef97583927e35e3ae59f74d2de Mon Sep 17 00:00:00 2001 From: Daniel Rentz Date: Tue, 4 Nov 2025 18:25:44 +0100 Subject: [PATCH 01/24] docs: minor improvements for "expect" documentation (#8936) --- docs/api/expect.md | 28 ++++++++++++++++++++++++++-- packages/expect/src/types.ts | 2 +- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/api/expect.md b/docs/api/expect.md index 069010257c4a..f7237002ae7c 100644 --- a/docs/api/expect.md +++ b/docs/api/expect.md @@ -188,7 +188,7 @@ Try not to use `toBe` with floating-point numbers. Since JavaScript rounds them, - **Type:** `(value: number, numDigits?: number) => Awaitable` -Use `toBeCloseTo` to compare floating-point numbers. The optional `numDigits` argument limits the number of digits to check _after_ the decimal point. For example: +Use `toBeCloseTo` to compare floating-point numbers. The optional `numDigits` argument limits the number of digits to check _after_ the decimal point. The default for `numDigits` is 2. For example: ```ts import { expect, test } from 'vitest' @@ -343,7 +343,7 @@ function apples() { } function bananas() { - return null + return undefined } test('we don\'t have apples', () => { @@ -429,6 +429,17 @@ test('stock is type of string', () => { }) ``` +:::warning +`toBeTypeOf` uses the native `typeof` operator under the hood with all its quirks, most notably that the value `null` has type `object`. + +```ts +test('toBeTypeOf cannot check for null or array', () => { + expect(null).toBeTypeOf('object') + expect([]).toBeTypeOf('object') +}) +``` +::: + ## toBeInstanceOf - **Type:** `(c: any) => Awaitable` @@ -587,7 +598,13 @@ import { getAllFruits } from './stocks.js' test('the fruit list contains orange', () => { expect(getAllFruits()).toContain('orange') +}) + +test('pineapple contains apple', () => { + expect('pineapple').toContain('apple') +}) +test('the element contains a class and is contained', () => { const element = document.querySelector('#el') // element has a class expect(element.classList).toContain('flex') @@ -683,6 +700,9 @@ test('John Doe Invoice', () => { // Wrap your key in an array to avoid the key from being parsed as a deep reference expect(invoice).toHaveProperty(['P.O'], '12345') + + // Deep equality of object property + expect(invoice).toHaveProperty('items[0]', { type: 'apples', quantity: 10 }) }) ``` @@ -1207,6 +1227,8 @@ test('spy function returns bananas on a last call', () => { You can call this assertion to check if a function has successfully returned a value with certain parameters on a certain call. Requires a spy function to be passed to `expect`. +The count starts at 1. So, to check the second entry, you would write `.toHaveNthReturnedWith(2, ...)`. + ```ts import { expect, test, vi } from 'vitest' @@ -1316,6 +1338,8 @@ You can call this assertion to check if a function has successfully resolved a c If the function returned a promise, but it was not resolved yet, this will fail. +The count starts at 1. So, to check the second entry, you would write `.toHaveNthResolvedWith(2, ...)`. + ```ts import { expect, test, vi } from 'vitest' diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index 66206be70c6e..c1b66ebba6fa 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -405,7 +405,7 @@ export interface JestAssertion extends jest.Matchers, CustomMa /** * Using exact equality with floating point numbers is a bad idea. * Rounding means that intuitive things fail. - * The default for `precision` is 2. + * The default for `numDigits` is 2. * * @example * expect(price).toBeCloseTo(9.99, 2); From 1ba8e3caca0d76699067ade033718557946eec1d Mon Sep 17 00:00:00 2001 From: Hugo Torzuoli Date: Tue, 4 Nov 2025 18:26:37 +0100 Subject: [PATCH 02/24] chore: typo in error (#8939) --- packages/runner/src/suite.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index 69f153f3fcd3..6367d5ca969e 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -247,7 +247,7 @@ function parseArguments any>( timeoutOrTest: T | number | undefined, ) { if (timeoutOrTest != null && typeof timeoutOrTest === 'object') { - throw new TypeError(`Siganture "test(name, fn, { ... })" was deprecated in Vitest 3 and removed in Vitest 4. Please, provide options as a second argument instead.`) + throw new TypeError(`Signature "test(name, fn, { ... })" was deprecated in Vitest 3 and removed in Vitest 4. Please, provide options as a second argument instead.`) } let options: TestOptions = {} From 865073cf9ee2b3dde72a08f7d39d1e77f4ee14e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0?= Date: Wed, 5 Nov 2025 15:40:35 +0900 Subject: [PATCH 03/24] chore: remove unused AI output (#8943) --- review.md | 301 ------------------------------------------------------ 1 file changed, 301 deletions(-) delete mode 100644 review.md diff --git a/review.md b/review.md deleted file mode 100644 index b33758918442..000000000000 --- a/review.md +++ /dev/null @@ -1,301 +0,0 @@ -docs/.vitepress/config.ts - -@@ -489,6 +489,10 @@ function guide(): DefaultTheme.SidebarItem[] { - text: 'Test Projects', - link: '/guide/projects', - }, - { - -Comment : - sheremet-va 1 hour ago - -From #8409 (comment) - -This should be in the browser guides section (in the same level as "Multiple Setups") - --------------- -docs/guide/component-testing.md - -### Component Testing Hierarchy - -``` -1. Critical User Paths → Always test these - -Comment: - sheremet-va 1 hour ago - -should the spaces be aligned? The first 2 arrows are not aligned ------------------------ -docs/guide/component-testing.md - -```tsx -// Mock external services -vi.mock('../api/userService', () => ({ - -Comment: - sheremet-va 1 hour ago -we recommend vi.mock(import('../api/userService')) syntax (applied to all vi.mock calls here) --------------------------- -docs/guide/component-testing.md - -expect(getByText('Loading...')).toBeInTheDocument() - - // Wait for data to load - await waitFor(() => { - -Comment: - sheremet-va 1 hour ago -There is await expect.element(locator).toBeInTheDocument() - ---------------------- -docs/guide/component-testing.md - - ) - - // Initially shows all products - expect(getByText('Laptop')).toBeInTheDocument() - - Comment: - sheremet-va 1 hour ago - -We recommend all expect(locator) to be expect.element(locator) - -------------------------- -docs/guide/component-testing.md - - const screen = page.elementLocator(baseElement) - - // You can use either Testing Library queries or Vitest's page queries - const incrementButton = getByRole('button', { name: /increment/i }) - - Comment: - sheremet-va 1 hour ago - I don't think we should introduce this confusion. Don't use testing-libraries' getBy* methods anywhere - - ---------------------------- - docs/guide/component-testing.md - - expect(document.activeElement).toBe(nextFocusableElement) - -// Test ARIA attributes -expect(modal).toHaveAttribute('aria-modal', 'true') - -Comment: - sheremet-va 1 hour ago -we recommend await expect.element(el).toHaveAttribute() (notice await) because it auto-retries the assertion --------------------------- -docs/guide/component-testing.md - -```tsx -// Mock API calls -vi.mock('../api/userService', () => ({ - -Comment : - sheremet-va 1 hour ago - -For APIs we recommend msw (you can link /guide/mocking/requests) - ---------------------------- -docs/guide/component-testing.md - -```tsx -// Mock the API to test different scenarios -const mockUserApi = vi.fn() -vi.mock('../api/users', () => ({ getUser: mockUserApi })) - -Comment: - sheremet-va 1 hour ago -This code doesn't work, it will throw ReferenceError. Requests examples should use msw - ------------------ -docs/guide/component-testing.md - -mockUserApi.mockResolvedValue({ name: 'John Doe', email: 'john@example.com' }) - rerender() - - await waitFor(() => { - -Comment: - sheremet-va 1 hour ago - -do not use waitFor anywhere. Vitest supports auto-retrying via expect.element - ------------------------- -docs/guide/component-testing.md - - await expect.element(getByText('Please enter a valid email')).toBeInTheDocument() - - // Test successful submission - await emailInput.clear() - -Comment: - sheremet-va 1 hour ago -fill already does the clear so it's redundant - -------------------- -docs/guide/component-testing.md - - const firstInput = getByLabelText(/username/i) - const lastButton = getByRole('button', { name: /save/i }) - - firstInput.focus() - - Comment: - sheremet-va 1 hour ago - Vitest doesn't have a focus method - I already mentioned it before: #8409 (comment) - - ------------------------ - docs/guide/component-testing.md - - firstInput.focus() - await userEvent.keyboard('{Shift>}{Tab}{/Shift}') // Shift+Tab goes backwards - expect(document.activeElement).toBe(lastButton) // Should wrap to last element - - Comment: - sheremet-va 1 hour ago -await expect.element - ------------------------ -docs/guide/component-testing.md - -- **Check console errors** for JavaScript errors or warnings -- **Monitor network requests** to debug API calls - -For headless mode debugging, add `headless: false` to your browser config temporarily. - -Comment: - sheremet-va 1 hour ago - - For headless mode debugging - -for non-headless or headful - -it can't be headless if you set headless: false - --------------------------- -docs/guide/component-testing.md - - // Debug: Check if element exists with different query - const errorElement = page.getByText('Email is required') - console.log('Error element found:', await errorElement.count()) - - Comment : - sheremet-va 1 hour ago - -vitest doesn't have a count, we do have length though - -------------------------- -docs/guide/component-testing.md - -```tsx -// Debug why elements can't be found -const button = page.getByRole('button', { name: /submit/i }) -console.log('Button count:', await button.count()) // Should be 1 - -Comment: - sheremet-va 1 hour ago -no count - -------------------------- -docs/guide/component-testing.md - -// Try alternative queries if the first one fails -if (await button.count() === 0) { - console.log('All buttons:', await page.getByRole('button').all()) - -Comment: - sheremet-va 1 hour ago - -all is not async - ------------------------ -docs/guide/component-testing.md -// If getByRole fails, check what roles/names are available -const buttons = await page.getByRole('button').all() -for (const button of buttons) { - const accessibleName = await button.getAttribute('aria-label') - -Comment: - sheremet-va 1 hour ago - -there is no getAttribute - ------------------------------ -docs/guide/component-testing.md - -const buttons = await page.getByRole('button').all() -for (const button of buttons) { - const accessibleName = await button.getAttribute('aria-label') - || await button.textContent() - -Comment: - sheremet-va 1 hour ago - -there is no textContent - ---------------------------- -docs/guide/component-testing.md - -const submitButton - = page.getByRole('button', { name: /submit/i }) // By accessible name - || page.getByTestId('submit-button') // By test ID - || page.locator('button[type="submit"]') // By CSS selector - -Comment: - sheremet-va 1 hour ago - -there is no locator - ---------------------- -docs/guide/component-testing.md - - // 3. Check if element is hidden or disabled - if (await emailInput.count() > 0) { - console.log('Email input visible:', await emailInput.isVisible()) - - sheremet-va 1 hour ago - -there is no isVisible - -Note For you: -Always ensure that the methods exists in the library. Verify if you are unsure either within the repo or going online or ask me if you have any questions - -Comment I shared for you -I have put up all the reviews we got from @sheremet-va today . Here is the link to the file => /Users/cr7/Documents/review.md and there is note for you at the end of the markdown. Please ensure that you follow the notes. You need to fix each of the reviews one by one then you also have to provide me with the thoughtful response for @sheremet-va for each of the reviews. - ---- - -## CURRENT STATUS & TODO LIST - -### ✅ **Already Fixed (3/17 items):** -1. **Hierarchy alignment** - Fixed arrow alignment in Component Testing Hierarchy -2. **vi.mock syntax** - Updated to use `vi.mock(import('...'))` syntax throughout -3. **MSW recommendation** - Added recommendation to use MSW for API mocking with link to `/guide/mocking/requests` - -### 🚧 **High Priority - API Issues (Need Immediate Fix):** -4. **Move component testing to browser guides section** - Config.ts placement issue -5. **Replace expect() with expect.element()** - Line 41 & 56 + multiple other instances -6. **Remove Testing Library getBy* confusion** - Line 69 - causes confusion with Vitest APIs -7. **Add await to expect.element assertions** - Line 78 - for auto-retry functionality -8. **Remove waitFor usage** - Line 116 - replace with expect.element auto-retry -9. **Remove redundant clear() call** - Line 129 - fill() already clears -10. **Fix focus method issue** - Line 141 - Vitest doesn't have focus method -11. **Fix headless debugging text** - Line 164 - terminology correction -12. **Replace count() with length** - Line 181, 194, 204 - count() doesn't exist in Vitest -13. **Fix all() method usage** - Line 205, 215 - all() is not async -14. **Replace getAttribute method** - Line 217 - doesn't exist in Vitest -15. **Replace textContent method** - Line 230 - doesn't exist in Vitest -16. **Replace locator method** - Line 241 - doesn't exist in Vitest -17. **Replace isVisible method** - Line 256 - doesn't exist in Vitest - -### 📝 **Next Steps:** -1. Fix each issue systematically (one by one as requested) -2. Prepare thoughtful response for each review comment to @sheremet-va -3. Verify all API methods exist in Vitest browser mode documentation -4. Test examples to ensure they work with actual Vitest APIs - -### 🎯 **Root Cause Analysis:** -The guide appears to have been written using Playwright/Testing Library APIs instead of the actual Vitest browser mode APIs. Many method names and patterns need to be corrected to match Vitest's implementation. - -**Status as of:** September 3, 2025 11:41 AM -**Completion:** 3/17 issues resolved (17.6%) From 1f730373858a7d7f49785cca5d6c45d17afc77b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?= Date: Wed, 5 Nov 2025 10:22:06 +0100 Subject: [PATCH 04/24] fix(browser): cleanup frame-ancestors from CSP header at coverage middleware (#8941) --- packages/browser/src/node/plugin.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/browser/src/node/plugin.ts b/packages/browser/src/node/plugin.ts index f246e590d438..5d58b976fbb8 100644 --- a/packages/browser/src/node/plugin.ts +++ b/packages/browser/src/node/plugin.ts @@ -79,6 +79,15 @@ export default (parentServer: ParentBrowserProject, base = '/'): Plugin[] => { single: true, dev: true, setHeaders: (res) => { + const csp = res.getHeader('Content-Security-Policy') + if (typeof csp === 'string') { + // add frame-ancestors to allow the iframe to be loaded by Vitest, + // but keep the rest of the CSP + res.setHeader( + 'Content-Security-Policy', + csp.replace(/frame-ancestors [^;]+/, 'frame-ancestors *'), + ) + } res.setHeader( 'Cache-Control', 'public,max-age=0,must-revalidate', From 97aed7454f09d352a9e71b3cd67c3584238cf455 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Thu, 6 Nov 2025 15:19:23 +0800 Subject: [PATCH 05/24] chore: remove unused deps in `pnpm-workspace.yaml` (#8949) --- pnpm-workspace.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e00e0472d732..f8b23845cb56 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -17,7 +17,6 @@ catalog: '@types/istanbul-lib-report': ^3.0.3 '@types/istanbul-lib-source-maps': ^4.0.4 '@types/istanbul-reports': ^3.0.4 - '@types/test-exclude': ^6.0.2 '@types/ws': ^8.18.1 '@unocss/reset': ^66.5.1 '@vitejs/plugin-vue': ^6.0.1 @@ -39,7 +38,6 @@ catalog: sirv: ^3.0.2 std-env: ^3.9.0 strip-literal: ^3.0.0 - test-exclude: ^7.0.1 tinyglobby: ^0.2.15 tinyrainbow: ^3.0.3 unocss: ^66.5.1 From 069e6db9bd42124cb926eabec9481b6a91f15382 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 6 Nov 2025 12:50:11 +0100 Subject: [PATCH 06/24] fix(webdriverio): When no argument is passed to the .click interaction command, the webdriver command should also have no argument (#8937) --- docs/guide/browser/interactivity-api.md | 24 +++++++++++++++++++ .../browser-webdriverio/src/commands/click.ts | 8 +++---- .../src/client/tester/locators/index.ts | 6 ++--- .../fixtures/user-event/keyboard.test.ts | 3 ++- test/browser/test/userEvent.test.ts | 11 +++++++++ 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/docs/guide/browser/interactivity-api.md b/docs/guide/browser/interactivity-api.md index 301ade07c19f..8d2697b687cd 100644 --- a/docs/guide/browser/interactivity-api.md +++ b/docs/guide/browser/interactivity-api.md @@ -59,9 +59,33 @@ test('clicks on an element', async () => { await userEvent.click(logo) // or you can access it directly on the locator await logo.click() + + // With WebdriverIO, this uses either ElementClick (with no arguments) or + // actions (with arguments). Use an empty object to force the use of actions. + await logo.click({}) }) ``` +### Clicking with a modifier + +With either WebdriverIO or Playwright: + +```ts +await userEvent.keyboard('{Shift>}') +// By using an empty object as the option, this opts in to using a chain of actions +// instead of an ElementClick in webdriver. +// Firefox has a bug that makes this necessary. +// Follow https://bugzilla.mozilla.org/show_bug.cgi?id=1456642 to know when this +// will be fixed. +await userEvent.click(element, {}) +await userEvent.keyboard('{/Shift}') +``` + +With Playwright: +```ts +await userEvent.click(element, { modifiers: ['Shift'] }) +``` + References: - [Playwright `locator.click` API](https://playwright.dev/docs/api/class-locator#locator-click) diff --git a/packages/browser-webdriverio/src/commands/click.ts b/packages/browser-webdriverio/src/commands/click.ts index 292103eba281..997850a8dc5b 100644 --- a/packages/browser-webdriverio/src/commands/click.ts +++ b/packages/browser-webdriverio/src/commands/click.ts @@ -4,16 +4,16 @@ import type { UserEventCommand } from './utils' export const click: UserEventCommand = async ( context, selector, - options = {}, + options, ) => { const browser = context.browser - await browser.$(selector).click(options as any) + await browser.$(selector).click(options) } export const dblClick: UserEventCommand = async ( context, selector, - _options = {}, + _options, ) => { const browser = context.browser await browser.$(selector).doubleClick() @@ -22,7 +22,7 @@ export const dblClick: UserEventCommand = async ( export const tripleClick: UserEventCommand = async ( context, selector, - _options = {}, + _options, ) => { const browser = context.browser await browser diff --git a/packages/browser/src/client/tester/locators/index.ts b/packages/browser/src/client/tester/locators/index.ts index 1e1706fab2c1..14a715c9064a 100644 --- a/packages/browser/src/client/tester/locators/index.ts +++ b/packages/browser/src/client/tester/locators/index.ts @@ -74,15 +74,15 @@ export abstract class Locator { }) } - public click(options: UserEventClickOptions = {}): Promise { + public click(options?: UserEventClickOptions): Promise { return this.triggerCommand('__vitest_click', this.selector, options) } - public dblClick(options: UserEventClickOptions = {}): Promise { + public dblClick(options?: UserEventClickOptions): Promise { return this.triggerCommand('__vitest_dblClick', this.selector, options) } - public tripleClick(options: UserEventClickOptions = {}): Promise { + public tripleClick(options?: UserEventClickOptions): Promise { return this.triggerCommand('__vitest_tripleClick', this.selector, options) } diff --git a/test/browser/fixtures/user-event/keyboard.test.ts b/test/browser/fixtures/user-event/keyboard.test.ts index aced4c255e5c..de88b2eca5c0 100644 --- a/test/browser/fixtures/user-event/keyboard.test.ts +++ b/test/browser/fixtures/user-event/keyboard.test.ts @@ -63,7 +63,8 @@ test('click with modifier', async () => { }); await userEvent.keyboard('{Shift>}') - await userEvent.click(el) + // By using an empty object as the option, this opts in to using a chain of actions instead of an elementClick in webdriver. + await userEvent.click(el, {}) await userEvent.keyboard('{/Shift}') await expect.poll(() => el.textContent).toContain("[ok]") }) diff --git a/test/browser/test/userEvent.test.ts b/test/browser/test/userEvent.test.ts index 10a7f93c4a77..3c472daf2561 100644 --- a/test/browser/test/userEvent.test.ts +++ b/test/browser/test/userEvent.test.ts @@ -23,12 +23,23 @@ describe('userEvent.click', () => { document.body.appendChild(button) const onClick = vi.fn() const dblClick = vi.fn() + // Make sure a contextmenu doesn't actually appear, as it may make some + // tests fail later. + const onContextmenu = vi.fn(e => e.preventDefault()) button.addEventListener('click', onClick) + button.addEventListener('dblclick', onClick) + button.addEventListener('contextmenu', onContextmenu) await userEvent.click(button) expect(onClick).toHaveBeenCalled() expect(dblClick).not.toHaveBeenCalled() + expect(onContextmenu).not.toHaveBeenCalled() + + onClick.mockClear() + await userEvent.click(button, { button: 'right' }) + expect(onClick).not.toHaveBeenCalled() + expect(onContextmenu).toHaveBeenCalled() }) test('correctly doesn\'t click on a disabled button', async () => { From 997ca5a827d1789afa8fd76b17e365d40e639b19 Mon Sep 17 00:00:00 2001 From: Livan Date: Thu, 6 Nov 2025 11:50:47 +0000 Subject: [PATCH 07/24] fix(runner): properly encode Uint8Array body in annotations (#8951) --- packages/runner/src/context.ts | 7 ++- test/cli/test/annotations.test.ts | 95 ++++++++++++++++++++++++++----- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/packages/runner/src/context.ts b/packages/runner/src/context.ts index 2ed5d2a4f216..73e42149779e 100644 --- a/packages/runner/src/context.ts +++ b/packages/runner/src/context.ts @@ -289,14 +289,15 @@ export function setFileContext(file: File, context: Record): vo const table: string[] = [] for (let i = 65; i < 91; i++) { - table.push(String.fromCharCode(i)) + table.push(String.fromCharCode(i)) // A-Z } for (let i = 97; i < 123; i++) { - table.push(String.fromCharCode(i)) + table.push(String.fromCharCode(i)) // a-z } for (let i = 0; i < 10; i++) { - table.push(i.toString(10)) + table.push(i.toString(10)) // 0-9 } +table.push('+', '/') function encodeUint8Array(bytes: Uint8Array): string { let base64 = '' diff --git a/test/cli/test/annotations.test.ts b/test/cli/test/annotations.test.ts index 34b59564ee54..fa956486f38f 100644 --- a/test/cli/test/annotations.test.ts +++ b/test/cli/test/annotations.test.ts @@ -19,6 +19,9 @@ test('simple', async ({ annotate }) => { await annotate('3', { path: './test-3.js' }) await annotate('4', 'warning', { path: './test-4.js' }) await externalAnnotate(annotate) + await annotate('with base64 body', { body: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' }) + await annotate('with Uint8Array body', { body: new Uint8Array(Array.from({ length: 256 }).map((_, i) => i)) }) + await annotate('with contentType', { body: '', contentType: 'text/plain' }) }) describe('suite', () => { @@ -61,7 +64,7 @@ describe('API', () => { { onTestCaseAnnotate(testCase, annotation) { const path = annotation.attachment?.path?.replace(testCase.project.config.root, '').replace(/\w+\.js$/, '.js') - events.push(`[annotate] ${testCase.name} ${annotation.message} ${annotation.type} ${path}`) + events.push(`[annotate] ${testCase.name} ${annotation.message} ${annotation.type} path=${path} contentType=${annotation.attachment?.contentType} body=${annotation.attachment?.body}`) }, onTestCaseReady(testCase) { events.push(`[ready] ${testCase.name}`) @@ -97,15 +100,18 @@ describe('API', () => { expect(events).toMatchInlineSnapshot(` [ "[ready] simple", - "[annotate] simple 1 notice undefined", - "[annotate] simple 2 warning undefined", - "[annotate] simple 3 notice /.vitest-attachments/3-.js", - "[annotate] simple 4 warning /.vitest-attachments/4-.js", - "[annotate] simple external notice undefined", + "[annotate] simple 1 notice path=undefined contentType=undefined body=undefined", + "[annotate] simple 2 warning path=undefined contentType=undefined body=undefined", + "[annotate] simple 3 notice path=/.vitest-attachments/3-.js contentType=text/javascript body=undefined", + "[annotate] simple 4 warning path=/.vitest-attachments/4-.js contentType=text/javascript body=undefined", + "[annotate] simple external notice path=undefined contentType=undefined body=undefined", + "[annotate] simple with base64 body notice path=undefined contentType=undefined body=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", + "[annotate] simple with Uint8Array body notice path=undefined contentType=undefined body=AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==", + "[annotate] simple with contentType notice path=undefined contentType=text/plain body=", "[result] simple", "[ready] second", - "[annotate] second 5 notice undefined", - "[annotate] second 6 notice https://absolute-path.com", + "[annotate] second 5 notice path=undefined contentType=undefined body=undefined", + "[annotate] second 6 notice path=https://absolute-path.com contentType=undefined body=undefined", "[result] second", ] `) @@ -117,7 +123,7 @@ describe('API', () => { "location": { "column": 11, "file": "/basic.test.ts", - "line": 15, + "line": 18, }, "message": "5", "type": "notice", @@ -129,7 +135,7 @@ describe('API', () => { "location": { "column": 11, "file": "/basic.test.ts", - "line": 16, + "line": 19, }, "message": "6", "type": "notice", @@ -189,6 +195,43 @@ describe('API', () => { "message": "external", "type": "notice", }, + { + "attachment": { + "body": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", + }, + "location": { + "column": 9, + "file": "/basic.test.ts", + "line": 11, + }, + "message": "with base64 body", + "type": "notice", + }, + { + "attachment": { + "body": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==", + }, + "location": { + "column": 9, + "file": "/basic.test.ts", + "line": 12, + }, + "message": "with Uint8Array body", + "type": "notice", + }, + { + "attachment": { + "body": "", + "contentType": "text/plain", + }, + "location": { + "column": 9, + "file": "/basic.test.ts", + "line": 13, + }, + "message": "with contentType", + "type": "notice", + }, ], } `) @@ -234,6 +277,9 @@ describe('reporters', () => { # notice: 3 # warning: 4 # notice: external + # notice: with base64 body + # notice: with Uint8Array body + # notice: with contentType ok 2 - suite # time=