// useChangeSubject.spec.tsx
///
import { useResource, useChangeSubject, useSubject } from "./mockLdoMethods.js";
import type { FunctionComponent } from "react";
import React, { useState } from "react";
import { describe, it, expect, beforeEach } from "vitest";
import { render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes.js";
import { set } from "@ldo/jsonld-dataset-proxy";
import "@testing-library/jest-dom/vitest";
/**
* Test component: deterministic friend IDs (Example1, Example2, ...),
* accessible labels, and committed data shown via useSubject.
*/
const FormTest: FunctionComponent = () => {
const randomResource = useResource("http://example.com/resource.ttl");
const submittedData = useSubject(SolidProfileShapeShapeType, "Example0");
const [count, setCount] = useState(1);
const [data, setData, commitData] = useChangeSubject(
SolidProfileShapeShapeType,
"Example0",
);
return (
Form
{/* Committed view */}
Submitted Data
Name: {submittedData?.fn ?? ""}
{submittedData?.knows?.map((person) => (
-
Id: {person["@id"]} Name: {person.fn}
))}
);
};
/**
* Spec: drives the UI as requested.
*/
describe("useChangeSubject", () => {
let user: ReturnType;
beforeEach(() => {
user = userEvent.setup();
});
it("handles typing, list add/remove, and commit cycles", async () => {
render();
// 1) Type "Example0" into the Name field, assert after each keystroke
const nameInput = screen.getByRole("textbox", { name: "Name" });
const targetName = "Example0";
let progressive = "";
for (const c of targetName) {
progressive += c;
await user.type(nameInput, c);
expect(nameInput).toHaveValue(progressive);
}
// Submitted is blank so far
const submittedSection = screen.getByRole("region", {
name: /submitted data/i,
});
const submittedName =
within(submittedSection).getByTestId("submitted-name");
const submittedList =
within(submittedSection).getByTestId("submitted-list");
expect(submittedName).toHaveTextContent("Name:");
expect(within(submittedList).queryAllByRole("listitem")).toHaveLength(0);
// 2) Add two friends -> Example1, Example2
const addFriendBtn = screen.getByRole("button", { name: /add friend/i });
await user.click(addFriendBtn);
await user.click(addFriendBtn);
const friend1 = screen.getByTestId("friend-Example1");
const friend2 = screen.getByTestId("friend-Example2");
expect(within(friend1).getByText("Example1")).toBeInTheDocument();
expect(within(friend2).getByText("Example2")).toBeInTheDocument();
// 3) Type friend names with per-keystroke assertions
const friend1Input = within(friend1).getByRole("textbox", {
name: "Friend name for Example1",
});
const friend2Input = within(friend2).getByRole("textbox", {
name: "Friend name for Example2",
});
const friend1Name = "Example1";
const friend2Name = "Example2";
let p = "";
for (const c of friend1Name) {
p += c;
await user.type(friend1Input, c);
expect(friend1Input).toHaveValue(p);
}
p = "";
for (const c of friend2Name) {
p += c;
await user.type(friend2Input, c);
expect(friend2Input).toHaveValue(p);
}
// Still nothing committed
expect(submittedName).toHaveTextContent("Name:");
expect(within(submittedList).queryAllByRole("listitem")).toHaveLength(0);
// 4) Remove Example2
await user.click(
within(friend2).getByRole("button", { name: /remove friend/i }),
);
expect(screen.queryByTestId("friend-Example2")).not.toBeInTheDocument();
// 5) Submit -> committed data reflects Example0 + Example1 only
await user.click(screen.getByRole("button", { name: /Submit/i }));
// Form retained its values
expect(nameInput).toHaveValue("Example0");
expect(friend1Input).toHaveValue("Example1");
expect(screen.queryByTestId("friend-Example2")).not.toBeInTheDocument();
// Wait for the submitted data to appear in the document before asserting
const submittedSection2 = screen.getByRole("region", {
name: /submitted data/i,
});
const submittedName2 =
within(submittedSection2).getByTestId("submitted-name");
// Use `findByText` from the `within` helper to wait for the change
await within(submittedSection2).findByText("Name: Example0");
// Now that we've successfully waited, we can safely make our assertions
expect(submittedName2).toHaveTextContent("Name: Example0");
const itemsAfterSubmit = within(submittedList).getAllByRole("listitem");
expect(itemsAfterSubmit).toHaveLength(1);
expect(itemsAfterSubmit[0]).toHaveTextContent(
"Id: Example1 Name: Example1",
);
// 6) Change name and resubmit
await user.clear(nameInput);
const newName = "anotherExample0";
let q = "";
for (const c of newName) {
q += c;
await user.type(nameInput, c);
expect(nameInput).toHaveValue(q);
}
await user.click(screen.getByRole("button", { name: /submit/i }));
expect(submittedName).toHaveTextContent(`Name: ${newName}`);
const itemsAfterSecondSubmit =
within(submittedList).getAllByRole("listitem");
expect(itemsAfterSecondSubmit).toHaveLength(1);
expect(itemsAfterSecondSubmit[0]).toHaveTextContent(
"Id: Example1 Name: Example1",
);
});
});