deadhead-space-freight-tycoon/packages/content/test/ships.test.ts

80 lines
3.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { shipModelSchema, shipModels, gameConfig } from "../src/index";
const ship = (id: string) => shipModels.find((s) => s.id === id)!;
describe("ship models", () => {
it("all pass the schema", () => {
for (const model of shipModels) {
expect(() => shipModelSchema.parse(model)).not.toThrow();
}
});
// CR-012 §2 replaces the Step 2.3 ordering tests.
const order = (
key: "price" | "cruiseSpeedKmPerGameHour" | "cargoCapacityTonnes",
ids: string[],
) =>
ids
.slice(1)
.forEach((id, i) =>
expect(ship(id)[key], `${ids[i]} < ${id}`).toBeGreaterThan(ship(ids[i]!)[key]),
);
const purchasable = shipModels.filter((m) => m.purchasable);
const handling = (id: string) =>
ship(id).handlingGameHoursPerTonne ?? gameConfig.handlingGameHoursPerTonne;
it("has five purchasable models plus the loaner, all atmospheric", () => {
expect(shipModels.map((s) => s.id)).toEqual([
"courier",
"lighter",
"clipper",
"freighter",
"bulk-hauler",
"company-courier",
]);
for (const model of shipModels) {
expect(model.landingClass).toBe("atmospheric");
expect(model.role.length).toBeGreaterThan(10);
}
expect(ship("lighter").purchasable && ship("clipper").purchasable).toBe(true);
});
it("orders price Courier < Lighter < Clipper < Freighter < Bulk Hauler", () => {
order("price", ["courier", "lighter", "clipper", "freighter", "bulk-hauler"]);
});
it("makes the Clipper fastest, the Bulk Hauler slowest, and the Lighter slower than the Freighter", () => {
const speeds = shipModels.map((m) => m.cruiseSpeedKmPerGameHour);
expect(ship("clipper").cruiseSpeedKmPerGameHour).toBe(Math.max(...speeds));
expect(ship("bulk-hauler").cruiseSpeedKmPerGameHour).toBe(
Math.min(...purchasable.map((m) => m.cruiseSpeedKmPerGameHour)),
);
order("cruiseSpeedKmPerGameHour", ["bulk-hauler", "lighter", "freighter"]);
});
it("orders capacity Courier < Clipper < Lighter < Freighter < Bulk Hauler", () => {
order("cargoCapacityTonnes", ["courier", "clipper", "lighter", "freighter", "bulk-hauler"]);
const lighterShare =
ship("lighter").cargoCapacityTonnes / ship("freighter").cargoCapacityTonnes;
expect(lighterShare).toBeGreaterThanOrEqual(0.75);
expect(lighterShare).toBeLessThanOrEqual(0.9);
});
it("gives the Lighter the fastest loading and the Clipper a thirsty burn rate", () => {
for (const m of shipModels) {
if (m.id !== "lighter") expect(handling("lighter")).toBeLessThan(handling(m.id));
}
expect(ship("clipper").burnFuPerMillionKm).toBeGreaterThan(ship("courier").burnFuPerMillionKm);
expect(ship("clipper").burnFuPerMillionKm).toBeGreaterThan(
ship("freighter").burnFuPerMillionKm,
);
});
it("gives every ship model its own map sprite key (CR-003)", () => {
const sprites = shipModels.map((x) => x.sprite);
for (const sprite of sprites) expect(sprite).toMatch(/^[a-z][a-z-]*$/);
expect(new Set(sprites).size).toBe(sprites.length);
});
});