From 33efc2b16fc1ab11999783a8b4a756443920fc38 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 11 Jan 2024 14:41:12 +0100 Subject: [PATCH] test(cy): use docker commands from @nextcloud/cypress Signed-off-by: Max --- cypress.config.ts | 2 +- cypress/dockerNode.ts | 224 ------------------------------------------ package-lock.json | 11 ++- package.json | 2 +- 4 files changed, 10 insertions(+), 229 deletions(-) delete mode 100644 cypress/dockerNode.ts diff --git a/cypress.config.ts b/cypress.config.ts index c763bea84..e581b23c0 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,4 +1,4 @@ -import { configureNextcloud, startNextcloud, stopNextcloud, waitOnNextcloud } from './cypress/dockerNode' +import { configureNextcloud, startNextcloud, stopNextcloud, waitOnNextcloud } from '@nextcloud/cypress/docker' import { defineConfig } from 'cypress' import getCompareSnapshotsPlugin from 'cypress-visual-regression/dist/plugin' diff --git a/cypress/dockerNode.ts b/cypress/dockerNode.ts deleted file mode 100644 index de2a02819..000000000 --- a/cypress/dockerNode.ts +++ /dev/null @@ -1,224 +0,0 @@ -/** - * @copyright Copyright (c) 2022 John Molakvoæ - * - * @author John Molakvoæ - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ -/* eslint-disable no-console */ -import type { Stream } from 'stream' -import type { Container } from 'dockerode' - -import Docker from 'dockerode' -import path from 'path' -import waitOn from 'wait-on' - -import pkg from '../package.json' - -const APP_PATH = path.resolve(__dirname, '../') -const APP_NAME = pkg.name - -const CONTAINER_NAME = 'nextcloud-cypress-tests-' + APP_NAME -const SERVER_IMAGE = 'ghcr.io/nextcloud/continuous-integration-shallow-server' - -export const docker = new Docker() - -/** - * Start the testing container - * - * @param branch the current git branch - */ -export const startNextcloud = async function(branch = 'master'): Promise { - try { - // Pulling images - console.log('Pulling images... ⏳') - await new Promise((resolve, reject) => docker.pull(SERVER_IMAGE, (_err, stream: Stream) => { - const onFinished = function(err: Error | null) { - if (!err) { - return resolve(true) - } - reject(err) - } - // https://github.com/apocas/dockerode/issues/357 - docker.modem.followProgress(stream, onFinished) - })) - console.log('└─ Done') - - // Getting latest image - console.log('\nChecking running containers... 🔍') - const localImage = await docker.listImages({ filters: `{"reference": ["${SERVER_IMAGE}"]}` }) - - // Remove old container if exists and not initialized by us - try { - const oldContainer = docker.getContainer(CONTAINER_NAME) - const oldContainerData = await oldContainer.inspect() - if (oldContainerData.State.Running) { - console.log('├─ Existing running container found') - if (localImage[0].Id !== oldContainerData.Image) { - console.log('└─ But running container is outdated, replacing...') - } else { - // Get container's IP - console.log('├─ Reusing that container') - const ip = await getContainerIP(oldContainer) - return ip - } - } else { - console.log('└─ None found!') - } - // Forcing any remnants to be removed just in case - await oldContainer.remove({ force: true }) - } catch (error) { - console.log('└─ None found!') - } - - // Starting container - console.log('\nStarting Nextcloud container... 🚀') - console.log(`├─ Using branch '${branch}'`) - console.log(`├─ And binding app '${APP_NAME}' from '${APP_PATH}'`) - const container = await docker.createContainer({ - Image: SERVER_IMAGE, - name: CONTAINER_NAME, - HostConfig: { - Binds: [`${APP_PATH}:/var/www/html/apps/${APP_NAME}`], - }, - Env: [ - `BRANCH=${branch}`, - ], - }) - await container.start() - - // Get container's IP - const ip = await getContainerIP(container) - - console.log(`├─ Nextcloud container's IP is ${ip} 🌏`) - return ip - } catch (err) { - console.log('└─ Unable to start the container 🛑') - console.log(err) - stopNextcloud() - throw new Error('Unable to start the container') - } -} - -/** - * Configure Nextcloud - */ -export const configureNextcloud = async function() { - console.log('\nConfiguring nextcloud...') - const container = docker.getContainer(CONTAINER_NAME) - await runExec(container, ['php', 'occ', '--version'], true) - - // Be consistent for screenshots - await runExec(container, ['php', 'occ', 'config:system:set', 'default_language', '--value', 'en'], true) - await runExec(container, ['php', 'occ', 'config:system:set', 'force_language', '--value', 'en'], true) - await runExec(container, ['php', 'occ', 'config:system:set', 'default_locale', '--value', 'en_US'], true) - await runExec(container, ['php', 'occ', 'config:system:set', 'force_locale', '--value', 'en_US'], true) - await runExec(container, ['php', 'occ', 'config:system:set', 'enforce_theme', '--value', 'light'], true) - - // Enable the app and give status - await runExec(container, ['php', 'occ', 'app:enable', '--force', 'viewer'], true) - // await runExec(container, ['php', 'occ', 'app:list'], true) - - console.log('└─ Nextcloud is now ready to use 🎉') -} - -/** - * Force stop the testing nextcloud container - */ -export const stopNextcloud = async function() { - try { - const container = docker.getContainer(CONTAINER_NAME) - console.log('Stopping Nextcloud container...') - container.remove({ force: true }) - console.log('└─ Nextcloud container removed 🥀') - } catch (err) { - console.log(err) - } -} - -/** - * Get the testing container's IP address - * - * @param container the container to get the ip from - */ -export const getContainerIP = async function( - container: Container = docker.getContainer(CONTAINER_NAME), -): Promise { - let ip = '' - let tries = 0 - while (ip === '' && tries < 10) { - tries++ - - await container.inspect(function(_err, data) { - ip = data?.NetworkSettings?.IPAddress || '' - }) - - if (ip !== '') { - break - } - - await sleep(1000 * tries) - } - - return ip -} - -/** - * Would be simpler to start the container from cypress.config.ts, - * but when checking out different branches, it can take a few seconds - * Until we can properly configure the baseUrl retry intervals, - * We need to make sure the server is already running before cypress - * - * @param {string} ip the ip to wait for - * @see https://github.com/cypress-io/cypress/issues/22676 - */ -export const waitOnNextcloud = async function(ip: string) { - console.log('├─ Waiting for Nextcloud to be ready... ⏳') - await waitOn({ resources: [`http://${ip}/index.php`] }) - console.log('└─ Done') -} - -const runExec = async function( - container: Docker.Container, - command: string[], - verbose = false, -) { - const exec = await container.exec({ - Cmd: command, - AttachStdout: true, - AttachStderr: true, - User: 'www-data', - }) - - return new Promise((resolve) => { - exec.start({}, (_err, stream) => { - if (stream) { - stream.setEncoding('utf-8') - stream.on('data', str => { - if (verbose && str.trim() !== '') { - console.log(`├─ ${str.trim().replace(/\n/gi, '\n├─ ')}`) - } - }) - stream.on('end', resolve) - } - }) - }) -} - -const sleep = function(milliseconds: number) { - return new Promise((resolve) => setTimeout(resolve, milliseconds)) -} diff --git a/package-lock.json b/package-lock.json index e19db3ec5..26c8af96b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3170,10 +3170,15 @@ } }, "node_modules/@nextcloud/cypress": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@nextcloud/cypress/-/cypress-1.0.0-beta.6.tgz", - "integrity": "sha512-pWittE2Ik9JAqWoCqMzXVolW0zfntvRPnMqclB5bXVcv4ss5dZqsSeID8CVarU+ymgb/EAf291EL8jAWbQ+BSQ==", + "version": "1.0.0-beta.7", + "resolved": "https://registry.npmjs.org/@nextcloud/cypress/-/cypress-1.0.0-beta.7.tgz", + "integrity": "sha512-TDweITt1aUj6GPM1JmtNNKMgWwSj6sn98iwIP0rUZbsc8eTMgNQtBL92eoj/FIo3i80Xh11wKc6rTGruvor8Yw==", "dev": true, + "dependencies": { + "dockerode": "^4.0.0", + "fast-xml-parser": "^4.2.5", + "wait-on": "^7.0.1" + }, "engines": { "node": "^20.0.0", "npm": "^9.0.0" diff --git a/package.json b/package.json index f8a630270..525dbad95 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@babel/plugin-proposal-class-properties": "^7.18.6", "@nextcloud/babel-config": "^1.0.0", "@nextcloud/browserslist-config": "^3.0.0", - "@nextcloud/cypress": "^1.0.0-beta.2", + "@nextcloud/cypress": "^1.0.0-beta.7", "@nextcloud/eslint-config": "^8.3.0", "@nextcloud/stylelint-config": "^2.3.1", "@nextcloud/webpack-vue-config": "^6.0.0",