fix(webkit): fix a couple of navigation tests (#217)

This commit is contained in:
Pavel Feldman 2019-12-11 17:46:26 -08:00 committed by Dmitry Gozman
parent cdace02e62
commit 7c7c13e89d
4 changed files with 44 additions and 23 deletions

View file

@ -638,7 +638,7 @@ export class LifecycleWatcher {
frame._page._lifecycleWatchers.add(this); frame._page._lifecycleWatchers.add(this);
this._listeners = [ this._listeners = [
helper.addEventListener(this._frame._page, Events.Page.Request, (request: network.Request) => { helper.addEventListener(this._frame._page, Events.Page.Request, (request: network.Request) => {
if (request.frame() === this._frame && request.isNavigationRequest()) if (request.frame() === this._frame && request.isNavigationRequest() && (!this._navigationRequest || request.redirectChain().includes(this._navigationRequest)))
this._navigationRequest = request; this._navigationRequest = request;
}), }),
]; ];
@ -681,7 +681,7 @@ export class LifecycleWatcher {
} }
navigationResponse(): Promise<network.Response | null> { navigationResponse(): Promise<network.Response | null> {
return this._navigationRequest ? this._navigationRequest._waitForFinishedResponse() : null; return this._navigationRequest ? this._navigationRequest._waitForFinished() : null;
} }
private _createTimeoutPromise(timeout: number): Promise<Error | null> { private _createTimeoutPromise(timeout: number): Promise<Error | null> {

View file

@ -82,6 +82,8 @@ export class Request {
private _frame: frames.Frame; private _frame: frames.Frame;
private _waitForResponsePromise: Promise<Response>; private _waitForResponsePromise: Promise<Response>;
private _waitForResponsePromiseCallback: (value?: Response) => void; private _waitForResponsePromiseCallback: (value?: Response) => void;
private _waitForFinishedPromise: Promise<Response | undefined>;
private _waitForFinishedPromiseCallback: (value?: Response | undefined) => void;
constructor(frame: frames.Frame | null, redirectChain: Request[], isNavigationRequest: boolean, constructor(frame: frames.Frame | null, redirectChain: Request[], isNavigationRequest: boolean,
url: string, resourceType: string, method: string, postData: string, headers: Headers) { url: string, resourceType: string, method: string, postData: string, headers: Headers) {
@ -94,10 +96,12 @@ export class Request {
this._postData = postData; this._postData = postData;
this._headers = headers; this._headers = headers;
this._waitForResponsePromise = new Promise(f => this._waitForResponsePromiseCallback = f); this._waitForResponsePromise = new Promise(f => this._waitForResponsePromiseCallback = f);
this._waitForFinishedPromise = new Promise(f => this._waitForFinishedPromiseCallback = f);
} }
_setFailureText(failureText: string) { _setFailureText(failureText: string) {
this._failureText = failureText; this._failureText = failureText;
this._waitForFinishedPromiseCallback();
} }
url(): string { url(): string {
@ -124,15 +128,20 @@ export class Request {
return this._response; return this._response;
} }
async _waitForFinishedResponse(): Promise<Response> { async _waitForFinished(): Promise<Response | undefined> {
return this._waitForFinishedPromise;
}
async _waitForResponse(): Promise<Response> {
const response = await this._waitForResponsePromise; const response = await this._waitForResponsePromise;
await response._requestFinishedPromise; await response._finishedPromise;
return response; return response;
} }
_setResponse(response: Response) { _setResponse(response: Response) {
this._response = response; this._response = response;
this._waitForResponsePromiseCallback(response); this._waitForResponsePromiseCallback(response);
response._finishedPromise.then(() => this._waitForFinishedPromiseCallback(response));
} }
frame(): frames.Frame | null { frame(): frames.Frame | null {
@ -166,8 +175,8 @@ type GetResponseBodyCallback = () => Promise<Buffer>;
export class Response { export class Response {
private _request: Request; private _request: Request;
private _contentPromise: Promise<Buffer> | null = null; private _contentPromise: Promise<Buffer> | null = null;
_requestFinishedPromise: Promise<Error | null>; _finishedPromise: Promise<Error | null>;
private _requestFinishedPromiseCallback: any; private _finishedPromiseCallback: any;
private _remoteAddress: RemoteAddress; private _remoteAddress: RemoteAddress;
private _status: number; private _status: number;
private _statusText: string; private _statusText: string;
@ -177,20 +186,20 @@ export class Response {
constructor(request: Request, status: number, statusText: string, headers: Headers, remoteAddress: RemoteAddress, getResponseBodyCallback: GetResponseBodyCallback) { constructor(request: Request, status: number, statusText: string, headers: Headers, remoteAddress: RemoteAddress, getResponseBodyCallback: GetResponseBodyCallback) {
this._request = request; this._request = request;
this._request._setResponse(this);
this._status = status; this._status = status;
this._statusText = statusText; this._statusText = statusText;
this._url = request.url(); this._url = request.url();
this._headers = headers; this._headers = headers;
this._remoteAddress = remoteAddress; this._remoteAddress = remoteAddress;
this._getResponseBodyCallback = getResponseBodyCallback; this._getResponseBodyCallback = getResponseBodyCallback;
this._requestFinishedPromise = new Promise(f => { this._finishedPromise = new Promise(f => {
this._requestFinishedPromiseCallback = f; this._finishedPromiseCallback = f;
}); });
this._request._setResponse(this);
} }
_requestFinished(error?: Error) { _requestFinished(error?: Error) {
this._requestFinishedPromiseCallback.call(null, error); this._finishedPromiseCallback.call(null, error);
} }
remoteAddress(): RemoteAddress { remoteAddress(): RemoteAddress {
@ -219,7 +228,7 @@ export class Response {
buffer(): Promise<Buffer> { buffer(): Promise<Buffer> {
if (!this._contentPromise) { if (!this._contentPromise) {
this._contentPromise = this._requestFinishedPromise.then(async error => { this._contentPromise = this._finishedPromise.then(async error => {
if (error) if (error)
throw error; throw error;
return this._getResponseBodyCallback(); return this._getResponseBodyCallback();

View file

@ -79,7 +79,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
this._page = new Page(this, browserContext); this._page = new Page(this, browserContext);
this._networkManager.on(NetworkManagerEvents.Request, event => this._page.emit(Events.Page.Request, event)); this._networkManager.on(NetworkManagerEvents.Request, event => this._page.emit(Events.Page.Request, event));
this._networkManager.on(NetworkManagerEvents.Response, event => this._page.emit(Events.Page.Response, event)); this._networkManager.on(NetworkManagerEvents.Response, event => this._page.emit(Events.Page.Response, event));
this._networkManager.on(NetworkManagerEvents.RequestFailed, event => this._page.emit(Events.Page.RequestFailed, event)); this._networkManager.on(NetworkManagerEvents.RequestFailed, event => this._requestFailed(event));
this._networkManager.on(NetworkManagerEvents.RequestFinished, event => this._page.emit(Events.Page.RequestFinished, event)); this._networkManager.on(NetworkManagerEvents.RequestFinished, event => this._page.emit(Events.Page.RequestFinished, event));
} }
@ -551,4 +551,12 @@ export class FrameManager extends EventEmitter implements PageDelegate {
async resetViewport(oldSize: types.Size): Promise<void> { async resetViewport(oldSize: types.Size): Promise<void> {
await this._session.send('Emulation.setDeviceMetricsOverride', { ...oldSize, deviceScaleFactor: 0 }); await this._session.send('Emulation.setDeviceMetricsOverride', { ...oldSize, deviceScaleFactor: 0 });
} }
private _requestFailed(request: network.Request) {
if (request.isNavigationRequest() && request.failure().errorText !== 'Load request cancelled') {
request.frame()._onExpectedNewDocumentNavigation('fake-loader-id', request.url());
request.frame()._onAbortedNewDocumentNavigation('fake-loader-id', request.failure().errorText);
}
this._page.emit(Events.Page.RequestFailed, request);
}
} }

View file

@ -73,7 +73,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
const response = await page.goto(server.EMPTY_PAGE, {waitUntil: 'domcontentloaded'}); const response = await page.goto(server.EMPTY_PAGE, {waitUntil: 'domcontentloaded'});
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
}); });
it('should work when page calls history API in beforeunload', async({page, server}) => { it.skip(WEBKIT)('should work when page calls history API in beforeunload', async({page, server}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => { await page.evaluate(() => {
window.addEventListener('beforeunload', () => history.replaceState(null, 'initial', window.location.href), false); window.addEventListener('beforeunload', () => history.replaceState(null, 'initial', window.location.href), false);
@ -98,7 +98,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
else else
expect(error.message).toContain('Invalid url'); expect(error.message).toContain('Invalid url');
}); });
it.skip(WEBKIT)('should fail when navigating to bad SSL', async({page, httpsServer}) => { it('should fail when navigating to bad SSL', async({page, httpsServer}) => {
// Make sure that network events do not emit 'undefined'. // Make sure that network events do not emit 'undefined'.
// @see https://crbug.com/750469 // @see https://crbug.com/750469
page.on('request', request => expect(request).toBeTruthy()); page.on('request', request => expect(request).toBeTruthy());
@ -106,20 +106,22 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
page.on('requestfailed', request => expect(request).toBeTruthy()); page.on('requestfailed', request => expect(request).toBeTruthy());
let error = null; let error = null;
await page.goto(httpsServer.EMPTY_PAGE).catch(e => error = e); await page.goto(httpsServer.EMPTY_PAGE).catch(e => error = e);
// FIXME: shows dialog in WebKit. if (CHROME)
if (CHROME || WEBKIT)
expect(error.message).toContain('net::ERR_CERT_AUTHORITY_INVALID'); expect(error.message).toContain('net::ERR_CERT_AUTHORITY_INVALID');
else if (WEBKIT)
expect(error.message).toContain('Unacceptable TLS certificate');
else else
expect(error.message).toContain('SSL_ERROR_UNKNOWN'); expect(error.message).toContain('SSL_ERROR_UNKNOWN');
}); });
it.skip(WEBKIT)('should fail when navigating to bad SSL after redirects', async({page, server, httpsServer}) => { it('should fail when navigating to bad SSL after redirects', async({page, server, httpsServer}) => {
server.setRedirect('/redirect/1.html', '/redirect/2.html'); server.setRedirect('/redirect/1.html', '/redirect/2.html');
server.setRedirect('/redirect/2.html', '/empty.html'); server.setRedirect('/redirect/2.html', '/empty.html');
let error = null; let error = null;
await page.goto(httpsServer.PREFIX + '/redirect/1.html').catch(e => error = e); await page.goto(httpsServer.PREFIX + '/redirect/1.html').catch(e => error = e);
// FIXME: shows dialog in WebKit. if (CHROME)
if (CHROME || WEBKIT)
expect(error.message).toContain('net::ERR_CERT_AUTHORITY_INVALID'); expect(error.message).toContain('net::ERR_CERT_AUTHORITY_INVALID');
else if (WEBKIT)
expect(error.message).toContain('Unacceptable TLS certificate');
else else
expect(error.message).toContain('SSL_ERROR_UNKNOWN'); expect(error.message).toContain('SSL_ERROR_UNKNOWN');
}); });
@ -128,11 +130,13 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
await page.goto(server.EMPTY_PAGE, {waitUntil: 'networkidle'}).catch(err => error = err); await page.goto(server.EMPTY_PAGE, {waitUntil: 'networkidle'}).catch(err => error = err);
expect(error.message).toContain('"networkidle" option is no longer supported'); expect(error.message).toContain('"networkidle" option is no longer supported');
}); });
it.skip(WEBKIT)('should fail when main resources failed to load', async({page, server}) => { it('should fail when main resources failed to load', async({page, server}) => {
let error = null; let error = null;
await page.goto('http://localhost:44123/non-existing-url').catch(e => error = e); await page.goto('http://localhost:44123/non-existing-url').catch(e => error = e);
if (CHROME || WEBKIT) if (CHROME)
expect(error.message).toContain('net::ERR_CONNECTION_REFUSED'); expect(error.message).toContain('net::ERR_CONNECTION_REFUSED');
else if (WEBKIT)
expect(error.message).toContain('Could not connect: Connection refused');
else else
expect(error.message).toContain('NS_ERROR_CONNECTION_REFUSED'); expect(error.message).toContain('NS_ERROR_CONNECTION_REFUSED');
}); });
@ -311,12 +315,12 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
expect(requests.length).toBe(1); expect(requests.length).toBe(1);
expect(requests[0].url()).toBe(server.EMPTY_PAGE); expect(requests[0].url()).toBe(server.EMPTY_PAGE);
}); });
it.skip(WEBKIT)('should work with self requesting page', async({page, server}) => { it('should work with self requesting page', async({page, server}) => {
const response = await page.goto(server.PREFIX + '/self-request.html'); const response = await page.goto(server.PREFIX + '/self-request.html');
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
expect(response.url()).toContain('self-request.html'); expect(response.url()).toContain('self-request.html');
}); });
it.skip(WEBKIT)('should fail when navigating and show the url at the error message', async function({page, server, httpsServer}) { it('should fail when navigating and show the url at the error message', async function({page, server, httpsServer}) {
const url = httpsServer.PREFIX + '/redirect/1.html'; const url = httpsServer.PREFIX + '/redirect/1.html';
let error = null; let error = null;
try { try {