diff --git a/tests/e2e/tests/settings/rbac/actions/assign-role-to-user.spec.ts b/tests/e2e/tests/settings/rbac/actions/assign-role-to-user.spec.ts new file mode 100644 index 0000000000..542ca1a8e2 --- /dev/null +++ b/tests/e2e/tests/settings/rbac/actions/assign-role-to-user.spec.ts @@ -0,0 +1,60 @@ +import { test, expect, type Page } from '@playwright/test'; + +import { sharedSetup } from '../../../../utils/setup'; +import { navToHeader, clickAndWait } from '../../../../utils/shared'; + +// Constants for the created role +const TARGET_USER = { firstName: 'Editor', lastName: 'Testing' }; +const ROLES = { new: 'Author', old: 'Editor' }; + +test.describe('RBAC - Assign Role to Users', () => { + // Runs before each test + test.beforeEach(async ({ page }) => { + // Perform shared setup to reset the database, log in, and prepare the environment + await sharedSetup('rbac-assign-roles-to-user', page, { + login: true, + resetFiles: true, + importData: 'with-admin.tar', + skipTour: true, + }); + + // Navigate to the Users management page + await navToHeader(page, ['Settings', ['Administration Panel', 'Users']], 'Users'); + }); + + // Test for verifying Super Admin can create a new role + test('Super Admin can assign a role to any user', async ({ page }) => { + const userFullName = `${TARGET_USER.firstName} ${TARGET_USER.lastName}`; + + // Step 1: find the "Editor" user + const editorRowLocator = page.getByRole('row', { name: userFullName }); + + // Step 2: go to the user view, wait for the page to load + await clickAndWait(page, editorRowLocator.getByRole('link', { name: `Edit ${userFullName}` })); + + // Step 3: update the user's roles + // Open the role selection list + await page.getByLabel("User's roles*").locator('svg').last().click(); + // Remove the Editor role + await page.getByRole('listbox').getByLabel(ROLES.old).locator('button').uncheck(); + // Add the Author role + await page.getByRole('listbox').getByLabel(ROLES.new).locator('button').check(); + + // Exit the roles' selection list context + await page.keyboard.press('Escape'); + + // Step 3: save the modifications + await clickAndWait(page, page.getByRole('button', { name: 'Save' })); + + // Step 4: navigate back to the Users management page + await navToHeader(page, ['Settings', ['Administration Panel', 'Users']], 'Users'); + + // Step 5: make sure the user has the correct role and that the old one has been removed + await expect( + page.getByRole('row', { name: `${userFullName} editor@testing.com ${ROLES.old}` }) + ).not.toBeVisible(); + await expect( + page.getByRole('row', { name: `${userFullName} editor@testing.com ${ROLES.new}` }) + ).toBeVisible(); + }); +}); diff --git a/tests/e2e/tests/settings/rbac/actions/create-role.spec.ts b/tests/e2e/tests/settings/rbac/actions/create-role.spec.ts new file mode 100644 index 0000000000..e30052d834 --- /dev/null +++ b/tests/e2e/tests/settings/rbac/actions/create-role.spec.ts @@ -0,0 +1,56 @@ +import { test, expect, type Page } from '@playwright/test'; + +import { sharedSetup } from '../../../../utils/setup'; +import { navToHeader, clickAndWait } from '../../../../utils/shared'; + +// Constants for the created role +const NEW_ROLE = { name: 'Publisher', description: 'Role with publishing capabilities' }; + +/** + * Navigate to the Roles management settings via the menu + */ +const goToAdminRolesPage = async (page: Page) => { + await navToHeader(page, ['Settings', ['Administration Panel', 'Roles']], 'Roles'); +}; + +test.describe('RBAC - Create Roles', () => { + // Runs before each test + test.beforeEach(async ({ page }) => { + // Perform shared setup to reset the database, log in, and prepare the environment + await sharedSetup('rbac-roles', page, { + login: true, + resetFiles: true, + importData: 'with-admin.tar', + skipTour: true, + }); + + // Navigate to the Roles management page + await goToAdminRolesPage(page); + }); + + // Test for verifying Super Admin can create a new role + test('Super Admin can create a new role', async ({ page }) => { + // Step 1: click "Create new role" + await clickAndWait(page, page.getByRole('button', { name: 'Add new role' }).first()); + + // Step 2: fill in the role name and description + await page.getByRole('textbox', { name: 'Name' }).fill(NEW_ROLE.name); + await page.getByRole('textbox', { name: 'Description' }).fill(NEW_ROLE.description); + + // Step 3: assign the public "publish" permission for articles + await page.getByRole('tab', { name: 'Collection Types' }).click(); // Select permissions tab + await page.getByRole('checkbox', { name: 'Select Publish article' }).check(); + + // Step 4: save the newly created role + await clickAndWait(page, page.getByRole('button', { name: 'Save' })); + + // Step 5: verify the newly created role in the list + await goToAdminRolesPage(page); // Go back to the Roles management page + + const roleLocator = page.getByRole('row', { name: NEW_ROLE.name }); + + await expect(roleLocator).toBeVisible(); + await expect(roleLocator.getByRole('gridcell', { name: NEW_ROLE.name })).toBeVisible(); + await expect(roleLocator.getByRole('gridcell', { name: NEW_ROLE.description })).toBeVisible(); + }); +}); diff --git a/tests/e2e/tests/settings/rbac/actions/delete-role.spec.ts b/tests/e2e/tests/settings/rbac/actions/delete-role.spec.ts new file mode 100644 index 0000000000..65abf353d7 --- /dev/null +++ b/tests/e2e/tests/settings/rbac/actions/delete-role.spec.ts @@ -0,0 +1,38 @@ +import { test, expect } from '@playwright/test'; + +import { sharedSetup } from '../../../../utils/setup'; +import { navToHeader, clickAndWait } from '../../../../utils/shared'; + +test.describe('RBAC - Delete Roles', () => { + // Runs before each test + test.beforeEach(async ({ page }) => { + // Perform shared setup to reset the database, log in, and prepare the environment + await sharedSetup('rbac-roles', page, { + login: true, + resetFiles: true, + importData: 'with-admin.tar', + skipTour: true, + }); + + // Navigate to the Roles management page + await navToHeader(page, ['Settings', ['Administration Panel', 'Roles']], 'Roles'); + }); + + // Test for verifying Super Admin can delete an existing role + test('Super Admin can delete an existing role', async ({ page }) => { + // Step 1: locate the "Author" role row + const authorRowLocator = page.getByRole('row', { name: 'Author' }); + + // Step 2: delete the role + await authorRowLocator.getByRole('button', { name: 'Delete' }).click(); + + // Step 3: confirm deletion in the alert dialog + await clickAndWait( + page, + page.getByRole('alertdialog').getByRole('button', { name: 'Confirm' }) + ); + + // Step 4: verify the role no longer appears in the list + await expect(page.getByRole('row', { name: 'Author', exact: true })).not.toBeVisible(); + }); +}); diff --git a/tests/e2e/tests/settings/rbac/actions/edit-role.spec.ts b/tests/e2e/tests/settings/rbac/actions/edit-role.spec.ts new file mode 100644 index 0000000000..b7ad39634e --- /dev/null +++ b/tests/e2e/tests/settings/rbac/actions/edit-role.spec.ts @@ -0,0 +1,67 @@ +import { test, expect, type Page } from '@playwright/test'; + +import { sharedSetup } from '../../../../utils/setup'; +import { navToHeader, clickAndWait } from '../../../../utils/shared'; + +// Constants for the edited role +const EDITED_ROLE = { name: 'Contractor', description: 'Role with contractor capabilities' }; + +/** + * Navigate to the Roles management settings via the menu + */ +const goToAdminRolesPage = async (page: Page) => { + await navToHeader(page, ['Settings', ['Administration Panel', 'Roles']], 'Roles'); +}; + +test.describe('RBAC - Edit Roles', () => { + // Runs before each test + test.beforeEach(async ({ page }) => { + // Perform shared setup to reset the database, log in, and prepare the environment + await sharedSetup('rbac-edit-roles', page, { + login: true, + resetFiles: true, + importData: 'with-admin.tar', + skipTour: true, + }); + + // Navigate to the Roles management page + await goToAdminRolesPage(page); + }); + + // Test for verifying Super Admin can edit an existing role + test('Super Admin can edit an existing role', async ({ page }) => { + // Step 1: click the "Editor" role row + const editorRowLocator = page.getByRole('row', { name: 'Editor' }); + await clickAndWait(page, editorRowLocator); + + // Step 2: fill in the new role name and description + await page.getByRole('textbox', { name: 'Name' }).fill(EDITED_ROLE.name); + await page.getByRole('textbox', { name: 'Description' }).fill(EDITED_ROLE.description); + + // Step 3: modify the public permissions for articles + await page.getByRole('tab', { name: 'Collection Types' }).click(); // Open permissions tab + + await page.getByRole('checkbox', { name: 'Select Read article' }).uncheck(); + await page.getByRole('checkbox', { name: 'Select Publish article' }).uncheck(); + await page.getByRole('checkbox', { name: 'Select Update article' }).uncheck(); + await page.getByRole('checkbox', { name: 'Select Delete article' }).uncheck(); + await page.getByRole('checkbox', { name: 'Select Publish article' }).uncheck(); + + // Step 4: save the updated role + await clickAndWait(page, page.getByRole('button', { name: 'Save' })); + + // Step 5: verify the changes in the role list + // Navigate back to the Roles management page + await goToAdminRolesPage(page); + + const roleLocator = page.getByRole('row', { name: EDITED_ROLE.name }); + + await expect(roleLocator).toBeVisible(); + await expect( + roleLocator.getByRole('gridcell', { name: EDITED_ROLE.name, exact: true }) + ).toBeVisible(); + await expect( + roleLocator.getByRole('gridcell', { name: EDITED_ROLE.description, exact: true }) + ).toBeVisible(); + }); +}); diff --git a/tests/e2e/tests/settings/rbac/actions/see-role.spec.ts b/tests/e2e/tests/settings/rbac/actions/see-role.spec.ts new file mode 100644 index 0000000000..4ec585a132 --- /dev/null +++ b/tests/e2e/tests/settings/rbac/actions/see-role.spec.ts @@ -0,0 +1,33 @@ +import { test, expect } from '@playwright/test'; + +import { sharedSetup } from '../../../../utils/setup'; +import { navToHeader, clickAndWait } from '../../../../utils/shared'; + +test.describe('RBAC - See Roles', () => { + // Runs before each test + test.beforeEach(async ({ page }) => { + // Perform shared setup to reset the database, log in, and prepare the environment + await sharedSetup('rbac-see-roles', page, { + login: true, + resetFiles: true, + importData: 'with-admin.tar', + skipTour: true, + }); + + // Navigate to the Roles management page + await navToHeader(page, ['Settings', ['Administration Panel', 'Roles']], 'Roles'); + }); + + // Test for verifying Super Admin can view details of an existing role + test('Super Admin can see an existing role', async ({ page }) => { + // Step 1: click the "Editor" role row + const editorRowLocator = page.getByRole('row', { name: 'Editor' }); + await clickAndWait(page, editorRowLocator); + + // Verify the details of the role + await expect(page.getByRole('textbox', { name: 'Name' })).toHaveValue('Editor'); + await expect(page.getByRole('textbox', { name: 'Description' })).toHaveValue( + 'Editors can manage and publish contents including those of other users.' + ); + }); +}); diff --git a/tests/e2e/tests/settings/rbac/readme.md b/tests/e2e/tests/settings/rbac/readme.md new file mode 100644 index 0000000000..dfa90658fa --- /dev/null +++ b/tests/e2e/tests/settings/rbac/readme.md @@ -0,0 +1,128 @@ +# Test Suite for Role-Based Access Control + +This test suite focuses on Strapi's Role-Based Access Control (RBAC) feature. + +The tests ensure that administrators or users with appropriate privileges can manage roles and permissions effectively. + +## Test Scenarios + +The test scenarios are organized into two distinct groups: one dedicated to actions (individual tests focusing on +specific tasks) and another for scenarios (combinations of multiple actions to simulate real-world workflows). + +--- + +### 1. **Assign Role to Users** + +#### File: [`assign-role-to-user.spec.ts`](./actions/assign-role-to-user.spec.ts) + +**Type:** +Action + +**Goal:** +Ensure that the Super Admin can assign, remove, or update roles for users effectively. + +**Test Steps:** + +- Log in as a Super Admin and navigate to the Users management page. +- Select a user (Editor role) from the list and open their edit page. +- Remove the current role (`Editor`) and assign a new role (`Author`). +- Save the changes and navigate back to the Users management page. +- Verify that the user now has the updated role (`Author`) and that the old role (`Editor`) is removed. + +--- + +### 2. **Delete Roles** + +#### File: [`delete-role.spec.ts`](./actions/delete-role.spec.ts) + +**Type:** +Action + +**Goal:** +To validate that the Super Admin can delete an existing role successfully. + +**Test Steps:** + +- Log in as a Super Admin and navigate to the Roles management page. +- Identify the role to be deleted (for example, `Author`). +- Click on the delete button and confirm the deletion in the alert dialog. +- Verify that the role no longer appears in the list of roles. + +--- + +### 3. **Edit Roles** + +#### File: [`edit-role.spec.ts`](./actions/edit-role.spec.ts) + +**Type:** +Action + +**Goal:** +To verify that the Super Admin can edit the details and permissions of an existing role. + +**Test Steps:** + +- Log in as a Super Admin and navigate to the Roles management page. +- Select a role to edit (`Editor`) and modify its name, description, and permissions. +- Add or remove specific permissions (for example, disabling 'Update', 'Publish', and 'Delete article' permissions). +- Save the modifications and verify the changes by navigating back to the Roles page. + +--- + +### 4. **See Roles** + +#### File: [`see-role.spec.ts`](./actions/see-role.spec.ts) + +**Type:** +Action + +**Goal:** +To confirm that the Super Admin can view the details of an existing role, including its name, description, and +permissions. + +**Test Steps:** + +- Log in as a Super Admin and navigate to the Roles management page. +- Select an existing role (for example, `Editor`) to view its details. +- Verify that the role's name and description are displayed accurately. + +--- + +### 5. **Create Roles** + +#### File: [`create-role.spec.ts`](./actions/create-role.spec.ts) + +**Type:** +Action + +**Goal:** +To validate that the Super Admin can create a new role with customized permissions. + +**Test Steps:** + +- Log in as a Super Admin and navigate to the Roles management page. +- Click the "Add new role" button to open the role creation form. +- Fill in the role's name (for example, `Publisher`) and description. +- Assign specific permissions (for example, allow the `Publish article` permission). +- Save the newly created role and verify that it appears in the list. + +--- + +### 6. **Full Role Management Flow** + +#### File: [`create-new-role.scenario.spec.ts`](./scenarios/create-new-role.scenario.spec.ts) + +**Type:** +Scenario + +**Goal:** +To cover a comprehensive end-to-end flow combining creating, editing, assigning, and deleting roles to ensure the system supports a complete lifecycle of role management. + +**Test Steps:** + +- Create a new role (`Publisher`) and assign permissions. +- Verify the new role appears in the Roles list. +- Assign the new role to a user. +- Edit the role's permissions and verify the changes in the list. +- Revert the user to their previously assigned role. +- Delete the newly created role and verify that it has been successfully removed. diff --git a/tests/e2e/tests/settings/rbac/scenarios/create-new-role.scenario.spec.ts b/tests/e2e/tests/settings/rbac/scenarios/create-new-role.scenario.spec.ts new file mode 100644 index 0000000000..ca80b8d8b0 --- /dev/null +++ b/tests/e2e/tests/settings/rbac/scenarios/create-new-role.scenario.spec.ts @@ -0,0 +1,154 @@ +import { test, expect, type Page, type Locator } from '@playwright/test'; + +import { sharedSetup } from '../../../../utils/setup'; +import { navToHeader, clickAndWait } from '../../../../utils/shared'; + +// Constants for the scenario +const OLD_ROLE = { name: 'Editor' }; +const NEW_ROLE = { name: 'Publisher', description: 'Role with publishing capabilities' }; +const TARGET_USER = { firstName: 'Editor', lastName: 'Testing', email: 'editor@testing.com' }; +const USER_FULL_NAME = `${TARGET_USER.firstName} ${TARGET_USER.lastName}`; + +/** + * Navigate to the Roles management settings via the menu + */ +const goToAdminRolesPage = async (page: Page) => { + await navToHeader(page, ['Settings', ['Administration Panel', 'Roles']], 'Roles'); +}; + +/** + * Navigate to the Users management page via the menu + */ +const goToUsersManagementPage = async (page: Page) => { + await navToHeader(page, ['Settings', ['Administration Panel', 'Users']], 'Users'); +}; + +test.describe('RBAC - Full Role Management Flow', () => { + test.beforeEach(async ({ page }) => { + // Perform shared setup to reset the database, log in, and prepare the environment + await sharedSetup('rbac-full-role-flow', page, { + login: true, + resetFiles: true, + importData: 'with-admin.tar', + skipTour: true, + }); + }); + + test('Administrator creates, assigns, and edits a role', async ({ page }) => { + // Step 1: create a new role + await addPublisherRole(page); + + await goToAdminRolesPage(page); + + // Verify the new role in the list + const roleLocator = page.getByRole('row', { name: NEW_ROLE.name }); + + await expect(roleLocator).toBeVisible(); + await expect(roleLocator.getByRole('gridcell', { name: NEW_ROLE.name })).toBeVisible(); + await expect(roleLocator.getByRole('gridcell', { name: NEW_ROLE.description })).toBeVisible(); + + // Step 2: assign the new role to a user + await assignRoleToUser(page, USER_FULL_NAME, NEW_ROLE.name); + + // Verify the user has the correct role + await goToUsersManagementPage(page); + + await expect( + page.getByRole('row', { name: `${USER_FULL_NAME} ${TARGET_USER.email} ${NEW_ROLE.name}` }) + ).toBeVisible(); + + // Step 3: edit the permissions of the role + await editPublisherRole(page); + + // Verify the updated role in the list + await goToAdminRolesPage(page); + + await expect(page.getByRole('row', { name: NEW_ROLE.name })).toBeVisible(); + + // Step 4: revert the roles' assignment for the user + await assignRoleToUser(page, USER_FULL_NAME, OLD_ROLE.name); + + // Step 5: delete the created role + await deletePublisherRole(page); + + // Verify the role has been deleted + await expect(page.getByRole('row', { name: NEW_ROLE.name, exact: true })).not.toBeVisible(); + }); +}); + +const addPublisherRole = async (page: Page) => { + await goToAdminRolesPage(page); + + await clickAndWait(page, page.getByRole('button', { name: 'Add new role' }).first()); + + await page.getByRole('textbox', { name: 'Name' }).fill(NEW_ROLE.name); + await page.getByRole('textbox', { name: 'Description' }).fill(NEW_ROLE.description); + + // Assign the "publish" permission for articles initially + await page.getByRole('tab', { name: 'Collection Types' }).click(); + await page.getByRole('checkbox', { name: 'Select Publish article' }).check(); + + // Save the newly created role + await clickAndWait(page, page.getByRole('button', { name: 'Save' })); +}; + +const editPublisherRole = async (page: Page) => { + await goToAdminRolesPage(page); + + // Open the role edit page + await clickAndWait(page, page.getByRole('row', { name: NEW_ROLE.name })); + + // Modify permissions + await page.getByRole('tab', { name: 'Collection Types' }).click(); // Open permissions tab + + await page.getByRole('checkbox', { name: `Select Read article` }).check(); + await page.getByRole('checkbox', { name: `Select Update article` }).check(); + await page.getByRole('checkbox', { name: 'Select Create article' }).check(); + await page.getByRole('checkbox', { name: 'Select Delete article' }).check(); + + await page.getByRole('checkbox', { name: 'Select Publish article' }).uncheck(); + + // Save the updated role + await clickAndWait(page, page.getByRole('button', { name: 'Save' })); +}; + +const deletePublisherRole = async (page: Page) => { + await goToAdminRolesPage(page); + + await page + .getByRole('row', { name: NEW_ROLE.name }) + .getByRole('button', { name: 'Delete' }) + .click(); + + // Confirm the deletion in the alert dialog + await clickAndWait(page, page.getByRole('alertdialog').getByRole('button', { name: 'Confirm' })); +}; + +const assignRoleToUser = async (page: Page, userFullName: string, role: string) => { + await goToUsersManagementPage(page); // Navigate to Users management page + + // Find the user's row + const userRowLocator = page.getByRole('row', { name: userFullName }); + + // Go to the user's edit view page + await clickAndWait(page, userRowLocator.getByRole('link', { name: `Edit ${userFullName}` })); + + // Update the user's roles + await page.getByLabel("User's roles*").locator('svg').last().click(); // Open role selector + + const listBoxLocator = page.getByRole('listbox'); + + // Make sure all the roles are unchecked before selecting the new one + for (const checkbox of await listBoxLocator.locator('button').all()) { + await checkbox.uncheck(); + } + + // Assign the new role + await listBoxLocator.getByLabel(role).locator('button').check(); + + // Exit role selection + await page.keyboard.press('Escape'); + + // Save changes + await clickAndWait(page, page.getByRole('button', { name: 'Save' })); +};