element-web/apps/web/test/viewmodels/message-body/ReactionsRowViewModel-test.tsx
Zack dda9ec061b
Shared Components Restructure, Cherry Picked | Room Timeline (#32916)
* refactor(shared-components): move room timeline tree

* refactor(web): move room timeline viewmodels

* Prettier FIx

* fix(refactor): align newer imports with room timeline paths

* test(shared-components): add room timeline visual baselines

* test(shared-components): drop stale timeline baseline paths
2026-03-30 15:15:21 +00:00

106 lines
3.3 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 { type MouseEvent } from "react";
import { ReactionsRowViewModel } from "../../../src/viewmodels/room/timeline/event-tile/reactions/ReactionsRowViewModel";
describe("ReactionsRowViewModel", () => {
const createVm = (
overrides?: Partial<ConstructorParameters<typeof ReactionsRowViewModel>[0]>,
): ReactionsRowViewModel =>
new ReactionsRowViewModel({
isActionable: true,
reactionGroupCount: 10,
canReact: true,
addReactionButtonActive: false,
...overrides,
});
it("computes initial snapshot from props", () => {
const vm = createVm();
const snapshot = vm.getSnapshot();
expect(snapshot.isVisible).toBe(true);
expect(snapshot.showAllButtonVisible).toBe(true);
expect(snapshot.showAddReactionButton).toBe(true);
expect(snapshot.addReactionButtonActive).toBe(false);
});
it("hides show-all after onShowAllClick", () => {
const vm = createVm();
const listener = jest.fn();
vm.subscribe(listener);
vm.onShowAllClick();
expect(vm.getSnapshot().showAllButtonVisible).toBe(false);
expect(listener).toHaveBeenCalledTimes(1);
});
it("updates visibility when reaction group count changes", () => {
const vm = createVm();
vm.setReactionGroupCount(0);
expect(vm.getSnapshot().isVisible).toBe(false);
});
it("updates add-reaction button visibility from canReact", () => {
const vm = createVm();
vm.setCanReact(false);
expect(vm.getSnapshot().showAddReactionButton).toBe(false);
});
it("updates add-reaction active state", () => {
const vm = createVm();
vm.setAddReactionButtonActive(true);
expect(vm.getSnapshot().addReactionButtonActive).toBe(true);
});
it("forwards add-reaction handlers", () => {
const vm = createVm();
const onAddReactionClick = jest.fn();
const onAddReactionContextMenu = jest.fn();
vm.setAddReactionHandlers({
onAddReactionClick,
onAddReactionContextMenu,
});
const clickEvent = {
currentTarget: document.createElement("button"),
} as unknown as MouseEvent<HTMLButtonElement>;
vm.onAddReactionClick(clickEvent);
vm.onAddReactionContextMenu(clickEvent);
expect(onAddReactionClick).toHaveBeenCalledWith(clickEvent);
expect(onAddReactionContextMenu).toHaveBeenCalledWith(clickEvent);
});
it("doesn't emit only setters that always merge when values are unchanged", () => {
const vm = createVm();
const previousSnapshot = vm.getSnapshot();
const listener = jest.fn();
vm.subscribe(listener);
vm.setCanReact(true);
vm.setReactionGroupCount(10);
vm.setActionable(true);
vm.setAddReactionButtonActive(false);
// `setReactionGroupCount` is optimized and skips emit for unchanged derived values.
// The other setters always merge and therefore emit.
expect(listener).toHaveBeenCalledTimes(0);
expect(vm.getSnapshot()).toEqual(previousSnapshot);
});
});