Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(files_sharing): add file request cypress testing #46631

Merged
merged 3 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
7 changes: 5 additions & 2 deletions apps/files/src/components/NewNodeDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<NcDialog :name="name"
<NcDialog data-cy-files-new-node-dialog
:name="name"
:open="open"
close-on-click-outside
out-transition
@update:open="onClose">
<template #actions>
<NcButton type="primary"
<NcButton data-cy-files-new-node-dialog-submit
type="primary"
:disabled="!isUniqueName"
@click="onCreate">
{{ t('files', 'Create') }}
</NcButton>
</template>
<form @submit.prevent="onCreate">
<NcTextField ref="input"
data-cy-files-new-node-dialog-input
:error="!isUniqueName"
:helper-text="errorMessage"
:label="label"
Expand Down
2 changes: 1 addition & 1 deletion apps/files/src/utils/newNodeDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface ILabels {
* @param defaultName Default name to use
* @param folderContent Nodes with in the current folder to check for unique name
* @param labels Labels to set on the dialog
* @return string if successfull otherwise null if aborted
* @return string if successful otherwise null if aborted
*/
export function newNodeName(defaultName: string, folderContent: Node[], labels: ILabels = {}) {
const contentNames = folderContent.map((node: Node) => node.basename)
Expand Down
22 changes: 9 additions & 13 deletions apps/files_sharing/src/components/NewFileRequestDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -270,19 +270,15 @@ export default defineComponent({
async createShare() {
this.loading = true

// This should never happen™
if (this.expirationDate == null) {
throw new Error('Expiration date is missing')
let expireDate = ''
if (this.expirationDate) {
const year = this.expirationDate.getFullYear()
const month = (this.expirationDate.getMonth() + 1).toString().padStart(2, '0')
const day = this.expirationDate.getDate().toString().padStart(2, '0')

// Format must be YYYY-MM-DD
expireDate = `${year}-${month}-${day}`
}

const year = this.expirationDate.getFullYear()
const month = (this.expirationDate.getMonth() + 1).toString().padStart(2, '0')
const day = this.expirationDate.getDate().toString().padStart(2, '0')

// Format must be YYYY-MM-DD
const expireDate = this.expirationDate
? `${year}-${month}-${day}`
: undefined
const shareUrl = generateOcsUrl('apps/files_sharing/api/v1/shares')
try {
const request = await axios.post<OCSResponse>(shareUrl, {
Expand All @@ -296,7 +292,7 @@ export default defineComponent({
note: this.note,

password: this.password || undefined,
expireDate,
expireDate: expireDate || undefined,

// Empty string
shareWith: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export default defineComponent({

methods: {
onToggleDeadline(checked: boolean) {
this.$emit('update:expirationDate', checked ? new Date() : null)
this.$emit('update:expirationDate', checked ? (this.maxDate || this.minDate) : null)
},

async onTogglePassword(checked: boolean) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
:readonly="true"
:show-trailing-button="true"
:trailing-button-label="t('files_sharing', 'Copy to clipboard')"
data-cy-file-request-dialog-fieldset="link"
@click="copyShareLink"
@trailing-button-click="copyShareLink">
<template #trailing-button-icon>
Expand All @@ -30,6 +31,7 @@
<NcTextField :value.sync="email"
:label="t('files_sharing', 'Send link via email')"
:placeholder="t('files_sharing', 'Enter an email address or paste a list')"
data-cy-file-request-dialog-fieldset="email"
type="email"
@keypress.enter.stop="addNewEmail"
@paste.stop.prevent="onPasteEmails"
Expand Down
4 changes: 3 additions & 1 deletion apps/files_sharing/src/new/newFileRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ const NewFileRequestDialogVue = defineAsyncComponent(() => import('../components

const sharingConfig = new Config()

export const EntryId = 'file-request'

export const entry = {
id: 'file-request',
id: EntryId,
displayName: t('files_sharing', 'Create file request'),
iconSvgInline: FileUploadSvg,
order: 30,
Expand Down
9 changes: 6 additions & 3 deletions apps/files_sharing/src/views/PublicAuthPrompt.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

<template>
<NcDialog class="public-auth-prompt"
data-cy-public-auth-prompt-dialog
dialog-classes="public-auth-prompt__dialog"
:can-close="false"
:name="dialogName">
Expand All @@ -26,16 +27,18 @@
@submit.prevent.stop="">
<NcTextField ref="input"
class="public-auth-prompt__input"
data-cy-public-auth-prompt-dialog-name
:label="t('files_sharing', 'Enter your name')"
name="name"
:required="true"
:minlength="2"
:value.sync="name" />
:required="true"
:value.sync="name"
name="name" />
</form>

<!-- Submit -->
<template #actions>
<NcButton ref="submit"
data-cy-public-auth-prompt-dialog-submit
:disabled="name.trim() === ''"
@click="onSubmit">
{{ t('files_sharing', 'Submit name') }}
Expand Down
15 changes: 15 additions & 0 deletions cypress/e2e/files/FilesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,18 @@ export const clickOnBreadcrumbs = (label: string) => {
cy.get('[data-cy-files-content-breadcrumbs]').contains(label).click()
cy.wait('@propfind')
}

export const createFolder = (folderName: string) => {
cy.intercept('MKCOL', /\/remote.php\/dav\/files\//).as('createFolder')

// TODO: replace by proper data-cy selectors
cy.get('[data-cy-upload-picker] .action-item__menutoggle').first().click()
cy.contains('.upload-picker__menu-entry button', 'New folder').click()
cy.get('[data-cy-files-new-node-dialog]').should('be.visible')
cy.get('[data-cy-files-new-node-dialog-input]').type(`{selectall}${folderName}`)
cy.get('[data-cy-files-new-node-dialog-submit]').click()

cy.wait('@createFolder')

getRowForFile(folderName).should('be.visible')
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
/* eslint-disable jsdoc/require-jsdoc */
import { triggerActionForFile } from '../files/FilesUtils'

import { EntryId as FileRequestEntryID } from '../../../apps/files_sharing/src/new/newFileRequest'

export interface ShareSetting {
read: boolean
update: boolean
Expand Down Expand Up @@ -96,3 +98,82 @@ export function openSharingPanel(fileName: string) {
.get('[aria-controls="tab-sharing"]')
.click()
}

type FileRequestOptions = {
label?: string
note?: string
password?: string
/* YYYY-MM-DD format */
expiration?: string
}

/**
* Create a file request for a folder
* @param path The path of the folder, leading slash is required
* @param options The options for the file request
*/
export const createFileRequest = (path: string, options: FileRequestOptions = {}) => {
if (!path.startsWith('/')) {
throw new Error('Path must start with a slash')
}

// Navigate to the folder
cy.visit('/apps/files/files?dir=' + path)

// Open the file request dialog
cy.get('[data-cy-upload-picker] .action-item__menutoggle').first().click()
cy.contains('.upload-picker__menu-entry button', 'Create file request').click()
cy.get('[data-cy-file-request-dialog]').should('be.visible')

// Check and fill the first page options
cy.get('[data-cy-file-request-dialog-fieldset="label"]').should('be.visible')
cy.get('[data-cy-file-request-dialog-fieldset="destination"]').should('be.visible')
cy.get('[data-cy-file-request-dialog-fieldset="note"]').should('be.visible')

cy.get('[data-cy-file-request-dialog-fieldset="destination"] input').should('contain.value', path)
if (options.label) {
cy.get('[data-cy-file-request-dialog-fieldset="label"] input').type(`{selectall}${options.label}`)
}
if (options.note) {
cy.get('[data-cy-file-request-dialog-fieldset="note"] textarea').type(`{selectall}${options.note}`)
}

// Go to the next page
cy.get('[data-cy-file-request-dialog-controls="next"]').click()
cy.get('[data-cy-file-request-dialog-fieldset="expiration"] input[type="checkbox"]').should('exist')
cy.get('[data-cy-file-request-dialog-fieldset="expiration"] input[type="date"]').should('not.exist')
cy.get('[data-cy-file-request-dialog-fieldset="password"] input[type="checkbox"]').should('exist')
cy.get('[data-cy-file-request-dialog-fieldset="password"] input[type="password"]').should('not.exist')
if (options.expiration) {
cy.get('[data-cy-file-request-dialog-fieldset="expiration"] input[type="checkbox"]').check({ force: true })
cy.get('[data-cy-file-request-dialog-fieldset="expiration"] input[type="date"]').type(`{selectall}${options.expiration}`)
}
if (options.password) {
cy.get('[data-cy-file-request-dialog-fieldset="password"] input[type="checkbox"]').check({ force: true })
cy.get('[data-cy-file-request-dialog-fieldset="password"] input[type="password"]').type(`{selectall}${options.password}`)
}

// Create the file request
cy.get('[data-cy-file-request-dialog-controls="next"]').click()

// Get the file request URL
cy.get('[data-cy-file-request-dialog-fieldset="link"]').then(($link) => {
const url = $link.val()
cy.log(`File request URL: ${url}`)
cy.wrap(url).as('fileRequestUrl')
})

// Close
cy.get('[data-cy-file-request-dialog-controls="finish"]').click()
}

export const enterGuestName = (name: string) => {
cy.get('[data-cy-public-auth-prompt-dialog]').should('be.visible')
cy.get('[data-cy-public-auth-prompt-dialog-name]').should('be.visible')
cy.get('[data-cy-public-auth-prompt-dialog-submit]').should('be.visible')

cy.get('[data-cy-public-auth-prompt-dialog-name]').type(`{selectall}${name}`)
cy.get('[data-cy-public-auth-prompt-dialog-submit]').click()

cy.get('[data-cy-public-auth-prompt-dialog]').should('not.exist')
}
59 changes: 59 additions & 0 deletions cypress/e2e/files_sharing/file-request.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { User } from '@nextcloud/cypress'
import { createFolder, getRowForFile } from '../files/FilesUtils'
import { createFileRequest, enterGuestName } from './FilesSharingUtils'

describe('Files', { testIsolation: true }, () => {
let user: User
let url = ''
let folderName = 'test-folder'

it('Login with a user and create a file request', () => {
cy.createRandomUser().then((_user) => {
user = _user
cy.login(user)
})

cy.visit('/apps/files')
createFolder(folderName)

createFileRequest(`/${folderName}`)
cy.get('@fileRequestUrl').should('contain', '/s/').then((_url: string) => {
cy.logout()
url = _url
})
})

it('Open the file request as a guest', () => {
cy.visit(url)
enterGuestName('Guest')

// Check various elements on the page
cy.get('#public-upload .emptycontent').should('be.visible')
cy.get('#public-upload h2').contains(`Upload files to ${folderName}`)
cy.get('#public-upload input[type="file"]').as('fileInput').should('exist')

cy.intercept('PUT', '/public.php/dav/files/*/*').as('uploadFile')

// Upload a file
cy.get('@fileInput').selectFile({
contents: Cypress.Buffer.from('abcdef'),
fileName: 'file.txt',
mimeType: 'text/plain',
lastModified: Date.now(),
}, { force: true })

cy.wait('@uploadFile').its('response.statusCode').should('eq', 201)
})

it('Check the uploaded file', () => {
cy.login(user)
cy.visit(`/apps/files/files?dir=/${folderName}`)
getRowForFile('Guest').should('be.visible').get('a[data-cy-files-list-row-name-link]').click()
getRowForFile('file.txt').should('be.visible')
})
})
2 changes: 1 addition & 1 deletion cypress/e2e/files_versions/filesVersionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/
/* eslint-disable jsdoc/require-jsdoc */
import type { User } from '@nextcloud/cypress'
import { createShare, type ShareSetting } from '../files_sharing/filesSharingUtils'
import { createShare, type ShareSetting } from '../files_sharing/FilesSharingUtils'

export const uploadThreeVersions = (user: User, fileName: string) => {
// A new version will not be created if the changes occur
Expand Down
2 changes: 0 additions & 2 deletions dist/4589-4589.js

This file was deleted.

Loading
Loading