test(service-worker): better simulate opaque requests (#30977)

Previously, opaque responses where handled a little differently than
other responses from the mock server. More specifically, they were not
tracked (so no assertions could be made for them) and their
[`Body` mixin][1] methods (such as `arrayBuffer()`, `json()`, `text()`)
would throw an error due to `body` being `null`.

This commit ensures opaque responses are also captured on the mock
server and also changes `Body` mixin methods to better simulate the
[spec'd behavior][2].

(These improvements will be necessary to test caching of opaque
responses in a subsequent commit.)

[1]: https://developer.mozilla.org/en-US/docs/Web/API/Body
[2]: https://fetch.spec.whatwg.org/#concept-body-consume-body

PR Close #30977
This commit is contained in:
George Kalpakas 2019-06-24 15:04:11 +03:00 committed by Alex Rickabaugh
parent c150354464
commit 5306330d85
2 changed files with 18 additions and 29 deletions

View File

@ -13,46 +13,34 @@ export class MockBody implements Body {
constructor(public _body: string|null) {} constructor(public _body: string|null) {}
async arrayBuffer(): Promise<ArrayBuffer> { async arrayBuffer(): Promise<ArrayBuffer> {
this.markBodyUsed(); const body = this.getBody();
if (this._body !== null) { const buffer = new ArrayBuffer(body.length);
const buffer = new ArrayBuffer(this._body.length); const view = new Uint8Array(buffer);
const access = new Uint8Array(buffer);
for (let i = 0; i < this._body.length; i++) { for (let i = 0; i < body.length; i++) {
access[i] = this._body.charCodeAt(i); view[i] = body.charCodeAt(i);
} }
return buffer; return buffer;
} else {
throw new Error('No body');
}
} }
async blob(): Promise<Blob> { throw 'Not implemented'; } async blob(): Promise<Blob> { throw 'Not implemented'; }
async json(): Promise<any> { async json(): Promise<any> { return JSON.parse(this.getBody()); }
this.markBodyUsed();
if (this._body !== null) {
return JSON.parse(this._body);
} else {
throw new Error('No body');
}
}
async text(): Promise<string> { async text(): Promise<string> { return this.getBody(); }
this.markBodyUsed();
if (this._body !== null) {
return this._body;
} else {
throw new Error('No body');
}
}
async formData(): Promise<FormData> { throw 'Not implemented'; } async formData(): Promise<FormData> { throw 'Not implemented'; }
private markBodyUsed(): void { private getBody(): string {
if (this.bodyUsed === true) { if (this.bodyUsed === true) {
throw new Error('Cannot reuse body without cloning.'); throw new Error('Cannot reuse body without cloning.');
} }
this.bodyUsed = true; this.bodyUsed = true;
// According to the spec, a `null` body results in an empty `ReadableStream` (which for our
// needs is equivalent to `''`). See https://fetch.spec.whatwg.org/#concept-body-consume-body.
return this._body || '';
} }
} }

View File

@ -120,11 +120,12 @@ export class MockServerState {
throw new Error('Offline.'); throw new Error('Offline.');
} }
if (req.credentials === 'include') { this.requests.push(req);
if ((req.credentials === 'include') || (req.mode === 'no-cors')) {
return new MockResponse(null, {status: 0, statusText: '', type: 'opaque'}); return new MockResponse(null, {status: 0, statusText: '', type: 'opaque'});
} }
const url = req.url.split('?')[0]; const url = req.url.split('?')[0];
this.requests.push(req);
if (this.resources.has(url)) { if (this.resources.has(url)) {
return this.resources.get(url) !.clone(); return this.resources.get(url) !.clone();
} }