diff --git a/tests/highlight-locators.spec.ts b/tests/highlight-locators.spec.ts new file mode 100644 index 000000000..1f996efb1 --- /dev/null +++ b/tests/highlight-locators.spec.ts @@ -0,0 +1,74 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { chromium } from '@playwright/test'; +import { expect, test } from './utils'; + +test.beforeEach(({ mode }) => { + // Locator highlighting is only relevant when the browser stays open. + test.skip(mode !== 'reuse'); + // the x-pw-highlight element has otherwise a closed shadow root. + process.env.PWTEST_UNDER_TEST = '1'; +}); + +test('should work', async ({ activate }) => { + const cdpPort = 9234; + const { vscode, testController } = await activate({ + 'playwright.config.js': `module.exports = { + use: { + launchOptions: { + args: ['--remote-debugging-port=${cdpPort}'] + } + } + }`, + 'test.spec.ts': ` + import { test } from '@playwright/test'; + test('one', async ({ page }) => { + await page.goto('https://example.com'); + await page.setContent(\` + + + \`); + await page.getByRole('button', { name: 'one' }).click(); // line 8 + await page.getByRole('button', { name: 'two' }).click(); // line 9 + page.getByRole('button', { name: 'not there!' }); // line 10 + }); + `, + }); + + const testItems = testController.findTestItems(/test.spec.ts/); + expect(testItems.length).toBe(1); + await vscode.openEditors('test.spec.ts'); + await testController.run(testItems); + const browser = await chromium.connectOverCDP(`http://localhost:${cdpPort}`); + { + expect(browser.contexts()).toHaveLength(1); + expect(browser.contexts()[0].pages()).toHaveLength(1); + } + const page = browser.contexts()[0].pages()[0]; + { + vscode.languages.emitHoverEvent('typescript', vscode.window.activeTextEditor.document, new vscode.Position(9, 26)); + await expect.poll(() => page.locator('x-pw-highlight').boundingBox()).toEqual(await page.getByRole('button', { name: 'two' }).boundingBox()); + } + { + vscode.languages.emitHoverEvent('typescript', vscode.window.activeTextEditor.document, new vscode.Position(8, 26)); + await expect.poll(() => page.locator('x-pw-highlight').boundingBox()).toEqual(await page.getByRole('button', { name: 'one' }).boundingBox()); + } + { + vscode.languages.emitHoverEvent('typescript', vscode.window.activeTextEditor.document, new vscode.Position(10, 26)); + await expect.poll(() => page.locator('x-pw-highlight').boundingBox()).toEqual(null); + } +}); diff --git a/tests/mock/vscode.ts b/tests/mock/vscode.ts index 671a08a72..21b7ccb00 100644 --- a/tests/mock/vscode.ts +++ b/tests/mock/vscode.ts @@ -692,6 +692,10 @@ enum UIKind { Web = 2 } +type HoverProvider = { + provideHover?(document: Document, position: Position, token: CancellationToken): void +}; + export class VSCode { isUnderTest = true; CancellationTokenSource = CancellationTokenSource; @@ -747,6 +751,7 @@ export class VSCode { readonly commandLog: string[] = []; readonly l10n = new L10n(); lastWithProgressData = undefined; + private _hoverProviders: Map = new Map(); constructor(baseDir: string, browser: Browser) { this.context = { subscriptions: [], extensionUri: Uri.file(baseDir) }; @@ -764,7 +769,16 @@ export class VSCode { this.debug = new Debug(); const diagnosticsCollections: DiagnosticsCollection[] = []; - this.languages.registerHoverProvider = () => disposable; + this.languages.registerHoverProvider = (language: string, provider: HoverProvider) => { + this._hoverProviders.set(language, provider); + return disposable; + }; + this.languages.emitHoverEvent = (language: string, document: Document, position: Position, token: CancellationToken) => { + const provider = this._hoverProviders.get(language); + if (!provider) + return; + provider.provideHover?.(document, position, token); + }; this.languages.getDiagnostics = () => { const result: Diagnostic[] = []; for (const collection of diagnosticsCollections) {