mirror of
https://github.com/Novaloop-AG/healthchat-web.git
synced 2026-10-31 16:23:03 +00:00
11030ae68d
* Refactor DateSeparator using MVVM and move to shared-components
* Add a few more stories, tests and screenshots
* Use the shared component and viewmodel in element-web
* Renaming custom content property an updating snapshots
* Fix lint errors and update snapshot after merge
* Change lifecycle handling for DateSeparatoreViewModel in components where manual handling is preferrable over wrapper component.
* Move context menu from viewmodel to shared components - step 1
* Create a jump to date picker component in shared components
* Add tests for coverage and fix layout issues and roving indexes
* Make element-web use the new component
* Simplify context menu and adjusting tests
* The HTMLExport now render shared components and need a I18nContext.Provider
* Updating unit tests for context menu
* Changed to {translate: _t} to let scripts pick up translations
* Fix lint issue and updating screenshots after merge
* Update snaps for element web components
* Renaming MVVM view components with suffix View.
* Fixing problem with input date calendar icon and system dark theme
* Changed the rendering of the menu and added a separate button component
* Handle input control with useRef in onKeyDown
* Updating DateSeparator snapshots on unit tests
* Updating layout after compound Menu got a className property
* Move files to new subfolder after merge
* Updated snapshot after merge
* Updating lock file
* Updates to styling from PR review
* Updates to focus/blur functionality
* Fixed tabbing and export documentation to stories
* Updated snapshots
---------
Co-authored-by: Zack <zazi21@student.bth.se>
183 lines
7.0 KiB
TypeScript
183 lines
7.0 KiB
TypeScript
/*
|
|
* Copyright 2026 Element Creations Ltd.
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
* Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
import React from "react";
|
|
import { fireEvent, render, screen } from "@test-utils";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import { type DateSeparatorViewModel, type DateSeparatorViewSnapshot } from "./DateSeparatorView";
|
|
import { DateSeparatorContextMenuView } from "./DateSeparatorContextMenuView";
|
|
|
|
class TestDateSeparatorViewModel implements DateSeparatorViewModel {
|
|
private listeners = new Set<() => void>();
|
|
|
|
public constructor(private snapshot: DateSeparatorViewSnapshot) {}
|
|
|
|
public getSnapshot = (): DateSeparatorViewSnapshot => this.snapshot;
|
|
|
|
public subscribe = (listener: () => void): (() => void) => {
|
|
this.listeners.add(listener);
|
|
return () => this.listeners.delete(listener);
|
|
};
|
|
|
|
public onLastWeekPicked = vi.fn<() => void>();
|
|
public onLastMonthPicked = vi.fn<() => void>();
|
|
public onBeginningPicked = vi.fn<() => void>();
|
|
public onDatePicked = vi.fn<(dateString: string) => void>();
|
|
}
|
|
|
|
function renderMenu({
|
|
open = true,
|
|
jumpToEnabled = true,
|
|
onOpenChange = vi.fn<(open: boolean) => void>(),
|
|
}: {
|
|
open?: boolean;
|
|
jumpToEnabled?: boolean;
|
|
onOpenChange?: (open: boolean) => void;
|
|
} = {}): { vm: TestDateSeparatorViewModel; onOpenChange: (open: boolean) => void } {
|
|
const vm = new TestDateSeparatorViewModel({
|
|
label: "Today",
|
|
jumpToEnabled,
|
|
jumpFromDate: "2025-01-15",
|
|
});
|
|
|
|
render(
|
|
<DateSeparatorContextMenuView
|
|
vm={vm}
|
|
open={open}
|
|
onOpenChange={onOpenChange}
|
|
trigger={
|
|
<button type="button" data-testid="jump-to-trigger">
|
|
Trigger
|
|
</button>
|
|
}
|
|
/>,
|
|
);
|
|
|
|
return { vm, onOpenChange };
|
|
}
|
|
|
|
describe("DateSeparatorContextMenuView", () => {
|
|
it("renders menu actions and date picker when open", () => {
|
|
renderMenu({ open: true, jumpToEnabled: true });
|
|
|
|
expect(screen.getByTestId("jump-to-date-last-week")).toBeInTheDocument();
|
|
expect(screen.getByTestId("jump-to-date-last-month")).toBeInTheDocument();
|
|
expect(screen.getByTestId("jump-to-date-beginning")).toBeInTheDocument();
|
|
expect(screen.getByTestId("jump-to-date-picker")).toBeInTheDocument();
|
|
});
|
|
|
|
it("calls onOpenChange for opening and closing transitions", async () => {
|
|
const user = userEvent.setup();
|
|
const onOpenChange = vi.fn<(open: boolean) => void>();
|
|
|
|
renderMenu({ open: false, jumpToEnabled: true, onOpenChange });
|
|
await user.click(screen.getByTestId("jump-to-trigger"));
|
|
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
|
|
renderMenu({ open: true, jumpToEnabled: true, onOpenChange });
|
|
await user.click(screen.getByTestId("jump-to-date-last-week"));
|
|
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
});
|
|
|
|
it("wires week/month/beginning menu actions to the correct callbacks", async () => {
|
|
const user = userEvent.setup();
|
|
const { vm } = renderMenu({ open: true, jumpToEnabled: true });
|
|
|
|
await user.click(screen.getByTestId("jump-to-date-last-week"));
|
|
await user.click(screen.getByTestId("jump-to-date-last-month"));
|
|
await user.click(screen.getByTestId("jump-to-date-beginning"));
|
|
|
|
expect(vm.onLastWeekPicked).toHaveBeenCalledTimes(1);
|
|
expect(vm.onLastMonthPicked).toHaveBeenCalledTimes(1);
|
|
expect(vm.onBeginningPicked).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("submits date picker and closes the menu", async () => {
|
|
const user = userEvent.setup();
|
|
const onOpenChange = vi.fn<(open: boolean) => void>();
|
|
const { vm } = renderMenu({ open: true, jumpToEnabled: true, onOpenChange });
|
|
|
|
const dateInput = screen.getByLabelText("Pick a date to jump to");
|
|
fireEvent.input(dateInput, { target: { value: "2025-01-10" } });
|
|
await user.click(screen.getByRole("button", { name: "Go" }));
|
|
|
|
expect(vm.onDatePicked).toHaveBeenCalledWith("2025-01-10");
|
|
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
});
|
|
|
|
it("moves focus from date input to submit button on Tab", async () => {
|
|
const user = userEvent.setup();
|
|
renderMenu({ open: true, jumpToEnabled: true });
|
|
|
|
const dateInput = screen.getByLabelText("Pick a date to jump to");
|
|
const submitButton = screen.getByRole("button", { name: "Go" });
|
|
dateInput.focus();
|
|
await user.keyboard("{Tab}");
|
|
|
|
expect(submitButton).toHaveFocus();
|
|
});
|
|
|
|
it("moves focus from submit button back to date input on Shift+Tab", async () => {
|
|
const user = userEvent.setup();
|
|
renderMenu({ open: true, jumpToEnabled: true });
|
|
|
|
const dateInput = screen.getByLabelText("Pick a date to jump to");
|
|
const submitButton = screen.getByRole("button", { name: "Go" });
|
|
submitButton.focus();
|
|
await user.keyboard("{Shift>}{Tab}{/Shift}");
|
|
|
|
expect(dateInput).toHaveFocus();
|
|
});
|
|
|
|
it("closes the menu on Tab from the submit button", async () => {
|
|
const user = userEvent.setup();
|
|
const onOpenChange = vi.fn<(open: boolean) => void>();
|
|
const { vm } = renderMenu({ open: true, jumpToEnabled: true, onOpenChange });
|
|
|
|
const submitButton = screen.getByRole("button", { name: "Go" });
|
|
submitButton.focus();
|
|
await user.keyboard("{Tab}");
|
|
|
|
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
expect(vm.onDatePicked).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("submits date picker with Enter on the submit button", async () => {
|
|
const user = userEvent.setup();
|
|
const onOpenChange = vi.fn<(open: boolean) => void>();
|
|
const { vm } = renderMenu({ open: true, jumpToEnabled: true, onOpenChange });
|
|
|
|
const dateInput = screen.getByLabelText("Pick a date to jump to");
|
|
fireEvent.input(dateInput, { target: { value: "2025-01-11" } });
|
|
|
|
const submitButton = screen.getByRole("button", { name: "Go" });
|
|
submitButton.focus();
|
|
await user.keyboard("{Enter}");
|
|
|
|
expect(vm.onDatePicked).toHaveBeenCalledWith("2025-01-11");
|
|
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
});
|
|
|
|
it("submits date picker with Space on the submit button", async () => {
|
|
const user = userEvent.setup();
|
|
const onOpenChange = vi.fn<(open: boolean) => void>();
|
|
const { vm } = renderMenu({ open: true, jumpToEnabled: true, onOpenChange });
|
|
|
|
const dateInput = screen.getByLabelText("Pick a date to jump to");
|
|
fireEvent.input(dateInput, { target: { value: "2025-01-12" } });
|
|
|
|
const submitButton = screen.getByRole("button", { name: "Go" });
|
|
submitButton.focus();
|
|
await user.keyboard(" ");
|
|
|
|
expect(vm.onDatePicked).toHaveBeenCalledWith("2025-01-12");
|
|
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
});
|
|
});
|