mirror of
				https://github.com/lightpanda-io/browser.git
				synced 2025-10-30 15:41:48 +00:00 
			
		
		
		
	migrate fetch tests to htmlRunner
This commit is contained in:
		| @@ -17,9 +17,12 @@ | ||||
| // along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| const std = @import("std"); | ||||
| const log = @import("../../log.zig"); | ||||
| const URL = @import("../../url.zig").URL; | ||||
| const Page = @import("../page.zig").Page; | ||||
|  | ||||
| const iterator = @import("../iterator/iterator.zig"); | ||||
|  | ||||
| const v8 = @import("v8"); | ||||
| const Env = @import("../env.zig").Env; | ||||
|  | ||||
| @@ -108,7 +111,8 @@ pub fn constructor(_init: ?HeadersInit, page: *Page) !Headers { | ||||
| } | ||||
|  | ||||
| pub fn append(self: *Headers, name: []const u8, value: []const u8, allocator: std.mem.Allocator) !void { | ||||
|     const gop = try self.headers.getOrPut(allocator, name); | ||||
|     const key = try allocator.dupe(u8, name); | ||||
|     const gop = try self.headers.getOrPut(allocator, key); | ||||
|  | ||||
|     if (gop.found_existing) { | ||||
|         // If we found it, append the value. | ||||
| @@ -129,13 +133,13 @@ pub fn _delete(self: *Headers, name: []const u8) void { | ||||
|     _ = self.headers.remove(name); | ||||
| } | ||||
|  | ||||
| pub const HeaderEntryIterator = struct { | ||||
| pub const HeadersEntryIterator = struct { | ||||
|     slot: [2][]const u8, | ||||
|     iter: HeaderHashMap.Iterator, | ||||
|  | ||||
|     // TODO: these SHOULD be in lexigraphical order but I'm not sure how actually | ||||
|     // important that is. | ||||
|     pub fn _next(self: *HeaderEntryIterator) ?[2][]const u8 { | ||||
|     pub fn _next(self: *HeadersEntryIterator) ?[2][]const u8 { | ||||
|         if (self.iter.next()) |entry| { | ||||
|             self.slot[0] = entry.key_ptr.*; | ||||
|             self.slot[1] = entry.value_ptr.*; | ||||
| @@ -146,10 +150,12 @@ pub const HeaderEntryIterator = struct { | ||||
|     } | ||||
| }; | ||||
|  | ||||
| pub fn _entries(self: *const Headers) HeaderEntryIterator { | ||||
| pub fn _entries(self: *const Headers) HeadersEntryIterable { | ||||
|     return .{ | ||||
|         .slot = undefined, | ||||
|         .iter = self.headers.iterator(), | ||||
|         .inner = .{ | ||||
|             .slot = undefined, | ||||
|             .iter = self.headers.iterator(), | ||||
|         }, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @@ -171,10 +177,10 @@ pub fn _has(self: *const Headers, name: []const u8) bool { | ||||
|     return self.headers.contains(name); | ||||
| } | ||||
|  | ||||
| pub const HeaderKeyIterator = struct { | ||||
| pub const HeadersKeyIterator = struct { | ||||
|     iter: HeaderHashMap.KeyIterator, | ||||
|  | ||||
|     pub fn _next(self: *HeaderKeyIterator) ?[]const u8 { | ||||
|     pub fn _next(self: *HeadersKeyIterator) ?[]const u8 { | ||||
|         if (self.iter.next()) |key| { | ||||
|             return key.*; | ||||
|         } else { | ||||
| @@ -183,21 +189,22 @@ pub const HeaderKeyIterator = struct { | ||||
|     } | ||||
| }; | ||||
|  | ||||
| pub fn _keys(self: *const Headers) HeaderKeyIterator { | ||||
|     return .{ .iter = self.headers.keyIterator() }; | ||||
| pub fn _keys(self: *const Headers) HeadersKeyIterable { | ||||
|     return .{ .inner = .{ .iter = self.headers.keyIterator() } }; | ||||
| } | ||||
|  | ||||
| pub fn _set(self: *Headers, name: []const u8, value: []const u8, page: *Page) !void { | ||||
|     const arena = page.arena; | ||||
|  | ||||
|     const gop = try self.headers.getOrPut(arena, name); | ||||
|     const key = try arena.dupe(u8, name); | ||||
|     const gop = try self.headers.getOrPut(arena, key); | ||||
|     gop.value_ptr.* = try arena.dupe(u8, value); | ||||
| } | ||||
|  | ||||
| pub const HeaderValueIterator = struct { | ||||
| pub const HeadersValueIterator = struct { | ||||
|     iter: HeaderHashMap.ValueIterator, | ||||
|  | ||||
|     pub fn _next(self: *HeaderValueIterator) ?[]const u8 { | ||||
|     pub fn _next(self: *HeadersValueIterator) ?[]const u8 { | ||||
|         if (self.iter.next()) |value| { | ||||
|             return value.*; | ||||
|         } else { | ||||
| @@ -206,53 +213,15 @@ pub const HeaderValueIterator = struct { | ||||
|     } | ||||
| }; | ||||
|  | ||||
| pub fn _values(self: *const Headers) HeaderValueIterator { | ||||
|     return .{ .iter = self.headers.valueIterator() }; | ||||
| pub fn _values(self: *const Headers) HeadersValueIterable { | ||||
|     return .{ .inner = .{ .iter = self.headers.valueIterator() } }; | ||||
| } | ||||
|  | ||||
| pub const HeadersKeyIterable = iterator.Iterable(HeadersKeyIterator, "HeadersKeyIterator"); | ||||
| pub const HeadersValueIterable = iterator.Iterable(HeadersValueIterator, "HeadersValueIterator"); | ||||
| pub const HeadersEntryIterable = iterator.Iterable(HeadersEntryIterator, "HeadersEntryIterator"); | ||||
|  | ||||
| const testing = @import("../../testing.zig"); | ||||
| test "fetch: headers" { | ||||
|     var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io" }); | ||||
|     defer runner.deinit(); | ||||
|  | ||||
|     try runner.testCases(&.{ | ||||
|         .{ "let emptyHeaders = new Headers()", "undefined" }, | ||||
|     }, .{}); | ||||
|  | ||||
|     try runner.testCases(&.{ | ||||
|         .{ "let headers = new Headers({'Set-Cookie': 'name=world'})", "undefined" }, | ||||
|         .{ "headers.get('set-cookie')", "name=world" }, | ||||
|     }, .{}); | ||||
|  | ||||
|     // adapted from the mdn examples | ||||
|     try runner.testCases(&.{ | ||||
|         .{ "const myHeaders = new Headers();", "undefined" }, | ||||
|         .{ "myHeaders.append('Content-Type', 'image/jpeg')", "undefined" }, | ||||
|         .{ "myHeaders.has('Picture-Type')", "false" }, | ||||
|         .{ "myHeaders.get('Content-Type')", "image/jpeg" }, | ||||
|         .{ "myHeaders.append('Content-Type', 'image/png')", "undefined" }, | ||||
|         .{ "myHeaders.get('Content-Type')", "image/jpeg, image/png" }, | ||||
|         .{ "myHeaders.delete('Content-Type')", "undefined" }, | ||||
|         .{ "myHeaders.get('Content-Type')", "null" }, | ||||
|         .{ "myHeaders.set('Picture-Type', 'image/svg')", "undefined" }, | ||||
|         .{ "myHeaders.get('Picture-Type')", "image/svg" }, | ||||
|         .{ "myHeaders.has('Picture-Type')", "true" }, | ||||
|     }, .{}); | ||||
|  | ||||
|     try runner.testCases(&.{ | ||||
|         .{ "const originalHeaders = new Headers([['Content-Type', 'application/json'], ['Authorization', 'Bearer token123']])", "undefined" }, | ||||
|         .{ "originalHeaders.get('Content-Type')", "application/json" }, | ||||
|         .{ "originalHeaders.get('Authorization')", "Bearer token123" }, | ||||
|         .{ "const newHeaders = new Headers(originalHeaders)", "undefined" }, | ||||
|         .{ "newHeaders.get('Content-Type')", "application/json" }, | ||||
|         .{ "newHeaders.get('Authorization')", "Bearer token123" }, | ||||
|         .{ "newHeaders.has('Content-Type')", "true" }, | ||||
|         .{ "newHeaders.has('Authorization')", "true" }, | ||||
|         .{ "newHeaders.has('X-Custom')", "false" }, | ||||
|         // Verify that modifying the new headers doesn't affect the original | ||||
|         .{ "newHeaders.set('X-Custom', 'test-value')", "undefined" }, | ||||
|         .{ "newHeaders.get('X-Custom')", "test-value" }, | ||||
|         .{ "originalHeaders.get('X-Custom')", "null" }, | ||||
|         .{ "originalHeaders.has('X-Custom')", "false" }, | ||||
|     }, .{}); | ||||
| test "fetch: Headers" { | ||||
|     try testing.htmlRunner("fetch/headers.html"); | ||||
| } | ||||
|   | ||||
| @@ -54,6 +54,10 @@ pub const RequestCache = enum { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn toString(self: RequestCache) []const u8 { | ||||
|         return @tagName(self); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| pub const RequestCredentials = enum { | ||||
| @@ -70,6 +74,10 @@ pub const RequestCredentials = enum { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn toString(self: RequestCredentials) []const u8 { | ||||
|         return @tagName(self); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| // https://developer.mozilla.org/en-US/docs/Web/API/RequestInit | ||||
| @@ -154,6 +162,10 @@ pub fn get_cache(self: *const Request) RequestCache { | ||||
|     return self.cache; | ||||
| } | ||||
|  | ||||
| pub fn get_credentials(self: *const Request) RequestCredentials { | ||||
|     return self.credentials; | ||||
| } | ||||
|  | ||||
| pub fn get_headers(self: *Request) *Headers { | ||||
|     return &self.headers; | ||||
| } | ||||
| @@ -249,50 +261,6 @@ pub fn _text(self: *Response, page: *Page) !Env.Promise { | ||||
| } | ||||
|  | ||||
| const testing = @import("../../testing.zig"); | ||||
| test "fetch: request" { | ||||
|     var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io" }); | ||||
|     defer runner.deinit(); | ||||
|  | ||||
|     try runner.testCases(&.{ | ||||
|         .{ "let request = new Request('flower.png')", "undefined" }, | ||||
|         .{ "request.url", "https://lightpanda.io/flower.png" }, | ||||
|         .{ "request.method", "GET" }, | ||||
|     }, .{}); | ||||
|  | ||||
|     try runner.testCases(&.{ | ||||
|         .{ "let request2 = new Request('https://google.com', { method: 'POST', body: 'Hello, World' })", "undefined" }, | ||||
|         .{ "request2.url", "https://google.com" }, | ||||
|         .{ "request2.method", "POST" }, | ||||
|     }, .{}); | ||||
| } | ||||
|  | ||||
| test "fetch: Browser.fetch" { | ||||
|     var runner = try testing.jsRunner(testing.tracking_allocator, .{}); | ||||
|     defer runner.deinit(); | ||||
|  | ||||
|     try runner.testCases(&.{ | ||||
|         .{ | ||||
|             \\  var ok = false; | ||||
|             \\  const request = new Request("http://127.0.0.1:9582/loader"); | ||||
|             \\  fetch(request).then((response) => { ok = response.ok; }); | ||||
|             \\  false; | ||||
|             , | ||||
|             "false", | ||||
|         }, | ||||
|         // all events have been resolved. | ||||
|         .{ "ok", "true" }, | ||||
|     }, .{}); | ||||
|  | ||||
|     try runner.testCases(&.{ | ||||
|         .{ | ||||
|             \\  var ok2 = false; | ||||
|             \\  const request2 = new Request("http://127.0.0.1:9582/loader"); | ||||
|             \\  (async function () { resp = await fetch(request2); ok2 = resp.ok; }()); | ||||
|             \\  false; | ||||
|             , | ||||
|             "false", | ||||
|         }, | ||||
|         // all events have been resolved. | ||||
|         .{ "ok2", "true" }, | ||||
|     }, .{}); | ||||
| test "fetch: Request" { | ||||
|     try testing.htmlRunner("fetch/request.html"); | ||||
| } | ||||
|   | ||||
| @@ -36,7 +36,8 @@ const Page = @import("../page.zig").Page; | ||||
| // https://developer.mozilla.org/en-US/docs/Web/API/Response | ||||
| const Response = @This(); | ||||
|  | ||||
| status: u16 = 0, | ||||
| status: u16 = 200, | ||||
| status_text: []const u8 = "", | ||||
| headers: Headers, | ||||
| mime: ?Mime = null, | ||||
| url: []const u8 = "", | ||||
| @@ -50,7 +51,7 @@ const ResponseBody = union(enum) { | ||||
|  | ||||
| const ResponseOptions = struct { | ||||
|     status: u16 = 200, | ||||
|     statusText: []const u8 = "", | ||||
|     statusText: ?[]const u8 = null, | ||||
|     headers: ?HeadersInit = null, | ||||
| }; | ||||
|  | ||||
| @@ -72,10 +73,13 @@ pub fn constructor(_input: ?ResponseBody, _options: ?ResponseOptions, page: *Pag | ||||
|     }; | ||||
|  | ||||
|     const headers: Headers = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else .{}; | ||||
|     const status_text = if (options.statusText) |st| try arena.dupe(u8, st) else ""; | ||||
|  | ||||
|     return .{ | ||||
|         .body = body, | ||||
|         .headers = headers, | ||||
|         .status = options.status, | ||||
|         .status_text = status_text, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @@ -105,6 +109,10 @@ pub fn get_status(self: *const Response) u16 { | ||||
|     return self.status; | ||||
| } | ||||
|  | ||||
| pub fn get_statusText(self: *const Response) []const u8 { | ||||
|     return self.status_text; | ||||
| } | ||||
|  | ||||
| pub fn get_url(self: *const Response) []const u8 { | ||||
|     return self.url; | ||||
| } | ||||
| @@ -183,9 +191,6 @@ pub fn _text(self: *Response, page: *Page) !Env.Promise { | ||||
| } | ||||
|  | ||||
| const testing = @import("../../testing.zig"); | ||||
| test "fetch: response" { | ||||
|     var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io" }); | ||||
|     defer runner.deinit(); | ||||
|  | ||||
|     try runner.testCases(&.{}, .{}); | ||||
| test "fetch: Response" { | ||||
|     try testing.htmlRunner("fetch/response.html"); | ||||
| } | ||||
|   | ||||
| @@ -36,9 +36,9 @@ const Response = @import("Response.zig"); | ||||
|  | ||||
| pub const Interfaces = .{ | ||||
|     @import("Headers.zig"), | ||||
|     @import("Headers.zig").HeaderEntryIterator, | ||||
|     @import("Headers.zig").HeaderKeyIterator, | ||||
|     @import("Headers.zig").HeaderValueIterator, | ||||
|     @import("Headers.zig").HeadersEntryIterable, | ||||
|     @import("Headers.zig").HeadersKeyIterable, | ||||
|     @import("Headers.zig").HeadersValueIterable, | ||||
|     @import("Request.zig"), | ||||
|     @import("Response.zig"), | ||||
| }; | ||||
|   | ||||
							
								
								
									
										102
									
								
								src/tests/fetch/headers.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/tests/fetch/headers.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| <script src="../testing.js"></script> | ||||
|  | ||||
| <script id=headers> | ||||
|   let headers = new Headers({"Set-Cookie": "name=world"}); | ||||
|   testing.expectEqual("name=world", headers.get("set-cookie")); | ||||
|  | ||||
|   let myHeaders = new Headers(); | ||||
|   myHeaders.append("Content-Type", "image/jpeg"), | ||||
|   testing.expectEqual(false, myHeaders.has("Picture-Type")); | ||||
|   testing.expectEqual("image/jpeg", myHeaders.get("Content-Type")); | ||||
|  | ||||
|   myHeaders.append("Content-Type", "image/png"); | ||||
|   testing.expectEqual("image/jpeg, image/png", myHeaders.get("Content-Type")); | ||||
|  | ||||
|   myHeaders.delete("Content-Type"); | ||||
|   testing.expectEqual(null, myHeaders.get("Content-Type")); | ||||
|  | ||||
|   myHeaders.set("Picture-Type", "image/svg") | ||||
|   testing.expectEqual("image/svg", myHeaders.get("Picture-Type")); | ||||
|   testing.expectEqual(true, myHeaders.has("Picture-Type")) | ||||
|  | ||||
|   const originalHeaders = new Headers([["Content-Type", "application/json"], ["Authorization", "Bearer token123"]]); | ||||
|   testing.expectEqual("application/json", originalHeaders.get("Content-Type")); | ||||
|   testing.expectEqual("Bearer token123", originalHeaders.get("Authorization")); | ||||
|  | ||||
|   const newHeaders = new Headers(originalHeaders); | ||||
|   testing.expectEqual("application/json", newHeaders.get("Content-Type")); | ||||
|   testing.expectEqual("Bearer token123" ,newHeaders.get("Authorization")); | ||||
|   testing.expectEqual(true ,newHeaders.has("Content-Type")); | ||||
|   testing.expectEqual(true ,newHeaders.has("Authorization")); | ||||
|   testing.expectEqual(false, newHeaders.has("X-Custom")); | ||||
|  | ||||
|   newHeaders.set("X-Custom", "test-value"); | ||||
|   testing.expectEqual("test-value", newHeaders.get("X-Custom")); | ||||
|   testing.expectEqual(null, originalHeaders.get("X-Custom")); | ||||
|   testing.expectEqual(false, originalHeaders.has("X-Custom")); | ||||
| </script> | ||||
|  | ||||
| <script id=keys> | ||||
|   const testKeyHeaders = new Headers(); | ||||
|   testKeyHeaders.set("Content-Type", "application/json"); | ||||
|   testKeyHeaders.set("Authorization", "Bearer token123"); | ||||
|   testKeyHeaders.set("X-Custom", "test-value"); | ||||
|  | ||||
|   const keys = []; | ||||
|   for (const key of testKeyHeaders.keys()) { | ||||
|       keys.push(key); | ||||
|   } | ||||
|  | ||||
|   testing.expectEqual(3, keys.length); | ||||
|   testing.expectEqual(true, keys.includes("Content-Type")); | ||||
|   testing.expectEqual(true, keys.includes("Authorization")); | ||||
|   testing.expectEqual(true, keys.includes("X-Custom")); | ||||
| </script> | ||||
|  | ||||
| <script id=values> | ||||
|   const testValuesHeaders = new Headers(); | ||||
|   testValuesHeaders.set("Content-Type", "application/json"); | ||||
|   testValuesHeaders.set("Authorization", "Bearer token123"); | ||||
|   testValuesHeaders.set("X-Custom", "test-value"); | ||||
|  | ||||
|   const values = []; | ||||
|   for (const value of testValuesHeaders.values()) { | ||||
|       values.push(value); | ||||
|   } | ||||
|  | ||||
|   testing.expectEqual(3, values.length); | ||||
|   testing.expectEqual(true, values.includes("application/json")); | ||||
|   testing.expectEqual(true, values.includes("Bearer token123")); | ||||
|   testing.expectEqual(true, values.includes("test-value")); | ||||
| </script> | ||||
|  | ||||
| <script id=entries> | ||||
|   const testEntriesHeaders = new Headers(); | ||||
|   testEntriesHeaders.set("Content-Type", "application/json"); | ||||
|   testEntriesHeaders.set("Authorization", "Bearer token123"); | ||||
|   testEntriesHeaders.set("X-Custom", "test-value"); | ||||
|  | ||||
|   const entries = []; | ||||
|   for (const entry of testEntriesHeaders.entries()) { | ||||
|       entries.push(entry); | ||||
|   } | ||||
|          | ||||
|   testing.expectEqual(3, entries.length); | ||||
|  | ||||
|   const entryMap = new Map(entries); | ||||
|   testing.expectEqual("application/json", entryMap.get("Content-Type")); | ||||
|   testing.expectEqual("Bearer token123", entryMap.get("Authorization")); | ||||
|   testing.expectEqual("test-value", entryMap.get("X-Custom")); | ||||
|    | ||||
|   const entryKeys = Array.from(entryMap.keys()); | ||||
|   testing.expectEqual(3, entryKeys.length); | ||||
|   testing.expectEqual(true, entryKeys.includes("Content-Type")); | ||||
|   testing.expectEqual(true, entryKeys.includes("Authorization")); | ||||
|   testing.expectEqual(true, entryKeys.includes("X-Custom")); | ||||
|    | ||||
|   const entryValues = Array.from(entryMap.values()); | ||||
|   testing.expectEqual(3, entryValues.length); | ||||
|   testing.expectEqual(true, entryValues.includes("application/json")); | ||||
|   testing.expectEqual(true, entryValues.includes("Bearer token123")); | ||||
|   testing.expectEqual(true, entryValues.includes("test-value")) | ||||
| </script> | ||||
							
								
								
									
										22
									
								
								src/tests/fetch/request.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/tests/fetch/request.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <script src="../testing.js"></script> | ||||
|  | ||||
| <script id=request> | ||||
|   let request = new Request("flower.png"); | ||||
|   testing.expectEqual("http://localhost:9582/src/tests/fetch/flower.png", request.url); | ||||
|   testing.expectEqual("GET", request.method); | ||||
|  | ||||
|   let request2 = new Request("https://google.com", { | ||||
|     method: "POST", | ||||
|     body: "Hello, World", | ||||
|     cache: "reload", | ||||
|     credentials: "omit", | ||||
|     headers: { "Sender": "me", "Target": "you" } | ||||
|     } | ||||
|   ); | ||||
|   testing.expectEqual("https://google.com", request2.url); | ||||
|   testing.expectEqual("POST", request2.method); | ||||
|   testing.expectEqual("omit", request2.credentials); | ||||
|   testing.expectEqual("reload", request2.cache); | ||||
|   testing.expectEqual("me", request2.headers.get("SeNdEr")); | ||||
|   testing.expectEqual("you", request2.headers.get("target")); | ||||
| </script> | ||||
							
								
								
									
										38
									
								
								src/tests/fetch/response.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/tests/fetch/response.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| <script src="../testing.js"></script> | ||||
|  | ||||
| <script id=response> | ||||
|   let response = new Response("Hello, World!"); | ||||
|   testing.expectEqual(200, response.status); | ||||
|   testing.expectEqual("", response.statusText); | ||||
|   testing.expectEqual(true, response.ok); | ||||
|   testing.expectEqual("", response.url); | ||||
|   testing.expectEqual(false, response.redirected); | ||||
|  | ||||
|   let response2 = new Response("Error occurred", { | ||||
|     status: 404, | ||||
|     statusText: "Not Found", | ||||
|     headers: {  | ||||
|         "Content-Type": "text/plain",  | ||||
|         "X-Custom": "test-value", | ||||
|         "Cache-Control": "no-cache" | ||||
|     } | ||||
|   }); | ||||
|   testing.expectEqual(404, response2.status); | ||||
|   testing.expectEqual("Not Found", response2.statusText); | ||||
|   testing.expectEqual(false, response2.ok); | ||||
|   testing.expectEqual("text/plain", response2.headers.get("Content-Type")); | ||||
|   testing.expectEqual("test-value", response2.headers.get("X-Custom")); | ||||
|   testing.expectEqual("no-cache", response2.headers.get("cache-control")); | ||||
|          | ||||
|   let response3 = new Response("Created", { status: 201, statusText: "Created" }); | ||||
|   testing.expectEqual(201, response3.status); | ||||
|   testing.expectEqual("Created", response3.statusText); | ||||
|   testing.expectEqual(true, response3.ok); | ||||
|  | ||||
|   let nullResponse = new Response(null); | ||||
|   testing.expectEqual(200, nullResponse.status); | ||||
|   testing.expectEqual("", nullResponse.statusText); | ||||
|  | ||||
|   let emptyResponse = new Response(""); | ||||
|   testing.expectEqual(200, emptyResponse.status); | ||||
| </script> | ||||
		Reference in New Issue
	
	Block a user
	 Muki Kiboigo
					Muki Kiboigo