diff --git a/.github/nightly-logs/verification-coverage.log b/.github/nightly-logs/verification-coverage.log
index 83a0c227..defdc07b 100644
--- a/.github/nightly-logs/verification-coverage.log
+++ b/.github/nightly-logs/verification-coverage.log
@@ -18,3 +18,4 @@ Frontend-PWA/src/core/services/useSystemInfo.ts
Frontend-PWA/src/shared/ui/Toast.vue
Backend-Worker/src/controllers/WorkerHubController.ts
Backend-Worker/src/schemas.ts
+Frontend-PWA/src/features/roster/components/MemberCard.vue
diff --git a/Frontend-PWA/src/features/roster/components/components-tests/MemberCard.spec.ts b/Frontend-PWA/src/features/roster/components/components-tests/MemberCard.spec.ts
new file mode 100644
index 00000000..2d7de739
--- /dev/null
+++ b/Frontend-PWA/src/features/roster/components/components-tests/MemberCard.spec.ts
@@ -0,0 +1,160 @@
+/**
+ * @vitest-environment jsdom
+ */
+import { describe, it, expect, vi } from "vitest";
+import { mount } from "@vue/test-utils";
+import MemberCard from "../MemberCard.vue";
+import type { LeaderboardMember } from "@core/types";
+
+// Mock Layer 1 services via deep imports to avoid Barrel side effects (ADR Section II)
+vi.mock("../../../../core/services/useBenchmarking", () => ({
+ useBenchmarking: () => ({
+ getSafeBenchmark: vi.fn((type, metric, value) => `Benchmark: ${type} ${metric} ${value}`),
+ }),
+}));
+
+vi.mock("../../../../core/utils/formatters", () => ({
+ formatRole: vi.fn((role) => ({
+ label: `Formatted ${role}`,
+ class: `role-${role}`,
+ })),
+ formatTimeAgo: vi.fn((date) => `Time ago: ${date}`),
+}));
+
+const mockMember: LeaderboardMember = {
+ id: "P12345",
+ n: "Test Player",
+ t: 7500,
+ performanceScore: 85,
+ performanceRawScore: 12345,
+ dt: 5,
+ d: {
+ role: "elder",
+ days: 100,
+ avg: 500,
+ seen: "2024-03-20T10:00:00Z",
+ rate: "95%",
+ wfame: 2500,
+ hist: "3000 24W01 | 1500 24W02",
+ },
+};
+
+describe("MemberCard.vue", () => {
+ const defaultProps = {
+ id: "P12345",
+ member: mockMember,
+ expanded: false,
+ selected: false,
+ selectionMode: false,
+ };
+
+ const mountMemberCard = (props = {}) => {
+ return mount(MemberCard, {
+ props: { ...defaultProps, ...props },
+ global: {
+ stubs: {
+ BaseCard: {
+ name: "BaseCard",
+ template: `
+
+ `,
+ props: ["id", "expanded", "selected", "selectionMode", "isTagged", "score"],
+ },
+ Icon: true,
+ MomentumPill: true,
+ StatisticItem: {
+ name: "StatisticItem",
+ template: '',
+ props: ["label", "value", "loading", "benchmarkType", "benchmarkMetric", "benchmarkRawValue"]
+ },
+ CardActions: {
+ name: "CardActions",
+ template: '',
+ props: ["id", "loading", "compact"]
+ },
+ // Stubbing async component directly in global.stubs
+ WarHistoryChart: {
+ name: "WarHistoryChart",
+ template: '',
+ props: ["history", "loading"]
+ }
+ },
+ directives: {
+ tooltip: vi.fn(),
+ },
+ },
+ });
+ };
+
+ it("renders member identity correctly", () => {
+ const wrapper = mountMemberCard();
+
+ expect(wrapper.find(".player-name").text()).toBe("Test Player");
+ expect(wrapper.find(".tenure").text()).toBe("100d");
+ expect(wrapper.find(".role").text()).toBe("Formatted elder");
+ expect(wrapper.find(".role").classes()).toContain("role-elder");
+ });
+
+ it("renders trophies and performance score", () => {
+ const wrapper = mountMemberCard();
+
+ expect(wrapper.find(".trophy-val").text()).toBe("7,500");
+ expect(wrapper.find(".stat-score").text()).toBe("85");
+ });
+
+ it("handles null trophies", () => {
+ const memberWithNullTrophies = { ...mockMember, t: null as any };
+ const wrapper = mountMemberCard({ member: memberWithNullTrophies });
+
+ expect(wrapper.find(".trophy-val").text()).toBe("0");
+ });
+
+ it("applies aria-label correctly for accessibility", () => {
+ const wrapper = mountMemberCard();
+ const baseCardStub = wrapper.find('[aria-label="Test Player, score 85, Formatted elder"]');
+
+ expect(baseCardStub.exists()).toBe(true);
+ });
+
+ it("renders expanded content when expanded is true", () => {
+ const wrapper = mountMemberCard({ expanded: true });
+
+ const statsGrid = wrapper.find(".stats-grid");
+ expect(statsGrid.exists()).toBe(true);
+ expect(statsGrid.attributes("aria-busy")).toBe("false");
+
+ expect(wrapper.find(".war-history-chart-mock").exists()).toBe(true);
+ expect(wrapper.find(".card-actions-stub").exists()).toBe(true);
+ });
+
+ it("shows refreshing state in expanded content", () => {
+ const wrapper = mountMemberCard({ expanded: true, appIsRefreshing: true });
+
+ expect(wrapper.find(".stats-grid").attributes("aria-busy")).toBe("true");
+ expect(wrapper.findComponent({ name: "WarHistoryChart" }).props("loading")).toBe(true);
+ expect(wrapper.findComponent({ name: "CardActions" }).props("loading")).toBe(true);
+ });
+
+ it("emits toggle event when BaseCard emits toggle", async () => {
+ const wrapper = mountMemberCard();
+ const baseCard = wrapper.findComponent({ name: "BaseCard" });
+
+ await baseCard.vm.$emit("toggle");
+ expect(wrapper.emitted("toggle")).toBeTruthy();
+ });
+
+ it("emits toggle-select event when BaseCard emits toggle-select", async () => {
+ const wrapper = mountMemberCard();
+ const baseCard = wrapper.findComponent({ name: "BaseCard" });
+
+ await baseCard.vm.$emit("toggle-select");
+ expect(wrapper.emitted("toggle-select")).toBeTruthy();
+ });
+});