import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { runInAction } from "mobx";
import { act } from "react";
import Terria from "../../../lib/Models/Terria";
import ViewState from "../../../lib/ReactViewModels/ViewState";
import TourPortal from "../../../lib/ReactViews/Tour/TourPortal";
import { renderWithContexts } from "../withContext";
describe("TourPortal", function () {
let terria: Terria;
let viewState: ViewState;
beforeEach(function () {
terria = new Terria({
baseUrl: "./"
});
viewState = new ViewState({
terria: terria
});
});
describe("with basic props", function () {
describe("renders", function () {
it("nothing when current tour index is negative", function () {
const { container } = renderWithContexts(, viewState);
// tourportal should just not render anything in this case
expect(container).toBeEmptyDOMElement();
});
it("renders something using the TourPreface path under preface conditions", function () {
runInAction(() => {
viewState.setTourIndex(0);
viewState.setShowTour(true);
});
renderWithContexts(, viewState);
// tourportal should render the TourPreface: 2*close & accept buttons
const buttons = screen.getAllByRole("button");
expect(buttons.length).toEqual(3);
expect(screen.getByText("tour.preface.title")).toBeVisible();
expect(screen.getByText("tour.preface.content")).toBeVisible();
expect(
screen.getByRole("button", { name: "tour.preface.start" })
).toBeVisible();
expect(
screen.getByRole("button", { name: "tour.preface.close" })
).toBeVisible();
});
it("renders something using the TourGrouping path under showPortal conditions", async function () {
// Create mock refs with real DOM elements
const testRef = { current: document.createElement("div") };
const testRef2 = { current: document.createElement("div") };
const testRef3 = { current: document.createElement("div") };
runInAction(() => {
viewState.setTourIndex(0);
// Set showTour directly — setShowTour(true) uses setTimeout internally
viewState.showTour = true;
viewState.updateAppRef("TestRef", testRef);
viewState.updateAppRef("TestRef2", testRef2);
viewState.updateAppRef("TestRef3", testRef3);
viewState.tourPoints = [
{
appRefName: "TestRef",
priority: 10,
content: "## Best friends\n\nMochi and neko are best friends"
},
{
appRefName: "TestRef2",
priority: 20,
content: "## Motivated by food\n\nNeko loves food"
},
{
appRefName: "TestRef3",
priority: 30,
content: "## Lazy\n\nThey like to lounge around all day"
}
];
});
renderWithContexts(, viewState);
// 3 test tour points
expect(viewState.tourPointsWithValidRefs.length).toBe(3);
// Active tour point content is rendered
expect(screen.getByText("Best friends")).toBeVisible();
expect(
screen.getByText("Mochi and neko are best friends")
).toBeVisible();
expect(
screen.getByRole("button", { name: "general.next" })
).toBeVisible();
expect(
screen.queryByRole("button", { name: "general.back" })
).not.toBeInTheDocument();
await userEvent.click(
screen.getByRole("button", { name: "general.next" })
);
// Next tour point content is rendered
expect(screen.getByText("Motivated by food")).toBeVisible();
expect(screen.getByText("Neko loves food")).toBeVisible();
expect(
screen.getByRole("button", { name: "general.next" })
).toBeVisible();
expect(
screen.getByRole("button", { name: "general.back" })
).toBeVisible();
await userEvent.click(
screen.getByRole("button", { name: "general.next" })
);
// Last tour point content is rendered
expect(screen.getByText("Lazy")).toBeVisible();
expect(
screen.getByText("They like to lounge around all day")
).toBeVisible();
expect(
screen.queryByRole("button", { name: "general.next" })
).not.toBeInTheDocument();
expect(
screen.getByRole("button", { name: "general.back" })
).toBeVisible();
// Remove one tour point and we should only have 2 left
act(() => {
runInAction(() => {
viewState.deleteAppRef("TestRef");
});
});
// 2 test tour points
expect(viewState.tourPointsWithValidRefs.length).toBe(2);
});
});
});
});