diff --git a/packages/playwright/src/matchers/toMatchAriaSnapshot.ts b/packages/playwright/src/matchers/toMatchAriaSnapshot.ts index c291770fd5619..d379d8610c1e8 100644 --- a/packages/playwright/src/matchers/toMatchAriaSnapshot.ts +++ b/packages/playwright/src/matchers/toMatchAriaSnapshot.ts @@ -134,7 +134,7 @@ export async function toMatchAriaSnapshot( } return { pass: true, message: () => '', name: 'toMatchAriaSnapshot' }; } else { - const suggestedRebaseline = `toMatchAriaSnapshot(\`\n${escapeTemplateString(indent(typedReceived.regex, '{indent} '))}\n{indent}\`)`; + const suggestedRebaseline = `\`\n${escapeTemplateString(indent(typedReceived.regex, '{indent} '))}\n{indent}\``; return { pass: false, message: () => '', name: 'toMatchAriaSnapshot', suggestedRebaseline }; } } diff --git a/packages/playwright/src/runner/rebase.ts b/packages/playwright/src/runner/rebase.ts index de18df465b8a8..196944fd88baf 100644 --- a/packages/playwright/src/runner/rebase.ts +++ b/packages/playwright/src/runner/rebase.ts @@ -68,24 +68,27 @@ export async function applySuggestedRebaselines(config: FullConfigInternal, repo traverse(fileNode, { CallExpression: path => { const node = path.node; - if (node.arguments.length !== 1) + if (node.arguments.length < 1) return; if (!t.isMemberExpression(node.callee)) return; const argument = node.arguments[0]; if (!t.isStringLiteral(argument) && !t.isTemplateLiteral(argument)) return; - - const matcher = node.callee.property; + const prop = node.callee.property; + if (!prop.loc || !argument.start || !argument.end) + return; + // Replacements are anchored by the location of the call expression. + // However, replacement text is meant to only replace the first argument. for (const replacement of replacements) { // In Babel, rows are 1-based, columns are 0-based. - if (matcher.loc!.start.line !== replacement.location.line) + if (prop.loc.start.line !== replacement.location.line) continue; - if (matcher.loc!.start.column + 1 !== replacement.location.column) + if (prop.loc.start.column + 1 !== replacement.location.column) continue; - const indent = lines[matcher.loc!.start.line - 1].match(/^\s*/)![0]; + const indent = lines[prop.loc.start.line - 1].match(/^\s*/)![0]; const newText = replacement.code.replace(/\{indent\}/g, indent); - ranges.push({ start: matcher.start!, end: node.end!, oldText: source.substring(matcher.start!, node.end!), newText }); + ranges.push({ start: argument.start, end: argument.end, oldText: source.substring(argument.start, argument.end), newText }); // We can have multiple, hopefully equal, replacements for the same location, // for example when a single test runs multiple times because of projects or retries. // Do not apply multiple replacements for the same assertion. diff --git a/tests/playwright-test/update-aria-snapshot.spec.ts b/tests/playwright-test/update-aria-snapshot.spec.ts index 15afff31e2072..0052d3d3d972e 100644 --- a/tests/playwright-test/update-aria-snapshot.spec.ts +++ b/tests/playwright-test/update-aria-snapshot.spec.ts @@ -454,6 +454,50 @@ test('should generate baseline for input values', async ({ runInlineTest }, test expect(result2.exitCode).toBe(0); }); +test('should update when options are specified', async ({ runInlineTest }, testInfo) => { + const result = await runInlineTest({ + '.git/marker': '', + 'a.spec.ts': ` + import { test, expect } from '@playwright/test'; + test('test', async ({ page }) => { + await page.setContent(\`\`); + await expect(page.locator('body')).toMatchAriaSnapshot(\`\`, { timeout: 2500 }); + await expect(page.locator('body')).toMatchAriaSnapshot('', + { + timeout: 2500 + }); + }); + ` + }); + + expect(result.exitCode).toBe(0); + const patchPath = testInfo.outputPath('test-results/rebaselines.patch'); + const data = fs.readFileSync(patchPath, 'utf-8'); + expect(trimPatch(data)).toBe(`diff --git a/a.spec.ts b/a.spec.ts +--- a/a.spec.ts ++++ b/a.spec.ts +@@ -2,8 +2,12 @@ + import { test, expect } from '@playwright/test'; + test('test', async ({ page }) => { + await page.setContent(\`\`); +- await expect(page.locator('body')).toMatchAriaSnapshot(\`\`, { timeout: 2500 }); +- await expect(page.locator('body')).toMatchAriaSnapshot('', ++ await expect(page.locator('body')).toMatchAriaSnapshot(\` ++ - textbox: hello world ++ \`, { timeout: 2500 }); ++ await expect(page.locator('body')).toMatchAriaSnapshot(\` ++ - textbox: hello world ++ \`, + { + timeout: 2500 + }); +`); + + execSync(`patch -p1 < ${patchPath}`, { cwd: testInfo.outputPath() }); + const result2 = await runInlineTest({}); + expect(result2.exitCode).toBe(0); +}); + test('should not update snapshots when locator did not match', async ({ runInlineTest }, testInfo) => { const result = await runInlineTest({ '.git/marker': '',