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
test: Add end-to-end tests for share expiry date
Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux committed Jan 16, 2025
commit 645252246ea61621037458cf01ea9b55737854c3
5 changes: 5 additions & 0 deletions cypress/e2e/files/FilesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
*
*/

export const closeSidebar = () => {
// {force: true} as it might be hidden behind toasts
cy.get('[data-cy-sidebar] .app-sidebar__close').click({ force: true })
}

export const getRowForFile = (filename: string) => cy.get(`[data-cy-files-list-row-name="${CSS.escape(filename)}"]`)

export const getActionsForFile = (filename: string) => getRowForFile(filename).find('[data-cy-files-list-row-actions]')
Expand Down
24 changes: 20 additions & 4 deletions cypress/e2e/files_sharing/FilesSharingUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/* eslint-disable jsdoc/require-jsdoc */

import { triggerActionForFile } from '../files/FilesUtils'

export interface ShareSetting {
Expand All @@ -12,6 +13,7 @@ export interface ShareSetting {
share: boolean
download: boolean
note: string
expiryDate: Date
}

export function createShare(fileName: string, username: string, shareSettings: Partial<ShareSetting> = {}) {
Expand All @@ -31,15 +33,20 @@ export function createShare(fileName: string, username: string, shareSettings: P
updateShare(fileName, 0, shareSettings)
}

export function openSharingDetails(index: number) {
cy.get('#app-sidebar-vue').within(() => {
cy.get('[data-cy-files-sharing-share-actions]').eq(index).click()
cy.get('[data-cy-files-sharing-share-permissions-bundle="custom"]').click()
})
}

export function updateShare(fileName: string, index: number, shareSettings: Partial<ShareSetting> = {}) {
openSharingPanel(fileName)
openSharingDetails(index)

cy.intercept({ times: 1, method: 'PUT', url: '**/apps/files_sharing/api/v1/shares/*' }).as('updateShare')

cy.get('#app-sidebar-vue').within(() => {
cy.get('[data-cy-files-sharing-share-actions]').eq(index).click()
cy.get('[data-cy-files-sharing-share-permissions-bundle="custom"]').click()

if (shareSettings.download !== undefined) {
cy.get('[data-cy-files-sharing-share-permissions-checkbox="download"]').find('input').as('downloadCheckbox')
if (shareSettings.download) {
Expand Down Expand Up @@ -86,13 +93,22 @@ export function updateShare(fileName: string, index: number, shareSettings: Part

if (shareSettings.note !== undefined) {
cy.findByRole('checkbox', { name: /note to recipient/i }).check({ force: true, scrollBehavior: 'nearest' })
cy.findByRole('textbox', { name: /note to recipient/i }).type(shareSettings.note)
cy.findByRole('textbox', { name: /note for the share recipient/i }).type(shareSettings.note)
}

if (shareSettings.expiryDate !== undefined) {
cy.findByRole('checkbox', { name: /expiration date/i })
.check({ force: true, scrollBehavior: 'nearest' })
cy.get('#share-date-picker')
.type(`${shareSettings.expiryDate.getFullYear()}-${String(shareSettings.expiryDate.getMonth() + 1).padStart(2, '0')}-${String(shareSettings.expiryDate.getDate()).padStart(2, '0')}`)
}

cy.get('[data-cy-files-sharing-share-editor-action="save"]').click({ scrollBehavior: 'nearest' })

cy.wait('@updateShare')
})
// close all toasts
cy.get('.toast-success').findAllByRole('button').click({ force: true, multiple: true })
}

export function openSharingPanel(fileName: string) {
Expand Down
125 changes: 125 additions & 0 deletions cypress/e2e/files_sharing/expiry-date.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { User } from '@nextcloud/cypress'
import { randomBytes } from 'crypto'
import { closeSidebar } from '../files/FilesUtils.ts'
import { createShare, openSharingDetails, openSharingPanel, updateShare } from './FilesSharingUtils.ts'

describe('files_sharing: Expiry date', () => {
const expectedDefaultDate = new Date(Date.now() + 2 * 24 * 60 * 60 * 1000)
const expectedDefaultDateString = `${expectedDefaultDate.getFullYear()}-${String(expectedDefaultDate.getMonth() + 1).padStart(2, '0')}-${String(expectedDefaultDate.getDate()).padStart(2, '0')}`
const fortnight = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000)
const fortnightString = `${fortnight.getFullYear()}-${String(fortnight.getMonth() + 1).padStart(2, '0')}-${String(fortnight.getDate()).padStart(2, '0')}`

let alice: User
let bob: User

before(() => {
// Ensure we have the admin setting setup for default dates with 2 days in the future
cy.runOccCommand('config:app:set --value yes core shareapi_default_internal_expire_date')
cy.runOccCommand('config:app:set --value 2 core shareapi_internal_expire_after_n_days')

cy.createRandomUser().then((user) => {
alice = user
cy.login(alice)
})
cy.createRandomUser().then((user) => {
bob = user
})
})

after(() => {
cy.runOccCommand('config:app:delete core shareapi_default_internal_expire_date')
cy.runOccCommand('config:app:delete core shareapi_enforce_internal_expire_date')
cy.runOccCommand('config:app:delete core shareapi_internal_expire_after_n_days')
})

beforeEach(() => {
cy.runOccCommand('config:app:delete core shareapi_enforce_internal_expire_date')
})

it('See default expiry date is set and enforced', () => {
// Enforce the date
cy.runOccCommand('config:app:set --value yes core shareapi_enforce_internal_expire_date')
const dir = prepareDirectory()

validateExpiryDate(dir, expectedDefaultDateString)
cy.findByRole('checkbox', { name: /expiration date/i })
.should('be.checked')
.and('be.disabled')
})

it('See default expiry date is set also if not enforced', () => {
const dir = prepareDirectory()

validateExpiryDate(dir, expectedDefaultDateString)
cy.findByRole('checkbox', { name: /expiration date/i })
.should('be.checked')
.and('not.be.disabled')
.check({ force: true, scrollBehavior: 'nearest' })
})

it('Can set custom expiry date', () => {
const dir = prepareDirectory()
updateShare(dir, 0, { expiryDate: fortnight })
validateExpiryDate(dir, fortnightString)
})

it('Custom expiry date survives reload', () => {
const dir = prepareDirectory()
updateShare(dir, 0, { expiryDate: fortnight })
validateExpiryDate(dir, fortnightString)

cy.visit('/apps/files')
validateExpiryDate(dir, fortnightString)
})

/**
* Regression test for https://github.com/nextcloud/server/pull/50192
* Ensure that admin default settings do not always override the user set value.
*/
it('Custom expiry date survives unrelated update', () => {
const dir = prepareDirectory()
updateShare(dir, 0, { expiryDate: fortnight })
validateExpiryDate(dir, fortnightString)

closeSidebar()
updateShare(dir, 0, { note: 'Only note changed' })
validateExpiryDate(dir, fortnightString)

cy.visit('/apps/files')
validateExpiryDate(dir, fortnightString)
})

/**
* Prepare directory, login and share to bob
*/
function prepareDirectory(): string {
const name = randomBytes(4)
.toString('hex')
cy.mkdir(alice, `/${name}`)
cy.login(alice)
cy.visit('/apps/files')
createShare(name, bob.userId)
return name
}

/**
* Validate expiry date on a share
*
* @param filename The filename to validate
* @param expectedDate The expected date in YYYY-MM-dd
*/
function validateExpiryDate(filename: string, expectedDate: string) {
openSharingPanel(filename)
openSharingDetails(0)

cy.get('#share-date-picker')
.should('exist')
.and('have.value', expectedDate)
}

})
2 changes: 1 addition & 1 deletion cypress/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"extends": "../tsconfig.json",
"include": ["./**/*.ts"],
"compilerOptions": {
"types": ["cypress", "cypress-axe", "cypress-wait-until", "dockerode"],
"types": ["@testing-library/cypress", "cypress", "cypress-axe", "cypress-wait-until", "dockerode"],
}
}