- Replace .border-l-4.border-gray-600 checks with .catcher-pill - Update isExpanded prop references to isSelected - Adjust expanded view tests for new side-by-side layout - matchup-card-blue = runner full card - matchup-card = catcher full card - Fix deselection test to check isSelected prop (Transition keeps DOM during animation) All 15 RunnersOnBase tests passing All 16 RunnerCard tests passing
353 lines
11 KiB
TypeScript
353 lines
11 KiB
TypeScript
import { describe, it, expect, beforeEach } from "vitest";
|
|
import { mount } from "@vue/test-utils";
|
|
import { createPinia, setActivePinia } from "pinia";
|
|
import RunnerCard from "~/components/Game/RunnerCard.vue";
|
|
import { useGameStore } from "~/store/game";
|
|
import type { LineupPlayerState } from "~/types/game";
|
|
|
|
describe("RunnerCard", () => {
|
|
let pinia: ReturnType<typeof createPinia>;
|
|
|
|
beforeEach(() => {
|
|
pinia = createPinia();
|
|
setActivePinia(pinia);
|
|
});
|
|
|
|
const mockRunner: LineupPlayerState = {
|
|
lineup_id: 1,
|
|
batting_order: 1,
|
|
position: "LF",
|
|
card_id: 101,
|
|
};
|
|
|
|
describe("empty base state", () => {
|
|
it("renders empty state when no runner provided", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: null,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.find(".runner-pill.empty").exists()).toBe(true);
|
|
expect(wrapper.text()).toContain("Empty");
|
|
});
|
|
|
|
it("displays base label for empty base", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "2B",
|
|
runner: null,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.text()).toContain("2B");
|
|
});
|
|
|
|
it("shows hollow circle for empty base", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "3B",
|
|
runner: null,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
const circle = wrapper.find(".rounded-full.border-dashed");
|
|
expect(circle.exists()).toBe(true);
|
|
});
|
|
|
|
it("does not emit click event for empty base", async () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: null,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
await wrapper.trigger("click");
|
|
expect(wrapper.emitted("click")).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("occupied base state", () => {
|
|
beforeEach(() => {
|
|
const gameStore = useGameStore();
|
|
// Set game state first so updateLineup knows the team ID
|
|
gameStore.setGameState({
|
|
id: 1,
|
|
home_team_id: 1,
|
|
away_team_id: 2,
|
|
status: "active",
|
|
inning: 1,
|
|
half: "top",
|
|
outs: 0,
|
|
home_score: 0,
|
|
away_score: 0,
|
|
home_team_abbrev: "NYY",
|
|
away_team_abbrev: "BOS",
|
|
home_team_dice_color: "3b82f6",
|
|
current_batter: null,
|
|
current_pitcher: null,
|
|
on_first: null,
|
|
on_second: null,
|
|
on_third: null,
|
|
decision_phase: "idle",
|
|
play_count: 0,
|
|
});
|
|
|
|
gameStore.updateLineup(1, [
|
|
{
|
|
id: 1,
|
|
lineup_id: 1,
|
|
team_id: 1,
|
|
batting_order: 1,
|
|
position: "LF",
|
|
is_active: true,
|
|
player: {
|
|
id: 101,
|
|
name: "Mike Trout",
|
|
image: "https://example.com/trout.jpg",
|
|
headshot: "https://example.com/trout-headshot.jpg",
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("renders occupied state when runner provided", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: mockRunner,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.find(".runner-pill.occupied").exists()).toBe(true);
|
|
expect(wrapper.find(".runner-pill.empty").exists()).toBe(false);
|
|
});
|
|
|
|
it("displays runner name", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: mockRunner,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.text()).toContain("Mike Trout");
|
|
});
|
|
|
|
it("displays base label", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "2B",
|
|
runner: mockRunner,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.text()).toContain("2B");
|
|
});
|
|
|
|
it("displays player headshot when available", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: mockRunner,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
const img = wrapper.find('img[alt="Mike Trout"]');
|
|
expect(img.exists()).toBe(true);
|
|
expect(img.attributes("src")).toBe(
|
|
"https://example.com/trout-headshot.jpg",
|
|
);
|
|
});
|
|
|
|
it("applies team color to border", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: mockRunner,
|
|
isSelected: false,
|
|
teamColor: "#ff0000",
|
|
},
|
|
});
|
|
|
|
const avatar = wrapper.find(".rounded-full.border-2");
|
|
expect(avatar.attributes("style")).toContain(
|
|
"border-color: #ff0000",
|
|
);
|
|
});
|
|
|
|
it("emits click event when clicked", async () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: mockRunner,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
await wrapper.trigger("click");
|
|
expect(wrapper.emitted("click")).toHaveLength(1);
|
|
});
|
|
});
|
|
|
|
describe("selected state", () => {
|
|
beforeEach(() => {
|
|
const gameStore = useGameStore();
|
|
gameStore.setGameState({
|
|
id: 1,
|
|
home_team_id: 1,
|
|
away_team_id: 2,
|
|
status: "active",
|
|
inning: 1,
|
|
half: "top",
|
|
outs: 0,
|
|
home_score: 0,
|
|
away_score: 0,
|
|
home_team_abbrev: "NYY",
|
|
away_team_abbrev: "BOS",
|
|
home_team_dice_color: "3b82f6",
|
|
current_batter: null,
|
|
current_pitcher: null,
|
|
on_first: null,
|
|
on_second: null,
|
|
on_third: null,
|
|
decision_phase: "idle",
|
|
play_count: 0,
|
|
});
|
|
gameStore.updateLineup(1, [
|
|
{
|
|
id: 1,
|
|
lineup_id: 1,
|
|
team_id: 1,
|
|
batting_order: 1,
|
|
position: "LF",
|
|
is_active: true,
|
|
player: {
|
|
id: 101,
|
|
name: "Mike Trout",
|
|
image: "https://example.com/trout-card.jpg",
|
|
headshot: "https://example.com/trout-headshot.jpg",
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("does not apply selected class when not selected", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: mockRunner,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.find(".runner-pill.selected").exists()).toBe(false);
|
|
});
|
|
|
|
it("applies selected class when isSelected is true", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: mockRunner,
|
|
isSelected: true,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.find(".runner-pill.selected").exists()).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("player name handling", () => {
|
|
it('shows "Unknown Runner" when player not found in store', () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: mockRunner,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.text()).toContain("Unknown Runner");
|
|
});
|
|
});
|
|
|
|
describe("base label variations", () => {
|
|
it("displays 1B correctly", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "1B",
|
|
runner: null,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.text()).toContain("1B");
|
|
});
|
|
|
|
it("displays 2B correctly", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "2B",
|
|
runner: null,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.text()).toContain("2B");
|
|
});
|
|
|
|
it("displays 3B correctly", () => {
|
|
const wrapper = mount(RunnerCard, {
|
|
global: { plugins: [pinia] },
|
|
props: {
|
|
base: "3B",
|
|
runner: null,
|
|
isSelected: false,
|
|
teamColor: "#3b82f6",
|
|
},
|
|
});
|
|
|
|
expect(wrapper.text()).toContain("3B");
|
|
});
|
|
});
|
|
});
|