fix(recorder): reattach toolbar if it was unmounted by framework hydration (#32637)

Closes https://github.com/microsoft/playwright/issues/32632. A side
effect of Remix's hydration implementation is that it throws away the
entire DOM. This is broadly discussed in
https://github.com/remix-run/remix/issues/4822 - there might be a fix in
coming React versions, but who knows.
Besides breaking browser extensions, this also deletes our toolbar!
This PR fixes it by periodically checking in on `x-pw-glass`, and
remounting it if it was unmounted. Hacky but effective!
This commit is contained in:
Simon Knott 2024-09-17 08:37:49 +02:00 committed by GitHub
parent 47713e8a66
commit b0f15b320f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 26 additions and 1 deletions

View File

@ -90,7 +90,8 @@ export class Highlight {
}
install() {
this._injectedScript.document.documentElement.appendChild(this._glassPaneElement);
if (!this._injectedScript.document.documentElement.contains(this._glassPaneElement))
this._injectedScript.document.documentElement.appendChild(this._glassPaneElement);
}
setLanguage(language: Language) {

View File

@ -1036,7 +1036,14 @@ export class Recorder {
addEventListener(this.document, 'focus', event => this._onFocus(event), true),
addEventListener(this.document, 'scroll', event => this._onScroll(event), true),
];
this.highlight.install();
// some frameworks erase the DOM on hydration, this ensures it's reattached
const recreationInterval = setInterval(() => {
this.highlight.install();
}, 500);
this._listeners.push(() => clearInterval(recreationInterval));
this.overlay?.install();
this.document.adoptedStyleSheets.push(this._stylesheet);
}

View File

@ -739,4 +739,21 @@ await page.GetByLabel("Coun\\"try").ClickAsync();`);
expect.soft(sources1.get('Java')!.text).toContain(`assertThat(page.getByRole(AriaRole.TEXTBOX)).isVisible()`);
expect.soft(sources1.get('C#')!.text).toContain(`await Expect(page.GetByRole(AriaRole.Textbox)).ToBeVisibleAsync()`);
});
test('should keep toolbar visible even if webpage erases content in hydration', async ({ openRecorder }) => {
const recorder = await openRecorder();
const hydrate = () => {
setTimeout(() => {
document.documentElement.innerHTML = '<p>Post-Hydration Content</p>';
}, 500);
};
await recorder.setContentAndWait(`
<p>Pre-Hydration Content</p>
<script>(${hydrate})()</script>
`);
await expect(recorder.page.getByText('Post-Hydration Content')).toBeVisible();
await expect(recorder.page.locator('x-pw-glass')).toBeVisible();
});
});