diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f779bc0..61487f36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.90.20 +- Fixed Service Form from sending integer values as strings to API +- Added Cypress e2e testing (working on adding more) + # 0.90.19 - Fixed private Services from showing in API (/api/services and /api/services/{id}) - Removed unused code diff --git a/frontend/cypress.json b/frontend/cypress.json new file mode 100644 index 00000000..5b4b440c --- /dev/null +++ b/frontend/cypress.json @@ -0,0 +1,17 @@ +{ + "projectId": "bi8mhr", + "env": { + "DB_HOST": "localhost", + "DB_USER": "root", + "DB_DATABASE": "root", + "DB_PORT": "5432", + "DB_PASS": "password123", + "GO_ENV": "production" + }, + "baseUrl": "http://localhost:8888", + "chromeWebSecurity": false, + "defaultCommandTimeout": 5000, + "requestTimeout": 5000, + "watchForFileChanges": false, + "failOnStatusCode": false +} diff --git a/frontend/cypress/fixtures/example.json b/frontend/cypress/fixtures/example.json new file mode 100644 index 00000000..da18d935 --- /dev/null +++ b/frontend/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/frontend/cypress/integration/services_spec.js b/frontend/cypress/integration/services_spec.js new file mode 100644 index 00000000..d5216246 --- /dev/null +++ b/frontend/cypress/integration/services_spec.js @@ -0,0 +1,122 @@ +/// + +import "../support/commands" + +context('Services Tests', () => { + + + beforeEach(() => { + cy.restoreLocalStorageCache(); + }); + + afterEach(() => { + cy.saveLocalStorageCache(); + }); + + // it('should go to setup Statping with Postgres', () => { + // cy.visit('http://localhost:8080') + // cy.get('select[name=db_connection]').select('postgres') + // cy.get('input[name="db_host"]').clear().type(Cypress.env('DB_HOST')) + // cy.get('input[name="db_port"]').clear().type('5432') + // cy.get('input[name="db_user"]').clear().type(Cypress.env('DB_USER')) + // if (Cypress.env('TRAVIS')==="yes") { + // cy.get('input[name="db_password"]').clear() + // } else { + // cy.get('input[name="db_password"]').clear().type(Cypress.env('DB_PASS')) + // } + // cy.get('input[name="db_database"]').clear().type(Cypress.env('DB_DATABASE')) + // cy.get('input[name="project"]').clear().type('Demo Tester') + // cy.get('input[name="description"]').clear().type('This is a test from Crypress!') + // cy.get('input[name="domain"]').clear().type('http://localhost:8080') + // cy.get('input[name="username"]').clear().type('admin') + // cy.get('input[name="email"]').clear().type('info@domain.com') + // cy.get('input[name="password"]').clear().type('admin') + // cy.scrollTo('bottom') + // cy.get('#setup_button').click().wait(10000) + // cy.get('.header-title').should('contain', 'Demo Tester') + // cy.get('.header-desc').should('contain', 'This is a test from Crypress!') + // cy.scrollTo('bottom') + // cy.get('.service_li').should('have.length', 5) + // cy.get('.card').should('have.length', 5) + // }) + + it('should Login', () => { + cy.visit('/login') + cy.get('#username').clear().type('admin') + cy.get('#password').clear().type('admin') + cy.get('button[type="submit"]').click() + + cy.get('.navbar-brand').should('contain', 'Statping') + cy.getCookies() + + cy.getCookies().should('have.length', 1) + }) + + it('should goto services', () => { + cy.visit('/dashboard/services') + cy.get(':nth-child(1) > .card-body > .table > tbody > tr').should('have.length', 5) + cy.get('.sortable_groups > tr').should('have.length', 3) + }) + + it('should create new HTTP service', () => { + cy.visit('/dashboard/create_service') + cy.get(':nth-child(1) > .card-body > :nth-child(1) > .col-sm-8 > .form-control').clear().type('HTTP Service') + cy.get('#service_type').select('http') + cy.get('#service_url').clear().type('http://localhost:8888') + cy.get('#service_response_code').clear().type('200') + cy.get('#service_interval').clear().type('30') + cy.get(':nth-child(3) > .card-body > :nth-child(2) > .col-sm-8 > .form-control').clear().type('5') + cy.get('#permalink').clear().type('http_service') + + cy.get('#notify_after').clear().type('3') + + cy.get('button[type="submit"]').click() + }) + + it('should create new TCP service', () => { + cy.visit('/dashboard/create_service') + cy.get(':nth-child(1) > .card-body > :nth-child(1) > .col-sm-8 > .form-control').clear().type('TCP Service') + cy.get('#service_type').select('tcp') + cy.get('#service_url').clear().type('localhost') + cy.get('#service_port').clear().type('8888') + + cy.get('#service_interval').clear().type('30') + cy.get(':nth-child(3) > .card-body > :nth-child(2) > .col-sm-8 > .form-control').clear().type('5') + cy.get('#notify_after').clear().type('3') + + cy.get('#permalink').clear().type('tcp_service') + + cy.get('button[type="submit"]').click() + }) + + it('should create new UDP service', () => { + cy.visit('/dashboard/create_service') + cy.get(':nth-child(1) > .card-body > :nth-child(1) > .col-sm-8 > .form-control').clear().type('UDP Service') + cy.get('#service_type').select('udp') + cy.get('#service_url').clear().type('8.8.8.8') + cy.get('#service_port').clear().type('53') + + cy.get('#service_interval').clear().type('30') + cy.get(':nth-child(3) > .card-body > :nth-child(2) > .col-sm-8 > .form-control').clear().type('5') + cy.get('#notify_after').clear().type('3') + + cy.get('#permalink').clear().type('udp_service') + + cy.get('button[type="submit"]').click() + }) + + it('should create new ICMP service', () => { + cy.visit('/dashboard/create_service') + cy.get(':nth-child(1) > .card-body > :nth-child(1) > .col-sm-8 > .form-control').clear().type('ICMP Service') + cy.get('#service_type').select('icmp') + cy.get('#service_url').clear().type('8.8.8.8') + + cy.get('#service_interval').clear().type('30') + cy.get('#notify_after').clear().type('3') + + cy.get('#permalink').clear().type('icmp_service') + + cy.get('button[type="submit"]').click() + }) + +}) diff --git a/frontend/cypress/integration/setup_spec.js b/frontend/cypress/integration/setup_spec.js new file mode 100644 index 00000000..eb20312a --- /dev/null +++ b/frontend/cypress/integration/setup_spec.js @@ -0,0 +1,49 @@ +/// + +context('Setup Process', () => { + + // it('should go to setup Statping with Postgres', () => { + // cy.visit('http://localhost:8080') + // cy.get('select[name=db_connection]').select('postgres') + // cy.get('input[name="db_host"]').clear().type(Cypress.env('DB_HOST')) + // cy.get('input[name="db_port"]').clear().type('5432') + // cy.get('input[name="db_user"]').clear().type(Cypress.env('DB_USER')) + // if (Cypress.env('TRAVIS')==="yes") { + // cy.get('input[name="db_password"]').clear() + // } else { + // cy.get('input[name="db_password"]').clear().type(Cypress.env('DB_PASS')) + // } + // cy.get('input[name="db_database"]').clear().type(Cypress.env('DB_DATABASE')) + // cy.get('input[name="project"]').clear().type('Demo Tester') + // cy.get('input[name="description"]').clear().type('This is a test from Crypress!') + // cy.get('input[name="domain"]').clear().type('http://localhost:8080') + // cy.get('input[name="username"]').clear().type('admin') + // cy.get('input[name="email"]').clear().type('info@domain.com') + // cy.get('input[name="password"]').clear().type('admin') + // cy.scrollTo('bottom') + // cy.get('#setup_button').click().wait(10000) + // cy.get('.header-title').should('contain', 'Demo Tester') + // cy.get('.header-desc').should('contain', 'This is a test from Crypress!') + // cy.scrollTo('bottom') + // cy.get('.service_li').should('have.length', 5) + // cy.get('.card').should('have.length', 5) + // }) + + it('should setup Statping with SQLite', () => { + cy.visit('/setup', {failOnStatusCode: false}) + cy.get('#db_connection').select('sqlite') + cy.get('#project').clear().type('Demo Tester') + cy.get('#description').clear().type('This is a test from Crypress!') + cy.get('#domain').clear().type('http://localhost:8080') + cy.get('#username').clear().type('admin') + cy.get('#password').clear().type('admin') + cy.get('#password_confirm').clear().type('admin') + cy.get('button[type="submit"]').click() + + cy.get('.pt-4').should('contain', 'Demo Tester') + cy.get('.mb-5').should('contain', 'This is a test from Crypress!') + cy.get('.list-group').should('have.length', 5) + cy.get('.card').should('have.length', 5) + }) + +}) diff --git a/frontend/cypress/integration/users_spec.js b/frontend/cypress/integration/users_spec.js new file mode 100644 index 00000000..d5bde10b --- /dev/null +++ b/frontend/cypress/integration/users_spec.js @@ -0,0 +1,76 @@ +/// + +import "../support/commands" + +context('Users Tests', () => { + + + beforeEach(() => { + cy.restoreLocalStorageCache(); + }); + + afterEach(() => { + cy.saveLocalStorageCache(); + }); + + // it('should go to setup Statping with Postgres', () => { + // cy.visit('http://localhost:8080') + // cy.get('select[name=db_connection]').select('postgres') + // cy.get('input[name="db_host"]').clear().type(Cypress.env('DB_HOST')) + // cy.get('input[name="db_port"]').clear().type('5432') + // cy.get('input[name="db_user"]').clear().type(Cypress.env('DB_USER')) + // if (Cypress.env('TRAVIS')==="yes") { + // cy.get('input[name="db_password"]').clear() + // } else { + // cy.get('input[name="db_password"]').clear().type(Cypress.env('DB_PASS')) + // } + // cy.get('input[name="db_database"]').clear().type(Cypress.env('DB_DATABASE')) + // cy.get('input[name="project"]').clear().type('Demo Tester') + // cy.get('input[name="description"]').clear().type('This is a test from Crypress!') + // cy.get('input[name="domain"]').clear().type('http://localhost:8080') + // cy.get('input[name="username"]').clear().type('admin') + // cy.get('input[name="email"]').clear().type('info@domain.com') + // cy.get('input[name="password"]').clear().type('admin') + // cy.scrollTo('bottom') + // cy.get('#setup_button').click().wait(10000) + // cy.get('.header-title').should('contain', 'Demo Tester') + // cy.get('.header-desc').should('contain', 'This is a test from Crypress!') + // cy.scrollTo('bottom') + // cy.get('.service_li').should('have.length', 5) + // cy.get('.card').should('have.length', 5) + // }) + + it('should Login', () => { + cy.visit('/login') + cy.get('#username').clear().type('admin') + cy.get('#password').clear().type('admin') + cy.get('button[type="submit"]').click() + + cy.get('.navbar-brand').should('contain', 'Statping') + cy.getCookies() + + cy.getCookies().should('have.length', 1) + }) + + it('should goto users', () => { + cy.visit('/dashboard/users') + cy.get('#users_table > tr >').should('have.length', 1) + }) + + it('should create new User', () => { + cy.visit('/dashboard/users') + cy.get('#username').clear().type('admin2') + cy.get('#email').clear().type('info@admin.com') + cy.get('#password').clear().type('password123') + cy.get('#password_confirm').clear().type('password123') + + cy.get('button[type="submit"]').click() + }) + + it('should confirm new user', () => { + cy.visit('/dashboard/users') + cy.get('#users_table > tr >').should('have.length', 2) + }) + + +}) diff --git a/frontend/cypress/plugins/index.js b/frontend/cypress/plugins/index.js new file mode 100644 index 00000000..aa9918d2 --- /dev/null +++ b/frontend/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/frontend/cypress/support/commands.js b/frontend/cypress/support/commands.js new file mode 100644 index 00000000..59dcba0a --- /dev/null +++ b/frontend/cypress/support/commands.js @@ -0,0 +1,48 @@ +// *********************************************** +// 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) => { ... }) + +Cypress.Cookies.defaults({ + whitelist: "statping_auth" +}) + +let LOCAL_STORAGE_MEMORY = {}; + +Cypress.Commands.add("saveLocalStorageCache", () => { + Object.keys(localStorage).forEach(key => { + LOCAL_STORAGE_MEMORY[key] = localStorage[key]; + }); +}); + +Cypress.Commands.add("restoreLocalStorageCache", () => { + Object.keys(LOCAL_STORAGE_MEMORY).forEach(key => { + localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]); + }); +}); + +Cypress.Commands.add("clearLocalStorageCache", () => { + localStorage.clear(); + LOCAL_STORAGE_MEMORY = {}; +}); diff --git a/frontend/cypress/support/index.js b/frontend/cypress/support/index.js new file mode 100644 index 00000000..d68db96d --- /dev/null +++ b/frontend/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/frontend/package.json b/frontend/package.json index 4f76600b..590d9510 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,7 +8,9 @@ "dev": "cross-env NODE_ENV=development webpack-dev-server --host 0.0.0.0 --port 8888 --progress", "lint": "vue-cli-service lint", "test": "cross-env NODE_ENV=development mochapack --webpack-config webpack.config.js --require test/setup.js test/**/*.spec.js", - "backend-test": "newman run -e ../dev/postman_environment.json --delay-request 500 ../dev/postman.json" + "backend-test": "newman run -e ../dev/postman_environment.json --delay-request 500 ../dev/postman.json", + "cypress": "cypress open", + "e2e": "cypress run --record --key" }, "dependencies": { "@fortawesome/fontawesome-free-solid": "^5.1.0-3", @@ -37,14 +39,14 @@ "vuex": "^3.1.2" }, "devDependencies": { - "@babel/core": "~7.2", + "@babel/core": "^7.9.0", "@babel/plugin-proposal-class-properties": "~7.3", "@babel/plugin-proposal-decorators": "~7.3", "@babel/plugin-proposal-json-strings": "~7.2", "@babel/plugin-syntax-dynamic-import": "~7.2", "@babel/plugin-syntax-import-meta": "~7.2", "@babel/polyfill": "~7.2", - "@babel/preset-env": "~7.8.3", + "@babel/preset-env": "^7.9.0", "@vue/babel-preset-app": "^4.1.2", "@vue/cli-plugin-babel": "^4.1.0", "@vue/cli-service": "^4.2.3", @@ -55,6 +57,7 @@ "compression-webpack-plugin": "~2.0", "cross-env": "^7.0.2", "css-loader": "~2.1", + "cypress": "^4.3.0", "eslint": "~5.16", "eslint-config-standard": "~10.2", "eslint-friendly-formatter": "~3.0", diff --git a/frontend/src/forms/Service.vue b/frontend/src/forms/Service.vue index 8aa81ff0..fc345eef 100644 --- a/frontend/src/forms/Service.vue +++ b/frontend/src/forms/Service.vue @@ -237,6 +237,10 @@ delete s.latency delete s.online_24_hours s.check_interval = parseInt(s.check_interval) + s.timeout = parseInt(s.timeout) + s.port = parseInt(s.port) + s.notify_after = parseInt(s.notify_after) + s.expected_status = parseInt(s.expected_status) window.console.log(s) diff --git a/frontend/src/forms/Setup.vue b/frontend/src/forms/Setup.vue index 470b7018..c374d988 100644 --- a/frontend/src/forms/Setup.vue +++ b/frontend/src/forms/Setup.vue @@ -11,31 +11,31 @@