Business logic lives in services/, deliberately decoupled from the Slack SDK and from Supabase’s specific query shape wherever practical. This means the highest-value tests target services directly, with Slack/Supabase mocked at the boundary — no need to spin up a real Slack workspace to verify that extractDeadline handles “let’s ship by Friday” correctly.
| Layer | Tool | What it covers |
|---|---|---|
| Unit | Vitest | utils/dateParser.ts, services/*.service.ts business logic, with Supabase/Groq clients mocked |
| Integration | Vitest + a disposable Supabase branch/schema | Full round-trip: create task → list tasks → mark done, against a real (test) Postgres instance |
| Manual / E2E | Slack sandbox workspace | Slash commands, ephemeral prompts, PDF upload flow — see the checklist in docs/INSTALLATION.md step 6 |
// backend/src/utils/dateParser.test.ts
import { describe, it, expect } from "vitest";
import { parseRelativeDate } from "./dateParser";
describe("parseRelativeDate", () => {
it("resolves 'tomorrow at 3pm' to next day 15:00", () => {
const now = new Date("2026-07-06T10:00:00");
const result = parseRelativeDate("tomorrow at 3pm", now);
expect(result?.getDate()).toBe(7);
expect(result?.getHours()).toBe(15);
});
it("resolves 'eod' to 18:00 today", () => {
const now = new Date("2026-07-06T10:00:00");
const result = parseRelativeDate("eod", now);
expect(result?.getHours()).toBe(18);
});
it("returns null for unparseable input", () => {
expect(parseRelativeDate("sometime soon-ish")).toBeNull();
});
});
// backend/src/services/deadline.service.test.ts
import { describe, it, expect, vi } from "vitest";
import * as groqService from "./groq.service";
import { extractDeadline } from "./deadline.service";
describe("extractDeadline", () => {
it("skips the LLM call entirely when no temporal language is present", async () => {
const spy = vi.spyOn(groqService, "completeChat");
const result = await extractDeadline("thanks for the help earlier!", "2026-07-06");
expect(spy).not.toHaveBeenCalled();
expect(result.isDeadline).toBe(false);
});
});
cd backend
npm test
deadline.service.ts, meetingPrep.service.ts) so parsing failures are caught deterministically even if content quality varies.