mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-10-03 18:23:47 +10:00
122 lines
5.2 KiB
TypeScript
122 lines
5.2 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const dbMock = vi.hoisted(() => ({ select: vi.fn(), update: vi.fn() }));
|
|
const resumeServiceMock = vi.hoisted(() => ({
|
|
getById: vi.fn(),
|
|
create: vi.fn(),
|
|
delete: vi.fn(),
|
|
setLocked: vi.fn(),
|
|
}));
|
|
const applicationServiceMock = vi.hoisted(() => ({ update: vi.fn() }));
|
|
vi.mock("@reactive-resume/db/client", () => ({ db: dbMock }));
|
|
vi.mock("../resume/service", () => ({ resumeService: resumeServiceMock }));
|
|
vi.mock("../cover-letters/service", () => ({ coverLetterService: { getById: vi.fn(), update: vi.fn() } }));
|
|
vi.mock("../applications/service", () => ({ applicationService: applicationServiceMock }));
|
|
|
|
const { documentsService } = await import("./service");
|
|
|
|
// `select().from().where()` resolving to `rows`.
|
|
const rows = (result: unknown[]) => ({ from: () => ({ where: () => Promise.resolve(result) }) });
|
|
|
|
const updates = () => {
|
|
const set = vi.fn((_changes: Record<string, unknown>) => ({
|
|
where: () => Promise.resolve(),
|
|
}));
|
|
dbMock.update.mockReturnValue({ set });
|
|
return set;
|
|
};
|
|
|
|
beforeEach(() => {
|
|
for (const mock of [
|
|
...Object.values(dbMock),
|
|
...Object.values(resumeServiceMock),
|
|
...Object.values(applicationServiceMock),
|
|
])
|
|
mock.mockReset();
|
|
});
|
|
|
|
describe("Trash", () => {
|
|
it("won't move a locked document, and keeps the resume's error code", async () => {
|
|
dbMock.select.mockReturnValueOnce(rows([{ isLocked: true, trashedAt: null }]));
|
|
|
|
await expect(documentsService.trash({ userId: "u1", type: "resume", id: "r1" })).rejects.toMatchObject({
|
|
code: "RESUME_LOCKED",
|
|
status: 403,
|
|
});
|
|
expect(dbMock.update).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("deletes for good only what is already in Trash", async () => {
|
|
dbMock.select.mockReturnValueOnce(rows([{ isLocked: false, trashedAt: null }]));
|
|
await expect(documentsService.purge({ userId: "u1", type: "resume", id: "r1" })).rejects.toMatchObject({
|
|
code: "BAD_REQUEST",
|
|
});
|
|
|
|
dbMock.select.mockReturnValueOnce(rows([{ isLocked: false, trashedAt: new Date() }]));
|
|
await documentsService.purge({ userId: "u1", type: "resume", id: "r1" });
|
|
expect(resumeServiceMock.delete).toHaveBeenCalledWith({ id: "r1", userId: "u1" });
|
|
});
|
|
});
|
|
|
|
describe("copyForJob", () => {
|
|
const source = {
|
|
name: "Product Designer — Lumen",
|
|
tags: ["design"],
|
|
data: { metadata: { page: { locale: "en-US" } } },
|
|
};
|
|
|
|
it("links the copy to the job, and gives the job the copy when it has no resume", async () => {
|
|
resumeServiceMock.getById.mockResolvedValueOnce(source);
|
|
dbMock.select.mockReturnValueOnce(rows([{ id: "a1", company: "Orbital", resumeId: null }]));
|
|
resumeServiceMock.create.mockResolvedValueOnce("copy");
|
|
const set = updates();
|
|
|
|
const id = await documentsService.copyForJob({ userId: "u1", resumeId: "r1", applicationId: "a1" });
|
|
|
|
expect(id).toBe("copy");
|
|
expect(resumeServiceMock.create).toHaveBeenCalledWith(
|
|
expect.objectContaining({ name: "Product Designer — Orbital", tags: ["design"] }),
|
|
);
|
|
expect(set).toHaveBeenCalledWith({ applicationId: "a1" });
|
|
expect(applicationServiceMock.update).toHaveBeenCalledWith({ userId: "u1", id: "a1", resumeId: "copy" });
|
|
});
|
|
|
|
it.each(["saved", "applied"])(
|
|
"prepares a copy at %s while preserving its base and submitted documents",
|
|
async (status) => {
|
|
resumeServiceMock.getById.mockResolvedValueOnce(source);
|
|
dbMock.select.mockReturnValueOnce(rows([{ id: "a1", company: "Orbital", resumeId: "base", status }]));
|
|
resumeServiceMock.create.mockResolvedValueOnce("copy");
|
|
const set = updates();
|
|
|
|
await documentsService.copyForJob({ userId: "u1", resumeId: "r1", applicationId: "a1", name: "Mine" });
|
|
|
|
expect(resumeServiceMock.create).toHaveBeenCalledWith(expect.objectContaining({ name: "Mine" }));
|
|
expect(set).toHaveBeenCalledTimes(1);
|
|
if (status === "saved")
|
|
expect(applicationServiceMock.update).toHaveBeenCalledWith({ userId: "u1", id: "a1", resumeId: "copy" });
|
|
else expect(applicationServiceMock.update).not.toHaveBeenCalled();
|
|
expect(resumeServiceMock.create).toHaveBeenCalledWith(expect.objectContaining({ data: source.data }));
|
|
},
|
|
);
|
|
});
|
|
|
|
describe("linkApplication", () => {
|
|
it.each([
|
|
{ status: "saved", resumeId: null, sentResumeVersionId: null, selected: true },
|
|
{ status: "saved", resumeId: "base", sentResumeVersionId: null, selected: true },
|
|
{ status: "applied", resumeId: "submitted", sentResumeVersionId: "version", selected: false },
|
|
{ status: "saved", resumeId: "submitted", sentResumeVersionId: "version", selected: false },
|
|
])("links manual preparation while preserving submission history: %j", async ({ selected, ...application }) => {
|
|
dbMock.select.mockReturnValueOnce(rows([{ isLocked: false, trashedAt: null }]));
|
|
dbMock.select.mockReturnValueOnce(rows([{ id: "a1", company: "Orbital", ...application }]));
|
|
const set = vi.fn(() => ({ where: () => ({ returning: async () => [{ id: "new" }] }) }));
|
|
dbMock.update.mockReturnValue({ set });
|
|
await documentsService.linkApplication({ userId: "u1", type: "resume", id: "new", applicationId: "a1" });
|
|
expect(set).toHaveBeenCalledWith({ applicationId: "a1" });
|
|
if (selected)
|
|
expect(applicationServiceMock.update).toHaveBeenCalledWith({ userId: "u1", id: "a1", resumeId: "new" });
|
|
else expect(applicationServiceMock.update).not.toHaveBeenCalled();
|
|
});
|
|
});
|