108 lines
4.0 KiB
TypeScript
108 lines
4.0 KiB
TypeScript
import { content } from "@deadhead/content";
|
|
import { companyResponseSchema, errorResponseSchema } from "@deadhead/schema";
|
|
import { eq } from "drizzle-orm";
|
|
import { describe, expect, it } from "vitest";
|
|
import { pilots, players } from "../src/db/schema";
|
|
import { setCredits, useTestDatabase } from "./db";
|
|
import {
|
|
call,
|
|
getState,
|
|
insertDispatch,
|
|
signUp,
|
|
signUpOwner,
|
|
useTestApp,
|
|
type Guest,
|
|
} from "./game";
|
|
|
|
const database = useTestDatabase();
|
|
const testApp = useTestApp(database);
|
|
|
|
const claim = (guest: Guest, goalId: string) =>
|
|
call(testApp().app, guest, "POST", `/api/goals/${goalId}/claim`);
|
|
|
|
const errorCode = (response: { json(): unknown }) =>
|
|
errorResponseSchema.parse(response.json()).error.code;
|
|
|
|
/** An owner who has accepted the deal (so "pay off your loan" can apply). */
|
|
async function dealOwner() {
|
|
const owner = await signUpOwner(testApp().app, database().db);
|
|
await database()
|
|
.db.update(players)
|
|
.set({ dealAccepted: true })
|
|
.where(eq(players.id, owner.playerId));
|
|
return owner;
|
|
}
|
|
|
|
const status = async (guest: Guest, goalId: string) =>
|
|
(await getState(testApp().app, guest)).goals.find((g) => g.id === goalId)?.status;
|
|
|
|
describe("onboarding goals", () => {
|
|
it("are absent from state during the tutorial", async () => {
|
|
const guest = await signUp(testApp().app);
|
|
expect((await getState(testApp().app, guest)).goals).toEqual([]);
|
|
});
|
|
|
|
it("are listed in content order once the tutorial is over", async () => {
|
|
const owner = await dealOwner();
|
|
const goals = (await getState(testApp().app, owner)).goals;
|
|
expect(goals.map((g) => g.id)).toEqual(content.onboardingGoals.map((g) => g.id));
|
|
// Paid-off loan: the test owner has no balance.
|
|
expect(goals.find((g) => g.id === "loan-paid-off")?.status).toBe("ready");
|
|
expect(goals.find((g) => g.id === "veteran-contract")?.status).toBe("incomplete");
|
|
});
|
|
|
|
it("becomes ready when its condition is met: a delivery with the player's own ship", async () => {
|
|
const { clock } = testApp();
|
|
const owner = await dealOwner();
|
|
expect(await status(owner, "first-own-delivery")).toBe("incomplete");
|
|
const record = await insertDispatch(database().db, {
|
|
playerId: owner.playerId,
|
|
shipId: owner.shipId,
|
|
pilotId: owner.avatarId,
|
|
departAt: clock.now,
|
|
});
|
|
clock.now = record.arrivalAt;
|
|
expect(await status(owner, "first-own-delivery")).toBe("ready");
|
|
});
|
|
|
|
it("counts skill points spent", async () => {
|
|
const owner = await dealOwner();
|
|
await database()
|
|
.db.update(pilots)
|
|
.set({ skillPointsSpent: 1 })
|
|
.where(eq(pilots.id, owner.avatarId));
|
|
expect(await status(owner, "first-skill-point")).toBe("ready");
|
|
});
|
|
|
|
it("claiming a completed goal adds its reward once", async () => {
|
|
const owner = await dealOwner();
|
|
await setCredits(database().db, owner.playerId, 100);
|
|
const reward = content.onboardingGoal("loan-paid-off")!.reward;
|
|
|
|
const response = await claim(owner, "loan-paid-off");
|
|
expect(response.statusCode).toBe(200);
|
|
expect(companyResponseSchema.parse(response.json()).company.credits).toBe(100 + reward);
|
|
expect(await status(owner, "loan-paid-off")).toBe("claimed");
|
|
|
|
const again = await claim(owner, "loan-paid-off");
|
|
expect(again.statusCode).toBe(409);
|
|
expect(errorCode(again)).toBe("goal-already-claimed");
|
|
expect((await getState(testApp().app, owner)).company.credits).toBe(100 + reward);
|
|
});
|
|
|
|
it("refuses an incomplete goal and an unknown one", async () => {
|
|
const owner = await dealOwner();
|
|
await setCredits(database().db, owner.playerId, 100);
|
|
const response = await claim(owner, "veteran-contract");
|
|
expect(response.statusCode).toBe(409);
|
|
expect(errorCode(response)).toBe("goal-not-ready");
|
|
expect((await claim(owner, "win-the-game")).statusCode).toBe(404);
|
|
expect((await getState(testApp().app, owner)).company.credits).toBe(100);
|
|
});
|
|
|
|
it("refuses claims during the tutorial", async () => {
|
|
const guest = await signUp(testApp().app);
|
|
expect(errorCode(await claim(guest, "loan-paid-off"))).toBe("goal-not-ready");
|
|
});
|
|
});
|