Skip to content
This repository has been archived by the owner on Jul 24, 2023. It is now read-only.

Commit

Permalink
Merge pull request #187 from ictsc/feature/add_scoring_index_page_uni…
Browse files Browse the repository at this point in the history
…t_test

add: ScoringIndexPage の 単体 テストを追加
  • Loading branch information
K-shir0 committed Jul 9, 2023
2 parents e0b8e93 + ed17a18 commit 2a1bed8
Show file tree
Hide file tree
Showing 3 changed files with 316 additions and 4 deletions.
311 changes: 311 additions & 0 deletions __test__/pages/scoring/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
import "@testing-library/jest-dom";

import { act, render, screen } from "@testing-library/react";
import { Mock, vi } from "vitest";

import useAuth from "@/hooks/auth";
import useProblems from "@/hooks/problems";
import Index from "@/pages/scoring";
import { testProblem } from "@/types/Problem";
import { testAdminUser, testUser } from "@/types/User";

vi.mock("next/router", () => require("next-router-mock"));
vi.mock("@/hooks/auth");
vi.mock("@/hooks/problems");
vi.mock("@/components/Navbar", () => ({
__esModule: true,
default: () => <div data-testid="navbar" />,
}));
vi.mock("@/components/LoadingPage", () => ({
__esModule: true,
default: () => <div data-testid="loading" />,
}));
beforeEach(() => {
// toHaveBeenCalledTimes がテストごとにリセットされるようにする
vi.clearAllMocks();
});

describe("Scoring", () => {
test("未ログインで、NotFound が表示される", async () => {
// setup
(useAuth as Mock).mockReturnValue({
user: null,
});
(useProblems as Mock).mockReturnValue({
problems: [],
isLoading: false,
});
render(<Index />);

// when
expect(
screen.queryByText("This page could not be found.")
).toBeInTheDocument();

// then
expect(screen.queryByTestId("navbar")).not.toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("ログイン済みで問題が取得できない場合、NotFound が表示される", async () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [],
isLoading: false,
});
render(<Index />);

// when
expect(
screen.queryByText("This page could not be found.")
).toBeInTheDocument();

// then
expect(screen.queryByTestId("navbar")).not.toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("参加者でアクセスした場合、NotFound が表示される", async () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testUser,
});
(useProblems as Mock).mockReturnValue({
problems: [],
isLoading: false,
});
render(<Index />);

// when
expect(
screen.queryByText("This page could not be found.")
).toBeInTheDocument();

// then
expect(screen.queryByTestId("navbar")).not.toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("問題を取得中の場合、ローディング画面が表示される", async () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [],
isLoading: true,
});
render(<Index />);

// when
expect(screen.queryByTestId("loading")).toBeInTheDocument();

// then
expect(screen.queryByTestId("navbar")).toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("問題一覧が表示される", async () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [testProblem],
isLoading: false,
});
render(<Index />);
const tds = screen.queryAllByRole("cell");

// when
expect(screen.queryByText("採点")).toBeInTheDocument();
expect(tds[1]).toHaveTextContent("/-/-");
expect(tds[2]).toHaveTextContent("id");
expect(tds[3]).toHaveTextContent("XYZ");
expect(tds[4]).toHaveTextContent("テスト問題タイトル");
expect(tds[5]).toHaveTextContent("--- title: テスト --- #...");
expect(tds[6]).toHaveTextContent("100");
expect(tds[7]).toHaveTextContent("150");
expect(tds[8]).toHaveTextContent("");
expect(tds[9]).toHaveTextContent("自分");

// then
expect(screen.queryByTestId("navbar")).toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("15分未満の問題がある場合、未採点の ~15分 に表示される", () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [{ ...testProblem, unchecked: 1 }],
isLoading: false,
});
render(<Index />);
const tds = screen.queryAllByRole("cell");

// when
expect(tds[1]).toHaveTextContent("1/-/-");

// then
expect(screen.queryByTestId("navbar")).toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("15分以上かつ19分以下の問題がある場合、未採点の 15~19分 に表示される", () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [{ ...testProblem, unchecked_near_overdue: 1 }],
isLoading: false,
});
render(<Index />);
const tds = screen.queryAllByRole("cell");

// when
expect(tds[1]).toHaveTextContent("/1/-");

// then
expect(screen.queryByTestId("navbar")).toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("20分以上の問題がある場合、未採点の 20分~ に表示される", () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [{ ...testProblem, unchecked_overdue: 1 }],
isLoading: false,
});
render(<Index />);
const tds = screen.queryAllByRole("cell");

// when
expect(tds[1]).toHaveTextContent("/-/1");

// then
expect(screen.queryByTestId("navbar")).toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("20文字未満の問題文は、20文字目以降が省略されない", () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [{ ...testProblem, body: "a".repeat(19) }],
isLoading: false,
});
render(<Index />);
const tds = screen.queryAllByRole("cell");

// when
expect(tds[5]).toHaveTextContent("a".repeat(19));
});

test("20文字以上の問題文は、20文字目以降が省略される", () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [{ ...testProblem, body: "a".repeat(20) }],
isLoading: false,
});
render(<Index />);
const tds = screen.queryAllByRole("cell");

// when
// aaa... となる
expect(tds[5]).toHaveTextContent(`${"a".repeat(20)}...`);

// then
expect(screen.queryByTestId("navbar")).toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("問題文が Null の場合、空文字が表示される", () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [{ ...testProblem, body: null }],
isLoading: false,
});
render(<Index />);
const tds = screen.queryAllByRole("cell");

// when
// aaa... となる
expect(tds[5]).toHaveTextContent("");

// then
expect(screen.queryByTestId("navbar")).toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("問題作成者id が自分でない場合空文字が表示される", () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [{ ...testProblem, author_id: "other" }],
isLoading: false,
});
render(<Index />);
const tds = screen.queryAllByRole("cell");

// when
expect(tds[9]).toHaveTextContent("");

// then
expect(screen.queryByTestId("navbar")).toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(2);
});

test("問題をクリックした場合、問題文が表示される", async () => {
// setup
(useAuth as Mock).mockReturnValue({
user: testAdminUser,
});
(useProblems as Mock).mockReturnValue({
problems: [{ ...testProblem, author_id: "other" }],
isLoading: false,
});
render(<Index />);
await act(async () => {
await screen.queryAllByRole("row")[1].click();
});

// when
expect(screen.queryByText("採点する")).toBeInTheDocument();

// then
expect(screen.queryByTestId("navbar")).toBeInTheDocument();
expect(useAuth).toHaveBeenCalledTimes(2);
expect(useProblems).toHaveBeenCalledTimes(4);
});
});
5 changes: 3 additions & 2 deletions pages/scoring/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import ICTSCCard from "@/components/Card";
import LoadingPage from "@/components/LoadingPage";
import MarkdownPreview from "@/components/MarkdownPreview";
import useAuth from "@/hooks/auth";
import { useProblem, useProblems } from "@/hooks/problem";
import useProblem from "@/hooks/problem";
import useProblems from "@/hooks/problems";
import BaseLayout from "@/layouts/BaseLayout";

function Index() {
Expand All @@ -31,7 +32,7 @@ function Index() {
);
}

if (!isFullAccess || isReadOnly || problems === null) {
if (!isFullAccess || isReadOnly || problems.length === 0) {
return <Error statusCode={404} />;
}

Expand Down
4 changes: 2 additions & 2 deletions types/Problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ export const testProblem: Problem = {
title: "テスト問題タイトル",
body: "---\ntitle: テスト\n---\n# テスト本文",
point: 100,
solved_criterion: 100,
solved_criterion: 150,
previous_problem_id: null,
author_id: "author_id",
author_id: "1",
unchecked: null,
unchecked_near_overdue: null,
unchecked_overdue: null,
Expand Down

0 comments on commit 2a1bed8

Please sign in to comment.