diff --git a/extension/src/ui/connect.css b/extension/src/ui/connect.css index e86a20b..60945d4 100644 --- a/extension/src/ui/connect.css +++ b/extension/src/ui/connect.css @@ -192,4 +192,15 @@ body { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; +} + +/* Link-style button */ +.link-button { + background: none; + border: none; + color: #0066cc; + text-decoration: underline; + cursor: pointer; + padding: 0; + font: inherit; } \ No newline at end of file diff --git a/extension/src/ui/connect.tsx b/extension/src/ui/connect.tsx index e8c7812..301596e 100644 --- a/extension/src/ui/connect.tsx +++ b/extension/src/ui/connect.tsx @@ -23,7 +23,7 @@ type Status = | { type: 'connecting'; message: string } | { type: 'connected'; message: string } | { type: 'error'; message: string } - | { type: 'error'; versionMismatch: { pwMcpVersion: string; extensionVersion: string } }; + | { type: 'error'; versionMismatch: { pwMcpVersion: string; extensionVersion: string; downloadUrl: string } }; const ConnectApp: React.FC = () => { const [tabs, setTabs] = useState([]); @@ -61,13 +61,15 @@ const ConnectApp: React.FC = () => { 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 + extensionVersion, + downloadUrl } }); return; @@ -176,13 +178,34 @@ const ConnectApp: React.FC = () => { ); }; -const VersionMismatchError: React.FC<{ pwMcpVersion: string; extensionVersion: string }> = ({ pwMcpVersion, extensionVersion }) => { +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 (
- Incompatible Playwright MCP version: {pwMcpVersion} (extension version: {extensionVersion}). - Please install the latest version of the extension.{' '} - See installation instructions. + Incompatible Playwright MCP version: {pwMcpVersion} (extension version: {extensionVersion}).{' '} + to download the matching extension, then drag and drop it into the Chrome Extensions page.{' '} + See installation instructions for more details.
); }; @@ -191,7 +214,11 @@ const StatusBanner: React.FC<{ status: Status }> = ({ status }) => { return (
{'versionMismatch' in status ? ( - + ) : ( status.message )} diff --git a/extension/tests/extension.spec.ts b/extension/tests/extension.spec.ts index e66e636..fe60fb4 100644 --- a/extension/tests/extension.spec.ts +++ b/extension/tests/extension.spec.ts @@ -233,12 +233,18 @@ for (const [mode, startClientMethod] of [ }); const confirmationPage = await confirmationPagePromise; - await expect(confirmationPage.locator('.status-banner')).toHaveText(`Incompatible Playwright MCP version: ${packageJSON.version} (extension version: 0.0.1). Please install the latest version of the extension. See installation instructions.`); + 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.`); expect(await navigateResponse).toHaveResponse({ result: expect.stringContaining('Extension connection timeout.'), 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(); }); }