diff options
author | Julius Härtl <jus@bitgrid.net> | 2020-01-02 00:12:11 +0300 |
---|---|---|
committer | Julius Härtl <jus@bitgrid.net> | 2020-01-04 13:31:51 +0300 |
commit | 08386c96cf2b942c0d93f32aa0d39505ad6510ac (patch) | |
tree | f3ee4dc1d65fd946148119c6cfa2c4b1c9acd79a /cypress | |
parent | 290af2b60216700e2a8f7d4c3b1e9ddf0a0f2394 (diff) |
Cypress test skeleton
Signed-off-by: Julius Härtl <jus@bitgrid.net>
Diffstat (limited to 'cypress')
-rw-r--r-- | cypress/Dockerfile | 12 | ||||
-rw-r--r-- | cypress/docker-compose.yml | 14 | ||||
-rw-r--r-- | cypress/fixtures/test.md | 1 | ||||
-rw-r--r-- | cypress/integration/files.spec.js | 38 | ||||
-rw-r--r-- | cypress/integration/viewer.spec.js | 87 | ||||
-rw-r--r-- | cypress/plugins/index.js | 27 | ||||
-rwxr-xr-x | cypress/runLocal.sh | 19 | ||||
-rw-r--r-- | cypress/server.sh | 7 | ||||
-rw-r--r-- | cypress/support/commands.js | 117 | ||||
-rw-r--r-- | cypress/support/index.js | 20 | ||||
-rw-r--r-- | cypress/utils/index.js | 35 |
11 files changed, 377 insertions, 0 deletions
diff --git a/cypress/Dockerfile b/cypress/Dockerfile new file mode 100644 index 000000000..123a952fa --- /dev/null +++ b/cypress/Dockerfile @@ -0,0 +1,12 @@ +FROM nextcloudci/server:server-16 + +RUN mkdir /var/www/html/data +RUN chown -R www-data:www-data /var/www/html/data + +ENTRYPOINT /usr/local/bin/initAndRun.sh + +# FROM nextcloud:18-rc-apache + + +#ENTRYPOINT [] +#CMD ["apache2-foreground"] diff --git a/cypress/docker-compose.yml b/cypress/docker-compose.yml new file mode 100644 index 000000000..048cafaa2 --- /dev/null +++ b/cypress/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3' + +services: + nextcloud: + build: + context: . + restart: always + ports: + - 8081:80 + environment: + CYPRESS_baseUrl: + APP_SOURCE: /home/runner/work/text/text + volumes: + - $APP_SOURCE:/var/www/html/apps/text diff --git a/cypress/fixtures/test.md b/cypress/fixtures/test.md new file mode 100644 index 000000000..62c4c3f8a --- /dev/null +++ b/cypress/fixtures/test.md @@ -0,0 +1 @@ +## Hello world diff --git a/cypress/integration/files.spec.js b/cypress/integration/files.spec.js new file mode 100644 index 000000000..6f77be7db --- /dev/null +++ b/cypress/integration/files.spec.js @@ -0,0 +1,38 @@ +/** + * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + +describe('Files default view', function() { + before(function() { + cy.login('admin', 'admin') + }) + after(function() { + cy.logout() + }) + + it('See the default files list', function() { + cy.get('#fileList tr').should('contain', 'welcome.txt') + }) + + it('Take screenshot', function() { + cy.screenshot() + }) +}) diff --git a/cypress/integration/viewer.spec.js b/cypress/integration/viewer.spec.js new file mode 100644 index 000000000..36e22edf4 --- /dev/null +++ b/cypress/integration/viewer.spec.js @@ -0,0 +1,87 @@ +/** + * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + + +import { randHash } from '../utils/' +const randUser = randHash() + +describe('Open test.md in viewer', function() { + before(function() { + // Init user + cy.nextcloudCreateUser(randUser, 'password') + cy.login(randUser, 'password') + + // Upload test files + cy.uploadFile('test.md', 'text/markdown') + cy.visit('/apps/files') + + // wait a bit for things to be settled + cy.wait(1000) + }) + after(function() { + cy.logout() + }) + + it('See test.md in the list', function() { + cy.get('#fileList tr[data-file="test.md"]', { timeout: 10000 }) + .should('contain', 'test.md') + }) + + it('Open the viewer on file click', function() { + cy.visit('/apps/files') + cy.openFile('test.md') + cy.get('#viewer-content').should('be.visible') + cy.get('#viewer-content .modal-title').should('contain', 'test.md') + cy.get('#viewer-content .modal-header button.icon-menu-sidebar-white-forced').should('be.visible') + cy.get('#viewer-content .modal-header button.icon-close').should('be.visible') + + cy.wait(2000) + cy.get('#viewer-content', { timeout: 4000 }) + .should('be.visible') + .and('have.class', 'modal-mask') + .and('not.have.class', 'icon-loading') + }) + + it('Has opened the file', function() { + cy.get('#viewer-content #editor .ProseMirror').should('contain', 'Hello world') + cy.get('#viewer-content #editor .ProseMirror h2').should('contain', 'Hello world') + }) + + it('Shows the menu bar icons', function() { + // FIXME those checks are failing since the parent container is currently at 0x0 size + // due to the way we make the text app be a full screen viewer + // cy.get('#viewer-content #editor .menubar .menubar-icons .icon-undo').should('be.visible') + // cy.get('#viewer-content #editor .menubar .menubar-icons .icon-redo').should('be.visible') + // cy.get('#viewer-content #editor .menubar .menubar-icons .icon-bold').should('be.visible') + }) + + it('Closes the editor', function() { + cy.get('.modal-header button.icon-close').click() + cy.get('#viewer-content').should('not.be.visible') + }) + + it('Take screenshot', function() { + // gif is impossible to match with existing screenshot + // just taking a screenshot to manually compare if needed + cy.screenshot() + }) +}) diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js new file mode 100644 index 000000000..8431f105c --- /dev/null +++ b/cypress/plugins/index.js @@ -0,0 +1,27 @@ +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +const { + addMatchImageSnapshotPlugin +} = require('cypress-image-snapshot/plugin') +const browserify = require('@cypress/browserify-preprocessor') + +module.exports = (on) => { +} + +module.exports = (on, config) => { + + on('file:preprocessor', browserify()) + + addMatchImageSnapshotPlugin(on, config) +} diff --git a/cypress/runLocal.sh b/cypress/runLocal.sh new file mode 100755 index 000000000..e3b277113 --- /dev/null +++ b/cypress/runLocal.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +export CYPRESS_baseUrl=http://localhost:8081/index.php +export APP_SOURCE=$PWD/.. + +function finish { + docker-compose down +} +trap finish EXIT + +docker-compose up -d + +npm install --no-save wait-on +$(npm bin)/wait-on -i 500 -t 240000 $CYPRESS_baseUrl || (cd cypress && docker-compose logs && exit 1) +docker-compose exec -T nextcloud bash /var/www/html/apps/text/cypress/server.sh + +(cd .. && $(npm bin)/cypress $@) + + diff --git a/cypress/server.sh b/cypress/server.sh new file mode 100644 index 000000000..a50a2c5f0 --- /dev/null +++ b/cypress/server.sh @@ -0,0 +1,7 @@ +#!/bin/bash +git clone https://github.com/nextcloud/viewer /var/www/html/apps/viewer +su www-data -c " +php /var/www/html/occ app:enable viewer +php /var/www/html/occ app:enable text +php /var/www/html/occ app:list +" diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 000000000..7a0e0be8c --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,117 @@ +/** + * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + +import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command' +import axios from '@nextcloud/axios' + +addMatchImageSnapshotCommand() + +const url = Cypress.config('baseUrl').replace(/\/index.php\/?$/g, '') +Cypress.env('baseUrl', url) + +Cypress.Commands.add('login', (user, password, route = '/apps/files') => { + cy.clearCookies() + Cypress.Cookies.defaults({ + whitelist: /^(oc|nc)/ + }) + cy.visit(route) + cy.get('input[name=user]').type(user) + cy.get('input[name=password]').type(password) + cy.get('#submit-wrapper input[type=submit]').click() + cy.url().should('include', route) +}) + +Cypress.Commands.add('logout', () => { + cy.get('#expanddiv li[data-id="logout"] a').then(logout => { + if (logout) { + cy.visit(logout[0].href) + } + }) +}) + +Cypress.Commands.add('nextcloudCreateUser', (user, password) => { + cy.clearCookies() + cy.request({ + method: 'POST', + url: `${Cypress.env('baseUrl')}/ocs/v1.php/cloud/users?format=json`, + form: true, + body: { + userid: user, + password: password + }, + auth: { user: 'admin', pass: 'admin' }, + headers: { + 'OCS-ApiRequest': 'true', + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: 'Basic YWRtaW46YWRtaW4=' + } + }).then(response => { + cy.log(`Created user ${user}`, response.status) + }) +}) + +Cypress.Commands.add('uploadFile', (fileName, mimeType) => { + cy.fixture(fileName, 'base64') + .then(Cypress.Blob.base64StringToBlob) + .then(async blob => { + const file = new File([blob], fileName, { type: mimeType }) + await cy.window().then(async window => { + await axios.put(`${Cypress.env('baseUrl')}/remote.php/webdav/${fileName}`, file, { + headers: { + requesttoken: window.OC.requestToken, + 'Content-Type': mimeType + } + }).then(response => { + cy.log(`Uploaded ${fileName}`, response.status) + }) + }) + }) +}) + +Cypress.Commands.add('createFolder', dirName => { + cy.get('#controls .actions > .button.new').click() + cy.get('#controls .actions .newFileMenu a[data-action="folder"]').click() + cy.get('#controls .actions .newFileMenu a[data-action="folder"] input[type="text"]').type(dirName) + cy.get('#controls .actions .newFileMenu a[data-action="folder"] input.icon-confirm').click() + cy.log('Created folder', dirName) +}) + +Cypress.Commands.add('openFile', fileName => { + cy.get(`#fileList tr[data-file="${fileName}"] a.name`).click() + cy.wait(250) +}) + +Cypress.Commands.add('deleteFile', fileName => { + cy.get(`#fileList tr[data-file="${fileName}"] a.name .action-menu`).click() + cy.get(`#fileList tr[data-file="${fileName}"] a.name + .popovermenu .action-delete`).click() +}) + +Cypress.Commands.overwrite('matchImageSnapshot', (originalFn, subject, name, options) => { + // hide avatar because random colour break the visual regression tests + cy.window().then(win => { + const avatarDiv = win.document.querySelector('.avatardiv') + if (avatarDiv) { + avatarDiv.remove() + } + }) + return originalFn(subject, name, options) +}) diff --git a/cypress/support/index.js b/cypress/support/index.js new file mode 100644 index 000000000..d68db96df --- /dev/null +++ b/cypress/support/index.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/cypress/utils/index.js b/cypress/utils/index.js new file mode 100644 index 000000000..cee81c0f5 --- /dev/null +++ b/cypress/utils/index.js @@ -0,0 +1,35 @@ +/** + * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + +const getSearchParams = url => { + return url + .split(/[?&]/) + .reduce((acc, cur) => { + const parts = cur.split('=') + parts[1] && (acc[parts[0]] = parts[1]) + return acc + }, {}) +} + +const randHash = () => Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10) + +export default { getSearchParams, randHash } |