aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2023-06-29 15:33:36 +0200
committerChristopher Ng <chrng8@gmail.com>2023-06-30 11:38:11 -0700
commit97683a5b6657521d651d9c7e463951c1cf6ff51d (patch)
treef1046063ae94f5dc4a706ef374a0b13f9c69d55c
parentd76f39889a9cdf04c69d765c4440b53a8a173100 (diff)
downloadnextcloud-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.scss52
-rw-r--r--apps/settings/src/components/Users/UserRow.vue78
-rw-r--r--apps/settings/src/components/Users/UserRowActions.vue78
-rw-r--r--apps/settings/src/components/Users/UserRowSimple.vue43
-rw-r--r--cypress/e2e/settings/users.cy.ts53
-rw-r--r--cypress/e2e/settings/users_disable.cy.ts89
-rw-r--r--cypress/e2e/settings/users_modify.cy.ts82
-rw-r--r--cypress/support/commands.ts32
-rw-r--r--tests/acceptance/features/bootstrap/UsersSettingsContext.php7
-rw-r--r--tests/acceptance/features/users.feature68
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