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 #184 from ictsc/feature/add_problem_index_page_uni…
Browse files Browse the repository at this point in the history
…t_test

add: ProblemIndex の 単体 テストを追加
  • Loading branch information
K-shir0 authored Jul 8, 2023
2 parents 152077d + ee9ddf6 commit c362be2
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 27 deletions.
4 changes: 2 additions & 2 deletions __test__/hooks/problem.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe("useProblem", () => {
});

// when
renderHook(() => useProblem("test"));
renderHook(() => useProblem("XYZ"));

// then
expect(matter).toBeCalledWith(testProblem.body);
Expand Down Expand Up @@ -83,7 +83,7 @@ describe("useProblem", () => {
});

// when
const { result } = renderHook(() => useProblem("test"));
const { result } = renderHook(() => useProblem("XYZ"));

// then
expect(matter).toBeCalledWith("");
Expand Down
224 changes: 224 additions & 0 deletions __test__/pages/problems/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import "@testing-library/jest-dom";

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

import useAuth from "@/hooks/auth";
import useNotice from "@/hooks/notice";
import useProblems from "@/hooks/problems";
import Problems from "@/pages/problems";
import { testNotice } from "@/types/Notice";
import { testProblem } from "@/types/Problem";

vi.mock("recoil");
vi.mock("@/hooks/auth");
vi.mock("@/hooks/problems");
vi.mock("@/hooks/notice");
vi.mock("next/router", () => require("next-router-mock"));

beforeEach(() => {
// toHaveBeenCalledTimes がテストごとにリセットされるようにする
vi.clearAllMocks();
});
describe("Problems", () => {
test("画面が表示されることを確認する", async () => {
// setup
(useRecoilState as Mock).mockReturnValue([[], vi.fn()]);
(useAuth as Mock).mockReturnValue({
user: null,
});
(useProblems as Mock).mockReturnValue({
problems: [testProblem],
isLoading: false,
});
(useNotice as Mock).mockReturnValue({
notices: [testNotice],
isLoading: false,
});
render(<Problems />);

// verify
expect(screen.queryByText("テスト通知タイトル")).toBeInTheDocument();
expect(screen.queryByText("テスト通知本文")).toBeInTheDocument();
expect(screen.queryByText("XYZ")).toBeInTheDocument();
expect(screen.queryByText("テスト問題タイトル")).toBeInTheDocument();
expect(screen.queryByText("100/100pt")).toBeInTheDocument();
expect(useProblems).toHaveBeenCalledTimes(1);
expect(useNotice).toHaveBeenCalledTimes(1);
});

test("問題一覧とお知らせ一覧が取得中の場合、ローディング画面が表示されることを確認する", async () => {
// setup
(useRecoilState as Mock).mockReturnValue([[], vi.fn()]);
(useAuth as Mock).mockReturnValue({
user: null,
});
(useProblems as Mock).mockReturnValue({
problems: [],
isLoading: true,
});
(useNotice as Mock).mockReturnValue({
notices: [],
isLoading: true,
});
render(<Problems />);

// verify
expect(screen.queryByTestId("loading")).toBeInTheDocument();
expect(useProblems).toHaveBeenCalledTimes(1);
expect(useNotice).toHaveBeenCalledTimes(1);
});

test("問題一覧が取得中の場合、ローディング画面が表示されることを確認する", async () => {
// setup
(useRecoilState as Mock).mockReturnValue([[], vi.fn()]);
(useAuth as Mock).mockReturnValue({
user: null,
});
(useProblems as Mock).mockReturnValue({
problems: [],
isLoading: true,
});
(useNotice as Mock).mockReturnValue({
notices: [],
isLoading: false,
});
render(<Problems />);

// verify
expect(screen.queryByTestId("loading")).toBeInTheDocument();
expect(useProblems).toHaveBeenCalledTimes(1);
expect(useNotice).toHaveBeenCalledTimes(1);
});

test("お知らせ一覧が取得中の場合、ローディング画面が表示されることを確認する", async () => {
// setup
(useRecoilState as Mock).mockReturnValue([[], vi.fn()]);
(useAuth as Mock).mockReturnValue({
user: null,
});
(useProblems as Mock).mockReturnValue({
problems: [],
isLoading: false,
});
(useNotice as Mock).mockReturnValue({
notices: [],
isLoading: true,
});
render(<Problems />);

// verify
expect(screen.queryByTestId("loading")).toBeInTheDocument();
expect(useProblems).toHaveBeenCalledTimes(1);
expect(useNotice).toHaveBeenCalledTimes(1);
});

test("見えなくされている場合、お知らせが表示されないことを確認する", async () => {
// setup
(useRecoilState as Mock).mockReturnValue([[testNotice.source_id], vi.fn()]);
(useAuth as Mock).mockReturnValue({
user: null,
});
(useProblems as Mock).mockReturnValue({
problems: [testProblem],
isLoading: false,
});
(useNotice as Mock).mockReturnValue({
notices: [testNotice],
isLoading: false,
});
render(<Problems />);

// verify
expect(screen.queryByText("テスト通知タイトル")).not.toBeInTheDocument();
expect(screen.queryByText("テスト通知本文")).not.toBeInTheDocument();
expect(useProblems).toHaveBeenCalledTimes(1);
expect(useNotice).toHaveBeenCalledTimes(1);
});

test("お知らせを見えなくするボタンが動作することを確認する", async () => {
// setup
const onDismiss = vi.fn();
(useRecoilState as Mock).mockReturnValue([[], onDismiss]);
(useAuth as Mock).mockReturnValue({
user: null,
});
(useProblems as Mock).mockReturnValue({
problems: [testProblem],
isLoading: false,
});
(useNotice as Mock).mockReturnValue({
notices: [testNotice],
isLoading: false,
});
render(<Problems />);

// when
screen.getByRole("button").click();

// then
expect(onDismiss).toHaveBeenCalledWith([testNotice.source_id]);

// verify
expect(onDismiss).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(1);
expect(useNotice).toHaveBeenCalledTimes(1);
});

test("お知らせを見えなくする id がすでに存在している時、正しく配列にセットされる", async () => {
// setup
const onDismiss = vi.fn();
(useRecoilState as Mock).mockReturnValue([["TEST"], onDismiss]);
(useAuth as Mock).mockReturnValue({
user: null,
});
(useProblems as Mock).mockReturnValue({
problems: [testProblem],
isLoading: false,
});
(useNotice as Mock).mockReturnValue({
notices: [testNotice],
isLoading: false,
});
render(<Problems />);

// when
screen.getByRole("button").click();

// then
expect(onDismiss).toHaveBeenCalledWith(["TEST", testNotice.source_id]);

// verify
expect(onDismiss).toHaveBeenCalledTimes(1);
expect(useProblems).toHaveBeenCalledTimes(1);
expect(useNotice).toHaveBeenCalledTimes(1);
});

test("shortRule が正しく表示されることを確認する", async () => {
// setup
vi.mock("@/components/_const", () => ({
title: "title",
site: "site",
shortRule: "# ルール本文",
}));
(useRecoilState as Mock).mockReturnValue([[], vi.fn()]);
(useAuth as Mock).mockReturnValue({
user: null,
});
(useProblems as Mock).mockReturnValue({
problems: [testProblem],
isLoading: false,
});
(useNotice as Mock).mockReturnValue({
notices: [testNotice],
isLoading: false,
});
render(<Problems />);

// verify
expect(screen.queryByText("ルール本文")).toBeInTheDocument();
expect(useProblems).toHaveBeenCalledTimes(1);
expect(useNotice).toHaveBeenCalledTimes(1);
});
});
8 changes: 0 additions & 8 deletions __test__/pages/signup.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,6 @@ describe("Signup", () => {
screen.getByRole("button").click();
});

screen.debug();

// then
expect(
screen.queryByText("ユーザー名が重複しています。")
Expand Down Expand Up @@ -204,8 +202,6 @@ describe("Signup", () => {
screen.getByRole("button").click();
});

screen.debug();

// then
expect(
screen.queryByText("無効なユーザーグループです。")
Expand Down Expand Up @@ -234,8 +230,6 @@ describe("Signup", () => {
screen.getByRole("button").click();
});

screen.debug();

// then
expect(
screen.queryByText("無効なユーザーグループです。")
Expand Down Expand Up @@ -264,8 +258,6 @@ describe("Signup", () => {
screen.getByRole("button").click();
});

screen.debug();

// then
expect(screen.queryByText("無効な招待コードです。")).toBeInTheDocument();
});
Expand Down
5 changes: 4 additions & 1 deletion components/LoadingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import LoadingSpinner from "./LoadingSpinner";

function LoadingPage() {
return (
<div className="flex justify-center items-center h-screen">
<div
className="flex justify-center items-center h-screen"
data-testid="loading"
>
<LoadingSpinner />
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion components/_const.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const site = process.env.NEXT_PUBLIC_SITE_NAME;
export const rule = process.env.NEXT_PUBLIC_RULE;
export const shortRule = process.env.NEXT_PUBLIC_SHORT_RULE;
export const shortRule = process.env.NEXT_PUBLIC_SHORT_RULE ?? "";
export const recreateRule = process.env.NEXT_PUBLIC_RECREATE_RULE;

export const answerLimit = process.env.NEXT_PUBLIC_ANSWER_LIMIT;
4 changes: 2 additions & 2 deletions pages/problems/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import NotificationCard from "@/components/NotificationCard";
import ProblemCard from "@/components/ProblemCard";
import { shortRule } from "@/components/_const";
import useNotice from "@/hooks/notice";
import { useProblems } from "@/hooks/problem";
import useProblems from "@/hooks/problems";
import { dismissNoticeIdsState } from "@/hooks/state/recoil";
import CommonLayout from "@/layouts/CommonLayout";

Expand All @@ -34,7 +34,7 @@ function Problems() {
{shortRule !== "" && (
<div className="container-ictsc">
<ICTSCCard className="pt-4 pb-8">
<MarkdownPreview content={shortRule?.replace(/\\n/g, "\n") ?? ""} />
<MarkdownPreview content={shortRule.replace(/\\n/g, "\n")} />
</ICTSCCard>
</div>
)}
Expand Down
4 changes: 2 additions & 2 deletions types/Notice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type Notice = {

export const testNotice: Notice = {
source_id: "1",
title: "Test Notice",
body: "Test Notice Body",
title: "テスト通知タイトル",
body: "テスト通知本文",
draft: false,
};
22 changes: 11 additions & 11 deletions types/Problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@ export interface Problem {
is_solved: boolean;
}

export interface Matter {
code: string;
title: string;
point: number;
solvedCriterion: number;
authorId: string;
connectInfo?: ConnectionInfo[];
}

interface ConnectionInfo {
type?: string;
hostname?: string;
Expand All @@ -32,10 +23,19 @@ interface ConnectionInfo {
command?: string;
}

export interface Matter {
code: string;
title: string;
point: number;
solvedCriterion: number;
authorId: string;
connectInfo?: ConnectionInfo[];
}

export const testProblem: Problem = {
id: "id",
code: "test",
title: "テスト",
code: "XYZ",
title: "テスト問題タイトル",
body: "---\ntitle: テスト\n---\n# テスト本文",
point: 100,
solved_criterion: 100,
Expand Down

0 comments on commit c362be2

Please sign in to comment.