mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-29 21:15:19 +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(async (req) => req.blob())
|
||||||
.then((res) => {
|
.then((blob) => {
|
||||||
objectUrl = URL.createObjectURL(res);
|
objectUrl = URL.createObjectURL(blob);
|
||||||
setAvatarUrl(objectUrl);
|
setAvatarUrl(objectUrl);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((ex) => {
|
||||||
// Error will likely be evident from browser logs.
|
|
||||||
setAvatarUrl(undefined);
|
setAvatarUrl(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ export type SetClientParams = {
|
|||||||
|
|
||||||
const ClientContext = createContext<ClientState | undefined>(undefined);
|
const ClientContext = createContext<ClientState | undefined>(undefined);
|
||||||
|
|
||||||
|
export const ClientContextProvider = ClientContext.Provider;
|
||||||
|
|
||||||
export const useClientState = (): ClientState | undefined =>
|
export const useClientState = (): ClientState | undefined =>
|
||||||
useContext(ClientContext);
|
useContext(ClientContext);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user