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) {