157 lines
6.3 KiB
TypeScript
157 lines
6.3 KiB
TypeScript
import { content, upgradeMaxLevel } from "@deadhead/content";
|
|
import { companyResponseSchema, errorResponseSchema, playerStateSchema } from "@deadhead/schema";
|
|
import { eq } from "drizzle-orm";
|
|
import { describe, expect, it } from "vitest";
|
|
import { buildApp } from "../src/app";
|
|
import { createRecordingQueue } from "../src/jobs/queue";
|
|
import { useTestDatabase } from "./db";
|
|
import {
|
|
call,
|
|
getState,
|
|
insertDispatch,
|
|
signUp,
|
|
signUpOwner,
|
|
testContract,
|
|
useTestApp,
|
|
} from "./game";
|
|
import { pilots, ships } from "../src/db/schema";
|
|
import { testConfig } from "./helpers";
|
|
|
|
const database = useTestDatabase();
|
|
const testApp = useTestApp(database);
|
|
|
|
describe("developer tools (Step 10K.11)", () => {
|
|
it("advances the server clock", async () => {
|
|
const guest = await signUp(testApp().app);
|
|
const before = (await call(testApp().app, guest, "GET", "/api/time")).json().realTime as number;
|
|
const response = await call(testApp().app, guest, "POST", "/api/test/advance-clock", {
|
|
advanceMs: 600_000,
|
|
});
|
|
expect(response.statusCode).toBe(200);
|
|
const after = (await call(testApp().app, guest, "GET", "/api/time")).json().realTime as number;
|
|
expect(after - before).toBeGreaterThanOrEqual(600_000);
|
|
});
|
|
|
|
it("adds credits", async () => {
|
|
const guest = await signUp(testApp().app);
|
|
const start = (await getState(testApp().app, guest)).company.credits;
|
|
const response = await call(testApp().app, guest, "POST", "/api/test/add-credits", {
|
|
amount: 10_000,
|
|
});
|
|
expect(companyResponseSchema.parse(response.json()).company.credits).toBe(start + 10_000);
|
|
});
|
|
|
|
it("lands every flight when advanced to the last arrival", async () => {
|
|
const { app, clock } = testApp();
|
|
const owner = await signUpOwner(app, database().db);
|
|
const flight = await insertDispatch(database().db, {
|
|
playerId: owner.playerId,
|
|
shipId: owner.shipId,
|
|
pilotId: owner.avatarId,
|
|
departAt: clock.now,
|
|
contract: testContract(),
|
|
});
|
|
expect((await getState(app, owner)).activeDispatches).toHaveLength(1);
|
|
await call(app, owner, "POST", "/api/test/advance-clock", {
|
|
advanceMs: flight.arrivalAt - clock.now + 1000,
|
|
});
|
|
expect((await getState(app, owner)).activeDispatches).toHaveLength(0);
|
|
});
|
|
|
|
it("does not exist in production", async () => {
|
|
const app = buildApp(testConfig({ NODE_ENV: "production" }), {
|
|
database: database(),
|
|
jobs: createRecordingQueue(),
|
|
});
|
|
for (const [url, payload] of [
|
|
["/api/test/clock-offset", { offsetMs: 1 }],
|
|
["/api/test/advance-clock", { advanceMs: 1000 }],
|
|
["/api/test/add-credits", { amount: 10_000 }],
|
|
["/api/test/pilot", { pilotId: "p", action: "level-up" }],
|
|
["/api/test/ship", { shipId: "s", action: "max-upgrades" }],
|
|
["/api/test/discover-all", {}],
|
|
] as const) {
|
|
const response = await app.inject({ method: "POST", url, payload });
|
|
expect(response.statusCode, url).toBe(404);
|
|
}
|
|
await app.close();
|
|
});
|
|
|
|
it("levels a pilot up to the next level's XP, and clears duty and rest", async () => {
|
|
const { app, clock } = testApp();
|
|
const owner = await signUpOwner(app, database().db);
|
|
await database()
|
|
.db.update(pilots)
|
|
.set({ xp: 40, dutyHours: 9, restEndsAt: clock.now + 3_600_000 })
|
|
.where(eq(pilots.id, owner.avatarId));
|
|
const pilotAfter = async (action: string) => {
|
|
const response = await call(app, owner, "POST", "/api/test/pilot", {
|
|
pilotId: owner.avatarId,
|
|
action,
|
|
});
|
|
expect(response.statusCode).toBe(200);
|
|
return playerStateSchema.parse(response.json()).pilots.find((p) => p.id === owner.avatarId)!;
|
|
};
|
|
const levelled = await pilotAfter("level-up");
|
|
expect(levelled.xp).toBe(content.config.pilotLevelXpThresholds[0]);
|
|
expect(levelled.level).toBe(1);
|
|
expect(levelled.skillPointsAvailable).toBe(content.config.skillPointsPerLevel);
|
|
expect((await pilotAfter("level-up")).level).toBe(2);
|
|
const rested = await pilotAfter("clear-rest");
|
|
expect(rested).toMatchObject({ dutyHours: 0, resting: false, restEndsAt: null });
|
|
});
|
|
|
|
it("maxes and resets a ship's upgrades, and finishes shop work", async () => {
|
|
const { app, clock } = testApp();
|
|
const owner = await signUpOwner(app, database().db);
|
|
const ship = async (input: Record<string, unknown>) => {
|
|
const response = await call(app, owner, "POST", "/api/test/ship", {
|
|
shipId: owner.shipId,
|
|
...input,
|
|
});
|
|
expect(response.statusCode).toBe(200);
|
|
return playerStateSchema.parse(response.json()).ships.find((s) => s.id === owner.shipId)!;
|
|
};
|
|
const maxed = await ship({ action: "max-upgrades" });
|
|
for (const upgrade of content.upgrades) {
|
|
expect(maxed.upgrades[upgrade.id], upgrade.id).toBe(upgradeMaxLevel(upgrade, "courier"));
|
|
}
|
|
expect(maxed.stats.fuelRangeMillionKm).toBeGreaterThan(
|
|
content.shipModel("courier")!.fuelRangeMillionKm,
|
|
);
|
|
expect((await ship({ action: "reset-upgrades" })).upgrades).toEqual({});
|
|
|
|
await database()
|
|
.db.update(ships)
|
|
.set({ inShopUntil: clock.now + 600_000, shopUpgradeId: "engines", shopLevel: 1 })
|
|
.where(eq(ships.id, owner.shipId));
|
|
expect((await ship({ action: "finish-shop" })).inShopUntil).toBeNull();
|
|
});
|
|
|
|
it("moves an idle ship to a discovered place only", async () => {
|
|
const { app } = testApp();
|
|
const owner = await signUpOwner(app, database().db);
|
|
const move = (locationId: string) =>
|
|
call(app, owner, "POST", "/api/test/ship", {
|
|
shipId: owner.shipId,
|
|
action: "move",
|
|
locationId,
|
|
});
|
|
const moved = await move("moon");
|
|
expect(moved.statusCode).toBe(200);
|
|
expect(playerStateSchema.parse(moved.json()).ships[0]!.locationId).toBe("moon");
|
|
const refused = await move("mars");
|
|
expect(refused.statusCode).toBe(409);
|
|
expect(errorResponseSchema.parse(refused.json()).error.code).toBe("location-undiscovered");
|
|
});
|
|
|
|
it("discovers every location", async () => {
|
|
const { app } = testApp();
|
|
const owner = await signUpOwner(app, database().db);
|
|
const response = await call(app, owner, "POST", "/api/test/discover-all", {});
|
|
const { locations } = playerStateSchema.parse(response.json());
|
|
expect(locations.every((l) => l.discovered)).toBe(true);
|
|
expect(locations).toHaveLength(content.locations.length);
|
|
});
|
|
});
|