deadhead-space-freight-tycoon/apps/web/test/welcome.test.tsx

112 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { PlayerState } from "@deadhead/schema";
import { cleanup, screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it } from "vitest";
import { usePreferences } from "../src/state/preferences";
import { fakeApi, renderApp, samplePlayerState, sampleTutorialBoard, unauthorized } from "./render";
/** A fresh guest: "Start your company", then the new company with its welcome unseen. */
function newCompany() {
let started = false;
let state: PlayerState = samplePlayerState({ welcomeSeen: false });
const api = fakeApi({
getPlayerState: () => (started ? state : unauthorized()),
createGuest: () => {
started = true;
return { playerId: "p1", state };
},
getTutorialBoard: () => sampleTutorialBoard(),
markWelcomeSeen: () => {
state = { ...state, welcomeSeen: true };
return state;
},
});
return { api, state: () => state };
}
async function start(api: ReturnType<typeof newCompany>["api"]) {
renderApp(api, "/");
await userEvent.click(await screen.findByRole("button", { name: "Start your company" }));
return screen.findByRole("dialog", { name: "Welcome to Deadhead" });
}
describe("welcome cards (Step 22.2, decision 0.5.131)", () => {
it("walks through three cards and lands on Contracts with the intro card", async () => {
const { api, state } = newCompany();
const dialog = await start(api);
expect(dialog).toHaveTextContent("1 of 3");
expect(dialog).toHaveTextContent("never fly home empty");
await userEvent.click(within(dialog).getByRole("button", { name: "Next" }));
expect(dialog).toHaveTextContent("2 of 3");
expect(within(dialog).getByRole("heading")).toHaveTextContent("Your ships keep flying");
await userEvent.click(within(dialog).getByRole("button", { name: "Next" }));
expect(dialog).toHaveTextContent("3 of 3");
expect(dialog).toHaveTextContent(
"You're flying for Halvorsen Lunar Freight on the Earth–Moon run.",
);
expect(within(dialog).queryByRole("button", { name: "Next" })).not.toBeInTheDocument();
await userEvent.click(within(dialog).getByRole("button", { name: "Let's fly" }));
await waitFor(() => expect(screen.queryByRole("dialog")).not.toBeInTheDocument());
expect(api.call).toHaveBeenCalledWith("markWelcomeSeen", {});
expect(state().welcomeSeen).toBe(true);
expect(await screen.findByRole("heading", { level: 1, name: "Contracts" })).toBeInTheDocument();
expect(await screen.findByLabelText("Intro")).toHaveTextContent("needs a pilot");
});
it("closes from Skip on any card, marking it seen and landing on Contracts", async () => {
for (const nexts of [0, 1, 2]) {
const { api, state } = newCompany();
const dialog = await start(api);
for (let i = 0; i < nexts; i++) {
await userEvent.click(within(dialog).getByRole("button", { name: "Next" }));
}
await userEvent.click(within(dialog).getByRole("button", { name: "Skip" }));
await waitFor(() => expect(screen.queryByRole("dialog")).not.toBeInTheDocument());
expect(state().welcomeSeen).toBe(true);
expect(await screen.findByLabelText("Intro")).toBeInTheDocument();
cleanup();
}
});
it("doesn't come back after a reload once seen", async () => {
const { api } = newCompany();
const dialog = await start(api);
await userEvent.click(within(dialog).getByRole("button", { name: "Skip" }));
await waitFor(() => expect(screen.queryByRole("dialog")).not.toBeInTheDocument());
cleanup();
renderApp(api, "/contracts");
expect(await screen.findByLabelText("Intro")).toBeInTheDocument();
expect(screen.queryByRole("dialog", { name: "Welcome to Deadhead" })).not.toBeInTheDocument();
});
it("slides cards in, but not with reduced motion on", async () => {
const { api } = newCompany();
await start(api);
expect(screen.getByTestId("welcome-card")).toHaveClass("animate-slide");
cleanup();
usePreferences.getState().set({ reducedMotion: true });
const again = newCompany();
await start(again.api);
expect(screen.getByTestId("welcome-card")).not.toHaveClass("animate-slide");
usePreferences.getState().set({ reducedMotion: null });
});
it("keeps focus inside the pop-up until it closes", async () => {
const { api } = newCompany();
const dialog = await start(api);
// Focus starts on the main button.
expect(within(dialog).getByRole("button", { name: "Next" })).toHaveFocus();
for (let i = 0; i < 5; i++) {
await userEvent.tab();
expect(dialog).toContainElement(document.activeElement as HTMLElement);
}
await userEvent.tab({ shift: true });
expect(dialog).toContainElement(document.activeElement as HTMLElement);
});
});