mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-15 06:02:57 +03:00
fix(webkit): wait for main response on subresource-free goto (#216)
This commit is contained in:
parent
78847c2f52
commit
6440323003
@ -215,7 +215,7 @@ export class NetworkManager extends EventEmitter {
|
||||
_handleRequestRedirect(request: InterceptableRequest, responsePayload: Protocol.Network.Response) {
|
||||
const response = this._createResponse(request, responsePayload);
|
||||
request.request._redirectChain.push(request.request);
|
||||
response._bodyLoaded(new Error('Response body is unavailable for redirect responses'));
|
||||
response._requestFinished(new Error('Response body is unavailable for redirect responses'));
|
||||
this._requestIdToRequest.delete(request._requestId);
|
||||
this._attemptedAuthentications.delete(request._interceptionId);
|
||||
this.emit(NetworkManagerEvents.Response, response);
|
||||
@ -241,7 +241,7 @@ export class NetworkManager extends EventEmitter {
|
||||
// Under certain conditions we never get the Network.responseReceived
|
||||
// event from protocol. @see https://crbug.com/883475
|
||||
if (request.request.response())
|
||||
request.request.response()._bodyLoaded();
|
||||
request.request.response()._requestFinished();
|
||||
this._requestIdToRequest.delete(request._requestId);
|
||||
this._attemptedAuthentications.delete(request._interceptionId);
|
||||
this.emit(NetworkManagerEvents.RequestFinished, request.request);
|
||||
@ -256,7 +256,7 @@ export class NetworkManager extends EventEmitter {
|
||||
request.request._setFailureText(event.errorText);
|
||||
const response = request.request.response();
|
||||
if (response)
|
||||
response._bodyLoaded();
|
||||
response._requestFinished();
|
||||
this._requestIdToRequest.delete(request._requestId);
|
||||
this._attemptedAuthentications.delete(request._interceptionId);
|
||||
this.emit(NetworkManagerEvents.RequestFailed, request.request);
|
||||
|
@ -111,10 +111,10 @@ export class NetworkManager extends EventEmitter {
|
||||
// Keep redirected requests in the map for future reference in redirectChain.
|
||||
const isRedirected = response.status() >= 300 && response.status() <= 399;
|
||||
if (isRedirected) {
|
||||
response._bodyLoaded(new Error('Response body is unavailable for redirect responses'));
|
||||
response._requestFinished(new Error('Response body is unavailable for redirect responses'));
|
||||
} else {
|
||||
this._requests.delete(request._id);
|
||||
response._bodyLoaded();
|
||||
response._requestFinished();
|
||||
}
|
||||
this.emit(NetworkManagerEvents.RequestFinished, request.request);
|
||||
}
|
||||
@ -125,7 +125,7 @@ export class NetworkManager extends EventEmitter {
|
||||
return;
|
||||
this._requests.delete(request._id);
|
||||
if (request.request.response())
|
||||
request.request.response()._bodyLoaded();
|
||||
request.request.response()._requestFinished();
|
||||
request.request._setFailureText(event.errorCode);
|
||||
this.emit(NetworkManagerEvents.RequestFailed, request.request);
|
||||
}
|
||||
|
@ -680,8 +680,8 @@ export class LifecycleWatcher {
|
||||
this._checkLifecycleComplete();
|
||||
}
|
||||
|
||||
navigationResponse(): network.Response | null {
|
||||
return this._navigationRequest ? this._navigationRequest.response() : null;
|
||||
navigationResponse(): Promise<network.Response | null> {
|
||||
return this._navigationRequest ? this._navigationRequest._waitForFinishedResponse() : null;
|
||||
}
|
||||
|
||||
private _createTimeoutPromise(timeout: number): Promise<Error | null> {
|
||||
|
@ -70,7 +70,7 @@ export function rewriteCookies(cookies: SetNetworkCookieParam[]): SetNetworkCook
|
||||
export type Headers = { [key: string]: string };
|
||||
|
||||
export class Request {
|
||||
_response: Response | null = null;
|
||||
private _response: Response | null = null;
|
||||
_redirectChain: Request[];
|
||||
private _isNavigationRequest: boolean;
|
||||
private _failureText: string | null = null;
|
||||
@ -80,6 +80,8 @@ export class Request {
|
||||
private _postData: string;
|
||||
private _headers: Headers;
|
||||
private _frame: frames.Frame;
|
||||
private _waitForResponsePromise: Promise<Response>;
|
||||
private _waitForResponsePromiseCallback: (value?: Response) => void;
|
||||
|
||||
constructor(frame: frames.Frame | null, redirectChain: Request[], isNavigationRequest: boolean,
|
||||
url: string, resourceType: string, method: string, postData: string, headers: Headers) {
|
||||
@ -91,6 +93,7 @@ export class Request {
|
||||
this._method = method;
|
||||
this._postData = postData;
|
||||
this._headers = headers;
|
||||
this._waitForResponsePromise = new Promise(f => this._waitForResponsePromiseCallback = f);
|
||||
}
|
||||
|
||||
_setFailureText(failureText: string) {
|
||||
@ -121,6 +124,17 @@ export class Request {
|
||||
return this._response;
|
||||
}
|
||||
|
||||
async _waitForFinishedResponse(): Promise<Response> {
|
||||
const response = await this._waitForResponsePromise;
|
||||
await response._requestFinishedPromise;
|
||||
return response;
|
||||
}
|
||||
|
||||
_setResponse(response: Response) {
|
||||
this._response = response;
|
||||
this._waitForResponsePromiseCallback(response);
|
||||
}
|
||||
|
||||
frame(): frames.Frame | null {
|
||||
return this._frame;
|
||||
}
|
||||
@ -152,8 +166,8 @@ type GetResponseBodyCallback = () => Promise<Buffer>;
|
||||
export class Response {
|
||||
private _request: Request;
|
||||
private _contentPromise: Promise<Buffer> | null = null;
|
||||
private _bodyLoadedPromise: Promise<Error | null>;
|
||||
private _bodyLoadedPromiseFulfill: any;
|
||||
_requestFinishedPromise: Promise<Error | null>;
|
||||
private _requestFinishedPromiseCallback: any;
|
||||
private _remoteAddress: RemoteAddress;
|
||||
private _status: number;
|
||||
private _statusText: string;
|
||||
@ -163,20 +177,20 @@ export class Response {
|
||||
|
||||
constructor(request: Request, status: number, statusText: string, headers: Headers, remoteAddress: RemoteAddress, getResponseBodyCallback: GetResponseBodyCallback) {
|
||||
this._request = request;
|
||||
this._request._response = this;
|
||||
this._request._setResponse(this);
|
||||
this._status = status;
|
||||
this._statusText = statusText;
|
||||
this._url = request.url();
|
||||
this._headers = headers;
|
||||
this._remoteAddress = remoteAddress;
|
||||
this._getResponseBodyCallback = getResponseBodyCallback;
|
||||
this._bodyLoadedPromise = new Promise(fulfill => {
|
||||
this._bodyLoadedPromiseFulfill = fulfill;
|
||||
this._requestFinishedPromise = new Promise(f => {
|
||||
this._requestFinishedPromiseCallback = f;
|
||||
});
|
||||
}
|
||||
|
||||
_bodyLoaded(error?: Error) {
|
||||
this._bodyLoadedPromiseFulfill.call(null, error);
|
||||
_requestFinished(error?: Error) {
|
||||
this._requestFinishedPromiseCallback.call(null, error);
|
||||
}
|
||||
|
||||
remoteAddress(): RemoteAddress {
|
||||
@ -205,7 +219,7 @@ export class Response {
|
||||
|
||||
buffer(): Promise<Buffer> {
|
||||
if (!this._contentPromise) {
|
||||
this._contentPromise = this._bodyLoadedPromise.then(async error => {
|
||||
this._contentPromise = this._requestFinishedPromise.then(async error => {
|
||||
if (error)
|
||||
throw error;
|
||||
return this._getResponseBodyCallback();
|
||||
|
@ -115,7 +115,7 @@ export class NetworkManager extends EventEmitter {
|
||||
_handleRequestRedirect(request: InterceptableRequest, responsePayload: Protocol.Network.Response) {
|
||||
const response = this._createResponse(request, responsePayload);
|
||||
request.request._redirectChain.push(request.request);
|
||||
response._bodyLoaded(new Error('Response body is unavailable for redirect responses'));
|
||||
response._requestFinished(new Error('Response body is unavailable for redirect responses'));
|
||||
this._requestIdToRequest.delete(request._requestId);
|
||||
this._attemptedAuthentications.delete(request._interceptionId);
|
||||
this.emit(NetworkManagerEvents.Response, response);
|
||||
@ -141,7 +141,7 @@ export class NetworkManager extends EventEmitter {
|
||||
// Under certain conditions we never get the Network.responseReceived
|
||||
// event from protocol. @see https://crbug.com/883475
|
||||
if (request.request.response())
|
||||
request.request.response()._bodyLoaded();
|
||||
request.request.response()._requestFinished();
|
||||
this._requestIdToRequest.delete(request._requestId);
|
||||
this._attemptedAuthentications.delete(request._interceptionId);
|
||||
this.emit(NetworkManagerEvents.RequestFinished, request.request);
|
||||
@ -156,7 +156,7 @@ export class NetworkManager extends EventEmitter {
|
||||
request.request._setFailureText(event.errorText);
|
||||
const response = request.request.response();
|
||||
if (response)
|
||||
response._bodyLoaded();
|
||||
response._requestFinished();
|
||||
this._requestIdToRequest.delete(request._requestId);
|
||||
this._attemptedAuthentications.delete(request._interceptionId);
|
||||
this.emit(NetworkManagerEvents.RequestFailed, request.request);
|
||||
|
@ -23,7 +23,7 @@ const mkdtempAsync = helper.promisify(fs.mkdtemp);
|
||||
const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-');
|
||||
const utils = require('./utils');
|
||||
|
||||
module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, playwright}) {
|
||||
module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, playwright, WEBKIT}) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
@ -45,7 +45,8 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p
|
||||
await playwright.launch(options).catch(e => waitError = e);
|
||||
expect(waitError.message).toContain('Failed to launch');
|
||||
});
|
||||
it('should set the default viewport', async() => {
|
||||
// Fails on GTK due to async setViewport.
|
||||
it.skip(WEBKIT)('should set the default viewport', async() => {
|
||||
const options = Object.assign({}, defaultBrowserOptions, {
|
||||
defaultViewport: {
|
||||
width: 456,
|
||||
|
@ -234,14 +234,10 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
expect(remoteAddress.port).toBe(server.PORT);
|
||||
});
|
||||
|
||||
// FIXME: requires request interception.
|
||||
it.skip(WEBKIT)('Page.Events.RequestFailed', async({page, server}) => {
|
||||
await page.interception.enable();
|
||||
page.on('request', request => {
|
||||
if (request.url().endsWith('css'))
|
||||
page.interception.abort(request);
|
||||
else
|
||||
page.interception.continue(request);
|
||||
it.skip(FFOX)('Page.Events.RequestFailed', async({page, server}) => {
|
||||
server.setRoute('/one-style.css', (req, res) => {
|
||||
req.socket.write('deadbeef');
|
||||
req.socket.end();
|
||||
});
|
||||
const failedRequests = [];
|
||||
page.on('requestfailed', request => failedRequests.push(request));
|
||||
@ -250,14 +246,15 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
expect(failedRequests[0].url()).toContain('one-style.css');
|
||||
expect(failedRequests[0].response()).toBe(null);
|
||||
expect(failedRequests[0].resourceType()).toBe('stylesheet');
|
||||
if (CHROME || WEBKIT)
|
||||
expect(failedRequests[0].failure().errorText).toBe('net::ERR_FAILED');
|
||||
if (CHROME)
|
||||
expect(failedRequests[0].failure().errorText).toBe('net::ERR_INVALID_HTTP_RESPONSE');
|
||||
else if (WEBKIT)
|
||||
expect(failedRequests[0].failure().errorText).toBe('Message Corrupt');
|
||||
else
|
||||
expect(failedRequests[0].failure().errorText).toBe('NS_ERROR_FAILURE');
|
||||
expect(failedRequests[0].frame()).toBeTruthy();
|
||||
});
|
||||
// FIXME: WebKit requestfinished comes after goto.
|
||||
it.skip(WEBKIT)('Page.Events.RequestFinished', async({page, server}) => {
|
||||
it('Page.Events.RequestFinished', async({page, server}) => {
|
||||
const requests = [];
|
||||
page.on('requestfinished', request => requests.push(request));
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -267,7 +264,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
expect(requests[0].frame() === page.mainFrame()).toBe(true);
|
||||
expect(requests[0].frame().url()).toBe(server.EMPTY_PAGE);
|
||||
});
|
||||
it.skip(WEBKIT)('should fire events in proper order', async({page, server}) => {
|
||||
it('should fire events in proper order', async({page, server}) => {
|
||||
const events = [];
|
||||
page.on('request', request => events.push('request'));
|
||||
page.on('response', response => events.push('response'));
|
||||
@ -275,7 +272,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(events).toEqual(['request', 'response', 'requestfinished']);
|
||||
});
|
||||
it.skip(WEBKIT)('should support redirects', async({page, server}) => {
|
||||
it('should support redirects', async({page, server}) => {
|
||||
const events = [];
|
||||
page.on('request', request => events.push(`${request.method()} ${request.url()}`));
|
||||
page.on('response', response => events.push(`${response.status()} ${response.url()}`));
|
||||
@ -297,7 +294,6 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
const redirectChain = response.request().redirectChain();
|
||||
expect(redirectChain.length).toBe(1);
|
||||
expect(redirectChain[0].url()).toContain('/foo.html');
|
||||
expect(redirectChain[0].response().remoteAddress().port).toBe(server.PORT);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -118,7 +118,7 @@ module.exports.addTests = function({testRunner, expect, headless, playwright, FF
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip(WEBKIT)('Page.Events.Popup', function() {
|
||||
describe('Page.Events.Popup', function() {
|
||||
it('should work', async({page}) => {
|
||||
const [popup] = await Promise.all([
|
||||
new Promise(x => page.once('popup', x)),
|
||||
@ -719,7 +719,7 @@ module.exports.addTests = function({testRunner, expect, headless, playwright, FF
|
||||
expect(await page.evaluate(() => __injected)).toBe(42);
|
||||
});
|
||||
|
||||
it('should include sourceURL when path is provided', async({page, server}) => {
|
||||
(CHROME || FFOX) && it('should include sourceURL when path is provided', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.addScriptTag({ path: path.join(__dirname, 'assets/injectedfile.js') });
|
||||
const result = await page.evaluate(() => __injectedError.stack);
|
||||
|
@ -200,7 +200,8 @@ module.exports.addTests = function({testRunner, expect, product, FFOX, CHROME, W
|
||||
|
||||
expect(await page.evaluate(() => ({ w: window.innerWidth, h: window.innerHeight }))).toEqual({ w: 500, h: 500 });
|
||||
});
|
||||
it('should capture full element when larger than viewport', async({page, server}) => {
|
||||
// Fails on GTK due to async setViewport.
|
||||
it.skip(WEBKIT)('should capture full element when larger than viewport', async({page, server}) => {
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
|
||||
await page.setContent(`
|
||||
|
Loading…
Reference in New Issue
Block a user