mirror of
https://github.com/vector-im/element-call.git
synced 2026-03-31 07:00:26 +00:00
Add tests
This commit is contained in:
122
src/Avatar.test.tsx
Normal file
122
src/Avatar.test.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { afterEach, expect, test, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { FC, PropsWithChildren } from "react";
|
||||
|
||||
import { ClientContextProvider } from "./ClientContext";
|
||||
import { Avatar } from "./Avatar";
|
||||
import { mockMatrixRoomMember } from "./utils/test";
|
||||
|
||||
const TestComponent: FC<PropsWithChildren<{ client: MatrixClient }>> = ({
|
||||
client,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<ClientContextProvider
|
||||
value={{
|
||||
state: "valid",
|
||||
disconnected: false,
|
||||
supportedFeatures: {
|
||||
reactions: true,
|
||||
},
|
||||
setClient: vi.fn(),
|
||||
authenticated: {
|
||||
client,
|
||||
isPasswordlessUser: true,
|
||||
changePassword: vi.fn(),
|
||||
logout: vi.fn(),
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ClientContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
test("should just render a placeholder when the user has no avatar", () => {
|
||||
const client = vi.mocked<MatrixClient>({
|
||||
getAccessToken: () => "my-access-token",
|
||||
mxcUrlToHttp: () => vi.fn(),
|
||||
} as unknown as MatrixClient);
|
||||
|
||||
vi.spyOn(client, "mxcUrlToHttp");
|
||||
const member = mockMatrixRoomMember({
|
||||
userId: "@alice:example.org",
|
||||
getMxcAvatarUrl: () => undefined,
|
||||
});
|
||||
const displayName = "Alice";
|
||||
render(
|
||||
<TestComponent client={client}>
|
||||
<Avatar
|
||||
id={member.userId}
|
||||
name={displayName}
|
||||
size={96}
|
||||
src={member?.getMxcAvatarUrl()}
|
||||
/>
|
||||
</TestComponent>,
|
||||
);
|
||||
const element = screen.getByRole("img", { name: "@alice:example.org" });
|
||||
expect(element.tagName).toEqual("SPAN");
|
||||
expect(client.mxcUrlToHttp).toBeCalledTimes(0);
|
||||
});
|
||||
test("should attempt to fetch authenticated media", async () => {
|
||||
const expectedAuthUrl = "http://example.org/media/alice-avatar";
|
||||
const expectedObjectURL = "my-object-url";
|
||||
const accessToken = "my-access-token";
|
||||
const theBlob = new Blob([]);
|
||||
|
||||
// vitest doesn't have a implementation of create/revokeObjectURL, so we need
|
||||
// to delete the property. It's a bit odd, but it works.
|
||||
Reflect.deleteProperty(global.window.URL, "createObjectURL");
|
||||
globalThis.URL.createObjectURL = vi.fn().mockReturnValue(expectedObjectURL);
|
||||
Reflect.deleteProperty(global.window.URL, "revokeObjectURL");
|
||||
globalThis.URL.revokeObjectURL = vi.fn();
|
||||
|
||||
const fetchFn = vi.fn().mockResolvedValue({
|
||||
blob: async () => Promise.resolve(theBlob),
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchFn);
|
||||
|
||||
const client = vi.mocked<MatrixClient>({
|
||||
getAccessToken: () => accessToken,
|
||||
mxcUrlToHttp: () => vi.fn(),
|
||||
} as unknown as MatrixClient);
|
||||
|
||||
vi.spyOn(client, "mxcUrlToHttp").mockReturnValue(expectedAuthUrl);
|
||||
const member = mockMatrixRoomMember({
|
||||
userId: "@alice:example.org",
|
||||
getMxcAvatarUrl: () => "mxc://example.org/alice-avatar",
|
||||
});
|
||||
const displayName = "Alice";
|
||||
render(
|
||||
<TestComponent client={client}>
|
||||
<Avatar
|
||||
id={member.userId}
|
||||
name={displayName}
|
||||
size={96}
|
||||
src={member?.getMxcAvatarUrl()}
|
||||
/>
|
||||
</TestComponent>,
|
||||
);
|
||||
|
||||
// Fetch is asynchronous, so wait for this to resolve.
|
||||
await vi.waitUntil(() =>
|
||||
document.querySelector(`img[src='${expectedObjectURL}']`),
|
||||
);
|
||||
|
||||
expect(client.mxcUrlToHttp).toBeCalledTimes(1);
|
||||
expect(globalThis.fetch).toBeCalledWith(expectedAuthUrl, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
});
|
||||
@@ -100,12 +100,11 @@ export const Avatar: FC<Props> = ({
|
||||
},
|
||||
})
|
||||
.then(async (req) => req.blob())
|
||||
.then((res) => {
|
||||
objectUrl = URL.createObjectURL(res);
|
||||
.then((blob) => {
|
||||
objectUrl = URL.createObjectURL(blob);
|
||||
setAvatarUrl(objectUrl);
|
||||
})
|
||||
.catch(() => {
|
||||
// Error will likely be evident from browser logs.
|
||||
.catch((ex) => {
|
||||
setAvatarUrl(undefined);
|
||||
});
|
||||
|
||||
|
||||
@@ -71,6 +71,8 @@ export type SetClientParams = {
|
||||
|
||||
const ClientContext = createContext<ClientState | undefined>(undefined);
|
||||
|
||||
export const ClientContextProvider = ClientContext.Provider;
|
||||
|
||||
export const useClientState = (): ClientState | undefined =>
|
||||
useContext(ClientContext);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user