Skip to content

Commit

Permalink
test: add component tests for paper details card
Browse files Browse the repository at this point in the history
  • Loading branch information
Slartibartfass2 committed Jan 19, 2025
1 parent c52959f commit dd81310
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Usage:
<PaperDetail id={key} {key} {value} {loadingPaper} {areDetailsInEditMode} />
```
-->
<div class="flex flex-row gap-2">
<div class="flex flex-row gap-2" data-testid="paper-detail">
<!-- Match top padding of input -->
<span class="w-24 pt-[0.3125rem]">{key}</span>
{#await loadingPaper}
Expand All @@ -35,6 +35,6 @@ Usage:
{:then}
<ToggleableInput isEditable={areDetailsInEditMode} {value} />
{:catch error}
<span class="pt-2 text-error">Coudn't load {key}{error ? `: ${error}` : ""}</span>
<span class="pt-2 text-error">Couldn't load {key}{error ? `: ${error}` : ""}</span>
{/await}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
import UnderlineTabsList from "$lib/components/composites/tabs/UnderlineTabsList.svelte";
import * as Card from "$lib/components/primitives/card/index.js";
import * as Tabs from "$lib/components/primitives/tabs/index.js";
import { cn } from "$lib/utils/shadcn-helper";
import type { WithElementRef } from "bits-ui";
import type { Snippet } from "svelte";
import type { HTMLAttributes } from "svelte/elements";
interface Props {
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>> & {
tabs: Tab[];
children: Snippet;
}
const { tabs, children }: Props = $props();
};
const { tabs, children, class: className, ...restProps }: Props = $props();
</script>

<!-- Use PaperCardContent elements as children with values according to the tabs props -->
Expand All @@ -32,7 +36,10 @@ Usage:
</PaperCard>
```
-->
<Card.Root class="shadow-lg border-container-border-grey flex w-full h-full max-w-[50%]">
<Card.Root
class={cn(className, "shadow-lg border-container-border-grey flex w-full h-full max-w-[50%]")}
{...restProps}
>
<section class="flex flex-col h-full w-full">
<Tabs.Root value={tabs.length == 0 ? "" : tabs[0].value} class="flex flex-col h-full">
<UnderlineTabsList {tabs} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Usage:
<PaperDetailsCard {paper} allowEditModeToggle startInEditMode />
```
-->
<PaperCard {tabs}>
<PaperCard {tabs} data-testid="paper-details-card">
<PaperCardContent value="1">
<section class="flex flex-col gap-2 px-1">
<div class="flex flex-row justify-between items-center">
Expand Down Expand Up @@ -153,7 +153,7 @@ Usage:
value={paper.abstrakt}
/>
{:catch error}
<span class="text-error">Coudn't load abstract{error ? `: ${error}` : ""}</span>
<span class="text-error">Couldn't load abstract{error ? `: ${error}` : ""}</span>
{/await}
</section>
</PaperCardContent>
Expand Down
50 changes: 50 additions & 0 deletions tests/integration/input/toggleable-input.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import ToggleableInput from "$lib/components/composites/input/ToggleableInput.svelte";
import { render, screen } from "@testing-library/svelte";
import { keyboard } from "@testing-library/user-event/dist/cjs/setup/directApi.js";
import { describe, expect, test } from "vitest";

describe("ToggleableInput", () => {
test("When isEditable is set to true, then input border is shown and content can be edited", async () => {
render(ToggleableInput, {
target: document.body,
props: {
isEditable: true,
value: "",
},
});

const input = screen.getByRole("textbox");
expect(input).toBeInTheDocument();

expect(input.classList.contains("border")).toBe(true);
expect(input.classList.contains("border-input")).toBe(true);
expect(input.classList.contains("rounded-md")).toBe(true);
expect(input.classList.contains("border-transparent")).toBe(false);

expect(input).not.toHaveAttribute("readonly");

await keyboard("Test");

expect(input).not.toHaveValue("Test");
expect(input).toHaveValue("");
});

test("When isEditable is set to false, then input border is not shown and content cannot be edited", () => {
render(ToggleableInput, {
target: document.body,
props: {
isEditable: false,
},
});

const input = screen.getByRole("textbox");
expect(input).toBeInTheDocument();

expect(input.classList.contains("border")).toBe(true);
expect(input.classList.contains("border-input")).toBe(false);
expect(input.classList.contains("rounded-md")).toBe(false);
expect(input.classList.contains("border-transparent")).toBe(true);

expect(input).toHaveAttribute("readonly");
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import PaperDetailsCard from "$lib/components/composites/paper-components/paper-view/cards/PaperDetailsCard.svelte";
import { render, screen, waitFor } from "@testing-library/svelte";
import { describe, expect, test } from "vitest";
import { createPaper } from "../../../../model-builder";
import { waitForComponentLoading } from "../../../test-helper";
import userEvent from "@testing-library/user-event";
import type { Paper } from "$lib/model/backend";

describe("PaperDetailsCard", () => {
test("When props are provided, then component is shown", async () => {
render(PaperDetailsCard, {
target: document.body,
props: {
loadingPaper: Promise.resolve(createPaper()),
allowEditModeToggle: true,
startInEditMode: false,
showButtonBar: true,
},
});

await waitForComponentLoading();

const card = screen.getByTestId("paper-details-card");
expect(card).toBeInTheDocument();

// edit mode can be toggled
const editButtons = document.getElementsByTagName("svg");
let editButtonCount = 0;
for (const editButton of editButtons) {
if (!editButton.classList.contains("lucide-pencil")) {
continue;
}

expect(editButton).toBeInTheDocument();
editButtonCount++;
}
expect(editButtonCount).toBe(2);

// paper details are in read-only mode
const paperDetails = screen.queryAllByTestId("paper-details");
expect(paperDetails).toHaveLength(5);

Check failure on line 41 in tests/integration/paper-components/paper-view/cards/paper-details-card.test.ts

View workflow job for this annotation

GitHub Actions / Integration Testing with Vitest

tests/integration/paper-components/paper-view/cards/paper-details-card.test.ts > PaperDetailsCard > When props are provided, then component is shown

AssertionError: expected [] to have a length of 5 but got +0 - Expected + Received - 5 + 0 ❯ tests/integration/paper-components/paper-view/cards/paper-details-card.test.ts:41:30
for (const paperDetail of paperDetails) {
expect(paperDetail).toBeInTheDocument();
const input = paperDetail.getElementsByTagName("textarea")[0];
expect(input).toHaveAttribute("readonly");
}

// additional details are not shown by default
const buttons = screen
.queryAllByRole("button")
.filter((button) => button.textContent === "Show more information");
expect(buttons).toHaveLength(1);
const showMoreButton = buttons[0];
expect(showMoreButton).toBeInTheDocument();
});

test("When show more information button is pressed, then additional details are shown", async () => {
const user = userEvent.setup();
render(PaperDetailsCard, {
target: document.body,
props: {
loadingPaper: Promise.resolve(createPaper()),
allowEditModeToggle: true,
startInEditMode: false,
showButtonBar: true,
},
});

await waitForComponentLoading();

const buttons = screen
.queryAllByRole("button")
.filter((button) => button.textContent === "Show more information");
expect(buttons).toHaveLength(1);

Check failure on line 74 in tests/integration/paper-components/paper-view/cards/paper-details-card.test.ts

View workflow job for this annotation

GitHub Actions / Integration Testing with Vitest

tests/integration/paper-components/paper-view/cards/paper-details-card.test.ts > PaperDetailsCard > When show more information button is pressed, then additional details are shown

AssertionError: expected [] to have a length of 1 but got +0 - Expected + Received - 1 + 0 ❯ tests/integration/paper-components/paper-view/cards/paper-details-card.test.ts:74:25
const showMoreButton = buttons[0];
expect(showMoreButton).toBeInTheDocument();

await user.click(showMoreButton);

await waitFor(() => {
const paperDetails = screen.queryAllByTestId("paper-details");
expect(paperDetails).toHaveLength(8);
});

expect(showMoreButton).toHaveTextContent("Show less information");
});

test("When edit mode is toggled, then paper details are in edit mode", async () => {
const user = userEvent.setup();
render(PaperDetailsCard, {
target: document.body,
props: {
loadingPaper: Promise.resolve(createPaper()),
allowEditModeToggle: true,
startInEditMode: false,
showButtonBar: true,
},
});

await waitForComponentLoading();

const svgs = document.getElementsByTagName("svg");
const editButtons: SVGSVGElement[] = [];
for (const svg of svgs) {
if (svg.classList.contains("lucide-pencil")) {
editButtons.push(svg);
}
}
expect(editButtons.length).toBe(2);

const generalInfoBtn = editButtons[0];
const abstractBtn = editButtons[1];

await user.click(generalInfoBtn);

await waitFor(() => {
const paperDetails = screen.queryAllByTestId("paper-details");
expect(paperDetails).toHaveLength(5);

Check failure on line 118 in tests/integration/paper-components/paper-view/cards/paper-details-card.test.ts

View workflow job for this annotation

GitHub Actions / Integration Testing with Vitest

tests/integration/paper-components/paper-view/cards/paper-details-card.test.ts > PaperDetailsCard > When edit mode is toggled, then paper details are in edit mode

AssertionError: expected [] to have a length of 5 but got +0 Ignored nodes: comments, script, style <html> <head /> <body> <div class="bg-card text-card-foreground rounded-lg border shadow-lg border-container-border-grey flex w-full h-full max-w-[50%]" data-testid="paper-details-card" > <section class="flex flex-col h-full w-full" > <div class="flex flex-col h-full" data-orientation="horizontal" data-tabs-root="" id="bits-13" > <div aria-orientation="horizontal" class="text-muted-foreground inline-flex items-center w-full h-fit justify-start rounded-none border-b b-2 bg-transparent p-0 px-3 pt-3" data-orientation="horizontal" data-tabs-list="" id="bits-14" role="tablist" > <button aria-controls="bits-17" aria-selected="true" class="ring-offset-background data-[state=active]:bg-background data-[state=active]:text-default inline-flex items-center justify-center whitespace-nowrap py-1.5 text-default-nc focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm data-[state=active]:border-b-primary h-fit rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-2 transition-none max-w-[50%]" data-orientation="horizontal" data-state="active" data-tabs-trigger="" data-value="1" id="bits-15" role="tab" tabindex="0" type="button" > <div class="truncate" > Information </div> </button> <button aria-controls="bits-18" aria-selected="false" class="ring-offset-background data-[state=active]:bg-background data-[state=active]:text-default inline-flex items-center justify-center whitespace-nowrap py-1.5 text-default-nc focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm data-[state=active]:border-b-primary h-fit rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-2 transition-none max-w-[50%]" data-orientation="horizontal" data-state="inactive" data-tabs-trigger="" data-value="2" id="bits-16" role="tab" tabindex="-1" type="button" > <div class="truncate" > Document </div> </button> </div> <div class="p-5 flex flex-col h-full" > <div aria-labelledby="bits-15" class="ring-offset-background focus-visible:ring-ring mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 h-full overflow-hidden" data-state="active" data-tabs-content="" data-value="1" id="bits-17" role="tabpanel" tabindex="0" > <div class="flex flex-col gap-5 h-full" > <section class="flex flex-col gap-2 px-1" > <div class="flex flex-row justify-between items-center" > <h2> General Information </h2> <svg class="lucide-icon lucide lucide-pencil hover:cursor-pointer select-none" fill="none" height="20" stroke="currentColor" stroke-linecap="round"
for (const paperDetail of paperDetails.slice(0, 4)) {
const input = paperDetail.getElementsByTagName("textarea")[0];
expect(input).not.toHaveAttribute("readonly");
}
});

await user.click(abstractBtn);

await waitFor(() => {
const paperDetails = screen.queryAllByTestId("paper-details");
expect(paperDetails).toHaveLength(5);
const input = paperDetails[4].getElementsByTagName("textarea")[0];
expect(input).not.toHaveAttribute("readonly");
});
});

test("When editMode is not allowed, then edit buttons are not shown", async () => {
render(PaperDetailsCard, {
target: document.body,
props: {
loadingPaper: Promise.resolve(createPaper()),
allowEditModeToggle: false,
startInEditMode: false,
showButtonBar: true,
},
});

await waitForComponentLoading();

const editButtons = document.getElementsByTagName("svg");
let editButtonCount = 0;
for (const editButton of editButtons) {
if (!editButton.classList.contains("lucide-pencil")) {
continue;
}

expect(editButton).toBeInTheDocument();
editButtonCount++;
}
expect(editButtonCount).toBe(0);
});

test("When paper is loading, then skeletons are shown", async () => {
render(PaperDetailsCard, {
target: document.body,
props: {
loadingPaper: new Promise<Paper>((resolve) => {
setTimeout(() => {
resolve(createPaper());
}, 1000);
}),
allowEditModeToggle: true,
startInEditMode: false,
showButtonBar: true,
},
});

const skeletons = screen.queryAllByTestId("skeleton");
expect(skeletons).toHaveLength(11);
});
});
73 changes: 73 additions & 0 deletions tests/integration/paper-components/paper-view/paper-detail.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import PaperDetail from "$lib/components/composites/paper-components/paper-view/PaperDetail.svelte";
import { render, screen } from "@testing-library/svelte";
import { describe, expect, test } from "vitest";
import { createPaper } from "../../../model-builder";
import type { Paper } from "$lib/model/backend";
import { waitForComponentLoading } from "../../test-helper";

describe("PaperDetail", () => {
test("When props are provided, then component is shown", async () => {
render(PaperDetail, {
target: document.body,
props: {
key: "Title",
value: "Example Title",
loadingPaper: Promise.resolve(createPaper()),
areDetailsInEditMode: false,
},
});

await waitForComponentLoading();

const spans = document.getElementsByTagName("span");
expect(spans.length).toEqual(2);

Check failure on line 23 in tests/integration/paper-components/paper-view/paper-detail.test.ts

View workflow job for this annotation

GitHub Actions / Integration Testing with Vitest

tests/integration/paper-components/paper-view/paper-detail.test.ts > PaperDetail > When props are provided, then component is shown

AssertionError: expected 1 to deeply equal 2 - Expected + Received - 2 + 1 ❯ tests/integration/paper-components/paper-view/paper-detail.test.ts:23:30
const keySpan = spans[0];
const valueSpan = spans[1];

expect(keySpan.textContent).toEqual("Title");
expect(valueSpan.textContent).toEqual("Example Title");
});

test("When paper is loading, then skeleton is shown", () => {
render(PaperDetail, {
target: document.body,
props: {
key: "Title",
value: "Example Title",
loadingPaper: new Promise<Paper>((resolve) => {
setTimeout(() => {
resolve(createPaper());
}, 1000);
}),
areDetailsInEditMode: false,
},
});

const spans = document.getElementsByTagName("span");
expect(spans.length).toEqual(1);
const keySpan = spans[0];

expect(keySpan.textContent).toEqual("Title");
expect(screen.queryByTestId("skeleton")).not.toBeNull();
});

test("When paper loading failed, then errot text is shown", () => {
render(PaperDetail, {
target: document.body,
props: {
key: "Title",
value: "Example Title",
loadingPaper: Promise.reject(),
areDetailsInEditMode: false,
},
});

const spans = document.getElementsByTagName("span");
expect(spans.length).toEqual(2);

Check failure on line 66 in tests/integration/paper-components/paper-view/paper-detail.test.ts

View workflow job for this annotation

GitHub Actions / Integration Testing with Vitest

tests/integration/paper-components/paper-view/paper-detail.test.ts > PaperDetail > When paper loading failed, then errot text is shown

AssertionError: expected 1 to deeply equal 2 - Expected + Received - 2 + 1 ❯ tests/integration/paper-components/paper-view/paper-detail.test.ts:66:30
const keySpan = spans[0];
const valueSpan = spans[1];

expect(keySpan.textContent).toEqual("Title");
expect(valueSpan.textContent).toEqual("Couldn't load Title");
});
});

0 comments on commit dd81310

Please sign in to comment.