Skip to content
File

Blob: src/workerd/api/tests/fetch-test.js

javascript127 lines
1// Copyright (c) 2024 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4import { strictEqual, throws } from 'assert';
5 
6// Test depends on the setting of the upper_case_all_http_methods compatibility flag.
7strictEqual(
8 globalThis.Cloudflare.compatibilityFlags['upper_case_all_http_methods'],
9 true
10);
11 
12export const test = {
13 test() {
14 // Verify that lower-cased method names are converted to upper-case.
15 // even though the Fetch API doesn't do this in general for all methods.
16 // Note that the upper_case_all_http_methods compat flag is intentionally
17 // diverging from the Fetch API here.
18 const req = new Request('https://example.com', { method: 'patch' });
19 strictEqual(req.method, 'PATCH');
20 
21 // Unrecognized methods error as expected, with the error message
22 // showing the original-cased method name.
23 throws(() => new Request('http://example.org', { method: 'patchy' }), {
24 message: /^Invalid HTTP method string: patchy$/,
25 });
26 },
27};
28 
29export const fetchGen = {
30 async test() {
31 const enc = new TextEncoder();
32 async function* gen() {
33 yield enc.encode('Hello ');
34 yield enc.encode('World!');
35 }
36 const resp = new Response(gen());
37 strictEqual(await resp.text(), 'Hello World!');
38 
39 const req = new Request('http://example.com', {
40 method: 'POST',
41 body: gen(),
42 });
43 strictEqual(await req.text(), 'Hello World!');
44 
45 const resp2 = new Response([enc.encode('Hello '), enc.encode('World!')]);
46 strictEqual(await resp2.text(), 'Hello World!');
47 
48 // Boxed strings work correctly.
49 const resp3 = new Response(new String('Hello'));
50 strictEqual(await resp3.text(), 'Hello');
51 
52 // Regular strings work correctly.
53 const resp4 = new Response('Hello');
54 strictEqual(await resp4.text(), 'Hello');
55 
56 const objIter = {
57 *[Symbol.iterator]() {
58 yield enc.encode('Hello ');
59 yield enc.encode('Object Iterator!');
60 },
61 };
62 const respIter = new Response(objIter);
63 strictEqual(await respIter.text(), 'Hello Object Iterator!');
64 
65 // Custom toString prevents iterator treatment.
66 const obj = {
67 *[Symbol.iterator]() {
68 yield enc.encode('ignored');
69 },
70 toString() {
71 return 'Hello';
72 },
73 };
74 const resp5 = new Response(obj);
75 strictEqual(await resp5.text(), 'Hello');
76 
77 class MyObj {
78 *[Symbol.iterator]() {
79 yield enc.encode('ignored');
80 }
81 toString() {
82 return 'Hello';
83 }
84 }
85 const resp6 = new Response(new MyObj());
86 strictEqual(await resp6.text(), 'Hello');
87 
88 class Base {
89 toString() {
90 return 'Hello';
91 }
92 }
93 class SubObj extends Base {
94 *[Symbol.iterator]() {
95 yield enc.encode('ignored');
96 }
97 }
98 const resp7 = new Response(new SubObj());
99 strictEqual(await resp7.text(), 'Hello');
100 
101 // Also custom toPrimitive prevents iterator treatment.
102 const objPrim = {
103 *[Symbol.iterator]() {
104 yield enc.encode('ignored');
105 },
106 [Symbol.toPrimitive]() {
107 return 'Hello';
108 },
109 };
110 const respPrim = new Response(objPrim);
111 strictEqual(await respPrim.text(), 'Hello');
112 
113 // Unless it's specifically an async iterator.
114 const asyncIter = {
115 async *[Symbol.asyncIterator]() {
116 yield enc.encode('Hello ');
117 yield enc.encode('Async World!');
118 },
119 toString() {
120 return 'ignored';
121 },
122 };
123 const resp8 = new Response(asyncIter);
124 strictEqual(await resp8.text(), 'Hello Async World!');
125 },
126};