mirror of
https://github.com/vector-im/element-web.git
synced 2026-04-16 11:02:13 +02:00
* resolve undefined this in onClick handler * add regression test for bound DisambiguatedProfileViewModel onClick * Update docs * add regression for sender profile click mention insertion * Eslint Fix (cherry picked from commit 134c7cde46447bf865fe1b3b136d2c1c4c6eb64f) Co-authored-by: Zack <zazi21@student.bth.se>
This commit is contained in:
parent
faf3278a8e
commit
d19208bee3
14
docs/MVVM.md
14
docs/MVVM.md
@ -127,6 +127,20 @@ export class FooViewModel extends BaseViewModel<FooViewSnapshot, Props> implemen
|
||||
}
|
||||
```
|
||||
|
||||
#### Binding of View Model Actions:
|
||||
|
||||
All view model actions must be defined as arrow functions to ensure they are bound to the class instance.
|
||||
|
||||
Using standard class methods can result in `this` being undefined when the function is passed as a callback (e.g. to a React event handler), which may cause runtime errors.
|
||||
|
||||
Correct pattern:
|
||||
|
||||
```ts
|
||||
public doSomething = (): void => {
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
### `useViewModel` hook
|
||||
|
||||
Your view must call this hook with the view-model as argument. Think of this as your view subscribing to the view model.<br>
|
||||
|
||||
@ -1008,6 +1008,34 @@ test.describe("Timeline", () => {
|
||||
await expect(page.getByRole("button", { name: "Show video" })).toBeVisible();
|
||||
await expect(page.locator("video")).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("should insert a mention when clicking sender profile in timeline", async ({
|
||||
page,
|
||||
app,
|
||||
homeserver,
|
||||
room,
|
||||
}) => {
|
||||
const senderDisplayName = "SenderBot";
|
||||
const messageFromSender = "message from sender";
|
||||
|
||||
const bot = new Bot(page, homeserver, {
|
||||
displayName: senderDisplayName,
|
||||
autoAcceptInvites: false,
|
||||
});
|
||||
await bot.prepareClient();
|
||||
await app.client.inviteUser(room.roomId, bot.credentials.userId);
|
||||
await bot.joinRoom(room.roomId);
|
||||
await bot.sendMessage(room.roomId, messageFromSender);
|
||||
|
||||
await app.viewRoomById(room.roomId);
|
||||
|
||||
const senderMessageTile = getEventTilesWithBodies(page).filter({ hasText: messageFromSender }).first();
|
||||
await expect(senderMessageTile).toBeVisible();
|
||||
|
||||
await senderMessageTile.locator(".mx_DisambiguatedProfile").click();
|
||||
|
||||
await expect(app.getComposerField().getByText(senderDisplayName)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("message sending", { tag: ["@no-firefox", "@no-webkit"] }, () => {
|
||||
|
||||
@ -141,7 +141,7 @@ export class DisambiguatedProfileViewModel
|
||||
this.snapshot.set(DisambiguatedProfileViewModel.computeSnapshot(this.props));
|
||||
}
|
||||
|
||||
public onClick(evt: MouseEvent<HTMLDivElement>): void {
|
||||
public onClick = (evt: MouseEvent<HTMLDivElement>): void => {
|
||||
this.props.onClick?.(evt);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -75,13 +75,27 @@ describe("DisambiguatedProfileViewModel", () => {
|
||||
const subscriber = jest.fn();
|
||||
|
||||
vm.subscribe(subscriber);
|
||||
onClick({} as never);
|
||||
vm.onClick?.({} as never);
|
||||
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
expect(subscriber).not.toHaveBeenCalled();
|
||||
expect(vm.getSnapshot()).toBe(prevSnapshot);
|
||||
});
|
||||
|
||||
it("should keep onClick bound when extracted as a callback", () => {
|
||||
const onClick = jest.fn();
|
||||
const vm = new DisambiguatedProfileViewModel({
|
||||
member,
|
||||
fallbackName: "Fallback",
|
||||
onClick,
|
||||
});
|
||||
|
||||
const clickHandler = vm.onClick;
|
||||
|
||||
expect(() => clickHandler?.({} as never)).not.toThrow();
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should emit snapshot update when fallbackName changes", () => {
|
||||
const vm = new DisambiguatedProfileViewModel({
|
||||
member: null,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user