Skip to content

Commit d72685e

Browse files
committed
Add tests for isFile and isFormData helpers. Loosen isFormData helper.
1 parent be83da0 commit d72685e

File tree

5 files changed

+67
-23
lines changed

5 files changed

+67
-23
lines changed

lib/FileLike.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export interface FileLike {
77

88
lastModified: number
99

10-
stream(): {[Symbol.asyncIterator](): AsyncIterableIterator<any>}
10+
stream(): {[Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array>}
1111

1212
[Symbol.toStringTag]: string
1313
}

lib/FormDataLike.ts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,21 @@
11
import {FileLike} from "./FileLike"
22

3+
/**
4+
* This interface reflects possible values of each FormData entry
5+
*/
36
export type FormDataEntryValue = string | FileLike
47

8+
/**
9+
* This interface reflects minimal shape of the FormData
10+
*/
511
export interface FormDataLike {
6-
set(name: string, value: unknown): void
12+
append(name: string, value: unknown, filename?: string): void
713

8-
append(name: string, value: unknown): void
14+
getAll(name: string): FormDataEntryValue[]
915

10-
has(name: string): boolean
16+
entries(): Generator<[string, FormDataEntryValue]>
1117

12-
get(name: string): null | FormDataEntryValue
13-
14-
getAll(name: string): Array<null | FormDataEntryValue>
15-
16-
delete(name: string): void
17-
18-
keys(): IterableIterator<string>
19-
20-
values(): IterableIterator<FormDataEntryValue>
21-
22-
entries(): IterableIterator<[string, FormDataEntryValue]>
23-
24-
[Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>
18+
[Symbol.iterator](): Generator<[string, FormDataEntryValue]>
2519

2620
[Symbol.toStringTag]: string
2721
}

lib/util/isFile.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import {FileLike} from "../FileLike"
55
const VALID_NAMES = ["File", "Blob"]
66

77
/**
8-
* Check if given object is File
8+
* Check if given object is File.
9+
*
10+
* Note that this function will return "false" for Blob, because the Encoder expects FormData to return File when a value is binary data.
911
*
1012
* @param value an object to test
1113
*/
@@ -15,6 +17,9 @@ const isFile = (value?: unknown): value is FileLike => Boolean(
1517
&& isFunction((value as FileLike).constructor)
1618
&& VALID_NAMES.includes((value as FileLike)[Symbol.toStringTag])
1719
&& isFunction((value as FileLike).stream)
20+
&& (value as FileLike).name != null
21+
&& (value as FileLike).size != null
22+
&& (value as FileLike).lastModified != null
1823
)
1924

2025
export default isFile

lib/util/isFormData.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,60 @@ import {FormData} from "formdata-node"
44

55
import isFormData from "./isFormData"
66

7+
import {FormDataLike, FormDataEntryValue} from "../FormDataLike"
8+
79
test("Returns true for spec-compatible FormData instance", t => {
810
t.true(isFormData(new FormData()))
911
})
1012

13+
test("Returns true for a class that implements minimal FormData", t => {
14+
class MyFormData implements FormDataLike {
15+
append(): void {}
16+
17+
getAll(): FormDataEntryValue[] {
18+
return []
19+
}
20+
21+
* entries(): Generator<[string, FormDataEntryValue]> {
22+
yield ["name", "value"]
23+
}
24+
25+
[Symbol.iterator]() {
26+
return this.entries()
27+
}
28+
29+
get [Symbol.toStringTag](): string {
30+
return "FormData"
31+
}
32+
}
33+
34+
t.true(isFormData(new MyFormData()))
35+
})
36+
37+
test("Returns true for FormData-shaped object", t => {
38+
const object = {
39+
append(): void {},
40+
41+
getAll(): FormDataEntryValue[] {
42+
return []
43+
},
44+
45+
* entries(): Generator<[string, FormDataEntryValue]> {
46+
yield ["name", "value"]
47+
},
48+
49+
[Symbol.iterator]() {
50+
return this.entries()
51+
},
52+
53+
get [Symbol.toStringTag](): string {
54+
return "FormData"
55+
}
56+
}
57+
58+
t.true(isFormData(object))
59+
})
60+
1161
test("Returns false for null", t => {
1262
t.false(isFormData(null))
1363
})

lib/util/isFormData.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,8 @@ const isFormData = (value?: unknown): value is FormDataLike => Boolean(
1111
(value as FormDataLike)
1212
&& isFunction((value as FormDataLike).constructor)
1313
&& (value as FormDataLike)[Symbol.toStringTag] === "FormData"
14-
&& isFunction((value as FormDataLike).set)
1514
&& isFunction((value as FormDataLike).append)
16-
&& isFunction((value as FormDataLike).has)
17-
&& isFunction((value as FormDataLike).get)
1815
&& isFunction((value as FormDataLike).getAll)
19-
&& isFunction((value as FormDataLike).keys)
20-
&& isFunction((value as FormDataLike).values)
2116
&& isFunction((value as FormDataLike).entries)
2217
&& isFunction((value as FormDataLike)[Symbol.iterator])
2318
)

0 commit comments

Comments
 (0)