175 lines
5.6 KiB
TypeScript
175 lines
5.6 KiB
TypeScript
import React from "react";
|
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
import { MockedProvider, MockedResponse } from "@apollo/client/testing";
|
|
import { MemoryRouter } from "react-router-dom";
|
|
import QuestionList from "../components/QuestionList";
|
|
import { SnackbarProvider } from "notistack";
|
|
import {
|
|
getAllQuestionsMock,
|
|
getQuestionByIdMock,
|
|
questionNodesMock,
|
|
} from "../backend/queries/question.mock";
|
|
import { getAllCategoriesMock } from "../backend/queries/category.mock";
|
|
import {
|
|
addQuestionMock,
|
|
deleteQuestionMock,
|
|
editQuestionMock,
|
|
} from "../backend/mutations/question.mock";
|
|
import {
|
|
expandAccordionAndGetIconButtons,
|
|
queryAllAddIconButtons,
|
|
queryAllEditIconButtons,
|
|
} from "./test-helper";
|
|
|
|
describe("The QuestionList", () => {
|
|
test("displays the existing questions, but not the details of it", async () => {
|
|
renderQuestionList();
|
|
|
|
const questionCards = await waitForInitialQuestionsToRender();
|
|
questionCards.forEach((card) => {
|
|
expect(card.innerHTML).toMatch(/Question [1-3]\?/);
|
|
});
|
|
expect(questionCards[0].innerHTML).toMatch(/Category 1/);
|
|
expect(queryAllEditIconButtons()).toHaveLength(0);
|
|
});
|
|
|
|
test("enables toggling details on each question", async () => {
|
|
renderQuestionList();
|
|
|
|
// Initial state: Every question card is not expanded
|
|
const questionCards = await waitForInitialQuestionsToRender();
|
|
|
|
// Expand first question card
|
|
await expandAccordionAndGetIconButtons(questionCards[0]);
|
|
|
|
// Shrink first question card again
|
|
fireEvent.click(questionCards[0]);
|
|
await waitFor(() => {
|
|
expect(queryAllEditIconButtons()).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
test("enables editing a question title", async () => {
|
|
renderQuestionList(editQuestionMock);
|
|
|
|
const questionCards = await waitForInitialQuestionsToRender();
|
|
const { editIconButton } = await expandAccordionAndGetIconButtons(
|
|
questionCards[0]
|
|
);
|
|
|
|
// open edit dialog
|
|
expect(screen.queryByText(/Frage bearbeiten/)).toBeNull();
|
|
fireEvent.click(editIconButton);
|
|
await waitFor(() => {
|
|
expect(screen.queryByText(/Frage bearbeiten/)).not.toBeNull();
|
|
});
|
|
|
|
// change question title
|
|
const questionTitleField = screen.getByDisplayValue(/Question 1/);
|
|
fireEvent.change(questionTitleField, {
|
|
target: { value: "New title for Question 1?" },
|
|
});
|
|
await waitFor(() => {
|
|
expect(screen.queryByDisplayValue(/New title for /)).not.toBeNull();
|
|
});
|
|
|
|
// call backend and assert apollo cache update
|
|
const confirmButton = screen.getByRole("button", { name: /Speichern/ });
|
|
fireEvent.click(confirmButton);
|
|
await waitFor(() => {
|
|
expect(screen.queryByText(/Frage bearbeiten/)).toBeNull();
|
|
expect(screen.queryByText(/New title for Question 1/)).not.toBeNull();
|
|
});
|
|
});
|
|
|
|
test("enables adding a question", async () => {
|
|
renderQuestionList(addQuestionMock);
|
|
await waitForInitialQuestionsToRender();
|
|
|
|
// open add dialog
|
|
const dialogIdentifier = /Neue Frage erstellen/;
|
|
expect(screen.queryByText(dialogIdentifier)).toBeNull();
|
|
const addButton = queryAllAddIconButtons()[0];
|
|
fireEvent.click(addButton);
|
|
await waitFor(() => {
|
|
expect(screen.queryByText(dialogIdentifier)).not.toBeNull();
|
|
});
|
|
|
|
// change question title
|
|
const questionTitleField = screen.getByLabelText(/Zusammenfassung/);
|
|
fireEvent.change(questionTitleField, {
|
|
target: { value: "New question?" },
|
|
});
|
|
await waitFor(() => {
|
|
expect(screen.queryByDisplayValue(/New question/)).not.toBeNull();
|
|
});
|
|
|
|
// call backend and assert apollo cache update
|
|
const confirmButton = screen.getByRole("button", { name: /Erstellen/ });
|
|
fireEvent.click(confirmButton);
|
|
await waitFor(() => {
|
|
expect(screen.queryByText(dialogIdentifier)).toBeNull();
|
|
expect(screen.queryByText(/New question/)).not.toBeNull();
|
|
});
|
|
});
|
|
|
|
test("enables deleting a question", async () => {
|
|
renderQuestionList(deleteQuestionMock);
|
|
|
|
const questionCards = await waitForInitialQuestionsToRender();
|
|
expect(screen.queryByText(/Question 2/)).not.toBeNull();
|
|
const { deleteIconButton } = await expandAccordionAndGetIconButtons(
|
|
questionCards[1]
|
|
);
|
|
|
|
// open delete confirmation dialog
|
|
expect(screen.queryByText(/Frage löschen/)).toBeNull();
|
|
fireEvent.click(deleteIconButton);
|
|
await waitFor(() => {
|
|
expect(screen.queryByText(/Frage löschen/)).not.toBeNull();
|
|
});
|
|
|
|
// call backend and assert apollo cache update
|
|
const confirmButton = screen.getByRole("button", { name: /Löschen/ });
|
|
fireEvent.click(confirmButton);
|
|
await waitFor(() => {
|
|
expect(screen.queryByText(/Frage löschen/)).toBeNull();
|
|
expect(screen.queryByText(/Question 2/)).toBeNull();
|
|
});
|
|
});
|
|
});
|
|
|
|
function renderQuestionList(additionalMocks?: Array<MockedResponse>) {
|
|
const initialMocks = [
|
|
...getAllQuestionsMock,
|
|
...getQuestionByIdMock,
|
|
...getAllCategoriesMock,
|
|
];
|
|
const allMocks = additionalMocks
|
|
? [...initialMocks, ...additionalMocks]
|
|
: initialMocks;
|
|
return render(
|
|
<MockedProvider mocks={allMocks}>
|
|
<MemoryRouter>
|
|
<SnackbarProvider>
|
|
<QuestionList />
|
|
</SnackbarProvider>
|
|
</MemoryRouter>
|
|
</MockedProvider>
|
|
);
|
|
}
|
|
|
|
const waitForInitialQuestionsToRender = async (): Promise<
|
|
Array<HTMLElement>
|
|
> => {
|
|
const numberOfQuestionsInMockQuery = questionNodesMock.length;
|
|
let questionCards: Array<HTMLElement> = [];
|
|
await waitFor(() => {
|
|
questionCards = screen.queryAllByRole("button", {
|
|
name: /Question [1-3]\?/,
|
|
});
|
|
expect(questionCards.length).toEqual(numberOfQuestionsInMockQuery);
|
|
});
|
|
return questionCards;
|
|
};
|