fix(events): avoid firing lifecycle events twice (#16055)
Previously, when some iframe started/finished a new navigation, we could have removed and then re-addded load/domcontentloaded on the main frame. Drive-by: unflake wheel test in Firefox.
This commit is contained in:
parent
af8e3e7afa
commit
809002df60
|
|
@ -530,7 +530,7 @@ export class Frame extends SdkObject {
|
||||||
_onClearLifecycle() {
|
_onClearLifecycle() {
|
||||||
this._firedLifecycleEvents.clear();
|
this._firedLifecycleEvents.clear();
|
||||||
// Recalculate subtree lifecycle for the whole tree - it should not be that big.
|
// Recalculate subtree lifecycle for the whole tree - it should not be that big.
|
||||||
this._page.mainFrame()._recalculateLifecycle();
|
this._page.mainFrame()._recalculateLifecycle(this);
|
||||||
// Keep the current navigation request if any.
|
// Keep the current navigation request if any.
|
||||||
this._inflightRequests = new Set(Array.from(this._inflightRequests).filter(request => request === this._currentDocument.request));
|
this._inflightRequests = new Set(Array.from(this._inflightRequests).filter(request => request === this._currentDocument.request));
|
||||||
this._stopNetworkIdleTimer();
|
this._stopNetworkIdleTimer();
|
||||||
|
|
@ -593,10 +593,10 @@ export class Frame extends SdkObject {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_recalculateLifecycle() {
|
_recalculateLifecycle(frameThatAllowsRemovingLifecycleEvents?: Frame) {
|
||||||
const events = new Set<types.LifecycleEvent>(this._firedLifecycleEvents);
|
const events = new Set<types.LifecycleEvent>(this._firedLifecycleEvents);
|
||||||
for (const child of this._childFrames) {
|
for (const child of this._childFrames) {
|
||||||
child._recalculateLifecycle();
|
child._recalculateLifecycle(frameThatAllowsRemovingLifecycleEvents);
|
||||||
// We require a particular lifecycle event to be fired in the whole
|
// We require a particular lifecycle event to be fired in the whole
|
||||||
// frame subtree, and then consider it done.
|
// frame subtree, and then consider it done.
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
|
|
@ -604,6 +604,12 @@ export class Frame extends SdkObject {
|
||||||
events.delete(event);
|
events.delete(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (frameThatAllowsRemovingLifecycleEvents !== this) {
|
||||||
|
// Usually, lifecycle events are fired once and not removed after that, so we keep existing ones.
|
||||||
|
// However, when we clear them right before a new commit, this is allowed for a particular frame.
|
||||||
|
for (const event of this._subtreeLifecycleEvents)
|
||||||
|
events.add(event);
|
||||||
|
}
|
||||||
const mainFrame = this._page.mainFrame();
|
const mainFrame = this._page.mainFrame();
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
// Checking whether we have already notified about this event.
|
// Checking whether we have already notified about this event.
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ it('should fire once', async ({ page, server, browserName }) => {
|
||||||
|
|
||||||
it('should fire once with iframe navigation', async ({ page, server, browserName }) => {
|
it('should fire once with iframe navigation', async ({ page, server, browserName }) => {
|
||||||
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/15086' });
|
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/15086' });
|
||||||
it.fail();
|
it.fixme(browserName === 'firefox', 'Firefox sometimes double fires.');
|
||||||
|
|
||||||
let requestCount = 0;
|
let requestCount = 0;
|
||||||
server.setRoute('/tracker', (_, res) => {
|
server.setRoute('/tracker', (_, res) => {
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,9 @@ it('should work when the event is canceled', async ({ page }) => {
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
document.querySelector('div').addEventListener('wheel', e => e.preventDefault());
|
document.querySelector('div').addEventListener('wheel', e => e.preventDefault());
|
||||||
});
|
});
|
||||||
|
// Give wheel listener a chance to propagate through all the layers in Firefox.
|
||||||
|
for (let i = 0; i < 10; i++)
|
||||||
|
await page.evaluate(() => new Promise(x => requestAnimationFrame(() => requestAnimationFrame(x))));
|
||||||
await page.mouse.wheel(0, 100);
|
await page.mouse.wheel(0, 100);
|
||||||
await expectEvent(page, {
|
await expectEvent(page, {
|
||||||
deltaX: 0,
|
deltaX: 0,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue