From 3d14f1f6aca62284024c037b9947587a0b78b140 Mon Sep 17 00:00:00 2001 From: Alexis Sanehisa Date: Wed, 27 May 2026 15:04:07 -0400 Subject: [PATCH 1/4] test --- .../hours/hoursStatus.hydration.test.tsx | 111 +++++++++++++++++- .../components/hours/hoursStatus.stories.tsx | 25 ++++ .../src/components/hours/hoursStatus.tsx | 58 ++++++--- .../hours/hoursTable.hydration.test.tsx | 45 ++++++- .../components/hours/hoursTable.ssr.test.tsx | 10 ++ .../src/components/hours/hoursTable.tsx | 12 ++ .../src/components/hours/types.ts | 8 ++ 7 files changed, 247 insertions(+), 22 deletions(-) diff --git a/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx b/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx index 53d2c965..6d3a51ca 100644 --- a/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx +++ b/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx @@ -1,6 +1,6 @@ import { hydrateRoot } from "react-dom/client"; import { renderToString } from "react-dom/server"; -import { act } from "react-dom/test-utils"; +import { act } from "react"; import { afterEach, describe, expect, it } from "vitest"; import { DateTime, Settings } from "luxon"; import { HoursStatus } from "./hoursStatus.js"; @@ -31,7 +31,7 @@ describe("HoursStatus hydration", () => { Settings.defaultZone = "America/New_York"; (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; - vi.spyOn(globalThis, "setTimeout").mockImplementation((() => 0) as typeof setTimeout); + vi.spyOn(globalThis, "setTimeout").mockImplementation((() => 0) as unknown as typeof setTimeout); const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); const container = document.createElement("div"); @@ -45,7 +45,14 @@ describe("HoursStatus hydration", () => { let root: ReturnType | undefined; await act(async () => { - root = hydrateRoot(container, ); + root = hydrateRoot( + container, + + ); await Promise.resolve(); }); @@ -59,4 +66,102 @@ describe("HoursStatus hydration", () => { root?.unmount(); }); }); + + it("hydrates to the coming soon label without warnings", async () => { + const mockedNow = DateTime.fromObject( + { year: 2025, month: 1, day: 7, hour: 10 }, + { zone: "America/New_York" } + ); + + Settings.now = () => mockedNow.toMillis(); + Settings.defaultZone = "America/New_York"; + (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + + const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout").mockImplementation( + (() => 0) as unknown as typeof setTimeout + ); + const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + + const container = document.createElement("div"); + container.innerHTML = renderToString( +
+ ); + document.body.appendChild(container); + + expect(container.textContent).toBe(""); + + let root: ReturnType | undefined; + + await act(async () => { + root = hydrateRoot( + container, + + ); + await Promise.resolve(); + }); + + expect(consoleErrorSpy).not.toHaveBeenCalled(); + expect(setTimeoutSpy).not.toHaveBeenCalled(); + expect(container.textContent).toContain("Coming Soon"); + expect(container.textContent).not.toContain("Open Now"); + expect(container.textContent).not.toContain("Closed"); + expect(container.textContent).not.toContain("Closes at"); + expect(container.textContent).not.toContain("Opens at"); + + await act(async () => { + root?.unmount(); + }); + }); + + it("hydrates to the coming soon template override without warnings", async () => { + const mockedNow = DateTime.fromObject( + { year: 2025, month: 1, day: 7, hour: 10 }, + { zone: "America/New_York" } + ); + + Settings.now = () => mockedNow.toMillis(); + Settings.defaultZone = "America/New_York"; + (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + + const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout").mockImplementation( + (() => 0) as unknown as typeof setTimeout + ); + const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + + const container = document.createElement("div"); + container.innerHTML = renderToString( +
+ ); + document.body.appendChild(container); + + expect(container.textContent).toBe(""); + + let root: ReturnType | undefined; + + await act(async () => { + root = hydrateRoot( + container, + "Pronto"} + /> + ); + await Promise.resolve(); + }); + + expect(consoleErrorSpy).not.toHaveBeenCalled(); + expect(setTimeoutSpy).not.toHaveBeenCalled(); + expect(container.textContent).toContain("Pronto"); + expect(container.textContent).not.toContain("Coming Soon"); + + await act(async () => { + root?.unmount(); + }); + }); }); diff --git a/packages/pages-components/src/components/hours/hoursStatus.stories.tsx b/packages/pages-components/src/components/hours/hoursStatus.stories.tsx index 9837fda0..6c64450e 100644 --- a/packages/pages-components/src/components/hours/hoursStatus.stories.tsx +++ b/packages/pages-components/src/components/hours/hoursStatus.stories.tsx @@ -85,6 +85,31 @@ export const Open247: Story = { }, }; +export const ComingSoon: Story = { + args: { + hours: HoursData, + comingSoon: true, + }, + parameters: { + mockedLuxonDateTime: DateTime.fromObject( + { year: 2025, month: 1, day: 7, hour: 10 } // Tuesday 10 AM + ), + }, +}; + +export const ComingSoonTranslated: Story = { + args: { + hours: HoursData, + comingSoon: true, + comingSoonTemplate: () => "Pronto", + }, + parameters: { + mockedLuxonDateTime: DateTime.fromObject( + { year: 2025, month: 1, day: 7, hour: 10 } // Tuesday 10 AM + ), + }, +}; + export const IndefinitelyClosedActive: Story = { args: { hours: HoursTemporarilyClosed, diff --git a/packages/pages-components/src/components/hours/hoursStatus.tsx b/packages/pages-components/src/components/hours/hoursStatus.tsx index 8fca83fc..9fde4955 100644 --- a/packages/pages-components/src/components/hours/hoursStatus.tsx +++ b/packages/pages-components/src/components/hours/hoursStatus.tsx @@ -10,11 +10,22 @@ function isOpen24h(params: StatusParams): boolean { return params?.currentInterval?.is24h?.() || false; } +function isComingSoon(params: StatusParams): boolean { + return !!params.comingSoon; +} + function isIndefinitelyClosed(params: StatusParams): boolean { return !params.futureInterval; } +function defaultComingSoonTemplate(_: StatusParams): React.ReactNode { + return Coming Soon; +} + function defaultCurrentTemplate(params: StatusParams): React.ReactNode { + if (isComingSoon(params)) { + return defaultComingSoonTemplate(params); + } if (isOpen24h(params)) { return Open 24 Hours; } @@ -25,21 +36,21 @@ function defaultCurrentTemplate(params: StatusParams): React.ReactNode { } function defaultSeparatorTemplate(params: StatusParams): React.ReactNode { - if (isOpen24h(params) || isIndefinitelyClosed(params)) { + if (isComingSoon(params) || isOpen24h(params) || isIndefinitelyClosed(params)) { return null; } return ; } function defaultFutureTemplate(params: StatusParams): React.ReactNode { - if (isOpen24h(params) || isIndefinitelyClosed(params)) { + if (isComingSoon(params) || isOpen24h(params) || isIndefinitelyClosed(params)) { return null; } return {params.isOpen ? "Closes at" : "Opens at"}; } function defaultTimeTemplate(params: StatusParams): React.ReactNode { - if (isOpen24h(params) || isIndefinitelyClosed(params)) { + if (isComingSoon(params) || isOpen24h(params) || isIndefinitelyClosed(params)) { return null; } let time = ""; @@ -54,7 +65,7 @@ function defaultTimeTemplate(params: StatusParams): React.ReactNode { } function defaultDayOfWeekTemplate(params: StatusParams): React.ReactNode { - if (isOpen24h(params) || isIndefinitelyClosed(params)) { + if (isComingSoon(params) || isOpen24h(params) || isIndefinitelyClosed(params)) { return null; } const dayOptions: Intl.DateTimeFormatOptions = { @@ -78,6 +89,7 @@ function defaultStatusTemplate( props?: HoursStatusProps ): React.ReactNode { const currentTemplate = params.currentTemplate || defaultCurrentTemplate; + const comingSoonTemplate = params.comingSoonTemplate || defaultComingSoonTemplate; const separatorTemplate = params.separatorTemplate || defaultSeparatorTemplate; const futureTemplate = params.futureTemplate || defaultFutureTemplate; const timeTemplate = params.timeTemplate || defaultTimeTemplate; @@ -85,7 +97,7 @@ function defaultStatusTemplate( return (
- {currentTemplate(params)} + {params.comingSoon ? comingSoonTemplate(params) : currentTemplate(params)} {separatorTemplate(params)} {futureTemplate(params)} {timeTemplate(params)} @@ -101,6 +113,8 @@ const emptyStyle = { minHeight: `${1.5}em` }; * describing the current Open/Closed status of the entity * * @param {HoursType} hours data from Yext Streams + * @param {Boolean} comingSoon display a coming soon state instead of the normal status + * @param {Function} comingSoonTemplate override rendering for the "coming soon" part of this component "[[Coming Soon]]" * @param {Intl.DateTimeFormatOptions} timeOptions * @param {Intl.DateTimeFormatOptions} dayOptions * @param {Function} statusTemplate completely override rendering for this component @@ -121,26 +135,34 @@ const HoursStatus: React.FC = (props) => { setIsClient(true); }, []); - if (!props.hours) { + const statusTemplateFn = props.statusTemplate || defaultStatusTemplate; + const comingSoon = !!props.comingSoon; + let isOpen = false; + let currentInterval: StatusParams["currentInterval"] = null; + let futureInterval: StatusParams["futureInterval"] = null; + + if (!props.hours && !comingSoon) { return <>; } - const statusTemplateFn = props.statusTemplate || defaultStatusTemplate; - const h = new Hours(props.hours, props.timezone); - const isOpen = h.isOpenNow(); - const currentInterval = h.getCurrentInterval(); - const futureInterval = h.getNextInterval(); - - // When the current interval ends, or the next interval starts, trigger component rerender - const isOpenChangeTime = currentInterval?.end || futureInterval?.start; - if (isOpenChangeTime && !hasStatusTimeout) { - setHasStatusTimeout(true); - const delayMS = isOpenChangeTime.toMillis() - DateTime.now().toMillis(); - setTimeout(() => setHasStatusTimeout(false), delayMS); + if (!comingSoon && props.hours) { + const h = new Hours(props.hours, props.timezone); + isOpen = h.isOpenNow(); + currentInterval = h.getCurrentInterval(); + futureInterval = h.getNextInterval(); + + // When the current interval ends, or the next interval starts, trigger component rerender + const isOpenChangeTime = currentInterval?.end || futureInterval?.start; + if (isOpenChangeTime && !hasStatusTimeout) { + setHasStatusTimeout(true); + const delayMS = isOpenChangeTime.toMillis() - DateTime.now().toMillis(); + setTimeout(() => setHasStatusTimeout(false), delayMS); + } } const statusParams: StatusParams = { isOpen, + comingSoon, currentInterval, futureInterval, ...props, diff --git a/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx b/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx index 2f68f87a..645a7723 100644 --- a/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx +++ b/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx @@ -1,6 +1,6 @@ import { hydrateRoot } from "react-dom/client"; import { renderToString } from "react-dom/server"; -import { act } from "react-dom/test-utils"; +import { act } from "react"; import { afterEach, describe, expect, it } from "vitest"; import { DateTime, Settings } from "luxon"; import { HoursTable, ServerSideHoursTable } from "./hoursTable.js"; @@ -75,4 +75,47 @@ describe("HoursTable hydration", () => { root?.unmount(); }); }); + + it("stays empty when coming soon is enabled", async () => { + const mockedNow = DateTime.fromObject( + { year: 2025, month: 1, day: 9, hour: 12 }, + { zone: "America/New_York" } + ); + + Settings.now = () => mockedNow.toMillis(); + Settings.defaultZone = "America/New_York"; + (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + + vi.spyOn(Intl.DateTimeFormat.prototype, "resolvedOptions").mockImplementation( + function (this: Intl.DateTimeFormat) { + return { + ...originalResolvedOptions.call(this), + timeZone: "America/New_York", + }; + } + ); + + const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + const container = document.createElement("div"); + container.innerHTML = renderToString( + + ); + document.body.appendChild(container); + + expect(container.innerHTML).toBe(""); + + let root: ReturnType | undefined; + + await act(async () => { + root = hydrateRoot(container, ); + await Promise.resolve(); + }); + + expect(consoleErrorSpy).not.toHaveBeenCalled(); + expect(container.innerHTML).toBe(""); + + await act(async () => { + root?.unmount(); + }); + }); }); diff --git a/packages/pages-components/src/components/hours/hoursTable.ssr.test.tsx b/packages/pages-components/src/components/hours/hoursTable.ssr.test.tsx index 3e62bbde..7f439230 100644 --- a/packages/pages-components/src/components/hours/hoursTable.ssr.test.tsx +++ b/packages/pages-components/src/components/hours/hoursTable.ssr.test.tsx @@ -36,4 +36,14 @@ describe("HoursTable SSR", () => { expect(html).not.toContain("is-today"); expect(dayLabels[0]).toBe("Sunday"); }); + + it("renders nothing when coming soon is enabled", () => { + const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + const html = renderToString( + + ); + + expect(consoleErrorSpy).not.toHaveBeenCalled(); + expect(html).toBe(""); + }); }); diff --git a/packages/pages-components/src/components/hours/hoursTable.tsx b/packages/pages-components/src/components/hours/hoursTable.tsx index a0438504..e2f86353 100644 --- a/packages/pages-components/src/components/hours/hoursTable.tsx +++ b/packages/pages-components/src/components/hours/hoursTable.tsx @@ -146,6 +146,10 @@ const HoursTable: React.FC = (props) => { setIsClient(true); }, []); + if (props.comingSoon) { + return <>; + } + if (!props.hours) { return <>; } @@ -156,6 +160,10 @@ const HoursTable: React.FC = (props) => { }; export const ClientSideHoursTable: React.FC = (props) => { + if (props.comingSoon) { + return <>; + } + const h = new Hours(props.hours, Intl.DateTimeFormat().resolvedOptions().timeZone); const now = DateTime.now(); @@ -169,6 +177,10 @@ export const ClientSideHoursTable: React.FC = (props) => { }; export const ServerSideHoursTable: React.FC = (props) => { + if (props.comingSoon) { + return <>; + } + const { hours, dayOfWeekNames, intervalTranslations } = props; const hoursTableData: HoursTableDayData[] = days.map((day) => { diff --git a/packages/pages-components/src/components/hours/types.ts b/packages/pages-components/src/components/hours/types.ts index 55d13112..82fdbb90 100644 --- a/packages/pages-components/src/components/hours/types.ts +++ b/packages/pages-components/src/components/hours/types.ts @@ -37,6 +37,8 @@ export type DayOfWeekNames = { export interface HoursTableProps { /** Hours data from Yext Streams */ hours: HoursType; + /** Display an empty state instead of the table */ + comingSoon?: boolean; /** Label for each day of week, ordered starting from Sunday */ dayOfWeekNames?: DayOfWeekNames; /** Set the day of the first row of the table */ @@ -83,6 +85,8 @@ export enum Day { export interface StatusParams { /** Whether the entity is currently open */ isOpen: boolean; + /** Whether the entity should display a coming soon state */ + comingSoon?: boolean; /** The first interval that contains the current time */ currentInterval: HoursInterval | null; /** The next interval that hasn't started */ @@ -96,6 +100,8 @@ export interface StatusParams { export interface TemplateParams { /** Override rendering for the "current" part of this component "[[Open Now]] - closes at 5:00PM Monday" */ currentTemplate?: (s: StatusParams) => React.ReactNode; + /** Override rendering for the "coming soon" part of this component "[[Coming Soon]]" */ + comingSoonTemplate?: (s: StatusParams) => React.ReactNode; /** Override rendering for the "separator" part of this component "Open Now [[-]] closes at 5:00PM Monday" */ separatorTemplate?: (s: StatusParams) => React.ReactNode; /** FutureTemplate override rendering for the "future" part of this component "Open Now - [[closes at]] 5:00PM Monday" */ @@ -113,6 +119,8 @@ export interface HoursStatusProps extends TemplateParams { hours: HoursType; /** The IANA or UTC Offset timezone of the hours data from Yext Streams */ timezone: string; + /** Display a coming soon state instead of the normal open/closed status */ + comingSoon?: boolean; /** Formatting for the "time" part of this component "Open Now - closes at [[5:00PM]] Monday" */ timeOptions?: Intl.DateTimeFormatOptions; /** Formatting for the "day" part of this component "Open Now - closes at 5:00PM [[Monday]]" */ From 5b99bf8e8b5c576b2e60dab22eaacf5c445fc5a3 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 19:06:42 +0000 Subject: [PATCH 2/4] Automated linting/formatter update --- packages/pages-components/CHANGELOG.md | 4 +-- .../hours/hoursStatus.hydration.test.tsx | 28 ++++++++----------- .../hours/hoursTable.hydration.test.tsx | 5 +++- .../components/hours/hoursTable.ssr.test.tsx | 4 +-- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/packages/pages-components/CHANGELOG.md b/packages/pages-components/CHANGELOG.md index 636f76e2..954e613b 100644 --- a/packages/pages-components/CHANGELOG.md +++ b/packages/pages-components/CHANGELOG.md @@ -2,11 +2,11 @@ ##### Chores -* prevent shell injection in github action (vuln-44056) ([#148](https://github.com/yext/js/pull/148)) ([62edc854](https://github.com/yext/js/commit/62edc8541bb93c17941dc8c58e7f4bddb1ebc758)) +- prevent shell injection in github action (vuln-44056) ([#148](https://github.com/yext/js/pull/148)) ([62edc854](https://github.com/yext/js/commit/62edc8541bb93c17941dc8c58e7f4bddb1ebc758)) ##### New Features -* **pages-components:** expose entity prop to the analytics track method ([#149](https://github.com/yext/js/pull/149)) ([5e5932ab](https://github.com/yext/js/commit/5e5932abd2346475be18091a2f99a3dd50665122)) +- **pages-components:** expose entity prop to the analytics track method ([#149](https://github.com/yext/js/pull/149)) ([5e5932ab](https://github.com/yext/js/commit/5e5932abd2346475be18091a2f99a3dd50665122)) #### 2.1.1 (2026-04-21) diff --git a/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx b/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx index 6d3a51ca..8b53d97f 100644 --- a/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx +++ b/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx @@ -31,7 +31,9 @@ describe("HoursStatus hydration", () => { Settings.defaultZone = "America/New_York"; (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; - vi.spyOn(globalThis, "setTimeout").mockImplementation((() => 0) as unknown as typeof setTimeout); + vi.spyOn(globalThis, "setTimeout").mockImplementation( + (() => 0) as unknown as typeof setTimeout + ); const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); const container = document.createElement("div"); @@ -47,11 +49,7 @@ describe("HoursStatus hydration", () => { await act(async () => { root = hydrateRoot( container, - + ); await Promise.resolve(); }); @@ -77,9 +75,9 @@ describe("HoursStatus hydration", () => { Settings.defaultZone = "America/New_York"; (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; - const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout").mockImplementation( - (() => 0) as unknown as typeof setTimeout - ); + const setTimeoutSpy = vi + .spyOn(globalThis, "setTimeout") + .mockImplementation((() => 0) as unknown as typeof setTimeout); const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); const container = document.createElement("div"); @@ -95,11 +93,7 @@ describe("HoursStatus hydration", () => { await act(async () => { root = hydrateRoot( container, - + ); await Promise.resolve(); }); @@ -127,9 +121,9 @@ describe("HoursStatus hydration", () => { Settings.defaultZone = "America/New_York"; (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; - const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout").mockImplementation( - (() => 0) as unknown as typeof setTimeout - ); + const setTimeoutSpy = vi + .spyOn(globalThis, "setTimeout") + .mockImplementation((() => 0) as unknown as typeof setTimeout); const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); const container = document.createElement("div"); diff --git a/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx b/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx index 645a7723..a9091dc6 100644 --- a/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx +++ b/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx @@ -107,7 +107,10 @@ describe("HoursTable hydration", () => { let root: ReturnType | undefined; await act(async () => { - root = hydrateRoot(container, ); + root = hydrateRoot( + container, + + ); await Promise.resolve(); }); diff --git a/packages/pages-components/src/components/hours/hoursTable.ssr.test.tsx b/packages/pages-components/src/components/hours/hoursTable.ssr.test.tsx index 7f439230..7a36339f 100644 --- a/packages/pages-components/src/components/hours/hoursTable.ssr.test.tsx +++ b/packages/pages-components/src/components/hours/hoursTable.ssr.test.tsx @@ -39,9 +39,7 @@ describe("HoursTable SSR", () => { it("renders nothing when coming soon is enabled", () => { const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); - const html = renderToString( - - ); + const html = renderToString(); expect(consoleErrorSpy).not.toHaveBeenCalled(); expect(html).toBe(""); From 5649b24056b59ff321fc45496a567284439afdc2 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 19:08:44 +0000 Subject: [PATCH 3/4] Update snapshots --- ...nents-hoursstatus--coming-soon-translated.png | Bin 0 -> 5079 bytes .../components-hoursstatus--coming-soon.png | Bin 0 -> 5730 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/pages-components/.storybook/snapshots/__snapshots__/components-hoursstatus--coming-soon-translated.png create mode 100644 packages/pages-components/.storybook/snapshots/__snapshots__/components-hoursstatus--coming-soon.png diff --git a/packages/pages-components/.storybook/snapshots/__snapshots__/components-hoursstatus--coming-soon-translated.png b/packages/pages-components/.storybook/snapshots/__snapshots__/components-hoursstatus--coming-soon-translated.png new file mode 100644 index 0000000000000000000000000000000000000000..9d5a3d7f751548d83d1615236139a195074ba70e GIT binary patch literal 5079 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 Yqi5!vErk>zd3jHzo5e?YybcN literal 0 HcmV?d00001 From fbd36eb7684c0b8bfaa3ba6b51ea133ee60f6ac3 Mon Sep 17 00:00:00 2001 From: Alexis Sanehisa Date: Wed, 27 May 2026 15:22:31 -0400 Subject: [PATCH 4/4] test --- .../src/components/hours/hoursStatus.hydration.test.tsx | 2 +- .../src/components/hours/hoursTable.hydration.test.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx b/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx index 8b53d97f..3bcb59b3 100644 --- a/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx +++ b/packages/pages-components/src/components/hours/hoursStatus.hydration.test.tsx @@ -1,6 +1,6 @@ import { hydrateRoot } from "react-dom/client"; import { renderToString } from "react-dom/server"; -import { act } from "react"; +import { act } from "react-dom/test-utils"; import { afterEach, describe, expect, it } from "vitest"; import { DateTime, Settings } from "luxon"; import { HoursStatus } from "./hoursStatus.js"; diff --git a/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx b/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx index a9091dc6..da2677c1 100644 --- a/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx +++ b/packages/pages-components/src/components/hours/hoursTable.hydration.test.tsx @@ -1,6 +1,6 @@ import { hydrateRoot } from "react-dom/client"; import { renderToString } from "react-dom/server"; -import { act } from "react"; +import { act } from "react-dom/test-utils"; import { afterEach, describe, expect, it } from "vitest"; import { DateTime, Settings } from "luxon"; import { HoursTable, ServerSideHoursTable } from "./hoursTable.js";