microsoft / microsoft/playwright
[Bug]: Firefox never reports domcontentloaded for a document produced by an XSL transform
@dcrousso is already working on this.
Since Aug 26, 2026.
- Dominant language
- TypeScript
- Stars
- 96.3k
- Forks
- 6.5k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 180
Description
### Version
1.62.1
### Steps to reproduce
Serve an XML document that references an XSL stylesheet, then navigate to it with `waitUntil: 'domcontentloaded'`.
```js
import http from 'node:http';
import { chromium, firefox } from 'playwright';
const xsl = `
transformed
`;
const xml = `
hello`;
const server = http.createServer((req, res) => {
const [type, body] = req.url.startsWith('/style.xsl') ? ['text/xsl', xsl] : ['application/xml', xml];
res.writeHead(200, { 'content-type': type });
res.end(body);
});
await new Promise((resolve) => server.listen(0, resolve));
const url = `http://127.0.0.1:${server.address().port}/doc.xml`;
for (const [name, browserType] of Object.entries({ firefox, chromium })) {
const browser = await browserType.launch();
const page = await browser.newPage();
console.log(`\n${name} ${browser.version()}`);
for (const waitUntil of ['domcontentloaded', 'load']) {
const started = Date.now();
try {
await page.goto(url, { waitUntil, timeout: 5000 });
console.log(` goto '${waitUntil}' -> resolved in ${Date.now() - started}ms`);
} catch (error) {
console.log(` goto '${waitUntil}' -> ${error.message.split('\n')[0]}`);
}
}
console.log(` document.readyState: ${await page.evaluate(() => document.readyState)}`);
try {
await page.waitForLoadState('domcontentloaded', { timeout: 5000 });
console.log(' waitForLoadState(domcontentloaded) on the loaded page -> resolved');
} catch (error) {
console.log(` waitForLoadState(domcontentloaded) on the loaded page -> ${error.message.split('\n')[0]}`);
}
await browser.close();
}
server.close();
```
### Expected behavior
goto with waitUntil: 'domcontentloaded' resolves, as it does in Chromium and as waitUntil: 'load' does in Firefox. load cannot fire before DOMContentLoaded, so once the document is loaded, waiting for the earlier event should never block.
### Actual behavior
In Firefox the event is never reported for the transform output, so both goto and waitForLoadState hit their timeout while the document is fully loaded (readyState: 'complete', transformed DOM in place). Retrying and using a fresh browser context change nothing. Chromium is fine.
Any XSL-styled XML page reproduces it, not just the local server above, e.g. `https://yoast.com/sitemap_index.xml`.
### Additional context
_No response_
### Environment
```shell
System:
OS: macOS 26.2
CPU: (14) arm64 Apple M4 Pro
Memory: 237.63 MB / 24.00 GB
Binaries:
Node: 24.15.0 - /Users/.../.nvm/versions/node/v24.15.0/bin/node
npm: 11.12.1 - /Users/.../.nvm/versions/node/v24.15.0/bin/npm
pnpm: 11.15.1 - /opt/homebrew/bin/pnpm
IDEs:
Cursor: 3.15.6 - /usr/local/bin/cursor
Claude Code: 2.1.169 - /Users/.../.local/bin/claude
Languages:
Bash: 3.2.57 - /bin/bash
npmPackages:
@playwright/browser-chromium: 1.62.1 => 1.62.1
@playwright/browser-firefox: 1.62.1 => 1.62.1
playwright: 1.62.1 => 1.62.1
```
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.