Skip to content

Large diffs are not rendered by default.

216 changes: 216 additions & 0 deletions __tests__/components/header/HeaderSearchModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const useDropForgePermissionsMock = jest.fn();

jest.mock("react-use", () => {
return {
createBreakpoint: () => () => "MD",
useClickAway: (_ref: any, cb: () => void) => {
clickAwayCb = cb;
},
Expand Down Expand Up @@ -286,6 +287,221 @@ describe("HeaderSearchModal", () => {
).toBe(true);
});

it("matches close pluralized page titles for page searches", async () => {
setup({
selectedCategory: "PAGES",
sidebarSections: [
{
key: "network",
name: "Network",
icon: () => null,
items: [{ name: "Memes Calendar", href: "/meme-calendar" }],
subsections: [],
},
],
queryImpl: () => ({
isFetching: false,
data: [],
error: undefined,
refetch: jest.fn(() => Promise.resolve()),
}),
});

const input = screen.getByRole("textbox", { name: "Search" });
fireEvent.change(input, { target: { value: "meme calendar" } });

const items = await screen.findAllByTestId("item");
expect(
items.some(
(item) =>
(item.textContent ?? "").includes('"title":"Memes Calendar"') &&
(item.textContent ?? "").includes('"/meme-calendar"')
)
).toBe(true);
});

it("matches close singularized page titles for page searches", async () => {
setup({
selectedCategory: "PAGES",
sidebarSections: [
{
key: "network",
name: "Network",
icon: () => null,
items: [{ name: "Meme Calendar", href: "/meme-calendar" }],
subsections: [],
},
],
queryImpl: () => ({
isFetching: false,
data: [],
error: undefined,
refetch: jest.fn(() => Promise.resolve()),
}),
});

const input = screen.getByRole("textbox", { name: "Search" });
fireEvent.change(input, { target: { value: "memes calendar" } });

const items = await screen.findAllByTestId("item");
expect(
items.some(
(item) =>
(item.textContent ?? "").includes('"title":"Meme Calendar"') &&
(item.textContent ?? "").includes('"/meme-calendar"')
)
).toBe(true);
});

it("matches partial token page searches with close pluralization", async () => {
setup({
selectedCategory: "PAGES",
sidebarSections: [
{
key: "network",
name: "Network",
icon: () => null,
items: [{ name: "Memes Calendar", href: "/meme-calendar" }],
subsections: [],
},
],
queryImpl: () => ({
isFetching: false,
data: [],
error: undefined,
refetch: jest.fn(() => Promise.resolve()),
}),
});

const input = screen.getByRole("textbox", { name: "Search" });
fireEvent.change(input, { target: { value: "meme cal" } });

const items = await screen.findAllByTestId("item");
expect(
items.some(
(item) =>
(item.textContent ?? "").includes('"title":"Memes Calendar"') &&
(item.textContent ?? "").includes('"/meme-calendar"')
)
).toBe(true);
});

it("matches page queries that span breadcrumbs and titles", async () => {
setup({
selectedCategory: "PAGES",
sidebarSections: [
{
key: "network",
name: "Network",
icon: () => null,
items: [],
subsections: [
{
name: "Metrics",
items: [{ name: "Health", href: "/network/health" }],
},
],
},
],
queryImpl: () => ({
isFetching: false,
data: [],
error: undefined,
refetch: jest.fn(() => Promise.resolve()),
}),
});

const input = screen.getByRole("textbox", { name: "Search" });
fireEvent.change(input, { target: { value: "metrics health" } });

const items = await screen.findAllByTestId("item");
expect(
items.some(
(item) =>
(item.textContent ?? "").includes('"title":"Health"') &&
(item.textContent ?? "").includes('"/network/health"')
)
).toBe(true);
});

it("prioritizes exact href matches ahead of title and breadcrumb fallbacks", async () => {
setup({
selectedCategory: "PAGES",
sidebarSections: [
{
key: "network",
name: "Network",
icon: () => null,
items: [],
subsections: [
{
name: "Metrics",
items: [{ name: "Health", href: "/network/health" }],
},
],
},
{
key: "about",
name: "About",
icon: () => null,
items: [{ name: "Network Health", href: "/about/network-health" }],
subsections: [],
},
],
queryImpl: () => ({
isFetching: false,
data: [],
error: undefined,
refetch: jest.fn(() => Promise.resolve()),
}),
});

const input = screen.getByRole("textbox", { name: "Search" });
fireEvent.change(input, { target: { value: "/network/health" } });

const items = await screen.findAllByTestId("item");
expect(items[0]?.textContent).toContain('"/network/health"');
});

it("prioritizes path-like partial href queries ahead of token-based title matches", async () => {
setup({
selectedCategory: "PAGES",
sidebarSections: [
{
key: "network",
name: "Network",
icon: () => null,
items: [],
subsections: [
{
name: "Metrics",
items: [{ name: "Health", href: "/network/health" }],
},
],
},
{
key: "about",
name: "About",
icon: () => null,
items: [{ name: "Network Health", href: "/about/network-health" }],
subsections: [],
},
],
queryImpl: () => ({
isFetching: false,
data: [],
error: undefined,
refetch: jest.fn(() => Promise.resolve()),
}),
});

const input = screen.getByRole("textbox", { name: "Search" });
fireEvent.change(input, { target: { value: "/network/he" } });

const items = await screen.findAllByTestId("item");
expect(items[0]?.textContent).toContain('"/network/health"');
});

it("includes drop forge pages in search results when accessible", () => {
setup({
selectedCategory: "PAGES",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {
formatUtcMonth,
formatUtcMonthYear,
mintStartInstantUtcForMintDay,
nextMintDateOnOrAfter,
wallTimeToUtcInstantInZone,
Expand Down Expand Up @@ -27,6 +29,17 @@ const mintEndInstantUtcForMintDay = (mintDay: Date): Date => {
};

describe("meme calendar timezone handling", () => {
const originalTz = process.env.TZ;

afterEach(() => {
if (originalTz === undefined) {
delete process.env.TZ;
return;
}

process.env.TZ = originalTz;
});
Comment thread
prxt6529 marked this conversation as resolved.

it("keeps mint start anchored to 17:40 Athens time across 2024", () => {
const months = Array.from({ length: 12 }, (_, idx) => idx);

Expand Down Expand Up @@ -121,4 +134,13 @@ describe("meme calendar timezone handling", () => {
expect(summerPhaseTimes[0]?.toISOString()).toBe("2024-07-01T14:40:00.000Z");
expect(winterPhaseTimes[0]?.toISOString()).toBe("2024-01-03T15:40:00.000Z");
});

it("formats UTC month labels consistently for US timezones", () => {
process.env.TZ = "America/Los_Angeles";

const seasonStart = isoDate(2026, 0, 1);

expect(formatUtcMonth(seasonStart, "long")).toBe("January");
expect(formatUtcMonthYear(seasonStart)).toBe("Jan 2026");
});
});
120 changes: 120 additions & 0 deletions __tests__/contexts/TitleContext.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import DynamicHeadTitle from "@/components/dynamic-head/DynamicHeadTitle";
import {
TitleProvider,
useSetWaveData,
useTitle,
} from "@/contexts/TitleContext";
import { render, screen, waitFor } from "@testing-library/react";

let mockPathname = "/waves/wave-1";
let mockSearchParams = new URLSearchParams("divider=841669");
let mockActiveWaveId: string | null = "wave-1";

jest.mock("next/navigation", () => ({
usePathname: () => mockPathname,
useSearchParams: () => mockSearchParams,
}));

jest.mock("@/contexts/wave/MyStreamContext", () => ({
useMyStreamOptional: () =>
mockActiveWaveId
? {
activeWave: {
id: mockActiveWaveId,
set: jest.fn(),
},
}
: null,
}));

function TitleHarness({
waveData,
}: {
readonly waveData: { name: string; newItemsCount: number } | null;
}) {
useSetWaveData(waveData);
const { title } = useTitle();
return <div>{title}</div>;
}

describe("TitleContext", () => {
beforeEach(() => {
mockPathname = "/waves/wave-1";
mockSearchParams = new URLSearchParams("divider=841669");
mockActiveWaveId = "wave-1";
document.title = "";
});

it("resets the client title when leaving a wave for the meme calendar", async () => {
const view = render(
<TitleProvider>
<DynamicHeadTitle />
<TitleHarness
waveData={{ name: "6529 Dev Daily Standup", newItemsCount: 0 }}
/>
</TitleProvider>
);

await waitFor(() => {
expect(
screen.getByText("6529 Dev Daily Standup | Brain")
).toBeInTheDocument();
});
await waitFor(() => {
expect(document.title).toBe("6529 Dev Daily Standup | Brain");
});

mockPathname = "/meme-calendar";
mockSearchParams = new URLSearchParams();

view.rerender(
<TitleProvider>
<DynamicHeadTitle />
<TitleHarness waveData={null} />
</TitleProvider>
);

await waitFor(() => {
expect(screen.getByText("Memes Minting Calendar")).toBeInTheDocument();
});
await waitFor(() => {
expect(document.title).toBe("Memes Minting Calendar");
});
});

it("resets the client title when the active wave id changes on the same route", async () => {
mockPathname = "/messages";
mockSearchParams = new URLSearchParams("wave=wave-1");

const view = render(
<TitleProvider>
<DynamicHeadTitle />
<TitleHarness waveData={{ name: "Wave One", newItemsCount: 0 }} />
</TitleProvider>
);

await waitFor(() => {
expect(screen.getByText("Wave One | Brain")).toBeInTheDocument();
});
await waitFor(() => {
expect(document.title).toBe("Wave One | Brain");
});

mockSearchParams = new URLSearchParams("wave=wave-2");
mockActiveWaveId = "wave-2";

view.rerender(
<TitleProvider>
<DynamicHeadTitle />
<TitleHarness waveData={null} />
</TitleProvider>
);

await waitFor(() => {
expect(screen.getByText("Messages | Brain")).toBeInTheDocument();
});
await waitFor(() => {
expect(document.title).toBe("Messages | Brain");
});
});
});
Loading
Loading