From 7f29d334f26229753e68d20a5aaab33c39de9f06 Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Sun, 1 Mar 2026 12:21:21 +0900
Subject: feat(frontend): show submission history on play screen

Replace the placeholder submission status section with a full submission
history table using the existing getGamePlaySubmissions API. Extract
shared DataTable, DataTableCell, and formatUnixTimestamp from
RankingTable into a reusable Gaming/DataTable component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 .../GolfPlayApps/GolfPlayAppGaming.test.tsx        | 107 +++++++++++++++++++++
 1 file changed, 107 insertions(+)
 create mode 100644 frontend/app/components/GolfPlayApps/GolfPlayAppGaming.test.tsx

(limited to 'frontend/app/components/GolfPlayApps/GolfPlayAppGaming.test.tsx')

diff --git a/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.test.tsx b/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.test.tsx
new file mode 100644
index 0000000..2d51d66
--- /dev/null
+++ b/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.test.tsx
@@ -0,0 +1,107 @@
+/**
+ * @vitest-environment jsdom
+ */
+import { cleanup, render, screen } from "@testing-library/react";
+import { createStore, Provider } from "jotai";
+import { afterEach, describe, expect, test } from "vitest";
+import {
+	setCurrentTimestampAtom,
+	setDurationSecondsAtom,
+	setGameStartedAtAtom,
+	setLatestGameStateAtom,
+} from "../../states/play";
+import GolfPlayAppGaming from "./GolfPlayAppGaming";
+
+afterEach(() => {
+	cleanup();
+});
+
+function createTestStore() {
+	const store = createStore();
+	const now = Math.floor(Date.now() / 1000);
+	store.set(setCurrentTimestampAtom);
+	store.set(setDurationSecondsAtom, 600);
+	store.set(setGameStartedAtAtom, now - 60);
+	store.set(setLatestGameStateAtom, {
+		status: "none",
+		code: "",
+		score: null,
+		best_score_submitted_at: null,
+	});
+	return store;
+}
+
+const defaultProps = {
+	gameDisplayName: "Test Game",
+	playerProfile: {
+		id: 1,
+		displayName: "Test Player",
+		iconPath: null,
+	},
+	problemTitle: "Test Problem",
+	problemDescription: "Description",
+	problemLanguage: "php" as const,
+	sampleCode: "<?php echo 1;",
+	initialCode: "",
+	onCodeChange: () => {},
+	onCodeSubmit: () => {},
+	isFinished: false,
+};
+
+describe("GolfPlayAppGaming submission history", () => {
+	test("shows placeholder row when no submissions", () => {
+		const store = createTestStore();
+		render(
+			<Provider store={store}>
+				<GolfPlayAppGaming {...defaultProps} submissions={[]} />
+			</Provider>,
+		);
+		expect(screen.getByText("提出待ち")).toBeDefined();
+		const dashes = screen.getAllByText("-");
+		expect(dashes.length).toBe(3);
+	});
+
+	test("renders submission rows with status and code size", () => {
+		const store = createTestStore();
+		const submissions = [
+			{
+				submission_id: 1,
+				game_id: 1,
+				status: "success" as const,
+				code: "<?php echo 1;",
+				code_size: 7,
+				created_at: 1740000000,
+			},
+			{
+				submission_id: 2,
+				game_id: 1,
+				status: "wrong_answer" as const,
+				code: "<?php echo 2;",
+				code_size: 10,
+				created_at: 1740000060,
+			},
+		];
+		render(
+			<Provider store={store}>
+				<GolfPlayAppGaming {...defaultProps} submissions={submissions} />
+			</Provider>,
+		);
+		expect(screen.getByText("成功")).toBeDefined();
+		expect(screen.getByText("テスト失敗")).toBeDefined();
+		expect(screen.getByText("7")).toBeDefined();
+		expect(screen.getByText("10")).toBeDefined();
+	});
+
+	test("renders table headers", () => {
+		const store = createTestStore();
+		render(
+			<Provider store={store}>
+				<GolfPlayAppGaming {...defaultProps} submissions={[]} />
+			</Provider>,
+		);
+		expect(screen.getByText("ステータス")).toBeDefined();
+		expect(screen.getByText("スコア")).toBeDefined();
+		expect(screen.getByText("提出時刻")).toBeDefined();
+		expect(screen.getByText("コード")).toBeDefined();
+	});
+});
-- 
cgit v1.3.1

