@griddo/ax 11.15.9 → 11.16.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/__tests__/components/RestrictionsModal/CurrentAccessList/CurrentAccessList.test.tsx +173 -0
- package/src/__tests__/components/RestrictionsModal/OptionsStep/OptionsStep.test.tsx +160 -0
- package/src/__tests__/components/RestrictionsModal/RestrictionsModal.test.tsx +134 -0
- package/src/__tests__/components/RestrictionsModal/RolesList/RolesList.test.tsx +234 -0
- package/src/__tests__/components/RestrictionsModal/UsersList/UsersList.test.tsx +288 -0
- package/src/__tests__/hooks/users.test.tsx +382 -0
- package/src/api/pages.tsx +24 -1
- package/src/api/sites.tsx +14 -14
- package/src/api/structuredData.tsx +17 -7
- package/src/components/Browser/index.tsx +12 -0
- package/src/components/Browser/style.tsx +5 -1
- package/src/components/ConfigPanel/Form/index.tsx +11 -10
- package/src/components/ContentItem/index.tsx +31 -0
- package/src/components/ContentItem/style.tsx +43 -0
- package/src/components/Fields/ImageField/index.tsx +2 -1
- package/src/components/Fields/RadioField/index.tsx +3 -3
- package/src/components/Fields/RadioField/style.tsx +1 -1
- package/src/components/FloatingNote/index.tsx +12 -1
- package/src/components/FloatingNote/style.tsx +2 -1
- package/src/components/Modal/style.tsx +11 -0
- package/src/components/PageFinder/SelectionListItem/index.tsx +27 -17
- package/src/components/PageFinder/index.tsx +65 -28
- package/src/components/PageFinder/style.tsx +0 -1
- package/src/components/RestrictionsModal/CurrentAccessList/index.tsx +74 -0
- package/src/components/RestrictionsModal/CurrentAccessList/style.tsx +155 -0
- package/src/components/RestrictionsModal/OptionsStep/index.tsx +55 -0
- package/src/components/RestrictionsModal/OptionsStep/style.tsx +29 -0
- package/src/components/RestrictionsModal/RolesList/RoleItem/index.tsx +54 -0
- package/src/components/RestrictionsModal/RolesList/RoleItem/style.tsx +34 -0
- package/src/components/RestrictionsModal/RolesList/index.tsx +107 -0
- package/src/components/RestrictionsModal/RolesList/style.tsx +76 -0
- package/src/components/RestrictionsModal/UsersList/UserItem/index.tsx +78 -0
- package/src/components/RestrictionsModal/UsersList/UserItem/style.tsx +73 -0
- package/src/components/RestrictionsModal/UsersList/index.tsx +151 -0
- package/src/components/RestrictionsModal/UsersList/style.tsx +55 -0
- package/src/components/RestrictionsModal/index.tsx +181 -0
- package/src/components/RestrictionsModal/style.tsx +31 -0
- package/src/components/RestrictionsModal/utils.tsx +24 -0
- package/src/components/ScheduleModal/index.tsx +32 -8
- package/src/components/SelectionComponent/index.tsx +65 -0
- package/src/components/SelectionComponent/style.tsx +69 -0
- package/src/components/TableFilters/RoleFilter/index.tsx +3 -3
- package/src/components/TableList/TableItem/style.tsx +7 -13
- package/src/components/Tabs/index.tsx +2 -1
- package/src/components/UserRolesAndSites/index.tsx +2 -2
- package/src/components/index.tsx +6 -0
- package/src/containers/PageEditor/actions.tsx +43 -0
- package/src/containers/PageEditor/constants.tsx +1 -0
- package/src/containers/PageEditor/interfaces.tsx +26 -19
- package/src/containers/PageEditor/reducer.tsx +32 -19
- package/src/containers/Users/reducer.tsx +1 -0
- package/src/helpers/forms.tsx +3 -1
- package/src/hooks/index.tsx +2 -1
- package/src/hooks/users.tsx +154 -14
- package/src/modules/ActivityLog/LogFilters/UserFilter/index.tsx +11 -12
- package/src/modules/Content/PageItem/index.tsx +17 -10
- package/src/modules/Content/index.tsx +1 -3
- package/src/modules/GlobalEditor/Editor/index.tsx +6 -0
- package/src/modules/GlobalEditor/PageBrowser/index.tsx +6 -0
- package/src/modules/GlobalEditor/Preview/index.tsx +4 -2
- package/src/modules/GlobalEditor/index.tsx +72 -45
- package/src/modules/Navigation/Menus/List/Table/ConfigPanel/Form/index.tsx +3 -5
- package/src/modules/Navigation/Menus/List/Table/ConfigPanel/index.tsx +4 -4
- package/src/modules/Navigation/Menus/List/Table/SidePanel/Form/ConnectedField/index.tsx +2 -3
- package/src/modules/Navigation/Menus/List/Table/SidePanel/Form/index.tsx +3 -4
- package/src/modules/Navigation/Menus/List/Table/SidePanel/index.tsx +5 -6
- package/src/modules/PageEditor/Editor/index.tsx +6 -0
- package/src/modules/PageEditor/PageBrowser/index.tsx +6 -0
- package/src/modules/PageEditor/Preview/index.tsx +9 -2
- package/src/modules/PageEditor/atoms.tsx +110 -3
- package/src/modules/PageEditor/index.tsx +76 -95
- package/src/modules/Settings/Integrations/IntegrationForm/index.tsx +1 -3
- package/src/modules/Sites/SitesList/GridView/GridSiteItem/style.tsx +19 -2
- package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/index.tsx +2 -2
- package/src/modules/Sites/SitesList/WelcomeModal/utils.ts +2 -2
- package/src/modules/StructuredData/Form/ConnectedField/index.tsx +2 -2
- package/src/modules/StructuredData/Form/index.tsx +120 -75
- package/src/modules/StructuredData/Form/style.tsx +7 -1
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +15 -8
- package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +15 -9
- package/src/modules/StructuredData/{StructuredDataList/StructuredDataItem/utils.tsx → utils.tsx} +16 -2
- package/src/modules/Users/Profile/atoms.tsx +62 -4
- package/src/modules/Users/Profile/index.tsx +83 -4
- package/src/modules/Users/Profile/style.tsx +60 -0
- package/src/modules/Users/UserCreate/SiteItem/RolesModal/RoleItem/index.tsx +3 -5
- package/src/modules/Users/UserCreate/SiteItem/index.tsx +2 -2
- package/src/modules/Users/UserCreate/atoms.tsx +69 -0
- package/src/modules/Users/UserCreate/index.tsx +149 -70
- package/src/modules/Users/UserCreate/style.tsx +24 -1
- package/src/modules/Users/UserForm/index.tsx +260 -146
- package/src/modules/Users/UserForm/style.tsx +13 -1
- package/src/modules/Users/UserList/UserItem/index.tsx +3 -3
- package/src/types/index.tsx +19 -6
- package/src/types/logs.tsx +1 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { ThemeProvider } from "styled-components";
|
|
2
|
+
import configureStore from "redux-mock-store";
|
|
3
|
+
import { parseTheme } from "@ax/helpers";
|
|
4
|
+
import "@testing-library/jest-dom";
|
|
5
|
+
|
|
6
|
+
import globalTheme from "@ax/themes/theme.json";
|
|
7
|
+
import RolesList from "@ax/components/RestrictionsModal/RolesList";
|
|
8
|
+
import { render, cleanup, screen, fireEvent } from "../../../../../config/jest/test-utils";
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
cleanup();
|
|
12
|
+
jest.resetAllMocks();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const mockStore = configureStore();
|
|
16
|
+
|
|
17
|
+
const initialState = {
|
|
18
|
+
users: {
|
|
19
|
+
roles: [
|
|
20
|
+
{ id: 1, name: "Admin" },
|
|
21
|
+
{ id: 2, name: "Editor" },
|
|
22
|
+
{ id: 3, name: "Viewer" },
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const defaultProps = {
|
|
28
|
+
onCancel: jest.fn(),
|
|
29
|
+
onApply: jest.fn(),
|
|
30
|
+
selectedRoleIds: [],
|
|
31
|
+
isSaving: false,
|
|
32
|
+
onResetAccess: jest.fn(),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const renderComponent = (props = defaultProps, storeState = initialState) => {
|
|
36
|
+
const store = mockStore(storeState);
|
|
37
|
+
|
|
38
|
+
return render(
|
|
39
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
40
|
+
<RolesList {...props} />
|
|
41
|
+
</ThemeProvider>,
|
|
42
|
+
{ store },
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
describe("RolesList component rendering", () => {
|
|
47
|
+
it("should render the component", () => {
|
|
48
|
+
renderComponent();
|
|
49
|
+
|
|
50
|
+
expect(screen.getByText(/Select the roles/)).toBeTruthy();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should render all available roles", () => {
|
|
54
|
+
renderComponent();
|
|
55
|
+
|
|
56
|
+
expect(screen.getByText("Admin")).toBeTruthy();
|
|
57
|
+
expect(screen.getByText("Editor")).toBeTruthy();
|
|
58
|
+
expect(screen.getByText("Viewer")).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should render the search field", () => {
|
|
62
|
+
renderComponent();
|
|
63
|
+
|
|
64
|
+
expect(screen.getByPlaceholderText("Search")).toBeTruthy();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should render the Apply button", () => {
|
|
68
|
+
renderComponent();
|
|
69
|
+
|
|
70
|
+
expect(screen.getByText("Apply")).toBeTruthy();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should render Cancel button when no roles are selected", () => {
|
|
74
|
+
renderComponent({ ...defaultProps, selectedRoleIds: [] });
|
|
75
|
+
|
|
76
|
+
expect(screen.getByText("Cancel")).toBeTruthy();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should render Reset Page Access button when roles are already selected", () => {
|
|
80
|
+
renderComponent({ ...defaultProps, selectedRoleIds: [1] });
|
|
81
|
+
|
|
82
|
+
expect(screen.getByText("Reset Page Access")).toBeTruthy();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should show Saving text and disable Apply button when isSaving is true", () => {
|
|
86
|
+
renderComponent({ ...defaultProps, isSaving: true });
|
|
87
|
+
|
|
88
|
+
const savingButton = screen.getByRole("button", { name: /Saving/ });
|
|
89
|
+
expect(savingButton).toBeTruthy();
|
|
90
|
+
expect((savingButton as HTMLButtonElement).disabled).toBe(true);
|
|
91
|
+
expect(screen.queryByText("Apply")).toBeNull();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("RolesList component search functionality", () => {
|
|
96
|
+
it("should filter roles based on search term", () => {
|
|
97
|
+
renderComponent();
|
|
98
|
+
|
|
99
|
+
const searchField = screen.getByPlaceholderText("Search") as HTMLInputElement;
|
|
100
|
+
fireEvent.change(searchField, { target: { value: "admin" } });
|
|
101
|
+
|
|
102
|
+
expect(screen.getByText("Admin")).toBeTruthy();
|
|
103
|
+
expect(screen.queryByText("Editor")).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should show Select Roles button when search is active", () => {
|
|
107
|
+
renderComponent();
|
|
108
|
+
|
|
109
|
+
const searchField = screen.getByPlaceholderText("Search") as HTMLInputElement;
|
|
110
|
+
fireEvent.change(searchField, { target: { value: "admin" } });
|
|
111
|
+
|
|
112
|
+
expect(screen.getByText("Select Roles")).toBeTruthy();
|
|
113
|
+
expect(screen.queryByText("Apply")).toBeNull();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should clear search and show apply buttons when Select Roles button is clicked", () => {
|
|
117
|
+
renderComponent();
|
|
118
|
+
|
|
119
|
+
const searchField = screen.getByPlaceholderText("Search") as HTMLInputElement;
|
|
120
|
+
fireEvent.change(searchField, { target: { value: "admin" } });
|
|
121
|
+
|
|
122
|
+
const selectButton = screen.getByText("Select Roles");
|
|
123
|
+
fireEvent.click(selectButton);
|
|
124
|
+
|
|
125
|
+
expect((searchField as HTMLInputElement).value).toBe("");
|
|
126
|
+
expect(screen.getByText("Apply")).toBeTruthy();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("RolesList component role selection", () => {
|
|
131
|
+
it("should toggle role selection when clicked", () => {
|
|
132
|
+
renderComponent();
|
|
133
|
+
|
|
134
|
+
const roleCheckboxes = screen.getAllByRole("checkbox") as HTMLInputElement[];
|
|
135
|
+
fireEvent.click(roleCheckboxes[0]);
|
|
136
|
+
|
|
137
|
+
expect(roleCheckboxes[0].checked).toBe(true);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should allow selecting multiple roles", () => {
|
|
141
|
+
renderComponent();
|
|
142
|
+
|
|
143
|
+
const roleCheckboxes = screen.getAllByRole("checkbox") as HTMLInputElement[];
|
|
144
|
+
fireEvent.click(roleCheckboxes[0]);
|
|
145
|
+
fireEvent.click(roleCheckboxes[1]);
|
|
146
|
+
|
|
147
|
+
expect(roleCheckboxes[0].checked).toBe(true);
|
|
148
|
+
expect(roleCheckboxes[1].checked).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should deselect role when clicked again", () => {
|
|
152
|
+
renderComponent();
|
|
153
|
+
|
|
154
|
+
const roleCheckboxes = screen.getAllByRole("checkbox") as HTMLInputElement[];
|
|
155
|
+
fireEvent.click(roleCheckboxes[0]);
|
|
156
|
+
expect(roleCheckboxes[0].checked).toBe(true);
|
|
157
|
+
|
|
158
|
+
fireEvent.click(roleCheckboxes[0]);
|
|
159
|
+
expect(roleCheckboxes[0].checked).toBe(false);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should preserve selected roles during search", () => {
|
|
163
|
+
renderComponent();
|
|
164
|
+
|
|
165
|
+
const roleCheckboxes = screen.getAllByRole("checkbox") as HTMLInputElement[];
|
|
166
|
+
fireEvent.click(roleCheckboxes[0]);
|
|
167
|
+
|
|
168
|
+
const searchField = screen.getByPlaceholderText("Search") as HTMLInputElement;
|
|
169
|
+
fireEvent.change(searchField, { target: { value: "editor" } });
|
|
170
|
+
|
|
171
|
+
// Clear search to see all roles again
|
|
172
|
+
fireEvent.change(searchField, { target: { value: "" } });
|
|
173
|
+
|
|
174
|
+
const allCheckboxes = screen.getAllByRole("checkbox") as HTMLInputElement[];
|
|
175
|
+
expect(allCheckboxes[0].checked).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe("RolesList component actions", () => {
|
|
180
|
+
it("should call onApply with selected role IDs when Apply button is clicked", () => {
|
|
181
|
+
const onApplyMock = jest.fn();
|
|
182
|
+
|
|
183
|
+
renderComponent({ ...defaultProps, onApply: onApplyMock });
|
|
184
|
+
|
|
185
|
+
const roleCheckboxes = screen.getAllByRole("checkbox");
|
|
186
|
+
fireEvent.click(roleCheckboxes[0]);
|
|
187
|
+
|
|
188
|
+
const applyButton = screen.getByText("Apply");
|
|
189
|
+
fireEvent.click(applyButton);
|
|
190
|
+
|
|
191
|
+
expect(onApplyMock).toBeCalledWith([1]);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("should call onCancel when Cancel button is clicked", () => {
|
|
195
|
+
const onCancelMock = jest.fn();
|
|
196
|
+
|
|
197
|
+
renderComponent({
|
|
198
|
+
...defaultProps,
|
|
199
|
+
selectedRoleIds: [],
|
|
200
|
+
onCancel: onCancelMock,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const cancelButton = screen.getByText("Cancel");
|
|
204
|
+
fireEvent.click(cancelButton);
|
|
205
|
+
|
|
206
|
+
expect(onCancelMock).toBeCalled();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("should call onResetAccess when Reset Page Access button is clicked", () => {
|
|
210
|
+
const onResetAccessMock = jest.fn();
|
|
211
|
+
|
|
212
|
+
renderComponent({
|
|
213
|
+
...defaultProps,
|
|
214
|
+
selectedRoleIds: [1],
|
|
215
|
+
onResetAccess: onResetAccessMock,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const resetButton = screen.getByText("Reset Page Access");
|
|
219
|
+
fireEvent.click(resetButton);
|
|
220
|
+
|
|
221
|
+
expect(onResetAccessMock).toBeCalled();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("should disable Reset Page Access button when isSaving is true", () => {
|
|
225
|
+
renderComponent({
|
|
226
|
+
...defaultProps,
|
|
227
|
+
selectedRoleIds: [1],
|
|
228
|
+
isSaving: true,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const resetButton = screen.getByRole("button", { name: /Reset Page Access/ });
|
|
232
|
+
expect((resetButton as HTMLButtonElement).disabled).toBe(true);
|
|
233
|
+
});
|
|
234
|
+
});
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { act } from "@testing-library/react";
|
|
2
|
+
import { ThemeProvider } from "styled-components";
|
|
3
|
+
import configureStore from "redux-mock-store";
|
|
4
|
+
import { parseTheme } from "@ax/helpers";
|
|
5
|
+
import "@testing-library/jest-dom";
|
|
6
|
+
|
|
7
|
+
import globalTheme from "@ax/themes/theme.json";
|
|
8
|
+
import UsersList from "@ax/components/RestrictionsModal/UsersList";
|
|
9
|
+
import type { IUser } from "@ax/types";
|
|
10
|
+
import { render, cleanup, screen, fireEvent } from "../../../../../config/jest/test-utils";
|
|
11
|
+
|
|
12
|
+
jest.mock("@ax/components/RestrictionsModal/utils", () => ({
|
|
13
|
+
fetchUsers: jest.fn().mockResolvedValue([
|
|
14
|
+
{ id: 1, username: "john", name: "John Doe", email: "john@example.com", failed: 0, roles: [], isSuperAdmin: false, pagePermissions: [] },
|
|
15
|
+
{ id: 2, username: "jane", name: "Jane Smith", email: "jane@example.com", failed: 0, roles: [], isSuperAdmin: false, pagePermissions: [] },
|
|
16
|
+
{ id: 3, username: "bob", name: "Bob Wilson", email: "bob@example.com", failed: 0, roles: [], isSuperAdmin: false, pagePermissions: [] },
|
|
17
|
+
]),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
cleanup();
|
|
22
|
+
jest.resetAllMocks();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const mockStore = configureStore();
|
|
26
|
+
|
|
27
|
+
const initialState = {
|
|
28
|
+
users: {
|
|
29
|
+
currentUser: { id: 1, username: "john", name: "John Doe", email: "john@example.com", failed: 0, roles: [], isSuperAdmin: false, pagePermissions: [] },
|
|
30
|
+
},
|
|
31
|
+
sites: {
|
|
32
|
+
currentSiteInfo: { id: 1 },
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const defaultProps: {
|
|
37
|
+
onCancel: jest.Mock;
|
|
38
|
+
onApply: jest.Mock;
|
|
39
|
+
selectedUserIds: number[];
|
|
40
|
+
isSaving: boolean;
|
|
41
|
+
onResetAccess: jest.Mock;
|
|
42
|
+
users: IUser[];
|
|
43
|
+
} = {
|
|
44
|
+
onCancel: jest.fn(),
|
|
45
|
+
onApply: jest.fn(),
|
|
46
|
+
selectedUserIds: [],
|
|
47
|
+
isSaving: false,
|
|
48
|
+
onResetAccess: jest.fn(),
|
|
49
|
+
users: [
|
|
50
|
+
{ id: 1, username: "john", name: "John Doe", email: "john@example.com", failed: 0, roles: [], isSuperAdmin: false, pagePermissions: [] },
|
|
51
|
+
{ id: 2, username: "jane", name: "Jane Smith", email: "jane@example.com", failed: 0, roles: [], isSuperAdmin: false, pagePermissions: [] },
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const renderComponent = (props = defaultProps, storeState = initialState) => {
|
|
56
|
+
const store = mockStore(storeState);
|
|
57
|
+
|
|
58
|
+
return render(
|
|
59
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
60
|
+
<UsersList {...props} />
|
|
61
|
+
</ThemeProvider>,
|
|
62
|
+
{ store },
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
describe("UsersList component rendering", () => {
|
|
67
|
+
it("should render the component", async () => {
|
|
68
|
+
await act(async () => {
|
|
69
|
+
renderComponent();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(screen.getByText(/Select the users/)).toBeTruthy();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should render the search field", async () => {
|
|
76
|
+
await act(async () => {
|
|
77
|
+
renderComponent();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(screen.getByPlaceholderText("Search")).toBeTruthy();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should render the Apply button", async () => {
|
|
84
|
+
await act(async () => {
|
|
85
|
+
renderComponent();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(screen.getByText("Apply")).toBeTruthy();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should render Cancel button when no users are selected", async () => {
|
|
92
|
+
await act(async () => {
|
|
93
|
+
renderComponent({ ...defaultProps, selectedUserIds: [] });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(screen.getByText("Cancel")).toBeTruthy();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should render Reset Page Access button when users are already selected", async () => {
|
|
100
|
+
await act(async () => {
|
|
101
|
+
renderComponent({ ...defaultProps, selectedUserIds: [1] });
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(screen.getByText("Reset Page Access")).toBeTruthy();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should show Saving text and disable Apply button when isSaving is true", async () => {
|
|
108
|
+
await act(async () => {
|
|
109
|
+
renderComponent({ ...defaultProps, isSaving: true });
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const savingButton = screen.getByRole("button", { name: /Saving/ });
|
|
113
|
+
expect(savingButton).toBeTruthy();
|
|
114
|
+
expect((savingButton as HTMLButtonElement).disabled).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should show ACCESS TO section when users are selected", async () => {
|
|
118
|
+
await act(async () => {
|
|
119
|
+
renderComponent({
|
|
120
|
+
...defaultProps,
|
|
121
|
+
users: [{ id: 2, username: "jane", name: "Jane Smith", email: "jane@example.com", failed: 0, roles: [], isSuperAdmin: false, pagePermissions: [] }],
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// The section renders when search is empty and users are selected
|
|
126
|
+
expect(screen.queryByText(/Select the users/)).toBeTruthy();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should show AVAILABLE USERS section", async () => {
|
|
130
|
+
await act(async () => {
|
|
131
|
+
renderComponent();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
expect(screen.getByText("AVAILABLE USERS")).toBeTruthy();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("UsersList component search functionality", () => {
|
|
139
|
+
it("should show Select Users button when search has value", async () => {
|
|
140
|
+
renderComponent();
|
|
141
|
+
|
|
142
|
+
const searchField = screen.getByPlaceholderText("Search") as HTMLInputElement;
|
|
143
|
+
|
|
144
|
+
await act(async () => {
|
|
145
|
+
fireEvent.change(searchField, { target: { value: "test" } });
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// When search is active, the button label changes
|
|
149
|
+
const selectButton = screen.queryByRole("button", { name: /Select Users/ });
|
|
150
|
+
expect(selectButton).toBeTruthy();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("should clear search when Select Users button is clicked", async () => {
|
|
154
|
+
renderComponent();
|
|
155
|
+
|
|
156
|
+
const searchField = screen.getByPlaceholderText("Search") as HTMLInputElement;
|
|
157
|
+
|
|
158
|
+
await act(async () => {
|
|
159
|
+
fireEvent.change(searchField, { target: { value: "test" } });
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const selectButton = screen.getByRole("button", { name: /Select Users/ });
|
|
163
|
+
|
|
164
|
+
await act(async () => {
|
|
165
|
+
fireEvent.click(selectButton);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
expect((searchField as HTMLInputElement).value).toBe("");
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe("UsersList component user selection", () => {
|
|
173
|
+
it("should render user checkboxes", async () => {
|
|
174
|
+
renderComponent();
|
|
175
|
+
|
|
176
|
+
const checkboxes = screen.getAllByRole("checkbox");
|
|
177
|
+
expect(checkboxes.length).toBeGreaterThan(0);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should select and deselect users", async () => {
|
|
181
|
+
renderComponent();
|
|
182
|
+
|
|
183
|
+
const checkboxes = screen.getAllByRole("checkbox") as HTMLInputElement[];
|
|
184
|
+
fireEvent.click(checkboxes[0]);
|
|
185
|
+
expect(checkboxes[0].checked).toBe(true);
|
|
186
|
+
|
|
187
|
+
fireEvent.click(checkboxes[0]);
|
|
188
|
+
expect(checkboxes[0].checked).toBe(false);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should call onApply with selected user IDs when Apply button is clicked", async () => {
|
|
192
|
+
const onApplyMock = jest.fn();
|
|
193
|
+
|
|
194
|
+
renderComponent({ ...defaultProps, onApply: onApplyMock });
|
|
195
|
+
|
|
196
|
+
const checkboxes = screen.getAllByRole("checkbox");
|
|
197
|
+
if (checkboxes.length > 0) {
|
|
198
|
+
fireEvent.click(checkboxes[0]);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const applyButton = screen.getByText("Apply");
|
|
202
|
+
fireEvent.click(applyButton);
|
|
203
|
+
|
|
204
|
+
expect(onApplyMock).toBeCalled();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should include current user when applying selection", async () => {
|
|
208
|
+
const onApplyMock = jest.fn();
|
|
209
|
+
|
|
210
|
+
renderComponent({
|
|
211
|
+
...defaultProps,
|
|
212
|
+
users: [{ id: 2, username: "jane", name: "Jane Smith", email: "jane@example.com", failed: 0, roles: [], isSuperAdmin: false, pagePermissions: [] }],
|
|
213
|
+
onApply: onApplyMock,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const applyButton = screen.getByText("Apply");
|
|
217
|
+
fireEvent.click(applyButton);
|
|
218
|
+
|
|
219
|
+
// Current user (id: 1) should always be included
|
|
220
|
+
const callArgs = onApplyMock.mock.calls[0][0];
|
|
221
|
+
expect(callArgs).toContain(1);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe("UsersList component actions", () => {
|
|
226
|
+
it("should call onCancel when Cancel button is clicked", async () => {
|
|
227
|
+
const onCancelMock = jest.fn();
|
|
228
|
+
|
|
229
|
+
await act(async () => {
|
|
230
|
+
renderComponent({
|
|
231
|
+
...defaultProps,
|
|
232
|
+
selectedUserIds: [],
|
|
233
|
+
onCancel: onCancelMock,
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const cancelButton = screen.getByText("Cancel");
|
|
238
|
+
|
|
239
|
+
await act(async () => {
|
|
240
|
+
fireEvent.click(cancelButton);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
expect(onCancelMock).toBeCalled();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("should call onResetAccess when Reset Page Access button is clicked", () => {
|
|
247
|
+
const onResetAccessMock = jest.fn();
|
|
248
|
+
|
|
249
|
+
renderComponent({
|
|
250
|
+
...defaultProps,
|
|
251
|
+
selectedUserIds: [1],
|
|
252
|
+
onResetAccess: onResetAccessMock,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
const resetButton = screen.getByText("Reset Page Access");
|
|
256
|
+
fireEvent.click(resetButton);
|
|
257
|
+
|
|
258
|
+
expect(onResetAccessMock).toBeCalled();
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("should disable Reset Page Access button when isSaving is true", () => {
|
|
262
|
+
renderComponent({
|
|
263
|
+
...defaultProps,
|
|
264
|
+
selectedUserIds: [1],
|
|
265
|
+
isSaving: true,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const resetButton = screen.getByRole("button", { name: /Reset Page Access/ });
|
|
269
|
+
expect((resetButton as HTMLButtonElement).disabled).toBe(true);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("should ensure current user is always included in apply", async () => {
|
|
273
|
+
const onApplyMock = jest.fn();
|
|
274
|
+
|
|
275
|
+
renderComponent({
|
|
276
|
+
...defaultProps,
|
|
277
|
+
users: [{ id: 2, username: "jane", name: "Jane Smith", email: "jane@example.com", failed: 0, roles: [], isSuperAdmin: false, pagePermissions: [] }],
|
|
278
|
+
onApply: onApplyMock,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
const applyButton = screen.getByText("Apply");
|
|
282
|
+
fireEvent.click(applyButton);
|
|
283
|
+
|
|
284
|
+
// Current user (id: 1) should be included along with any selected users
|
|
285
|
+
const callArgs = onApplyMock.mock.calls[0][0];
|
|
286
|
+
expect(callArgs).toContain(1);
|
|
287
|
+
});
|
|
288
|
+
});
|