Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit d108750

Browse files
committed
Tests
Signed-off-by: Michael Telatynski <[email protected]>
1 parent 6913b02 commit d108750

File tree

7 files changed

+387
-49
lines changed

7 files changed

+387
-49
lines changed

playwright/e2e/integration-manager/utils.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ import type { ElementAppPage } from "../../pages/ElementAppPage";
1919
export async function openIntegrationManager(app: ElementAppPage) {
2020
const { page } = app;
2121
await app.toggleRoomInfoPanel();
22-
await page
23-
.locator(".mx_RoomSummaryCard_appsGroup")
24-
.getByRole("button", { name: "Add widgets, bridges & bots" })
25-
.click();
22+
await page.getByRole("tab", { name: "Extensions" }).click();
23+
await page.getByRole("button", { name: "Add extensions" }).click();
2624
}

playwright/e2e/right-panel/right-panel.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ test.describe("RightPanel", () => {
7373
test("should handle clicking add widgets", async ({ page, app }) => {
7474
await viewRoomSummaryByName(page, app, ROOM_NAME);
7575

76-
await page.getByRole("button", { name: "Add widgets, bridges & bots" }).click();
76+
await page.getByRole("tab", { name: "Extensions" }).click();
77+
await page.getByRole("button", { name: "Add extensions" }).click();
7778
await expect(page.locator(".mx_IntegrationManager")).toBeVisible();
7879
});
7980

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
Copyright 2024 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from "react";
18+
import { mocked, Mocked } from "jest-mock";
19+
import { render, screen } from "@testing-library/react";
20+
import { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
21+
import { MatrixWidgetType } from "matrix-widget-api";
22+
import userEvent from "@testing-library/user-event";
23+
24+
import ExtensionsCard from "../../../../src/components/views/right_panel/ExtensionsCard";
25+
import { stubClient } from "../../../test-utils";
26+
import { IApp } from "../../../../src/stores/WidgetStore";
27+
import WidgetUtils, { useWidgets } from "../../../../src/utils/WidgetUtils";
28+
import { WidgetLayoutStore } from "../../../../src/stores/widgets/WidgetLayoutStore";
29+
import { IntegrationManagers } from "../../../../src/integrations/IntegrationManagers";
30+
31+
jest.mock("../../../../src/utils/WidgetUtils");
32+
33+
describe("<ExtensionsCard />", () => {
34+
let client: Mocked<MatrixClient>;
35+
let room: Room;
36+
37+
beforeEach(() => {
38+
client = mocked(stubClient());
39+
room = new Room("!room:server", client, client.getSafeUserId());
40+
mocked(WidgetUtils.getWidgetName).mockImplementation((app) => app?.name ?? "No Name");
41+
});
42+
43+
it("should render empty state", () => {
44+
mocked(useWidgets).mockReturnValue([]);
45+
const { asFragment } = render(<ExtensionsCard room={room} onClose={jest.fn()} />);
46+
expect(screen.getByText("Boost productivity with more tools, widgets and bots")).toBeInTheDocument();
47+
expect(asFragment()).toMatchSnapshot();
48+
});
49+
50+
it("should render widgets", async () => {
51+
mocked(useWidgets).mockReturnValue([
52+
{
53+
id: "id",
54+
roomId: room.roomId,
55+
eventId: "$event1",
56+
creatorUserId: client.getSafeUserId(),
57+
type: MatrixWidgetType.Custom,
58+
name: "Custom Widget",
59+
url: "http://url1",
60+
},
61+
{
62+
id: "jitsi",
63+
roomId: room.roomId,
64+
eventId: "$event2",
65+
creatorUserId: client.getSafeUserId(),
66+
type: MatrixWidgetType.JitsiMeet,
67+
name: "Jitsi",
68+
url: "http://jitsi",
69+
},
70+
] satisfies IApp[]);
71+
72+
const { asFragment } = render(<ExtensionsCard room={room} onClose={jest.fn()} />);
73+
expect(screen.getByText("Custom Widget")).toBeInTheDocument();
74+
expect(screen.getByText("Jitsi")).toBeInTheDocument();
75+
expect(asFragment()).toMatchSnapshot();
76+
});
77+
78+
it("should show context menu on widget row", async () => {
79+
jest.spyOn(WidgetUtils, "canUserModifyWidgets").mockReturnValue(true);
80+
mocked(useWidgets).mockReturnValue([
81+
{
82+
id: "id",
83+
roomId: room.roomId,
84+
eventId: "$event1",
85+
creatorUserId: client.getSafeUserId(),
86+
type: MatrixWidgetType.Custom,
87+
name: "Custom Widget",
88+
url: "http://url1",
89+
},
90+
] satisfies IApp[]);
91+
92+
const { container } = render(<ExtensionsCard room={room} onClose={jest.fn()} />);
93+
await userEvent.click(container.querySelector(".mx_ExtensionsCard_app_options")!);
94+
expect(document.querySelector(".mx_IconizedContextMenu")).toMatchSnapshot();
95+
});
96+
97+
it("should show set room layout button", async () => {
98+
jest.spyOn(WidgetLayoutStore.instance, "canCopyLayoutToRoom").mockReturnValue(true);
99+
mocked(useWidgets).mockReturnValue([
100+
{
101+
id: "id",
102+
roomId: room.roomId,
103+
eventId: "$event1",
104+
creatorUserId: client.getSafeUserId(),
105+
type: MatrixWidgetType.Custom,
106+
name: "Custom Widget",
107+
url: "http://url1",
108+
},
109+
] satisfies IApp[]);
110+
111+
render(<ExtensionsCard room={room} onClose={jest.fn()} />);
112+
expect(screen.getByText("Set layout for everyone")).toBeInTheDocument();
113+
});
114+
115+
it("should show widget as pinned", async () => {
116+
jest.spyOn(WidgetLayoutStore.instance, "isInContainer").mockReturnValue(true);
117+
mocked(useWidgets).mockReturnValue([
118+
{
119+
id: "id",
120+
roomId: room.roomId,
121+
eventId: "$event1",
122+
creatorUserId: client.getSafeUserId(),
123+
type: MatrixWidgetType.Custom,
124+
name: "Custom Widget",
125+
url: "http://url1",
126+
},
127+
] satisfies IApp[]);
128+
129+
render(<ExtensionsCard room={room} onClose={jest.fn()} />);
130+
expect(screen.getByText("Custom Widget").closest(".mx_ExtensionsCard_Button_pinned")).toBeInTheDocument();
131+
});
132+
133+
it("should show cannot pin warning", async () => {
134+
jest.spyOn(WidgetLayoutStore.instance, "isInContainer").mockReturnValue(false);
135+
jest.spyOn(WidgetLayoutStore.instance, "canAddToContainer").mockReturnValue(false);
136+
mocked(useWidgets).mockReturnValue([
137+
{
138+
id: "id",
139+
roomId: room.roomId,
140+
eventId: "$event1",
141+
creatorUserId: client.getSafeUserId(),
142+
type: MatrixWidgetType.Custom,
143+
name: "Custom Widget",
144+
url: "http://url1",
145+
},
146+
] satisfies IApp[]);
147+
148+
render(<ExtensionsCard room={room} onClose={jest.fn()} />);
149+
expect(screen.getByLabelText("You can only pin up to 3 widgets")).toBeInTheDocument();
150+
});
151+
152+
it("should should open integration manager on click", async () => {
153+
jest.spyOn(IntegrationManagers.sharedInstance(), "hasManager").mockReturnValue(false);
154+
const spy = jest.spyOn(IntegrationManagers.sharedInstance(), "openNoManagerDialog");
155+
render(<ExtensionsCard room={room} onClose={jest.fn()} />);
156+
await userEvent.click(screen.getByText("Add extensions"));
157+
expect(spy).toHaveBeenCalled();
158+
});
159+
});

test/components/views/right_panel/RightPanelTabs-test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ describe("<RightPanelTabs />", () => {
3838
const { container } = render(<RightPanelTabs phase={RightPanelPhases.RoomMemberList} />);
3939
expect(container).toMatchSnapshot();
4040
// Assert that the active tab is Info
41-
expect(container.querySelectorAll("[aria-selected='true'").length).toEqual(1);
42-
expect(container.querySelector("[aria-selected='true'")).toHaveAccessibleName("People");
41+
expect(container.querySelectorAll("[aria-selected='true']").length).toEqual(1);
42+
expect(container.querySelector("[aria-selected='true']")).toHaveAccessibleName("People");
4343
});
4444

4545
it("Renders nothing for some phases, eg: FilePanel", () => {
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<ExtensionsCard /> should render empty state 1`] = `
4+
<DocumentFragment>
5+
<div
6+
class="mx_BaseCard mx_ExtensionsCard"
7+
>
8+
<div
9+
class="mx_BaseCard_header"
10+
>
11+
<button
12+
class="_button_zt6rp_17 _has-icon_zt6rp_61"
13+
data-kind="secondary"
14+
data-size="sm"
15+
role="button"
16+
tabindex="0"
17+
>
18+
<div
19+
aria-hidden="true"
20+
height="20"
21+
width="20"
22+
/>
23+
Add extensions
24+
</button>
25+
</div>
26+
<div
27+
class="mx_AutoHideScrollbar"
28+
tabindex="-1"
29+
>
30+
<div
31+
class="mx_Flex mx_EmptyState"
32+
style="--mx-flex-display: flex; --mx-flex-direction: column; --mx-flex-align: center; --mx-flex-justify: center; --mx-flex-gap: var(--cpd-space-4x);"
33+
>
34+
<div
35+
height="32px"
36+
width="32px"
37+
/>
38+
<p
39+
class="_typography_yh5dq_162 _font-body-lg-semibold_yh5dq_83"
40+
>
41+
Boost productivity with more tools, widgets and bots
42+
</p>
43+
<p
44+
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59"
45+
>
46+
Select “Add extensions” to browse and add extensions to this room
47+
</p>
48+
</div>
49+
</div>
50+
</div>
51+
</DocumentFragment>
52+
`;
53+
54+
exports[`<ExtensionsCard /> should render widgets 1`] = `
55+
<DocumentFragment>
56+
<div
57+
class="mx_BaseCard mx_ExtensionsCard"
58+
>
59+
<div
60+
class="mx_BaseCard_header"
61+
>
62+
<button
63+
class="_button_zt6rp_17 _has-icon_zt6rp_61"
64+
data-kind="secondary"
65+
data-size="sm"
66+
role="button"
67+
tabindex="0"
68+
>
69+
<div
70+
aria-hidden="true"
71+
height="20"
72+
width="20"
73+
/>
74+
Add extensions
75+
</button>
76+
</div>
77+
<div
78+
class="mx_AutoHideScrollbar"
79+
tabindex="-1"
80+
>
81+
<div
82+
class="_separator_144s5_17"
83+
data-kind="primary"
84+
data-orientation="horizontal"
85+
role="separator"
86+
/>
87+
<div
88+
class="mx_BaseCard_Button mx_ExtensionsCard_Button"
89+
>
90+
<div
91+
class="mx_AccessibleButton mx_ExtensionsCard_icon_app"
92+
role="button"
93+
tabindex="0"
94+
>
95+
<span
96+
aria-label="Avatar"
97+
class="_avatar_mcap2_17 mx_BaseAvatar mx_WidgetAvatar"
98+
data-color="1"
99+
data-testid="avatar-img"
100+
data-type="round"
101+
style="--cpd-avatar-size: 24px;"
102+
>
103+
<img
104+
alt=""
105+
class="_image_mcap2_50"
106+
data-type="round"
107+
height="24px"
108+
loading="lazy"
109+
referrerpolicy="no-referrer"
110+
src="image-file-stub"
111+
width="24px"
112+
/>
113+
</span>
114+
<p
115+
class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69 mx_lineClamp"
116+
>
117+
Custom Widget
118+
</p>
119+
</div>
120+
<div
121+
aria-label="Pin"
122+
class="mx_AccessibleButton mx_ExtensionsCard_app_pinToggle"
123+
role="button"
124+
tabindex="0"
125+
/>
126+
</div>
127+
<div
128+
class="mx_BaseCard_Button mx_ExtensionsCard_Button"
129+
>
130+
<div
131+
class="mx_AccessibleButton mx_ExtensionsCard_icon_app"
132+
role="button"
133+
tabindex="0"
134+
>
135+
<span
136+
aria-label="Avatar"
137+
class="_avatar_mcap2_17 mx_BaseAvatar mx_WidgetAvatar"
138+
data-color="1"
139+
data-testid="avatar-img"
140+
data-type="round"
141+
style="--cpd-avatar-size: 24px;"
142+
>
143+
<img
144+
alt=""
145+
class="_image_mcap2_50"
146+
data-type="round"
147+
height="24px"
148+
loading="lazy"
149+
referrerpolicy="no-referrer"
150+
src="image-file-stub"
151+
width="24px"
152+
/>
153+
</span>
154+
<p
155+
class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69 mx_lineClamp"
156+
>
157+
Jitsi
158+
</p>
159+
</div>
160+
<div
161+
aria-label="Pin"
162+
class="mx_AccessibleButton mx_ExtensionsCard_app_pinToggle"
163+
role="button"
164+
tabindex="0"
165+
/>
166+
</div>
167+
</div>
168+
</div>
169+
</DocumentFragment>
170+
`;
171+
172+
exports[`<ExtensionsCard /> should show context menu on widget row 1`] = `
173+
<ul
174+
class="mx_IconizedContextMenu"
175+
role="none"
176+
>
177+
<div
178+
class="mx_IconizedContextMenu_optionList mx_IconizedContextMenu_optionList_notFirst"
179+
>
180+
<li
181+
aria-label="Remove for everyone"
182+
class="mx_AccessibleButton mx_IconizedContextMenu_item"
183+
role="menuitem"
184+
tabindex="0"
185+
>
186+
<span
187+
class="mx_IconizedContextMenu_label"
188+
>
189+
Remove for everyone
190+
</span>
191+
</li>
192+
</div>
193+
</ul>
194+
`;

0 commit comments

Comments
 (0)