fix: isolate EventCard tests and clean compose refs hook
This commit is contained in:
@@ -54,9 +54,12 @@ function composeRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
|
|||||||
* A custom hook that composes multiple refs
|
* A custom hook that composes multiple refs
|
||||||
* Accepts callback refs and RefObject(s)
|
* Accepts callback refs and RefObject(s)
|
||||||
*/
|
*/
|
||||||
function useComposedRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
|
function useComposedRefs<T>(
|
||||||
// biome-ignore lint/correctness/useExhaustiveDependencies: we want to memoize by all values
|
ref1: PossibleRef<T>,
|
||||||
return React.useCallback(composeRefs(...refs), refs);
|
ref2: PossibleRef<T>,
|
||||||
|
ref3?: PossibleRef<T>,
|
||||||
|
): React.RefCallback<T> {
|
||||||
|
return React.useMemo(() => composeRefs(ref1, ref2, ref3), [ref1, ref2, ref3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { composeRefs, useComposedRefs };
|
export { composeRefs, useComposedRefs };
|
||||||
|
|||||||
@@ -1,65 +1,76 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||||
import { renderToStaticMarkup } from "react-dom/server";
|
import { renderToStaticMarkup } from "react-dom/server";
|
||||||
import { EventCard } from "@/components/event-card";
|
import { EventCard } from "@/components/event-card";
|
||||||
import type { CalendarEvent } from "@/lib/types";
|
import type { CalendarEvent } from "@/lib/types";
|
||||||
|
|
||||||
const sampleEvent: CalendarEvent = {
|
const sampleEvent: CalendarEvent = {
|
||||||
id: "evt_1",
|
id: "evt_1",
|
||||||
title: "Design Review",
|
title: "Design Review",
|
||||||
start: "2026-04-09T10:00:00+00:00",
|
start: "2026-04-09T10:00:00+00:00",
|
||||||
end: "2026-04-09T11:00:00+00:00",
|
end: "2026-04-09T11:00:00+00:00",
|
||||||
description: "Review the updated event list UI.",
|
description: "Review the updated event list UI.",
|
||||||
location: "Studio A",
|
location: "Studio A",
|
||||||
url: "https://example.com/event",
|
url: "https://example.com/event",
|
||||||
allDay: false,
|
allDay: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("EventCard actions trigger", () => {
|
describe("EventCard actions trigger", () => {
|
||||||
test("shows the triple-dots trigger without requiring hover and exposes an aria-label for the icon-only button", () => {
|
beforeEach(() => {
|
||||||
const markup = renderToStaticMarkup(
|
globalThis.document = {
|
||||||
EventCard({
|
addEventListener: () => {},
|
||||||
event: sampleEvent,
|
removeEventListener: () => {},
|
||||||
onEdit: () => {},
|
} as unknown as Document;
|
||||||
onDelete: () => {},
|
});
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(markup).toContain('aria-label="Event actions"');
|
afterEach(() => {
|
||||||
expect(markup).not.toContain("opacity-0");
|
delete (globalThis as { document?: Document }).document;
|
||||||
expect(markup).not.toContain("group-hover:opacity-100");
|
});
|
||||||
});
|
|
||||||
|
|
||||||
test("renders friendly shared date formatting instead of native locale strings", () => {
|
test("shows the triple-dots trigger without requiring hover and exposes an aria-label for the icon-only button", () => {
|
||||||
const markup = renderToStaticMarkup(
|
const markup = renderToStaticMarkup(
|
||||||
EventCard({
|
EventCard({
|
||||||
event: sampleEvent,
|
event: sampleEvent,
|
||||||
onEdit: () => {},
|
onEdit: () => {},
|
||||||
onDelete: () => {},
|
onDelete: () => {},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(markup).toContain("10:00–11:00");
|
expect(markup).toContain('aria-label="Event actions"');
|
||||||
expect(markup).not.toContain("AM");
|
expect(markup).not.toContain("opacity-0");
|
||||||
});
|
expect(markup).not.toContain("group-hover:opacity-100");
|
||||||
|
});
|
||||||
|
|
||||||
test("renders inline warning copy for invalid event ranges", () => {
|
test("renders friendly shared date formatting instead of native locale strings", () => {
|
||||||
const markup = renderToStaticMarkup(
|
const markup = renderToStaticMarkup(
|
||||||
EventCard({
|
EventCard({
|
||||||
event: {
|
event: sampleEvent,
|
||||||
id: "evt_invalid",
|
onEdit: () => {},
|
||||||
title: "Broken Event",
|
onDelete: () => {},
|
||||||
start: "2026-04-09T11:00:00+00:00",
|
}),
|
||||||
end: "2026-04-09T10:00:00+00:00",
|
);
|
||||||
allDay: false,
|
|
||||||
},
|
|
||||||
onEdit: () => {},
|
|
||||||
onDelete: () => {},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(markup).toContain("Warning:");
|
expect(markup).toContain("10:00–11:00");
|
||||||
expect(markup).toContain("end time is before start time");
|
expect(markup).not.toContain("AM");
|
||||||
expect(markup).not.toContain("Preview");
|
});
|
||||||
expect(markup).not.toContain("Ship");
|
|
||||||
});
|
test("renders inline warning copy for invalid event ranges", () => {
|
||||||
|
const markup = renderToStaticMarkup(
|
||||||
|
EventCard({
|
||||||
|
event: {
|
||||||
|
id: "evt_invalid",
|
||||||
|
title: "Broken Event",
|
||||||
|
start: "2026-04-09T11:00:00+00:00",
|
||||||
|
end: "2026-04-09T10:00:00+00:00",
|
||||||
|
allDay: false,
|
||||||
|
},
|
||||||
|
onEdit: () => {},
|
||||||
|
onDelete: () => {},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(markup).toContain("Warning:");
|
||||||
|
expect(markup).toContain("end time is before start time");
|
||||||
|
expect(markup).not.toContain("Preview");
|
||||||
|
expect(markup).not.toContain("Ship");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user