diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2023-06-29 15:33:36 +0200 |
---|---|---|
committer | Christopher Ng <chrng8@gmail.com> | 2023-06-30 11:38:11 -0700 |
commit | 97683a5b6657521d651d9c7e463951c1cf6ff51d (patch) | |
tree | f1046063ae94f5dc4a706ef374a0b13f9c69d55c | |
parent | d76f39889a9cdf04c69d765c4440b53a8a173100 (diff) | |
download | nextcloud-server-97683a5b6657521d651d9c7e463951c1cf6ff51d.tar.gz nextcloud-server-97683a5b6657521d651d9c7e463951c1cf6ff51d.zip |
fix(settings): Migrate away from deprecated `NcPopoverMenu`
* Replace popover menu with `NcActions`
* Deduplicate user actions code between `UserRow` and `UserRowSimple`
* Fix user action to cover whole row heigh to prevent dropdown from shining through the actions
* Fix user action popover to be overlayed by current edited row actions
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
-rw-r--r-- | apps/settings/css/settings.scss | 52 | ||||
-rw-r--r-- | apps/settings/src/components/Users/UserRow.vue | 78 | ||||
-rw-r--r-- | apps/settings/src/components/Users/UserRowActions.vue | 78 | ||||
-rw-r--r-- | apps/settings/src/components/Users/UserRowSimple.vue | 43 | ||||
-rw-r--r-- | cypress/e2e/settings/users.cy.ts | 53 | ||||
-rw-r--r-- | cypress/e2e/settings/users_disable.cy.ts | 89 | ||||
-rw-r--r-- | cypress/e2e/settings/users_modify.cy.ts | 82 | ||||
-rw-r--r-- | cypress/support/commands.ts | 32 | ||||
-rw-r--r-- | tests/acceptance/features/bootstrap/UsersSettingsContext.php | 7 | ||||
-rw-r--r-- | tests/acceptance/features/users.feature | 68 |
10 files changed, 381 insertions, 201 deletions
diff --git a/apps/settings/css/settings.scss b/apps/settings/css/settings.scss index 835456b4563..e80c20d39fc 100644 --- a/apps/settings/css/settings.scss +++ b/apps/settings/css/settings.scss @@ -1386,7 +1386,7 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { // Scroll if too much groups &:not(.row--editable) { .groups, - .subadmins, + .subadmins, .subAdminsGroups { overflow: auto; max-height: 100%; @@ -1395,7 +1395,7 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { .managers, .groups, - .subadmins, + .subadmins, .subAdminsGroups, .quota { min-width: $grid-col-min-width; @@ -1569,50 +1569,14 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { &.userActions { display: flex; + align-items: center; justify-content: flex-end; - #newsubmit { - width: 100%; - } - - .toggleUserActions { - position: relative; - display: flex; - align-items: center; - background-color: var(--color-main-background); - - .icon-more { - width: 44px; - height: 44px; - opacity: .5; - cursor: pointer; - - &:focus, - &:hover, - &:active { - opacity: .7; - background-color: var(--color-background-dark) - } - } - } - - .feedback { - display: flex; - align-items: center; - white-space: nowrap; - transition: opacity 200ms ease-in-out; - - .icon-checkmark { - opacity: .5; - margin-right: 5px; - } - } - } - - /* Fill the grid cell */ - .v-select.select-vue { - min-width: 100%; - width: 100%; + // Make sure to cover whole row + height: 100%; + width: fit-content; + padding-inline: 12px; + background-color: var(--color-main-background); } } } diff --git a/apps/settings/src/components/Users/UserRow.vue b/apps/settings/src/components/Users/UserRow.vue index 2b2e8438597..6d5850068de 100644 --- a/apps/settings/src/components/Users/UserRow.vue +++ b/apps/settings/src/components/Users/UserRow.vue @@ -44,7 +44,6 @@ <!-- User full data --> <UserRowSimple v-else-if="!editing" :editing.sync="editing" - :feedback-message="feedbackMessage" :groups="groups" :languages="languages" :loading="loading" @@ -222,59 +221,41 @@ </div> <div class="userActions"> - <div v-if="!loading.all" - class="toggleUserActions"> - <NcActions> - <NcActionButton icon="icon-checkmark" - :title="t('settings', 'Done')" - :aria-label="t('settings', 'Done')" - @click="handleDoneButton" /> - </NcActions> - <div v-click-outside="hideMenu" class="userPopoverMenuWrapper"> - <button class="icon-more" - :aria-expanded="openedMenu" - :aria-label="t('settings', 'Toggle user actions menu')" - @click.prevent="toggleMenu" /> - <div :class="{ 'open': openedMenu }" class="popovermenu"> - <NcPopoverMenu :menu="userActions" /> - </div> - </div> - </div> - <div :style="{opacity: feedbackMessage !== '' ? 1 : 0}" - class="feedback"> - <div class="icon-checkmark" /> - {{ feedbackMessage }} - </div> + <UserRowActions v-if="!loading.all" + :actions="userActions" + :edit="true" + @update:edit="toggleEdit" /> </div> </div> </template> <script> -import ClickOutside from 'vue-click-outside' +import { showSuccess, showError } from '@nextcloud/dialogs' -import NcPopoverMenu from '@nextcloud/vue/dist/Components/NcPopoverMenu.js' import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js' -import NcActions from '@nextcloud/vue/dist/Components/NcActions.js' -import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' +import ClickOutside from 'vue-click-outside' + +import UserRowActions from './UserRowActions.vue' import UserRowSimple from './UserRowSimple.vue' import UserRowMixin from '../../mixins/UserRowMixin.js' -import { showSuccess, showError } from '@nextcloud/dialogs' export default { name: 'UserRow', + components: { - UserRowSimple, - NcPopoverMenu, - NcActions, - NcActionButton, NcSelect, NcTextField, + UserRowActions, + UserRowSimple, }, + directives: { ClickOutside, }, + mixins: [UserRowMixin], + props: { users: { type: Array, @@ -325,7 +306,6 @@ export default { selectedQuota: false, rand: parseInt(Math.random() * 1000), openedMenu: false, - feedbackMessage: '', possibleManagers: [], currentManager: '', editing: false, @@ -348,8 +328,8 @@ export default { editedMail: this.user.email ?? '', } }, - computed: { + computed: { /* USER POPOVERMENU ACTIONS */ userActions() { const actions = [ @@ -400,8 +380,10 @@ export default { return this.languages[0].languages.concat(this.languages[1].languages) }, }, + async beforeMount() { await this.searchUserManager() + if (this.user.manager) { await this.initManager(this.user.manager) } @@ -432,13 +414,14 @@ export default { this.loading.wipe = true this.loading.all = true this.$store.dispatch('wipeUserDevices', userid) - .then(() => { + .then(() => showSuccess(t('settings', 'Wiped {userid}\'s devices', { userid })), { timeout: 2000 }) + .finally(() => { this.loading.wipe = false this.loading.all = false }) } }, - true + true, ) }, @@ -500,7 +483,7 @@ export default { }) } }, - true + true, ) }, @@ -778,19 +761,13 @@ export default { sendWelcomeMail() { this.loading.all = true this.$store.dispatch('sendWelcomeMail', this.user.id) - .then(success => { - if (success) { - // Show feedback to indicate the success - this.feedbackMessage = t('setting', 'Welcome mail sent!') - setTimeout(() => { - this.feedbackMessage = '' - }, 2000) - } + .then(() => showSuccess(t('setting', 'Welcome mail sent!'), { timeout: 2000 })) + .finally(() => { this.loading.all = false }) }, - handleDoneButton() { + toggleEdit() { this.editing = false if (this.editedDisplayName !== this.user.displayname) { this.editedDisplayName = this.user.displayname @@ -807,7 +784,12 @@ export default { z-index: 1 !important; } - .row :deep() { + .row :deep() { + .v-select.select { + // reset min width to 100% instead of X px + min-width: 100%; + } + .mailAddress, .password, .displayName { diff --git a/apps/settings/src/components/Users/UserRowActions.vue b/apps/settings/src/components/Users/UserRowActions.vue new file mode 100644 index 00000000000..ad89528fda7 --- /dev/null +++ b/apps/settings/src/components/Users/UserRowActions.vue @@ -0,0 +1,78 @@ +<template> + <NcActions :aria-label="t('settings', 'Toggle user actions menu')" + :inline="1"> + <NcActionButton @click="toggleEdit"> + {{ edit ? t('settings', 'Done') : t('settings', 'Edit') }} + <template #icon> + <NcIconSvgWrapper :svg="editSvg" aria-hidden="true" /> + </template> + </NcActionButton> + <NcActionButton v-for="(action, index) in actions" + :key="index" + :aria-label="action.text" + :icon="action.icon" + @click="action.action"> + {{ action.text }} + </NcActionButton> + </NcActions> +</template> + +<script lang="ts"> +import { PropType, defineComponent } from 'vue' + +import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' +import NcActions from '@nextcloud/vue/dist/Components/NcActions.js' +import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js' +import SvgCheck from '@mdi/svg/svg/check.svg?raw' +import SvgPencil from '@mdi/svg/svg/pencil.svg?raw' + +interface UserAction { + action: (event: MouseEvent) => void, + icon: string, + text: string +} + +export default defineComponent({ + components: { + NcActionButton, + NcActions, + NcIconSvgWrapper, + }, + + props: { + /** + * Array of user actions + */ + actions: { + type: Array as PropType<readonly UserAction[]>, + required: true, + }, + + /** + * The state whether the row is currently edited + */ + edit: { + type: Boolean, + required: true, + }, + }, + + computed: { + /** + * Current MDI logo to show for edit toggle + */ + editSvg() { + return this.edit ? SvgCheck : SvgPencil + }, + }, + + methods: { + /** + * Toggle edit mode by emitting the update event + */ + toggleEdit() { + this.$emit('update:edit', !this.edit) + }, + }, +}) +</script> diff --git a/apps/settings/src/components/Users/UserRowSimple.vue b/apps/settings/src/components/Users/UserRowSimple.vue index 20a3e96d54f..3d7f79b4195 100644 --- a/apps/settings/src/components/Users/UserRowSimple.vue +++ b/apps/settings/src/components/Users/UserRowSimple.vue @@ -59,45 +59,26 @@ {{ user.manager }} </div> <div class="userActions"> - <div v-if="canEdit && !loading.all" class="toggleUserActions"> - <NcActions> - <NcActionButton icon="icon-rename" - :title="t('settings', 'Edit User')" - :aria-label="t('settings', 'Edit User')" - @click="toggleEdit" /> - </NcActions> - <div class="userPopoverMenuWrapper"> - <button v-click-outside="hideMenu" - class="icon-more" - :aria-expanded="openedMenu" - :aria-label="t('settings', 'Toggle user actions menu')" - @click.prevent="toggleMenu" /> - <div class="popovermenu" :class="{ 'open': openedMenu }"> - <NcPopoverMenu :menu="userActions" /> - </div> - </div> - </div> - <div class="feedback" :style="{opacity: feedbackMessage !== '' ? 1 : 0}"> - <div class="icon-checkmark" /> - {{ feedbackMessage }} - </div> + <UserRowActions v-if="canEdit && !loading.all" + :actions="userActions" + :edit="false" + @update:edit="toggleEdit" /> </div> </div> </template> <script> -import NcPopoverMenu from '@nextcloud/vue/dist/Components/NcPopoverMenu.js' -import NcActions from '@nextcloud/vue/dist/Components/NcActions.js' -import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' -import ClickOutside from 'vue-click-outside' import { getCurrentUser } from '@nextcloud/auth' + +import ClickOutside from 'vue-click-outside' + +import UserRowActions from './UserRowActions.vue' import UserRowMixin from '../../mixins/UserRowMixin.js' + export default { name: 'UserRowSimple', components: { - NcPopoverMenu, - NcActionButton, - NcActions, + UserRowActions, }, directives: { ClickOutside, @@ -124,10 +105,6 @@ export default { type: Boolean, required: true, }, - feedbackMessage: { - type: String, - required: true, - }, subAdminsGroups: { type: Array, required: true, diff --git a/cypress/e2e/settings/users.cy.ts b/cypress/e2e/settings/users.cy.ts index ba1f4449ea0..bc5211e291f 100644 --- a/cypress/e2e/settings/users.cy.ts +++ b/cypress/e2e/settings/users.cy.ts @@ -25,9 +25,8 @@ import { User } from '@nextcloud/cypress' const admin = new User('admin', 'admin') const jdoe = new User('jdoe', 'jdoe') -describe('Setting: Users list', function() { +describe('Settings: Create and delete users', function() { before(function() { - cy.createUser(jdoe) cy.login(admin) }) @@ -35,48 +34,26 @@ describe('Setting: Users list', function() { cy.deleteUser(jdoe) }) - it('Can change the password', function() { + it('Can delete a user', function() { + // ensure user exists + cy.createUser(jdoe).login(admin) + // open the User settings cy.visit('/settings/users') - cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(($row) => { + // see that the user is in the list + cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(() => { // see that the list of users contains the user jdoe cy.contains(jdoe.userId).should('exist') - // toggle the edit mode for the user jdoe - cy.get('.userActions button .icon-rename').click() + // open the actions menu for the user + cy.get('.userActions button.action-item__menutoggle').click() }) - cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(($row) => { - // see that the edit mode is on - cy.wrap($row).should('have.class', 'row--editable') - // see that the password of user0 is "" - cy.get('input[type="password"]').should('exist').and('have.value', '') - // set the password for user0 to 123456 - cy.get('input[type="password"]').type('123456') - // When I set the password for user0 to 123456 - cy.get('input[type="password"]').should('have.value', '123456') - cy.get('.password button').click() - - // Ignore failure if modal is not shown - cy.once('fail', (error) => { - expect(error.name).to.equal('AssertionError') - expect(error).to.have.property('node', '.modal-container') - }) - // Make sure no confirmation modal is shown - cy.root().closest('body').find('.modal-container').then(($modal) => { - if ($modal.length > 0) { - cy.wrap($modal).find('input[type="password"]').type(admin.password) - cy.wrap($modal).find('button').contains('Confirm').click() - } - }) - - // see that the password cell for user user0 is done loading - cy.get('.user-row-text-field.icon-loading-small').should('exist') - cy.waitUntil(() => cy.get('.user-row-text-field.icon-loading-small').should('not.exist'), { timeout: 10000 }) - // password input is emptied on change - cy.get('input[type="password"]').should('have.value', '') - }) - // Success message is shown - cy.get('.toastify.toast-success').contains(/Password.+successfully.+changed/i).should('exist') + // The "Delete user" action in the actions menu is shown and clicked + cy.get('.action-item__popper .action').contains('Delete user').should('exist').click() + // And confirmation dialog accepted + cy.get('.oc-dialog button').contains(`Delete ${jdoe.userId}`).click() + // deleted clicked the user is not shown anymore + cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).should('not.exist') }) }) diff --git a/cypress/e2e/settings/users_disable.cy.ts b/cypress/e2e/settings/users_disable.cy.ts new file mode 100644 index 00000000000..7495950b3c1 --- /dev/null +++ b/cypress/e2e/settings/users_disable.cy.ts @@ -0,0 +1,89 @@ +/** + * @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de> + * + * @author Ferdinand Thiessen <opensource@fthiessen.de> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import { User } from '@nextcloud/cypress' + +const admin = new User('admin', 'admin') +const jdoe = new User('jdoe', 'jdoe') + +describe('Settings: Disable and enable users', function() { + before(function() { + cy.createUser(jdoe) + cy.login(admin) + }) + + after(() => { + cy.deleteUser(jdoe) + }) + + it('Can disable the user', function() { + // ensure user is enabled + cy.enableUser(jdoe) + // open the User settings + cy.visit('/settings/users') + // see that the user is in the list of active users + cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(() => { + // see that the list of users contains the user jdoe + cy.contains(jdoe.userId).should('exist') + // open the actions menu for the user + cy.get('.userActions button.action-item__menutoggle').click() + }) + + // The "Disable user" action in the actions menu is shown and clicked + cy.get('.action-item__popper .action').contains('Disable user').should('exist').click() + // When clicked the section is not shown anymore + cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).should('not.exist') + // But the disabled user section now exists + cy.get('#disabled').should('exist') + // Open disabled users section + cy.get('#disabled a').click() + cy.url().should('match', /\/disabled/) + // The list of disabled users should now contain the user + cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).should('exist') + }) + + it('Can enable the user', function() { + // ensure user is disabled + cy.enableUser(jdoe, false) + // open the User settings + cy.visit('/settings/users') + + // Open disabled users section + cy.get('#disabled a').click() + cy.url().should('match', /\/disabled/) + + cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(() => { + // see that the list of disabled users contains the user jdoe + cy.contains(jdoe.userId).should('exist') + // open the actions menu for the user + cy.get('.userActions button.action-item__menutoggle').click() + }) + + // The "Enable user" action in the actions menu is shown and clicked + cy.get('.action-item__popper .action').contains('Enable user').should('exist').click() + // When clicked the section is not shown anymore + cy.get('#disabled').should('not.exist') + // Make sure it is still gone after the reload reload + cy.reload().login(admin) + cy.get('#disabled').should('not.exist') + }) +}) diff --git a/cypress/e2e/settings/users_modify.cy.ts b/cypress/e2e/settings/users_modify.cy.ts new file mode 100644 index 00000000000..d78104c7591 --- /dev/null +++ b/cypress/e2e/settings/users_modify.cy.ts @@ -0,0 +1,82 @@ +/** + * @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de> + * + * @author Ferdinand Thiessen <opensource@fthiessen.de> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import { User } from '@nextcloud/cypress' + +const admin = new User('admin', 'admin') +const jdoe = new User('jdoe', 'jdoe') + +describe('Settings: Change user properties', function() { + before(function() { + cy.createUser(jdoe) + cy.login(admin) + }) + + after(() => { + cy.deleteUser(jdoe) + }) + + it('Can change the password', function() { + // open the User settings + cy.visit('/settings/users') + + cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(($row) => { + // see that the list of users contains the user jdoe + cy.contains(jdoe.userId).should('exist') + // toggle the edit mode for the user jdoe + cy.get('.userActions .action-items > button:first-of-type').click() + }) + + cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(($row) => { + // see that the edit mode is on + cy.wrap($row).should('have.class', 'row--editable') + // see that the password of user0 is "" + cy.get('input[type="password"]').should('exist').and('have.value', '') + // set the password for user0 to 123456 + cy.get('input[type="password"]').type('123456') + // When I set the password for user0 to 123456 + cy.get('input[type="password"]').should('have.value', '123456') + cy.get('.password button').click() + + // Ignore failure if modal is not shown + cy.once('fail', (error) => { + expect(error.name).to.equal('AssertionError') + expect(error).to.have.property('node', '.modal-container') + }) + // Make sure no confirmation modal is shown + cy.root().closest('body').find('.modal-container').then(($modal) => { + if ($modal.length > 0) { + cy.wrap($modal).find('input[type="password"]').type(admin.password) + cy.wrap($modal).find('button').contains('Confirm').click() + } + }) + + // see that the password cell for user user0 is done loading + cy.get('.user-row-text-field.icon-loading-small').should('exist') + cy.waitUntil(() => cy.get('.user-row-text-field.icon-loading-small').should('not.exist'), { timeout: 10000 }) + // password input is emptied on change + cy.get('input[type="password"]').should('have.value', '') + }) + // Success message is shown + cy.get('.toastify.toast-success').contains(/Password.+successfully.+changed/i).should('exist') + }) +}) diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 31e867a5caf..e48965822fa 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -34,6 +34,11 @@ declare global { namespace Cypress { interface Chainable<Subject = any> { /** + * Enable or disable a given user + */ + enableUser(user: User, enable?: boolean): Cypress.Chainable<Cypress.Response<any>>, + + /** * Upload a file from the fixtures folder to a given user storage. * **Warning**: Using this function will reset the previous session */ @@ -70,6 +75,33 @@ const url = (Cypress.config('baseUrl') || '').replace(/\/index.php\/?$/g, '') Cypress.env('baseUrl', url) /** + * Enable or disable a user + * TODO: standardise in @nextcloud/cypress + * + * @param {User} user the user to dis- / enable + * @param {boolean} enable True if the user should be enable, false to disable + */ +Cypress.Commands.add('enableUser', (user: User, enable = true) => { + const url = `${Cypress.config('baseUrl')}/ocs/v2.php/cloud/users/${user.userId}/${enable ? 'enable' : 'disable'}`.replace('index.php/', '') + return cy.request({ + method: 'PUT', + url, + form: true, + auth: { + user: 'admin', + password: 'admin', + }, + headers: { + 'OCS-ApiRequest': 'true', + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }).then((response) => { + cy.log(`Enabled user ${user}`, response.status) + return cy.wrap(response) + }) +}) + +/** * cy.uploadedFile - uploads a file from the fixtures folder * TODO: standardise in @nextcloud/cypress * diff --git a/tests/acceptance/features/bootstrap/UsersSettingsContext.php b/tests/acceptance/features/bootstrap/UsersSettingsContext.php index 19d49ed1f4f..548bcf03a8e 100644 --- a/tests/acceptance/features/bootstrap/UsersSettingsContext.php +++ b/tests/acceptance/features/bootstrap/UsersSettingsContext.php @@ -125,7 +125,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface { * @return Locator */ public static function actionsMenuOf($user) { - return Locator::forThe()->css(".icon-more")-> + return Locator::forThe()->css(".userActions .action-item:not(.action-item--single)")-> descendantOf(self::rowForUser($user))-> describedAs("Actions menu for user $user in Users Settings"); } @@ -134,8 +134,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface { * @return Locator */ public static function theAction($action, $user) { - return Locator::forThe()->xpath("//button[normalize-space() = '$action']")-> - descendantOf(self::rowForUser($user))-> + return Locator::forThe()->xpath("//button[@aria-label = normalize-space('$action')]")-> describedAs("$action action for the user $user row in Users Settings"); } @@ -160,7 +159,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface { * @return Locator */ public static function editModeToggle($user) { - return Locator::forThe()->css(".toggleUserActions button")-> + return Locator::forThe()->css(".userActions .action-items button:first-of-type")-> descendantOf(self::rowForUser($user))-> describedAs("The edit toggle button for the user $user in Users Settings"); } diff --git a/tests/acceptance/features/users.feature b/tests/acceptance/features/users.feature index 3d223ee12cf..27291c3c9f4 100644 --- a/tests/acceptance/features/users.feature +++ b/tests/acceptance/features/users.feature @@ -22,42 +22,42 @@ Feature: users Then I see that the list of users contains the user "test" # And I see that the display name for the user "test" is "Test display name" - Scenario: delete a user - Given I act as Jane - And I am logged in as the admin - And I open the User settings - And I see that the list of users contains the user user0 - And I open the actions menu for the user user0 - And I see that the "Delete user" action in the user0 actions menu is shown - When I click the "Delete user" action in the user0 actions menu - And I click the "Delete user0's account" button of the confirmation dialog - Then I see that the list of users does not contains the user user0 +# Scenario: delete a user +# Given I act as Jane +# And I am logged in as the admin +# And I open the User settings +# And I see that the list of users contains the user user0 +# And I open the actions menu for the user user0 +# And I see that the "Delete user" action in the user0 actions menu is shown +# When I click the "Delete user" action in the user0 actions menu +# And I click the "Delete user0's account" button of the confirmation dialog +# Then I see that the list of users does not contains the user user0 - Scenario: disable a user - Given I act as Jane - And I am logged in as the admin - And I open the User settings - And I see that the list of users contains the user user0 - And I open the actions menu for the user user0 - And I see that the "Disable user" action in the user0 actions menu is shown - When I click the "Disable user" action in the user0 actions menu - Then I see that the list of users does not contains the user user0 - When I open the "Disabled users" section - Then I see that the list of users contains the user user0 +# Scenario: disable a user +# Given I act as Jane +# And I am logged in as the admin +# And I open the User settings +# And I see that the list of users contains the user user0 +# And I open the actions menu for the user user0 +# And I see that the "Disable user" action in the user0 actions menu is shown +# When I click the "Disable user" action in the user0 actions menu +# Then I see that the list of users does not contains the user user0 +# When I open the "Disabled users" section +# Then I see that the list of users contains the user user0 - Scenario: users navigation without disabled users - Given I act as Jane - And I am logged in as the admin - And I open the User settings - And I open the "Disabled users" section - And I see that the list of users contains the user disabledUser - And I open the actions menu for the user disabledUser - And I see that the "Enable user" action in the disabledUser actions menu is shown - When I click the "Enable user" action in the disabledUser actions menu - Then I see that the section "Disabled users" is not shown - # check again after reloading the settings - When I open the User settings - Then I see that the section "Disabled users" is not shown +# Scenario: users navigation without disabled users +# Given I act as Jane +# And I am logged in as the admin +# And I open the User settings +# And I open the "Disabled users" section +# And I see that the list of users contains the user disabledUser +# And I open the actions menu for the user disabledUser +# And I see that the "Enable user" action in the disabledUser actions menu is shown +# When I click the "Enable user" action in the disabledUser actions menu +# Then I see that the section "Disabled users" is not shown +# # check again after reloading the settings +# When I open the User settings +# Then I see that the section "Disabled users" is not shown Scenario: assign user to a group Given I act as Jane |