mirror of
https://github.com/nextcloud/server.git
synced 2025-03-14 16:33:21 +00:00
fix(settings): Stablize user list cypress tests
* Use common `data-testid` to identify elements rather than to depend on internal classes or properties * Force clean the state for the user tests * Move leftover acceptance tests for users from drone to cypress Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
888473f5e2
commit
5b0c27b6da
20 changed files with 566 additions and 677 deletions
.drone.yml
.github/workflows
apps/settings/src/components
cypress
e2e/settings
support
dist
settings-users-8351.jssettings-users-8351.js.mapsettings-vue-settings-apps-users-management.jssettings-vue-settings-apps-users-management.js.map
tests/acceptance
30
.drone.yml
30
.drone.yml
|
@ -1621,36 +1621,6 @@ trigger:
|
|||
- pull_request
|
||||
- push
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: acceptance-users
|
||||
|
||||
steps:
|
||||
- name: submodules
|
||||
image: ghcr.io/nextcloud/continuous-integration-alpine-git:latest
|
||||
commands:
|
||||
- git submodule update --init
|
||||
- name: acceptance-users
|
||||
image: ghcr.io/nextcloud/continuous-integration-acceptance-php8.0:latest
|
||||
commands:
|
||||
- tests/acceptance/run-local.sh --timeout-multiplier 10 --nextcloud-server-domain acceptance-users --selenium-server selenium:4444 allow-git-repository-modifications features/users.feature
|
||||
|
||||
services:
|
||||
- name: selenium
|
||||
image: ghcr.io/nextcloud/continuous-integration-selenium:3.141.59
|
||||
environment:
|
||||
# Reduce default log level for Selenium server (INFO) as it is too
|
||||
# verbose.
|
||||
JAVA_OPTS: -Dselenium.LOGGER.level=WARNING
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- master
|
||||
- stable*
|
||||
event:
|
||||
- pull_request
|
||||
- push
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: acceptance-apps
|
||||
|
|
6
.github/workflows/cypress.yml
vendored
6
.github/workflows/cypress.yml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout app
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3.5.2
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Check composer.json
|
||||
id: check_composer
|
||||
|
@ -39,8 +39,8 @@ jobs:
|
|||
uses: skjnldsv/read-package-engines-version-actions@8205673bab74a63eb9b8093402fd9e0e018663a1 # v2.2
|
||||
id: versions
|
||||
with:
|
||||
fallbackNode: "^14"
|
||||
fallbackNpm: "^7"
|
||||
fallbackNode: "^20"
|
||||
fallbackNpm: "^9"
|
||||
|
||||
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
|
||||
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
:data-component="UserRow"
|
||||
:data-sources="filteredUsers"
|
||||
data-key="id"
|
||||
data-test-id="userList"
|
||||
data-cy-user-list
|
||||
:item-height="rowHeight"
|
||||
:style="style"
|
||||
:extra-props="{
|
||||
|
|
|
@ -23,12 +23,14 @@
|
|||
<template>
|
||||
<tr class="header">
|
||||
<th class="header__cell header__cell--avatar"
|
||||
data-cy-user-list-header-avatar
|
||||
scope="col">
|
||||
<span class="hidden-visually">
|
||||
{{ t('settings', 'Avatar') }}
|
||||
</span>
|
||||
</th>
|
||||
<th class="header__cell header__cell--displayname"
|
||||
data-cy-user-list-header-displayname
|
||||
scope="col">
|
||||
<strong>
|
||||
{{ t('settings', 'Display name') }}
|
||||
|
@ -39,33 +41,40 @@
|
|||
</th>
|
||||
<th class="header__cell"
|
||||
:class="{ 'header__cell--obfuscated': hasObfuscated }"
|
||||
data-cy-user-list-header-password
|
||||
scope="col">
|
||||
<span>{{ passwordLabel }}</span>
|
||||
</th>
|
||||
<th class="header__cell"
|
||||
data-cy-user-list-header-email
|
||||
scope="col">
|
||||
<span>{{ t('settings', 'Email') }}</span>
|
||||
</th>
|
||||
<th class="header__cell header__cell--large"
|
||||
data-cy-user-list-header-groups
|
||||
scope="col">
|
||||
<span>{{ t('settings', 'Groups') }}</span>
|
||||
</th>
|
||||
<th v-if="subAdminsGroups.length > 0 && settings.isAdmin"
|
||||
class="header__cell header__cell--large"
|
||||
data-cy-user-list-header-subadmins
|
||||
scope="col">
|
||||
<span>{{ t('settings', 'Group admin for') }}</span>
|
||||
</th>
|
||||
<th class="header__cell"
|
||||
data-cy-user-list-header-quota
|
||||
scope="col">
|
||||
<span>{{ t('settings', 'Quota') }}</span>
|
||||
</th>
|
||||
<th v-if="showConfig.showLanguages"
|
||||
class="header__cell header__cell--large"
|
||||
data-cy-user-list-header-languages
|
||||
scope="col">
|
||||
<span>{{ t('settings', 'Language') }}</span>
|
||||
</th>
|
||||
<th v-if="showConfig.showUserBackend || showConfig.showStoragePath"
|
||||
class="header__cell header__cell--large"
|
||||
data-cy-user-list-header-storage-location
|
||||
scope="col">
|
||||
<span v-if="showConfig.showUserBackend">
|
||||
{{ t('settings', 'User backend') }}
|
||||
|
@ -77,15 +86,18 @@
|
|||
</th>
|
||||
<th v-if="showConfig.showLastLogin"
|
||||
class="header__cell"
|
||||
data-cy-user-list-header-last-login
|
||||
scope="col">
|
||||
<span>{{ t('settings', 'Last login') }}</span>
|
||||
</th>
|
||||
<th class="header__cell header__cell--large header__cell--fill"
|
||||
data-cy-user-list-header-manager
|
||||
scope="col">
|
||||
<!-- TRANSLATORS This string describes a manager in the context of an organization -->
|
||||
<span>{{ t('settings', 'Manager') }}</span>
|
||||
</th>
|
||||
<th class="header__cell header__cell--actions"
|
||||
data-cy-user-list-header-actions
|
||||
scope="col">
|
||||
<span class="hidden-visually">
|
||||
{{ t('settings', 'User actions') }}
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
<template>
|
||||
<tr class="user-list__row"
|
||||
:data-test="user.id">
|
||||
<td class="row__cell row__cell--avatar">
|
||||
:data-cy-user-row="user.id">
|
||||
<td class="row__cell row__cell--avatar" data-cy-user-list-cell-avatar>
|
||||
<NcLoadingIcon v-if="isLoadingUser"
|
||||
:name="t('settings', 'Loading user …')"
|
||||
:size="32" />
|
||||
|
@ -36,12 +36,12 @@
|
|||
:user="user.id" />
|
||||
</td>
|
||||
|
||||
<td class="row__cell row__cell--displayname" data-test-id="cell-displayname">
|
||||
<td class="row__cell row__cell--displayname" data-cy-user-list-cell-displayname>
|
||||
<template v-if="editing && user.backendCapabilities.setDisplayName">
|
||||
<NcTextField ref="displayNameField"
|
||||
class="user-row-text-field"
|
||||
data-test-id="input-displayName"
|
||||
:data-test-loading="`${loading.displayName}`"
|
||||
data-cy-user-list-input-displayname
|
||||
:data-loading="loading.displayName || undefined"
|
||||
:trailing-button-label="t('settings', 'Submit')"
|
||||
:class="{ 'icon-loading-small': loading.displayName }"
|
||||
:show-trailing-button="true"
|
||||
|
@ -63,13 +63,13 @@
|
|||
</template>
|
||||
</td>
|
||||
|
||||
<td data-test-id="cell-password"
|
||||
<td data-cy-user-list-cell-password
|
||||
class="row__cell"
|
||||
:class="{ 'row__cell--obfuscated': hasObfuscated }">
|
||||
<template v-if="editing && settings.canChangePassword && user.backendCapabilities.setPassword">
|
||||
<NcTextField class="user-row-text-field"
|
||||
data-test-id="input-password"
|
||||
:data-test-loading="`${loading.password}`"
|
||||
data-cy-user-list-input-password
|
||||
:data-loading="loading.password || undefined"
|
||||
:trailing-button-label="t('settings', 'Submit')"
|
||||
:class="{'icon-loading-small': loading.password}"
|
||||
:show-trailing-button="true"
|
||||
|
@ -91,10 +91,12 @@
|
|||
</span>
|
||||
</td>
|
||||
|
||||
<td class="row__cell" data-test-id="cell-email">
|
||||
<td class="row__cell" data-cy-user-list-cell-email>
|
||||
<template v-if="editing">
|
||||
<NcTextField class="user-row-text-field"
|
||||
:class="{'icon-loading-small': loading.mailAddress}"
|
||||
data-cy-user-list-input-email
|
||||
:data-loading="loading.mailAddress || undefined"
|
||||
:show-trailing-button="true"
|
||||
:trailing-button-label="t('settings', 'Submit')"
|
||||
:label="t('settings', 'Set new email address')"
|
||||
|
@ -113,13 +115,15 @@
|
|||
</span>
|
||||
</td>
|
||||
|
||||
<td class="row__cell row__cell--large row__cell--multiline" data-test-id="cell-groups">
|
||||
<td class="row__cell row__cell--large row__cell--multiline" data-cy-user-list-cell-groups>
|
||||
<template v-if="editing">
|
||||
<label class="hidden-visually"
|
||||
:for="'groups' + uniqueId">
|
||||
{{ t('settings', 'Add user to group') }}
|
||||
</label>
|
||||
<NcSelect :input-id="'groups' + uniqueId"
|
||||
<NcSelect data-cy-user-list-input-groups
|
||||
:data-loading="loading.groups || undefined"
|
||||
:input-id="'groups' + uniqueId"
|
||||
:close-on-select="false"
|
||||
:disabled="isLoadingField"
|
||||
:loading="loading.groups"
|
||||
|
@ -143,14 +147,16 @@
|
|||
</td>
|
||||
|
||||
<td v-if="subAdminsGroups.length > 0 && settings.isAdmin"
|
||||
data-test-id="cell-subadmins"
|
||||
data-cy-user-list-cell-subadmins
|
||||
class="row__cell row__cell--large row__cell--multiline">
|
||||
<template v-if="editing && settings.isAdmin && subAdminsGroups.length > 0">
|
||||
<label class="hidden-visually"
|
||||
:for="'subadmins' + uniqueId">
|
||||
{{ t('settings', 'Set user as admin for') }}
|
||||
</label>
|
||||
<NcSelect :input-id="'subadmins' + uniqueId"
|
||||
<NcSelect data-cy-user-list-input-subadmins
|
||||
:data-loading="loading.subadmins || undefined"
|
||||
:input-id="'subadmins' + uniqueId"
|
||||
:close-on-select="false"
|
||||
:disabled="isLoadingField"
|
||||
:loading="loading.subadmins"
|
||||
|
@ -170,7 +176,7 @@
|
|||
</span>
|
||||
</td>
|
||||
|
||||
<td class="row__cell" data-test-id="cell-quota">
|
||||
<td class="row__cell" data-cy-user-list-cell-quota>
|
||||
<template v-if="editing">
|
||||
<label class="hidden-visually"
|
||||
:for="'quota' + uniqueId">
|
||||
|
@ -179,6 +185,8 @@
|
|||
<NcSelect v-model="editedUserQuota"
|
||||
:close-on-select="true"
|
||||
:create-option="validateQuota"
|
||||
data-cy-user-list-input-quota
|
||||
:data-loading="loading.quota || undefined"
|
||||
:disabled="isLoadingField"
|
||||
:loading="loading.quota"
|
||||
:append-to-body="false"
|
||||
|
@ -202,13 +210,15 @@
|
|||
|
||||
<td v-if="showConfig.showLanguages"
|
||||
class="row__cell row__cell--large"
|
||||
data-test-id="cell-language">
|
||||
data-cy-user-list-cell-language>
|
||||
<template v-if="editing">
|
||||
<label class="hidden-visually"
|
||||
:for="'language' + uniqueId">
|
||||
{{ t('settings', 'Set the language') }}
|
||||
</label>
|
||||
<NcSelect :id="'language' + uniqueId"
|
||||
data-cy-user-list-input-language
|
||||
:data-loading="loading.languages || undefined"
|
||||
:allow-empty="false"
|
||||
:disabled="isLoadingField"
|
||||
:loading="loading.languages"
|
||||
|
@ -226,7 +236,7 @@
|
|||
</td>
|
||||
|
||||
<td v-if="showConfig.showUserBackend || showConfig.showStoragePath"
|
||||
data-test-id="cell-storageLocation"
|
||||
data-cy-user-list-cell-storage-location
|
||||
class="row__cell row__cell--large">
|
||||
<template v-if="!isObfuscated">
|
||||
<span v-if="showConfig.showUserBackend">{{ user.backend }}</span>
|
||||
|
@ -241,11 +251,11 @@
|
|||
<td v-if="showConfig.showLastLogin"
|
||||
:title="userLastLoginTooltip"
|
||||
class="row__cell"
|
||||
data-test-id="cell-lastLogin">
|
||||
data-cy-user-list-cell-last-login>
|
||||
<span v-if="!isObfuscated">{{ userLastLogin }}</span>
|
||||
</td>
|
||||
|
||||
<td class="row__cell row__cell--large row__cell--fill" data-test-id="cell-manager">
|
||||
<td class="row__cell row__cell--large row__cell--fill" data-cy-user-list-cell-manager>
|
||||
<template v-if="editing">
|
||||
<label class="hidden-visually"
|
||||
:for="'manager' + uniqueId">
|
||||
|
@ -253,6 +263,8 @@
|
|||
</label>
|
||||
<NcSelect v-model="currentManager"
|
||||
class="select--fill"
|
||||
data-cy-user-list-input-manager
|
||||
:data-loading="loading.manager || undefined"
|
||||
:input-id="'manager' + uniqueId"
|
||||
:close-on-select="true"
|
||||
:disabled="isLoadingField"
|
||||
|
@ -271,7 +283,7 @@
|
|||
</span>
|
||||
</td>
|
||||
|
||||
<td class="row__cell row__cell--actions" data-test-id="cell-actions">
|
||||
<td class="row__cell row__cell--actions" data-cy-user-list-cell-actions>
|
||||
<UserRowActions v-if="visible && !isObfuscated && canEdit && !loading.all"
|
||||
:actions="userActions"
|
||||
:disabled="isLoadingField"
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
<NcActions :aria-label="t('settings', 'Toggle user actions menu')"
|
||||
:disabled="disabled"
|
||||
:inline="1">
|
||||
<NcActionButton data-test-id="button-toggleEdit"
|
||||
:data-test="`${edit}`"
|
||||
<NcActionButton :data-cy-user-list-action-toggle-edit="`${edit}`"
|
||||
:disabled="disabled"
|
||||
@click="toggleEdit">
|
||||
{{ edit ? t('settings', 'Done') : t('settings', 'Edit') }}
|
||||
|
|
|
@ -24,7 +24,6 @@ import { User } from '@nextcloud/cypress'
|
|||
import { getUserListRow, handlePasswordConfirmation } from './usersUtils'
|
||||
|
||||
const admin = new User('admin', 'admin')
|
||||
const jdoe = new User('jdoe', 'jdoe')
|
||||
const john = new User('john', '123456')
|
||||
|
||||
describe('Settings: Create and delete users', function() {
|
||||
|
@ -38,7 +37,7 @@ describe('Settings: Create and delete users', function() {
|
|||
cy.login(admin)
|
||||
cy.listUsers().then((users) => {
|
||||
cy.login(admin)
|
||||
if ((users as string[]).includes('john')) {
|
||||
if ((users as string[]).includes(john.userId)) {
|
||||
// ensure created user is deleted
|
||||
cy.deleteUser(john).login(admin)
|
||||
// ensure deleted user is not present
|
||||
|
@ -55,15 +54,15 @@ describe('Settings: Create and delete users', function() {
|
|||
// see that the username is ""
|
||||
cy.get('input[data-test="username"]').should('exist').and('have.value', '')
|
||||
// set the username to john
|
||||
cy.get('input[data-test="username"]').type('john')
|
||||
cy.get('input[data-test="username"]').type(john.userId)
|
||||
// see that the username is john
|
||||
cy.get('input[data-test="username"]').should('have.value', 'john')
|
||||
cy.get('input[data-test="username"]').should('have.value', john.userId)
|
||||
// see that the password is ""
|
||||
cy.get('input[type="password"]').should('exist').and('have.value', '')
|
||||
// set the password to 123456
|
||||
cy.get('input[type="password"]').type('123456')
|
||||
cy.get('input[type="password"]').type(john.password)
|
||||
// see that the password is 123456
|
||||
cy.get('input[type="password"]').should('have.value', '123456')
|
||||
cy.get('input[type="password"]').should('have.value', john.password)
|
||||
// submit the new user form
|
||||
cy.get('button[type="submit"]').click()
|
||||
})
|
||||
|
@ -72,10 +71,9 @@ describe('Settings: Create and delete users', function() {
|
|||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// see that the created user is in the list
|
||||
cy.get('tbody.user-list__body tr[data-test="john"]').within(() => {
|
||||
getUserListRow(john.userId)
|
||||
// see that the list of users contains the user john
|
||||
cy.contains('john').should('exist')
|
||||
})
|
||||
.contains(john.userId).should('exist')
|
||||
})
|
||||
|
||||
it('Can create a user with additional field data', function() {
|
||||
|
@ -85,8 +83,8 @@ describe('Settings: Create and delete users', function() {
|
|||
cy.get('form[data-test="form"]').within(() => {
|
||||
// set the username
|
||||
cy.get('input[data-test="username"]').should('exist').and('have.value', '')
|
||||
cy.get('input[data-test="username"]').type('john')
|
||||
cy.get('input[data-test="username"]').should('have.value', 'john')
|
||||
cy.get('input[data-test="username"]').type(john.userId)
|
||||
cy.get('input[data-test="username"]').should('have.value', john.userId)
|
||||
// set the display name
|
||||
cy.get('input[data-test="displayName"]').should('exist').and('have.value', '')
|
||||
cy.get('input[data-test="displayName"]').type('John Smith')
|
||||
|
@ -97,8 +95,8 @@ describe('Settings: Create and delete users', function() {
|
|||
cy.get('input[data-test="email"]').should('have.value', 'john@example.org')
|
||||
// set the password
|
||||
cy.get('input[type="password"]').should('exist').and('have.value', '')
|
||||
cy.get('input[type="password"]').type('123456')
|
||||
cy.get('input[type="password"]').should('have.value', '123456')
|
||||
cy.get('input[type="password"]').type(john.password)
|
||||
cy.get('input[type="password"]').should('have.value', john.password)
|
||||
// submit the new user form
|
||||
cy.get('button[type="submit"]').click()
|
||||
})
|
||||
|
@ -107,35 +105,42 @@ describe('Settings: Create and delete users', function() {
|
|||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// see that the created user is in the list
|
||||
getUserListRow('john')
|
||||
getUserListRow(john.userId)
|
||||
// see that the list of users contains the user john
|
||||
.contains('john')
|
||||
.contains(john.userId)
|
||||
.should('exist')
|
||||
})
|
||||
|
||||
it('Can delete a user', function() {
|
||||
let testUser
|
||||
// create user
|
||||
cy.createUser(jdoe).login(admin)
|
||||
cy.createRandomUser()
|
||||
.then(($user) => {
|
||||
testUser = $user
|
||||
})
|
||||
cy.login(admin)
|
||||
// ensure created user is present
|
||||
cy.reload().login(admin)
|
||||
cy.reload().then(() => {
|
||||
// see that the user is in the list
|
||||
getUserListRow(testUser.userId).within(() => {
|
||||
// see that the list of users contains the user testUser
|
||||
cy.contains(testUser.userId).should('exist')
|
||||
// open the actions menu for the user
|
||||
cy.get('[data-cy-user-list-cell-actions]')
|
||||
.find('button.action-item__menutoggle')
|
||||
.click({ force: true })
|
||||
})
|
||||
|
||||
// see that the user is in the list
|
||||
cy.get(`tbody.user-list__body tr[data-test="${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('td.row__cell--actions button.action-item__menutoggle').click()
|
||||
// The "Delete user" action in the actions menu is shown and clicked
|
||||
cy.get('.action-item__popper .action').contains('Delete user').should('exist').click({ force: true })
|
||||
// And confirmation dialog accepted
|
||||
cy.get('.oc-dialog button').contains(`Delete ${testUser.userId}`).click({ force: true })
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// deleted clicked the user is not shown anymore
|
||||
getUserListRow(testUser.userId).should('not.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()
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// deleted clicked the user is not shown anymore
|
||||
cy.get(`tbody.user-list__body tr[data-test="${jdoe.userId}"]`).should('not.exist')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import type { User } from '@nextcloud/cypress'
|
||||
|
||||
/**
|
||||
* Assert that `element` does not exist or is not visible
|
||||
* Useful in cases such as when NcModal is opened/closed rapidly
|
||||
|
@ -33,12 +35,28 @@ export function assertNotExistOrNotVisible(element: JQuery<HTMLElement>) {
|
|||
expect(doesNotExist || isNotVisible, 'does not exist or is not visible').to.be.true
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function ensure users and groups in this tests have a clean state
|
||||
*/
|
||||
export function clearState() {
|
||||
// cleanup ignoring any failures
|
||||
cy.runOccCommand('group:list --output=json').then(($result) => {
|
||||
const groups = Object.keys(JSON.parse($result.stdout)).filter((name) => name !== 'admin')
|
||||
groups.forEach((groupID) => cy.runOccCommand(`group:delete '${groupID}'`))
|
||||
})
|
||||
|
||||
cy.runOccCommand('user:list --output=json').then(($result) => {
|
||||
const users = Object.keys(JSON.parse($result.stdout)).filter((name) => name !== 'admin')
|
||||
users.forEach((userID) => cy.runOccCommand(`user:delete '${userID}'`))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the settings users list
|
||||
* @return Cypress chainable object
|
||||
*/
|
||||
export function getUserList() {
|
||||
return cy.get('[data-test-id="userList"]')
|
||||
return cy.get('[data-cy-user-list]')
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,7 +66,37 @@ export function getUserList() {
|
|||
* @return Cypress chainable object
|
||||
*/
|
||||
export function getUserListRow(userId: string) {
|
||||
return getUserList().find(`tr[data-test="${userId}"]`)
|
||||
return getUserList().find(`[data-cy-user-row="${userId}"]`)
|
||||
}
|
||||
|
||||
export function waitLoading(selector: string) {
|
||||
// We need to make sure the element is loading, otherwise the "done loading" will succeed even if we did not start loading.
|
||||
// But Cypress might also be simply too slow to catch the loading phase. Thats why we need to wait in this case.
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.get(`${selector}[data-loading]`).if().should('exist').else().wait(1000)
|
||||
// https://github.com/NoriSte/cypress-wait-until/issues/75#issuecomment-572685623
|
||||
cy.waitUntil(() => Cypress.$(selector).length > 0 && !Cypress.$(selector).attr('data-loading')?.length, { timeout: 10000 })
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the edit button of the user row
|
||||
* @param user The user row to edit
|
||||
* @param toEdit True if it should be switch to edit mode, false to switch to read-only
|
||||
*/
|
||||
export function toggleEditButton(user: User, toEdit = true) {
|
||||
// see that the list of users contains the user
|
||||
getUserListRow(user.userId).should('exist')
|
||||
// toggle the edit mode for the user
|
||||
.find('[data-cy-user-list-cell-actions]')
|
||||
.find(`[data-cy-user-list-action-toggle-edit="${!toEdit}"]`)
|
||||
.if()
|
||||
.click({ force: true })
|
||||
.else()
|
||||
// otherwise ensure the button is already in edit mode
|
||||
.then(() => getUserListRow(user.userId)
|
||||
.find(`[data-cy-user-list-action-toggle-edit="${toEdit}"]`)
|
||||
.should('exist'),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,7 +107,6 @@ export function handlePasswordConfirmation(adminPassword = 'admin') {
|
|||
const handleModal = (context: Cypress.Chainable) => {
|
||||
return context.contains('.modal-container', 'Confirm your password')
|
||||
.if()
|
||||
.if('visible')
|
||||
.within(() => {
|
||||
cy.get('input[type="password"]').type(adminPassword)
|
||||
cy.get('button').contains('Confirm').click()
|
||||
|
|
|
@ -49,9 +49,7 @@ describe('Settings: Show and hide columns', function() {
|
|||
|
||||
it('Can show a column', function() {
|
||||
// see that the language column is not in the header
|
||||
cy.get('.user-list__header tr').within(() => {
|
||||
cy.contains('Language').should('not.exist')
|
||||
})
|
||||
cy.get('[data-cy-user-list-header-languages]').should('not.exist')
|
||||
|
||||
// see that the language column is not in all user rows
|
||||
cy.get('tbody.user-list__body tr').each(($row) => {
|
||||
|
@ -72,25 +70,21 @@ describe('Settings: Show and hide columns', function() {
|
|||
cy.waitUntil(() => cy.get('.modal-container').should(el => assertNotExistOrNotVisible(el)))
|
||||
|
||||
// see that the language column is in the header
|
||||
cy.get('.user-list__header tr').within(() => {
|
||||
cy.contains('Language').should('exist')
|
||||
})
|
||||
cy.get('[data-cy-user-list-header-languages]').should('exist')
|
||||
|
||||
// see that the language column is in all user rows
|
||||
getUserList().find('tbody tr').each(($row) => {
|
||||
cy.wrap($row).get('[data-test-id="cell-language"]').should('exist')
|
||||
cy.wrap($row).get('[data-cy-user-list-cell-language]').should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
it('Can hide a column', function() {
|
||||
// see that the last login column is in the header
|
||||
cy.get('.user-list__header tr').within(() => {
|
||||
cy.contains('Last login').should('exist')
|
||||
})
|
||||
cy.get('[data-cy-user-list-header-last-login]').should('exist')
|
||||
|
||||
// see that the last login column is in all user rows
|
||||
getUserList().find('tbody tr').each(($row) => {
|
||||
cy.wrap($row).get('[data-test-id="cell-lastLogin"]').should('exist')
|
||||
cy.wrap($row).get('[data-cy-user-list-cell-last-login]').should('exist')
|
||||
})
|
||||
|
||||
// open the settings dialog
|
||||
|
@ -107,13 +101,11 @@ describe('Settings: Show and hide columns', function() {
|
|||
cy.waitUntil(() => cy.get('.modal-container').should(el => assertNotExistOrNotVisible(el)))
|
||||
|
||||
// see that the last login column is not in the header
|
||||
cy.get('.user-list__header tr').within(() => {
|
||||
cy.contains('Last login').should('not.exist')
|
||||
})
|
||||
cy.get('[data-cy-user-list-header-last-login]').should('not.exist')
|
||||
|
||||
// see that the last login column is not in all user rows
|
||||
getUserList().find('tbody tr').each(($row) => {
|
||||
cy.wrap($row).get('[data-test-id="cell-lastLogin"]').should('not.exist')
|
||||
cy.wrap($row).get('[data-cy-user-list-cell-last-login]').should('not.exist')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -21,61 +21,67 @@
|
|||
*/
|
||||
|
||||
import { User } from '@nextcloud/cypress'
|
||||
import { clearState, getUserListRow } from './usersUtils'
|
||||
|
||||
const admin = new User('admin', 'admin')
|
||||
const jdoe = new User('jdoe', 'jdoe')
|
||||
|
||||
describe('Settings: Disable and enable users', function() {
|
||||
before(function() {
|
||||
cy.createUser(jdoe)
|
||||
let testUser: User
|
||||
|
||||
beforeEach(function() {
|
||||
clearState()
|
||||
cy.createRandomUser().then(($user) => {
|
||||
testUser = $user
|
||||
})
|
||||
cy.login(admin)
|
||||
// open the User settings
|
||||
cy.visit('/settings/users')
|
||||
})
|
||||
|
||||
// Not guranteed to run but would be nice to cleanup
|
||||
after(() => {
|
||||
cy.deleteUser(jdoe)
|
||||
cy.deleteUser(testUser)
|
||||
})
|
||||
|
||||
it('Can disable the user', function() {
|
||||
// ensure user is enabled
|
||||
cy.enableUser(jdoe)
|
||||
cy.enableUser(testUser)
|
||||
|
||||
// see that the user is in the list of active users
|
||||
cy.get(`tbody.user-list__body tr[data-test="${jdoe.userId}"]`).within(() => {
|
||||
// see that the list of users contains the user jdoe
|
||||
cy.contains(jdoe.userId).should('exist')
|
||||
getUserListRow(testUser.userId).within(() => {
|
||||
// see that the list of users contains the user testUser
|
||||
cy.contains(testUser.userId).should('exist')
|
||||
// open the actions menu for the user
|
||||
cy.get('td.row__cell--actions button.action-item__menutoggle').click({ scrollBehavior: 'center' })
|
||||
cy.get('[data-cy-user-list-cell-actions] button.action-item__menutoggle').click({ scrollBehavior: 'center' })
|
||||
})
|
||||
|
||||
// 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(`tbody.user-list__body tr[data-test="${jdoe.userId}"]`).should('not.exist')
|
||||
getUserListRow(testUser.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(`tbody.user-list__body tr[data-test="${jdoe.userId}"]`).should('exist')
|
||||
getUserListRow(testUser.userId).should('exist')
|
||||
})
|
||||
|
||||
it('Can enable the user', function() {
|
||||
// ensure user is disabled
|
||||
cy.enableUser(jdoe, false)
|
||||
cy.enableUser(testUser, false).reload()
|
||||
|
||||
// Open disabled users section
|
||||
cy.get('#disabled a').click()
|
||||
cy.url().should('match', /\/disabled/)
|
||||
|
||||
// see that the user is in the list of active users
|
||||
cy.get(`tbody.user-list__body tr[data-test="${jdoe.userId}"]`).within(() => {
|
||||
// see that the list of disabled users contains the user jdoe
|
||||
cy.contains(jdoe.userId).should('exist')
|
||||
getUserListRow(testUser.userId).within(() => {
|
||||
// see that the list of disabled users contains the user testUser
|
||||
cy.contains(testUser.userId).should('exist')
|
||||
// open the actions menu for the user
|
||||
cy.get('td.row__cell--actions button.action-item__menutoggle').click({ scrollBehavior: 'center' })
|
||||
cy.get('[data-cy-user-list-cell-actions] button.action-item__menutoggle').click({ scrollBehavior: 'center' })
|
||||
})
|
||||
|
||||
// The "Enable user" action in the actions menu is shown and clicked
|
||||
|
|
|
@ -21,18 +21,21 @@
|
|||
*/
|
||||
|
||||
import { User } from '@nextcloud/cypress'
|
||||
import { handlePasswordConfirmation } from './usersUtils'
|
||||
import { getUserListRow, handlePasswordConfirmation, toggleEditButton } from './usersUtils'
|
||||
|
||||
// eslint-disable-next-line n/no-extraneous-import
|
||||
import randomString from 'crypto-random-string'
|
||||
|
||||
const admin = new User('admin', 'admin')
|
||||
|
||||
describe('Settings: Create and delete groups', () => {
|
||||
describe('Settings: Create groups', () => {
|
||||
before(() => {
|
||||
cy.login(admin)
|
||||
// open the User settings
|
||||
cy.visit('/settings/users')
|
||||
})
|
||||
|
||||
it('Can create a group', () => {
|
||||
const groupName = randomString(7)
|
||||
// open the Create group menu
|
||||
cy.get('button[aria-label="Create group"]').click()
|
||||
|
||||
|
@ -40,9 +43,9 @@ describe('Settings: Create and delete groups', () => {
|
|||
// see that the group name is ""
|
||||
cy.get('input[placeholder="Group name"]').should('exist').and('have.value', '')
|
||||
// set the group name to foo
|
||||
cy.get('input[placeholder="Group name"]').type('foo')
|
||||
cy.get('input[placeholder="Group name"]').type(groupName)
|
||||
// see that the group name is foo
|
||||
cy.get('input[placeholder="Group name"]').should('have.value', 'foo')
|
||||
cy.get('input[placeholder="Group name"]').should('have.value', groupName)
|
||||
// submit the group name
|
||||
cy.get('input[placeholder="Group name"] ~ button').click()
|
||||
})
|
||||
|
@ -53,38 +56,170 @@ describe('Settings: Create and delete groups', () => {
|
|||
// see that the created group is in the list
|
||||
cy.get('ul.app-navigation__list').within(() => {
|
||||
// see that the list of groups contains the group foo
|
||||
cy.contains('foo').should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
it('Can delete a group', () => {
|
||||
// see that the group is in the list
|
||||
cy.get('ul.app-navigation__list').within(() => {
|
||||
// see that the list of groups contains the group foo
|
||||
cy.contains('foo').should('exist')
|
||||
// open the actions menu for the group
|
||||
cy.contains('li', 'foo').within(() => {
|
||||
cy.get('button.action-item__menutoggle').click()
|
||||
})
|
||||
})
|
||||
|
||||
// The "Remove group" action in the actions menu is shown and clicked
|
||||
cy.get('.action-item__popper button').contains('Remove group').should('exist').click()
|
||||
// And confirmation dialog accepted
|
||||
cy.get('.modal-container button').contains('Confirm').click()
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
cy.get('body').contains('.modal-container', 'Confirm your password')
|
||||
.if('visible')
|
||||
.then(($modal) => {
|
||||
cy.wrap($modal).find('input[type="password"]').type(admin.password)
|
||||
cy.wrap($modal).find('button').contains('Confirm').click()
|
||||
})
|
||||
|
||||
// deleted group is not shown anymore
|
||||
cy.get('ul.app-navigation__list').within(() => {
|
||||
// see that the list of groups does not contain the group foo
|
||||
cy.contains('foo').should('not.exist')
|
||||
cy.contains(groupName).should('exist')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Settings: Assign user to a group', { testIsolation: false }, () => {
|
||||
const groupName = randomString(7)
|
||||
let testUser: User
|
||||
|
||||
after(() => cy.deleteUser(testUser))
|
||||
before(() => {
|
||||
cy.createRandomUser().then((user) => {
|
||||
testUser = user
|
||||
})
|
||||
cy.runOccCommand(`group:add '${groupName}'`)
|
||||
cy.login(admin)
|
||||
cy.visit('/settings/users')
|
||||
})
|
||||
|
||||
it('see that the group is in the list', () => {
|
||||
cy.get('ul.app-navigation__list').contains('li', groupName).should('exist')
|
||||
cy.get('ul.app-navigation__list').contains('li', groupName).within(() => {
|
||||
cy.get('.counter-bubble__counter')
|
||||
.should('not.exist') // is hidden when 0
|
||||
})
|
||||
})
|
||||
|
||||
it('see that the user is in the list', () => {
|
||||
getUserListRow(testUser.userId)
|
||||
.contains(testUser.userId)
|
||||
.should('exist')
|
||||
.scrollIntoView()
|
||||
})
|
||||
|
||||
it('switch into user edit mode', () => {
|
||||
toggleEditButton(testUser)
|
||||
getUserListRow(testUser.userId)
|
||||
.find('[data-cy-user-list-input-groups]')
|
||||
.should('exist')
|
||||
})
|
||||
|
||||
it('assign the group', () => {
|
||||
// focus inside the input
|
||||
getUserListRow(testUser.userId)
|
||||
.find('[data-cy-user-list-input-groups] input')
|
||||
.click({ force: true })
|
||||
// enter the group name
|
||||
getUserListRow(testUser.userId)
|
||||
.find('[data-cy-user-list-input-groups] input')
|
||||
.type(`${groupName.slice(0, 5)}`) // only type part as otherwise we would create a new one with the same name
|
||||
cy.contains('li.vs__dropdown-option', groupName)
|
||||
.click({ force: true })
|
||||
|
||||
handlePasswordConfirmation(admin.password)
|
||||
})
|
||||
|
||||
it('leave the user edit mode', () => {
|
||||
toggleEditButton(testUser, false)
|
||||
})
|
||||
|
||||
it('see the group was successfully assigned', () => {
|
||||
// see a new memeber
|
||||
cy.get('ul.app-navigation__list')
|
||||
.contains('li', groupName)
|
||||
.find('.counter-bubble__counter')
|
||||
.should('contain', '1')
|
||||
})
|
||||
|
||||
it('validate the user was added on backend', () => {
|
||||
cy.runOccCommand(`user:info --output=json '${testUser.userId}'`).then((output) => {
|
||||
cy.wrap(output.code).should('eq', 0)
|
||||
cy.wrap(JSON.parse(output.stdout)?.groups).should('include', groupName)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Settings: Delete an empty group', { testIsolation: false }, () => {
|
||||
const groupName = randomString(7)
|
||||
|
||||
before(() => {
|
||||
cy.runOccCommand(`group:add '${groupName}'`)
|
||||
cy.login(admin)
|
||||
cy.visit('/settings/users')
|
||||
})
|
||||
|
||||
it('see that the group is in the list', () => {
|
||||
cy.get('ul.app-navigation__list').within(() => {
|
||||
// see that the list of groups contains the group foo
|
||||
cy.contains(groupName).should('exist').scrollIntoView()
|
||||
// open the actions menu for the group
|
||||
cy.contains('li', groupName).within(() => {
|
||||
cy.get('button.action-item__menutoggle').click({ force: true })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('can delete the group', () => {
|
||||
// The "Remove group" action in the actions menu is shown and clicked
|
||||
cy.get('.action-item__popper button').contains('Remove group').should('exist').click({ force: true })
|
||||
// And confirmation dialog accepted
|
||||
cy.get('.modal-container button').contains('Confirm').click({ force: true })
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
handlePasswordConfirmation(admin.password)
|
||||
})
|
||||
|
||||
it('deleted group is not shown anymore', () => {
|
||||
cy.get('ul.app-navigation__list').within(() => {
|
||||
// see that the list of groups does not contain the group
|
||||
cy.contains(groupName).should('not.exist')
|
||||
})
|
||||
// and also not in database
|
||||
cy.runOccCommand('group:list --output=json').then(($response) => {
|
||||
const groups: string[] = Object.keys(JSON.parse($response.stdout))
|
||||
expect(groups).to.not.include(groupName)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Settings: Delete a non empty group', () => {
|
||||
let testUser: User
|
||||
const groupName = randomString(7)
|
||||
|
||||
before(() => {
|
||||
cy.runOccCommand(`group:add '${groupName}'`)
|
||||
cy.createRandomUser().then(($user) => {
|
||||
testUser = $user
|
||||
cy.runOccCommand(`group:addUser '${groupName}' '${$user.userId}'`)
|
||||
})
|
||||
cy.login(admin)
|
||||
cy.visit('/settings/users')
|
||||
})
|
||||
after(() => cy.deleteUser(testUser))
|
||||
|
||||
it('see that the group is in the list', () => {
|
||||
// see that the list of groups contains the group
|
||||
cy.get('ul.app-navigation__list').contains('li', groupName).should('exist').scrollIntoView()
|
||||
})
|
||||
|
||||
it('can delete the group', () => {
|
||||
// open the menu
|
||||
cy.get('ul.app-navigation__list')
|
||||
.contains('li', groupName)
|
||||
.find('button.action-item__menutoggle')
|
||||
.click({ force: true })
|
||||
|
||||
// The "Remove group" action in the actions menu is shown and clicked
|
||||
cy.get('.action-item__popper button').contains('Remove group').should('exist').click({ force: true })
|
||||
// And confirmation dialog accepted
|
||||
cy.get('.modal-container button').contains('Confirm').click({ force: true })
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
handlePasswordConfirmation(admin.password)
|
||||
})
|
||||
|
||||
it('deleted group is not shown anymore', () => {
|
||||
cy.get('ul.app-navigation__list').within(() => {
|
||||
// see that the list of groups does not contain the group foo
|
||||
cy.contains(groupName).should('not.exist')
|
||||
})
|
||||
// and also not in database
|
||||
cy.runOccCommand('group:list --output=json').then(($response) => {
|
||||
const groups: string[] = Object.keys(JSON.parse($response.stdout))
|
||||
expect(groups).to.not.include(groupName)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -21,92 +21,260 @@
|
|||
*/
|
||||
|
||||
import { User } from '@nextcloud/cypress'
|
||||
import { getUserListRow, handlePasswordConfirmation } from './usersUtils'
|
||||
import { clearState, getUserListRow, handlePasswordConfirmation, toggleEditButton, waitLoading } from './usersUtils'
|
||||
|
||||
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)
|
||||
// open the User settings
|
||||
cy.visit('/settings/users')
|
||||
})
|
||||
let user: User
|
||||
|
||||
beforeEach(function() {
|
||||
// reset to read-only mode: try to find the edit button and click it if set to editing
|
||||
getUserListRow(jdoe.userId)
|
||||
.find('[data-test-id="cell-actions"]')
|
||||
// replace with following (more error resilent) with nextcloud-vue 8
|
||||
// find('[data-test-id="button-toggleEdit"][data-test="true"]')
|
||||
.find('button[aria-label="Done"]')
|
||||
.if()
|
||||
.click({ force: true })
|
||||
})
|
||||
|
||||
after(() => {
|
||||
cy.deleteUser(jdoe)
|
||||
clearState()
|
||||
cy.createRandomUser().then(($user) => { user = $user })
|
||||
cy.login(admin)
|
||||
})
|
||||
|
||||
it('Can change the display name', function() {
|
||||
// see that the list of users contains the user jdoe
|
||||
getUserListRow(jdoe.userId).should('exist')
|
||||
// toggle the edit mode for the user jdoe
|
||||
.find('[data-test-id="cell-actions"]')
|
||||
.find('button[aria-label="Edit"]')
|
||||
// replace with following (more error resilent) with nextcloud-vue 8
|
||||
// find('[data-test-id="button-toggleEdit"]')
|
||||
.click({ force: true })
|
||||
// open the User settings as admin
|
||||
cy.visit('/settings/users')
|
||||
|
||||
getUserListRow(jdoe.userId).within(() => {
|
||||
// toggle edit button into edit mode
|
||||
toggleEditButton(user, true)
|
||||
|
||||
getUserListRow(user.userId).within(() => {
|
||||
// set the display name
|
||||
cy.get('input[data-test-id="input-displayName"]').should('exist').and('have.value', 'jdoe')
|
||||
cy.get('input[data-test-id="input-displayName"]').clear()
|
||||
cy.get('input[data-test-id="input-displayName"]').type('John Doe')
|
||||
cy.get('input[data-test-id="input-displayName"]').should('have.value', 'John Doe')
|
||||
cy.get('input[data-test-id="input-displayName"] ~ button').click()
|
||||
cy.get('[data-cy-user-list-input-displayname]').should('exist').and('have.value', user.userId)
|
||||
cy.get('[data-cy-user-list-input-displayname]').clear()
|
||||
cy.get('[data-cy-user-list-input-displayname]').type('John Doe')
|
||||
cy.get('[data-cy-user-list-input-displayname]').should('have.value', 'John Doe')
|
||||
cy.get('[data-cy-user-list-input-displayname] ~ button').click()
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// see that the display name cell is done loading
|
||||
cy.get('[data-test-id="input-displayName"]').should('have.attr', 'data-test-loading', 'true')
|
||||
cy.waitUntil(() => cy.get('[data-test-id="input-displayName"]').should('have.attr', 'data-test-loading', 'false'), { timeout: 10000 })
|
||||
waitLoading('[data-cy-user-list-input-displayname]')
|
||||
})
|
||||
|
||||
// Success message is shown
|
||||
cy.get('.toastify.toast-success').contains(/Display.+name.+was.+successfully.+changed/i).should('exist')
|
||||
})
|
||||
|
||||
it('Can change the password', function() {
|
||||
// see that the list of users contains the user jdoe
|
||||
getUserListRow(jdoe.userId).should('exist')
|
||||
// toggle the edit mode for the user jdoe
|
||||
.find('[data-test-id="cell-actions"]')
|
||||
.find('button[aria-label="Edit"]')
|
||||
// replace with following (more error resilent) with nextcloud-vue 8
|
||||
// find('[data-test-id="button-toggleEdit"]')
|
||||
.click({ force: true })
|
||||
// open the User settings as admin
|
||||
cy.visit('/settings/users')
|
||||
|
||||
getUserListRow(jdoe.userId).within(() => {
|
||||
// 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('input[type="password"] ~ button').click()
|
||||
// toggle edit button into edit mode
|
||||
toggleEditButton(user, true)
|
||||
|
||||
getUserListRow(user.userId).within(() => {
|
||||
// see that the password of user is ""
|
||||
cy.get('[data-cy-user-list-input-password]').should('exist').and('have.value', '')
|
||||
// set the password for user to 123456
|
||||
cy.get('[data-cy-user-list-input-password]').type('123456')
|
||||
// When I set the password for user to 123456
|
||||
cy.get('[data-cy-user-list-input-password]').should('have.value', '123456')
|
||||
cy.get('[data-cy-user-list-input-password] ~ button').click()
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// see that the password cell for user user0 is done loading
|
||||
cy.get('[data-test-id="input-password"]').should('have.attr', 'data-test-loading', 'true')
|
||||
cy.waitUntil(() => cy.get('[data-test-id="input-password"]').should('have.attr', 'data-test-loading', 'false'), { timeout: 10000 })
|
||||
// see that the password cell for user is done loading
|
||||
waitLoading('[data-cy-user-list-input-password]')
|
||||
// password input is emptied on change
|
||||
cy.get('[data-test-id="input-password"]').should('have.value', '')
|
||||
cy.get('[data-cy-user-list-input-password]').should('have.value', '')
|
||||
})
|
||||
|
||||
// Success message is shown
|
||||
cy.get('.toastify.toast-success').contains(/Password.+successfully.+changed/i).should('exist')
|
||||
})
|
||||
|
||||
it('Can change the email address', function() {
|
||||
// open the User settings as admin
|
||||
cy.visit('/settings/users')
|
||||
|
||||
// toggle edit button into edit mode
|
||||
toggleEditButton(user, true)
|
||||
|
||||
getUserListRow(user.userId).find('[data-cy-user-list-cell-email]').within(() => {
|
||||
// see that the email of user is ""
|
||||
cy.get('input').should('exist').and('have.value', '')
|
||||
// set the email for user to mymail@example.com
|
||||
cy.get('input').type('mymail@example.com')
|
||||
// When I set the password for user to mymail@example.com
|
||||
cy.get('input').should('have.value', 'mymail@example.com')
|
||||
cy.get('input ~ button').click()
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// see that the password cell for user is done loading
|
||||
waitLoading('[data-cy-user-list-input-email]')
|
||||
})
|
||||
|
||||
// Success message is shown
|
||||
cy.get('.toastify.toast-success').contains(/Email.+successfully.+changed/i).should('exist')
|
||||
})
|
||||
|
||||
it('Can change the user quota to a predefined one', function() {
|
||||
// open the User settings as admin
|
||||
cy.visit('/settings/users')
|
||||
|
||||
// toggle edit button into edit mode
|
||||
toggleEditButton(user, true)
|
||||
|
||||
getUserListRow(user.userId).find('[data-cy-user-list-cell-quota]').scrollIntoView()
|
||||
getUserListRow(user.userId).find('[data-cy-user-list-cell-quota] [data-cy-user-list-input-quota]').within(() => {
|
||||
// see that the quota of user is unlimited
|
||||
cy.get('.vs__selected').should('exist').and('contain.text', 'Unlimited')
|
||||
// Open the quota selector
|
||||
cy.get('[role="combobox"]').click({ force: true })
|
||||
// see that there are default options for the quota
|
||||
cy.get('li').then(($options) => {
|
||||
expect($options).to.have.length(5)
|
||||
cy.wrap($options).contains('Default quota')
|
||||
cy.wrap($options).contains('Unlimited')
|
||||
cy.wrap($options).contains('1 GB')
|
||||
cy.wrap($options).contains('10 GB')
|
||||
// select 5 GB
|
||||
cy.wrap($options).contains('5 GB').click({ force: true })
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
handlePasswordConfirmation(admin.password)
|
||||
})
|
||||
// see that the quota of user is 5 GB
|
||||
cy.get('.vs__selected').should('exist').and('contain.text', '5 GB')
|
||||
})
|
||||
|
||||
// see that the changes are loading
|
||||
waitLoading('[data-cy-user-list-input-quota]')
|
||||
|
||||
// finish editing the user
|
||||
toggleEditButton(user, false)
|
||||
|
||||
// I see that the quota was set on the backend
|
||||
cy.runOccCommand(`user:info --output=json '${user.userId}'`).then(($result) => {
|
||||
expect($result.code).to.equal(0)
|
||||
const info = JSON.parse($result.stdout)
|
||||
expect(info?.quota).to.equal('5 GB')
|
||||
})
|
||||
})
|
||||
|
||||
it('Can change the user quota to a custom value', function() {
|
||||
// open the User settings as admin
|
||||
cy.visit('/settings/users')
|
||||
|
||||
// toggle edit button into edit mode
|
||||
toggleEditButton(user, true)
|
||||
|
||||
getUserListRow(user.userId).find('[data-cy-user-list-cell-quota]').scrollIntoView()
|
||||
getUserListRow(user.userId).find('[data-cy-user-list-cell-quota]').within(() => {
|
||||
// see that the quota of user is unlimited
|
||||
cy.get('.vs__selected').should('exist').and('contain.text', 'Unlimited')
|
||||
// set the quota to 4 MB
|
||||
cy.get('[data-cy-user-list-input-quota] input').type('4 MB{enter}')
|
||||
|
||||
// Make sure no confirmation modal is shown
|
||||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// see that the quota of user is 4 MB
|
||||
// TODO: Enable this after the file size handling is fixed
|
||||
// cy.get('.vs__selected').should('exist').and('contain.text', '4 MB')
|
||||
|
||||
// see that the changes are loading
|
||||
waitLoading('[data-cy-user-list-input-quota]')
|
||||
})
|
||||
|
||||
// finish editing the user
|
||||
toggleEditButton(user, false)
|
||||
|
||||
// I see that the quota was set on the backend
|
||||
cy.runOccCommand(`user:info --output=json '${user.userId}'`).then(($result) => {
|
||||
expect($result.code).to.equal(0)
|
||||
// TODO: Enable this after the file size handling is fixed!!!!!!
|
||||
// const info = JSON.parse($result.stdout)
|
||||
// expect(info?.quota).to.equal('4 MB')
|
||||
})
|
||||
})
|
||||
|
||||
it('Can set manager of a user', function() {
|
||||
// create the manager
|
||||
let manager: User
|
||||
cy.createRandomUser().then(($user) => { manager = $user })
|
||||
|
||||
// open the User settings as admin
|
||||
cy.login(admin)
|
||||
cy.visit('/settings/users')
|
||||
|
||||
// toggle edit button into edit mode
|
||||
toggleEditButton(user, true)
|
||||
|
||||
getUserListRow(user.userId)
|
||||
.find('[data-cy-user-list-cell-manager]')
|
||||
.scrollIntoView()
|
||||
|
||||
getUserListRow(user.userId).find('[data-cy-user-list-cell-manager]').within(() => {
|
||||
// see that the user has no manager
|
||||
cy.get('.vs__selected').should('not.exist')
|
||||
// Open the dropdown menu
|
||||
cy.get('[role="combobox"]').click({ force: true })
|
||||
// select the manager
|
||||
cy.contains('li', manager.userId).click({ force: true })
|
||||
|
||||
// Handle password confirmation on time out
|
||||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// see that the user has a manager set
|
||||
cy.get('.vs__selected').should('exist').and('contain.text', manager.userId)
|
||||
})
|
||||
|
||||
// see that the changes are loading
|
||||
waitLoading('[data-cy-user-list-input-manager]')
|
||||
|
||||
// finish editing the user
|
||||
toggleEditButton(user, false)
|
||||
|
||||
// validate the manager is set
|
||||
cy.getUserData(user).then(($result) => expect($result.body).to.contain(`<manager>${manager.userId}</manager>`))
|
||||
})
|
||||
|
||||
it('Can make user a subadmin of a group', function() {
|
||||
// create a group
|
||||
const groupName = 'userstestgroup'
|
||||
cy.runOccCommand(`group:add '${groupName}'`)
|
||||
|
||||
// open the User settings as admin
|
||||
cy.visit('/settings/users')
|
||||
|
||||
// toggle edit button into edit mode
|
||||
toggleEditButton(user, true)
|
||||
|
||||
getUserListRow(user.userId).find('[data-cy-user-list-cell-subadmins]').scrollIntoView()
|
||||
getUserListRow(user.userId).find('[data-cy-user-list-cell-subadmins]').within(() => {
|
||||
// see that the user is no subadmin
|
||||
cy.get('.vs__selected').should('not.exist')
|
||||
// Open the dropdown menu
|
||||
cy.get('[role="combobox"]').click({ force: true })
|
||||
// select the group
|
||||
cy.contains('li', groupName).click({ force: true })
|
||||
|
||||
// handle password confirmation on time out
|
||||
handlePasswordConfirmation(admin.password)
|
||||
|
||||
// see that the user is subadmin of the group
|
||||
cy.get('.vs__selected').should('exist').and('contain.text', groupName)
|
||||
})
|
||||
|
||||
waitLoading('[data-cy-user-list-input-subadmins]')
|
||||
|
||||
// finish editing the user
|
||||
toggleEditButton(user, false)
|
||||
|
||||
// I see that the quota was set on the backend
|
||||
cy.getUserData(user).then(($response) => {
|
||||
expect($response.status).to.equal(200)
|
||||
const dom = (new DOMParser()).parseFromString($response.body, 'text/xml')
|
||||
expect(dom.querySelector('subadmin element')?.textContent).to.contain(groupName)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -67,7 +67,7 @@ declare global {
|
|||
/**
|
||||
* Run an occ command in the docker container.
|
||||
*/
|
||||
runOccCommand(command: string): Cypress.Chainable<void>,
|
||||
runOccCommand(command: string, options?: Partial<Cypress.ExecOptions>): Cypress.Chainable<Cypress.Exec>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ Cypress.Commands.add('uploadFile', (user, fixture = 'image.jpg', mimeType = 'ima
|
|||
* @param {string} target the target of the file relative to the user root
|
||||
*/
|
||||
Cypress.Commands.add('uploadContent', (user, blob, mimeType, target) => {
|
||||
// eslint-disable-next-line cypress/unsafe-to-chain-command
|
||||
cy.clearCookies()
|
||||
.then(async () => {
|
||||
const fileName = basename(target)
|
||||
|
@ -216,6 +217,6 @@ Cypress.Commands.add('resetUserTheming', (user?: User) => {
|
|||
}
|
||||
})
|
||||
|
||||
Cypress.Commands.add('runOccCommand', (command: string) => {
|
||||
cy.exec(`docker exec --user www-data nextcloud-cypress-tests-server php ./occ ${command}`)
|
||||
Cypress.Commands.add('runOccCommand', (command: string, options?: Partial<Cypress.ExecOptions>) => {
|
||||
return cy.exec(`docker exec --user www-data nextcloud-cypress-tests-server php ./occ ${command}`, options)
|
||||
})
|
||||
|
|
BIN
dist/settings-users-8351.js
vendored
BIN
dist/settings-users-8351.js
vendored
Binary file not shown.
BIN
dist/settings-users-8351.js.map
vendored
BIN
dist/settings-users-8351.js.map
vendored
Binary file not shown.
BIN
dist/settings-vue-settings-apps-users-management.js
vendored
BIN
dist/settings-vue-settings-apps-users-management.js
vendored
Binary file not shown.
Binary file not shown.
|
@ -24,7 +24,6 @@ default:
|
|||
- SettingsMenuContext
|
||||
- ThemingAppContext
|
||||
- ToastContext
|
||||
- UsersSettingsContext
|
||||
filters:
|
||||
tags: "~@apache"
|
||||
apache:
|
||||
|
@ -52,7 +51,6 @@ default:
|
|||
- SettingsMenuContext
|
||||
- ThemingAppContext
|
||||
- ToastContext
|
||||
- UsersSettingsContext
|
||||
filters:
|
||||
tags: "@apache"
|
||||
extensions:
|
||||
|
|
|
@ -1,379 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* @copyright Copyright (c) 2017, Daniel Calviño Sánchez (danxuliu@gmail.com)
|
||||
* @copyright Copyright (c) 2018, John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
|
||||
* @copyright Copyright (c) 2019, Greta Doci <gretadoci@gmail.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use WebDriver\Key;
|
||||
|
||||
class UsersSettingsContext implements Context, ActorAwareInterface {
|
||||
use ActorAware;
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function newUserForm() {
|
||||
return Locator::forThe()->css('[data-test="form"]')->
|
||||
describedAs("New user form in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function userNameFieldForNewUser() {
|
||||
return Locator::forThe()->css('[data-test="username"]')->
|
||||
describedAs("User name field for new user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function displayNameFieldForNewUser() {
|
||||
return Locator::forThe()->css('[data-test="displayName"]')->
|
||||
describedAs("Display name field for new user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function passwordFieldForNewUser() {
|
||||
return Locator::forThe()->css('[data-test="password"]')->
|
||||
describedAs("Password field for new user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function newUserButton() {
|
||||
return Locator::forThe()->id("new-user-button")->
|
||||
describedAs("New user button in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function createNewUserButton() {
|
||||
return Locator::forThe()->css('[data-test="submit"]')->
|
||||
describedAs("Create user button in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function rowForUser($user) {
|
||||
return Locator::forThe()->xpath("//tbody[contains(@class, 'user-list__body')]/tr[td[@data-test='$user']]")->
|
||||
describedAs("Row for user $user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning: you need to watch out for the proper classes order
|
||||
*
|
||||
* @return Locator
|
||||
*/
|
||||
public static function classCellForUser($class, $user) {
|
||||
return Locator::forThe()->xpath("//*[contains(concat(' ', normalize-space(@class), ' '), ' $class ')]")->
|
||||
descendantOf(self::rowForUser($user))->
|
||||
describedAs("$class cell for user $user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function inputForUserInCell($cell, $user) {
|
||||
return Locator::forThe()->css("input")->
|
||||
descendantOf(self::classCellForUser($cell, $user))->
|
||||
describedAs("$cell input for user $user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function displayNameCellForUser($user) {
|
||||
return self::inputForUserInCell("displayName", $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function optionInInputForUser($cell, $user) {
|
||||
return Locator::forThe()->css(".vs__dropdown-option--highlight")->
|
||||
describedAs("Selected $cell option in $cell input for user $user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function actionsMenuOf($user) {
|
||||
return Locator::forThe()->css(".userActions .action-item:not(.action-item--single)")->
|
||||
descendantOf(self::rowForUser($user))->
|
||||
describedAs("Actions menu for user $user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function theAction($action, $user) {
|
||||
return Locator::forThe()->xpath("//button[@aria-label = normalize-space('$action')]")->
|
||||
describedAs("$action action for the user $user row in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function theColumn($column) {
|
||||
return Locator::forThe()->xpath("//div[@class='user-list-grid']//div[normalize-space() = '$column']")->
|
||||
describedAs("The $column column in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function selectedSelectOption($cell, $user) {
|
||||
return Locator::forThe()->css(".vs__selected .name-parts")->
|
||||
descendantOf(self::classCellForUser($cell, $user))->
|
||||
describedAs("The selected option of the $cell select for the user $user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function editModeToggle($user) {
|
||||
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");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function editModeOn($user) {
|
||||
return Locator::forThe()->css("div.user-list-grid div.row.row--editable[data-id=$user]")->
|
||||
describedAs("I see the edit mode is on for the user $user in Users Settings");
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I click the New user button
|
||||
*/
|
||||
public function iClickTheNewUserButton() {
|
||||
$this->actor->find(self::newUserButton(), 10)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I click the :action action in the :user actions menu
|
||||
*/
|
||||
public function iClickTheAction($action, $user) {
|
||||
$this->actor->find(self::theAction($action, $user), 10)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I open the actions menu for the user :user
|
||||
*/
|
||||
public function iOpenTheActionsMenuOf($user) {
|
||||
$this->actor->find(self::actionsMenuOf($user), 10)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I set the user name for the new user to :user
|
||||
*/
|
||||
public function iSetTheUserNameForTheNewUserTo($user) {
|
||||
$this->actor->find(self::userNameFieldForNewUser(), 10)->setValue($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I set the display name for the new user to :displayName
|
||||
*/
|
||||
public function iSetTheDisplayNameForTheNewUserTo($displayName) {
|
||||
$this->actor->find(self::displayNameFieldForNewUser(), 10)->setValue($displayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I set the password for the new user to :password
|
||||
*/
|
||||
public function iSetThePasswordForTheNewUserTo($password) {
|
||||
$this->actor->find(self::passwordFieldForNewUser(), 10)->setValue($password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I create the new user
|
||||
*/
|
||||
public function iCreateTheNewUser() {
|
||||
$this->actor->find(self::createNewUserButton(), 10)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I toggle the edit mode for the user :user
|
||||
*/
|
||||
public function iToggleTheEditModeForUser($user) {
|
||||
$this->actor->find(self::editModeToggle($user), 10)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I create user :user with password :password
|
||||
*/
|
||||
public function iCreateUserWithPassword($user, $password) {
|
||||
$this->actor->find(self::userNameFieldForNewUser(), 10)->setValue($user);
|
||||
$this->actor->find(self::passwordFieldForNewUser())->setValue($password);
|
||||
$this->actor->find(self::createNewUserButton())->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I set the :field for :user to :value
|
||||
*/
|
||||
public function iSetTheFieldForUserTo($field, $user, $value) {
|
||||
$this->actor->find(self::inputForUserInCell($field, $user), 2)->setValue($value . Key::ENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigning/withdrawing is the same action (it toggles).
|
||||
*
|
||||
* @When I assign the user :user to the group :group
|
||||
* @When I withdraw the user :user from the group :group
|
||||
*/
|
||||
public function iAssignTheUserToTheGroup($user, $group) {
|
||||
$this->actor->find(self::inputForUserInCell('groups', $user))->setValue($group);
|
||||
$this->actor->find(self::optionInInputForUser('groups', $user))->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I set the user :user quota to :quota
|
||||
*/
|
||||
public function iSetTheUserQuotaTo($user, $quota) {
|
||||
$this->actor->find(self::inputForUserInCell('quota', $user))->setValue($quota);
|
||||
$this->actor->find(self::optionInInputForUser('quota', $user))->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the list of users contains the user :user
|
||||
*/
|
||||
public function iSeeThatTheListOfUsersContainsTheUser($user) {
|
||||
if (!WaitFor::elementToBeEventuallyShown(
|
||||
$this->actor,
|
||||
self::rowForUser($user),
|
||||
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
|
||||
Assert::fail("The user $user in the list of users is not shown yet after $timeout seconds");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the list of users does not contains the user :user
|
||||
*/
|
||||
public function iSeeThatTheListOfUsersDoesNotContainsTheUser($user) {
|
||||
if (!WaitFor::elementToBeEventuallyNotShown(
|
||||
$this->actor,
|
||||
self::rowForUser($user),
|
||||
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
|
||||
Assert::fail("The user $user in the list of users is still shown after $timeout seconds");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the new user form is shown
|
||||
*/
|
||||
public function iSeeThatTheNewUserFormIsShown() {
|
||||
if (!WaitFor::elementToBeEventuallyShown(
|
||||
$this->actor,
|
||||
self::newUserForm(),
|
||||
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
|
||||
Assert::fail("The new user form is not shown yet after $timeout seconds");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the :action action in the :user actions menu is shown
|
||||
*/
|
||||
public function iSeeTheAction($action, $user) {
|
||||
Assert::assertTrue(
|
||||
$this->actor->find(self::theAction($action, $user), 10)->isVisible());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the :column column is shown
|
||||
*/
|
||||
public function iSeeThatTheColumnIsShown($column) {
|
||||
Assert::assertTrue(
|
||||
$this->actor->find(self::theColumn($column), 10)->isVisible());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the :field of :user is :value
|
||||
*/
|
||||
public function iSeeThatTheFieldOfUserIs($field, $user, $value) {
|
||||
Assert::assertEquals(
|
||||
$this->actor->find(self::inputForUserInCell($field, $user), 10)->getValue(), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the display name for the user :user is :displayName
|
||||
*/
|
||||
public function iSeeThatTheDisplayNameForTheUserIs($user, $displayName) {
|
||||
Assert::assertEquals(
|
||||
$displayName, $this->actor->find(self::displayNameCellForUser($user), 10)->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the :cell cell for user :user is done loading
|
||||
*/
|
||||
public function iSeeThatTheCellForUserIsDoneLoading($cell, $user) {
|
||||
// It could happen that the cell for the user was done loading and thus
|
||||
// the loading icon hidden again even before finding the loading icon
|
||||
// started. Therefore, if the loading icon could not be found it is just
|
||||
// assumed that it was already hidden again. Nevertheless, this check
|
||||
// should be done anyway to ensure that the following scenario steps are
|
||||
// not executed before the cell for the user was done loading.
|
||||
try {
|
||||
$this->actor->find(self::classCellForUser($cell . ' icon-loading-small', $user), 1);
|
||||
} catch (NoSuchElementException $exception) {
|
||||
echo "The loading icon for user $user was not found after " . (1 * $this->actor->getFindTimeoutMultiplier()) . " seconds, assumming that it was shown and hidden again before the check started and continuing";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WaitFor::elementToBeEventuallyNotShown(
|
||||
$this->actor,
|
||||
self::classCellForUser($cell . ' icon-loading-small', $user),
|
||||
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
|
||||
Assert::fail("The loading icon for user $user is still shown after $timeout seconds");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the user quota of :user is :quota
|
||||
*/
|
||||
public function iSeeThatTheuserQuotaIs($user, $quota) {
|
||||
Assert::assertEquals(
|
||||
$this->actor->find(self::selectedSelectOption('quota', $user), 2)->getText(), $quota);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the edit mode is on for user :user
|
||||
*/
|
||||
public function iSeeThatTheEditModeIsOn($user) {
|
||||
if (!WaitFor::elementToBeEventuallyShown(
|
||||
$this->actor,
|
||||
self::editModeOn($user),
|
||||
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
|
||||
Assert::fail("The edit mode for user $user in the list of users is not on yet after $timeout seconds");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
@apache
|
||||
Feature: users
|
||||
|
||||
Scenario: assign user to a group
|
||||
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
|
||||
# When I toggle the edit mode for the user user0
|
||||
# Then I see that the edit mode is on for user user0
|
||||
# disabled because we need the TAB patch:
|
||||
# https://github.com/minkphp/MinkSelenium2Driver/pull/244
|
||||
# When I assign the user user0 to the group admin
|
||||
# Then I see that the section Admins is shown
|
||||
# And I see that the section Admins has a count of 2
|
||||
|
||||
Scenario: create and delete a group
|
||||
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
|
||||
# disabled because we need the TAB patch:
|
||||
# https://github.com/minkphp/MinkSelenium2Driver/pull/244
|
||||
# And I assign the user user0 to the group Group1
|
||||
# And I see that the section Group1 is shown
|
||||
# And I click the "icon-delete" button on the Group1 section
|
||||
# And I see that the confirmation dialog is shown
|
||||
# When I click the "Yes" button of the confirmation dialog
|
||||
# Then I see that the section Group1 is not shown
|
||||
|
||||
Scenario: delete an empty group
|
||||
Given I act as Jane
|
||||
And I am logged in as the admin
|
||||
And I open the User settings
|
||||
# disabled because we need the TAB patch:
|
||||
# https://github.com/minkphp/MinkSelenium2Driver/pull/244
|
||||
# And I assign the user user0 to the group Group1
|
||||
# And I see that the section Group1 is shown
|
||||
# And I withdraw the user user0 from the group Group1
|
||||
# And I see that the section Group1 does not have a count
|
||||
# And I click the "icon-delete" button on the Group1 section
|
||||
# And I see that the confirmation dialog is shown
|
||||
# When I click the "Yes" button of the confirmation dialog
|
||||
# Then I see that the section Group1 is not shown
|
||||
|
||||
# Scenario: change email
|
||||
# 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 see that the mailAddress of user0 is ""
|
||||
# When I set the mailAddress for user0 to "test@nextcloud.com"
|
||||
# And I see that the mailAddress cell for user user0 is done loading
|
||||
# Then I see that the mailAddress of user0 is "test@nextcloud.com"
|
||||
|
||||
Scenario: change user quota
|
||||
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
|
||||
# When I toggle the edit mode for the user user0
|
||||
# Then I see that the edit mode is on for user user0
|
||||
# And I see that the user quota of user0 is Unlimited
|
||||
# disabled because we need the TAB patch:
|
||||
# https://github.com/minkphp/MinkSelenium2Driver/pull/244
|
||||
# When I set the user user0 quota to 1GB
|
||||
# And I see that the quota cell for user user0 is done loading
|
||||
# Then I see that the user quota of user0 is "1 GB"
|
||||
# When I set the user user0 quota to Unlimited
|
||||
# And I see that the quota cell for user user0 is done loading
|
||||
# Then I see that the user quota of user0 is Unlimited
|
||||
# When I set the user user0 quota to 0
|
||||
# And I see that the quota cell for user user0 is done loading
|
||||
# Then I see that the user quota of user0 is "0 B"
|
||||
# When I set the user user0 quota to Default
|
||||
# And I see that the quota cell for user user0 is done loading
|
||||
# Then I see that the user quota of user0 is "Default quota"
|
Loading…
Reference in a new issue