test: add initial unit integration and e2e coverage
Adds the initial testing baseline for the project: Unit coverage: - Zod schemas for items, assignments, movements, categories, auth, recipients, users, and assets - password hashing and verification helpers - auth role helper functions Integration coverage with PostgreSQL Testcontainers: - item use-cases: create, duplicate names, delete constraints - assignment use-cases: create, insufficient stock, return, double return - asset use-cases: available/assigned creation and lifecycle transitions - user use-cases: create/update, uniqueness, admin safeguards, password reset - category use-cases: create/update/delete constraints - recipient use-cases: create/update and uniqueness constraints E2E smoke coverage with Playwright: - unauthenticated redirect to login - seeded admin login - dashboard load - admin users page - inventory items page - assignments page Also configures: - Vitest - Playwright - PostgreSQL Testcontainers helpers - deterministic E2E admin bootstrap - test artifact ignores Validation: - bun run test: 9 files / 37 tests passed - bun run test:e2e: 3 passed - bunx tsc --noEmit: passed - bunx prisma validate: passed
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
import { describe, expect, it } from "vitest"
|
||||
import { createAssetSchema, updateAssetSchema } from "@/schemas/asset.schema"
|
||||
import { createAssignmentSchema } from "@/schemas/assignment.schema"
|
||||
import { signInSchema } from "@/schemas/auth.schema"
|
||||
import { createCategorySchema } from "@/schemas/category.schema"
|
||||
import { createItemSchema, updateItemSchema } from "@/schemas/item.schema"
|
||||
import { createMovementSchema } from "@/schemas/movement.schema"
|
||||
import { createRecipientSchema } from "@/schemas/recipient.schema"
|
||||
import { createUserSchema, updateUserSchema } from "@/schemas/user.schema"
|
||||
|
||||
describe("core schemas", () => {
|
||||
it("coerces valid numeric fields", () => {
|
||||
expect(
|
||||
createItemSchema.safeParse({
|
||||
name: "Laptop",
|
||||
categoryId: "category-id",
|
||||
stock: "3",
|
||||
}),
|
||||
).toMatchObject({ success: true, data: { stock: 3 } })
|
||||
|
||||
expect(
|
||||
createAssignmentSchema.safeParse({
|
||||
itemId: "item-id",
|
||||
recipientId: "recipient-id",
|
||||
quantity: "2",
|
||||
}),
|
||||
).toMatchObject({ success: true, data: { quantity: 2 } })
|
||||
|
||||
expect(
|
||||
createMovementSchema.safeParse({
|
||||
type: "IN",
|
||||
quantity: "1",
|
||||
itemId: "item-id",
|
||||
}),
|
||||
).toMatchObject({ success: true, data: { quantity: 1 } })
|
||||
})
|
||||
|
||||
it("rejects invalid numeric fields", () => {
|
||||
expect(
|
||||
createItemSchema.safeParse({
|
||||
name: "Laptop",
|
||||
categoryId: "category-id",
|
||||
stock: -1,
|
||||
}).success,
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
createAssignmentSchema.safeParse({
|
||||
itemId: "item-id",
|
||||
recipientId: "recipient-id",
|
||||
quantity: 0,
|
||||
}).success,
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
createMovementSchema.safeParse({
|
||||
type: "IN",
|
||||
quantity: 0,
|
||||
itemId: "item-id",
|
||||
}).success,
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it("validates required identifiers for update schemas", () => {
|
||||
expect(
|
||||
updateItemSchema.safeParse({
|
||||
id: "item-id",
|
||||
name: "Laptop",
|
||||
categoryId: "category-id",
|
||||
stock: 1,
|
||||
}).success,
|
||||
).toBe(true)
|
||||
|
||||
expect(
|
||||
updateItemSchema.safeParse({
|
||||
id: "",
|
||||
name: "Laptop",
|
||||
categoryId: "category-id",
|
||||
stock: 1,
|
||||
}).success,
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
updateUserSchema.safeParse({
|
||||
id: "user-id",
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
}).success,
|
||||
).toBe(true)
|
||||
|
||||
expect(
|
||||
updateUserSchema.safeParse({
|
||||
id: "",
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
}).success,
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it("validates category and auth requirements", () => {
|
||||
expect(createCategorySchema.safeParse({ name: "IT" }).success).toBe(false)
|
||||
expect(createCategorySchema.safeParse({ name: "Hardware" }).success).toBe(
|
||||
true,
|
||||
)
|
||||
|
||||
expect(
|
||||
signInSchema.safeParse({ username: "admin", password: "abc" }).success,
|
||||
).toBe(true)
|
||||
expect(
|
||||
signInSchema.safeParse({ username: "", password: "abc" }).success,
|
||||
).toBe(false)
|
||||
expect(
|
||||
signInSchema.safeParse({ username: "admin", password: "ab" }).success,
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it("validates recipient email only when present", () => {
|
||||
expect(
|
||||
createRecipientSchema.safeParse({
|
||||
username: "recipient",
|
||||
firstName: "Rec",
|
||||
lastName: "Ipient",
|
||||
department: "IT",
|
||||
email: "recipient@example.test",
|
||||
}).success,
|
||||
).toBe(true)
|
||||
|
||||
expect(
|
||||
createRecipientSchema.safeParse({
|
||||
username: "recipient",
|
||||
firstName: "Rec",
|
||||
lastName: "Ipient",
|
||||
department: "IT",
|
||||
email: "not-an-email",
|
||||
}).success,
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
createRecipientSchema.safeParse({
|
||||
username: "recipient",
|
||||
firstName: "Rec",
|
||||
lastName: "Ipient",
|
||||
department: "IT",
|
||||
email: "",
|
||||
}).success,
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it("validates user password, email, and role", () => {
|
||||
expect(
|
||||
createUserSchema.safeParse({
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
password: "password1",
|
||||
role: "STAFF",
|
||||
isActive: true,
|
||||
}).success,
|
||||
).toBe(true)
|
||||
|
||||
expect(
|
||||
createUserSchema.safeParse({
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "bad-email",
|
||||
password: "password1",
|
||||
role: "STAFF",
|
||||
isActive: true,
|
||||
}).success,
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
createUserSchema.safeParse({
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
password: "short",
|
||||
role: "STAFF",
|
||||
isActive: true,
|
||||
}).success,
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
createUserSchema.safeParse({
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
password: "password1",
|
||||
role: "OWNER",
|
||||
isActive: true,
|
||||
}).success,
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it("validates asset status options", () => {
|
||||
expect(
|
||||
createAssetSchema.safeParse({
|
||||
itemId: "item-id",
|
||||
serialNumber: "SERIAL-001",
|
||||
status: "AVAILABLE",
|
||||
}).success,
|
||||
).toBe(true)
|
||||
|
||||
expect(
|
||||
createAssetSchema.safeParse({
|
||||
itemId: "item-id",
|
||||
serialNumber: "SERIAL-001",
|
||||
status: "BROKEN",
|
||||
}).success,
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
updateAssetSchema.safeParse({
|
||||
id: "asset-id",
|
||||
itemId: "item-id",
|
||||
serialNumber: "SERIAL-001",
|
||||
status: "BROKEN",
|
||||
}).success,
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user