Commit 82bbc657 authored by Alessandro Curci's avatar Alessandro Curci
Browse files

dropped protractor in favor of cypress

implemented first tests (login+person)
parent 0a626feb
......@@ -39,3 +39,4 @@ src/img/Thumbs.db:encryptable
src/img/vendors/
/staging_build_n_sync.sh
!/cypress.env.json
......@@ -70,6 +70,19 @@
"browserTarget": "OPDM:build"
}
},
"e2e": {
"builder": "@cypress/schematic:cypress",
"options": {
"devServerTarget": "OPDM:serve",
"watch": true,
"headless": false
},
"configurations": {
"production": {
"devServerTarget": "OPDM:serve:production"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
......@@ -82,7 +95,6 @@
"node_modules/pace-js/pace.js"
],
"styles": [
"node_modules/simple-line-icons/css/simple-line-icons.css",
"src/scss/style.scss"
],
"assets": [
......@@ -95,32 +107,28 @@
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
"src/tsconfig.spec.json",
"cypress/tsconfig.json"
],
"exclude": []
}
}
}
},
"OPDM-e2e": {
"root": "",
"sourceRoot": "",
"projectType": "application",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
},
"cypress-run": {
"builder": "@cypress/schematic:cypress",
"options": {
"protractorConfig": "./protractor.conf.js",
"devServerTarget": "OPDM:serve"
},
"configurations": {
"production": {
"devServerTarget": "OPDM:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"cypress-open": {
"builder": "@cypress/schematic:cypress",
"options": {
"tsConfig": [
"e2e/tsconfig.e2e.json"
],
"exclude": []
"watch": true,
"headless": false
}
}
}
......
{
"username": "openpolis",
"password": "ancient.carbine.ecumenic.boston",
"auth_url": "https://staging.service.opdm.openpolis.io/api-token-auth/"
}
{
"integrationFolder": "cypress/integration",
"supportFile": "cypress/support/index.ts",
"videosFolder": "cypress/videos",
"screenshotsFolder": "cypress/screenshots",
"pluginsFile": "cypress/plugins/index.ts",
"fixturesFolder": "cypress/fixtures",
"baseUrl": "http://localhost:4200",
"experimentalStudio": true,
"viewportWidth": 1366,
"viewportHeight": 800
}
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
describe('Login/Logout test', () => {
it('Login pages exists', () => {
cy.visit('/');
cy.contains('Inserisci le tue credenziali');
});
it('Rejects login with bad credentials', () => {
cy.visit('/');
cy.get('#username').type('123');
cy.get('#password').type('123');
cy.get('#login-button').click();
cy.contains('.toast-title', '401');
});
it('Signs in with good credentials', () => {
cy.visit('/');
cy.get('#username').type(Cypress.env('username'));
cy.get('#password').type(Cypress.env('password'));
cy.get('#login-button').click().should(() => {
expect(localStorage.getItem('OPDM_currentUser')).to.contains('{"token":');
});
cy.location().should((loc) => {
expect(loc.hash).to.eq('#/dashboard')
});
});
it('Logs out correctly', () => {
cy.get('.app-header .icon-user').click();
cy.get('.app-header .fa-sign-out-alt').click().should(() => {
expect(localStorage.getItem('OPDM_currentUser')).to.be.null;
});
cy.location().should((loc) => {
expect(loc.hash).to.eq('#/pages/login')
});
});
});
describe('Person test', () => {
beforeEach(() => {
cy.login()
})
it('Navigates to Persona page', () => {
cy.visit('/#/persons');
});
it('Filters results', () => {
cy.visit('/#/persons');
cy.get('[data-cy="search"]').clear();
cy.get('[data-cy="search"]').type('Ettore Di Cesare');
cy.get('.ngx-datatable :nth-child(4) > .datatable-body-cell-label').contains('Ettore');
cy.get('.ngx-datatable :nth-child(5) > .datatable-body-cell-label').contains('Di Cesare');
})
it('Creates new person', () => {
cy.visit('/#/persons/edit');
cy.get('[data-cy="given_name"]').clear();
cy.get('[data-cy="given_name"]').type('NuovaPersonaNome');
cy.get('[data-cy="family_name"]').clear();
cy.get('[data-cy="family_name"]').type('NuovaPersonaCognome');
cy.get('[data-cy="birth_location_area"] > .ng-select-container > .ng-value-container > .ng-input > input').clear();
cy.get('[data-cy="birth_location_area"] > .ng-select-container > .ng-value-container > .ng-input > input').type('Roma');
cy.get('.ng-select-bottom .highlighted').contains(/^Roma$/).click();
cy.get('[data-cy="birth_date"]').clear();
cy.get('[data-cy="birth_date"]').type('2021-11-21');
cy.get(':nth-child(1) > .custom-control-label').click();
cy.get(':nth-child(1) > [data-cy="gender"]').check();
cy.get('#main-save-button').click();
});
it('Checks person similarity', () => {
cy.visit('/#/persons/edit');
cy.get('[data-cy="given_name"]').clear();
cy.get('[data-cy="given_name"]').type('NuovaPersonaNom');
cy.get('[data-cy="family_name"]').clear();
cy.get('[data-cy="family_name"]').type('NuovaPersonaCognom');
cy.get('[data-cy="Similarità trovate"]').contains('NuovaPersonaNom');
cy.get('[data-cy="Similarità trovate"]').contains('NuovaPersonaCognom');
});
it('Deletes person', () => {
cy.visit('/#/persons');
cy.get('[data-cy="search"]').clear();
cy.get('[data-cy="search"]').type('NuovaPersonaNom NuovaPersonaCognom');
cy.get('.ngx-datatable .datatable-body-cell-label').contains('NuovaPersonaNom');
cy.get('.ngx-datatable .datatable-body-cell-label')
.contains('NuovaPersonaNom')
.parents('.datatable-row-group')
.find('app-action-item-delete span[title="Elimina"]').click();
cy.get('#item-delete-confirm-button').click();
})
});
// 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) => {}
// ***********************************************
// This example namespace declaration will help
// with Intellisense and code completion in your
// IDE or Text Editor.
// ***********************************************
// declare namespace Cypress {
// interface Chainable<Subject = any> {
// 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) => { ... })
// @ts-ignore
Cypress.Commands.add('login', () => {
cy.request({
method: 'POST',
url: Cypress.env('auth_url'),
body: {
username: Cypress.env('username'),
password: Cypress.env('password'),
}
})
.its('body')
.then(body => {
cy.window().then(win => win.localStorage.setItem('OPDM_currentUser', JSON.stringify(body)))
})
});
// ***********************************************************
// 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';
{
"extends": "../tsconfig.json",
"include": ["**/*.ts"],
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types":[
"jasmine",
"node"
]
"sourceMap": false,
"types": ["cypress"]
}
}
import { CoreUIPage } from './app.po';
describe('core-ui App', function() {
let page: CoreUIPage;
beforeEach(() => {
page = new CoreUIPage();
});
it('should display message saying app works', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('app works!');
});
});
import { browser, element, by } from 'protractor/globals';
export class CoreUIPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}
This diff is collapsed.
......@@ -14,7 +14,9 @@
"lint": "ng lint",
"e2e": "ng e2e",
"bundle-report": "webpack-bundle-analyzer dist/stats.json",
"compodoc": "./node_modules/.bin/compodoc -p src/tsconfig.app.json"
"compodoc": "./node_modules/.bin/compodoc -p src/tsconfig.app.json",
"cypress:open": "cypress open",
"cypress:run": "cypress run"
},
"private": true,
"dependencies": {
......@@ -62,6 +64,7 @@
"@angular/cli": "11.2.18",
"@angular/compiler-cli": "11.2.14",
"@angular/language-service": "11.2.14",
"@cypress/schematic": "^1.6.0",
"@fortawesome/fontawesome-pro": "5.15.4",
"@types/jasmine": "~3.6.0",
"@types/jasminewd2": "2.0.10",
......@@ -69,6 +72,7 @@
"@types/lodash-es": "4.17.5",
"@types/node": "^12.11.1",
"codelyzer": "^6.0.0",
"cypress": "latest",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~6.3.12",
......@@ -77,7 +81,6 @@
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"protractor": "~7.0.0",
"ts-node": "8.0.3",
"tslint": "~6.1.0",
"typescript": "4.0.7",
......
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
beforeLaunch: function() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
},
onPrepare() {
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
......@@ -8,6 +8,10 @@ import {ColumnsTPL, FormTPL, ListTPL, ListTPLOptions} from './app.config.interfa
import createNumberMask from 'text-mask-addons/dist/createNumberMask';
import emailMask from 'text-mask-addons/dist/emailMask';
import set from 'lodash-es/set';
import get from 'lodash-es/get';
import { environment } from 'environments/environment';
......@@ -609,6 +613,29 @@ export class AppConfig {
// @formatter:on
/* tslint:enable */
/* --------------------------------------------------------------------------------------------------------------------
*
* HELPER METHODS
*
* -------------------------------------------------------------------------------------------------------------------- */
public fieldsAddCyKeyAttribute(fields) {
fields.forEach((F) => {
const label = get(F, 'templateOptions.label');
if (label) {
console.log('label', label);
set(F, 'templateOptions.attributes.data-cy', label)
}
if (Array.isArray(F.fieldGroup)) {
F.fieldGroup.forEach((FG) => {
if (FG.key) {
set(FG, 'templateOptions.attributes.data-cy', FG.key);
}
});
}
})
};
/* --------------------------------------------------------------------------------------------------------------------
*
* LISTS DEFINITION
......@@ -1075,6 +1102,9 @@ export class AppConfig {
// @formatter:on
/* tslint:enable */
if (this.debug) {
this.fieldsAddCyKeyAttribute(filters);
}
return {title, columns, filters, actions, options, prefetch};
}
......@@ -1138,7 +1168,7 @@ export class AppConfig {
columns: [
{name:'Punti' , prop:'score' , head:'hdr', cell:'sep_num' , resize:0, sort:0, drag:0, flexGrow:0, width: 65, canAutoResize:0 },
{name:'G' , prop:'gender' , head:'hdr', cell:'gender' , resize:0, sort:0, drag:1, flexGrow:1, width: 40, canAutoResize:0},
{name:'Persona' , prop:'' , head:'hdr', cell:'personlink' , resize:1, sort:0, drag:0, flexGrow:9, },
{name:'Persona' , prop:'' , head:'hdr', cell:'personlink' , resize:1, sort:0, drag:0, flexGrow:9, },
{name:'Incarichi', prop:'memberships', head:'hdr', cell:'memberships', resize:1, sort:0, drag:0, flexGrow:9, },
]
},
......@@ -1404,6 +1434,9 @@ export class AppConfig {
// @formatter:on
/* tslint:enable */
if (this.debug) {
this.fieldsAddCyKeyAttribute(fields);
}
return {title, fields, options};
}
}
......@@ -126,7 +126,7 @@ import {DownloadCsvService} from './_services/download-csv.service';
AppComponent,
...APP_CONTAINERS,
...APP_COMPONENTS,
...APP_DIRECTIVES,
...APP_DIRECTIVES
],
providers: [
AppConfig,
......
......@@ -39,8 +39,8 @@ import {APICommonService} from '../../../../_services/api-common.service';
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="decline()">Annulla</button>
<button type="button" class="btn btn-danger" (click)="confirm()">Conferma</button>
<button id="item-delete-decline-button" type="button" class="btn btn-secondary" (click)="decline()">Annulla</button>
<button id="item-delete-confirm-button" type="button" class="btn btn-danger" (click)="confirm()">Conferma</button>
</div>
</div>
</ng-template>
......
......@@ -23,7 +23,7 @@ import {APISerializer} from '../../../serializers/generic';
>
</formly-form>
<div class="clearfix mb-4">
<button type="button" class="btn btn-primary float-right"
<button type="button" class="btn btn-primary float-right panel-save-button"
(click)="form.valid && form.dirty && onSubmit(form.value)"
[disabled]="!form.valid || !form.dirty"
[ladda]="isSubmiting">Salva
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment