From 3e967da6d09483245b096af5ac599c7d72eb9d46 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Tue, 9 Jun 2020 13:52:00 +0200 Subject: [PATCH 01/26] feat: adds cypress to the builder --- config.js | 13 + packages/builder/cypress.json | 4 + .../builder/cypress/fixtures/example.json | 5 + .../builder/cypress/fixtures/profile.json | 5 + packages/builder/cypress/fixtures/users.json | 232 ++++++++++++++++++ packages/builder/cypress/plugins/index.js | 21 ++ packages/builder/cypress/support/commands.js | 25 ++ packages/builder/cypress/support/index.js | 20 ++ packages/builder/package.json | 6 +- 9 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 config.js create mode 100644 packages/builder/cypress.json create mode 100644 packages/builder/cypress/fixtures/example.json create mode 100644 packages/builder/cypress/fixtures/profile.json create mode 100644 packages/builder/cypress/fixtures/users.json create mode 100644 packages/builder/cypress/plugins/index.js create mode 100644 packages/builder/cypress/support/commands.js create mode 100644 packages/builder/cypress/support/index.js diff --git a/config.js b/config.js new file mode 100644 index 0000000000..7bc75c9fb2 --- /dev/null +++ b/config.js @@ -0,0 +1,13 @@ +module.exports = () => ({ + datastore: "local", + datastoreConfig: { + rootPath: "./.data", + }, + keys: ["secret1", "secret2"], + port: 4001, + latestPackagesFolder: ".", + extraMasterPlugins: {}, + dev: true, + customizeMaster: appDefinition => appDefinition, + useAppRootPath: true, +}) diff --git a/packages/builder/cypress.json b/packages/builder/cypress.json new file mode 100644 index 0000000000..477d0a6dc4 --- /dev/null +++ b/packages/builder/cypress.json @@ -0,0 +1,4 @@ +{ + "baseUrl": "http://localhost:4001/_builder/", + "video": false +} \ No newline at end of file diff --git a/packages/builder/cypress/fixtures/example.json b/packages/builder/cypress/fixtures/example.json new file mode 100644 index 0000000000..da18d9352a --- /dev/null +++ b/packages/builder/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} \ No newline at end of file diff --git a/packages/builder/cypress/fixtures/profile.json b/packages/builder/cypress/fixtures/profile.json new file mode 100644 index 0000000000..b6c355ca5c --- /dev/null +++ b/packages/builder/cypress/fixtures/profile.json @@ -0,0 +1,5 @@ +{ + "id": 8739, + "name": "Jane", + "email": "jane@example.com" +} \ No newline at end of file diff --git a/packages/builder/cypress/fixtures/users.json b/packages/builder/cypress/fixtures/users.json new file mode 100644 index 0000000000..79b699aa77 --- /dev/null +++ b/packages/builder/cypress/fixtures/users.json @@ -0,0 +1,232 @@ +[ + { + "id": 1, + "name": "Leanne Graham", + "username": "Bret", + "email": "Sincere@april.biz", + "address": { + "street": "Kulas Light", + "suite": "Apt. 556", + "city": "Gwenborough", + "zipcode": "92998-3874", + "geo": { + "lat": "-37.3159", + "lng": "81.1496" + } + }, + "phone": "1-770-736-8031 x56442", + "website": "hildegard.org", + "company": { + "name": "Romaguera-Crona", + "catchPhrase": "Multi-layered client-server neural-net", + "bs": "harness real-time e-markets" + } + }, + { + "id": 2, + "name": "Ervin Howell", + "username": "Antonette", + "email": "Shanna@melissa.tv", + "address": { + "street": "Victor Plains", + "suite": "Suite 879", + "city": "Wisokyburgh", + "zipcode": "90566-7771", + "geo": { + "lat": "-43.9509", + "lng": "-34.4618" + } + }, + "phone": "010-692-6593 x09125", + "website": "anastasia.net", + "company": { + "name": "Deckow-Crist", + "catchPhrase": "Proactive didactic contingency", + "bs": "synergize scalable supply-chains" + } + }, + { + "id": 3, + "name": "Clementine Bauch", + "username": "Samantha", + "email": "Nathan@yesenia.net", + "address": { + "street": "Douglas Extension", + "suite": "Suite 847", + "city": "McKenziehaven", + "zipcode": "59590-4157", + "geo": { + "lat": "-68.6102", + "lng": "-47.0653" + } + }, + "phone": "1-463-123-4447", + "website": "ramiro.info", + "company": { + "name": "Romaguera-Jacobson", + "catchPhrase": "Face to face bifurcated interface", + "bs": "e-enable strategic applications" + } + }, + { + "id": 4, + "name": "Patricia Lebsack", + "username": "Karianne", + "email": "Julianne.OConner@kory.org", + "address": { + "street": "Hoeger Mall", + "suite": "Apt. 692", + "city": "South Elvis", + "zipcode": "53919-4257", + "geo": { + "lat": "29.4572", + "lng": "-164.2990" + } + }, + "phone": "493-170-9623 x156", + "website": "kale.biz", + "company": { + "name": "Robel-Corkery", + "catchPhrase": "Multi-tiered zero tolerance productivity", + "bs": "transition cutting-edge web services" + } + }, + { + "id": 5, + "name": "Chelsey Dietrich", + "username": "Kamren", + "email": "Lucio_Hettinger@annie.ca", + "address": { + "street": "Skiles Walks", + "suite": "Suite 351", + "city": "Roscoeview", + "zipcode": "33263", + "geo": { + "lat": "-31.8129", + "lng": "62.5342" + } + }, + "phone": "(254)954-1289", + "website": "demarco.info", + "company": { + "name": "Keebler LLC", + "catchPhrase": "User-centric fault-tolerant solution", + "bs": "revolutionize end-to-end systems" + } + }, + { + "id": 6, + "name": "Mrs. Dennis Schulist", + "username": "Leopoldo_Corkery", + "email": "Karley_Dach@jasper.info", + "address": { + "street": "Norberto Crossing", + "suite": "Apt. 950", + "city": "South Christy", + "zipcode": "23505-1337", + "geo": { + "lat": "-71.4197", + "lng": "71.7478" + } + }, + "phone": "1-477-935-8478 x6430", + "website": "ola.org", + "company": { + "name": "Considine-Lockman", + "catchPhrase": "Synchronised bottom-line interface", + "bs": "e-enable innovative applications" + } + }, + { + "id": 7, + "name": "Kurtis Weissnat", + "username": "Elwyn.Skiles", + "email": "Telly.Hoeger@billy.biz", + "address": { + "street": "Rex Trail", + "suite": "Suite 280", + "city": "Howemouth", + "zipcode": "58804-1099", + "geo": { + "lat": "24.8918", + "lng": "21.8984" + } + }, + "phone": "210.067.6132", + "website": "elvis.io", + "company": { + "name": "Johns Group", + "catchPhrase": "Configurable multimedia task-force", + "bs": "generate enterprise e-tailers" + } + }, + { + "id": 8, + "name": "Nicholas Runolfsdottir V", + "username": "Maxime_Nienow", + "email": "Sherwood@rosamond.me", + "address": { + "street": "Ellsworth Summit", + "suite": "Suite 729", + "city": "Aliyaview", + "zipcode": "45169", + "geo": { + "lat": "-14.3990", + "lng": "-120.7677" + } + }, + "phone": "586.493.6943 x140", + "website": "jacynthe.com", + "company": { + "name": "Abernathy Group", + "catchPhrase": "Implemented secondary concept", + "bs": "e-enable extensible e-tailers" + } + }, + { + "id": 9, + "name": "Glenna Reichert", + "username": "Delphine", + "email": "Chaim_McDermott@dana.io", + "address": { + "street": "Dayna Park", + "suite": "Suite 449", + "city": "Bartholomebury", + "zipcode": "76495-3109", + "geo": { + "lat": "24.6463", + "lng": "-168.8889" + } + }, + "phone": "(775)976-6794 x41206", + "website": "conrad.com", + "company": { + "name": "Yost and Sons", + "catchPhrase": "Switchable contextually-based project", + "bs": "aggregate real-time technologies" + } + }, + { + "id": 10, + "name": "Clementina DuBuque", + "username": "Moriah.Stanton", + "email": "Rey.Padberg@karina.biz", + "address": { + "street": "Kattie Turnpike", + "suite": "Suite 198", + "city": "Lebsackbury", + "zipcode": "31428-2261", + "geo": { + "lat": "-38.2386", + "lng": "57.2232" + } + }, + "phone": "024-648-3804", + "website": "ambrose.net", + "company": { + "name": "Hoeger LLC", + "catchPhrase": "Centralized empowering task-force", + "bs": "target end-to-end models" + } + } +] \ No newline at end of file diff --git a/packages/builder/cypress/plugins/index.js b/packages/builder/cypress/plugins/index.js new file mode 100644 index 0000000000..aa9918d215 --- /dev/null +++ b/packages/builder/cypress/plugins/index.js @@ -0,0 +1,21 @@ +/// +// *********************************************************** +// 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) + +/** + * @type {Cypress.PluginConfig} + */ +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js new file mode 100644 index 0000000000..ca4d256f3e --- /dev/null +++ b/packages/builder/cypress/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/packages/builder/cypress/support/index.js b/packages/builder/cypress/support/index.js new file mode 100644 index 0000000000..d68db96df2 --- /dev/null +++ b/packages/builder/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/packages/builder/package.json b/packages/builder/package.json index 8fe9ffd494..32f5cd823f 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -9,7 +9,10 @@ "test": "jest", "test:watch": "jest --watchAll", "dev:builder": "routify --routify-dir routify -c rollup", - "rollup": "rollup -c -w" + "rollup": "rollup -c -w", + "cy:setup": "node ../cli/bin/budi init -d ~/.budibase-cypress && node ../cli/bin/budi run -d ~/.budibase-cypress", + "cy:run": "dev:cypress run", + "cy:open": "cypress open" }, "jest": { "globals": { @@ -67,6 +70,7 @@ "@sveltech/routify": "1.7.11", "babel-jest": "^24.8.0", "browser-sync": "^2.26.7", + "cypress": "^4.8.0", "http-proxy-middleware": "^0.19.1", "jest": "^24.8.0", "ncp": "^2.0.0", From b9e8319670608d8c154d97afa57bb308dcca6fd4 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Tue, 9 Jun 2020 13:52:19 +0200 Subject: [PATCH 02/26] adds test for creating budibase app --- .../cypress/integration/createApp.spec.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 packages/builder/cypress/integration/createApp.spec.js diff --git a/packages/builder/cypress/integration/createApp.spec.js b/packages/builder/cypress/integration/createApp.spec.js new file mode 100644 index 0000000000..d8f9331eec --- /dev/null +++ b/packages/builder/cypress/integration/createApp.spec.js @@ -0,0 +1,25 @@ +context('Create Application', () => { + + beforeEach(() => { + cy.visit('localhost:4001/_builder') + }) + + // https://on.cypress.io/interacting-with-elements + + it('should create a new application', () => { + // https://on.cypress.io/type + cy.get('.banner-button') + .click() + .get('input[name="name"]') + .type('My Cool Application').should('have.value', 'My Cool Application') + + cy.get('textarea[name="description"]') + .type('This is a description').should('have.value', 'This is a description') + + cy.contains('Save').click() + + cy.visit('localhost:4001/_builder') + + cy.contains('My Cool Application') + }) +}) From e0e6be8aa3ad0652525a4e61833a2bfe00f6c105 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Tue, 9 Jun 2020 15:39:50 +0200 Subject: [PATCH 03/26] setup commands to allow running tests from project root instead of just builder package --- CONTRIBUTING.md | 10 ++++++++++ package.json | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ab2e7d597b..ac35a4277d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -166,6 +166,16 @@ rm -rf ~/.budibase ``` Follow from **Step 3. Install and Build** in the setup guide above. You should have a fresh Budibase installation. +### Running tests + +#### End-to-end Tests + +Budibase uses Cypress to run a number of E2E tests. To run the tests execute the following command: + +``` +yarn test:e2e +``` + ### Other Useful Information diff --git a/package.json b/package.json index 443c8cccc3..e4e4a3bd4e 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "test": "lerna run test", "lint": "eslint packages", "lint:fix": "eslint --fix packages", - "format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\"" + "format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\"", + "test:e2e": "lerna run cy:test" }, "dependencies": { "@material/icon-button": "4.0.0", From e4fded71142b2f89e5fbdcc2ae06f5fc4ac4f30e Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Tue, 9 Jun 2020 15:40:00 +0200 Subject: [PATCH 04/26] update create app test --- packages/builder/cypress/integration/createApp.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/cypress/integration/createApp.spec.js b/packages/builder/cypress/integration/createApp.spec.js index d8f9331eec..a6e488baf6 100644 --- a/packages/builder/cypress/integration/createApp.spec.js +++ b/packages/builder/cypress/integration/createApp.spec.js @@ -20,6 +20,6 @@ context('Create Application', () => { cy.visit('localhost:4001/_builder') - cy.contains('My Cool Application') + cy.contains('My Cool Application').should('exist') }) }) From 0c20d328ae705bdb0842692ce0591efc51444e68 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Tue, 9 Jun 2020 15:40:14 +0200 Subject: [PATCH 05/26] add tests to create model and record --- .../cypress/integration/createModel.spec.js | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 packages/builder/cypress/integration/createModel.spec.js diff --git a/packages/builder/cypress/integration/createModel.spec.js b/packages/builder/cypress/integration/createModel.spec.js new file mode 100644 index 0000000000..50e523c598 --- /dev/null +++ b/packages/builder/cypress/integration/createModel.spec.js @@ -0,0 +1,74 @@ +context('Create Model', () => { + + beforeEach(() => { + cy.visit('localhost:4001/_builder') + }) + + // https://on.cypress.io/interacting-with-elements + + it('should create a new model', () => { + // https://on.cypress.io/type + cy.get('.banner-button') + .click() + .get('input[name="name"]') + .type('My Cool Application').should('have.value', 'My Cool Application') + + cy.get('textarea[name="description"]') + .type('This is a description').should('have.value', 'This is a description') + + cy.contains('Save').click() + + // Enter model name + cy.get('.budibase__input') + .type('dog') + + // Add new field + cy.get('.new-field') + .click() + + // Enter field name + cy.get('.budibase__input').first() + .type('name') + + // Save + cy.contains('Save').click() + + + // Add new field + cy.get('.new-field') + .click() + + // Enter field name + cy.get('.budibase__input').first() + .type('age') + + cy.get('select').select('number') + + // Save + cy.contains('Save').click() + + cy.contains('age').should('exist') + + // Save + cy.contains('Save').click() + + cy.get('.title').should('have.text', 'dog') + }) + it('should add a record', () => { + + // Open just created app + cy.get(':nth-child(1) > .card-footer > .app-button') + .click() + + // Open add record modal + cy.get('.button') + .click() + + cy.get(':nth-child(1) > .uk-input').type('bob').get(':nth-child(2) > .uk-input').type('15') + + // Save + cy.contains('Save').click() + + cy.contains('bob').should('have.text', 'bob') + }) +}) From 989b0429936c4a5e40436e4ea2aede2f164b7781 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Tue, 9 Jun 2020 15:48:25 +0200 Subject: [PATCH 06/26] adds missing package.json commands --- packages/builder/package.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/builder/package.json b/packages/builder/package.json index 32f5cd823f..ebd30c31bd 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -10,9 +10,10 @@ "test:watch": "jest --watchAll", "dev:builder": "routify --routify-dir routify -c rollup", "rollup": "rollup -c -w", - "cy:setup": "node ../cli/bin/budi init -d ~/.budibase-cypress && node ../cli/bin/budi run -d ~/.budibase-cypress", - "cy:run": "dev:cypress run", - "cy:open": "cypress open" + "cy:setup": "rm -rf node ~/.budibase-cypress && ../cli/bin/budi init -d ~/.budibase-cypress && node ../cli/bin/budi run -d ~/.budibase-cypress", + "cy:run": "cypress run", + "cy:open": "cypress open", + "cy:test": "start-server-and-test cy:setup http://localhost:4001/_builder cy:run" }, "jest": { "globals": { @@ -87,6 +88,7 @@ "rollup-plugin-svelte": "^5.0.3", "rollup-plugin-terser": "^4.0.4", "rollup-plugin-url": "^2.2.2", + "start-server-and-test": "^1.11.0", "svelte": "3.23.x" }, "gitHead": "115189f72a850bfb52b65ec61d932531bf327072" From 202abaa13eff9deb78c4b56a35ce99735cabf49e Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 11 Jun 2020 12:04:31 +0200 Subject: [PATCH 07/26] rework tests to use commands for DRYness --- .../cypress/integration/createApp.spec.js | 12 +--- .../cypress/integration/createModel.spec.js | 65 +++---------------- .../cypress/integration/createUser.spec.js | 19 ++++++ packages/builder/cypress/support/commands.js | 59 +++++++++++++++++ 4 files changed, 88 insertions(+), 67 deletions(-) create mode 100644 packages/builder/cypress/integration/createUser.spec.js diff --git a/packages/builder/cypress/integration/createApp.spec.js b/packages/builder/cypress/integration/createApp.spec.js index a6e488baf6..cbfbed06bb 100644 --- a/packages/builder/cypress/integration/createApp.spec.js +++ b/packages/builder/cypress/integration/createApp.spec.js @@ -8,18 +8,10 @@ context('Create Application', () => { it('should create a new application', () => { // https://on.cypress.io/type - cy.get('.banner-button') - .click() - .get('input[name="name"]') - .type('My Cool Application').should('have.value', 'My Cool Application') - - cy.get('textarea[name="description"]') - .type('This is a description').should('have.value', 'This is a description') - - cy.contains('Save').click() + cy.createApp('My Cool App', 'This is a description') cy.visit('localhost:4001/_builder') - cy.contains('My Cool Application').should('exist') + cy.contains('My Cool App').should('exist') }) }) diff --git a/packages/builder/cypress/integration/createModel.spec.js b/packages/builder/cypress/integration/createModel.spec.js index 50e523c598..ec447f07f9 100644 --- a/packages/builder/cypress/integration/createModel.spec.js +++ b/packages/builder/cypress/integration/createModel.spec.js @@ -1,73 +1,24 @@ context('Create Model', () => { - beforeEach(() => { + before(() => { cy.visit('localhost:4001/_builder') + // https://on.cypress.io/type + cy.createApp('Model App', 'Model App Description') }) // https://on.cypress.io/interacting-with-elements - it('should create a new model', () => { - // https://on.cypress.io/type - cy.get('.banner-button') - .click() - .get('input[name="name"]') - .type('My Cool Application').should('have.value', 'My Cool Application') - cy.get('textarea[name="description"]') - .type('This is a description').should('have.value', 'This is a description') - - cy.contains('Save').click() - - // Enter model name - cy.get('.budibase__input') - .type('dog') - - // Add new field - cy.get('.new-field') - .click() - - // Enter field name - cy.get('.budibase__input').first() - .type('name') - - // Save - cy.contains('Save').click() - - - // Add new field - cy.get('.new-field') - .click() - - // Enter field name - cy.get('.budibase__input').first() - .type('age') - - cy.get('select').select('number') - - // Save - cy.contains('Save').click() - - cy.contains('age').should('exist') - - // Save - cy.contains('Save').click() + cy.createModel('dog', 'name', 'age') + // Check if model exists cy.get('.title').should('have.text', 'dog') }) it('should add a record', () => { + // Page needs to be reloaded for some reason, cookie might be remove between tests? + cy.reload() - // Open just created app - cy.get(':nth-child(1) > .card-footer > .app-button') - .click() - - // Open add record modal - cy.get('.button') - .click() - - cy.get(':nth-child(1) > .uk-input').type('bob').get(':nth-child(2) > .uk-input').type('15') - - // Save - cy.contains('Save').click() + cy.addRecord('bob', '15') cy.contains('bob').should('have.text', 'bob') }) diff --git a/packages/builder/cypress/integration/createUser.spec.js b/packages/builder/cypress/integration/createUser.spec.js new file mode 100644 index 0000000000..5d46ec780b --- /dev/null +++ b/packages/builder/cypress/integration/createUser.spec.js @@ -0,0 +1,19 @@ +context('Create Model', () => { + + before(() => { + cy.visit('localhost:4001/_builder') + // https://on.cypress.io/type + cy.createApp('User App', 'This app is used to test user creation') + }) + + // https://on.cypress.io/interacting-with-elements + it('should create a user', () => { + // Close Model modal that shows up after creating an app + cy.get('.close').click() + + cy.createUser('bbuser', 'test', 'ADMIN') + + // Check to make sure user was created! + cy.contains('bbuser').should('have.text', 'bbuser') + }) +}) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index ca4d256f3e..29a2e00673 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -23,3 +23,62 @@ // // -- This will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) + +Cypress.Commands.add("createApp", (name, description) => { + cy.get('.banner-button') + .click() + .get('input[name="name"]') + .type(name).should('have.value', name) + + cy.get('textarea[name="description"]') + .type(description).should('have.value', description) + + cy.contains('Save').click() +}) +Cypress.Commands.add("createModel", (modelName, firstField, secondField) => { + // Enter model name + cy.get('.budibase__input') + .type(modelName) + + // Add 'name' field + cy.get('.new-field') + .click() + cy.get('.budibase__input').first() + .type(firstField) + cy.contains('Save').click() + + + // Add 'age' field + cy.get('.new-field') + .click() + cy.get('.budibase__input').first() + .type(secondField) + cy.get('select').select('number') + cy.contains('Save').click() + cy.contains(secondField).should('exist') + + // Save model + cy.contains('Save').click() +}) +Cypress.Commands.add("addRecord", (firstField, secondField) => { + cy.contains('Create new record') + .click() + + cy.get(':nth-child(1) > .uk-input').type(firstField).get(':nth-child(2) > .uk-input').type(secondField) + + // Save + cy.contains('Save').click() +}) + +Cypress.Commands.add("createUser", (username, password, level) => { + // Create User + cy.get('.nav-group-header > .ri-add-line') + .click() + + cy.get(':nth-child(2) > .uk-input').type(username) + cy.get(':nth-child(3) > .uk-input').type(password) + cy.get('.uk-select').select(level) + + // Save + cy.contains('Save').click() +}) \ No newline at end of file From b473604bc4326d8fa1e4fbae607fac3413e8f9df Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 11 Jun 2020 12:56:16 +0200 Subject: [PATCH 08/26] adds tests to add components and change props on them --- .../integration/createComponents.spec.js | 53 +++++++++++++++++++ packages/builder/cypress/support/commands.js | 12 +++++ .../src/components/common/Input.svelte | 2 + .../userInterface/PropertyControl.svelte | 3 +- 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 packages/builder/cypress/integration/createComponents.spec.js diff --git a/packages/builder/cypress/integration/createComponents.spec.js b/packages/builder/cypress/integration/createComponents.spec.js new file mode 100644 index 0000000000..ad23566c0d --- /dev/null +++ b/packages/builder/cypress/integration/createComponents.spec.js @@ -0,0 +1,53 @@ +context('Create Model', () => { + + before(() => { + cy.visit('localhost:4001/_builder') + // https://on.cypress.io/type + cy.createApp('Model App', 'Model App Description') + cy.createModel('dog', 'name', 'age') + cy.addRecord('bob', '15') + }) + + // https://on.cypress.io/interacting-with-elements + it('should add a container', () => { + cy.contains('frontend').click() + cy.get('.switcher > :nth-child(2)').click() + + cy.contains('Container').click() + }) + it('should add a headline', () => { + cy.addHeadlineComponent('An Amazing headline!') + + getIframeBody().contains('An Amazing headline!') + }) + it('change the background color of the headline', () => { + cy.contains('Background').click() + cy.get('input[name="background"]') + .type('rgb(102, 51, 153)') + cy.contains('Design').click() + + getIframeBody().contains('An Amazing headline!').should('have.css', 'background-color', 'rgb(102, 51, 153)') + }) +}) + +const getIframeDocument = () => { + return cy + .get('iframe') + // Cypress yields jQuery element, which has the real + // DOM element under property "0". + // From the real DOM iframe element we can get + // the "document" element, it is stored in "contentDocument" property + // Cypress "its" command can access deep properties using dot notation + // https://on.cypress.io/its + .its('0.contentDocument').should('exist') +} + +const getIframeBody = () => { + // get the document + return getIframeDocument() + // automatically retries until body is loaded + .its('body').should('not.be.undefined') + // wraps "body" DOM element to allow + // chaining more Cypress commands, like ".find(...)" + .then(cy.wrap) +} \ No newline at end of file diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index 29a2e00673..ffe265a2a2 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -81,4 +81,16 @@ Cypress.Commands.add("createUser", (username, password, level) => { // Save cy.contains('Save').click() +}) + +Cypress.Commands.add("addHeadlineComponent", (text) => { + // Create User + cy.get('.switcher > :nth-child(2)').click() + + cy.contains('Text').click() + cy.contains('Headline').click() + cy.get('.tabs > :nth-child(2)').click() + cy.get('input[type="text"]') + .type(text) + cy.contains('Design').click() }) \ No newline at end of file diff --git a/packages/builder/src/components/common/Input.svelte b/packages/builder/src/components/common/Input.svelte index 82305be60a..5db342b2c8 100644 --- a/packages/builder/src/components/common/Input.svelte +++ b/packages/builder/src/components/common/Input.svelte @@ -2,6 +2,7 @@ import { onMount } from "svelte" import { buildStyle } from "../../helpers.js" export let value = "" + export let name = "" export let textAlign = "left" export let width = "160px" export let placeholder = "" @@ -25,6 +26,7 @@ handleChange(key, val)} onChange={val => handleChange(key, val)} - {...props} /> + {...props} + name={key} /> From 0ab7b99f410c53742eb9de437dfd76fffde39a97 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 11 Jun 2020 13:20:13 +0200 Subject: [PATCH 09/26] update names for tests --- packages/builder/cypress/integration/createApp.spec.js | 2 +- packages/builder/cypress/integration/createComponents.spec.js | 2 +- packages/builder/cypress/integration/createModel.spec.js | 2 +- packages/builder/cypress/integration/createUser.spec.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/builder/cypress/integration/createApp.spec.js b/packages/builder/cypress/integration/createApp.spec.js index cbfbed06bb..07a8687ea8 100644 --- a/packages/builder/cypress/integration/createApp.spec.js +++ b/packages/builder/cypress/integration/createApp.spec.js @@ -1,4 +1,4 @@ -context('Create Application', () => { +context('Create an Application', () => { beforeEach(() => { cy.visit('localhost:4001/_builder') diff --git a/packages/builder/cypress/integration/createComponents.spec.js b/packages/builder/cypress/integration/createComponents.spec.js index ad23566c0d..299f6b8ad2 100644 --- a/packages/builder/cypress/integration/createComponents.spec.js +++ b/packages/builder/cypress/integration/createComponents.spec.js @@ -1,4 +1,4 @@ -context('Create Model', () => { +context('Create Components', () => { before(() => { cy.visit('localhost:4001/_builder') diff --git a/packages/builder/cypress/integration/createModel.spec.js b/packages/builder/cypress/integration/createModel.spec.js index ec447f07f9..061dadaa3d 100644 --- a/packages/builder/cypress/integration/createModel.spec.js +++ b/packages/builder/cypress/integration/createModel.spec.js @@ -1,4 +1,4 @@ -context('Create Model', () => { +context('Create a Model', () => { before(() => { cy.visit('localhost:4001/_builder') diff --git a/packages/builder/cypress/integration/createUser.spec.js b/packages/builder/cypress/integration/createUser.spec.js index 5d46ec780b..80d1a51d84 100644 --- a/packages/builder/cypress/integration/createUser.spec.js +++ b/packages/builder/cypress/integration/createUser.spec.js @@ -1,4 +1,4 @@ -context('Create Model', () => { +context('Create a User', () => { before(() => { cy.visit('localhost:4001/_builder') From 5140069ed633680863cad77d6cd7f29dd15b692f Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 11 Jun 2020 16:40:07 +0200 Subject: [PATCH 10/26] adds some data-cy properties to a number of elements and starts work on workflow tests --- .../cypress/integration/createModel.spec.js | 4 +- .../integration/createWorkflow.spec.js | 39 +++++++++++++++++++ packages/builder/cypress/support/commands.js | 10 +++-- .../userInterface/CategoryTab.svelte | 1 + .../userInterface/ItemTab/Item.svelte | 6 ++- .../workflow/SetupPanel/SetupPanel.svelte | 5 ++- .../BlockList/WorkflowBlock.svelte | 5 ++- .../WorkflowPanel/WorkflowPanel.svelte | 2 + 8 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 packages/builder/cypress/integration/createWorkflow.spec.js diff --git a/packages/builder/cypress/integration/createModel.spec.js b/packages/builder/cypress/integration/createModel.spec.js index 061dadaa3d..3d46316607 100644 --- a/packages/builder/cypress/integration/createModel.spec.js +++ b/packages/builder/cypress/integration/createModel.spec.js @@ -1,6 +1,7 @@ context('Create a Model', () => { before(() => { + Cypress.Cookies.preserveOnce('builder:token') cy.visit('localhost:4001/_builder') // https://on.cypress.io/type cy.createApp('Model App', 'Model App Description') @@ -15,9 +16,6 @@ context('Create a Model', () => { cy.get('.title').should('have.text', 'dog') }) it('should add a record', () => { - // Page needs to be reloaded for some reason, cookie might be remove between tests? - cy.reload() - cy.addRecord('bob', '15') cy.contains('bob').should('have.text', 'bob') diff --git a/packages/builder/cypress/integration/createWorkflow.spec.js b/packages/builder/cypress/integration/createWorkflow.spec.js new file mode 100644 index 0000000000..62f00e92d2 --- /dev/null +++ b/packages/builder/cypress/integration/createWorkflow.spec.js @@ -0,0 +1,39 @@ +context('Create a workflow', () => { + + before(() => { + Cypress.Cookies.preserveOnce('builder:token') + cy.visit('localhost:4001/_builder') + // https://on.cypress.io/type + cy.createApp('Workflow Test App', 'This app is used to test that workflows do in fact work!') + }) + + // https://on.cypress.io/interacting-with-elements + it('should create a workflow', () => { + cy.createModel('dog', 'name', 'age') + cy.createUser('bbuser', 'test', 'ADMIN') + + + cy.contains('workflow').click() + cy.get('.new-workflow-button').click() + cy.get('input').type('Add Record') + cy.contains('Save').click() + + cy.get('[data-cy=add-workflow-component]').click() + cy.contains('Actions').click() + + cy.get('[data-cy=SAVE_RECORD]').click() + + cy.get(':nth-child(2) > .budibase__input').type('goodboy') + cy.get(':nth-child(3) > .budibase__input').type('11') + + // Save + cy.get('[data-cy=save-workflow-setup]').click() + cy.get('.workflow-button').click() + + }) + it('should be able to run', () => { + cy.contains('frontend').click() + cy.addButtonComponent() + + }) +}) \ No newline at end of file diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index ffe265a2a2..7a3d276425 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -84,13 +84,17 @@ Cypress.Commands.add("createUser", (username, password, level) => { }) Cypress.Commands.add("addHeadlineComponent", (text) => { - // Create User cy.get('.switcher > :nth-child(2)').click() - cy.contains('Text').click() - cy.contains('Headline').click() + cy.get('[data-cy=Text]').click() + cy.get('[data-cy=Headline]').click() cy.get('.tabs > :nth-child(2)').click() cy.get('input[type="text"]') .type(text) cy.contains('Design').click() +}) +Cypress.Commands.add("addButtonComponent", (text) => { + cy.get('.switcher > :nth-child(2)').click() + + cy.get('[data-cy=Button]').click() }) \ No newline at end of file diff --git a/packages/builder/src/components/userInterface/CategoryTab.svelte b/packages/builder/src/components/userInterface/CategoryTab.svelte index 074839eca2..5f7c3e584e 100644 --- a/packages/builder/src/components/userInterface/CategoryTab.svelte +++ b/packages/builder/src/components/userInterface/CategoryTab.svelte @@ -7,6 +7,7 @@
{#each categories as category}
  • onClick(category)} class:active={selectedCategory === category}> {category.name} diff --git a/packages/builder/src/components/userInterface/ItemTab/Item.svelte b/packages/builder/src/components/userInterface/ItemTab/Item.svelte index e5b36d0183..4e2806b018 100644 --- a/packages/builder/src/components/userInterface/ItemTab/Item.svelte +++ b/packages/builder/src/components/userInterface/ItemTab/Item.svelte @@ -3,7 +3,11 @@ export let item -
    +
    diff --git a/packages/builder/src/components/workflow/SetupPanel/SetupPanel.svelte b/packages/builder/src/components/workflow/SetupPanel/SetupPanel.svelte index 456505a4a8..eb88f6bb23 100644 --- a/packages/builder/src/components/workflow/SetupPanel/SetupPanel.svelte +++ b/packages/builder/src/components/workflow/SetupPanel/SetupPanel.svelte @@ -96,7 +96,10 @@ {#if workflowBlock}
    - From d0178ed6b5de716a814f5d75fa8c48d8b5fc2b7c Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 11 Jun 2020 17:59:11 +0200 Subject: [PATCH 13/26] adds script to run cypress tests --- packages/builder/.gitignore | 1 + packages/builder/cypress/setup.js | 15 +++++++++++++++ packages/builder/package.json | 5 +++-- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 packages/builder/cypress/setup.js diff --git a/packages/builder/.gitignore b/packages/builder/.gitignore index 94ba827047..49444a4fc0 100644 --- a/packages/builder/.gitignore +++ b/packages/builder/.gitignore @@ -5,4 +5,5 @@ package-lock.json yarn.lock release/ dist/ +cypress/screenshots routify diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js new file mode 100644 index 0000000000..67ac005e49 --- /dev/null +++ b/packages/builder/cypress/setup.js @@ -0,0 +1,15 @@ +// What this script does: +// 1. Removes the old test folder if it exists (.budibase-cypress) +// 2. Initialises using `.budibase-cypress` +// 3. Runs the server using said folder + +const rimraf = require("rimraf"); +const homedir = require('os').homedir() + '/.budibase-cypress'; +const { exec } = require("child_process") + +rimraf(homedir, function (error) { + console.log('Error: ', error); +}) + +exec(`../../packages/cli/bin/budi init -d ${homedir}`) +exec(`../../packages/cli/bin/budi run -d ${homedir}`) \ No newline at end of file diff --git a/packages/builder/package.json b/packages/builder/package.json index 30674b0f9d..56ee5135e3 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -10,10 +10,10 @@ "test:watch": "jest --watchAll", "dev:builder": "routify --routify-dir routify -c rollup", "rollup": "rollup -c -w", - "cy:setup": "rm -rf node ~/.budibase-cypress && ../cli/bin/budi init -d ~/.budibase-cypress && node ../cli/bin/budi run -d ~/.budibase-cypress", + "cy:setup": "node ./cypress/setup.js", "cy:run": "cypress run", "cy:open": "cypress open", - "cy:test": "start-server-and-test cy:setup http://localhost:4001/_builder cy:open" + "cy:test": "start-server-and-test cy:setup http://localhost:4001/_builder cy:run" }, "jest": { "globals": { @@ -76,6 +76,7 @@ "jest": "^24.8.0", "ncp": "^2.0.0", "npm-run-all": "^4.1.5", + "rimraf": "^3.0.2", "rollup": "^1.12.0", "rollup-plugin-alias": "^1.5.2", "rollup-plugin-browsersync": "^1.0.0", From 7bd45fd68331e7304bee02cd15d1836a09f5b525 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 11 Jun 2020 18:10:53 +0200 Subject: [PATCH 14/26] update script to be sync rather than async --- packages/builder/cypress/setup.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index 67ac005e49..b737f3ef2e 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -5,11 +5,9 @@ const rimraf = require("rimraf"); const homedir = require('os').homedir() + '/.budibase-cypress'; -const { exec } = require("child_process") +const { execSync } = require("child_process") -rimraf(homedir, function (error) { - console.log('Error: ', error); -}) +rimraf.sync(homedir) -exec(`../../packages/cli/bin/budi init -d ${homedir}`) -exec(`../../packages/cli/bin/budi run -d ${homedir}`) \ No newline at end of file +execSync(`../../packages/cli/bin/budi init -d ${homedir}`) +execSync(`../../packages/cli/bin/budi run -d ${homedir}`) From e68ce5e87e42594e875611647ba6e02d97f1a5a6 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 11 Jun 2020 18:14:28 +0200 Subject: [PATCH 15/26] fix linting errors --- package.json | 3 +- packages/builder/cypress/plugins/index.js | 21 ---- packages/builder/cypress/setup.js | 4 +- packages/builder/cypress/support/commands.js | 107 ++++++++++--------- packages/builder/cypress/support/index.js | 2 +- packages/builder/package.json | 5 + yarn.lock | 9 +- 7 files changed, 74 insertions(+), 77 deletions(-) delete mode 100644 packages/builder/cypress/plugins/index.js diff --git a/package.json b/package.json index e4e4a3bd4e..8185d0bbb0 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "@rollup/plugin-json": "^4.0.2", "babel-eslint": "^10.0.3", "eslint": "^6.8.0", + "eslint-plugin-cypress": "^2.11.1", "eslint-plugin-prettier": "^3.1.2", "eslint-plugin-svelte3": "^2.7.3", "lerna": "3.14.1", @@ -31,4 +32,4 @@ "@material/icon-button": "4.0.0", "date-fns": "^2.10.0" } -} \ No newline at end of file +} diff --git a/packages/builder/cypress/plugins/index.js b/packages/builder/cypress/plugins/index.js deleted file mode 100644 index aa9918d215..0000000000 --- a/packages/builder/cypress/plugins/index.js +++ /dev/null @@ -1,21 +0,0 @@ -/// -// *********************************************************** -// 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) - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config -} diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index b737f3ef2e..aca5ed627f 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -3,8 +3,8 @@ // 2. Initialises using `.budibase-cypress` // 3. Runs the server using said folder -const rimraf = require("rimraf"); -const homedir = require('os').homedir() + '/.budibase-cypress'; +const rimraf = require("rimraf") +const homedir = require("os").homedir() + "/.budibase-cypress" const { execSync } = require("child_process") rimraf.sync(homedir) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index 8e8c31d798..ed19ba8233 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -25,76 +25,81 @@ // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) Cypress.Commands.add("createApp", (name, description) => { - cy.get('.banner-button') - .click() - .get('input[name="name"]') - .type(name).should('have.value', name) + cy.get(".banner-button") + .click() + .get('input[name="name"]') + .type(name) + .should("have.value", name) - cy.get('textarea[name="description"]') - .type(description).should('have.value', description) + cy.get('textarea[name="description"]') + .type(description) + .should("have.value", description) - cy.contains('Save').click() + cy.contains("Save").click() }) Cypress.Commands.add("createModel", (modelName, firstField, secondField) => { - // Enter model name - cy.get('[data-cy=Name]').click() - .type(modelName) + // Enter model name + cy.get("[data-cy=Name]") + .click() + .type(modelName) - // Add 'name' field - cy.get('[data-cy=add-new-model-field]').click() - cy.get('[data-cy=Name]').click() - .type(firstField) - cy.contains('Save').click() + // Add 'name' field + cy.get("[data-cy=add-new-model-field]").click() + cy.get("[data-cy=Name]") + .click() + .type(firstField) + cy.contains("Save").click() + // Add 'age' field + cy.get("[data-cy=add-new-model-field]").click() - // Add 'age' field - cy.get('[data-cy=add-new-model-field]').click() + cy.get("[data-cy=Name]") + .click() + .type(secondField) + cy.get("select").select("number") + cy.contains("Save").click() + cy.contains(secondField).should("exist") - cy.get('[data-cy=Name]').click() - .type(secondField) - cy.get('select').select('number') - cy.contains('Save').click() - cy.contains(secondField).should('exist') - - // Save model - cy.contains('Save').click() + // Save model + cy.contains("Save").click() }) Cypress.Commands.add("addRecord", (firstField, secondField) => { - cy.contains('Create new record') - .click() + cy.contains("Create new record").click() - cy.get('[data-cy=name-input]').click().type(firstField) - cy.get('[data-cy=age-input]').click().type(secondField) + cy.get("[data-cy=name-input]") + .click() + .type(firstField) + cy.get("[data-cy=age-input]") + .click() + .type(secondField) - // Save - cy.contains('Save').click() + // Save + cy.contains("Save").click() }) Cypress.Commands.add("createUser", (username, password, level) => { - // Create User - cy.get('.nav-group-header > .ri-add-line') - .click() + // Create User + cy.get(".nav-group-header > .ri-add-line").click() - cy.get('[data-cy=username]').type(username) - cy.get('[data-cy=password]').type(password) - cy.get('[data-cy=accessLevel]').select(level) + cy.get("[data-cy=username]").type(username) + cy.get("[data-cy=password]").type(password) + cy.get("[data-cy=accessLevel]").select(level) - // Save - cy.contains('Save').click() + // Save + cy.contains("Save").click() }) -Cypress.Commands.add("addHeadlineComponent", (text) => { - cy.get('.switcher > :nth-child(2)').click() +Cypress.Commands.add("addHeadlineComponent", text => { + cy.get(".switcher > :nth-child(2)").click() - cy.get('[data-cy=Text]').click() - cy.get('[data-cy=Headline]').click() - cy.get('.tabs > :nth-child(2)').click() - cy.get('input[type="text"]') - .type(text) - cy.contains('Design').click() + cy.get("[data-cy=Text]").click() + cy.get("[data-cy=Headline]").click() + cy.get(".tabs > :nth-child(2)").click() + cy.get('input[type="text"]').type(text) + cy.contains("Design").click() }) -Cypress.Commands.add("addButtonComponent", (text) => { - cy.get('.switcher > :nth-child(2)').click() +Cypress.Commands.add("addButtonComponent", () => { + cy.get(".switcher > :nth-child(2)").click() - cy.get('[data-cy=Button]').click() -}) \ No newline at end of file + cy.get("[data-cy=Button]").click() +}) diff --git a/packages/builder/cypress/support/index.js b/packages/builder/cypress/support/index.js index d68db96df2..a80764cb2c 100644 --- a/packages/builder/cypress/support/index.js +++ b/packages/builder/cypress/support/index.js @@ -14,7 +14,7 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import './commands' +import "./commands" // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/packages/builder/package.json b/packages/builder/package.json index 56ee5135e3..49331426b4 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -41,6 +41,11 @@ "/node_modules/(?!svelte).+\\.js$" ] }, + "eslintConfig": { + "extends": [ + "plugin:cypress/recommended" + ] + }, "dependencies": { "@beyonk/svelte-notifications": "^2.0.3", "@budibase/bbui": "^1.1.1", diff --git a/yarn.lock b/yarn.lock index bb8ac784f1..cd956d394d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1980,6 +1980,13 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +eslint-plugin-cypress@^2.11.1: + version "2.11.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.1.tgz#a945e2774b88211e2c706a059d431e262b5c2862" + integrity sha512-MxMYoReSO5+IZMGgpBZHHSx64zYPSPTpXDwsgW7ChlJTF/sA+obqRbHplxD6sBStE+g4Mi0LCLkG4t9liu//mQ== + dependencies: + globals "^11.12.0" + eslint-plugin-prettier@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba" @@ -2526,7 +2533,7 @@ glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^11.1.0: +globals@^11.1.0, globals@^11.12.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== From eb178f3fac40d22807c6d586164b62dd16ecd1bf Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 11 Jun 2020 18:15:29 +0200 Subject: [PATCH 16/26] update instructions in contributing --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac35a4277d..9d473198b9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -170,12 +170,14 @@ Follow from **Step 3. Install and Build** in the setup guide above. You should h #### End-to-end Tests -Budibase uses Cypress to run a number of E2E tests. To run the tests execute the following command: +Budibase uses Cypress to run a number of E2E tests. To run the tests execute the following command in the root folder: ``` yarn test:e2e ``` +Or if you are in the builder you can run `yarn cy:test`. + ### Other Useful Information From 2ecb03e7ce28e206f0362901909cb52fc2f5d0bd Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Thu, 11 Jun 2020 20:37:01 +0100 Subject: [PATCH 17/26] changed setup to require CLI modules directly --- packages/builder/cypress/setup.js | 12 ++++++++---- packages/cli/src/commands/init/initHandler.js | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index aca5ed627f..9682a07118 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -4,10 +4,14 @@ // 3. Runs the server using said folder const rimraf = require("rimraf") -const homedir = require("os").homedir() + "/.budibase-cypress" -const { execSync } = require("child_process") +const { join } = require("path") +const homedir = join(require("os").homedir(), ".budibase-cypress") +const init = require("../../cli/src/commands/init/initHandler") +const run = require("../../cli/src/commands/run/runHandler") rimraf.sync(homedir) -execSync(`../../packages/cli/bin/budi init -d ${homedir}`) -execSync(`../../packages/cli/bin/budi run -d ${homedir}`) +init({ dir: homedir }) +.then(() => { + run({ dir: homedir }) +}) diff --git a/packages/cli/src/commands/init/initHandler.js b/packages/cli/src/commands/init/initHandler.js index c0c4ad1b9e..3fe4134447 100644 --- a/packages/cli/src/commands/init/initHandler.js +++ b/packages/cli/src/commands/init/initHandler.js @@ -7,7 +7,7 @@ const Sqrl = require("squirrelly") const uuid = require("uuid") module.exports = opts => { - run(opts) + return run(opts) } const run = async opts => { From 5672caae691b6e1765fcb3a6aab348683be7cc27 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Mon, 15 Jun 2020 10:14:58 +0200 Subject: [PATCH 18/26] removes unused file --- config.js | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 config.js diff --git a/config.js b/config.js deleted file mode 100644 index 7bc75c9fb2..0000000000 --- a/config.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = () => ({ - datastore: "local", - datastoreConfig: { - rootPath: "./.data", - }, - keys: ["secret1", "secret2"], - port: 4001, - latestPackagesFolder: ".", - extraMasterPlugins: {}, - dev: true, - customizeMaster: appDefinition => appDefinition, - useAppRootPath: true, -}) From 318c7ecb3ba5e3d3dda67c9f41bc796bdb408298 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Mon, 15 Jun 2020 10:41:38 +0200 Subject: [PATCH 19/26] adds ignore pattern to jest config so that it doesn't try to run cypress tests as unit tests --- packages/builder/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/builder/package.json b/packages/builder/package.json index 49331426b4..8456f0bfda 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -39,6 +39,9 @@ }, "transformIgnorePatterns": [ "/node_modules/(?!svelte).+\\.js$" + ], + "modulePathIgnorePatterns": [ + "/cypress/" ] }, "eslintConfig": { From 48d60a7183b95d6cf1fd32b1ab050b09ea019374 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Sun, 21 Jun 2020 20:54:37 +0100 Subject: [PATCH 20/26] removed ADMIN_SECRET env var (no longer needed) --- packages/builder/cypress/plugins/index.js | 21 +++++++++++++++++++++ packages/builder/cypress/setup.js | 2 +- packages/server/.env.template | 3 --- packages/server/scripts/jestSetup.js | 1 - packages/server/src/environment.js | 1 - 5 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 packages/builder/cypress/plugins/index.js diff --git a/packages/builder/cypress/plugins/index.js b/packages/builder/cypress/plugins/index.js new file mode 100644 index 0000000000..aa9918d215 --- /dev/null +++ b/packages/builder/cypress/plugins/index.js @@ -0,0 +1,21 @@ +/// +// *********************************************************** +// 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) + +/** + * @type {Cypress.PluginConfig} + */ +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index 9682a07118..a6566237ce 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -11,7 +11,7 @@ const run = require("../../cli/src/commands/run/runHandler") rimraf.sync(homedir) -init({ dir: homedir }) +init({ dir: homedir, clientId: "cypress-test" }) .then(() => { run({ dir: homedir }) }) diff --git a/packages/server/.env.template b/packages/server/.env.template index 170d391520..f282d9c67f 100644 --- a/packages/server/.env.template +++ b/packages/server/.env.template @@ -5,9 +5,6 @@ COUCH_DB_URL={{couchDbUrl}} # identifies a client database - i.e. group of apps CLIENT_ID={{clientId}} -# Full access API key for server -ADMIN_SECRET={{adminSecret}} - # used to create cookie hashes JWT_SECRET={{cookieKey1}} diff --git a/packages/server/scripts/jestSetup.js b/packages/server/scripts/jestSetup.js index ab5bc83885..8fc7082554 100644 --- a/packages/server/scripts/jestSetup.js +++ b/packages/server/scripts/jestSetup.js @@ -4,5 +4,4 @@ process.env.NODE_ENV = "jest" process.env.JWT_SECRET = "test-jwtsecret" process.env.CLIENT_ID = "test-client-id" process.env.BUDIBASE_DIR = tmpdir("budibase-unittests") -process.env.ADMIN_SECRET = "test-admin-secret" process.env.LOG_LEVEL = "silent" diff --git a/packages/server/src/environment.js b/packages/server/src/environment.js index fdf8b9874a..9bab1ed1a0 100644 --- a/packages/server/src/environment.js +++ b/packages/server/src/environment.js @@ -3,7 +3,6 @@ module.exports = { NODE_ENV: process.env.NODE_ENV, JWT_SECRET: process.env.JWT_SECRET, BUDIBASE_DIR: process.env.BUDIBASE_DIR, - ADMIN_SECRET: process.env.ADMIN_SECRET, PORT: process.env.PORT, COUCH_DB_URL: process.env.COUCH_DB_URL, SALT_ROUNDS: process.env.SALT_ROUNDS, From c88f4d2541fb3352bc2be77d7272db64fcad7e7c Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Sun, 21 Jun 2020 21:21:24 +0100 Subject: [PATCH 21/26] removed debug message --- packages/cli/src/commands/run/runHandler.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cli/src/commands/run/runHandler.js b/packages/cli/src/commands/run/runHandler.js index 04b21a4ff0..e3f669cf53 100644 --- a/packages/cli/src/commands/run/runHandler.js +++ b/packages/cli/src/commands/run/runHandler.js @@ -5,7 +5,6 @@ module.exports = ({ dir }) => { dir = xPlatHomeDir(dir) process.env.BUDIBASE_DIR = resolve(dir) require("dotenv").config({ path: resolve(dir, ".env") }) - console.log("dotenv loaded") // dont make this a variable or top level require // ti will cause environment module to be loaded prematurely From a69fdbfc166b9c89bef369a2310fd2ad20c7fbe1 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Sun, 21 Jun 2020 21:26:53 +0100 Subject: [PATCH 22/26] cypress tests - run on windows --- packages/builder/cypress/setup.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index a6566237ce..4f20fec9ba 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -13,5 +13,8 @@ rimraf.sync(homedir) init({ dir: homedir, clientId: "cypress-test" }) .then(() => { + delete require.cache[require.resolve("../../server/src/environment")] run({ dir: homedir }) }) + + From fab583242548e8bf49befd075b83f46d008de550 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Sun, 21 Jun 2020 21:41:10 +0100 Subject: [PATCH 23/26] lint fix --- packages/builder/cypress/plugins/index.js | 1 + packages/builder/cypress/setup.js | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/builder/cypress/plugins/index.js b/packages/builder/cypress/plugins/index.js index aa9918d215..59b2bab6e4 100644 --- a/packages/builder/cypress/plugins/index.js +++ b/packages/builder/cypress/plugins/index.js @@ -15,6 +15,7 @@ /** * @type {Cypress.PluginConfig} */ +// eslint-disable-next-line no-unused-vars module.exports = (on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index 4f20fec9ba..80516471da 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -11,10 +11,7 @@ const run = require("../../cli/src/commands/run/runHandler") rimraf.sync(homedir) -init({ dir: homedir, clientId: "cypress-test" }) -.then(() => { +init({ dir: homedir, clientId: "cypress-test" }).then(() => { delete require.cache[require.resolve("../../server/src/environment")] run({ dir: homedir }) }) - - From 733dd9753c1579601843755752fd1f69b5e8dc7f Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Mon, 22 Jun 2020 10:53:17 +0100 Subject: [PATCH 24/26] cypress - retain "builder:token" cookie between tests --- packages/builder/cypress/support/cookies.js | 3 +++ packages/builder/cypress/support/index.js | 1 + 2 files changed, 4 insertions(+) create mode 100644 packages/builder/cypress/support/cookies.js diff --git a/packages/builder/cypress/support/cookies.js b/packages/builder/cypress/support/cookies.js new file mode 100644 index 0000000000..bfb470c57b --- /dev/null +++ b/packages/builder/cypress/support/cookies.js @@ -0,0 +1,3 @@ +Cypress.Cookies.defaults({ + whitelist: "builder:token", +}) diff --git a/packages/builder/cypress/support/index.js b/packages/builder/cypress/support/index.js index a80764cb2c..15c9d759fc 100644 --- a/packages/builder/cypress/support/index.js +++ b/packages/builder/cypress/support/index.js @@ -14,6 +14,7 @@ // *********************************************************** // Import commands.js using ES2015 syntax: +import "./cookies" import "./commands" // Alternatively you can use CommonJS syntax: From 243948bc931b4abbd736771d60f33b2f191e20be Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Mon, 22 Jun 2020 11:29:34 +0100 Subject: [PATCH 25/26] cypress - changed background test to font-size (so i dont have to figure out how to test the colour picker) --- .../cypress/integration/createComponents.spec.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/builder/cypress/integration/createComponents.spec.js b/packages/builder/cypress/integration/createComponents.spec.js index 299f6b8ad2..cedd8fefe1 100644 --- a/packages/builder/cypress/integration/createComponents.spec.js +++ b/packages/builder/cypress/integration/createComponents.spec.js @@ -20,13 +20,13 @@ context('Create Components', () => { getIframeBody().contains('An Amazing headline!') }) - it('change the background color of the headline', () => { - cy.contains('Background').click() - cy.get('input[name="background"]') - .type('rgb(102, 51, 153)') + it('change the font size of the headline', () => { + cy.contains('Typography').click() + cy.get('input[name="font-size"]') + .type('60px') cy.contains('Design').click() - getIframeBody().contains('An Amazing headline!').should('have.css', 'background-color', 'rgb(102, 51, 153)') + getIframeBody().contains('An Amazing headline!').should('have.css', 'font-size', '60px') }) }) From b7003e9a1896e81180283ab708c2ca04ae117260 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Mon, 22 Jun 2020 16:39:28 +0200 Subject: [PATCH 26/26] remove cookies set up in each test and rely on cookie default added before --- packages/builder/cypress/integration/createModel.spec.js | 1 - packages/builder/cypress/integration/createWorkflow.spec.js | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/builder/cypress/integration/createModel.spec.js b/packages/builder/cypress/integration/createModel.spec.js index 3d46316607..830f5e7a48 100644 --- a/packages/builder/cypress/integration/createModel.spec.js +++ b/packages/builder/cypress/integration/createModel.spec.js @@ -1,7 +1,6 @@ context('Create a Model', () => { before(() => { - Cypress.Cookies.preserveOnce('builder:token') cy.visit('localhost:4001/_builder') // https://on.cypress.io/type cy.createApp('Model App', 'Model App Description') diff --git a/packages/builder/cypress/integration/createWorkflow.spec.js b/packages/builder/cypress/integration/createWorkflow.spec.js index b4d83e228b..9188721988 100644 --- a/packages/builder/cypress/integration/createWorkflow.spec.js +++ b/packages/builder/cypress/integration/createWorkflow.spec.js @@ -1,7 +1,6 @@ context('Create a workflow', () => { before(() => { - Cypress.Cookies.preserveOnce('builder:token') cy.visit('localhost:4001/_builder') cy.createApp('Workflow Test App', 'This app is used to test that workflows do in fact work!')