chore(extension): do not complain about old extension version (#937)
This commit is contained in:
@@ -22,8 +22,7 @@ import type { TabInfo } from './tabItem.js';
|
|||||||
type Status =
|
type Status =
|
||||||
| { type: 'connecting'; message: string }
|
| { type: 'connecting'; message: string }
|
||||||
| { type: 'connected'; message: string }
|
| { type: 'connected'; message: string }
|
||||||
| { type: 'error'; message: string }
|
| { type: 'error'; message: string };
|
||||||
| { type: 'error'; versionMismatch: { pwMcpVersion: string; extensionVersion: string; downloadUrl: string } };
|
|
||||||
|
|
||||||
const ConnectApp: React.FC = () => {
|
const ConnectApp: React.FC = () => {
|
||||||
const [tabs, setTabs] = useState<TabInfo[]>([]);
|
const [tabs, setTabs] = useState<TabInfo[]>([]);
|
||||||
@@ -59,23 +58,6 @@ const ConnectApp: React.FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pwMcpVersion = params.get('pwMcpVersion');
|
|
||||||
const extensionVersion = chrome.runtime.getManifest().version;
|
|
||||||
if (pwMcpVersion !== extensionVersion) {
|
|
||||||
const downloadUrl = params.get('downloadUrl') || `https://github.com/microsoft/playwright-mcp/releases/download/v${extensionVersion}/playwright-mcp-extension-v${extensionVersion}.zip`;
|
|
||||||
setShowButtons(false);
|
|
||||||
setShowTabList(false);
|
|
||||||
setStatus({
|
|
||||||
type: 'error',
|
|
||||||
versionMismatch: {
|
|
||||||
pwMcpVersion: pwMcpVersion || 'unknown',
|
|
||||||
extensionVersion,
|
|
||||||
downloadUrl
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void connectToMCPRelay(relayUrl);
|
void connectToMCPRelay(relayUrl);
|
||||||
|
|
||||||
// If this is a browser_navigate command, hide the tab list and show simple allow/reject
|
// If this is a browser_navigate command, hide the tab list and show simple allow/reject
|
||||||
@@ -199,50 +181,11 @@ const ConnectApp: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const VersionMismatchError: React.FC<{ pwMcpVersion: string; extensionVersion: string; downloadUrl: string }> = ({ pwMcpVersion, extensionVersion, downloadUrl }) => {
|
|
||||||
const readmeUrl = 'https://github.com/microsoft/playwright-mcp/blob/main/extension/README.md';
|
|
||||||
|
|
||||||
const handleDownloadAndOpenExtensions = () => {
|
|
||||||
// Start download
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = downloadUrl;
|
|
||||||
link.download = `playwright-mcp-extension-v${extensionVersion}.zip`;
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
|
|
||||||
if (tabs[0]?.id)
|
|
||||||
chrome.tabs.update(tabs[0].id, { url: 'chrome://extensions/' });
|
|
||||||
});
|
|
||||||
}, 1000); // Wait 1 second for download to initiate
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
Incompatible Playwright MCP version: {pwMcpVersion} (extension version: {extensionVersion}).{' '}
|
|
||||||
<button
|
|
||||||
onClick={handleDownloadAndOpenExtensions}
|
|
||||||
className='link-button'
|
|
||||||
>Click here</button> to download the matching extension, then drag and drop it into the Chrome Extensions page.{' '}
|
|
||||||
See <a href={readmeUrl} target='_blank' rel='noopener noreferrer'>installation instructions</a> for more details.
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const StatusBanner: React.FC<{ status: Status }> = ({ status }) => {
|
const StatusBanner: React.FC<{ status: Status }> = ({ status }) => {
|
||||||
return (
|
return (
|
||||||
<div className={`status-banner ${status.type}`}>
|
<div className={`status-banner ${status.type}`}>
|
||||||
{'versionMismatch' in status ? (
|
{status.message}
|
||||||
<VersionMismatchError
|
|
||||||
pwMcpVersion={status.versionMismatch.pwMcpVersion}
|
|
||||||
extensionVersion={status.versionMismatch.extensionVersion}
|
|
||||||
downloadUrl={status.versionMismatch.downloadUrl}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
status.message
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { chromium } from 'playwright';
|
import { chromium } from 'playwright';
|
||||||
import packageJSON from '../../package.json' assert { type: 'json' };
|
|
||||||
import { test as base, expect } from '../../tests/fixtures.js';
|
import { test as base, expect } from '../../tests/fixtures.js';
|
||||||
|
|
||||||
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||||
@@ -117,7 +116,7 @@ async function startWithExtensionFlag(browserWithExtension: BrowserWithExtension
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
const testWithOldVersion = test.extend({
|
const testWithOldExtensionVersion = test.extend({
|
||||||
pathToExtension: async ({}, use, testInfo) => {
|
pathToExtension: async ({}, use, testInfo) => {
|
||||||
const extensionDir = testInfo.outputPath('extension');
|
const extensionDir = testInfo.outputPath('extension');
|
||||||
const oldPath = fileURLToPath(new URL('../dist', import.meta.url));
|
const oldPath = fileURLToPath(new URL('../dist', import.meta.url));
|
||||||
@@ -216,7 +215,7 @@ for (const [mode, startClientMethod] of [
|
|||||||
await confirmationPagePromise;
|
await confirmationPagePromise;
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithOldVersion(`extension version mismatch (${mode})`, async ({ browserWithExtension, startClient, server, useShortConnectionTimeout }) => {
|
testWithOldExtensionVersion(`works with old extension version (${mode})`, async ({ browserWithExtension, startClient, server, useShortConnectionTimeout }) => {
|
||||||
useShortConnectionTimeout(500);
|
useShortConnectionTimeout(500);
|
||||||
|
|
||||||
// Prelaunch the browser, so that it is properly closed after the test.
|
// Prelaunch the browser, so that it is properly closed after the test.
|
||||||
@@ -233,19 +232,13 @@ for (const [mode, startClientMethod] of [
|
|||||||
arguments: { url: server.HELLO_WORLD },
|
arguments: { url: server.HELLO_WORLD },
|
||||||
});
|
});
|
||||||
|
|
||||||
const confirmationPage = await confirmationPagePromise;
|
const selectorPage = await confirmationPagePromise;
|
||||||
await expect(confirmationPage.locator('.status-banner')).toHaveText(`Incompatible Playwright MCP version: ${packageJSON.version} (extension version: 0.0.1). Click here to download the matching extension, then drag and drop it into the Chrome Extensions page. See installation instructions for more details.`);
|
// For browser_navigate command, the UI shows Allow/Reject buttons instead of tab selector
|
||||||
|
await selectorPage.getByRole('button', { name: 'Allow' }).click();
|
||||||
|
|
||||||
expect(await navigateResponse).toHaveResponse({
|
expect(await navigateResponse).toHaveResponse({
|
||||||
result: expect.stringContaining('Extension connection timeout.'),
|
pageState: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
|
||||||
isError: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const downloadPromise = confirmationPage.waitForEvent('download');
|
|
||||||
await confirmationPage.locator('.status-banner').getByRole('button', { name: 'Click here' }).click();
|
|
||||||
const download = await downloadPromise;
|
|
||||||
expect(download.url()).toBe(`https://github.com/microsoft/playwright-mcp/releases/download/v0.0.1/playwright-mcp-extension-v0.0.1.zip`);
|
|
||||||
await download.cancel();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import { WebSocket, WebSocketServer } from 'ws';
|
|||||||
import { httpAddressToString } from '../mcp/http.js';
|
import { httpAddressToString } from '../mcp/http.js';
|
||||||
import { logUnhandledError } from '../utils/log.js';
|
import { logUnhandledError } from '../utils/log.js';
|
||||||
import { ManualPromise } from '../mcp/manualPromise.js';
|
import { ManualPromise } from '../mcp/manualPromise.js';
|
||||||
import { packageJSON } from '../utils/package.js';
|
|
||||||
|
|
||||||
import type websocket from 'ws';
|
import type websocket from 'ws';
|
||||||
import type { ClientInfo } from '../browserContextFactory.js';
|
import type { ClientInfo } from '../browserContextFactory.js';
|
||||||
@@ -120,7 +119,6 @@ export class CDPRelayServer {
|
|||||||
version: clientInfo.version,
|
version: clientInfo.version,
|
||||||
};
|
};
|
||||||
url.searchParams.set('client', JSON.stringify(client));
|
url.searchParams.set('client', JSON.stringify(client));
|
||||||
url.searchParams.set('pwMcpVersion', packageJSON.version);
|
|
||||||
if (toolName)
|
if (toolName)
|
||||||
url.searchParams.set('newTab', String(toolName === 'browser_navigate'));
|
url.searchParams.set('newTab', String(toolName === 'browser_navigate'));
|
||||||
const href = url.toString();
|
const href = url.toString();
|
||||||
|
|||||||
Reference in New Issue
Block a user