Skip to content

Commit 7978ee8

Browse files
authored
Merge pull request #55885 from nextcloud/chore/e2e-test-server
chore: migrate Cypress to `@nextcloud/e2e-test-server`
2 parents f050c32 + cfe886a commit 7978ee8

File tree

82 files changed

+740
-956
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+740
-956
lines changed

.github/workflows/cypress.yml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,20 +205,19 @@ jobs:
205205
cypress/snapshots
206206
cypress/videos
207207
208-
- name: Extract NC logs
208+
- name: Show logs
209209
if: failure() && matrix.containers != 'component'
210-
run: docker logs nextcloud-cypress-tests_${{ env.APP_NAME }} > nextcloud.log
211-
212-
- name: Upload NC logs
213-
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
214-
if: failure() && matrix.containers != 'component'
215-
with:
216-
name: nc_logs_${{ matrix.containers }}
217-
path: nextcloud.log
210+
run: |
211+
for id in $(docker ps -aq); do
212+
docker container inspect "$id" --format '=== Logs for container {{.Name}} ==='
213+
docker logs "$id" >> nextcloud.log
214+
done
215+
echo '=== Nextcloud server logs ==='
216+
docker exec nextcloud-e2e-test-server_${{ env.APP_NAME }} cat data/nextcloud.log
218217
219218
- name: Create data dir archive
220219
if: failure() && matrix.containers != 'component'
221-
run: docker exec nextcloud-cypress-tests_${{ env.APP_NAME }} tar -cvjf - data > data.tar
220+
run: docker exec nextcloud-e2e-test-server_${{ env.APP_NAME }} tar -cvjf - data > data.tar
222221

223222
- name: Upload data dir archive
224223
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2

build/files-checker.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
'cron.php',
5858
'custom.d.ts',
5959
'cypress.config.ts',
60-
'cypress.d.ts',
6160
'cypress',
6261
'dist',
6362
'eslint.config.mjs',

cypress.config.ts

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,19 @@
44
* SPDX-License-Identifier: AGPL-3.0-or-later
55
*/
66

7-
import type { Configuration } from 'webpack'
8-
9-
import webpackPreprocessor from '@cypress/webpack-preprocessor'
7+
import { configureNextcloud, docker, getContainer, getContainerName, runExec, runOcc, startNextcloud, stopNextcloud, waitOnNextcloud } from '@nextcloud/e2e-test-server'
108
import { defineConfig } from 'cypress'
11-
import { removeDirectory } from 'cypress-delete-downloads-folder'
129
import cypressSplit from 'cypress-split'
13-
import { join } from 'path'
14-
import {
15-
applyChangesToNextcloud,
16-
configureNextcloud,
17-
startNextcloud,
18-
stopNextcloud,
19-
waitOnNextcloud,
20-
} from './cypress/dockerNode.ts'
21-
import webpackConfig from './webpack.config.js'
10+
import vitePreprocessor from 'cypress-vite'
11+
import { existsSync, rmdirSync } from 'node:fs'
12+
import { dirname, join, resolve } from 'node:path'
13+
import { fileURLToPath } from 'node:url'
14+
import { nodePolyfills } from 'vite-plugin-node-polyfills'
15+
16+
if (!globalThis.__dirname) {
17+
// Cypress has their own weird parser
18+
globalThis.__dirname = dirname(fileURLToPath(new URL(import.meta.url)))
19+
}
2220

2321
export default defineConfig({
2422
projectId: '37xpdh',
@@ -65,13 +63,13 @@ export default defineConfig({
6563
// We've imported your old cypress plugins here.
6664
// You may want to clean this up later by importing these.
6765
async setupNodeEvents(on, config) {
68-
on('file:preprocessor', webpackPreprocessor({ webpackOptions: webpackConfig as Configuration }))
69-
70-
on('task', { removeDirectory })
66+
on('file:preprocessor', vitePreprocessor({
67+
plugins: [nodePolyfills()],
68+
}))
7169

7270
// This allows to store global data (e.g. the name of a snapshot)
7371
// because Cypress.env() and other options are local to the current spec file.
74-
const data = {}
72+
const data: Record<string, unknown> = {}
7573
on('task', {
7674
setVariable({ key, value }) {
7775
data[key] = value
@@ -80,6 +78,17 @@ export default defineConfig({
8078
getVariable({ key }) {
8179
return data[key] ?? null
8280
},
81+
// allow to clear the downloads folder
82+
deleteFolder(path: string) {
83+
try {
84+
if (existsSync(path)) {
85+
rmdirSync(path, { maxRetries: 10, recursive: true })
86+
}
87+
return null
88+
} catch (error) {
89+
throw Error(`Error while deleting ${path}. Original error: ${error}`)
90+
}
91+
},
8392
})
8493

8594
// Disable spell checking to prevent rendering differences
@@ -117,21 +126,82 @@ export default defineConfig({
117126
cypressSplit(on, config)
118127
}
119128

129+
const mounts = {
130+
'3rdparty': resolve(__dirname, './3rdparty'),
131+
apps: resolve(__dirname, './apps'),
132+
core: resolve(__dirname, './core'),
133+
cypress: resolve(__dirname, './cypress'),
134+
dist: resolve(__dirname, './dist'),
135+
lib: resolve(__dirname, './lib'),
136+
ocs: resolve(__dirname, './ocs'),
137+
'ocs-provider': resolve(__dirname, './ocs-provider'),
138+
resources: resolve(__dirname, './resources'),
139+
tests: resolve(__dirname, './tests'),
140+
'console.php': resolve(__dirname, './console.php'),
141+
'cron.php': resolve(__dirname, './cron.php'),
142+
'index.php': resolve(__dirname, './index.php'),
143+
occ: resolve(__dirname, './occ'),
144+
'public.php': resolve(__dirname, './public.php'),
145+
'remote.php': resolve(__dirname, './remote.php'),
146+
'status.php': resolve(__dirname, './status.php'),
147+
'version.php': resolve(__dirname, './version.php'),
148+
} as Record<string, string>
149+
150+
for (const [key, path] of Object.entries(mounts)) {
151+
if (!existsSync(path)) {
152+
delete mounts[key]
153+
}
154+
}
155+
120156
// Before the browser launches
121157
// starting Nextcloud testing container
122-
const ip = await startNextcloud(process.env.BRANCH)
123-
158+
const port = 8042
159+
const ip = await startNextcloud(process.env.BRANCH, false, {
160+
mounts,
161+
exposePort: port,
162+
})
124163
// Setting container's IP as base Url
125-
config.baseUrl = `http://${ip}/index.php`
164+
config.baseUrl = `http://localhost:${port}/index.php`
165+
// if needed for the setup tests, connect to the actions network
166+
await connectToActionsNetwork()
167+
// make sure not to write into apps but use a local apps folder
168+
runExec(['mkdir', 'apps-cypress'])
169+
runExec(['cp', 'cypress/fixtures/app.config.php', 'config'])
170+
// now wait until Nextcloud is ready and configure it
126171
await waitOnNextcloud(ip)
127172
await configureNextcloud()
173+
// additionally we do not want to DoS the app store
174+
runOcc(['config:system:set', 'appstoreenabled', '--value', 'false', '--type', 'boolean'])
128175

129-
if (!process.env.CI) {
130-
await applyChangesToNextcloud()
131-
}
176+
// for later use in tests save the container name
177+
// @ts-expect-error we are adding a custom property
178+
config.dockerContainerName = getContainerName()
132179

133180
// IMPORTANT: return the config otherwise cypress-split will not work
134181
return config
135182
},
136183
},
137184
})
185+
186+
/**
187+
* Connect the running test container to the GitHub Actions network
188+
*/
189+
async function connectToActionsNetwork() {
190+
if (process.env.SETUP_TESTING !== 'true') {
191+
console.log('├─ Not running setup tests, skipping actions network connection 🌐')
192+
return
193+
}
194+
195+
console.log('├─ Looking for github actions network... 🔍')
196+
const networks = await docker.listNetworks()
197+
const network = networks.find((network) => network.Name.startsWith('github_network'))
198+
if (!network) {
199+
console.log('│ └─ No actions network found ⚠️')
200+
return
201+
}
202+
203+
console.log('│ |─ Found actions network: ' + network.Name)
204+
await docker.getNetwork(network.Id)
205+
.connect({ Container: getContainer().id })
206+
console.log('│ └─ Connected to actions network 🌐')
207+
}

cypress.d.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)