Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(navigations): remove LifecycleWatcher, fix flakes #882

Merged
merged 4 commits into from Feb 11, 2020

Conversation

JoelEinbinder
Copy link
Contributor

@JoelEinbinder JoelEinbinder commented Feb 7, 2020

Chromium flaked some tests on the bots, and I ended up refactoring all of our navigation code. ptal

Copy link
Contributor

@dgozman dgozman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, but I'll take one more look.

utils/testserver/index.js Outdated Show resolved Hide resolved
src/frames.ts Outdated Show resolved Hide resolved
src/frames.ts Outdated Show resolved Hide resolved
src/frames.ts Outdated Show resolved Hide resolved
src/frames.ts Outdated Show resolved Hide resolved
src/frames.ts Show resolved Hide resolved
src/frames.ts Outdated Show resolved Hide resolved
src/frames.ts Outdated
if (!initial) {
for (const watcher of this._lifecycleWatchers)
watcher._onCommittedNewDocumentNavigation(frame);
// TODO should the document watchers only fire if !initial?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was important for webkit, otherwise we used to resolve waitForNavigation() with about:blank on cross-process navigation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't appear to be the case. I added a test.

// For some reason, Firefox issues load event with one outstanding request.
const failed = page.goto(server.PREFIX + '/one-style.html', { waitUntil: FFOX ? 'networkidle0' : 'load' }).catch(e => e);
await server.waitForRequest('/one-style.css');
it('should fail when canceled by another navigation', async({page, server}) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, we would reject any navigation promises if the page navigated somewhere before the lifecycle events occurred. But that sometimes had false positives. Consider

<script>
window.location.href = 'https://www.microsoft.com';
</script>

This page will redirect to microsoft.com before the 'load' event. But everything is working as intended. This patch changes the behavior to no longer reject the goto promise.

The case this test is testing for can now only be detected if the navigation is interrupted before the document commits. This has a different error message per browser, all variations on the document request being aborted.

server.setRoute('/one-style.css', (req, res) => response = res);
const navigationPromise = page.goto(server.PREFIX + '/one-style.html');
await server.waitForRequest('/one-style.css');
await page.goto(server.PREFIX + '/one-style.html', {waitUntil: []});
const error = await page.waitForLoadState({ timeout: 1 }).catch(e => e);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test could fake if waitForLoadState ran before the document committed with page.goto.

@@ -345,7 +341,10 @@ export class FrameManager {
export class Frame {
_id: string;
readonly _firedLifecycleEvents: Set<LifecycleEvent>;
_lastDocumentId: string;
_lastDocumentId = '';
_requestWatchers = new Set<(request: network.Request) => void>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: these watcher sets can now be private

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately they can't. Private means class private, and they are used by the frame manager.

return {dispose, value: requestMap};
}

_createFrameDestroyedPromise(): Promise<Error> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can create this once in constructor and call it this._detachedOrDisconnectedPromise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started with that, but it made the error messages have bad stacks. I added a test for this as well :)

@JoelEinbinder JoelEinbinder merged commit 251ad38 into microsoft:master Feb 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants