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

Commit 44b9889

Browse files
authored
Move integrations switch (#12733)
* Move integrations switch This is the last thing to move out of 'general' now. * unused import * Move tests out to the SetIntegrationManager component * Only a decade out * Move playwright test to the new tab * Update snapshot * Update other snapshot
1 parent 19f9f98 commit 44b9889

10 files changed

+243
-141
lines changed

playwright/e2e/settings/general-user-settings-tab.spec.ts

-12
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import { test, expect } from "../../element-web-test";
1818

1919
const USER_NAME = "Bob";
2020
const USER_NAME_NEW = "Alice";
21-
const IntegrationManager = "scalar.vector.im";
2221

2322
test.describe("General user settings tab", () => {
2423
test.use({
@@ -73,17 +72,6 @@ test.describe("General user settings tab", () => {
7372
// Assert that the add button is rendered
7473
await expect(phoneNumbers.getByRole("button", { name: "Add" })).toBeVisible();
7574

76-
const setIntegrationManager = uut.locator(".mx_SetIntegrationManager");
77-
await setIntegrationManager.scrollIntoViewIfNeeded();
78-
await expect(
79-
setIntegrationManager.locator(".mx_SetIntegrationManager_heading_manager", { hasText: IntegrationManager }),
80-
).toBeVisible();
81-
// Make sure integration manager's toggle switch is enabled
82-
await expect(setIntegrationManager.locator(".mx_ToggleSwitch_enabled")).toBeVisible();
83-
await expect(setIntegrationManager.locator(".mx_SetIntegrationManager_heading_manager")).toHaveText(
84-
"Manage integrations(scalar.vector.im)",
85-
);
86-
8775
// Assert the account deactivation button is displayed
8876
const accountManagementSection = uut.getByTestId("account-management-section");
8977
await accountManagementSection.scrollIntoViewIfNeeded();

playwright/e2e/settings/security-user-settings-tab.spec.ts

+20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
Copyright 2023 Suguru Hirahara
3+
Copyright 2024 The Matrix.org Foundation C.I.C.
34
45
Licensed under the Apache License, Version 2.0 (the "License");
56
you may not use this file except in compliance with the License.
@@ -16,6 +17,8 @@ limitations under the License.
1617

1718
import { test, expect } from "../../element-web-test";
1819

20+
const IntegrationManager = "scalar.vector.im";
21+
1922
test.describe("Security user settings tab", () => {
2023
test.describe("with posthog enabled", () => {
2124
test.use({
@@ -56,5 +59,22 @@ test.describe("Security user settings tab", () => {
5659
// Assert that an input area for identity server exists
5760
await expect(setIdServer.getByRole("textbox", { name: "Enter a new identity server" })).toBeVisible();
5861
});
62+
63+
test("should enable show integrations as enabled", async ({ app, page }) => {
64+
const tab = await app.settings.openUserSettings("Security");
65+
66+
const setIntegrationManager = tab.locator(".mx_SetIntegrationManager");
67+
await setIntegrationManager.scrollIntoViewIfNeeded();
68+
await expect(
69+
setIntegrationManager.locator(".mx_SetIntegrationManager_heading_manager", {
70+
hasText: IntegrationManager,
71+
}),
72+
).toBeVisible();
73+
// Make sure integration manager's toggle switch is enabled
74+
await expect(setIntegrationManager.locator(".mx_ToggleSwitch_enabled")).toBeVisible();
75+
await expect(setIntegrationManager.locator(".mx_SetIntegrationManager_heading_manager")).toHaveText(
76+
"Manage integrations(scalar.vector.im)",
77+
);
78+
});
5979
});
6080
});

src/components/views/settings/SetIntegrationManager.tsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { SettingLevel } from "../../../settings/SettingLevel";
2525
import ToggleSwitch from "../elements/ToggleSwitch";
2626
import Heading from "../typography/Heading";
2727
import { SettingsSubsectionText } from "./shared/SettingsSubsection";
28+
import { UIFeature } from "../../../settings/UIFeature";
2829

2930
interface IProps {}
3031

@@ -71,6 +72,8 @@ export default class SetIntegrationManager extends React.Component<IProps, IStat
7172
bodyText = _t("integration_manager|use_im");
7273
}
7374

75+
if (!SettingsStore.getValue(UIFeature.Widgets)) return null;
76+
7477
return (
7578
<label
7679
className="mx_SetIntegrationManager"
@@ -79,8 +82,8 @@ export default class SetIntegrationManager extends React.Component<IProps, IStat
7982
>
8083
<div className="mx_SettingsFlag">
8184
<div className="mx_SetIntegrationManager_heading_manager">
82-
<Heading size="2">{_t("integration_manager|manage_title")}</Heading>
83-
<Heading size="3">{managerName}</Heading>
85+
<Heading size="3">{_t("integration_manager|manage_title")}</Heading>
86+
<Heading size="4">{managerName}</Heading>
8487
</div>
8588
<ToggleSwitch
8689
id="toggle_integration"

src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx

-8
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import Modal from "../../../../../Modal";
2929
import { UIFeature } from "../../../../../settings/UIFeature";
3030
import ErrorDialog, { extractErrorMessageFromError } from "../../../dialogs/ErrorDialog";
3131
import ChangePassword from "../../ChangePassword";
32-
import SetIntegrationManager from "../../SetIntegrationManager";
3332
import SettingsTab from "../SettingsTab";
3433
import { SettingsSection } from "../../shared/SettingsSection";
3534
import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection";
@@ -194,12 +193,6 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
194193
);
195194
}
196195

197-
private renderIntegrationManagerSection(): ReactNode {
198-
if (!SettingsStore.getValue(UIFeature.Widgets)) return null;
199-
200-
return <SetIntegrationManager />;
201-
}
202-
203196
public render(): React.ReactNode {
204197
let accountManagementSection: JSX.Element | undefined;
205198
const isAccountManagedExternally = !!this.state.externalAccountManagementUrl;
@@ -218,7 +211,6 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
218211
<UserPersonalInfoSettings canMake3pidChanges={this.state.canMake3pidChanges} />
219212
{this.renderAccountSection()}
220213
</SettingsSection>
221-
{this.renderIntegrationManagerSection()}
222214
{accountManagementSection}
223215
</SettingsTab>
224216
);

src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { SettingsSection } from "../../shared/SettingsSection";
4444
import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection";
4545
import { useOwnDevices } from "../../devices/useOwnDevices";
4646
import DiscoverySettings from "../../discovery/DiscoverySettings";
47+
import SetIntegrationManager from "../../SetIntegrationManager";
4748

4849
interface IIgnoredUserProps {
4950
userId: string;
@@ -376,6 +377,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
376377
return (
377378
<SettingsTab>
378379
{warning}
380+
<SetIntegrationManager />
379381
<SettingsSection heading={_t("settings|security|encryption_section")}>
380382
{secureBackup}
381383
{eventIndex}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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 { fireEvent, render, screen, within } from "@testing-library/react";
19+
import { logger } from "matrix-js-sdk/src/logger";
20+
21+
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
22+
import { SDKContext, SdkContextClass } from "../../../../src/contexts/SDKContext";
23+
import SettingsStore from "../../../../src/settings/SettingsStore";
24+
import { UIFeature } from "../../../../src/settings/UIFeature";
25+
import {
26+
getMockClientWithEventEmitter,
27+
mockClientMethodsServer,
28+
mockClientMethodsUser,
29+
flushPromises,
30+
} from "../../../test-utils";
31+
import SetIntegrationManager from "../../../../src/components/views/settings/SetIntegrationManager";
32+
import { SettingLevel } from "../../../../src/settings/SettingLevel";
33+
34+
describe("SetIntegrationManager", () => {
35+
const userId = "@alice:server.org";
36+
37+
const mockClient = getMockClientWithEventEmitter({
38+
...mockClientMethodsUser(userId),
39+
...mockClientMethodsServer(),
40+
getCapabilities: jest.fn(),
41+
getThreePids: jest.fn(),
42+
getIdentityServerUrl: jest.fn(),
43+
deleteThreePid: jest.fn(),
44+
});
45+
46+
let stores: SdkContextClass;
47+
48+
const getComponent = () => (
49+
<MatrixClientContext.Provider value={mockClient}>
50+
<SDKContext.Provider value={stores}>
51+
<SetIntegrationManager />
52+
</SDKContext.Provider>
53+
</MatrixClientContext.Provider>
54+
);
55+
56+
it("should not render manage integrations section when widgets feature is disabled", () => {
57+
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => settingName !== UIFeature.Widgets);
58+
render(getComponent());
59+
60+
expect(screen.queryByTestId("mx_SetIntegrationManager")).not.toBeInTheDocument();
61+
expect(SettingsStore.getValue).toHaveBeenCalledWith(UIFeature.Widgets);
62+
});
63+
it("should render manage integrations sections", () => {
64+
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => settingName === UIFeature.Widgets);
65+
66+
render(getComponent());
67+
68+
expect(screen.getByTestId("mx_SetIntegrationManager")).toMatchSnapshot();
69+
});
70+
it("should update integrations provisioning on toggle", () => {
71+
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => settingName === UIFeature.Widgets);
72+
jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
73+
74+
render(getComponent());
75+
76+
const integrationSection = screen.getByTestId("mx_SetIntegrationManager");
77+
fireEvent.click(within(integrationSection).getByRole("switch"));
78+
79+
expect(SettingsStore.setValue).toHaveBeenCalledWith(
80+
"integrationProvisioning",
81+
null,
82+
SettingLevel.ACCOUNT,
83+
true,
84+
);
85+
expect(within(integrationSection).getByRole("switch")).toBeChecked();
86+
});
87+
it("handles error when updating setting fails", async () => {
88+
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => settingName === UIFeature.Widgets);
89+
jest.spyOn(logger, "error").mockImplementation(() => {});
90+
91+
jest.spyOn(SettingsStore, "setValue").mockRejectedValue("oups");
92+
93+
render(getComponent());
94+
95+
const integrationSection = screen.getByTestId("mx_SetIntegrationManager");
96+
fireEvent.click(within(integrationSection).getByRole("switch"));
97+
98+
await flushPromises();
99+
100+
expect(logger.error).toHaveBeenCalledWith("Error changing integration manager provisioning");
101+
expect(logger.error).toHaveBeenCalledWith("oups");
102+
expect(within(integrationSection).getByRole("switch")).not.toBeChecked();
103+
});
104+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`SetIntegrationManager should render manage integrations sections 1`] = `
4+
<label
5+
class="mx_SetIntegrationManager"
6+
data-testid="mx_SetIntegrationManager"
7+
for="toggle_integration"
8+
>
9+
<div
10+
class="mx_SettingsFlag"
11+
>
12+
<div
13+
class="mx_SetIntegrationManager_heading_manager"
14+
>
15+
<h3
16+
class="mx_Heading_h3"
17+
>
18+
Manage integrations
19+
</h3>
20+
<h4
21+
class="mx_Heading_h4"
22+
>
23+
(scalar.vector.im)
24+
</h4>
25+
</div>
26+
<div
27+
aria-checked="false"
28+
aria-disabled="false"
29+
class="mx_AccessibleButton mx_ToggleSwitch mx_ToggleSwitch_enabled"
30+
id="toggle_integration"
31+
role="switch"
32+
tabindex="0"
33+
>
34+
<div
35+
class="mx_ToggleSwitch_ball"
36+
/>
37+
</div>
38+
</div>
39+
<div
40+
class="mx_SettingsSubsection_text"
41+
>
42+
<span>
43+
Use an integration manager
44+
<b>
45+
(scalar.vector.im)
46+
</b>
47+
to manage bots, widgets, and sticker packs.
48+
</span>
49+
</div>
50+
<div
51+
class="mx_SettingsSubsection_text"
52+
>
53+
Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.
54+
</div>
55+
</label>
56+
`;

test/components/views/settings/tabs/user/GeneralUserSettingsTab-test.tsx

-60
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
flushPromises,
2828
} from "../../../../../test-utils";
2929
import { UIFeature } from "../../../../../../src/settings/UIFeature";
30-
import { SettingLevel } from "../../../../../../src/settings/SettingLevel";
3130
import { OidcClientStore } from "../../../../../../src/stores/oidc/OidcClientStore";
3231
import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
3332

@@ -98,65 +97,6 @@ describe("<GeneralUserSettingsTab />", () => {
9897
expect(manageAccountLink.getAttribute("href")).toMatch(accountManagementLink);
9998
});
10099

101-
describe("Manage integrations", () => {
102-
it("should not render manage integrations section when widgets feature is disabled", () => {
103-
jest.spyOn(SettingsStore, "getValue").mockImplementation(
104-
(settingName) => settingName !== UIFeature.Widgets,
105-
);
106-
render(getComponent());
107-
108-
expect(screen.queryByTestId("mx_SetIntegrationManager")).not.toBeInTheDocument();
109-
expect(SettingsStore.getValue).toHaveBeenCalledWith(UIFeature.Widgets);
110-
});
111-
it("should render manage integrations sections", () => {
112-
jest.spyOn(SettingsStore, "getValue").mockImplementation(
113-
(settingName) => settingName === UIFeature.Widgets,
114-
);
115-
116-
render(getComponent());
117-
118-
expect(screen.getByTestId("mx_SetIntegrationManager")).toMatchSnapshot();
119-
});
120-
it("should update integrations provisioning on toggle", () => {
121-
jest.spyOn(SettingsStore, "getValue").mockImplementation(
122-
(settingName) => settingName === UIFeature.Widgets,
123-
);
124-
jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
125-
126-
render(getComponent());
127-
128-
const integrationSection = screen.getByTestId("mx_SetIntegrationManager");
129-
fireEvent.click(within(integrationSection).getByRole("switch"));
130-
131-
expect(SettingsStore.setValue).toHaveBeenCalledWith(
132-
"integrationProvisioning",
133-
null,
134-
SettingLevel.ACCOUNT,
135-
true,
136-
);
137-
expect(within(integrationSection).getByRole("switch")).toBeChecked();
138-
});
139-
it("handles error when updating setting fails", async () => {
140-
jest.spyOn(SettingsStore, "getValue").mockImplementation(
141-
(settingName) => settingName === UIFeature.Widgets,
142-
);
143-
jest.spyOn(logger, "error").mockImplementation(() => {});
144-
145-
jest.spyOn(SettingsStore, "setValue").mockRejectedValue("oups");
146-
147-
render(getComponent());
148-
149-
const integrationSection = screen.getByTestId("mx_SetIntegrationManager");
150-
fireEvent.click(within(integrationSection).getByRole("switch"));
151-
152-
await flushPromises();
153-
154-
expect(logger.error).toHaveBeenCalledWith("Error changing integration manager provisioning");
155-
expect(logger.error).toHaveBeenCalledWith("oups");
156-
expect(within(integrationSection).getByRole("switch")).not.toBeChecked();
157-
});
158-
});
159-
160100
describe("deactive account", () => {
161101
it("should not render section when account deactivation feature is disabled", () => {
162102
jest.spyOn(SettingsStore, "getValue").mockImplementation(

0 commit comments

Comments
 (0)