test/docs: add cookie workaround for issue #66 and skip failing repro
Add a focused regression test that reads page cookies via Network.getCookies through a page CDP session in extension mode. Keep the Storage.getCookies issue #66 reproduction test skipped with an explicit note that Storage.getCookies is unsupported in this relay path and document the required workaround in skill.md.
This commit is contained in:
@@ -312,6 +312,116 @@ describe('Relay Core Tests', () => {
|
|||||||
expect(result.content).toBeDefined()
|
expect(result.content).toBeDefined()
|
||||||
}, 30000)
|
}, 30000)
|
||||||
|
|
||||||
|
// Repro test for https://github.com/remorses/playwriter/issues/66.
|
||||||
|
// Current limitation: extension-mode routing does not support root-session
|
||||||
|
// Storage.getCookies in playwriter. MUST use Network.getCookies via page CDP
|
||||||
|
// session instead (see test below), so this repro stays skipped.
|
||||||
|
it.skip('should reproduce page.route failure in MCP execute path (issue #66)', async () => {
|
||||||
|
const server = await createSimpleServer({
|
||||||
|
routes: {
|
||||||
|
'/': '<!doctype html><html><body>route issue repro</body></html>',
|
||||||
|
'/api/data': '{"ok":true}',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await client.callTool({
|
||||||
|
name: 'execute',
|
||||||
|
arguments: {
|
||||||
|
code: js`
|
||||||
|
const newPage = await context.newPage();
|
||||||
|
state.issue66Page = newPage;
|
||||||
|
await newPage.goto('${server.baseUrl}', { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
|
let routeFetchError = null;
|
||||||
|
await newPage.route('**/api/**', async (route) => {
|
||||||
|
try {
|
||||||
|
const response = await route.fetch();
|
||||||
|
await route.fulfill({ response });
|
||||||
|
} catch (error) {
|
||||||
|
routeFetchError = error instanceof Error ? error.message : String(error);
|
||||||
|
await route.abort();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await newPage.evaluate(async () => {
|
||||||
|
await fetch('/api/data').catch(() => null);
|
||||||
|
});
|
||||||
|
|
||||||
|
return { routeFetchError };
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const resultWithContent = result as { content?: unknown }
|
||||||
|
const content = Array.isArray(resultWithContent.content) ? resultWithContent.content : []
|
||||||
|
const firstContent = content[0]
|
||||||
|
const output =
|
||||||
|
typeof firstContent === 'object' && firstContent !== null && 'text' in firstContent
|
||||||
|
? String((firstContent as { text?: unknown }).text ?? '')
|
||||||
|
: ''
|
||||||
|
expect(output).toContain('routeFetchError')
|
||||||
|
expect(output).toContain('Storage.getCookies')
|
||||||
|
expect(output).toContain('No tab found for method Storage.getCookies')
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
await client.callTool({
|
||||||
|
name: 'execute',
|
||||||
|
arguments: {
|
||||||
|
code: js`
|
||||||
|
if (state.issue66Page && !state.issue66Page.isClosed()) {
|
||||||
|
await state.issue66Page.close();
|
||||||
|
}
|
||||||
|
delete state.issue66Page;
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
// Ignore cleanup failure if MCP disconnected due to the repro.
|
||||||
|
}
|
||||||
|
await server.close()
|
||||||
|
}
|
||||||
|
}, 30000)
|
||||||
|
|
||||||
|
it('should read cookies via Network.getCookies through page CDP session', async () => {
|
||||||
|
const browserContext = getBrowserContext()
|
||||||
|
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
||||||
|
|
||||||
|
const server = await createSimpleServer({
|
||||||
|
routes: {
|
||||||
|
'/': '<!doctype html><html><body>cookies test</body></html>',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const page = await browserContext.newPage()
|
||||||
|
try {
|
||||||
|
await page.goto(server.baseUrl, { waitUntil: 'domcontentloaded' })
|
||||||
|
await page.bringToFront()
|
||||||
|
|
||||||
|
await serviceWorker.evaluate(async () => {
|
||||||
|
await globalThis.toggleExtensionForActiveTab()
|
||||||
|
})
|
||||||
|
|
||||||
|
await new Promise((r) => {
|
||||||
|
setTimeout(r, 200)
|
||||||
|
})
|
||||||
|
|
||||||
|
await page.evaluate(() => {
|
||||||
|
document.cookie = 'issue66=ok; path=/'
|
||||||
|
})
|
||||||
|
|
||||||
|
const cdpSession = await getCDPSessionForPage({ page })
|
||||||
|
const cookiesResult = await cdpSession.send('Network.getCookies', { urls: [page.url()] })
|
||||||
|
const cookie = cookiesResult.cookies.find((value) => {
|
||||||
|
return value.name === 'issue66'
|
||||||
|
})
|
||||||
|
expect(cookie?.value).toBe('ok')
|
||||||
|
} finally {
|
||||||
|
await page.close()
|
||||||
|
await server.close()
|
||||||
|
}
|
||||||
|
}, 30000)
|
||||||
|
|
||||||
it('should show extension as connected for pages created via newPage()', async () => {
|
it('should show extension as connected for pages created via newPage()', async () => {
|
||||||
const browserContext = getBrowserContext()
|
const browserContext = getBrowserContext()
|
||||||
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
||||||
|
|||||||
@@ -533,6 +533,16 @@ const data = await state.page.evaluate(async (url) => {
|
|||||||
}, 'https://example.com/protected/resource')
|
}, 'https://example.com/protected/resource')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Read page cookies via CDP** - use `Network.getCookies` on the page CDP session:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const cdp = await getCDPSession({ page: state.page })
|
||||||
|
const { cookies } = await cdp.send('Network.getCookies', { urls: [state.page.url()] })
|
||||||
|
console.log(cookies)
|
||||||
|
```
|
||||||
|
|
||||||
|
MUST use this for page-scoped cookies in extension mode. `Storage.getCookies` is a root-session command and will fail in playwriter.
|
||||||
|
|
||||||
**Downloading large data** - console output truncates large strings. Trigger a browser download instead:
|
**Downloading large data** - console output truncates large strings. Trigger a browser download instead:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|||||||
Reference in New Issue
Block a user