[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix(browser): scale iframe for non ui case (#6512)

authored by

Hiroshi Ogawa and committed by
GitHub
(Apr 17, 2025, 12:57 PM +0200) c3374808 67430083

+133 -11
+10
test/browser/specs/runner.test.ts
··· 222 222 } 223 223 }) 224 224 225 + test('viewport', async () => { 226 + const { stdout, stderr } = await runBrowserTests({ 227 + root: './fixtures/viewport', 228 + }) 229 + expect(stderr).toBe('') 230 + instances.forEach(({ browser }) => { 231 + expect(stdout).toReportPassedTest('basic.test.ts', browser) 232 + }) 233 + }) 234 + 225 235 test.runIf(provider === 'playwright')('timeout hooks', async () => { 226 236 const { stderr } = await runBrowserTests({ 227 237 root: './fixtures/timeout-hooks',
+19
test/browser/specs/viewport.test.ts
··· 1 + import { expect, test } from 'vitest' 2 + import { runBrowserTests } from './utils' 3 + 4 + test('viewport', async () => { 5 + const { stderr, ctx } = await runBrowserTests({ 6 + root: './fixtures/viewport', 7 + }) 8 + 9 + expect(stderr).toBe('') 10 + expect( 11 + Object.fromEntries( 12 + ctx.state.getFiles().map(f => [f.name, f.result.state]), 13 + ), 14 + ).toMatchInlineSnapshot(` 15 + { 16 + "basic.test.ts": "pass", 17 + } 18 + `) 19 + })
+3 -2
test/browser/test/userEvent.test.ts
··· 140 140 }, 141 141 }) 142 142 143 + // not exact due to scaling and rounding 143 144 expect(spy).toHaveBeenCalledWith({ 144 - x: 200, 145 - y: 150, 145 + x: expect.closeTo(200, -1), 146 + y: expect.closeTo(150, -1), 146 147 }) 147 148 }) 148 149 })
+17 -1
packages/browser/src/client/orchestrator.ts
··· 259 259 if (ui) { 260 260 await ui.setIframeViewport(width, height) 261 261 } 262 - else { 262 + else if (getBrowserState().provider === 'webdriverio') { 263 263 iframe.style.width = `${width}px` 264 264 iframe.style.height = `${height}px` 265 + iframe.parentElement?.setAttribute('data-scale', '1') 266 + } 267 + else { 268 + const scale = Math.min( 269 + 1, 270 + iframe.parentElement!.parentElement!.clientWidth / width, 271 + iframe.parentElement!.parentElement!.clientHeight / height, 272 + ) 273 + iframe.parentElement!.style.cssText = ` 274 + width: ${width}px; 275 + height: ${height}px; 276 + transform: scale(${scale}); 277 + transform-origin: left top; 278 + ` 279 + iframe.parentElement?.setAttribute('data-scale', String(scale)) 280 + await new Promise(r => requestAnimationFrame(r)) 265 281 } 266 282 } 267 283
+1
test/browser/fixtures/locators/blog.test.tsx
··· 18 18 19 19 await expect.element(secondPost.getByRole('heading')).toHaveTextContent('qui est esse') 20 20 21 + // TODO: click doesn't work on webdriverio when iframe is scaled 21 22 await userEvent.click(secondPost.getByRole('button', { name: 'Delete' })) 22 23 23 24 expect(screen.getByRole('listitem').all()).toHaveLength(3)
+58
test/browser/fixtures/viewport/basic.test.ts
··· 1 + import { page, userEvent, server } from "@vitest/browser/context"; 2 + import { expect, test } from "vitest"; 3 + 4 + test("drag and drop over large viewport", async () => { 5 + // put boxes horizontally [1] [2] ... [30] 6 + // then drag-and-drop from [1] to [30] 7 + 8 + const wrapper = document.createElement("div"); 9 + wrapper.style.cssText = "display: flex; width: 3000px;"; 10 + document.body.appendChild(wrapper); 11 + 12 + const events: { i: number; type: string }[] = []; 13 + 14 + for (let i = 1; i <= 30; i++) { 15 + const el = document.createElement("div"); 16 + el.textContent = `[${i}]`; 17 + el.style.cssText = ` 18 + flex: none; 19 + width: 100px; 20 + height: 100px; 21 + border: 1px solid black; 22 + box-sizing: border-box; 23 + display: flex; 24 + justify-content: center; 25 + align-items: center; 26 + `; 27 + el.draggable = true; 28 + wrapper.append(el); 29 + 30 + el.addEventListener("dragstart", (ev) => { 31 + ev.dataTransfer.effectAllowed = "move"; 32 + events.push({ type: "dragstart", i }); 33 + }); 34 + el.addEventListener("dragover", (ev) => { 35 + ev.preventDefault(); 36 + ev.dataTransfer.dropEffect = "move"; 37 + events.push({ type: "dragover", i }); 38 + }); 39 + el.addEventListener("drop", (ev) => { 40 + ev.preventDefault(); 41 + events.push({ type: "drop", i }); 42 + }); 43 + } 44 + 45 + // drag and drop only works reliably on playwright 46 + if (server.provider !== 'playwright') { 47 + return 48 + } 49 + 50 + await userEvent.dragAndDrop(page.getByText("[1]"), page.getByText("[30]")); 51 + 52 + expect(events).toMatchObject( 53 + expect.arrayContaining([ 54 + { type: "dragstart", i: 1 }, 55 + { type: "drop", i: 30 }, 56 + ]), 57 + ); 58 + });
+21
test/browser/fixtures/viewport/vitest.config.ts
··· 1 + import { fileURLToPath } from 'node:url' 2 + import { defineConfig } from 'vitest/config' 3 + import { instances, provider } from '../../settings' 4 + 5 + // pnpm -C test/browser test-fixtures --root fixtures/viewport --browser.ui=false 6 + // pnpm -C test/browser test-fixtures --root fixtures/viewport --browser.headless=true 7 + 8 + export default defineConfig({ 9 + test: { 10 + browser: { 11 + enabled: true, 12 + provider, 13 + instances: instances.map(instance => ({ 14 + ...instance, 15 + viewport: { width: 3000, height: 400 } 16 + })), 17 + 18 + }, 19 + }, 20 + cacheDir: fileURLToPath(new URL("./node_modules/.vite", import.meta.url)), 21 + })
+1 -1
packages/browser/src/client/tester/utils.ts
··· 167 167 } 168 168 169 169 export function getIframeScale(): number { 170 - const testerUi = window.parent.document.querySelector('#tester-ui') as HTMLElement | null 170 + const testerUi = window.parent.document.querySelector(`iframe[data-vitest]`)?.parentElement 171 171 if (!testerUi) { 172 172 throw new Error(`Cannot find Tester element. This is a bug in Vitest. Please, open a new issue with reproduction.`) 173 173 }
+3 -7
packages/browser/src/client/tester/locators/playwright.ts
··· 9 9 getByTextSelector, 10 10 getByTitleSelector, 11 11 } from 'ivya' 12 - import { getBrowserState } from '../../utils' 13 12 import { getIframeScale, processTimeoutOptions } from '../utils' 14 13 import { Locator, selectorEngine } from './index' 15 14 ··· 106 105 } 107 106 108 107 function processDragAndDropOptions(options_?: UserEventDragAndDropOptions) { 109 - // only ui scales the iframe, so we need to adjust the position 110 - if (!options_ || !getBrowserState().config.browser.ui) { 108 + if (!options_) { 111 109 return options_ 112 110 } 113 111 const options = options_ as NonNullable< ··· 123 121 } 124 122 125 123 function processHoverOptions(options_?: UserEventHoverOptions) { 126 - // only ui scales the iframe, so we need to adjust the position 127 - if (!options_ || !getBrowserState().config.browser.ui) { 124 + if (!options_) { 128 125 return options_ 129 126 } 130 127 const options = options_ as NonNullable< ··· 137 134 } 138 135 139 136 function processClickOptions(options_?: UserEventClickOptions) { 140 - // only ui scales the iframe, so we need to adjust the position 141 - if (!options_ || !getBrowserState().config.browser.ui) { 137 + if (!options_) { 142 138 return options_ 143 139 } 144 140 const options = options_ as NonNullable<