Skip to content

Commit

Permalink
test(console): assign permissions to organization role
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoyijun committed Apr 18, 2024
1 parent 368385b commit 7e6e6e8
Show file tree
Hide file tree
Showing 5 changed files with 378 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState } from 'react';
import Modal from 'react-modal';
import { useSWRConfig } from 'swr';

import ModalFooter from '@/components/Guide/ModalFooter';
import ModalHeader from '@/components/Guide/ModalHeader';
Expand All @@ -19,6 +20,7 @@ type Props = {
function GuideLibraryModal({ isOpen, onClose }: Props) {
const { navigate } = useTenantPathname();
const [showCreateForm, setShowCreateForm] = useState(false);
const { mutate: mutateGlobal } = useSWRConfig();

return (
<Modal
Expand Down Expand Up @@ -51,6 +53,8 @@ function GuideLibraryModal({ isOpen, onClose }: Props) {
onClose={(newApiResource) => {
if (newApiResource) {
navigate(`/api-resources/${newApiResource.id}`);
// Should update the global cache to reflect the new resource
void mutateGlobal('api/resources');
}
setShowCreateForm(false);
}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import ExpectApiResources from '#src/ui-helpers/expect-api-resources.js';
import ExpectConsole from '#src/ui-helpers/expect-console.js';
import ExpectOrganizations from '#src/ui-helpers/expect-organizations.js';
import {
generateResourceIndicator,
generateResourceName,
generateRoleName,
generateScopeName,
} from '#src/utils.js';

const expectConsole = new ExpectConsole();
const expectApiResources = new ExpectApiResources();
const expectOrganizations = new ExpectOrganizations();

const apiResourceName = generateResourceName();
const apiResourceIndicator = generateResourceIndicator();
const apiPermissionName = generateScopeName();

const organizationPermissionName = generateScopeName();
const organizationRoleName = generateRoleName();

const dummyPermissionDescription = 'Dummy permission description';

describe('Organization RBAC', () => {
beforeAll(async () => {
await expectConsole.start();
});

it('navigates to API resources page', async () => {
await expectApiResources.gotoPage('/api-resources', 'API resources');
await expectApiResources.toExpectTableHeaders('API name', 'API Identifier');
});

it('creates an API resource', async () => {
await expectApiResources.toCreateApiResource({
name: apiResourceName,
indicator: apiResourceIndicator,
});
});

it('creates an API permission for organization role', async () => {
await expectApiResources.toCreateApiResourcePermission(
{ name: apiPermissionName, description: dummyPermissionDescription },
apiResourceName
);
});

it('navigates to the organization template', async () => {
await expectConsole.gotoPage('/organization-template', 'Organization template');
await expectConsole.toExpectTabs('Organization roles', 'Organization permissions');
await expectConsole.toExpectTableHeaders('Organization Role', 'Permissions');
});

it('creates an organization permission', async () => {
await expectOrganizations.toCreateOrganizationPermission({
name: organizationPermissionName,
description: dummyPermissionDescription,
});
});

it('creates an organization role', async () => {
await expectOrganizations.toCreateOrganizationRole({
name: organizationRoleName,
description: dummyPermissionDescription,
});
});

it('assigns organization permissions and API permissions for organization role', async () => {
await expectOrganizations.toAssignPermissionsForOrganizationRole({
organizationPermission: organizationPermissionName,
apiPermission: {
resource: apiResourceName,
permission: apiPermissionName,
},
forOrganizationRole: organizationRoleName,
});
});

// Clean up
it('deletes created resources', async () => {
// Delete created organization role
await expectOrganizations.toDeleteOrganizationRole(organizationRoleName);

// Delete created organization permissions
await expectOrganizations.toDeleteOrganizationPermission(organizationPermissionName);

// Delete created API resource
await expectApiResources.toDeleteApiResource(apiResourceName);
});
});
105 changes: 105 additions & 0 deletions packages/integration-tests/src/ui-helpers/expect-api-resources.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { cls } from '#src/utils.js';

import ExpectConsole from './expect-console.js';
import { expectToClickDetailsPageOption, expectToClickModalAction } from './index.js';

export default class ExpectApiResources extends ExpectConsole {
/**
* Go to the api resources page and create a new API resource, then assert that the URL matches
* the API resource detail page.
*
* @param {Object} params The parameters for creating the API resource.
* @param {string} params.name The name of the API resource to create.
* @param {string} params.indicator The indicator of the API resource to create.
*/
async toCreateApiResource({ name, indicator }: { name: string; indicator: string }) {
await this.gotoPage('/api-resources', 'API resources');
await this.toClickButton('Create API resource');

await this.toExpectModal('Start with tutorials');

// Click bottom button to skip tutorials
await this.toClickButton('Continue without tutorial', false);

await this.toExpectModal('Create API resource');

await this.toFillForm({
name,
indicator,
});

await this.toClick(
['.ReactModalPortal', `button${cls('primary')}`].join(' '),
'Create API resource',
false
);

this.toMatchUrl(/\/api-resources\/.+$/);
}

/**
* Go to the api resource details page by given resource name and create a new API permission, then assert the permission is created.
*
* @param {Object} params The parameters for creating the API permission.
* @param {string} params.name The name of the API permission to create.
* @param {string} params.description The description of the API permission to create.
* @param {string} forResourceName The name of the API resource for which the permission is created.
*/
async toCreateApiResourcePermission(
{
name,
description,
}: {
name: string;
description: string;
},
forResourceName: string
) {
await this.gotoPage('/api-resources', 'API resources');
await this.toExpectTableHeaders('API name', 'API Identifier');

await expect(this.page).toClick(['table', 'tbody', 'tr', 'td', `a${cls('title')}`].join(' '), {
text: forResourceName,
});

// Expect the API resource details page
await expect(this.page).toMatchElement([cls('header'), cls('metadata'), 'div'].join(' '), {
text: forResourceName,
});

await this.toClickButton('Create permission', false);

await this.toExpectModal('Create permission');

await this.toFillForm({ name, description });

await this.toClick(
['.ReactModalPortal', `button${cls('primary')}`].join(' '),
'Create permission',
false
);

await this.waitForToast(`The permission ${name} has been successfully created`);

await this.toExpectTableCell(name);
}

/**
* Go to the api resource details page by given resource name and delete the API resource.
*
* @param {string} name The name of the API resource to delete.
*/
async toDeleteApiResource(name: string) {
await this.gotoPage('/api-resources', 'API resources');
await this.toExpectTableCell(name);
await this.toClickTableCell(name);

await expectToClickDetailsPageOption(this.page, 'Delete');

await this.toExpectModal('Reminder');
await this.toFill('.ReactModalPortal input', name);

await expectToClickModalAction(this.page, 'Delete');
await this.waitForToast(`The API resource ${name} has been successfully deleted`);
}
}
27 changes: 25 additions & 2 deletions packages/integration-tests/src/ui-helpers/expect-console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ type ExpectConsoleOptions = {
tenantId?: string;
};

export type ConsoleTitle = 'Sign-in experience' | 'Organizations';
export type ConsoleTitle =
| 'Sign-in experience'
| 'Organizations'
| 'API resources'
| 'Organization template';

export default class ExpectConsole extends ExpectPage {
readonly options: Required<ExpectConsoleOptions>;
Expand Down Expand Up @@ -59,9 +63,15 @@ export default class ExpectConsole extends ExpectPage {

/**
* Navigate to a specific page in the Console.
* If the current page is the target page, it will not navigate.
*/
async gotoPage(pathname: string, title: ConsoleTitle) {
await this.navigateTo(this.buildUrl(path.join(this.options.tenantId, pathname)));
const target = this.buildUrl(path.join(this.options.tenantId, pathname));
if (this.page.url() === target.href) {
return;
}

await this.navigateTo(target);
await expect(this.page).toMatchElement(
[dcls('main'), dcls('container'), dcls('title')].join(' '),
{ text: title }
Expand Down Expand Up @@ -112,6 +122,19 @@ export default class ExpectConsole extends ExpectPage {
});
}

/**
* To click a table cell with the given text.
* @param text The text to expect, case-insensitive.
* @param shouldNavigate Whether to navigate to the page after clicking the cell.
*/
async toClickTableCell(text: string, shouldNavigate = true) {
await this.toClick(
['table', 'tbody', 'tr', 'td'].join(' '),
new RegExp(text, 'i'),
shouldNavigate
);
}

/**
* Expect a modal to appear with the given title.
*
Expand Down
Loading

0 comments on commit 7e6e6e8

Please sign in to comment.