feat(fetch): expose .timing()

make responseEnd optional

make it more similar to existing types

missed one!
This commit is contained in:
Simon Knott 2024-09-17 09:23:30 +02:00
parent 751b939d3a
commit 8de8383165
No known key found for this signature in database
GPG key ID: 8CEDC00028084AEC
10 changed files with 130 additions and 5 deletions

View file

@ -110,3 +110,26 @@ Returns the text representation of response body.
- returns: <[string]> - returns: <[string]>
Contains the URL of the response. Contains the URL of the response.
## method: APIResponse.timing
* since: v1.48
- returns: <[Object]>
- `startTime` <[float]> Request start time in milliseconds elapsed since January 1, 1970 00:00:00 UTC
- `domainLookupStart` <[float]> Time immediately before the client starts the domain name lookup for the
resource. The value is given in milliseconds relative to `startTime`, -1 if not available.
- `domainLookupEnd` <[float]> Time immediately after the client ends the domain name lookup for the resource.
The value is given in milliseconds relative to `startTime`, -1 if not available.
- `connectStart` <[float]> Time immediately before the client starts establishing the connection to the server
to retrieve the resource. The value is given in milliseconds relative to `startTime`, -1 if not available.
- `secureConnectionStart` <[float]> Time immediately before the client starts the handshake process to secure the
current connection. The value is given in milliseconds relative to `startTime`, -1 if not available.
- `connectEnd` <[float]> Time immediately before the client starts establishing the connection to the server
to retrieve the resource. The value is given in milliseconds relative to `startTime`, -1 if not available.
- `requestStart` <[float]> Time immediately before the client starts requesting the resource from the server. The value is given in milliseconds relative to `startTime`, -1 if not available.
- `responseStart` <[float]> Time immediately after the client receives the first byte of the response from the server. The value is given in milliseconds relative to `startTime`, -1 if not available.
- `responseEnd` <[float]> Time immediately after the client receives the last byte of the resource or immediately
before the transport connection is closed, whichever comes first. The value is given in milliseconds relative to
`startTime`, -1 if not available.
Returns resource timing information for given response. Find more information at
[Resource Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming).

View file

@ -314,7 +314,7 @@ Returns resource size information for given request.
- `startTime` <[float]> Request start time in milliseconds elapsed since January 1, 1970 00:00:00 UTC - `startTime` <[float]> Request start time in milliseconds elapsed since January 1, 1970 00:00:00 UTC
- `domainLookupStart` <[float]> Time immediately before the browser starts the domain name lookup for the - `domainLookupStart` <[float]> Time immediately before the browser starts the domain name lookup for the
resource. The value is given in milliseconds relative to `startTime`, -1 if not available. resource. The value is given in milliseconds relative to `startTime`, -1 if not available.
- `domainLookupEnd` <[float]> Time immediately after the browser starts the domain name lookup for the resource. - `domainLookupEnd` <[float]> Time immediately after the browser ends the domain name lookup for the resource.
The value is given in milliseconds relative to `startTime`, -1 if not available. The value is given in milliseconds relative to `startTime`, -1 if not available.
- `connectStart` <[float]> Time immediately before the user agent starts establishing the connection to the server - `connectStart` <[float]> Time immediately before the user agent starts establishing the connection to the server
to retrieve the resource. The value is given in milliseconds relative to `startTime`, -1 if not available. to retrieve the resource. The value is given in milliseconds relative to `startTime`, -1 if not available.

View file

@ -332,6 +332,13 @@ export class APIResponse implements api.APIResponse {
return this._headers.headersArray(); return this._headers.headersArray();
} }
timing() {
return {
...this._initializer.timing,
responseEnd: this._initializer.responseEndTiming,
};
}
async body(): Promise<Buffer> { async body(): Promise<Buffer> {
try { try {
const result = await this._request._channel.fetchResponseBody({ fetchUid: this._fetchUid() }); const result = await this._request._channel.fetchResponseBody({ fetchUid: this._fetchUid() });

View file

@ -224,6 +224,8 @@ scheme.APIResponse = tObject({
status: tNumber, status: tNumber,
statusText: tString, statusText: tString,
headers: tArray(tType('NameValue')), headers: tArray(tType('NameValue')),
timing: tType('ResourceTiming'),
responseEndTiming: tNumber,
}); });
scheme.LifecycleEvent = tEnum(['load', 'domcontentloaded', 'networkidle', 'commit']); scheme.LifecycleEvent = tEnum(['load', 'domcontentloaded', 'networkidle', 'commit']);
scheme.LocalUtilsInitializer = tObject({ scheme.LocalUtilsInitializer = tObject({

View file

@ -212,7 +212,9 @@ export class APIRequestContextDispatcher extends Dispatcher<APIRequestContext, c
status: fetchResponse.status, status: fetchResponse.status,
statusText: fetchResponse.statusText, statusText: fetchResponse.statusText,
headers: fetchResponse.headers, headers: fetchResponse.headers,
fetchUid: fetchResponse.fetchUid fetchUid: fetchResponse.fetchUid,
timing: fetchResponse.timing,
responseEndTiming: fetchResponse.responseEndTiming,
} }
}; };
} }

View file

@ -422,6 +422,20 @@ export abstract class APIRequestContext extends SdkObject {
const chunks: Buffer[] = []; const chunks: Buffer[] = [];
const notifyBodyFinished = () => { const notifyBodyFinished = () => {
const endAt = monotonicTime();
// spec: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming
const timing: channels.ResourceTiming = {
startTime: startAt,
domainLookupStart: dnsLookupAt ? 0 : -1,
domainLookupEnd: dnsLookupAt ? dnsLookupAt! - startAt : -1,
connectStart: dnsLookupAt ? dnsLookupAt! - startAt : 0,
secureConnectionStart: dnsLookupAt ? dnsLookupAt! - startAt : 0,
connectEnd: (tlsHandshakeAt ?? tcpConnectionAt!) - startAt,
requestStart: (tlsHandshakeAt ?? tcpConnectionAt!) - startAt,
responseStart: responseAt - startAt,
};
const responseEndTiming = endAt - startAt;
const body = Buffer.concat(chunks); const body = Buffer.concat(chunks);
notifyRequestFinished(body); notifyRequestFinished(body);
fulfill({ fulfill({
@ -429,7 +443,9 @@ export abstract class APIRequestContext extends SdkObject {
status: response.statusCode || 0, status: response.statusCode || 0,
statusText: response.statusMessage || '', statusText: response.statusMessage || '',
headers: toHeadersArray(response.rawHeaders), headers: toHeadersArray(response.rawHeaders),
body body,
timing,
responseEndTiming,
}); });
}; };

View file

@ -17366,6 +17366,66 @@ export interface APIResponse {
*/ */
text(): Promise<string>; text(): Promise<string>;
/**
* Returns resource timing information for given response. Find more information at
* [Resource Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming).
*/
timing(): {
/**
* Request start time in milliseconds elapsed since January 1, 1970 00:00:00 UTC
*/
startTime: number;
/**
* Time immediately before the client starts the domain name lookup for the resource. The value is given in
* milliseconds relative to `startTime`, -1 if not available.
*/
domainLookupStart: number;
/**
* Time immediately after the client ends the domain name lookup for the resource. The value is given in milliseconds
* relative to `startTime`, -1 if not available.
*/
domainLookupEnd: number;
/**
* Time immediately before the client starts establishing the connection to the server to retrieve the resource. The
* value is given in milliseconds relative to `startTime`, -1 if not available.
*/
connectStart: number;
/**
* Time immediately before the client starts the handshake process to secure the current connection. The value is
* given in milliseconds relative to `startTime`, -1 if not available.
*/
secureConnectionStart: number;
/**
* Time immediately before the client starts establishing the connection to the server to retrieve the resource. The
* value is given in milliseconds relative to `startTime`, -1 if not available.
*/
connectEnd: number;
/**
* Time immediately before the client starts requesting the resource from the server. The value is given in
* milliseconds relative to `startTime`, -1 if not available.
*/
requestStart: number;
/**
* Time immediately after the client receives the first byte of the response from the server. The value is given in
* milliseconds relative to `startTime`, -1 if not available.
*/
responseStart: number;
/**
* Time immediately after the client receives the last byte of the resource or immediately before the transport
* connection is closed, whichever comes first. The value is given in milliseconds relative to `startTime`, -1 if not
* available.
*/
responseEnd: number;
};
/** /**
* Contains the URL of the response. * Contains the URL of the response.
*/ */
@ -19307,8 +19367,8 @@ export interface Request {
domainLookupStart: number; domainLookupStart: number;
/** /**
* Time immediately after the browser starts the domain name lookup for the resource. The value is given in * Time immediately after the browser ends the domain name lookup for the resource. The value is given in milliseconds
* milliseconds relative to `startTime`, -1 if not available. * relative to `startTime`, -1 if not available.
*/ */
domainLookupEnd: number; domainLookupEnd: number;

View file

@ -398,6 +398,8 @@ export type APIResponse = {
status: number, status: number,
statusText: string, statusText: string,
headers: NameValue[], headers: NameValue[],
timing: ResourceTiming,
responseEndTiming: number,
}; };
export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle' | 'commit'; export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle' | 'commit';

View file

@ -353,6 +353,8 @@ APIResponse:
headers: headers:
type: array type: array
items: NameValue items: NameValue
timing: ResourceTiming
responseEndTiming: number
LifecycleEvent: LifecycleEvent:

View file

@ -52,6 +52,17 @@ it('fetch should work', async ({ context, server }) => {
expect(response.ok()).toBeTruthy(); expect(response.ok()).toBeTruthy();
expect(response.headers()['content-type']).toBe('application/json; charset=utf-8'); expect(response.headers()['content-type']).toBe('application/json; charset=utf-8');
expect(response.headersArray()).toContainEqual({ name: 'Content-Type', value: 'application/json; charset=utf-8' }); expect(response.headersArray()).toContainEqual({ name: 'Content-Type', value: 'application/json; charset=utf-8' });
expect(response.timing()).toEqual({
connectEnd: expect.any(Number),
connectStart: expect.any(Number),
domainLookupEnd: expect.any(Number),
domainLookupStart: expect.any(Number),
requestStart: expect.any(Number),
responseStart: expect.any(Number),
responseEnd: expect.any(Number),
secureConnectionStart: expect.any(Number),
startTime: expect.any(Number),
});
expect(await response.text()).toBe('{"foo": "bar"}\n'); expect(await response.text()).toBe('{"foo": "bar"}\n');
}); });