Change user permission by using a new apply button (#12346)

* Add PowerLevelSelector.tsx.
It's extracting the current behavior of the privileged users and muted of `RolesRoomSettingsTab.tsx` into a dedicated component.
It's also adding a new apply button.

* Use `PowerLevelSelector` to render privileged and muted users in `RolesRoomSettingsTab`

* Update existing tests

* Add playwright test

* Fix typo

* Fix typo
This commit is contained in:
Florian Duros 2024-03-19 14:45:23 +01:00 committed by GitHub
parent a5ed97b903
commit ddd0ec48ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 607 additions and 63 deletions

View file

@ -0,0 +1,120 @@
/*
*
* Copyright 2024 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* /
*/
import { render, screen } from "@testing-library/react";
import React, { ComponentProps } from "react";
import userEvent from "@testing-library/user-event";
import { PowerLevelSelector } from "../../../../src/components/views/settings/PowerLevelSelector";
import { stubClient } from "../../../test-utils";
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
describe("PowerLevelSelector", () => {
const matrixClient = stubClient();
const currentUser = matrixClient.getUserId()!;
const userLevels = {
[currentUser]: 100,
"@alice:server.org": 50,
"@bob:server.org": 0,
};
const renderPLS = (props: Partial<ComponentProps<typeof PowerLevelSelector>>) =>
render(
<MatrixClientContext.Provider value={matrixClient}>
<PowerLevelSelector
userLevels={userLevels}
canChangeLevels={true}
currentUserLevel={userLevels[currentUser]}
title="title"
// filter nothing by default
filter={() => true}
onClick={jest.fn()}
{...props}
>
empty label
</PowerLevelSelector>
</MatrixClientContext.Provider>,
);
it("should render", () => {
renderPLS({});
expect(screen.getByRole("group")).toMatchSnapshot();
});
it("should display only the current user", async () => {
// Display only the current user
renderPLS({ filter: (user) => user === currentUser });
// Only alice should be displayed
const userSelects = screen.getAllByRole("combobox");
expect(userSelects).toHaveLength(1);
expect(userSelects[0]).toHaveAccessibleName(currentUser);
expect(screen.getByRole("group")).toMatchSnapshot();
});
it("should be able to change the power level of the current user", async () => {
const onClick = jest.fn();
renderPLS({ onClick });
// Until the power level is changed, the apply button should be disabled
// compound button is using aria-disabled instead of the disabled attribute, we can't toBeDisabled on it
expect(screen.getByRole("button", { name: "Apply" })).toHaveAttribute("aria-disabled", "true");
const select = screen.getByRole("combobox", { name: currentUser });
// Sanity check
expect(select).toHaveValue("100");
// Change current user power level to 50
await userEvent.selectOptions(select, "50");
expect(select).toHaveValue("50");
// After the user level changes, the apply button should be enabled
expect(screen.getByRole("button", { name: "Apply" })).toHaveAttribute("aria-disabled", "false");
// Click on Apply should call onClick with the new power level
await userEvent.click(screen.getByRole("button", { name: "Apply" }));
expect(onClick).toHaveBeenCalledWith(50, currentUser);
});
it("should not be able to change the power level if `canChangeLevels` is false", async () => {
renderPLS({ canChangeLevels: false });
// The selects should be disabled
const userSelects = screen.getAllByRole("combobox");
userSelects.forEach((select) => expect(select).toBeDisabled());
});
it("should be able to change only the level of someone with a lower level", async () => {
const userLevels = {
[currentUser]: 50,
"@alice:server.org": 100,
};
renderPLS({ userLevels });
expect(screen.getByRole("combobox", { name: currentUser })).toBeEnabled();
expect(screen.getByRole("combobox", { name: "@alice:server.org" })).toBeDisabled();
});
it("should display the children if there is no user to display", async () => {
// No user to display
renderPLS({ filter: () => false });
expect(screen.getByText("empty label")).toBeInTheDocument();
});
});

View file

@ -0,0 +1,235 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PowerLevelSelector should display only the current user 1`] = `
<fieldset
class="mx_SettingsFieldset"
>
<legend
class="mx_SettingsFieldset_legend"
>
title
</legend>
<div
class="mx_SettingsFieldset_content"
>
<div
class="mx_PowerSelector"
>
<div
class="mx_Field mx_Field_select"
>
<select
data-testid="power-level-select-element"
id="mx_Field_4"
label="@userId:matrix.org"
placeholder="@userId:matrix.org"
type="text"
>
<option
data-testid="power-level-option-0"
value="0"
>
Default
</option>
<option
data-testid="power-level-option-50"
value="50"
>
Moderator
</option>
<option
data-testid="power-level-option-100"
value="100"
>
Admin
</option>
<option
data-testid="power-level-option-SELECT_VALUE_CUSTOM"
value="SELECT_VALUE_CUSTOM"
>
Custom level
</option>
</select>
<label
for="mx_Field_4"
>
@userId:matrix.org
</label>
</div>
</div>
<button
aria-disabled="true"
aria-label="Apply"
class="_button_dyfp8_17 mx_Dialog_nonDialogButton mx_PowerLevelSelector_Button"
data-kind="primary"
data-size="sm"
role="button"
tabindex="0"
>
Apply
</button>
</div>
</fieldset>
`;
exports[`PowerLevelSelector should render 1`] = `
<fieldset
class="mx_SettingsFieldset"
>
<legend
class="mx_SettingsFieldset_legend"
>
title
</legend>
<div
class="mx_SettingsFieldset_content"
>
<div
class="mx_PowerSelector"
>
<div
class="mx_Field mx_Field_select"
>
<select
data-testid="power-level-select-element"
id="mx_Field_1"
label="@bob:server.org"
placeholder="@bob:server.org"
type="text"
>
<option
data-testid="power-level-option-0"
value="0"
>
Default
</option>
<option
data-testid="power-level-option-50"
value="50"
>
Moderator
</option>
<option
data-testid="power-level-option-100"
value="100"
>
Admin
</option>
<option
data-testid="power-level-option-SELECT_VALUE_CUSTOM"
value="SELECT_VALUE_CUSTOM"
>
Custom level
</option>
</select>
<label
for="mx_Field_1"
>
@bob:server.org
</label>
</div>
</div>
<div
class="mx_PowerSelector"
>
<div
class="mx_Field mx_Field_select"
>
<select
data-testid="power-level-select-element"
id="mx_Field_2"
label="@alice:server.org"
placeholder="@alice:server.org"
type="text"
>
<option
data-testid="power-level-option-0"
value="0"
>
Default
</option>
<option
data-testid="power-level-option-50"
value="50"
>
Moderator
</option>
<option
data-testid="power-level-option-100"
value="100"
>
Admin
</option>
<option
data-testid="power-level-option-SELECT_VALUE_CUSTOM"
value="SELECT_VALUE_CUSTOM"
>
Custom level
</option>
</select>
<label
for="mx_Field_2"
>
@alice:server.org
</label>
</div>
</div>
<div
class="mx_PowerSelector"
>
<div
class="mx_Field mx_Field_select"
>
<select
data-testid="power-level-select-element"
id="mx_Field_3"
label="@userId:matrix.org"
placeholder="@userId:matrix.org"
type="text"
>
<option
data-testid="power-level-option-0"
value="0"
>
Default
</option>
<option
data-testid="power-level-option-50"
value="50"
>
Moderator
</option>
<option
data-testid="power-level-option-100"
value="100"
>
Admin
</option>
<option
data-testid="power-level-option-SELECT_VALUE_CUSTOM"
value="SELECT_VALUE_CUSTOM"
>
Custom level
</option>
</select>
<label
for="mx_Field_3"
>
@userId:matrix.org
</label>
</div>
</div>
<button
aria-disabled="true"
aria-label="Apply"
class="_button_dyfp8_17 mx_Dialog_nonDialogButton mx_PowerLevelSelector_Button"
data-kind="primary"
data-size="sm"
role="button"
tabindex="0"
>
Apply
</button>
</div>
</fieldset>
`;

View file

@ -15,10 +15,11 @@ limitations under the License.
*/
import React from "react";
import { fireEvent, render, RenderResult, screen, waitFor } from "@testing-library/react";
import { fireEvent, getByRole, render, RenderResult, screen, waitFor } from "@testing-library/react";
import { MatrixClient, EventType, MatrixEvent, Room, RoomMember, ISendEventResponse } from "matrix-js-sdk/src/matrix";
import { mocked } from "jest-mock";
import { defer } from "matrix-js-sdk/src/utils";
import userEvent from "@testing-library/user-event";
import RolesRoomSettingsTab from "../../../../../../src/components/views/settings/tabs/room/RolesRoomSettingsTab";
import { mkStubRoom, withClientContextRenderOptions, stubClient } from "../../../../../test-utils";
@ -262,6 +263,11 @@ describe("RolesRoomSettingsTab", () => {
fireEvent.change(selector, { target: { value: "50" } });
expect(selector).toHaveValue("50");
// Get the apply button of the privileged user section and click on it
const privilegedUsersSection = screen.getByRole("group", { name: "Privileged Users" });
const applyButton = getByRole(privilegedUsersSection, "button", { name: "Apply" });
await userEvent.click(applyButton);
deferred.reject("Error");
await waitFor(() => expect(selector).toHaveValue("100"));
});