Skip to content
Open
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
18 changes: 17 additions & 1 deletion .github/workflows/cypress-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ jobs:
fail-fast: false
matrix:
node-version: [20.x]
# containers: [1, 2, 3]
containers: [1, 2, 3]
php-versions: [ '8.2' ]
server-versions: [ 'master' ]

name: runner ${{ matrix.containers }}

env:
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, zip, gd, apcu
key: cache-v1
Expand Down Expand Up @@ -135,6 +137,8 @@ jobs:
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
npm_package_name: ${{ env.APP_NAME }}
SPLIT: ${{ strategy.job-total }}
SPLIT_INDEX: ${{ strategy.job-index }}

- name: Upload test failure screenshots
uses: actions/upload-artifact@v4
Expand All @@ -151,3 +155,15 @@ jobs:
name: Upload nextcloud log
path: data/nextcloud.log
retention-days: 5

summary:
runs-on: ubuntu-latest-low
needs: [ cypress ]

if: always()

name: cypress-summary

steps:
- name: Summary status
run: if ${{ needs.cypress.result != 'success' && needs.cypress.result != 'skipped' }}; then exit 1; fi
6 changes: 5 additions & 1 deletion cypress.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { defineConfig } = require('cypress')
const cypressSplit = require('cypress-split')

module.exports = defineConfig({
projectId: '1s7wkc',
Expand All @@ -8,9 +9,12 @@ module.exports = defineConfig({
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
cypressSplit(on, config)
require('./cypress/plugins/index.js')(on, config)
return config
},
baseUrl: 'http://nextcloud.local/index.php',
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
experimentalMemoryManagement: true,
},
})
103 changes: 103 additions & 0 deletions cypress/e2e/cardActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { randUser } from '../utils/index.js'
import { sampleBoard } from '../utils/sampleBoard'

const user = randUser()
const boardData = sampleBoard()

const auth = {
user: user.userId,
password: user.password,
}

const useModal = (useModal) => {
return cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/ocs/v2.php/apps/deck/api/v1.0/config/cardDetailsInModal?format=json`,
auth,
body: { value: useModal },
}).then((response) => {
expect(response.status).to.eq(200)
})
}

describe('Card actions', function () {
let boardId
before(function () {
cy.createUser(user)
cy.login(user)
cy.createExampleBoard({
user,
board: boardData,
}).then((board) => {
boardId = board.id
})
})

beforeEach(function () {
cy.login(user)
useModal(false).then(() => {
cy.visit(`/apps/deck/#/board/${boardId}`)
})
})

it('Custom card actions', () => {
const myAction = {
label: 'Test action',
icon: 'icon-user',
callback(card) {
console.log('Called callback', card)
},
}
cy.spy(myAction, 'callback').as('myAction.callback')

cy.window().then(win => {
win.OCA.Deck.registerCardAction(myAction)
})

cy.get('.card:contains("Hello world")').should('be.visible').click()
cy.get('#app-sidebar-vue')
.find('.ProseMirror h1').contains('Hello world').should('be.visible')

cy.get('.app-sidebar-header .action-item__menutoggle').click()
cy.get('.v-popper__popper button:contains("Test action")').click()

cy.get('@myAction.callback')
.should('be.called')
.its('firstCall.args.0')
.as('args')

cy.url().then(url => {
const cardId = url.split('/').pop()
cy.get('@args').should('have.property', 'name', 'Hello world')
cy.get('@args').should('have.property', 'stackname', 'TestList')
cy.get('@args').should('have.property', 'boardname', 'MyTestBoard')
cy.get('@args').its('link').then((url) => {
expect(url.split('/').pop() === cardId).to.be.true
cy.visit(url)
cy.get('#app-sidebar-vue')
.find('.ProseMirror h1').contains('Hello world').should('be.visible')
})
})
})

it('clone card', () => {
cy.intercept({ method: 'POST', url: '**/apps/deck/**/cards/*/clone' }).as('clone')
cy.get('.card:contains("Hello world")').should('be.visible').click()
cy.get('#app-sidebar-vue')
.find('.ProseMirror h1').contains('Hello world').should('be.visible')

cy.get('.app-sidebar-header .action-item__menutoggle').click()
cy.get('.v-popper__popper button:contains("Move/copy card")').click()
cy.get('.vs__dropdown-menu span[title="MyTestBoard"]').should('be.visible').click()
cy.wait(3000) // wait for select component to load stacks
cy.get('[data-cy="select-stack"] .vs__dropdown-toggle').should('be.visible').click()
cy.get('.vs__dropdown-menu span[title="TestList"]').should('be.visible').click()
cy.get('.modal-container button:contains("Copy card")').click()
cy.wait('@clone', { timeout: 7000 })
cy.get('.card:contains("Hello world")').should('have.length', 2)
})
})
65 changes: 0 additions & 65 deletions cypress/e2e/cardFeatures.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,69 +321,4 @@ describe('Card', function () {
})

})

describe('Card actions', () => {
beforeEach(function () {
cy.login(user)
useModal(false).then(() => {
cy.visit(`/apps/deck/#/board/${boardId}`)
})
})

it('Custom card actions', () => {
const myAction = {
label: 'Test action',
icon: 'icon-user',
callback(card) {
console.log('Called callback', card)
},
}
cy.spy(myAction, 'callback').as('myAction.callback')

cy.window().then(win => {
win.OCA.Deck.registerCardAction(myAction)
})

cy.get('.card:contains("Hello world")').should('be.visible').click()
cy.get('#app-sidebar-vue')
.find('.ProseMirror h1').contains('Hello world').should('be.visible')

cy.get('.app-sidebar-header .action-item__menutoggle').click()
cy.get('.v-popper__popper button:contains("Test action")').click()

cy.get('@myAction.callback')
.should('be.called')
.its('firstCall.args.0')
.as('args')

cy.url().then(url => {
const cardId = url.split('/').pop()
cy.get('@args').should('have.property', 'name', 'Hello world')
cy.get('@args').should('have.property', 'stackname', 'TestList')
cy.get('@args').should('have.property', 'boardname', 'MyTestBoard')
cy.get('@args').its('link').then((url) => {
expect(url.split('/').pop() === cardId).to.be.true
cy.visit(url)
cy.get('#app-sidebar-vue')
.find('.ProseMirror h1').contains('Hello world').should('be.visible')
})
})
})

it('clone card', () => {
cy.intercept({ method: 'POST', url: '**/apps/deck/**/cards/*/clone' }).as('clone')
cy.get('.card:contains("Hello world")').should('be.visible').click()
cy.get('#app-sidebar-vue')
.find('.ProseMirror h1').contains('Hello world').should('be.visible')

cy.get('.app-sidebar-header .action-item__menutoggle').click()
cy.get('.v-popper__popper button:contains("Move/copy card")').click()
cy.get('.vs__dropdown-menu span[title="MyTestBoard"]').should('be.visible').click()
cy.get('[data-cy="select-stack"] .vs__dropdown-toggle').should('be.visible').click()
cy.get('.vs__dropdown-menu span[title="TestList"]').should('be.visible').click()
cy.get('.modal-container button:contains("Copy card")').click()
cy.wait('@clone', { timeout: 7000 })
cy.get('.card:contains("Hello world")').should('have.length', 2)
})
})
})
Loading
Loading