fix(remote): make sure api calls reject before browser is closed (#31858)
Upon calling `browser.close()` or dropping remote connection, make sure to reject api calls before resolving `browser.close()` and firing a `disconnected` event. This change aligns the order guarantee with non-remote case.
This commit is contained in:
parent
0c6ecf8df4
commit
d8d5289e86
|
|
@ -151,8 +151,14 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
||||||
page._onClose();
|
page._onClose();
|
||||||
context._onClose();
|
context._onClose();
|
||||||
}
|
}
|
||||||
browser?._didClose();
|
|
||||||
connection.close(reason || closeError);
|
connection.close(reason || closeError);
|
||||||
|
// Give a chance to any API call promises to reject upon page/context closure.
|
||||||
|
// This happens naturally when we receive page.onClose and browser.onClose from the server
|
||||||
|
// in separate tasks. However, upon pipe closure we used to dispatch them all synchronously
|
||||||
|
// here and promises did not have a chance to reject.
|
||||||
|
// The order of rejects vs closure is a part of the API contract and our test runner
|
||||||
|
// relies on it to attribute rejections to the right test.
|
||||||
|
setTimeout(() => browser?._didClose(), 0);
|
||||||
};
|
};
|
||||||
pipe.on('closed', params => onPipeClosed(params.reason));
|
pipe.on('closed', params => onPipeClosed(params.reason));
|
||||||
connection.onmessage = message => this._wrapApiCall(() => pipe.send({ message }).catch(() => onPipeClosed()), /* isInternal */ true);
|
connection.onmessage = message => this._wrapApiCall(() => pipe.send({ message }).catch(() => onPipeClosed()), /* isInternal */ true);
|
||||||
|
|
|
||||||
|
|
@ -408,6 +408,29 @@ for (const kind of ['launchServer', 'run-server'] as const) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should reject waitForEvent before browser.close finishes', async ({ connect, startRemoteServer, server }) => {
|
||||||
|
const remoteServer = await startRemoteServer(kind);
|
||||||
|
const browser = await connect(remoteServer.wsEndpoint());
|
||||||
|
const newPage = await browser.newPage();
|
||||||
|
let rejected = false;
|
||||||
|
const promise = newPage.waitForEvent('download').catch(() => rejected = true);
|
||||||
|
await browser.close();
|
||||||
|
expect(rejected).toBe(true);
|
||||||
|
await promise;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should reject waitForEvent before browser.onDisconnect fires', async ({ connect, startRemoteServer, server }) => {
|
||||||
|
const remoteServer = await startRemoteServer(kind);
|
||||||
|
const browser = await connect(remoteServer.wsEndpoint());
|
||||||
|
const newPage = await browser.newPage();
|
||||||
|
const log: string[] = [];
|
||||||
|
const promise = newPage.waitForEvent('download').catch(() => log.push('rejected'));
|
||||||
|
browser.on('disconnected', () => log.push('disconnected'));
|
||||||
|
await remoteServer.close();
|
||||||
|
await promise;
|
||||||
|
await expect.poll(() => log).toEqual(['rejected', 'disconnected']);
|
||||||
|
});
|
||||||
|
|
||||||
test('should respect selectors', async ({ playwright, connect, startRemoteServer }) => {
|
test('should respect selectors', async ({ playwright, connect, startRemoteServer }) => {
|
||||||
const remoteServer = await startRemoteServer(kind);
|
const remoteServer = await startRemoteServer(kind);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue