Skip to content

Commit c02f1e8

Browse files
committed
🏁 Add deno tests
1 parent 23f22e4 commit c02f1e8

File tree

9 files changed

+202
-18
lines changed

9 files changed

+202
-18
lines changed

.github/workflows/deno.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Deno compatibility test
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- master
8+
- dev
9+
workflow_dispatch:
10+
11+
jobs:
12+
deno-test:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v3
16+
- uses: moonrepo/setup-toolchain@v0
17+
with:
18+
auto-install: true
19+
- name: Install dependencies
20+
run: npm ci
21+
- name: Build
22+
run: npm run build
23+
- name: Test Deno compatibility
24+
run: npm run test:deno

README.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
- 💡 **Intuitive** - lean API, handles errors, headers and (de)serialization
3232
- 🧊 **Immutable** - every call creates a cloned instance that can then be reused safely
3333
- 🔌 **Modular** - plug addons to add new features, and middlewares to intercept requests
34-
- 🧩 **Isomorphic** - compatible with modern browsers and Node.js 22+
34+
- 🧩 **Isomorphic** - compatible with modern browsers, Node.js 22+ and Deno
3535
- 🦺 **Type safe** - strongly typed, written in TypeScript
3636
-**Proven** - fully covered by unit tests and widely used
3737
- 💓 **Maintained** - alive and well for many years
@@ -223,18 +223,17 @@ Node.js 22+ includes native fetch support and all required Web APIs (FormData, U
223223

224224
## Deno
225225

226-
Works with [Deno](https://deno.land/) >=
227-
[0.41.0](https://github.com/denoland/deno/releases/tag/v0.41.0) out of the box.
226+
Works with [Deno](https://deno.land/) out of the box.
228227

229-
Types should be imported from `/dist/types.d.ts`.
228+
```bash
229+
deno add npm:wretch
230+
```
230231

231-
<!-- snippet:skip Deno specific-code -->
232232
```ts
233-
// You can import wretch from any CDN that serve ESModules.
234-
import wretch from "https://cdn.skypack.dev/wretch";
233+
import wretch from "wretch";
235234

236-
const text = await wretch("https://httpstat.us").get("/200").text();
237-
console.log(text); // -> 200 OK
235+
const text = await wretch("https://httpbun.org").get("/status/200").text();
236+
console.log(text); // -> { "code": 200, "description": "OK" }
238237
```
239238

240239
# Usage

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
"test": "concurrently --success first -k 'npm run mock:wait && c8 node --import tsx --test \"test/node/**/*.spec.ts\"' 'npm run mock'",
121121
"test:browser": "concurrently --success first -k 'npm run mock:wait && web-test-runner' 'npm run mock'",
122122
"test:browser:watch": "concurrently --success first -k 'npm run mock:wait && web-test-runner --watch' 'npm run mock'",
123+
"test:deno": "concurrently --success first -k 'npm run mock:wait && deno test --allow-net --allow-read --no-check --sloppy-imports --config test/deno/deno.json test/deno/wretch.spec.ts' 'npm run mock'",
123124
"test:snippets:generate": "node --import tsx scripts/generateSnippetTests.ts",
124125
"test:snippets": "npm run test:snippets:generate && node --experimental-vm-modules --import tsx --test test/generated/snippets.spec.ts",
125126
"test:snippets:skip-failing": "node --import tsx scripts/addSkipComments.ts",

test/deno/deno.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"lib": ["deno.ns", "deno.window"],
4+
"strict": false
5+
},
6+
"imports": {
7+
"@std/assert": "jsr:@std/assert@^1.0.15",
8+
"@std/testing": "jsr:@std/testing@^1.0.16"
9+
}
10+
}

test/deno/deno.lock

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/deno/helpers.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import * as assertImport from "@std/assert"
2+
3+
export const expect = (actual: any) => ({
4+
toBe: (expected: unknown) => assertImport.assertEquals(actual, expected),
5+
toEqual: (expected: unknown) => assertImport.assertEquals(actual, expected),
6+
toBeNull: () => assertImport.assertEquals(actual, null),
7+
toBeTruthy: () => assertImport.assert(actual),
8+
toBeUndefined: () => assertImport.assertEquals(actual, undefined),
9+
toBeGreaterThanOrEqual: (expected: any) => {
10+
assertImport.assert(typeof actual === "number" && typeof expected === "number")
11+
assertImport.assert(actual >= expected)
12+
},
13+
toStrictEqual: (expected: unknown) => assertImport.assertEquals(actual, expected),
14+
toMatchObject: (expected: any) => {
15+
for (const key in expected) {
16+
const expectedValue = expected[key]
17+
const actualValue = actual[key]
18+
19+
if (expectedValue instanceof Uint8Array) {
20+
if (actualValue && actualValue.type === "Buffer" && Array.isArray(actualValue.data)) {
21+
assertImport.assertEquals(actualValue.data, Array.from(expectedValue))
22+
} else {
23+
assertImport.assertEquals(Array.from(actualValue), Array.from(expectedValue))
24+
}
25+
} else if (typeof expectedValue === "object" && expectedValue !== null && !Array.isArray(expectedValue)) {
26+
if (expectedValue.type === "Buffer" && expectedValue.data instanceof Uint8Array) {
27+
assertImport.assertEquals(actualValue.type, "Buffer")
28+
assertImport.assertEquals(actualValue.data, Array.from(expectedValue.data))
29+
} else {
30+
assertImport.assertEquals(actualValue, expectedValue)
31+
}
32+
} else {
33+
assertImport.assertEquals(actualValue, expectedValue)
34+
}
35+
}
36+
}
37+
})
38+
39+
export const assert = {
40+
...assertImport,
41+
rejects: async (
42+
fn: () => Promise<unknown>,
43+
validator?: (error: unknown) => boolean
44+
) => {
45+
try {
46+
await fn()
47+
throw new Error("Expected promise to reject")
48+
} catch (error) {
49+
if (validator && !validator(error)) {
50+
throw new Error("Validator returned false")
51+
}
52+
}
53+
}
54+
}
55+
56+
export const fs = {
57+
openAsBlob: async (path: string) => {
58+
const file = await Deno.open(path, { read: true })
59+
const fileInfo = await file.stat()
60+
const buffer = new Uint8Array(fileInfo.size)
61+
await file.read(buffer)
62+
file.close()
63+
return new Blob([buffer])
64+
}
65+
}

test/deno/wretch.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { describe, it, beforeEach } from "@std/testing/bdd"
2+
import { expect, assert, fs } from "./helpers.ts"
3+
import { createWretchTests, createMixTests } from "../shared/wretch.spec.ts"
4+
5+
const duckImagePath = new URL("../assets/duck.jpg", import.meta.url).pathname
6+
const duckImage = await Deno.readFile(duckImagePath)
7+
8+
createWretchTests({
9+
describe: (name, fn) => describe(name, { sanitizeResources: false }, fn),
10+
it: (name, fn) => it(name, { sanitizeResources: false }, fn),
11+
beforeEach,
12+
assert,
13+
expect,
14+
fs,
15+
duckImage,
16+
duckImagePath,
17+
})
18+
19+
createMixTests({
20+
describe,
21+
it,
22+
assert,
23+
expect,
24+
fs,
25+
duckImage,
26+
duckImagePath,
27+
})

test/node/wretch.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const duckImage = fs.readFileSync(duckImagePath)
1414

1515
createWretchTests({
1616
describe,
17-
it,
17+
it: (name, fn) => it(name,{ timeout: 5000 }, fn),
1818
beforeEach,
1919
assert,
2020
expect,

test/shared/wretch.spec.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const isSafari =
2020
navigator.userAgent.indexOf("Safari") >= 0 &&
2121
navigator.userAgent.indexOf("Chrome") < 0
2222
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined"
23+
const isDeno = typeof globalThis.Deno !== "undefined"
2324

2425
const allRoutes = <T>(
2526
obj: Wretch,
@@ -81,7 +82,6 @@ export function createWretchTests(ctx: TestContext): void {
8182
if (before) {
8283
before(async function () {
8384
this.timeout(5000)
84-
await new Promise(resolve => setTimeout(resolve, 2000))
8585
})
8686
}
8787

@@ -550,7 +550,7 @@ export function createWretchTests(ctx: TestContext): void {
550550
})
551551

552552
it("should retrieve performance timings associated with a fetch request", async function () {
553-
if (isSafari)
553+
if (isSafari || isDeno)
554554
return
555555

556556
const w = wretch()
@@ -565,11 +565,14 @@ export function createWretchTests(ctx: TestContext): void {
565565
}).res().catch(_ => "ignore")
566566
})
567567

568-
for (let i = 0; i < 5; i++) {
569-
w.url(`${_URL}/fake/${i}`).get().perfs(timings => {
570-
expect(timings.name).toBe(`${_URL}/fake/${i}`)
571-
}).res().catch(() => "ignore")
572-
}
568+
await Promise.all(new Array(5).fill(0).map((_, i) =>
569+
new Promise<void>(resolve => {
570+
w.url(`${_URL}/fake/${i}`).get().perfs(timings => {
571+
expect(timings.name).toBe(`${_URL}/fake/${i}`)
572+
resolve()
573+
}).res().catch(() => "ignore")
574+
})
575+
))
573576
})
574577

575578
it("should monitor download progress", async function () {
@@ -784,7 +787,7 @@ export function createWretchTests(ctx: TestContext): void {
784787
})
785788

786789
it("should program resolvers", async function () {
787-
if(isSafari)
790+
if(isSafari || isDeno)
788791
return
789792

790793
let check = 0

0 commit comments

Comments
 (0)