Add user status on user profile icon (#33653)

* Add user status on user profile icon

Currently unstyled & no tests

* Style the user status icon

* Update snapshot

for avatar wrapper

* More snapshot updates

* add if braces

* Split out user status functions

to avoid circular dep which has the weird effect of just breaking
jest's mocking.

* type imports

* Update imports

* Update snapshot

* Tests

* baseline image

* Just snapshot the component itself

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
David Baker
2026-06-04 15:15:19 +00:00
committed by GitHub
co-authored by Michael Telatynski
parent f65a53a174
commit bb07f84e41
17 changed files with 398 additions and 169 deletions
@@ -6,12 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import { type MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
import { ClientEvent, type MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
import { type MockedObject, mocked } from "jest-mock";
import { stubClient } from "../../test-utils";
import { OwnProfileStore } from "../../../src/stores/OwnProfileStore";
import { UPDATE_EVENT } from "../../../src/stores/AsyncStore";
import SettingsStore from "../../../src/settings/SettingsStore";
describe("OwnProfileStore", () => {
let client: MockedObject<MatrixClient>;
@@ -76,4 +77,61 @@ describe("OwnProfileStore", () => {
expect(ownProfileStore.displayName).toBe(client.getSafeUserId());
expect(ownProfileStore.avatarMxc).toBeNull();
});
describe("userStatus", () => {
beforeEach(() => {
client.getProfileInfo.mockResolvedValue({});
});
it("should be undefined if the feature is disabled", async () => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
await ownProfileStore.start();
expect(ownProfileStore.userStatus).toBeUndefined();
});
it("should be undefined if no status is set", async () => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
client.getExtendedProfileProperty.mockResolvedValue(undefined);
await ownProfileStore.start();
expect(ownProfileStore.userStatus).toBeUndefined();
});
it("should fetch and expose the user status on start", async () => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
client.getExtendedProfileProperty.mockResolvedValue({ emoji: "🏝️", text: "On a tropical holiday" });
await ownProfileStore.start();
expect(client.getExtendedProfileProperty).toHaveBeenCalledWith(
client.getSafeUserId(),
"org.matrix.msc4426.status",
);
expect(ownProfileStore.userStatus).toEqual({ emoji: "🏝️", text: "On a tropical holiday" });
});
it("should update the user status when a UserProfileUpdate event is received for the current user", async () => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
client.getExtendedProfileProperty.mockResolvedValue({ emoji: "🏝️", text: "On a tropical holiday" });
await ownProfileStore.start();
client.getExtendedProfileProperty.mockResolvedValue({ emoji: "🏡", text: "Back home" });
client.emit(ClientEvent.UserProfileUpdate, client.getSafeUserId(), null);
await new Promise(process.nextTick);
expect(ownProfileStore.userStatus).toEqual({ emoji: "🏡", text: "Back home" });
});
it("should not update the user status when a UserProfileUpdate event is received for another user", async () => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
client.getExtendedProfileProperty.mockResolvedValue({ emoji: "🏝️", text: "On a tropical holiday" });
await ownProfileStore.start();
client.getExtendedProfileProperty.mockResolvedValue({ emoji: "🐭", text: "Is a mouse" });
client.emit(ClientEvent.UserProfileUpdate, "@other:example.com", null);
await new Promise(process.nextTick);
expect(ownProfileStore.userStatus).toEqual({ emoji: "🏝️", text: "On a tropical holiday" });
});
});
});