Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore(files_external): add cypress tests for user credentials action
Signed-off-by: skjnldsv <[email protected]>
  • Loading branch information
skjnldsv committed Feb 20, 2025
commit df005a53f0a48fd83b3d2bc5fd0da0c7bf4947a7
13 changes: 11 additions & 2 deletions apps/files_external/src/actions/enterCredentialsAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ async function setCredentials(node: Node, login: string, password: string): Prom
return true
}

export const ACTION_CREDENTIALS_EXTERNAL_STORAGE = 'credentials-external-storage'

export const action = new FileAction({
id: 'credentials-external-storage',
id: ACTION_CREDENTIALS_EXTERNAL_STORAGE,
displayName: () => t('files', 'Enter missing credentials'),
iconSvgInline: () => LoginSvg,

Expand Down Expand Up @@ -93,7 +95,14 @@ export const action = new FileAction({
))

if (login && password) {
return await setCredentials(node, login, password)
try {
await setCredentials(node, login, password)
showSuccess(t('files_external', 'Credentials successfully set'))
} catch (error) {
showError(t('files_external', 'Error while setting credentials: {error}', {
error: (error as Error).message,
}))
}
}

return null
Expand Down
2 changes: 1 addition & 1 deletion apps/files_external/src/views/CredentialsDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default defineComponent({
computed: {
dialogButtons() {
return [{
label: t('files_external', 'Submit'),
label: t('files_external', 'Confirm'),
type: 'primary',
nativeType: 'submit',
}]
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/files/FilesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export const getActionButtonForFileId = (fileid: number) => getActionsForFileId(
export const getActionButtonForFile = (filename: string) => getActionsForFile(filename).findByRole('button', { name: 'Actions' })

export const getActionEntryForFileId = (fileid: number, actionId: string) => {
return cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
return getRowForFileId(fileid).find(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
}
export const getActionEntryForFile = (filename: string, actionId: string) => {
return cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
return getRowForFile(filename).find(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
}

export const triggerActionForFileId = (fileid: number, actionId: string) => {
Expand Down
38 changes: 38 additions & 0 deletions cypress/e2e/files_external/StorageUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { User } from "@nextcloud/cypress"

export type StorageConfig = {
[key: string]: string
}

export enum StorageBackend {
DAV = 'dav',
SMB = 'smb',
SFTP = 'sftp',
}

export enum AuthBackend {
GlobalAuth = 'password::global',
LoginCredentials = 'password::logincredentials',
Password = 'password::password',
SessionCredentials = 'password::sessioncredentials',
UserGlobalAuth = 'password::global::user',
UserProvided = 'password::userprovided',
}

/**
* Create a storage via occ
*/
export function createStorageWithConfig(mountPoint: string, storageBackend: StorageBackend, authBackend: AuthBackend, configs: StorageConfig, user?: User): Cypress.Chainable {
const configsFlag = Object.keys(configs).map(key => `--config "${key}=${configs[key]}"`).join(' ')
const userFlag = user ? `--user ${user.userId}` : ''

const command = `files_external:create "${mountPoint}" "${storageBackend}" "${authBackend}" ${configsFlag} ${userFlag}`

cy.log(`Creating storage with command: ${command}`)
return cy.runOccCommand(command)
}
138 changes: 138 additions & 0 deletions cypress/e2e/files_external/files-user-credentials.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { User } from '@nextcloud/cypress'
import { AuthBackend, createStorageWithConfig, StorageBackend } from './StorageUtils'
import { getActionEntryForFile, getRowForFile, navigateToFolder, triggerInlineActionForFile } from '../files/FilesUtils'

import { ACTION_CREDENTIALS_EXTERNAL_STORAGE } from '../../../apps/files_external/src/actions/enterCredentialsAction'
import { handlePasswordConfirmation } from '../settings/usersUtils'

describe('Files user credentials', { testIsolation: true }, () => {
let user1: User
let user2: User
let storageUser: User

beforeEach(() => {
})

before(() => {
cy.runOccCommand('app:enable files_external')

// Create some users
cy.createRandomUser().then((user) => user1 = user)
cy.createRandomUser().then((user) => user2 = user)

// This user will hold the webdav storage
cy.createRandomUser().then((user) => {
storageUser = user
cy.uploadFile(user, 'image.jpg')
})
})

after(() => {
// Cleanup global storages
cy.runOccCommand(`files_external:list --output=json`).then(({stdout}) => {
const list = JSON.parse(stdout)
list.forEach((storage) => cy.runOccCommand(`files_external:delete --yes ${storage.mount_id}`), { failOnNonZeroExit: false })
})

cy.runOccCommand('app:disable files_external')
})

it('Create a user storage with user credentials', () => {
const url = Cypress.config('baseUrl') + '/remote.php/dav/files/' + storageUser.userId
createStorageWithConfig(storageUser.userId, StorageBackend.DAV, AuthBackend.UserProvided, { host: url.replace('index.php/', ''), 'secure': 'false' })

cy.login(user1)
cy.visit('/apps/files/extstoragemounts')
getRowForFile(storageUser.userId).should('be.visible')

cy.intercept('PUT', '**/apps/files_external/userglobalstorages/*').as('setCredentials')

triggerInlineActionForFile(storageUser.userId, ACTION_CREDENTIALS_EXTERNAL_STORAGE)

// See credentials dialog
const storageDialog = cy.findByRole('dialog', { name: 'Storage credentials' })
storageDialog.should('be.visible')
storageDialog.findByRole('textbox', { name: 'Login' }).type(storageUser.userId)
storageDialog.get('input[type="password"]').type(storageUser.password)
storageDialog.get('button').contains('Confirm').click()
storageDialog.should('not.exist')

// Storage dialog now closed, the user auth dialog should be visible
const authDialog = cy.findByRole('dialog', { name: 'Confirm your password' })
authDialog.should('be.visible')
handlePasswordConfirmation(user1.password)

// Wait for the credentials to be set
cy.wait('@setCredentials')

// Auth dialog should be closed and the set credentials button should be gone
authDialog.should('not.exist', { timeout: 2000 })
getActionEntryForFile(storageUser.userId, ACTION_CREDENTIALS_EXTERNAL_STORAGE).should('not.exist')

// Finally, the storage should be accessible
cy.visit('/apps/files')
navigateToFolder(storageUser.userId)
getRowForFile('image.jpg').should('be.visible')
})

it('Create a user storage with GLOBAL user credentials', () => {
const url = Cypress.config('baseUrl') + '/remote.php/dav/files/' + storageUser.userId
createStorageWithConfig('storage1', StorageBackend.DAV, AuthBackend.UserGlobalAuth, { host: url.replace('index.php/', ''), 'secure': 'false' })

cy.login(user2)
cy.visit('/apps/files/extstoragemounts')
getRowForFile('storage1').should('be.visible')

cy.intercept('PUT', '**/apps/files_external/userglobalstorages/*').as('setCredentials')

triggerInlineActionForFile('storage1', ACTION_CREDENTIALS_EXTERNAL_STORAGE)

// See credentials dialog
const storageDialog = cy.findByRole('dialog', { name: 'Storage credentials' })
storageDialog.should('be.visible')
storageDialog.findByRole('textbox', { name: 'Login' }).type(storageUser.userId)
storageDialog.get('input[type="password"]').type(storageUser.password)
storageDialog.get('button').contains('Confirm').click()
storageDialog.should('not.exist')

// Storage dialog now closed, the user auth dialog should be visible
const authDialog = cy.findByRole('dialog', { name: 'Confirm your password' })
authDialog.should('be.visible')
handlePasswordConfirmation(user2.password)

// Wait for the credentials to be set
cy.wait('@setCredentials')

// Auth dialog should be closed and the set credentials button should be gone
authDialog.should('not.exist', { timeout: 2000 })
getActionEntryForFile('storage1', ACTION_CREDENTIALS_EXTERNAL_STORAGE).should('not.exist')

// Finally, the storage should be accessible
cy.visit('/apps/files')
navigateToFolder('storage1')
getRowForFile('image.jpg').should('be.visible')
})

it('Create another user storage while reusing GLOBAL user credentials', () => {
const url = Cypress.config('baseUrl') + '/remote.php/dav/files/' + storageUser.userId
createStorageWithConfig('storage2', StorageBackend.DAV, AuthBackend.UserGlobalAuth, { host: url.replace('index.php/', ''), 'secure': 'false' })

cy.login(user2)
cy.visit('/apps/files/extstoragemounts')
getRowForFile('storage2').should('be.visible')

// Since we already have set the credentials, the action should not be present
getActionEntryForFile('storage1', ACTION_CREDENTIALS_EXTERNAL_STORAGE).should('not.exist')
getActionEntryForFile('storage2', ACTION_CREDENTIALS_EXTERNAL_STORAGE).should('not.exist')

// Finally, the storage should be accessible
cy.visit('/apps/files')
navigateToFolder('storage2')
getRowForFile('image.jpg').should('be.visible')
})
})