CLAUDE: Add comprehensive tests for RunnersOnBase and RunnerCard components
- Test empty/occupied/expanded states - Test player name handling and initials - Test runner selection and catcher card expansion - Test team color integration - All 40 tests passing
This commit is contained in:
parent
f0979ccc9e
commit
078516f682
606
frontend-sba/tests/unit/components/Game/RunnerCard.spec.ts
Normal file
606
frontend-sba/tests/unit/components/Game/RunnerCard.spec.ts
Normal file
@ -0,0 +1,606 @@
|
||||
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,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".runner-card.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,
|
||||
isExpanded: 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,
|
||||
isExpanded: 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,
|
||||
isExpanded: 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,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".runner-card.occupied").exists()).toBe(true);
|
||||
expect(wrapper.find(".runner-card.empty").exists()).toBe(false);
|
||||
});
|
||||
|
||||
it("displays runner name", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: 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,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("2B");
|
||||
});
|
||||
|
||||
it("displays runner number based on lineup_id", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("#01");
|
||||
});
|
||||
|
||||
it("displays player headshot when available", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: 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,
|
||||
isExpanded: false,
|
||||
teamColor: "#ff0000",
|
||||
},
|
||||
});
|
||||
|
||||
const avatar = wrapper.find(".rounded-full.border-2");
|
||||
expect(avatar.attributes("style")).toContain(
|
||||
"border-color: #ff0000",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows chevron icon when occupied", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
const chevron = wrapper.find("svg");
|
||||
expect(chevron.exists()).toBe(true);
|
||||
});
|
||||
|
||||
it("emits click event when clicked", async () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
await wrapper.trigger("click");
|
||||
expect(wrapper.emitted("click")).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("expanded 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,
|
||||
on_base_code: 0,
|
||||
home_team: {
|
||||
id: 1,
|
||||
name: "Home Team",
|
||||
abbreviation: "HOME",
|
||||
dice_color: "3b82f6",
|
||||
},
|
||||
away_team: {
|
||||
id: 2,
|
||||
name: "Away Team",
|
||||
abbreviation: "AWAY",
|
||||
dice_color: "10b981",
|
||||
},
|
||||
});
|
||||
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 show expanded view when collapsed", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".runner-expanded").exists()).toBe(false);
|
||||
});
|
||||
|
||||
it("shows expanded view when isExpanded is true", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: true,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".runner-expanded").exists()).toBe(true);
|
||||
});
|
||||
|
||||
it("displays full player card image when expanded", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: true,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
const cardImg = wrapper.find(
|
||||
'.runner-expanded img[alt="Mike Trout card"]',
|
||||
);
|
||||
expect(cardImg.exists()).toBe(true);
|
||||
expect(cardImg.attributes("src")).toBe(
|
||||
"https://example.com/trout-card.jpg",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows player initials when no card image available", () => {
|
||||
const gameStore = useGameStore();
|
||||
gameStore.setGameState({
|
||||
id: 1,
|
||||
home_team_id: 1,
|
||||
away_team_id: 2,
|
||||
status: "active",
|
||||
inning: 1,
|
||||
half: "top",
|
||||
outs: 0,
|
||||
on_base_code: 0,
|
||||
home_team: {
|
||||
id: 1,
|
||||
name: "Home Team",
|
||||
abbreviation: "HOME",
|
||||
dice_color: "3b82f6",
|
||||
},
|
||||
away_team: {
|
||||
id: 2,
|
||||
name: "Away Team",
|
||||
abbreviation: "AWAY",
|
||||
dice_color: "10b981",
|
||||
},
|
||||
});
|
||||
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: "",
|
||||
headshot: "",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: true,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("MT");
|
||||
});
|
||||
|
||||
it('displays "RUNNER" label in expanded header', () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "2B",
|
||||
runner: mockRunner,
|
||||
isExpanded: true,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".runner-expanded").text()).toContain("RUNNER");
|
||||
});
|
||||
|
||||
it("applies expanded class when isExpanded is true", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: true,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".runner-card.expanded").exists()).toBe(true);
|
||||
});
|
||||
|
||||
it("rotates chevron when expanded", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: true,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
const chevron = wrapper.find("svg");
|
||||
expect(chevron.classes()).toContain("rotate-90");
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("Unknown Runner");
|
||||
});
|
||||
|
||||
it("extracts initials from first and last name", () => {
|
||||
const gameStore = useGameStore();
|
||||
gameStore.setGameState({
|
||||
id: 1,
|
||||
home_team_id: 1,
|
||||
away_team_id: 2,
|
||||
status: "active",
|
||||
inning: 1,
|
||||
half: "top",
|
||||
outs: 0,
|
||||
on_base_code: 0,
|
||||
home_team: {
|
||||
id: 1,
|
||||
name: "Home Team",
|
||||
abbreviation: "HOME",
|
||||
dice_color: "3b82f6",
|
||||
},
|
||||
away_team: {
|
||||
id: 2,
|
||||
name: "Away Team",
|
||||
abbreviation: "AWAY",
|
||||
dice_color: "10b981",
|
||||
},
|
||||
});
|
||||
gameStore.updateLineup(1, [
|
||||
{
|
||||
id: 1,
|
||||
lineup_id: 1,
|
||||
team_id: 1,
|
||||
batting_order: 1,
|
||||
position: "LF",
|
||||
is_active: true,
|
||||
player: {
|
||||
id: 101,
|
||||
name: "Aaron Donald Judge",
|
||||
image: "",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: true,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
// Should use first and last name (A + J)
|
||||
expect(wrapper.text()).toContain("AJ");
|
||||
});
|
||||
|
||||
it("handles single-word names", () => {
|
||||
const gameStore = useGameStore();
|
||||
gameStore.setGameState({
|
||||
id: 1,
|
||||
home_team_id: 1,
|
||||
away_team_id: 2,
|
||||
status: "active",
|
||||
inning: 1,
|
||||
half: "top",
|
||||
outs: 0,
|
||||
on_base_code: 0,
|
||||
home_team: {
|
||||
id: 1,
|
||||
name: "Home Team",
|
||||
abbreviation: "HOME",
|
||||
dice_color: "3b82f6",
|
||||
},
|
||||
away_team: {
|
||||
id: 2,
|
||||
name: "Away Team",
|
||||
abbreviation: "AWAY",
|
||||
dice_color: "10b981",
|
||||
},
|
||||
});
|
||||
gameStore.updateLineup(1, [
|
||||
{
|
||||
id: 1,
|
||||
lineup_id: 1,
|
||||
team_id: 1,
|
||||
batting_order: 1,
|
||||
position: "LF",
|
||||
is_active: true,
|
||||
player: {
|
||||
id: 101,
|
||||
name: "Pele",
|
||||
image: "",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: mockRunner,
|
||||
isExpanded: true,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("PE");
|
||||
});
|
||||
});
|
||||
|
||||
describe("base label variations", () => {
|
||||
it("displays 1B correctly", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "1B",
|
||||
runner: null,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("1B");
|
||||
});
|
||||
|
||||
it("displays 2B correctly", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "2B",
|
||||
runner: null,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("2B");
|
||||
});
|
||||
|
||||
it("displays 3B correctly", () => {
|
||||
const wrapper = mount(RunnerCard, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
base: "3B",
|
||||
runner: null,
|
||||
isExpanded: false,
|
||||
teamColor: "#3b82f6",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("3B");
|
||||
});
|
||||
});
|
||||
});
|
||||
577
frontend-sba/tests/unit/components/Game/RunnersOnBase.spec.ts
Normal file
577
frontend-sba/tests/unit/components/Game/RunnersOnBase.spec.ts
Normal file
@ -0,0 +1,577 @@
|
||||
import { describe, it, expect, beforeEach, vi } from "vitest";
|
||||
import { mount } from "@vue/test-utils";
|
||||
import { createPinia, setActivePinia } from "pinia";
|
||||
import RunnersOnBase from "~/components/Game/RunnersOnBase.vue";
|
||||
import RunnerCard from "~/components/Game/RunnerCard.vue";
|
||||
import { useGameStore } from "~/store/game";
|
||||
import type { LineupPlayerState, Lineup } from "~/types/game";
|
||||
|
||||
describe("RunnersOnBase", () => {
|
||||
let pinia: ReturnType<typeof createPinia>;
|
||||
|
||||
beforeEach(() => {
|
||||
pinia = createPinia();
|
||||
setActivePinia(pinia);
|
||||
});
|
||||
|
||||
const mockRunnerFirst: LineupPlayerState = {
|
||||
lineup_id: 1,
|
||||
batting_order: 1,
|
||||
position: "LF",
|
||||
card_id: 101,
|
||||
};
|
||||
|
||||
const mockRunnerSecond: LineupPlayerState = {
|
||||
lineup_id: 2,
|
||||
batting_order: 2,
|
||||
position: "CF",
|
||||
card_id: 102,
|
||||
};
|
||||
|
||||
const mockRunnerThird: LineupPlayerState = {
|
||||
lineup_id: 3,
|
||||
batting_order: 3,
|
||||
position: "RF",
|
||||
card_id: 103,
|
||||
};
|
||||
|
||||
const mockCatcher: Lineup = {
|
||||
id: 1,
|
||||
lineup_id: 4,
|
||||
team_id: 1,
|
||||
batting_order: 4,
|
||||
position: "C",
|
||||
is_active: true,
|
||||
player: {
|
||||
id: 104,
|
||||
name: "Buster Posey",
|
||||
image: "https://example.com/posey.jpg",
|
||||
headshot: "https://example.com/posey-headshot.jpg",
|
||||
},
|
||||
};
|
||||
|
||||
const mockFieldingLineup: Lineup[] = [mockCatcher];
|
||||
|
||||
describe("component visibility", () => {
|
||||
it("does not render when no runners on base", () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: { first: null, second: null, third: null },
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".runners-on-base-container").exists()).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it("renders when at least one runner on base", () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: null,
|
||||
second: mockRunnerSecond,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".runners-on-base-container").exists()).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it("renders when bases loaded", () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: mockRunnerSecond,
|
||||
third: mockRunnerThird,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".runners-on-base-container").exists()).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("runner cards", () => {
|
||||
it("renders three RunnerCard components", () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
const runnerCards = wrapper.findAllComponents(RunnerCard);
|
||||
expect(runnerCards).toHaveLength(3);
|
||||
});
|
||||
|
||||
it("passes correct base labels to RunnerCard components", async () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
const runnerCards = wrapper.findAllComponents(RunnerCard);
|
||||
expect(runnerCards.length).toBeGreaterThanOrEqual(3);
|
||||
expect(runnerCards[0].props("base")).toBe("1B");
|
||||
expect(runnerCards[1].props("base")).toBe("2B");
|
||||
expect(runnerCards[2].props("base")).toBe("3B");
|
||||
});
|
||||
|
||||
it("passes runner data to RunnerCard components", () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: mockRunnerSecond,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
const runnerCards = wrapper.findAllComponents(RunnerCard);
|
||||
expect(runnerCards[0].props("runner")).toEqual(mockRunnerFirst);
|
||||
expect(runnerCards[1].props("runner")).toEqual(mockRunnerSecond);
|
||||
expect(runnerCards[2].props("runner")).toBeNull();
|
||||
});
|
||||
|
||||
it("passes team color to RunnerCard components", () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#ff0000",
|
||||
fieldingTeamColor: "#00ff00",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
const runnerCards = wrapper.findAllComponents(RunnerCard);
|
||||
runnerCards.forEach((card) => {
|
||||
expect(card.props("teamColor")).toBe("#ff0000");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("catcher display", () => {
|
||||
it("shows collapsed catcher card by default", () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
// Collapsed state shows border-l-4, expanded state shows .matchup-card
|
||||
expect(wrapper.find(".border-l-4.border-gray-600").exists()).toBe(
|
||||
true,
|
||||
);
|
||||
expect(wrapper.find(".matchup-card").exists()).toBe(false);
|
||||
});
|
||||
|
||||
it("displays catcher name", () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("Buster Posey");
|
||||
});
|
||||
|
||||
it('shows "Unknown Catcher" when no catcher in lineup', () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: [],
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain("Unknown Catcher");
|
||||
});
|
||||
});
|
||||
|
||||
describe("runner selection", () => {
|
||||
it("expands catcher card when runner is selected", async () => {
|
||||
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.jpg",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
const runnerCards = wrapper.findAllComponents(RunnerCard);
|
||||
await runnerCards[0].trigger("click");
|
||||
|
||||
// When runner selected, collapsed state hidden and expanded state shown
|
||||
expect(wrapper.find(".border-l-4.border-gray-600").exists()).toBe(
|
||||
false,
|
||||
);
|
||||
expect(wrapper.find(".matchup-card").exists()).toBe(true);
|
||||
});
|
||||
|
||||
it("collapses catcher card when runner is deselected", async () => {
|
||||
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.jpg",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
const runnerCards = wrapper.findAllComponents(RunnerCard);
|
||||
|
||||
// Click to expand
|
||||
await runnerCards[0].trigger("click");
|
||||
expect(wrapper.find(".matchup-card").exists()).toBe(true);
|
||||
|
||||
// Click again to collapse
|
||||
await runnerCards[0].trigger("click");
|
||||
expect(wrapper.find(".border-l-4.border-gray-600").exists()).toBe(
|
||||
true,
|
||||
);
|
||||
expect(wrapper.find(".matchup-card").exists()).toBe(false);
|
||||
});
|
||||
|
||||
it("switches selection when clicking different runner", async () => {
|
||||
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.jpg",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
lineup_id: 2,
|
||||
team_id: 1,
|
||||
batting_order: 2,
|
||||
position: "CF",
|
||||
is_active: true,
|
||||
player: {
|
||||
id: 102,
|
||||
name: "Aaron Judge",
|
||||
image: "https://example.com/judge.jpg",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: mockRunnerSecond,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
const runnerCards = wrapper.findAllComponents(RunnerCard);
|
||||
|
||||
// Select first runner
|
||||
await runnerCards[0].trigger("click");
|
||||
expect(runnerCards[0].props("isExpanded")).toBe(true);
|
||||
expect(runnerCards[1].props("isExpanded")).toBe(false);
|
||||
|
||||
// Select second runner
|
||||
await runnerCards[1].trigger("click");
|
||||
expect(runnerCards[0].props("isExpanded")).toBe(false);
|
||||
expect(runnerCards[1].props("isExpanded")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("team information", () => {
|
||||
it("displays team abbreviations when provided", async () => {
|
||||
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.jpg",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
battingTeamColor: "#3b82f6",
|
||||
fieldingTeamColor: "#10b981",
|
||||
battingTeamAbbrev: "BOS",
|
||||
fieldingTeamAbbrev: "NYY",
|
||||
},
|
||||
});
|
||||
|
||||
// Click runner to expand and show team abbreviation
|
||||
const runnerCards = wrapper.findAllComponents(RunnerCard);
|
||||
await runnerCards[0].trigger("click");
|
||||
|
||||
expect(wrapper.text()).toContain("NYY");
|
||||
});
|
||||
|
||||
it("uses default colors when not provided", () => {
|
||||
const wrapper = mount(RunnersOnBase, {
|
||||
global: { plugins: [pinia] },
|
||||
props: {
|
||||
runners: {
|
||||
first: mockRunnerFirst,
|
||||
second: null,
|
||||
third: null,
|
||||
},
|
||||
fieldingLineup: mockFieldingLineup,
|
||||
},
|
||||
});
|
||||
|
||||
const runnerCards = wrapper.findAllComponents(RunnerCard);
|
||||
expect(runnerCards[0].props("teamColor")).toBe("#3b82f6");
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user