feat(test): add api branch test
This commit is contained in:
parent
f7c81641b2
commit
1896e2385d
5 changed files with 1251 additions and 1 deletions
|
|
@ -7,6 +7,7 @@
|
||||||
"start": "node ./dist/app.js",
|
"start": "node ./dist/app.js",
|
||||||
"dev": "nodemon",
|
"dev": "nodemon",
|
||||||
"check": "tsc --noEmit",
|
"check": "tsc --noEmit",
|
||||||
|
"test": "vitest",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"debug": "nodemon",
|
"debug": "nodemon",
|
||||||
"build": "tsoa spec-and-routes && tsc",
|
"build": "tsoa spec-and-routes && tsc",
|
||||||
|
|
@ -27,12 +28,14 @@
|
||||||
"@types/multer": "^1.4.12",
|
"@types/multer": "^1.4.12",
|
||||||
"@types/node": "^20.17.10",
|
"@types/node": "^20.17.10",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
|
"@vitest/ui": "^3.1.4",
|
||||||
"nodemon": "^3.1.9",
|
"nodemon": "^3.1.9",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"prisma": "^6.3.0",
|
"prisma": "^6.3.0",
|
||||||
"prisma-kysely": "^1.8.0",
|
"prisma-kysely": "^1.8.0",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.7.2"
|
"typescript": "^5.7.2",
|
||||||
|
"vitest": "^3.1.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@elastic/elasticsearch": "^8.17.0",
|
"@elastic/elasticsearch": "^8.17.0",
|
||||||
|
|
|
||||||
909
pnpm-lock.yaml
generated
909
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
323
test/branch.test.ts
Normal file
323
test/branch.test.ts
Normal file
|
|
@ -0,0 +1,323 @@
|
||||||
|
import { afterAll, beforeAll, describe, expect, it, onTestFailed } from "vitest";
|
||||||
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
|
||||||
|
import { isDateString } from "./lib";
|
||||||
|
|
||||||
|
const prisma = new PrismaClient({
|
||||||
|
datasourceUrl: process.env.TEST_DATABASE_URL || process.env.DATABASE_URL,
|
||||||
|
});
|
||||||
|
const baseUrl = process.env.TEST_BASE_URL || "http://localhost";
|
||||||
|
const record: Record<string, any> = {
|
||||||
|
code: "CMT",
|
||||||
|
taxNo: "1052299402851",
|
||||||
|
name: "Chamomind",
|
||||||
|
nameEN: "Chamomind",
|
||||||
|
email: "contact@chamomind.com",
|
||||||
|
lineId: "@chamomind",
|
||||||
|
telephoneNo: "0988929248",
|
||||||
|
contactName: "John",
|
||||||
|
webUrl: "https://chamomind.com",
|
||||||
|
latitude: "",
|
||||||
|
longitude: "",
|
||||||
|
virtual: false,
|
||||||
|
permitNo: "1135182804792",
|
||||||
|
permitIssueDate: "2025-01-01T00:00:00.000Z",
|
||||||
|
permitExpireDate: "2030-01-01T00:00:00.000Z",
|
||||||
|
address: "11/3",
|
||||||
|
addressEN: "11/3",
|
||||||
|
soi: "1",
|
||||||
|
soiEN: "1",
|
||||||
|
moo: "2",
|
||||||
|
mooEN: "2",
|
||||||
|
street: "Straight",
|
||||||
|
streetEN: "Straight",
|
||||||
|
provinceId: "50",
|
||||||
|
districtId: "5001",
|
||||||
|
subDistrictId: "500107",
|
||||||
|
};
|
||||||
|
const recordList: Record<string, any>[] = [];
|
||||||
|
|
||||||
|
let token: string;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const body = new URLSearchParams();
|
||||||
|
|
||||||
|
body.append("grant_type", "password");
|
||||||
|
body.append("client_id", "app");
|
||||||
|
body.append("username", process.env.TEST_USERNAME || "");
|
||||||
|
body.append("password", process.env.TEST_PASSWORD || "");
|
||||||
|
body.append("scope", "openid");
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
process.env.KC_URL + "/realms/" + process.env.KC_REALM + "/protocol/openid-connect/token",
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
body: body,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(res.ok).toBe(true);
|
||||||
|
|
||||||
|
await res.json().then((data) => {
|
||||||
|
token = data["access_token"];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
if (!record["id"]) return;
|
||||||
|
|
||||||
|
await prisma.branch.deleteMany({
|
||||||
|
where: { id: { in: [record, ...recordList].map((v) => v["id"]) } },
|
||||||
|
});
|
||||||
|
await prisma.runningNo.deleteMany({
|
||||||
|
where: {
|
||||||
|
key: { in: [record, ...recordList].map((v) => `MAIN_BRANCH_${v["code"].slice(0, -5)}`) },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("branch management", () => {
|
||||||
|
it("create branch without required fields", async () => {
|
||||||
|
const requiredFields = [
|
||||||
|
"taxNo",
|
||||||
|
"name",
|
||||||
|
"nameEN",
|
||||||
|
"permitNo",
|
||||||
|
"telephoneNo",
|
||||||
|
"address",
|
||||||
|
"addressEN",
|
||||||
|
"email",
|
||||||
|
];
|
||||||
|
onTestFailed(() => console.log("Field:", requiredFields, "is required."));
|
||||||
|
|
||||||
|
for await (const field of requiredFields) {
|
||||||
|
const res = await fetch(baseUrl + "/api/v1/branch", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
["Content-Type"]: "application/json",
|
||||||
|
["Authorization"]: "Bearer " + token,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ ...record, [field]: undefined }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) recordList.push(await res.json());
|
||||||
|
|
||||||
|
expect(res.ok).toBe(false);
|
||||||
|
expect(res.status).toBe(400);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("create branch", async () => {
|
||||||
|
const res = await fetch(baseUrl + "/api/v1/branch", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
["Content-Type"]: "application/json",
|
||||||
|
["Authorization"]: "Bearer " + token,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(record),
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
const text = await res.text();
|
||||||
|
try {
|
||||||
|
console.log(JSON.parse(text));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(res.ok).toBe(true);
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
record["id"] = data["id"]; // This field is auto generated
|
||||||
|
record["code"] = data["code"]; // This field is auto generated
|
||||||
|
|
||||||
|
recordList.push(data);
|
||||||
|
|
||||||
|
expect(data).toMatchObject(record);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("get branch list", async () => {
|
||||||
|
const res = await fetch(baseUrl + "/api/v1/branch", {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
["Authorization"]: "Bearer " + token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
const text = await res.text();
|
||||||
|
try {
|
||||||
|
console.log(JSON.parse(text));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(res.ok).toBe(true);
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
expect(data).toHaveProperty("result");
|
||||||
|
expect(data).toHaveProperty("total");
|
||||||
|
expect(data).toHaveProperty("page");
|
||||||
|
expect(data).toHaveProperty("pageSize");
|
||||||
|
expect(data.result).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
code: expect.any(String),
|
||||||
|
virtual: expect.any(Boolean),
|
||||||
|
name: expect.any(String),
|
||||||
|
nameEN: expect.any(String),
|
||||||
|
email: expect.any(String),
|
||||||
|
taxNo: expect.any(String),
|
||||||
|
telephoneNo: expect.any(String),
|
||||||
|
latitude: expect.any(String),
|
||||||
|
longitude: expect.any(String),
|
||||||
|
contactName: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
lineId: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
webUrl: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
remark: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
selectedImage: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
|
||||||
|
isHeadOffice: expect.any(Boolean),
|
||||||
|
|
||||||
|
permitNo: expect.any(String),
|
||||||
|
permitIssueDate: expect.toSatisfy(isDateString(true)),
|
||||||
|
permitExpireDate: expect.toSatisfy(isDateString(true)),
|
||||||
|
|
||||||
|
address: expect.any(String),
|
||||||
|
addressEN: expect.any(String),
|
||||||
|
moo: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
mooEN: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
street: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
streetEN: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
provinceId: expect.any(String),
|
||||||
|
province: expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
name: expect.any(String),
|
||||||
|
nameEN: expect.any(String),
|
||||||
|
}),
|
||||||
|
districtId: expect.any(String),
|
||||||
|
district: expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
name: expect.any(String),
|
||||||
|
nameEN: expect.any(String),
|
||||||
|
}),
|
||||||
|
subDistrictId: expect.any(String),
|
||||||
|
subDistrict: expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
name: expect.any(String),
|
||||||
|
nameEN: expect.any(String),
|
||||||
|
zipCode: expect.any(String),
|
||||||
|
}),
|
||||||
|
|
||||||
|
status: expect.toBeOneOf(["CREATED", "ACTIVE", "INACTIVE"]),
|
||||||
|
statusOrder: expect.toBeOneOf([1, 0]),
|
||||||
|
|
||||||
|
createdAt: expect.toSatisfy(isDateString()),
|
||||||
|
createdByUserId: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
createdBy: expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
username: expect.any(String),
|
||||||
|
firstName: expect.any(String),
|
||||||
|
lastName: expect.any(String),
|
||||||
|
firstNameEN: expect.any(String),
|
||||||
|
lastNameEN: expect.any(String),
|
||||||
|
}),
|
||||||
|
updatedAt: expect.toSatisfy(isDateString()),
|
||||||
|
updatedByUserId: expect.toBeOneOf([expect.any(String), null]),
|
||||||
|
updatedBy: expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
username: expect.any(String),
|
||||||
|
firstName: expect.any(String),
|
||||||
|
lastName: expect.any(String),
|
||||||
|
firstNameEN: expect.any(String),
|
||||||
|
lastNameEN: expect.any(String),
|
||||||
|
}),
|
||||||
|
|
||||||
|
_count: expect.objectContaining({
|
||||||
|
branch: expect.any(Number),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("get branch by id", async () => {
|
||||||
|
const res = await fetch(baseUrl + "/api/v1/branch/" + record["id"], {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
["Authorization"]: "Bearer " + token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
const text = await res.text();
|
||||||
|
try {
|
||||||
|
console.log(JSON.parse(text));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(res.ok).toBe(true);
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
expect(data).toMatchObject(record);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("update branch by id", async () => {
|
||||||
|
const res = await fetch(baseUrl + "/api/v1/branch/" + record["id"], {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
["Content-Type"]: "application/json",
|
||||||
|
["Authorization"]: "Bearer " + token,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ name: "Chamomind Intl.", nameEN: "Chamomind Intl." }),
|
||||||
|
});
|
||||||
|
|
||||||
|
record["name"] = "Chamomind Intl.";
|
||||||
|
record["nameEN"] = "Chamomind Intl.";
|
||||||
|
|
||||||
|
expect(res.ok).toBe(true);
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
expect(data).toMatchObject(record);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("delete branch by id", async () => {
|
||||||
|
const res = await fetch(baseUrl + "/api/v1/branch/" + record["id"], {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
["Content-Type"]: "application/json",
|
||||||
|
["Authorization"]: "Bearer " + token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
const text = await res.text();
|
||||||
|
try {
|
||||||
|
console.log(JSON.parse(text));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(res.ok).toBe(true);
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
expect(data).toMatchObject(record);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("get deleted branch by id", async () => {
|
||||||
|
const res = await fetch(baseUrl + "/api/v1/branch/" + record["id"], {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
["Authorization"]: "Bearer " + token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.ok).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
10
test/lib/index.ts
Normal file
10
test/lib/index.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
export function isDateString(nullable: boolean = false): (val: any) => boolean {
|
||||||
|
return (value: any) => {
|
||||||
|
try {
|
||||||
|
if (value) return !!new Date(value);
|
||||||
|
return nullable;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
5
vite.config.ts
Normal file
5
vite.config.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { defineConfig } from "vitest/config";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
test: {},
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue