Merge branch '18559-user-profile' into main. Closes #18559
[arvados-workbench2.git] / cypress / integration / user-profile.spec.js
diff --git a/cypress/integration/user-profile.spec.js b/cypress/integration/user-profile.spec.js
new file mode 100644 (file)
index 0000000..7d21249
--- /dev/null
@@ -0,0 +1,449 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+describe('User profile tests', function() {
+    let activeUser;
+    let adminUser;
+    const roleGroupName = `Test role group (${Math.floor(999999 * Math.random())})`;
+    const projectGroupName = `Test project group (${Math.floor(999999 * Math.random())})`;
+
+    before(function() {
+        // Only set up common users once. These aren't set up as aliases because
+        // aliases are cleaned up after every test. Also it doesn't make sense
+        // to set the same users on beforeEach() over and over again, so we
+        // separate a little from Cypress' 'Best Practices' here.
+        cy.getUser('admin', 'Admin', 'User', true, true)
+            .as('adminUser').then(function() {
+                adminUser = this.adminUser;
+            }
+        );
+        cy.getUser('user', 'Active', 'User', false, true)
+            .as('activeUser').then(function() {
+                activeUser = this.activeUser;
+            }
+        );
+    });
+
+    function assertProfileValues({
+        firstName,
+        lastName,
+        email,
+        username,
+        org,
+        org_email,
+        role,
+        website,
+    }) {
+        cy.get('[data-cy=profile-form] input[name="firstName"]').invoke('val').should('equal', firstName);
+        cy.get('[data-cy=profile-form] input[name="lastName"]').invoke('val').should('equal', lastName);
+        cy.get('[data-cy=profile-form] [data-cy=email] [data-cy=value]').contains(email);
+        cy.get('[data-cy=profile-form] [data-cy=username] [data-cy=value]').contains(username);
+
+        cy.get('[data-cy=profile-form] input[name="prefs.profile.organization"]').invoke('val').should('equal', org);
+        cy.get('[data-cy=profile-form] input[name="prefs.profile.organization_email"]').invoke('val').should('equal', org_email);
+        cy.get('[data-cy=profile-form] select[name="prefs.profile.role"]').invoke('val').should('equal', role);
+        cy.get('[data-cy=profile-form] input[name="prefs.profile.website_url"]').invoke('val').should('equal', website);
+    }
+
+    function enterProfileValues({
+        org,
+        org_email,
+        role,
+        website,
+    }) {
+        cy.get('[data-cy=profile-form] input[name="prefs.profile.organization"]').clear();
+        if (org) {
+            cy.get('[data-cy=profile-form] input[name="prefs.profile.organization"]').type(org);
+        }
+        cy.get('[data-cy=profile-form] input[name="prefs.profile.organization_email"]').clear();
+        if (org_email) {
+            cy.get('[data-cy=profile-form] input[name="prefs.profile.organization_email"]').type(org_email);
+        }
+        cy.get('[data-cy=profile-form] select[name="prefs.profile.role"]').select(role);
+        cy.get('[data-cy=profile-form] input[name="prefs.profile.website_url"]').clear();
+        if (website) {
+            cy.get('[data-cy=profile-form] input[name="prefs.profile.website_url"]').type(website);
+        }
+    }
+
+    function assertContextMenuItems({
+        account,
+        activate,
+        deactivate,
+        login,
+        setup
+    }) {
+        cy.get('[data-cy=user-profile-panel-options-btn]').click();
+        cy.get('[data-cy=context-menu]').within(() => {
+            cy.get('[role=button]').contains('Advanced');
+
+            cy.get('[role=button]').should(account ? 'contain' : 'not.contain', 'Account Settings');
+            cy.get('[role=button]').should(activate ? 'contain' : 'not.contain', 'Activate User');
+            cy.get('[role=button]').should(deactivate ? 'contain' : 'not.contain', 'Deactivate User');
+            cy.get('[role=button]').should(login ? 'contain' : 'not.contain', 'Login As User');
+            cy.get('[role=button]').should(setup ? 'contain' : 'not.contain', 'Setup User');
+        });
+        cy.get('div[role=presentation]').click();
+    }
+
+    beforeEach(function() {
+        cy.updateResource(adminUser.token, 'users', adminUser.user.uuid, {
+            prefs: {
+                profile: {
+                    organization: '',
+                    organization_email: '',
+                    role: '',
+                    website_url: '',
+                },
+            },
+        });
+        cy.updateResource(adminUser.token, 'users', activeUser.user.uuid, {
+            prefs: {
+                profile: {
+                    organization: '',
+                    organization_email: '',
+                    role: '',
+                    website_url: '',
+                },
+            },
+        });
+    });
+
+    it('non-admin can edit own profile', function() {
+        cy.loginAs(activeUser);
+
+        cy.get('header button[title="Account Management"]').click();
+        cy.get('#account-menu').contains('My account').click();
+
+        // Admin actions should be hidden, no account menu
+        assertContextMenuItems({
+            account: false,
+            activate: false,
+            deactivate: false,
+            login: false,
+            setup: false,
+        });
+
+        // Check initial values
+        assertProfileValues({
+            firstName: 'Active',
+            lastName: 'User',
+            email: 'user@example.local',
+            username: 'user',
+            org: '',
+            org_email: '',
+            role: '',
+            website: '',
+        });
+
+        // Change values
+        enterProfileValues({
+            org: 'Org name',
+            org_email: 'email@example.com',
+            role: 'Data Scientist',
+            website: 'example.com',
+        });
+
+        // Submit
+        cy.get('[data-cy=profile-form] button[type="submit"]').click();
+
+        // Check new values
+        assertProfileValues({
+            firstName: 'Active',
+            lastName: 'User',
+            email: 'user@example.local',
+            username: 'user',
+            org: 'Org name',
+            org_email: 'email@example.com',
+            role: 'Data Scientist',
+            website: 'example.com',
+        });
+    });
+
+    it('non-admin cannot edit other profile', function() {
+        cy.loginAs(activeUser);
+        cy.goToPath('/user/' + adminUser.user.uuid);
+
+        assertProfileValues({
+            firstName: 'Admin',
+            lastName: 'User',
+            email: 'admin@example.local',
+            username: 'admin',
+            org: '',
+            org_email: '',
+            role: '',
+            website: '',
+        });
+
+        // Inputs should be disabled
+        cy.get('[data-cy=profile-form] input[name="prefs.profile.organization"]').should('be.disabled');
+        cy.get('[data-cy=profile-form] input[name="prefs.profile.organization_email"]').should('be.disabled');
+        cy.get('[data-cy=profile-form] select[name="prefs.profile.role"]').should('be.disabled');
+        cy.get('[data-cy=profile-form] input[name="prefs.profile.website_url"]').should('be.disabled');
+
+        // Submit should be disabled
+        cy.get('[data-cy=profile-form] button[type="submit"]').should('be.disabled');
+
+        // Admin actions should be hidden, no account menu
+        assertContextMenuItems({
+            account: false,
+            activate: false,
+            deactivate: false,
+            login: false,
+            setup: false,
+        });
+    });
+
+    it('admin can edit own profile', function() {
+        cy.loginAs(adminUser);
+
+        cy.get('header button[title="Account Management"]').click();
+        cy.get('#account-menu').contains('My account').click();
+
+        // Admin actions should be visible, no account menu
+        assertContextMenuItems({
+            account: false,
+            activate: false,
+            deactivate: true,
+            login: false,
+            setup: false,
+        });
+
+        // Check initial values
+        assertProfileValues({
+            firstName: 'Admin',
+            lastName: 'User',
+            email: 'admin@example.local',
+            username: 'admin',
+            org: '',
+            org_email: '',
+            role: '',
+            website: '',
+        });
+
+        // Change values
+        enterProfileValues({
+            org: 'Admin org name',
+            org_email: 'admin@example.com',
+            role: 'Researcher',
+            website: 'admin.local',
+        });
+        cy.get('[data-cy=profile-form] button[type="submit"]').click();
+
+        // Check new values
+        assertProfileValues({
+            firstName: 'Admin',
+            lastName: 'User',
+            email: 'admin@example.local',
+            username: 'admin',
+            org: 'Admin org name',
+            org_email: 'admin@example.com',
+            role: 'Researcher',
+            website: 'admin.local',
+        });
+    });
+
+    it('admin can edit other profile', function() {
+        cy.loginAs(adminUser);
+        cy.goToPath('/user/' + activeUser.user.uuid);
+
+        // Check new values
+        assertProfileValues({
+            firstName: 'Active',
+            lastName: 'User',
+            email: 'user@example.local',
+            username: 'user',
+            org: '',
+            org_email: '',
+            role: '',
+            website: '',
+        });
+
+        enterProfileValues({
+            org: 'Changed org name',
+            org_email: 'changed@example.com',
+            role: 'Researcher',
+            website: 'changed.local',
+        });
+        cy.get('[data-cy=profile-form] button[type="submit"]').click();
+
+        // Check new values
+        assertProfileValues({
+            firstName: 'Active',
+            lastName: 'User',
+            email: 'user@example.local',
+            username: 'user',
+            org: 'Changed org name',
+            org_email: 'changed@example.com',
+            role: 'Researcher',
+            website: 'changed.local',
+        });
+
+        // Admin actions should be visible, no account menu
+        assertContextMenuItems({
+            account: false,
+            activate: false,
+            deactivate: true,
+            login: true,
+            setup: false,
+        });
+    });
+
+    it('displays role groups on user profile', function() {
+        cy.loginAs(adminUser);
+
+        cy.createGroup(adminUser.token, {
+            name: roleGroupName,
+            group_class: 'role',
+        }).as('roleGroup').then(function() {
+            cy.createLink(adminUser.token, {
+                name: 'can_write',
+                link_class: 'permission',
+                head_uuid: this.roleGroup.uuid,
+                tail_uuid: adminUser.user.uuid
+            });
+            cy.createLink(adminUser.token, {
+                name: 'can_write',
+                link_class: 'permission',
+                head_uuid: this.roleGroup.uuid,
+                tail_uuid: activeUser.user.uuid
+            });
+        });
+
+        cy.createGroup(adminUser.token, {
+            name: projectGroupName,
+            group_class: 'project',
+        }).as('projectGroup').then(function() {
+            cy.createLink(adminUser.token, {
+                name: 'can_write',
+                link_class: 'permission',
+                head_uuid: this.projectGroup.uuid,
+                tail_uuid: adminUser.user.uuid
+            });
+            cy.createLink(adminUser.token, {
+                name: 'can_write',
+                link_class: 'permission',
+                head_uuid: this.projectGroup.uuid,
+                tail_uuid: activeUser.user.uuid
+            });
+        });
+
+        cy.goToPath('/user/' + activeUser.user.uuid);
+        cy.get('div [role="tab"]').contains('GROUPS').click();
+        cy.get('[data-cy=user-profile-groups-data-explorer]').contains(roleGroupName);
+        cy.get('[data-cy=user-profile-groups-data-explorer]').should('not.contain', projectGroupName);
+
+        cy.goToPath('/user/' + adminUser.user.uuid);
+        cy.get('div [role="tab"]').contains('GROUPS').click();
+        cy.get('[data-cy=user-profile-groups-data-explorer]').contains(roleGroupName);
+        cy.get('[data-cy=user-profile-groups-data-explorer]').should('not.contain', projectGroupName);
+    });
+
+    it('allows performing admin functions', function() {
+        cy.loginAs(adminUser);
+        cy.goToPath('/user/' + activeUser.user.uuid);
+
+        // Check that user is active
+        cy.get('[data-cy=account-status]').contains('Active');
+        cy.get('div [role="tab"]').contains('GROUPS').click();
+        cy.get('[data-cy=user-profile-groups-data-explorer]').should('contain', 'All users');
+        cy.get('div [role="tab"]').contains('PROFILE').click();
+        assertContextMenuItems({
+            account: false,
+            activate: false,
+            deactivate: true,
+            login: true,
+            setup: false,
+        });
+
+        // Deactivate user
+        cy.get('[data-cy=user-profile-panel-options-btn]').click();
+        cy.get('[data-cy=context-menu]').contains('Deactivate User').click();
+        cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
+
+        // Check that user is deactivated
+        cy.get('[data-cy=account-status]').contains('Inactive');
+        cy.get('div [role="tab"]').contains('GROUPS').click();
+        cy.get('[data-cy=user-profile-groups-data-explorer]').should('not.contain', 'All users');
+        cy.get('div [role="tab"]').contains('PROFILE').click();
+        assertContextMenuItems({
+            account: false,
+            activate: true,
+            deactivate: false,
+            login: true,
+            setup: true,
+        });
+
+        // Setup user
+        cy.get('[data-cy=user-profile-panel-options-btn]').click();
+        cy.get('[data-cy=context-menu]').contains('Setup User').click();
+        cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
+
+        // Check that user is setup
+        cy.get('[data-cy=account-status]').contains('Setup');
+        cy.get('div [role="tab"]').contains('GROUPS').click();
+        cy.get('[data-cy=user-profile-groups-data-explorer]').should('contain', 'All users');
+        cy.get('div [role="tab"]').contains('PROFILE').click();
+        assertContextMenuItems({
+            account: false,
+            activate: true,
+            deactivate: true,
+            login: true,
+            setup: false,
+        });
+
+        // Activate user
+        cy.get('[data-cy=user-profile-panel-options-btn]').click();
+        cy.get('[data-cy=context-menu]').contains('Activate User').click();
+        cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
+
+        // Check that user is active
+        cy.get('[data-cy=account-status]').contains('Active');
+        cy.get('div [role="tab"]').contains('GROUPS').click();
+        cy.get('[data-cy=user-profile-groups-data-explorer]').should('contain', 'All users');
+        cy.get('div [role="tab"]').contains('PROFILE').click();
+        assertContextMenuItems({
+            account: false,
+            activate: false,
+            deactivate: true,
+            login: true,
+            setup: false,
+        });
+
+        // Deactivate and activate user skipping setup
+        cy.get('[data-cy=user-profile-panel-options-btn]').click();
+        cy.get('[data-cy=context-menu]').contains('Deactivate User').click();
+        cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
+        // Check
+        cy.get('[data-cy=account-status]').contains('Inactive');
+        cy.get('div [role="tab"]').contains('GROUPS').click();
+        cy.get('[data-cy=user-profile-groups-data-explorer]').should('not.contain', 'All users');
+        cy.get('div [role="tab"]').contains('PROFILE').click();
+        assertContextMenuItems({
+            account: false,
+            activate: true,
+            deactivate: false,
+            login: true,
+            setup: true,
+        });
+        // reactivate
+        cy.get('[data-cy=user-profile-panel-options-btn]').click();
+        cy.get('[data-cy=context-menu]').contains('Activate User').click();
+        cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
+
+        // Check that user is active
+        cy.get('[data-cy=account-status]').contains('Active');
+        cy.get('div [role="tab"]').contains('GROUPS').click();
+        cy.get('[data-cy=user-profile-groups-data-explorer]').should('contain', 'All users');
+        cy.get('div [role="tab"]').contains('PROFILE').click();
+        assertContextMenuItems({
+            account: false,
+            activate: false,
+            deactivate: true,
+            login: true,
+            setup: false,
+        });
+    });
+
+});