从头开始创建一个自动产生文档/类型安全的现代API(14) 完整测试脚本

测试脚本脑图

根据需要测试的功能点,我画了以下脑图:

修改测试脚本

修改 app/api/[[...route]]/routes/tasks/tasks.test.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/* eslint-disable ts/ban-ts-comment */
import { testClient } from "hono/testing";
import { execSync } from "node:child_process";
import fs from "node:fs";
import * as HttpStatusPhrases from "stoker/http-status-phrases";
import { afterAll, beforeAll, describe, expect, expectTypeOf, it } from "vitest";
import { ZodIssueCode } from "zod";


import { ZOD_ERROR_CODES, ZOD_ERROR_MESSAGES } from "@/utility/constants";
import createApp from "../../lib/create-app";

import router from "./tasks.index";
import env from "@/utility/env";

if (env.NODE_ENV !== "test") {
throw new Error("NODE_ENV must be 'test'");
}

const client = testClient(createApp().route("/", router));

describe("tasks routes", () => {
beforeAll(async () => {
execSync("bun drizzle-kit push");
});

afterAll(async () => {
fs.rmSync("test.db", { force: true });
});

it("post /tasks validates the body when creating", async () => {
const response = await client.api.tasks.$post({
// @ts-expect-error
json: {
done: false,
},
});
expect(response.status).toBe(422);
if (response.status === 422) {
const json = await response.json();
expect(json.error.issues[0].path[0]).toBe("name");
expect(json.error.issues[0].message).toBe(ZOD_ERROR_MESSAGES.REQUIRED);
}
});

const id = 1;
const name = "Learn vitest";

it("post /tasks creates a task", async () => {
const response = await client.api.tasks.$post({
json: {
name,
done: false,
},
});
expect(response.status).toBe(200);
if (response.status === 200) {
const json = await response.json();
expect(json.name).toBe(name);
expect(json.done).toBe(false);
}
});

it("get /tasks lists all tasks", async () => {
const response = await client.api.tasks.$get();
expect(response.status).toBe(200);
if (response.status === 200) {
const json = await response.json();
expectTypeOf(json).toBeArray();
expect(json.length).toBe(1);
}
});

it("get /tasks/{id} validates the id param", async () => {
const response = await client.api.tasks[":id"].$get({
param: {
// @ts-expect-error
id: "wat",
},
});
expect(response.status).toBe(422);
if (response.status === 422) {
const json = await response.json();
expect(json.error.issues[0].path[0]).toBe("id");
expect(json.error.issues[0].message).toBe(ZOD_ERROR_MESSAGES.EXPECTED_NUMBER);
}
});

it("get /tasks/{id} returns 404 when task not found", async () => {
const response = await client.api.tasks[":id"].$get({
param: {
id: 999,
},
});
expect(response.status).toBe(404);
if (response.status === 404) {
const json = await response.json();
expect(json.message).toBe(HttpStatusPhrases.NOT_FOUND);
}
});

it("get /tasks/{id} gets a single task", async () => {
const response = await client.api.tasks[":id"].$get({
param: {
id,
},
});
expect(response.status).toBe(200);
if (response.status === 200) {
const json = await response.json();
expect(json.name).toBe(name);
expect(json.done).toBe(false);
}
});

it("patch /tasks/{id} validates the body when updating", async () => {
const response = await client.api.tasks[":id"].$patch({
param: {
id,
},
json: {
name: "",
},
});
expect(response.status).toBe(422);
if (response.status === 422) {
const json = await response.json();
expect(json.error.issues[0].path[0]).toBe("name");
expect(json.error.issues[0].code).toBe(ZodIssueCode.too_small);
}
});

it("patch /tasks/{id} validates the id param", async () => {
const response = await client.api.tasks[":id"].$patch({
param: {
// @ts-expect-error
id: "wat",
},
json: {},
});
expect(response.status).toBe(422);
if (response.status === 422) {
const json = await response.json();
expect(json.error.issues[0].path[0]).toBe("id");
expect(json.error.issues[0].message).toBe(ZOD_ERROR_MESSAGES.EXPECTED_NUMBER);
}
});

it("patch /tasks/{id} validates empty body", async () => {
const response = await client.api.tasks[":id"].$patch({
param: {
id,
},
json: {},
});
expect(response.status).toBe(422);
if (response.status === 422) {
const json = await response.json();
expect(json.error.issues[0].code).toBe(ZOD_ERROR_CODES.INVALID_UPDATES);
expect(json.error.issues[0].message).toBe(ZOD_ERROR_MESSAGES.NO_UPDATES);
}
});

it("patch /tasks/{id} updates a single property of a task", async () => {
const response = await client.api.tasks[":id"].$patch({
param: {
id,
},
json: {
done: true,
},
});
expect(response.status).toBe(200);
if (response.status === 200) {
const json = await response.json();
expect(json.done).toBe(true);
}
});

it("delete /tasks/{id} validates the id when deleting", async () => {
const response = await client.api.tasks[":id"].$delete({
param: {
// @ts-expect-error
id: "wat",
},
});
expect(response.status).toBe(422);
if (response.status === 422) {
const json = await response.json();
expect(json.error.issues[0].path[0]).toBe("id");
expect(json.error.issues[0].message).toBe(ZOD_ERROR_MESSAGES.EXPECTED_NUMBER);
}
});

it("delete /tasks/{id} removes a task", async () => {
const response = await client.api.tasks[":id"].$delete({
param: {
id,
},
});
expect(response.status).toBe(204);
});
});

测试了一下,成功通过测试。


作者:Bearalise
出处:从头开始创建一个自动产生文档/类型安全的现代API(14) 完整测试脚本
版权:本文版权归作者所有
转载:欢迎转载,但未经作者同意,必须保留此段声明,必须在文章中给出原文链接。

请我喝杯咖啡吧~

支付宝
微信