diff --git a/angular.json b/angular.json index 694e13e9cf..d79ff946e3 100644 --- a/angular.json +++ b/angular.json @@ -166,12 +166,44 @@ "options": { "tsConfig": [ "src/tsconfig.app.json", - "src/tsconfig.spec.json" + "src/tsconfig.spec.json", + "cypress/tsconfig.json" ], "exclude": [ "**/node_modules/**" ] } + }, + "cypress-run": { + "builder": "@cypress/schematic:cypress", + "options": { + "devServerTarget": "mifosx-web-app:serve" + }, + "configurations": { + "production": { + "devServerTarget": "mifosx-web-app:serve:production" + } + } + }, + "cypress-open": { + "builder": "@cypress/schematic:cypress", + "options": { + "watch": true, + "headless": false + } + }, + "e2e": { + "builder": "@cypress/schematic:cypress", + "options": { + "devServerTarget": "mifosx-web-app:serve", + "watch": true, + "headless": false + }, + "configurations": { + "production": { + "devServerTarget": "mifosx-web-app:serve:production" + } + } } } }, @@ -180,14 +212,15 @@ "projectType": "application", "architect": { "e2e": { - "builder": "@angular-devkit/build-angular:protractor", + "builder": "@cypress/schematic:cypress", "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "mifosx-web-app:serve" + "devServerTarget": "mifosx-web-app-e2e:serve", + "watch": true, + "headless": false }, "configurations": { "production": { - "devServerTarget": "mifosx-web-app:serve:production" + "devServerTarget": "mifosx-web-app-e2e:serve:production" } } }, @@ -195,15 +228,35 @@ "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": [ - "e2e/tsconfig.e2e.json" + "e2e/cypress/tsconfig.json" ], "exclude": [ "**/node_modules/**" ] } + }, + "cypress-run": { + "builder": "@cypress/schematic:cypress", + "options": { + "devServerTarget": "mifosx-web-app-e2e:serve", + "configFile": "e2e/cypress.json" + }, + "configurations": { + "production": { + "devServerTarget": "mifosx-web-app-e2e:serve:production" + } + } + }, + "cypress-open": { + "builder": "@cypress/schematic:cypress", + "options": { + "watch": true, + "headless": false, + "configFile": "e2e/cypress.json" + } } } } }, "defaultProject": "mifosx-web-app" -} +} \ No newline at end of file diff --git a/cypress.config.ts b/cypress.config.ts new file mode 100644 index 0000000000..a3b79a6806 --- /dev/null +++ b/cypress.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + videosFolder: 'cypress/videos', + screenshotsFolder: 'cypress/screenshots', + fixturesFolder: 'cypress/fixtures', + e2e: { + // We've imported your old cypress plugins here. + // You may want to clean this up later by importing these. + setupNodeEvents(on, config) { + return require('./cypress/plugins/index.ts')(on, config) + }, + baseUrl: 'http://localhost:4200', + }, +}) diff --git a/cypress/e2e/spec.cy.ts b/cypress/e2e/spec.cy.ts new file mode 100644 index 0000000000..61fc792a5a --- /dev/null +++ b/cypress/e2e/spec.cy.ts @@ -0,0 +1,26 @@ +describe('Login Page', () => { + it('Visits the initial web page', () => { + cy.visit('/'); + cy.url().should('includes', 'login'); + cy.get('#mat-input-0').should ('be.visible'); + cy.get('#mat-input-1').should ('be.visible'); + cy.contains('Login'); + cy.contains('Remember me'); + }); + + it('Login', () => { + cy.visit('/'); + cy.get('#mat-input-0').type('mifos'); + cy.get('#mat-input-1').type('password'); + cy.get('.mat-raised-button').click(); + cy.contains('Home'); + }); + + it('Logout', () => { + cy.visit('/#/home'); + cy.get('.img-button').click(); + cy.get('#logout').click(); + cy.contains('Username'); + }); + +}); diff --git a/cypress/plugins/index.ts b/cypress/plugins/index.ts new file mode 100644 index 0000000000..edf74d3186 --- /dev/null +++ b/cypress/plugins/index.ts @@ -0,0 +1,3 @@ +// Plugins enable you to tap into, modify, or extend the internal behavior of Cypress +// For more info, visit https://on.cypress.io/plugins-api +module.exports = (on, config) => {}; diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts new file mode 100644 index 0000000000..af1f44a0fc --- /dev/null +++ b/cypress/support/commands.ts @@ -0,0 +1,43 @@ +// *********************************************** +// This example namespace declaration will help +// with Intellisense and code completion in your +// IDE or Text Editor. +// *********************************************** +// declare namespace Cypress { +// interface Chainable { +// customCommand(param: any): typeof customCommand; +// } +// } +// +// function customCommand(param: any): void { +// console.warn(param); +// } +// +// NOTE: You can use it like so: +// Cypress.Commands.add('customCommand', customCommand); +// +// *********************************************** +// 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/cypress/support/e2e.ts b/cypress/support/e2e.ts new file mode 100644 index 0000000000..ac293b6165 --- /dev/null +++ b/cypress/support/e2e.ts @@ -0,0 +1,17 @@ +// *********************************************************** +// 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 +// *********************************************************** + +// When a command from ./commands is ready to use, import with `import './commands'` syntax +// import './commands'; diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json new file mode 100644 index 0000000000..79d78d7ec9 --- /dev/null +++ b/cypress/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "include": ["**/*.ts"], + "compilerOptions": { + "sourceMap": false, + "types": ["cypress"] + } +} diff --git a/e2e/cypress.json b/e2e/cypress.json new file mode 100644 index 0000000000..93a9fab39e --- /dev/null +++ b/e2e/cypress.json @@ -0,0 +1,9 @@ +{ + "integrationFolder": "e2e/cypress/integration", + "supportFile": "e2e/cypress/support/index.ts", + "videosFolder": "e2e/cypress/videos", + "screenshotsFolder": "e2e/cypress/screenshots", + "pluginsFile": "e2e/cypress/plugins/index.ts", + "fixturesFolder": "e2e/cypress/fixtures", + "baseUrl": "http://localhost:4200" +} \ No newline at end of file diff --git a/e2e/cypress/integration/spec.ts b/e2e/cypress/integration/spec.ts new file mode 100644 index 0000000000..9b941a18a8 --- /dev/null +++ b/e2e/cypress/integration/spec.ts @@ -0,0 +1,7 @@ +describe('My First Test', () => { + it('Visits the initial project page', () => { + cy.visit('/'); + cy.contains('Welcome'); + cy.contains('sandbox app is running!'); + }); +}); diff --git a/e2e/cypress/plugins/index.ts b/e2e/cypress/plugins/index.ts new file mode 100644 index 0000000000..edf74d3186 --- /dev/null +++ b/e2e/cypress/plugins/index.ts @@ -0,0 +1,3 @@ +// Plugins enable you to tap into, modify, or extend the internal behavior of Cypress +// For more info, visit https://on.cypress.io/plugins-api +module.exports = (on, config) => {}; diff --git a/e2e/cypress/support/commands.ts b/e2e/cypress/support/commands.ts new file mode 100644 index 0000000000..af1f44a0fc --- /dev/null +++ b/e2e/cypress/support/commands.ts @@ -0,0 +1,43 @@ +// *********************************************** +// This example namespace declaration will help +// with Intellisense and code completion in your +// IDE or Text Editor. +// *********************************************** +// declare namespace Cypress { +// interface Chainable { +// customCommand(param: any): typeof customCommand; +// } +// } +// +// function customCommand(param: any): void { +// console.warn(param); +// } +// +// NOTE: You can use it like so: +// Cypress.Commands.add('customCommand', customCommand); +// +// *********************************************** +// 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/e2e/cypress/support/index.ts b/e2e/cypress/support/index.ts new file mode 100644 index 0000000000..ac293b6165 --- /dev/null +++ b/e2e/cypress/support/index.ts @@ -0,0 +1,17 @@ +// *********************************************************** +// 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 +// *********************************************************** + +// When a command from ./commands is ready to use, import with `import './commands'` syntax +// import './commands'; diff --git a/e2e/cypress/tsconfig.json b/e2e/cypress/tsconfig.json new file mode 100644 index 0000000000..0c793608f8 --- /dev/null +++ b/e2e/cypress/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "include": ["**/*.ts"], + "compilerOptions": { + "sourceMap": false, + "types": ["cypress"] + } +} diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json new file mode 100644 index 0000000000..6c10a7a2e6 --- /dev/null +++ b/e2e/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.json", + "include": ["**/*.ts"], + "compilerOptions": { + "sourceMap": false, + "types": ["cypress"] + } +} + \ No newline at end of file diff --git a/package.json b/package.json index 4fccd0f4ed..af7e9ca8b5 100644 --- a/package.json +++ b/package.json @@ -19,11 +19,13 @@ "lint": "ng lint && stylelint \"src/**/*.scss\" --syntax scss && htmlhint \"src\" --config .htmlhintrc", "test": "npm run env -s && ng test", "test:ci": "npm run env -s && npm run lint -s && ng test --code-coverage --watch=false", - "e2e": "npm run env -s && ng e2e", + "e2e": "ng e2e", "translations:extract": "ngx-translate-extract --input ./src --output ./src/translations/template.json --format=json --clean -sort --marker extract", "docs": "hads ./docs -o", "env": "node version.js", - "postinstall": "node version.js && ngcc" + "postinstall": "node version.js && ngcc", + "cypress:open": "cypress open", + "cypress:run": "cypress run" }, "dependencies": { "@angular-devkit/schematics": "^14.0.4", @@ -63,12 +65,14 @@ "@angular/compiler-cli": "12.2.16", "@angular/language-service": "12.2.16", "@biesbjerg/ngx-translate-extract": "^7.0.4", + "@cypress/schematic": "^1.7.0", "@ngx-rocket/scripts": "3.0.3", "@types/jasmine": "3.3.13", "@types/jasminewd2": "2.0.6", "@types/lodash": "4.14.132", "@types/node": "12.11.1", "codelyzer": "6.0.0", + "cypress": "^10.7.0", "git-describe": "^4.1.1", "hads": "^3.0.3", "htmlhint": "0.11.0",