mirror of
https://github.com/ansible/awx.git
synced 2026-02-26 07:26:03 -03:30
Fix rbac on Add button on User Access/Team Roles lists
This commit is contained in:
@@ -54,6 +54,12 @@ class Users extends Base {
|
|||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readAdminOfOrganizations(userId, params) {
|
||||||
|
return this.http.get(`${this.baseUrl}${userId}/admin_of_organizations/`, {
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Users;
|
export default Users;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
import { CaretLeftIcon } from '@patternfly/react-icons';
|
import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||||
import { Card, PageSection } from '@patternfly/react-core';
|
import { Card, PageSection } from '@patternfly/react-core';
|
||||||
|
import { Config } from '../../contexts/Config';
|
||||||
import RoutedTabs from '../../components/RoutedTabs';
|
import RoutedTabs from '../../components/RoutedTabs';
|
||||||
import ContentError from '../../components/ContentError';
|
import ContentError from '../../components/ContentError';
|
||||||
import TeamDetail from './TeamDetail';
|
import TeamDetail from './TeamDetail';
|
||||||
@@ -102,7 +103,11 @@ function Team({ i18n, setBreadcrumb }) {
|
|||||||
)}
|
)}
|
||||||
{team && (
|
{team && (
|
||||||
<Route path="/teams/:id/roles">
|
<Route path="/teams/:id/roles">
|
||||||
<TeamAccessList />
|
<Config>
|
||||||
|
{({ me }) => (
|
||||||
|
<>{me && <TeamAccessList me={me} team={team} />}</>
|
||||||
|
)}
|
||||||
|
</Config>
|
||||||
</Route>
|
</Route>
|
||||||
)}
|
)}
|
||||||
<Route key="not-found" path="*">
|
<Route key="not-found" path="*">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
Title,
|
Title,
|
||||||
} from '@patternfly/react-core';
|
} from '@patternfly/react-core';
|
||||||
import { CubesIcon } from '@patternfly/react-icons';
|
import { CubesIcon } from '@patternfly/react-icons';
|
||||||
import { TeamsAPI, RolesAPI } from '../../../api';
|
import { TeamsAPI, RolesAPI, UsersAPI } from '../../../api';
|
||||||
import useRequest, { useDeleteItems } from '../../../util/useRequest';
|
import useRequest, { useDeleteItems } from '../../../util/useRequest';
|
||||||
import DataListToolbar from '../../../components/DataListToolbar';
|
import DataListToolbar from '../../../components/DataListToolbar';
|
||||||
import PaginatedDataList from '../../../components/PaginatedDataList';
|
import PaginatedDataList from '../../../components/PaginatedDataList';
|
||||||
@@ -28,17 +28,16 @@ const QS_CONFIG = getQSConfig('roles', {
|
|||||||
order_by: 'id',
|
order_by: 'id',
|
||||||
});
|
});
|
||||||
|
|
||||||
function TeamRolesList({ i18n }) {
|
function TeamRolesList({ i18n, me, team }) {
|
||||||
const [isWizardOpen, setIsWizardOpen] = useState(false);
|
const [isWizardOpen, setIsWizardOpen] = useState(false);
|
||||||
const { search } = useLocation();
|
const { search } = useLocation();
|
||||||
const { id } = useParams();
|
|
||||||
const [roleToDisassociate, setRoleToDisassociate] = useState(null);
|
const [roleToDisassociate, setRoleToDisassociate] = useState(null);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
request: fetchRoles,
|
request: fetchRoles,
|
||||||
contentError,
|
contentError,
|
||||||
result: { roleCount, roles, options },
|
result: { roleCount, roles, isAdminOfOrg },
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const params = parseQueryString(QS_CONFIG, search);
|
const params = parseQueryString(QS_CONFIG, search);
|
||||||
@@ -46,18 +45,23 @@ function TeamRolesList({ i18n }) {
|
|||||||
{
|
{
|
||||||
data: { results, count },
|
data: { results, count },
|
||||||
},
|
},
|
||||||
{
|
{ count: orgAdminCount },
|
||||||
data: { actions },
|
|
||||||
},
|
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
TeamsAPI.readRoles(id, params),
|
TeamsAPI.readRoles(team.id, params),
|
||||||
TeamsAPI.readRoleOptions(id),
|
UsersAPI.readAdminOfOrganizations(me.id, {
|
||||||
|
id: team.organization,
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
return { roleCount: count, roles: results, options: actions };
|
return {
|
||||||
}, [id, search]),
|
roleCount: count,
|
||||||
|
roles: results,
|
||||||
|
isAdminOfOrg: orgAdminCount > 0,
|
||||||
|
};
|
||||||
|
}, [me.id, team.id, team.organization, search]),
|
||||||
{
|
{
|
||||||
roles: [],
|
roles: [],
|
||||||
roleCount: 0,
|
roleCount: 0,
|
||||||
|
isAdminOfOrg: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -79,14 +83,13 @@ function TeamRolesList({ i18n }) {
|
|||||||
setRoleToDisassociate(null);
|
setRoleToDisassociate(null);
|
||||||
await RolesAPI.disassociateTeamRole(
|
await RolesAPI.disassociateTeamRole(
|
||||||
roleToDisassociate.id,
|
roleToDisassociate.id,
|
||||||
parseInt(id, 10)
|
parseInt(team.id, 10)
|
||||||
);
|
);
|
||||||
}, [roleToDisassociate, id]),
|
}, [roleToDisassociate, team.id]),
|
||||||
{ qsConfig: QS_CONFIG, fetchItems: fetchRoles }
|
{ qsConfig: QS_CONFIG, fetchItems: fetchRoles }
|
||||||
);
|
);
|
||||||
|
|
||||||
const canAdd =
|
const canAdd = team?.summary_fields?.user_capabilities?.edit || isAdminOfOrg;
|
||||||
options && Object.prototype.hasOwnProperty.call(options, 'POST');
|
|
||||||
|
|
||||||
const detailUrl = role => {
|
const detailUrl = role => {
|
||||||
const { resource_id, resource_type } = role.summary_fields;
|
const { resource_id, resource_type } = role.summary_fields;
|
||||||
@@ -128,7 +131,7 @@ function TeamRolesList({ i18n }) {
|
|||||||
hasContentLoading={isLoading || isDisassociateLoading}
|
hasContentLoading={isLoading || isDisassociateLoading}
|
||||||
items={roles}
|
items={roles}
|
||||||
itemCount={roleCount}
|
itemCount={roleCount}
|
||||||
pluralizedItemName={i18n._(t`Teams`)}
|
pluralizedItemName={i18n._(t`Team Roles`)}
|
||||||
qsConfig={QS_CONFIG}
|
qsConfig={QS_CONFIG}
|
||||||
toolbarSearchColumns={[
|
toolbarSearchColumns={[
|
||||||
{
|
{
|
||||||
@@ -157,7 +160,7 @@ function TeamRolesList({ i18n }) {
|
|||||||
setIsWizardOpen(true);
|
setIsWizardOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Add
|
{i18n._(t`Add`)}
|
||||||
</Button>,
|
</Button>,
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { TeamsAPI, RolesAPI } from '../../../api';
|
import { TeamsAPI, RolesAPI, UsersAPI } from '../../../api';
|
||||||
import {
|
import {
|
||||||
mountWithContexts,
|
mountWithContexts,
|
||||||
waitForElement,
|
waitForElement,
|
||||||
@@ -9,13 +9,74 @@ import TeamRolesList from './TeamRolesList';
|
|||||||
|
|
||||||
jest.mock('../../../api/models/Teams');
|
jest.mock('../../../api/models/Teams');
|
||||||
jest.mock('../../../api/models/Roles');
|
jest.mock('../../../api/models/Roles');
|
||||||
|
jest.mock('../../../api/models/Users');
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({
|
const me = {
|
||||||
...jest.requireActual('react-router-dom'),
|
id: 1,
|
||||||
useParams: () => ({
|
};
|
||||||
id: 18,
|
|
||||||
}),
|
const team = {
|
||||||
}));
|
id: 18,
|
||||||
|
type: 'team',
|
||||||
|
url: '/api/v2/teams/1/',
|
||||||
|
related: {
|
||||||
|
created_by: '/api/v2/users/1/',
|
||||||
|
modified_by: '/api/v2/users/1/',
|
||||||
|
projects: '/api/v2/teams/1/projects/',
|
||||||
|
users: '/api/v2/teams/1/users/',
|
||||||
|
credentials: '/api/v2/teams/1/credentials/',
|
||||||
|
roles: '/api/v2/teams/1/roles/',
|
||||||
|
object_roles: '/api/v2/teams/1/object_roles/',
|
||||||
|
activity_stream: '/api/v2/teams/1/activity_stream/',
|
||||||
|
access_list: '/api/v2/teams/1/access_list/',
|
||||||
|
organization: '/api/v2/organizations/1/',
|
||||||
|
},
|
||||||
|
summary_fields: {
|
||||||
|
organization: {
|
||||||
|
id: 1,
|
||||||
|
name: 'Default',
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
created_by: {
|
||||||
|
id: 1,
|
||||||
|
username: 'admin',
|
||||||
|
first_name: '',
|
||||||
|
last_name: '',
|
||||||
|
},
|
||||||
|
modified_by: {
|
||||||
|
id: 1,
|
||||||
|
username: 'admin',
|
||||||
|
first_name: '',
|
||||||
|
last_name: '',
|
||||||
|
},
|
||||||
|
object_roles: {
|
||||||
|
admin_role: {
|
||||||
|
description: 'Can manage all aspects of the team',
|
||||||
|
name: 'Admin',
|
||||||
|
id: 33,
|
||||||
|
},
|
||||||
|
member_role: {
|
||||||
|
description: 'User is a member of the team',
|
||||||
|
name: 'Member',
|
||||||
|
id: 34,
|
||||||
|
},
|
||||||
|
read_role: {
|
||||||
|
description: 'May view settings for the team',
|
||||||
|
name: 'Read',
|
||||||
|
id: 35,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
user_capabilities: {
|
||||||
|
edit: false,
|
||||||
|
delete: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created: '2020-07-22T18:21:54.233411Z',
|
||||||
|
modified: '2020-07-22T18:21:54.233442Z',
|
||||||
|
name: 'a team',
|
||||||
|
description: '',
|
||||||
|
organization: 1,
|
||||||
|
};
|
||||||
|
|
||||||
const roles = {
|
const roles = {
|
||||||
data: {
|
data: {
|
||||||
@@ -89,32 +150,40 @@ const roles = {
|
|||||||
count: 5,
|
count: 5,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const options = {
|
|
||||||
data: { actions: { POST: { id: 1, disassociate: true } } },
|
|
||||||
};
|
|
||||||
describe('<TeamRolesList />', () => {
|
describe('<TeamRolesList />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
UsersAPI.readAdminOfOrganizations.mockResolvedValue({
|
||||||
|
count: 1,
|
||||||
|
results: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Foo Org',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
test('should render properly', async () => {
|
test('should render properly', async () => {
|
||||||
TeamsAPI.readRoles.mockResolvedValue(roles);
|
TeamsAPI.readRoles.mockResolvedValue(roles);
|
||||||
TeamsAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<TeamRolesList />);
|
wrapper = mountWithContexts(<TeamRolesList me={me} team={team} />);
|
||||||
});
|
});
|
||||||
expect(wrapper.find('TeamRolesList').length).toBe(1);
|
expect(wrapper.find('TeamRolesList').length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should create proper detailUrl', async () => {
|
test('should create proper detailUrl', async () => {
|
||||||
TeamsAPI.readRoles.mockResolvedValue(roles);
|
TeamsAPI.readRoles.mockResolvedValue(roles);
|
||||||
TeamsAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<TeamRolesList />);
|
wrapper = mountWithContexts(<TeamRolesList me={me} team={team} />);
|
||||||
});
|
});
|
||||||
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
||||||
|
|
||||||
@@ -134,9 +203,10 @@ describe('<TeamRolesList />', () => {
|
|||||||
'/inventories/smart_inventory/77/details'
|
'/inventories/smart_inventory/77/details'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test('should not render add button', async () => {
|
test('should not render add button when user cannot edit team and is not an admin of the org', async () => {
|
||||||
TeamsAPI.readRoleOptions.mockResolvedValueOnce({
|
UsersAPI.readAdminOfOrganizations.mockResolvedValueOnce({
|
||||||
data: {},
|
count: 0,
|
||||||
|
results: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
TeamsAPI.readRoles.mockResolvedValue({
|
TeamsAPI.readRoles.mockResolvedValue({
|
||||||
@@ -160,8 +230,9 @@ describe('<TeamRolesList />', () => {
|
|||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<TeamRolesList />);
|
wrapper = mountWithContexts(<TeamRolesList me={me} team={team} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
||||||
@@ -172,10 +243,9 @@ describe('<TeamRolesList />', () => {
|
|||||||
|
|
||||||
test('should render disassociate modal', async () => {
|
test('should render disassociate modal', async () => {
|
||||||
TeamsAPI.readRoles.mockResolvedValue(roles);
|
TeamsAPI.readRoles.mockResolvedValue(roles);
|
||||||
TeamsAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<TeamRolesList />);
|
wrapper = mountWithContexts(<TeamRolesList me={me} team={team} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
||||||
@@ -225,10 +295,9 @@ describe('<TeamRolesList />', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
TeamsAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<TeamRolesList />);
|
wrapper = mountWithContexts(<TeamRolesList me={me} team={team} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
||||||
@@ -282,10 +351,9 @@ describe('<TeamRolesList />', () => {
|
|||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
TeamsAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<TeamRolesList />);
|
wrapper = mountWithContexts(<TeamRolesList me={me} team={team} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(
|
waitForElement(
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ function User({ i18n, setBreadcrumb, me }) {
|
|||||||
</Route>
|
</Route>
|
||||||
{user && (
|
{user && (
|
||||||
<Route path="/users/:id/access">
|
<Route path="/users/:id/access">
|
||||||
<UserAccessList />
|
<UserAccessList user={user} />
|
||||||
</Route>
|
</Route>
|
||||||
)}
|
)}
|
||||||
<Route path="/users/:id/tokens">
|
<Route path="/users/:id/tokens">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { useParams, useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import {
|
import {
|
||||||
@@ -29,8 +29,7 @@ const QS_CONFIG = getQSConfig('roles', {
|
|||||||
// TODO Figure out how to best conduct a search of this list.
|
// TODO Figure out how to best conduct a search of this list.
|
||||||
// Since we only have a role ID in the top level of each role object
|
// Since we only have a role ID in the top level of each role object
|
||||||
// we can't really search using the normal search parameters.
|
// we can't really search using the normal search parameters.
|
||||||
function UserAccessList({ i18n }) {
|
function UserAccessList({ i18n, user }) {
|
||||||
const { id } = useParams();
|
|
||||||
const { search } = useLocation();
|
const { search } = useLocation();
|
||||||
const [isWizardOpen, setIsWizardOpen] = useState(false);
|
const [isWizardOpen, setIsWizardOpen] = useState(false);
|
||||||
|
|
||||||
@@ -51,11 +50,11 @@ function UserAccessList({ i18n }) {
|
|||||||
data: { actions },
|
data: { actions },
|
||||||
},
|
},
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
UsersAPI.readRoles(id, params),
|
UsersAPI.readRoles(user.id, params),
|
||||||
UsersAPI.readRoleOptions(id),
|
UsersAPI.readOptions(),
|
||||||
]);
|
]);
|
||||||
return { roleCount: count, roles: results, options: actions };
|
return { roleCount: count, roles: results, options: actions };
|
||||||
}, [id, search]),
|
}, [user.id, search]),
|
||||||
{
|
{
|
||||||
roles: [],
|
roles: [],
|
||||||
roleCount: 0,
|
roleCount: 0,
|
||||||
@@ -75,14 +74,15 @@ function UserAccessList({ i18n }) {
|
|||||||
setRoleToDisassociate(null);
|
setRoleToDisassociate(null);
|
||||||
await RolesAPI.disassociateUserRole(
|
await RolesAPI.disassociateUserRole(
|
||||||
roleToDisassociate.id,
|
roleToDisassociate.id,
|
||||||
parseInt(id, 10)
|
parseInt(user.id, 10)
|
||||||
);
|
);
|
||||||
}, [roleToDisassociate, id]),
|
}, [roleToDisassociate, user.id]),
|
||||||
{ qsConfig: QS_CONFIG, fetchItems: fetchRoles }
|
{ qsConfig: QS_CONFIG, fetchItems: fetchRoles }
|
||||||
);
|
);
|
||||||
|
|
||||||
const canAdd =
|
const canAdd =
|
||||||
options && Object.prototype.hasOwnProperty.call(options, 'POST');
|
user?.summary_fields?.user_capabilities?.edit ||
|
||||||
|
(options && Object.prototype.hasOwnProperty.call(options, 'POST'));
|
||||||
|
|
||||||
const saveRoles = () => {
|
const saveRoles = () => {
|
||||||
setIsWizardOpen(false);
|
setIsWizardOpen(false);
|
||||||
@@ -170,7 +170,7 @@ function UserAccessList({ i18n }) {
|
|||||||
setIsWizardOpen(true);
|
setIsWizardOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Add
|
{i18n._(t`Add`)}
|
||||||
</Button>,
|
</Button>,
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
@@ -198,7 +198,7 @@ function UserAccessList({ i18n }) {
|
|||||||
<Button
|
<Button
|
||||||
key="disassociate"
|
key="disassociate"
|
||||||
variant="danger"
|
variant="danger"
|
||||||
aria-label={i18n._(t`confirm disassociate`)}
|
aria-label={i18n._(t`Confirm disassociate`)}
|
||||||
onClick={() => disassociateRole()}
|
onClick={() => disassociateRole()}
|
||||||
>
|
>
|
||||||
{i18n._(t`Disassociate`)}
|
{i18n._(t`Disassociate`)}
|
||||||
|
|||||||
@@ -10,12 +10,25 @@ import UserAccessList from './UserAccessList';
|
|||||||
jest.mock('../../../api/models/Users');
|
jest.mock('../../../api/models/Users');
|
||||||
jest.mock('../../../api/models/Roles');
|
jest.mock('../../../api/models/Roles');
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({
|
UsersAPI.readOptions.mockResolvedValue({
|
||||||
...jest.requireActual('react-router-dom'),
|
data: {
|
||||||
useParams: () => ({
|
actions: {
|
||||||
id: 18,
|
GET: {},
|
||||||
}),
|
},
|
||||||
}));
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const user = {
|
||||||
|
id: 18,
|
||||||
|
username: 'Foo User',
|
||||||
|
summary_fields: {
|
||||||
|
user_capabilities: {
|
||||||
|
edit: true,
|
||||||
|
delete: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const roles = {
|
const roles = {
|
||||||
data: {
|
data: {
|
||||||
results: [
|
results: [
|
||||||
@@ -88,21 +101,18 @@ const roles = {
|
|||||||
count: 5,
|
count: 5,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const options = {
|
|
||||||
data: { actions: { POST: { id: 1, disassociate: true } } },
|
|
||||||
};
|
|
||||||
describe('<UserAccessList />', () => {
|
describe('<UserAccessList />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
// wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
test('should render properly', async () => {
|
test('should render properly', async () => {
|
||||||
UsersAPI.readRoles.mockResolvedValue(roles);
|
UsersAPI.readRoles.mockResolvedValue(roles);
|
||||||
UsersAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<UserAccessList />);
|
wrapper = mountWithContexts(<UserAccessList user={user} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find('UserAccessList').length).toBe(1);
|
expect(wrapper.find('UserAccessList').length).toBe(1);
|
||||||
@@ -110,13 +120,12 @@ describe('<UserAccessList />', () => {
|
|||||||
|
|
||||||
test('should create proper detailUrl', async () => {
|
test('should create proper detailUrl', async () => {
|
||||||
UsersAPI.readRoles.mockResolvedValue(roles);
|
UsersAPI.readRoles.mockResolvedValue(roles);
|
||||||
UsersAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<UserAccessList />);
|
wrapper = mountWithContexts(<UserAccessList user={user} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
wrapper.update();
|
||||||
|
|
||||||
expect(wrapper.find(`Link#userRole-2`).prop('to')).toBe(
|
expect(wrapper.find(`Link#userRole-2`).prop('to')).toBe(
|
||||||
'/templates/job_template/15/details'
|
'/templates/job_template/15/details'
|
||||||
@@ -134,11 +143,7 @@ describe('<UserAccessList />', () => {
|
|||||||
'/inventories/smart_inventory/77/details'
|
'/inventories/smart_inventory/77/details'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test('should not render add button', async () => {
|
test('should not render add button when user cannot create other users and user cannot edit this user', async () => {
|
||||||
UsersAPI.readRoleOptions.mockResolvedValueOnce({
|
|
||||||
data: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
UsersAPI.readRoles.mockResolvedValue({
|
UsersAPI.readRoles.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
results: [
|
results: [
|
||||||
@@ -177,21 +182,33 @@ describe('<UserAccessList />', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<UserAccessList />);
|
wrapper = mountWithContexts(
|
||||||
|
<UserAccessList
|
||||||
|
user={{
|
||||||
|
...user,
|
||||||
|
summary_fields: {
|
||||||
|
user_capabilities: {
|
||||||
|
edit: false,
|
||||||
|
delete: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
wrapper.update();
|
||||||
|
|
||||||
expect(wrapper.find('Button[aria-label="Add resource roles"]').length).toBe(
|
expect(wrapper.find('Button[aria-label="Add resource roles"]').length).toBe(
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test('should open and close wizard', async () => {
|
test('should open and close wizard', async () => {
|
||||||
UsersAPI.readRoles.mockResolvedValue(roles);
|
UsersAPI.readRoles.mockResolvedValue(roles);
|
||||||
UsersAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<UserAccessList />);
|
wrapper = mountWithContexts(<UserAccessList user={user} />);
|
||||||
});
|
});
|
||||||
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
wrapper.update();
|
||||||
await act(async () =>
|
await act(async () =>
|
||||||
wrapper.find('Button[aria-label="Add resource roles"]').prop('onClick')()
|
wrapper.find('Button[aria-label="Add resource roles"]').prop('onClick')()
|
||||||
);
|
);
|
||||||
@@ -205,13 +222,12 @@ describe('<UserAccessList />', () => {
|
|||||||
});
|
});
|
||||||
test('should render disassociate modal', async () => {
|
test('should render disassociate modal', async () => {
|
||||||
UsersAPI.readRoles.mockResolvedValue(roles);
|
UsersAPI.readRoles.mockResolvedValue(roles);
|
||||||
UsersAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<UserAccessList />);
|
wrapper = mountWithContexts(<UserAccessList user={user} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
wrapper.update();
|
||||||
|
|
||||||
await act(async () =>
|
await act(async () =>
|
||||||
wrapper.find('Chip[aria-label="Execute"]').prop('onClick')({
|
wrapper.find('Chip[aria-label="Execute"]').prop('onClick')({
|
||||||
@@ -234,7 +250,7 @@ describe('<UserAccessList />', () => {
|
|||||||
).toBe(1);
|
).toBe(1);
|
||||||
await act(async () =>
|
await act(async () =>
|
||||||
wrapper
|
wrapper
|
||||||
.find('button[aria-label="confirm disassociate"]')
|
.find('button[aria-label="Confirm disassociate"]')
|
||||||
.prop('onClick')()
|
.prop('onClick')()
|
||||||
);
|
);
|
||||||
expect(RolesAPI.disassociateUserRole).toBeCalledWith(4, 18);
|
expect(RolesAPI.disassociateUserRole).toBeCalledWith(4, 18);
|
||||||
@@ -257,13 +273,12 @@ describe('<UserAccessList />', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
UsersAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<UserAccessList />);
|
wrapper = mountWithContexts(<UserAccessList user={user} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
|
wrapper.update();
|
||||||
|
|
||||||
await act(async () =>
|
await act(async () =>
|
||||||
wrapper.find('Chip[aria-label="Execute"]').prop('onClick')({
|
wrapper.find('Chip[aria-label="Execute"]').prop('onClick')({
|
||||||
@@ -286,7 +301,7 @@ describe('<UserAccessList />', () => {
|
|||||||
).toBe(1);
|
).toBe(1);
|
||||||
await act(async () =>
|
await act(async () =>
|
||||||
wrapper
|
wrapper
|
||||||
.find('button[aria-label="confirm disassociate"]')
|
.find('button[aria-label="Confirm disassociate"]')
|
||||||
.prop('onClick')()
|
.prop('onClick')()
|
||||||
);
|
);
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
@@ -313,10 +328,9 @@ describe('<UserAccessList />', () => {
|
|||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
UsersAPI.readRoleOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<UserAccessList />);
|
wrapper = mountWithContexts(<UserAccessList user={user} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(
|
waitForElement(
|
||||||
|
|||||||
Reference in New Issue
Block a user