This commit is contained in:
Vicente Falco 2018-01-17 14:58:48 +01:00
commit df03a41a68
61 changed files with 1156 additions and 512 deletions

24
Jenkinsfile vendored
View File

@ -43,11 +43,35 @@ node
stage ("Stopping/Removing Docker") stage ("Stopping/Removing Docker")
{ {
<<<<<<< HEAD
=======
<<<<<<< HEAD
step{
env.TAG = env.BUILD_NUMBER - 1;
sh "docker-compose down --rmi 'all'"
=======
environment {
env.BUILD_TAG = env.BUILD_NUMBER - 1;
>>>>>>> 1acfdf5950d33f4bf972dc2830e05d2f2b1ba99a
}
>>>>>>> e47138eda088c8d307f58d42cc34cbde7295946f
sh "docker-compose down --rmi 'all'" sh "docker-compose down --rmi 'all'"
} }
stage ("Generar dockers") stage ("Generar dockers")
{ {
<<<<<<< HEAD
=======
<<<<<<< HEAD
step{
env.TAG = env.BUILD_NUMBER + 1;
sh "docker-compose up -d --build"
=======
environment {
env.BUILD_TAG = env.BUILD_NUMBER;
>>>>>>> 1acfdf5950d33f4bf972dc2830e05d2f2b1ba99a
}
>>>>>>> e47138eda088c8d307f58d42cc34cbde7295946f
sh "docker-compose up -d --build" sh "docker-compose up -d --build"
} }
} }

View File

@ -1,53 +1,67 @@
# Project Title # Project Title
One Paragraph of project description goes here Salix is an Enterprise resource planning (ERP) integrated management of core business processes, in real-time and mediated by software and technology developed with the stack listed below.
Salix is also the scientific name of a beautifull tree! :)
### Prerequisites ### Prerequisites
For testing purposes you will need to install globally the following items: You will need to install globally the following items:
npm install -g karma $ npm install -g karma
npm install -g karma-cli $ npm install -g karma-cli
$ npm install -g gulp
## Getting Started // ### Installing $ npm install -g webpack
$ npm install -g nodemon
Pull from repo.
install nodejs v6 or above.
install nginx globally. install nginx globally.
Ask a senior dev for the datasources.development.json files required to run the project. ## Getting Started // ### Installing
Pull from repository.
install nodejs v6.
Ask a senior developer for the datasources.development.json files required to run the project.
on root run: on root run:
npm install $ npm install
gulp install $ gulp install
lauching nginx: lauching nginx:
./dev.sh $ ./dev.sh
launching frontend: launching frontend:
gulp client $ gulp client
or start nginx before client on sequence
$ gulp clientDev
launching backend: launching backend:
gulp services $ gulp services
or start the local database before services on sequence
$ gulp serivcesDev
Manually reset local fixtures:
$ gulp docker
to check docker images and containers status:
$ docker images
$ docker ps -a
## Running the tests ## Running the tests
for client-side unit tests run from project's root: for client-side unit tests run from project's root:
karma start $ karma start
for server-side unit tests run from project's root: for server-side unit tests run from project's root:
npm run testWatch or test for single run $ npm run test
### Break down into end to end tests ### Break down into end to end tests
on root run: Run local database plus e2e paths:
$ gulp e2e
gulp docker Just the e2e paths as the fixtures are untainted:
$ npm run e2e
wait 10 secs for db to be ready
npm run e2e
## Built With ## Built With

View File

@ -5,11 +5,11 @@
</vn-auto> </vn-auto>
<vn-auto pad-medium> <vn-auto pad-medium>
<vn-vertical> <vn-vertical>
<vn-horizontal ng-repeat="(field, title) in $ctrl.fieldsToShow" ng-if="$ctrl.client[field]"> <vn-horizontal ng-repeat="(field, title) in $ctrl.fieldsToShow">
<strong vn-auto>{{::title}}:</strong> <strong vn-auto>{{::title}}:</strong>
<vn-auto margin-small-left> <vn-auto margin-small-left>
<span ng-if="field.includes('credit')">{{$ctrl.client[field] | number:2}} €</span> <span ng-if="field.includes('credit')">{{$ctrl.client[field] || 0 | number:2}} €</span>
<span ng-if="!field.includes('credit')">{{::$ctrl.client[field]}}</span> <span ng-if="!field.includes('credit')">{{$ctrl.client[field]}}</span>
</vn-auto> </vn-auto>
</vn-horizontal> </vn-horizontal>
</vn-vertical> </vn-vertical>

View File

@ -5,13 +5,19 @@
form="form" form="form"
save="post"> save="post">
</vn-watcher> </vn-watcher>
<form pad-medium ng-submit="$ctrl.onSubmit()">
<form pad-medium name="form" ng-submit="$ctrl.onSubmit()">
<vn-card> <vn-card>
<vn-vertical pad-medium> <vn-vertical pad-medium>
<vn-title vn-one margin-large-bottom>Add Greuge</vn-title> <vn-title vn-one margin-large-bottom>Add Greuge</vn-title>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one margin-medium-right label="Importe" field="$ctrl.greuge.amount" type="number" vn-focus></vn-textfield> <vn-textfield vn-one margin-medium-right label="Amount" field="$ctrl.greuge.amount" type="number" step="1" vn-focus></vn-textfield>
<vn-date-picker vn-one label="Date" model="$ctrl.greuge.shipped"></vn-date-picker> <vn-date-picker vn-one
label="Date"
model="$ctrl.greuge.shipped"
ini-options="{enableTime: true, dateFormat: 'd-m-Y h:i', time_24hr: true}"
>
</vn-date-picker>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one margin-medium-right label="Comment" field="$ctrl.greuge.description"></vn-textfield> <vn-textfield vn-one margin-medium-right label="Comment" field="$ctrl.greuge.description"></vn-textfield>

View File

@ -5,7 +5,7 @@ class ClientGreugeCreate {
this.$ = $scope; this.$ = $scope;
this.$state = $state; this.$state = $state;
this.greuge = { this.greuge = {
shipped: $filter('date')(new Date(), 'yyyy-MM-dd') shipped: $filter('date')(new Date(), 'yyyy-MM-dd HH:mm')
}; };
} }
onSubmit() { onSubmit() {

View File

@ -0,0 +1,39 @@
import './greuge-create.js';
describe('Client', () => {
describe('Component vnClientGreugeCreate', () => {
let $componentController;
let $scope;
let $state;
let controller;
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$state_) => {
$componentController = _$componentController_;
$scope = $rootScope.$new();
$state = _$state_;
$scope.watcher = {
submit: () => {
return {
then: callback => {
callback();
}
};
}
};
controller = $componentController('vnClientGreugeCreate', {$scope: $scope});
}));
describe('onSubmit()', () => {
it('should call the function go() on $state to go to the greuges list', () => {
spyOn($state, 'go');
controller.onSubmit();
expect(controller.$state.go).toHaveBeenCalledWith('clientCard.greuge.list');
});
});
});
});

View File

@ -20,5 +20,6 @@
"Credit" : "Crédito", "Credit" : "Crédito",
"Secured credit": "Crédito asegurado", "Secured credit": "Crédito asegurado",
"Verified data": "Datos comprobados", "Verified data": "Datos comprobados",
"Mandate": "Mandato" "Mandate": "Mandato",
"Amount": "Importe"
} }

View File

@ -1,5 +1,11 @@
<vn-vertical ng-click="$ctrl.showDropDown = true"> <vn-vertical ng-click="$ctrl.showDropDown = true" tabindex="0">
<vn-textfield vn-auto label="{{$ctrl.label}}" model="$ctrl.displayValue" readonly="$ctrl.readonly"></vn-textfield> <vn-textfield vn-auto
label="{{$ctrl.label}}"
model="$ctrl.displayValue"
readonly="$ctrl.readonly"
tab-index="-1"
>
</vn-textfield>
<vn-drop-down vn-auto <vn-drop-down vn-auto
items="$ctrl.items" items="$ctrl.items"
show="$ctrl.showDropDown" show="$ctrl.showDropDown"

View File

@ -25,6 +25,9 @@ ul.vn-autocomplete {
} }
vn-autocomplete { vn-autocomplete {
position: relative; position: relative;
vn-vertical {
outline:none;
}
.mdl-chip__action { .mdl-chip__action {
position: absolute; position: absolute;

View File

@ -30,6 +30,7 @@ class DatePicker extends Component {
this._modelView = null; this._modelView = null;
this._model = undefined; this._model = undefined;
this._optionsChecked = false; this._optionsChecked = false;
this._waitingInit = 0;
this.hasFocus = false; this.hasFocus = false;
this.hasMouseIn = false; this.hasMouseIn = false;
componentHandler.upgradeElement($element[0].firstChild); componentHandler.upgradeElement($element[0].firstChild);
@ -39,12 +40,34 @@ class DatePicker extends Component {
return this._model; return this._model;
} }
set model(value) { set model(value) {
this._model = value; if (this._optionsChecked) {
if (value && !this.modelView) { this._waitingInit = 0;
let options = this._getOptions(); this._model = value;
let initialDateFormat = (options && options.dateFormat) ? options.dateFormat : 'Y-m-d'; if (value && !this.modelView) {
let format = this._formatFlat2Angular(initialDateFormat); let options = this._getOptions();
this.modelView = this.$filter('date')(value, format); let initialDateFormat;
if (options && options.dateFormat) {
initialDateFormat = options.dateFormat;
} else {
initialDateFormat = this.$translate.use() === 'es' ? 'd-m-Y' : 'Y-m-d';
if (options.enableTime) {
initialDateFormat += ' H:i:s';
}
}
let format = this._formatFlat2Angular(initialDateFormat);
this._modelView = this.$filter('date')(new Date(this._model), format);
this.mdlUpdate();
}
} else if (this._waitingInit < 4) {
this._waitingInit++;
this.$timeout(() => {
this.model = value;
}, 250);
} else {
this.model = null;
this.modelView = '';
this._waitingInit = 0;
} }
} }
get modelView() { get modelView() {
@ -54,10 +77,9 @@ class DatePicker extends Component {
this._modelView = value; this._modelView = value;
this.input.value = value; this.input.value = value;
this._setModel(value); this._setModel(value);
this.$timeout(() => { this.mdlUpdate();
this.mdlUpdate();
}, 500);
} }
onClear() { onClear() {
this.modelView = null; this.modelView = null;
} }
@ -67,9 +89,11 @@ class DatePicker extends Component {
} }
} }
mdlUpdate() { mdlUpdate() {
let mdlField = this.element.firstChild.MaterialTextfield; this.$timeout(() => {
if (mdlField) let mdlField = this.element.firstChild.MaterialTextfield;
mdlField.updateClasses_(); if (mdlField)
mdlField.updateClasses_();
}, 500);
} }
_formatFlat2Angular(string) { // change string Flatpickr format to angular format (d-m-Y -> dd-MM-yyyy) _formatFlat2Angular(string) { // change string Flatpickr format to angular format (d-m-Y -> dd-MM-yyyy)
@ -90,54 +114,59 @@ class DatePicker extends Component {
return parts.join('-'); return parts.join('-');
} }
_string2BackFormat(value) {
let formats = this.iniOptions.dateFormat.split(/[ZT.,/ :-]/);
let aux = value.split(/[ZT.,/ :-]/);
let date = {};
formats.forEach(
(k, i) => {
if (k.toLowerCase() === 'y') {
date.year = aux[i];
} else if (k === 'm' || k === 'n') {
date.month = aux[i];
} else if (k === 'd' || k === 'j') {
date.day = aux[i];
} else if (k.toLowerCase() === 'h') {
date.hour = aux[i];
} else if (k === 'i') {
date.minutes = aux[i];
} else if (k === 's') {
date.seccons = aux[i];
}
}
);
let dateStr = '';
let hourStr = '';
if (date.year && date.month && date.day) {
dateStr = `${date.year}-${date.month}-${date.day}`;
}
if (date.hour) {
hourStr = date.hour;
if (date.minutes) {
hourStr += ':' + date.minutes;
} else {
hourStr += ':00';
}
if (date.seccons) {
hourStr += ':' + date.seccons;
} else {
hourStr += ':00';
}
}
return `${dateStr} ${hourStr}`.trim();
}
_setModel(value) { _setModel(value) {
let model; let model;
let options = this._getOptions();
if (!value) { if (!value) {
model = undefined; model = undefined;
} else if (!this.iniOptions || (this.iniOptions.dateFormat && this.iniOptions.dateFormat.startsWith('Y-m-d'))) { } else if (!options || (options.dateFormat && options.dateFormat.startsWith('Y-m-d'))) {
model = value; model = value;
} else { } else {
let formats = this.iniOptions.dateFormat.split(/[ZT.,/ :-]/); model = this._string2BackFormat(value);
let aux = value.split(/[ZT.,/ :-]/);
let date = {};
formats.forEach(
(k, i) => {
if (k.toLowerCase() === 'y') {
date.year = aux[i];
} else if (k === 'm' || k === 'n') {
date.month = aux[i];
} else if (k === 'd' || k === 'j') {
date.day = aux[i];
} else if (k.toLowerCase() === 'h') {
date.hour = aux[i];
} else if (k === 'i') {
date.minutes = aux[i];
} else if (k === 's') {
date.seccons = aux[i];
}
}
);
let dateStr = '';
let hourStr = '';
if (date.year && date.month && date.day) {
dateStr = `${date.year}-${date.month}-${date.day}`;
}
if (date.hour) {
hourStr = date.hour;
if (date.minutes) {
hourStr += ':' + date.minutes;
} else {
hourStr += ':00';
}
if (date.seccons) {
hourStr += ':' + date.seccons;
} else {
hourStr += ':00';
}
}
model = `${dateStr} ${hourStr}`.trim();
} }
if (this.model !== model) { if (this.model !== model) {
@ -155,8 +184,8 @@ class DatePicker extends Component {
if (!this.iniOptions.locale) if (!this.iniOptions.locale)
this.iniOptions.locale = this.$translate.use(); this.iniOptions.locale = this.$translate.use();
if (!this.iniOptions.dateFormat && this.iniOptions.locale === 'es') if (!this.iniOptions.dateFormat)
this.iniOptions.dateFormat = 'd-m-Y'; this.iniOptions.dateFormat = this.iniOptions.locale === 'es' ? 'd-m-Y' : 'Y-m-d';
else if (this.iniOptions.dateFormat) { else if (this.iniOptions.dateFormat) {
let format = this.iniOptions.dateFormat.split(/[ZT.,/ :-]/); let format = this.iniOptions.dateFormat.split(/[ZT.,/ :-]/);
if (format.length <= 1) { if (format.length <= 1) {
@ -193,6 +222,12 @@ class DatePicker extends Component {
this.vp = undefined; this.vp = undefined;
} }
$onChanges(objChange) {
if (objChange.iniOptions && objChange.iniOptions.currentValue) {
this.iniOptions = Object.assign(this.iniOptions, objChange.iniOptions.currentValue);
}
}
$onInit() { $onInit() {
this.initPicker(); this.initPicker();
} }

View File

@ -38,6 +38,7 @@ describe('Component vnDatePicker', () => {
it(`should split the given string into parts`, () => { it(`should split the given string into parts`, () => {
controller.iniOptions = {dateFormat: 'd/m/Y'}; controller.iniOptions = {dateFormat: 'd/m/Y'};
controller._optionsChecked = true;
controller.model = '2017-12-23'; controller.model = '2017-12-23';
expect(controller.modelView).toBe('23-12-2017'); expect(controller.modelView).toBe('23-12-2017');

View File

@ -29,7 +29,6 @@ export function directive(interpolate, compile, $window) {
throw new Error(`vnValidation: Entity '${entityName}' doesn't exist`); throw new Error(`vnValidation: Entity '${entityName}' doesn't exist`);
let validations = entity.validations[fieldName]; let validations = entity.validations[fieldName];
if (!validations || validations.length == 0) if (!validations || validations.length == 0)
return; return;

View File

@ -7,7 +7,7 @@
</vn-auto> </vn-auto>
<vn-auto> <vn-auto>
<ul class="dropdown"> <ul class="dropdown">
<li tabIndex="-1" <li
ng-repeat="item in $ctrl.itemsFiltered track by $index" ng-repeat="item in $ctrl.itemsFiltered track by $index"
ng-click="$ctrl.selectItem(item)" ng-click="$ctrl.selectItem(item)"
ng-class="{'active': $index === $ctrl.activeOption, 'checked': item.checked}" ng-class="{'active': $index === $ctrl.activeOption, 'checked': item.checked}"
@ -19,7 +19,6 @@
<li <li
ng-if="$ctrl.loadMore&&!$ctrl.removeLoadMore" ng-if="$ctrl.loadMore&&!$ctrl.removeLoadMore"
class="dropdown__loadMore" class="dropdown__loadMore"
tabIndex="-1"
ng-class="{'active': $ctrl.itemsFiltered.length === $ctrl.activeOption, 'noMore' : !$ctrl.showLoadMore}" ng-class="{'active': $ctrl.itemsFiltered.length === $ctrl.activeOption, 'noMore' : !$ctrl.showLoadMore}"
ng-click="$ctrl.loadItems()" ng-click="$ctrl.loadItems()"
translate="{{$ctrl.showLoadMore ? 'Show More' : 'No more results'}}" translate="{{$ctrl.showLoadMore ? 'Show More' : 'No more results'}}"

View File

@ -1,5 +1,6 @@
import {module} from '../module'; import {module} from '../module';
import './style.scss'; import './style.scss';
import validKey from '../lib/keyCodes';
export default class DropDown { export default class DropDown {
constructor($element, $filter, $timeout) { constructor($element, $filter, $timeout) {
@ -29,6 +30,9 @@ export default class DropDown {
this.$timeout(() => { this.$timeout(() => {
this._tryToShow++; this._tryToShow++;
this.show = true; this.show = true;
if (this.activeOption === -1) {
this.activeOption = 0;
}
}, 250); }, 250);
} else { } else {
this._tryToShow = 0; this._tryToShow = 0;
@ -70,26 +74,27 @@ export default class DropDown {
} }
_toggleDropDown(value, oldValue) { _toggleDropDown(value, oldValue) {
if (value && !this._focusingFilter && !oldValue && this.filter) {
// open dropDown
this.$timeout(() => { // wait angular ngIf
this._setFocusInFilterInput();
this._eventScroll(value);
});
} else if (!value && oldValue) {
// close dropDown
this._eventScroll(value);
}
this.$timeout(() => { this.$timeout(() => {
this._eventScroll(value);
this._calculatePosition(value, oldValue); this._calculatePosition(value, oldValue);
}); });
} }
_eventScroll(add) { _eventScroll(add, num) {
let count = num || 0;
if (add) { if (add) {
this.container.addEventListener('scroll', e => this.loadFromScroll(e)); if (this.container) {
} else { this.container.addEventListener('scroll', e => this.loadFromScroll(e));
// this.$timeout(() => { // falla al entrar por primera vez xq pierde el foco y cierra el dropdown
// this._setFocusInFilterInput();
// });
} else if (count < 4) {
count++;
this.$timeout(() => { // wait angular ngIf
this._eventScroll(add, count);
}, 250);
}
} else if (this.container) {
this.container.removeEventListener('scroll', e => this.loadFromScroll(e)); this.container.removeEventListener('scroll', e => this.loadFromScroll(e));
} }
} }
@ -169,43 +174,43 @@ export default class DropDown {
onKeydown(event) { onKeydown(event) {
if (this.show) { if (this.show) {
switch (event.keyCode) { if (event.keyCode === 13) { // Enter
case 13: // Enter
this.$timeout(() => { this.$timeout(() => {
this.selectOption(); this.selectOption();
}); });
event.preventDefault(); event.preventDefault();
break; } else if (event.keyCode === 27) { // Escape
case 27: // Escape
this.clearSearch(); this.clearSearch();
break; } else if (event.keyCode === 38) { // Arrow up
case 38: // Arrow up
this.activeOption--; this.activeOption--;
this.$timeout(() => { this.$timeout(() => {
this.setScrollPosition(); this.setScrollPosition();
}, 100); }, 100);
break; } else if (event.keyCode === 40) { // Arrow down
case 40: // Arrow down
this.activeOption++; this.activeOption++;
this.$timeout(() => { this.$timeout(() => {
this.setScrollPosition(); this.setScrollPosition();
}, 100); }, 100);
break; } else if (event.keyCode === 35) { // End
case 35: // End
this.activeOption = this.itemsFiltered.length - 1; this.activeOption = this.itemsFiltered.length - 1;
this.$timeout(() => { this.$timeout(() => {
this.setScrollPosition(); this.setScrollPosition();
}, 100); }, 100);
break; } else if (event.keyCode === 36) { // Start
case 36: // Start
this.activeOption = 0; this.activeOption = 0;
this.$timeout(() => { this.$timeout(() => {
this.setScrollPosition(); this.setScrollPosition();
}, 100); }, 100);
break; } else if (this.filter) {
default: let oldValue = this.search || '';
return; if (validKey(event)) {
} this.search = oldValue + String.fromCharCode(event.keyCode);
} else if (event.keyCode === 8) { // backSpace
this.search = oldValue.slice(0, -1);
}
} /* else {
console.error(`Error: keyCode ${event.keyCode} not supported`);
} */
} }
} }
setScrollPosition() { setScrollPosition() {

View File

@ -1,7 +1,7 @@
import {module} from '../module'; import {module} from '../module';
const isFullEmpty = item => { const isFullEmpty = item => {
return (!item && item !== 0) || (typeof item === 'object' && !Object.keys(item).length); return (item === null || item === undefined) || (typeof item === 'object' && !Object.keys(item).length);
}; };
export default isFullEmpty; export default isFullEmpty;

View File

@ -14,3 +14,4 @@ export {NAME as INTERPOLATE, Interpolate} from './interpolate';
export {NAME as COPY_OBJECT} from './copy'; export {NAME as COPY_OBJECT} from './copy';
export {NAME as EQUALS_OBJECT} from './equals'; export {NAME as EQUALS_OBJECT} from './equals';
export {NAME as GET_DATA_MODIFIED, factory as Modified} from './modified'; export {NAME as GET_DATA_MODIFIED, factory as Modified} from './modified';
export {NAME as VALID_KEY} from './keyCodes';

View File

@ -0,0 +1,19 @@
import {module} from '../module';
const validKey = key => {
let keycode = key.keyCode || key;
let valid =
(keycode > 47 && keycode < 58) || // number keys
(keycode > 64 && keycode < 91) || // letter keys
(keycode > 95 && keycode < 112) || // numpad keys
(keycode > 185 && keycode < 193) || // ;=,-./` (in order)
(keycode > 218 && keycode < 223); // [\]' (in order)
return valid;
};
export default validKey;
export const NAME = 'validKey';
module.value(NAME, validKey);

View File

@ -2,7 +2,7 @@ import {validator} from 'vendor';
export const validators = { export const validators = {
presence: value => { presence: value => {
if (validator.isEmpty(value)) if (validator.isEmpty(value ? String(value) : ''))
throw new Error(`Value can't be empty`); throw new Error(`Value can't be empty`);
}, },
absence: value => { absence: value => {
@ -14,8 +14,8 @@ export const validators = {
min: conf.min || conf.is, min: conf.min || conf.is,
max: conf.max || conf.is max: conf.max || conf.is
}; };
let val = value ? String(value) : '';
if (!validator.isLength(value, options)) { if (!validator.isLength(val, options)) {
if (conf.is) { if (conf.is) {
throw new Error(`Value should be ${conf.is} characters long`); throw new Error(`Value should be ${conf.is} characters long`);
} else if (conf.min && conf.max) { } else if (conf.min && conf.max) {
@ -74,7 +74,7 @@ export function validate(value, conf) {
try { try {
checkNull(value, conf); checkNull(value, conf);
if (validator && value != null) if (validator) // && value != null ??
validator(value, conf); validator(value, conf);
} catch (e) { } catch (e) {
let message = conf.message ? conf.message : e.message; let message = conf.message ? conf.message : e.message;

View File

@ -1,8 +1,5 @@
<div <div
class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label" class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label"
tabindex="1"
ng-focus="$ctrl.hasFocus = true"
ng-blur="$ctrl.hasFocus = false"
ng-mouseenter="$ctrl.hasMouseIn = true" ng-mouseenter="$ctrl.hasMouseIn = true"
ng-mouseleave="$ctrl.hasMouseIn = false"> ng-mouseleave="$ctrl.hasMouseIn = false">
<input <input
@ -12,7 +9,10 @@
ng-model="$ctrl.value" ng-model="$ctrl.value"
vn-validation="{{$ctrl.rule}}" vn-validation="{{$ctrl.rule}}"
ng-disabled="$ctrl.disabled" ng-disabled="$ctrl.disabled"
ng-readonly="$ctrl.readonly"/> ng-readonly="$ctrl.readonly"
ng-focus="$ctrl.hasFocus = true"
ng-blur="$ctrl.hasFocus = false"
/>
<div class="mdl-chip__action"> <div class="mdl-chip__action">
<i class="material-icons" <i class="material-icons"
ng-if="$ctrl.hasInfo" ng-if="$ctrl.hasInfo"

View File

@ -32,6 +32,9 @@ export default class Textfield extends Input {
this.hasValue = Boolean(this._value); this.hasValue = Boolean(this._value);
this.mdlUpdate(); this.mdlUpdate();
} }
set tabIndex(value) {
this.input.tabIndex = value;
}
mdlUpdate() { mdlUpdate() {
let mdlField = this.$element[0].firstChild.MaterialTextfield; let mdlField = this.$element[0].firstChild.MaterialTextfield;
if (mdlField) if (mdlField)
@ -54,6 +57,7 @@ module.component('vnTextfield', {
disabled: '<?', disabled: '<?',
readonly: '<?', readonly: '<?',
rule: '@?', rule: '@?',
type: '@?' type: '@?',
tabIndex: '@?'
} }
}); });

View File

@ -12,12 +12,13 @@ import isFullEmpty from '../lib/fullEmpty';
* properties are provided. * properties are provided.
*/ */
export default class Watcher extends Component { export default class Watcher extends Component {
constructor($element, $scope, $state, $transitions, $http, vnApp, $translate) { constructor($element, $scope, $state, $transitions, $http, vnApp, $translate, $attrs) {
super($element); super($element);
this.$scope = $scope; this.$scope = $scope;
this.$state = $state; this.$state = $state;
this.$http = $http; this.$http = $http;
this.$translate = $translate; this.$translate = $translate;
this.$attrs = $attrs;
this.vnApp = vnApp; this.vnApp = vnApp;
this.state = null; this.state = null;
@ -93,10 +94,10 @@ export default class Watcher extends Component {
(resolve, reject) => this.noChanges(reject) (resolve, reject) => this.noChanges(reject)
); );
} }
let changedData = getModifiedData(this.data, this.orgData); let changedData = (this.$attrs.save && this.$attrs.save.toLowerCase() === 'post') ? this.copyInNewObject(this.data) : getModifiedData(this.data, this.orgData);
if (this.save) { if (this.save) {
this.save.model = this.copyInNewObject(changedData); this.save.model = changedData; // this.copyInNewObject(changedData);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.save.accept().then( this.save.accept().then(
json => this.writeData({data: json}, resolve), json => this.writeData({data: json}, resolve),
@ -180,6 +181,7 @@ export default class Watcher extends Component {
} }
dataChanged() { dataChanged() {
if (this.form && !this.form.$dirty) return false;
let newData = this.copyInNewObject(this.data); let newData = this.copyInNewObject(this.data);
return !isEqual(newData, this.orgData); return !isEqual(newData, this.orgData);
} }
@ -194,7 +196,7 @@ export default class Watcher extends Component {
} }
} }
Watcher.$inject = ['$element', '$scope', '$state', '$transitions', '$http', 'vnApp', '$translate']; Watcher.$inject = ['$element', '$scope', '$state', '$transitions', '$http', 'vnApp', '$translate', '$attrs'];
module.component('vnWatcher', { module.component('vnWatcher', {
template: require('./watcher.html'), template: require('./watcher.html'),

View File

@ -11,6 +11,7 @@ describe('Component vnWatcher', () => {
let vnApp; let vnApp;
let $translate; let $translate;
let controller; let controller;
let $attrs;
beforeEach(() => { beforeEach(() => {
angular.mock.module('client'); angular.mock.module('client');
@ -25,7 +26,10 @@ describe('Component vnWatcher', () => {
$transitions = _$transitions_; $transitions = _$transitions_;
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$translate = _$translate_; $translate = _$translate_;
controller = $componentController('vnWatcher', {$scope, $element, $state, vnApp, $transitions, $httpBackend, $translate}); $attrs = {
save: "patch"
};
controller = $componentController('vnWatcher', {$scope, $element, $state, vnApp, $transitions, $httpBackend, $translate, $attrs});
})); }));
describe('$onInit()', () => { describe('$onInit()', () => {

View File

@ -2,6 +2,7 @@
"module": "item", "module": "item",
"name": "Items", "name": "Items",
"icon": "/static/images/icon_item.png", "icon": "/static/images/icon_item.png",
"validations" : true,
"routes": [ "routes": [
{ {
"url": "/item", "url": "/item",

View File

@ -9,16 +9,9 @@
<div style="max-width: 70em; margin: 0 auto;"> <div style="max-width: 70em; margin: 0 auto;">
<vn-card> <vn-card>
<vn-vertical pad-large> <vn-vertical pad-large>
<vn-title>Create item</vn-title> <vn-title>New item</vn-title>
<vn-horizontal>
<vn-textfield vn-one label="Size" field="$ctrl.item.size" vn-focus></vn-textfield>
<vn-textfield vn-five label="Category" field="$ctrl.item.category"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Stems" field="$ctrl.item.stems"></vn-textfield>
<vn-textfield vn-five label="Description" field="$ctrl.item.description"></vn-textfield>
</vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Name" field="$ctrl.item.name" vn-focus></vn-textfield>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="/item/api/ItemTypes" url="/item/api/ItemTypes"
label="Type" label="Type"
@ -27,17 +20,23 @@
field="$ctrl.item.typeFk" field="$ctrl.item.typeFk"
> >
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one
url="/item/api/Inks"
label="Ink"
show-field="name"
value-field="id"
field="$ctrl.item.inkFk"
>
</vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
url="/item/api/Intrastats"
label="Intrastat"
show-field="description"
value-field="id"
field="$ctrl.item.intrastatFk"
order="description ASC"
filter-search="{where: {description: {regexp: 'search'}} }"
>
<tpl-item>{{$parent.$parent.item.description}}</tpl-item>
</vn-autocomplete>
<vn-textfield vn-one label="Relevancy" field="$ctrl.item.relevancy" type="number"></vn-textfield>
</vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="/item/api/Origins" url="/item/api/Origins"
@ -45,18 +44,10 @@
show-field="name" show-field="name"
value-field="id" value-field="id"
field="$ctrl.item.originFk" field="$ctrl.item.originFk"
> ></vn-autocomplete>
</vn-autocomplete> <vn-one></vn-one>
<vn-autocomplete vn-one
url="/item/api/Producers"
label="Producer"
show-field="name"
value-field="id"
field="$ctrl.item.producerFk"
>
</vn-autocomplete>
</vn-horizontal> </vn-horizontal>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
<vn-button-bar> <vn-button-bar>

View File

@ -1,16 +1,21 @@
import ngModule from '../module'; import ngModule from '../module';
class ItemCreate { class ItemCreate {
constructor() { constructor($scope, $state) {
this.item = {}; this.$ = $scope;
this.$state = $state;
this.item = {
relevancy: 0
};
} }
onSubmit() { onSubmit() {
this.$.watcher.submit().then( this.$.watcher.submit().then(
json => this.$state.go('item.card.basic', {id: json.data.id}) json => this.$state.go('item.card.data', {id: json.data.id})
); );
} }
} }
ItemCreate.$inject = ['$scope', '$state'];
ngModule.component('vnItemCreate', { ngModule.component('vnItemCreate', {
template: require('./item-create.html'), template: require('./item-create.html'),

View File

@ -4,5 +4,8 @@
"Category": "Categoría", "Category": "Categoría",
"Description": "Descripción", "Description": "Descripción",
"Size": "Tamaño", "Size": "Tamaño",
"Type": "Tipo" "Type": "Tipo",
"Name": "Nombre",
"Relevancy": "Relevancia",
"New item": "Nuevo artículo"
} }

View File

@ -1,14 +1,14 @@
/* eslint no-console: 0 */ /* eslint no-console: 0 */
import Nightmare from 'nightmare'; import Nightmare from 'nightmare';
export default function createNightmare(width = 1100, height = 600) { export default function createNightmare(width = 1280, height = 720) {
const nightmare = new Nightmare({show: true, typeInterval: 10}).viewport(width, height); const nightmare = new Nightmare({show: true, typeInterval: 10, x: 0, y: 0}).viewport(width, height);
nightmare.on('page', function(type, message, error) { nightmare.on('page', (type, message, error) => {
fail(error); fail(error);
}); });
nightmare.on('console', function(type, message) { nightmare.on('console', (type, message) => {
if (type === 'error') { if (type === 'error') {
fail(message); fail(message);
} }

View File

@ -78,6 +78,9 @@ export default {
IBANInput: `${components.vnTextfield}[name="iban"]`, IBANInput: `${components.vnTextfield}[name="iban"]`,
dueDayInput: `${components.vnTextfield}[name="dueDay"]`, dueDayInput: `${components.vnTextfield}[name="dueDay"]`,
cancelNotificationButton: 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-client-billing-data > vn-dialog > div > form > div.button-bar > tpl-buttons > button:nth-child(1)', cancelNotificationButton: 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-client-billing-data > vn-dialog > div > form > div.button-bar > tpl-buttons > button:nth-child(1)',
receivedCoreVNHCheckbox: `${components.vnCheck}[label='Received core VNH'] > label > input`,
receivedCoreVNLCheckbox: `${components.vnCheck}[label='Received core VNL'] > label > input`,
receivedB2BVNLCheckbox: `${components.vnCheck}[label='Received B2B VNL'] > label > input`,
saveButton: `${components.vnSubmit}` saveButton: `${components.vnSubmit}`
}, },
addresses: { addresses: {
@ -121,5 +124,19 @@ export default {
creditInput: `${components.vnTextfield}[name="credit"]`, creditInput: `${components.vnTextfield}[name="credit"]`,
saveButton: `${components.vnSubmit}`, saveButton: `${components.vnSubmit}`,
firstCreditText: 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > ui-view > vn-client-credit-list > vn-card > div > vn-vertical > vn-one > vn-horizontal:nth-child(1) > vn-one' firstCreditText: 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > ui-view > vn-client-credit-list > vn-card > div > vn-vertical > vn-one > vn-horizontal:nth-child(1) > vn-one'
},
greuge: {
greugeButton: `${components.vnMenuItem}[ui-sref="clientCard.greuge.list"]`,
addGreugeFloatButton: `${components.vnFloatButton}`,
amountInput: `${components.vnTextfield}[name="amount"]`,
descriptionInput: `${components.vnTextfield}[name="description"]`,
typeInput: `${components.vnAutocomplete}[field="$ctrl.greuge.greugeTypeFk"] > vn-vertical > ${components.vnTextfield}`,
typeSecondOption: `${components.vnAutocomplete}[field="$ctrl.greuge.greugeTypeFk"] > vn-vertical > vn-drop-down > vn-vertical > vn-auto:nth-child(2) > ul > li`,
saveButton: `${components.vnSubmit}`,
firstGreugeText: 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > ui-view > vn-client-greuge-list > vn-card > div > vn-vertical > vn-one > vn-horizontal'
},
mandate: {
mandateButton: `${components.vnMenuItem}[ui-sref="clientCard.mandate"]`,
firstMandateText: 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-client-mandate > vn-card > div > vn-vertical > vn-one > vn-horizontal'
} }
}; };

View File

@ -86,7 +86,7 @@ describe('create client path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toEqual('No changes to save'); expect(result).toEqual('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -100,7 +100,7 @@ describe('create client path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -115,7 +115,7 @@ describe('create client path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -130,7 +130,7 @@ describe('create client path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -145,7 +145,7 @@ describe('create client path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -175,7 +175,7 @@ describe('create client path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -190,7 +190,7 @@ describe('create client path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));

View File

@ -131,62 +131,62 @@ describe('Edit fiscalData path', () => {
it('should edit the social name', done => { it('should edit the social name', done => {
nightmare nightmare
.wait(selectors.fiscalData.socialNameInput) .wait(selectors.fiscalData.socialNameInput)
.clearInput(selectors.fiscalData.socialNameInput) .clearInput(selectors.fiscalData.socialNameInput)
.type(selectors.fiscalData.socialNameInput, 'Hulk edited') .type(selectors.fiscalData.socialNameInput, 'Hulk edited')
.click(selectors.fiscalData.saveButton) .click(selectors.fiscalData.saveButton)
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should confirm the social name have been edited', done => { it('should confirm the social name have been edited', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.fiscalData.fiscalDataButton) .waitToClick(selectors.fiscalData.fiscalDataButton)
.wait(selectors.fiscalData.socialNameInput) .wait(selectors.fiscalData.socialNameInput)
.getInputValue(selectors.fiscalData.socialNameInput) .getInputValue(selectors.fiscalData.socialNameInput)
.then(result => { .then(result => {
expect(result).toEqual('Hulk edited'); expect(result).toEqual('Hulk edited');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should edit the fiscal id', done => { it('should edit the fiscal id', done => {
nightmare nightmare
.wait(selectors.fiscalData.fiscalIdInput) .wait(selectors.fiscalData.fiscalIdInput)
.clearInput(selectors.fiscalData.fiscalIdInput) .clearInput(selectors.fiscalData.fiscalIdInput)
.type(selectors.fiscalData.fiscalIdInput, '94980061C') .type(selectors.fiscalData.fiscalIdInput, '94980061C')
.click(selectors.fiscalData.saveButton) .click(selectors.fiscalData.saveButton)
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should confirm the fiscal id have been edited', done => { it('should confirm the fiscal id have been edited', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.fiscalData.fiscalDataButton) .waitToClick(selectors.fiscalData.fiscalDataButton)
.wait(selectors.fiscalData.fiscalIdInput) .wait(selectors.fiscalData.fiscalIdInput)
.getInputValue(selectors.fiscalData.fiscalIdInput) .getInputValue(selectors.fiscalData.fiscalIdInput)
.then(result => { .then(result => {
expect(result).toEqual('94980061C'); expect(result).toEqual('94980061C');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should uncheck the Equalization tax checkbox', done => { it('should uncheck the Equalization tax checkbox', done => {
@ -216,19 +216,19 @@ describe('Edit fiscalData path', () => {
it('should confirm Equalization tax checkbox is unchecked', done => { it('should confirm Equalization tax checkbox is unchecked', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.fiscalData.fiscalDataButton) .waitToClick(selectors.fiscalData.fiscalDataButton)
.wait(selectors.fiscalData.equalizationTaxCheckboxLabel) .wait(selectors.fiscalData.equalizationTaxCheckboxLabel)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.fiscalData.equalizationTaxCheckboxLabel) }, selectors.fiscalData.equalizationTaxCheckboxLabel)
.then(value => { .then(value => {
expect(value).toBeFalsy(); expect(value).toBeFalsy();
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
describe('Confirm all addresses havent got EQtax as uncheck was propagated', () => { describe('Confirm all addresses havent got EQtax as uncheck was propagated', () => {
@ -412,168 +412,168 @@ describe('Edit fiscalData path', () => {
it('should confirm active checkbox is unchecked', done => { it('should confirm active checkbox is unchecked', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.fiscalData.fiscalDataButton) .waitToClick(selectors.fiscalData.fiscalDataButton)
.wait(selectors.fiscalData.activeCheckboxLabel) .wait(selectors.fiscalData.activeCheckboxLabel)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.fiscalData.activeCheckboxLabel) }, selectors.fiscalData.activeCheckboxLabel)
.then(value => { .then(value => {
expect(value).toBeFalsy(); expect(value).toBeFalsy();
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should check the invoice by address checkbox', done => { it('should uncheck the invoice by address checkbox', done => {
nightmare nightmare
.waitToClick(selectors.fiscalData.invoiceByAddressCheckboxInput) .waitToClick(selectors.fiscalData.invoiceByAddressCheckboxInput)
.waitToClick(selectors.fiscalData.saveButton) .waitToClick(selectors.fiscalData.saveButton)
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should confirm invoice by address checkbox is checked', done => { it('should confirm invoice by address checkbox is unchecked', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.fiscalData.fiscalDataButton) .waitToClick(selectors.fiscalData.fiscalDataButton)
.wait(selectors.fiscalData.invoiceByAddressCheckboxInput) .wait(selectors.fiscalData.invoiceByAddressCheckboxInput)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.fiscalData.invoiceByAddressCheckboxInput) }, selectors.fiscalData.invoiceByAddressCheckboxInput)
.then(value => { .then(value => {
expect(value).toBeTruthy(); expect(value).toBeFalsy();
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should check the Verified data checkbox', done => { it('should check the Verified data checkbox', done => {
nightmare nightmare
.waitToClick(selectors.fiscalData.verifiedDataCheckboxInput) .waitToClick(selectors.fiscalData.verifiedDataCheckboxInput)
.waitToClick(selectors.fiscalData.saveButton) .waitToClick(selectors.fiscalData.saveButton)
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should confirm Verified data checkbox is checked', done => { it('should confirm Verified data checkbox is unchecked', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.fiscalData.fiscalDataButton) .waitToClick(selectors.fiscalData.fiscalDataButton)
.wait(selectors.fiscalData.verifiedDataCheckboxInput) .wait(selectors.fiscalData.verifiedDataCheckboxInput)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.fiscalData.verifiedDataCheckboxInput) }, selectors.fiscalData.verifiedDataCheckboxInput)
.then(value => { .then(value => {
expect(value).toBeTruthy(); expect(value).toBeFalsy();
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should uncheck the Has to invoice checkbox', done => { it('should uncheck the Has to invoice checkbox', done => {
nightmare nightmare
.waitToClick(selectors.fiscalData.hasToInvoiceCheckboxLabel) .waitToClick(selectors.fiscalData.hasToInvoiceCheckboxLabel)
.waitToClick(selectors.fiscalData.saveButton) .waitToClick(selectors.fiscalData.saveButton)
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should confirm Has to invoice checkbox is unchecked', done => { it('should confirm Has to invoice checkbox is unchecked', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.fiscalData.fiscalDataButton) .waitToClick(selectors.fiscalData.fiscalDataButton)
.wait(selectors.fiscalData.hasToInvoiceCheckboxLabel) .wait(selectors.fiscalData.hasToInvoiceCheckboxLabel)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.fiscalData.hasToInvoiceCheckboxLabel) }, selectors.fiscalData.hasToInvoiceCheckboxLabel)
.then(value => { .then(value => {
expect(value).toBeFalsy(); expect(value).toBeFalsy();
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should uncheck the Invoice by mail checkbox', done => { it('should uncheck the Invoice by mail checkbox', done => {
nightmare nightmare
.waitToClick(selectors.fiscalData.invoiceByMailCheckboxLabel) .waitToClick(selectors.fiscalData.invoiceByMailCheckboxLabel)
.waitToClick(selectors.fiscalData.saveButton) .waitToClick(selectors.fiscalData.saveButton)
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should confirm Invoice by mail checkbox is unchecked', done => { it('should confirm Invoice by mail checkbox is unchecked', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.fiscalData.fiscalDataButton) .waitToClick(selectors.fiscalData.fiscalDataButton)
.wait(selectors.fiscalData.invoiceByMailCheckboxLabel) .wait(selectors.fiscalData.invoiceByMailCheckboxLabel)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.fiscalData.invoiceByMailCheckboxLabel) }, selectors.fiscalData.invoiceByMailCheckboxLabel)
.then(value => { .then(value => {
expect(value).toBeFalsy(); expect(value).toBeFalsy();
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should check the Vies checkbox', done => { it('should check the Vies checkbox', done => {
nightmare nightmare
.waitToClick(selectors.fiscalData.viesCheckboxInput) .waitToClick(selectors.fiscalData.viesCheckboxInput)
.waitToClick(selectors.fiscalData.saveButton) .waitToClick(selectors.fiscalData.saveButton)
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should confirm Vies checkbox is checked', done => { it('should confirm Vies checkbox is checked', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.fiscalData.fiscalDataButton) .waitToClick(selectors.fiscalData.fiscalDataButton)
.wait(selectors.fiscalData.viesCheckboxInput) .wait(selectors.fiscalData.viesCheckboxInput)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.fiscalData.viesCheckboxInput) }, selectors.fiscalData.viesCheckboxInput)
.then(value => { .then(value => {
expect(value).toBeTruthy(); expect(value).toBeTruthy();
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
}); });

View File

@ -160,35 +160,123 @@ describe('Edit pay method path', () => {
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
// BUG IBAN validation seems to break down whenever the due day is edited plus due day shouldnt accep values above 31. it(`should edit the due day`, done => {
nightmare
.clearInput(selectors.payMethod.dueDayInput)
.type(selectors.payMethod.dueDayInput, '60')
.waitToClick(selectors.payMethod.saveButton)
.waitToClick(selectors.payMethod.cancelNotificationButton)
.wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => {
expect(result).toEqual('Data saved!');
done();
})
.catch(catchErrors(done));
});
// it(`should edit the due day`, done => { it('should confirm the due day have been edited', done => {
// nightmare nightmare
// .clearInput(selectors.payMethod.dueDayInput) .waitForSnackbarReset()
// .type(selectors.payMethod.dueDayInput, '25') .waitToClick(selectors.basicData.basicDataButton)
// .waitToClick(selectors.payMethod.saveButton) .wait(selectors.basicData.nameInput)
// .waitToClick(selectors.payMethod.cancelNotificationButton) .waitToClick(selectors.payMethod.payMethodButton)
// .wait(selectors.globalItems.snackbarIsActive) .wait(selectors.payMethod.dueDayInput)
// .getInnerText(selectors.globalItems.snackbarIsActive) .getInputValue(selectors.payMethod.dueDayInput)
// .then(result => { .then(result => {
// expect(result).toEqual('Data saved!'); expect(result).toEqual('60');
// done(); done();
// }) })
// .catch(catchErrors(done)); .catch(catchErrors(done));
// }); });
// it('should confirm the due day have been edited', done => { it('should uncheck the Received core VNH checkbox', done => {
// nightmare nightmare
// .waitForSnackbarReset() .waitToClick(selectors.payMethod.receivedCoreVNHCheckbox)
// .waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.payMethod.saveButton)
// .wait(selectors.basicData.nameInput) .wait(selectors.globalItems.snackbarIsActive)
// .waitToClick(selectors.payMethod.payMethodButton) .getInnerText(selectors.globalItems.snackbarIsActive)
// .wait(selectors.payMethod.dueDayInput) .then(result => {
// .getInputValue(selectors.payMethod.dueDayInput) expect(result).toEqual('Data saved!');
// .then(result => { done();
// expect(result).toEqual('25'); })
// done(); .catch(catchErrors(done));
// }) });
// .catch(catchErrors(done));
// }); it('should confirm Received core VNH checkbox is unchecked', done => {
nightmare
.waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput)
.waitToClick(selectors.payMethod.payMethodButton)
.wait(selectors.payMethod.receivedCoreVNHCheckbox)
.evaluate(selector => {
return document.querySelector(selector).checked;
}, selectors.payMethod.receivedCoreVNHCheckbox)
.then(value => {
expect(value).toBeFalsy();
done();
})
.catch(catchErrors(done));
});
it('should uncheck the Received core VNL checkbox', done => {
nightmare
.waitToClick(selectors.payMethod.receivedCoreVNLCheckbox)
.waitToClick(selectors.payMethod.saveButton)
.wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => {
expect(result).toEqual('Data saved!');
done();
})
.catch(catchErrors(done));
});
it('should confirm Received core VNL checkbox is unchecked', done => {
nightmare
.waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput)
.waitToClick(selectors.payMethod.payMethodButton)
.wait(selectors.payMethod.receivedCoreVNLCheckbox)
.evaluate(selector => {
return document.querySelector(selector).checked;
}, selectors.payMethod.receivedCoreVNLCheckbox)
.then(value => {
expect(value).toBeFalsy();
done();
})
.catch(catchErrors(done));
});
it('should uncheck the Received B2B VNL checkbox', done => {
nightmare
.waitToClick(selectors.payMethod.receivedB2BVNLCheckbox)
.waitToClick(selectors.payMethod.saveButton)
.wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => {
expect(result).toEqual('Data saved!');
done();
})
.catch(catchErrors(done));
});
it('should confirm Received B2B VNL checkbox is unchecked', done => {
nightmare
.waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput)
.waitToClick(selectors.payMethod.payMethodButton)
.wait(selectors.payMethod.receivedB2BVNLCheckbox)
.evaluate(selector => {
return document.querySelector(selector).checked;
}, selectors.payMethod.receivedB2BVNLCheckbox)
.then(value => {
expect(value).toBeFalsy();
done();
})
.catch(catchErrors(done));
});
}); });

View File

@ -98,15 +98,15 @@ describe('Edit addresses path', () => {
it('should check the default checkbox then receive an error after clicking save button as the form is empty', done => { it('should check the default checkbox then receive an error after clicking save button as the form is empty', done => {
nightmare nightmare
.waitToClick(selectors.addresses.defaultCheckboxInput) .waitToClick(selectors.addresses.defaultCheckboxInput)
.waitToClick(selectors.fiscalData.saveButton) .waitToClick(selectors.fiscalData.saveButton)
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should receive an error when clicking the save button having all the form fields empty but consignee', done => { it('should receive an error when clicking the save button having all the form fields empty but consignee', done => {
@ -117,7 +117,7 @@ describe('Edit addresses path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -132,7 +132,7 @@ describe('Edit addresses path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -147,7 +147,7 @@ describe('Edit addresses path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -162,7 +162,7 @@ describe('Edit addresses path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -178,7 +178,7 @@ describe('Edit addresses path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -193,7 +193,7 @@ describe('Edit addresses path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -207,7 +207,7 @@ describe('Edit addresses path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
@ -222,7 +222,7 @@ describe('Edit addresses path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain('Error'); expect(result).toContain('Some fields are invalid');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));

View File

@ -86,32 +86,32 @@ describe('Edit web access path', () => {
it(`should click on the Enable web access checkbox to uncheck it`, done => { it(`should click on the Enable web access checkbox to uncheck it`, done => {
nightmare nightmare
.waitToClick(selectors.webAccess.enableWebAccessCheckbox) .waitToClick(selectors.webAccess.enableWebAccessCheckbox)
.waitToClick(selectors.fiscalData.saveButton) .waitToClick(selectors.fiscalData.saveButton)
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toContain(`Data saved!`); expect(result).toContain(`Data saved!`);
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should confirm Enable web access checkbox is unchecked', done => { it('should confirm Enable web access checkbox is unchecked', done => {
nightmare nightmare
.waitForSnackbarReset() .waitForSnackbarReset()
.waitToClick(selectors.basicData.basicDataButton) .waitToClick(selectors.basicData.basicDataButton)
.wait(selectors.basicData.nameInput) .wait(selectors.basicData.nameInput)
.waitToClick(selectors.webAccess.webAccessButton) .waitToClick(selectors.webAccess.webAccessButton)
.wait(selectors.webAccess.enableWebAccessCheckbox) .wait(selectors.webAccess.enableWebAccessCheckbox)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.webAccess.enableWebAccessCheckbox) }, selectors.webAccess.enableWebAccessCheckbox)
.then(value => { .then(value => {
expect(value).toBeFalsy(); expect(value).toBeFalsy();
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));
}); });
it('should edit the User name', done => { it('should edit the User name', done => {

View File

@ -2,13 +2,12 @@ import config from '../helpers/config.js';
import createNightmare from '../helpers/nightmare'; import createNightmare from '../helpers/nightmare';
import selectors from '../helpers/selectors.js'; import selectors from '../helpers/selectors.js';
import {catchErrors} from '../../services/utils/jasmineHelpers'; import {catchErrors} from '../../services/utils/jasmineHelpers';
import { fail } from 'assert';
const nightmare = createNightmare(); const nightmare = createNightmare();
const moduleAccessViewHashURL = '#!/'; const moduleAccessViewHashURL = '#!/';
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
fdescribe('Add credit path', () => { describe('Add credit path', () => {
describe('warm up', () => { describe('warm up', () => {
it('should warm up login and fixtures', done => { it('should warm up login and fixtures', done => {
nightmare nightmare
@ -104,7 +103,7 @@ fdescribe('Add credit path', () => {
.wait(selectors.globalItems.snackbarIsActive) .wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive) .getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => { .then(result => {
expect(result).toEqual('Data saved'); expect(result).toEqual('Data saved!');
done(); done();
}) })
.catch(catchErrors(done)); .catch(catchErrors(done));

View File

@ -0,0 +1,180 @@
import config from '../helpers/config.js';
import createNightmare from '../helpers/nightmare';
import selectors from '../helpers/selectors.js';
import {catchErrors} from '../../services/utils/jasmineHelpers';
const nightmare = createNightmare();
const moduleAccessViewHashURL = '#!/';
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
describe('Add greuge path', () => {
describe('warm up', () => {
it('should warm up login and fixtures', done => {
nightmare
.login()
.waitForURL(moduleAccessViewHashURL)
.waitToClick(selectors.globalItems.logOutButton)
.then(() => {
done();
})
.catch(catchErrors(done));
});
});
it('should log in', done => {
nightmare
.login()
.waitForURL(moduleAccessViewHashURL)
.url()
.then(url => {
expect(url).toEqual(config.url + moduleAccessViewHashURL);
done();
})
.catch(catchErrors(done));
});
it('should make sure the language is English', done => {
nightmare
.changeLanguageToEnglish()
.then(() => {
done();
})
.catch(catchErrors(done));
});
it('should click on the Clients button of the top bar menu', done => {
nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.clientsButton)
.wait(selectors.clientsIndex.createClientButton)
.url()
.then(url => {
expect(url).toEqual(config.url + '#!/clients');
done();
})
.catch(catchErrors(done));
});
it('should search for the user Petter Parker', done => {
nightmare
.wait(selectors.clientsIndex.searchResult)
.type(selectors.clientsIndex.searchClientInput, 'Petter Parker')
.click(selectors.clientsIndex.searchButton)
.waitForNumberOfElements(selectors.clientsIndex.searchResult, 1)
.countSearchResults(selectors.clientsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
done();
})
.catch(catchErrors(done));
});
it(`should click on the search result to access to the client's greuge`, done => {
nightmare
.waitForTextInElement(selectors.clientsIndex.searchResult, 'Petter Parker')
.waitToClick(selectors.clientsIndex.searchResult)
.waitToClick(selectors.greuge.greugeButton)
.waitForURL('greuge/list')
.url()
.then(url => {
expect(url).toContain('greuge/list');
done();
})
.catch(catchErrors(done));
});
it(`should click on the add greuge button`, done => {
nightmare
.waitToClick(selectors.greuge.addGreugeFloatButton)
.waitForURL('greuge/create')
.url()
.then(url => {
expect(url).toContain('greuge/create');
done();
})
.catch(catchErrors(done));
});
it(`should receive an error if all fields are empty but date on submit`, done => {
nightmare
.click(selectors.credit.saveButton)
.wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => {
expect(result).toContain('Some fields are invalid');
done();
})
.catch(catchErrors(done));
});
it(`should receive an error if all fields are empty but date and amount on submit`, done => {
nightmare
.type(selectors.greuge.amountInput, 999)
.click(selectors.greuge.saveButton)
.wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => {
expect(result).toContain('Some fields are invalid');
done();
})
.catch(catchErrors(done));
});
it(`should receive an error if all fields are empty but date and description on submit`, done => {
nightmare
.clearInput(selectors.greuge.amountInput)
.type(selectors.greuge.descriptionInput, 'new armor for Batman!')
.click(selectors.greuge.saveButton)
.wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => {
expect(result).toContain('Some fields are invalid');
done();
})
.catch(catchErrors(done));
});
it(`should receive an error if all fields are empty but date and type on submit`, done => {
nightmare
.clearInput(selectors.greuge.descriptionInput)
.waitToClick(selectors.greuge.typeInput)
.waitToClick(selectors.greuge.typeSecondOption)
.click(selectors.greuge.saveButton)
.wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => {
expect(result).toContain('Some fields are invalid');
done();
})
.catch(catchErrors(done));
});
it(`should create a new greuge with all its data`, done => {
nightmare
.type(selectors.greuge.amountInput, 999)
.type(selectors.greuge.descriptionInput, 'new armor for Batman!')
.click(selectors.greuge.saveButton)
.wait(selectors.globalItems.snackbarIsActive)
.getInnerText(selectors.globalItems.snackbarIsActive)
.then(result => {
expect(result).toContain('Data saved!');
done();
})
.catch(catchErrors(done));
});
it('should confirm the greuge was added to the list', done => {
nightmare
.waitForSnackbarReset()
.wait(selectors.greuge.firstGreugeText)
.getInnerText(selectors.greuge.firstGreugeText)
.then(value => {
expect(value).toContain(999);
expect(value).toContain('new armor for Batman!');
expect(value).toContain('Diff');
done();
})
.catch(catchErrors(done));
});
});

View File

@ -0,0 +1,99 @@
import config from '../helpers/config.js';
import createNightmare from '../helpers/nightmare';
import selectors from '../helpers/selectors.js';
import {catchErrors} from '../../services/utils/jasmineHelpers';
const nightmare = createNightmare();
const moduleAccessViewHashURL = '#!/';
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
describe('mandate path', () => {
describe('warm up', () => {
it('should warm up login and fixtures', done => {
nightmare
.login()
.waitForURL(moduleAccessViewHashURL)
.waitToClick(selectors.globalItems.logOutButton)
.then(() => {
done();
})
.catch(catchErrors(done));
});
});
it('should log in', done => {
nightmare
.login()
.waitForURL(moduleAccessViewHashURL)
.url()
.then(url => {
expect(url).toEqual(config.url + moduleAccessViewHashURL);
done();
})
.catch(catchErrors(done));
});
it('should make sure the language is English', done => {
nightmare
.changeLanguageToEnglish()
.then(() => {
done();
})
.catch(catchErrors(done));
});
it('should click on the Clients button of the top bar menu', done => {
nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.clientsButton)
.wait(selectors.clientsIndex.createClientButton)
.url()
.then(url => {
expect(url).toEqual(config.url + '#!/clients');
done();
})
.catch(catchErrors(done));
});
it('should search for the user Petter Parker', done => {
nightmare
.wait(selectors.clientsIndex.searchResult)
.type(selectors.clientsIndex.searchClientInput, 'Petter Parker')
.click(selectors.clientsIndex.searchButton)
.waitForNumberOfElements(selectors.clientsIndex.searchResult, 1)
.countSearchResults(selectors.clientsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
done();
})
.catch(catchErrors(done));
});
it(`should click on the search result to access to the client's mandate`, done => {
nightmare
.waitForTextInElement(selectors.clientsIndex.searchResult, 'Petter')
.waitToClick(selectors.clientsIndex.searchResult)
.waitToClick(selectors.mandate.mandateButton)
.waitForURL('mandate')
.url()
.then(url => {
expect(url).toContain('mandate');
done();
})
.catch(catchErrors(done));
});
it('should confirm the client has a mandate of the CORE type', done => {
nightmare
.wait(selectors.mandate.firstMandateText)
.getInnerText(selectors.mandate.firstMandateText)
.then(value => {
expect(value).toContain('1');
expect(value).toContain('WAY');
expect(value).toContain('CORE');
done();
})
.catch(catchErrors(done));
});
});

View File

@ -18,8 +18,8 @@ var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
jasmine.loadConfig({ jasmine.loadConfig({
spec_files: [ spec_files: [
'./e2e/helpers/extensions.js', './e2e/**/*[sS]pec.js',
'./e2e/**/*[sS]pec.js' './e2e/helpers/extensions.js'
], ],
helpers: [ helpers: [
'/services/utils/jasmineHelpers.js' '/services/utils/jasmineHelpers.js'

View File

@ -1,4 +1,5 @@
var gulp = require('gulp'); var gulp = require('gulp');
const jasmine = require('gulp-jasmine');
var gutil = require('gulp-util'); var gutil = require('gulp-util');
var wrap = require('gulp-wrap'); var wrap = require('gulp-wrap');
var concat = require('gulp-concat'); var concat = require('gulp-concat');
@ -37,6 +38,15 @@ gulp.task('client', ['clean'], function() {
return gulp.start('watch', 'routes', 'locales', 'webpack-dev-server'); return gulp.start('watch', 'routes', 'locales', 'webpack-dev-server');
}); });
gulp.task('nginxRestart', callback => {
let isWindows = /^win/.test(process.platform);
let command = isWindows ? '.\\dev.cmd' : './dev.sh';
exec(command, (err, stdout, stderr) => {
console.log(stdout);
callback(err);
});
});
gulp.task('services', () => { gulp.task('services', () => {
process.env.NODE_ENV = gutil.env.env || 'development'; process.env.NODE_ENV = gutil.env.env || 'development';
const pathServices = './services/'; const pathServices = './services/';
@ -49,6 +59,25 @@ gulp.task('services', () => {
}); });
}); });
gulp.task('clientDev', callback => {
runSequence('nginxRestart', 'client', callback);
});
gulp.task('servicesDev', callback => {
let isWindows = /^win/.test(process.platform);
let command = isWindows ? 'docker inspect dblocal | findstr Status' : 'docker inspect dblocal | grep Status';
gutil.env.env = 'test';
exec(command, (err, stdout, stderr) => {
let isNotRunning = !stdout.includes('running');
if (isNotRunning) {
runSequence('docker', 'waitForMySQL', 'services');
} else {
runSequence('services');
}
callback(err);
});
});
gulp.task('clean', function() { gulp.task('clean', function() {
return del([`${buildDir}/*`, `!${buildDir}/templates`, `!${buildDir}/images`], {force: true}); return del([`${buildDir}/*`, `!${buildDir}/templates`, `!${buildDir}/images`], {force: true});
}); });
@ -154,34 +183,33 @@ gulp.task('test', callback => {
// e2e tests // e2e tests
gulp.task('e2e', callback => { gulp.task('e2e', callback => {
runSequence('docker', 'runDockerLogs', 'endToEndTests', callback); runSequence('docker', 'waitForMySQL', 'endToEndTests', callback);
}); });
gulp.task('runDockerLogs', callback => { gulp.task('waitForMySQL', callback => {
let maxInterval = 30000;
let interval = 1000;
let timer = 0; let timer = 0;
console.log('Waiting for MySQL init process...'); console.log('Waiting for MySQL init process...');
let waitForLocaldb = setInterval(() => { let waitForLocaldb = setInterval(() => {
if (timer < 15000) { if (timer < maxInterval) {
timer += 1000; timer += interval;
exec('docker logs --tail 4 dblocal', (err, stdout, stderr) => { exec('docker logs --tail 4 dblocal', (err, stdout, stderr) => {
if (stdout.includes('MySQL init process done. Ready for start up.')) { if (stdout.includes('MySQL init process done. Ready for start up.')) {
console.log('MySQL init process done.');
clearInterval(waitForLocaldb); clearInterval(waitForLocaldb);
callback(err); callback(err);
} }
}); });
} else { } else {
console.log('MySQL connection not established whithin 15 secs!'); console.log(`MySQL connection not established whithin ${maxInterval / 1000} secs!`);
clearInterval(waitForLocaldb); clearInterval(waitForLocaldb);
} }
}, 1000); }, interval);
}); });
gulp.task('endToEndTests', callback => { gulp.task('endToEndTests', callback => {
exec('npm run e2e', (err, stdout, stderr) => { gulp.src('./e2e_tests.js')
console.log(stdout); .pipe(jasmine({reporter: 'none'}));
callback(err);
});
}); });
// docker dblocal // docker dblocal

View File

@ -44,6 +44,7 @@
"gulp-concat": "^2.6.0", "gulp-concat": "^2.6.0",
"gulp-extend": "^0.2.0", "gulp-extend": "^0.2.0",
"gulp-install": "^1.1.0", "gulp-install": "^1.1.0",
"gulp-jasmine": "^3.0.0",
"gulp-print": "^2.0.1", "gulp-print": "^2.0.1",
"gulp-util": "^3.0.7", "gulp-util": "^3.0.7",
"gulp-wrap": "^0.13.0", "gulp-wrap": "^0.13.0",
@ -57,7 +58,9 @@
"karma-jasmine": "^1.1.0", "karma-jasmine": "^1.1.0",
"karma-sourcemap-loader": "^0.3.7", "karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.4", "karma-webpack": "^2.0.4",
"md5": "^2.2.1",
"merge-stream": "^1.0.1", "merge-stream": "^1.0.1",
"mysql": "^2.15.0",
"nightmare": "^2.10.0", "nightmare": "^2.10.0",
"node-sass": "^3.11.0", "node-sass": "^3.11.0",
"raw-loader": "*", "raw-loader": "*",
@ -71,8 +74,7 @@
"build": "webpack --progress --colors", "build": "webpack --progress --colors",
"dev": "webpack-dev-server --progress --colors", "dev": "webpack-dev-server --progress --colors",
"lint": "eslint ./ --cache --ignore-pattern .gitignore", "lint": "eslint ./ --cache --ignore-pattern .gitignore",
"test": "node services_tests", "test": "nodemon -q services_tests.js -w services",
"testWatcher": "nodemon -q services_tests.js -w services",
"e2e": "node e2e_tests" "e2e": "node e2e_tests"
} }
} }

View File

@ -8,7 +8,6 @@
"posttest": "npm run lint && nsp check" "posttest": "npm run lint && nsp check"
}, },
"dependencies": { "dependencies": {
"md5": "^2.2.1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -1,4 +1,5 @@
var app = require('../../../server/server'); let app = require('../../../server/server');
let md5 = require('md5');
module.exports = function(Client) { module.exports = function(Client) {
Client.remoteMethod('createUserProfile', { Client.remoteMethod('createUserProfile', {
@ -23,7 +24,7 @@ module.exports = function(Client) {
let user = { let user = {
name: data.userName, name: data.userName,
email: firstEmail, email: firstEmail,
password: parseInt(Math.random() * 100000000000000) password: md5(parseInt(Math.random() * 100000000000000))
}; };
app.models.Account.beginTransaction('READ COMMITTED', (error, transaction) => { app.models.Account.beginTransaction('READ COMMITTED', (error, transaction) => {

View File

@ -1,31 +1,77 @@
import app from '../../../../server/server';
import {catchErrors} from '../../../../../../services/utils/jasmineHelpers'; import {catchErrors} from '../../../../../../services/utils/jasmineHelpers';
let app = require('../../../../server/server'); import {restoreFixtures} from '../../../../../../services/db/testing_fixtures';
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
describe('Client Create()', () => { describe('Client Create()', () => {
let data = { beforeEach(() => {
name: 'MaxEisenhardt', restoreFixtures();
userName: 'Magneto', });
email: 'magneto@marvel.com',
fi: 'X-tax number', let newAccountData = {
socialName: 'The X-Men' name: 'Wade',
userName: 'Deadpool',
email: 'Deadpool@marvel.com',
fi: 'DP',
socialName: 'Deadpool Marvel'
}; };
it('should createa new account', done => { it('should find Charles Xavier', done => {
app.models.Client.createUserProfile(data, () => { app.models.Account.findOne({where: {name: 'CharlesXavier'}})
app.models.Account.findOne({where: {name: data.userName}}) .then(account => {
.then(account => { expect(account.name).toEqual('CharlesXavier');
expect(account.name).toEqual(data.userName); done();
app.models.Client.findOne({where: {name: data.name}}) })
.then(client => {
expect(client.id).toEqual(account.id);
expect(client.name).toEqual(data.name);
expect(client.email).toEqual(data.email);
expect(client.fi).toEqual(data.fi);
expect(client.socialName).toEqual(data.socialName);
done();
});
})
.catch(catchErrors(done)); .catch(catchErrors(done));
});
it("should not find Deadpool as he's not created yet", done => {
app.models.Account.findOne({where: {name: newAccountData.userName}})
.then(account => {
expect(account).toEqual(null);
app.models.Client.findOne({where: {name: newAccountData.name}})
.then(client => {
expect(client).toEqual(null);
done();
});
})
.catch(catchErrors(done));
});
it('should not be able to create a user if exists', done => {
app.models.Client.findOne({where: {name: 'Charles Xavier'}})
.then(client => {
let formerAccountData = {
name: client.name,
userName: client.userName,
email: client.email,
fi: client.fi,
socialName: client.socialName
};
expect(app.models.Client.createUserProfile(formerAccountData)).toBeFalsy();
done();
}); });
}); });
// awaiting for fixtures
// it('should create a new account', done => {
// app.models.Client.createUserProfile(data => {
// app.models.Account.findOne({where: {name: data.userName}})
// .then(account => {
// expect(account.name).toEqual(data.userName);
// app.models.Client.findOne({where: {name: data.name}})
// .then(client => {
// expect(client.id).toEqual(account.id);
// expect(client.name).toEqual(data.name);
// expect(client.email).toEqual(data.email);
// expect(client.fi).toEqual(data.fi);
// expect(client.socialName).toEqual(data.socialName);
// done();
// });
// })
// .catch(catchErrors(done));
// });
// });
}); });

View File

@ -8,9 +8,9 @@ module.exports = function(Self) {
ctx.instance.created = Date(); ctx.instance.created = Date();
let token = ctx.options.accessToken; let token = ctx.options.accessToken;
let userId = token && token.userId; let userId = token && token.userId;
let app = require('../../server/server'); let app = require('../../server/server');
let Employee = app.models.Employee; let Employee = app.models.Employee;
Employee.findOne({where: {userFk: userId}}, function (err, user){ Employee.findOne({where: {userFk: userId}}, (err, user) => {
if (user) { if (user) {
ctx.instance.employeeFk = user.id; ctx.instance.employeeFk = user.id;
next(); next();

View File

@ -18,15 +18,9 @@ module.exports = function(Self) {
// Validations // Validations
Self.validatesUniquenessOf('name', {
message: 'El nombre debe ser único'
});
Self.validatesUniquenessOf('fi', { Self.validatesUniquenessOf('fi', {
message: 'El NIF/CIF debe ser único' message: 'El NIF/CIF debe ser único'
}); });
Self.validatesPresenceOf('socialName', {
message: 'Debe especificarse la razón social'
});
Self.validatesUniquenessOf('socialName', { Self.validatesUniquenessOf('socialName', {
message: 'La razón social debe ser única' message: 'La razón social debe ser única'
}); });

View File

@ -22,7 +22,8 @@
"description": "Fiscal indentifier" "description": "Fiscal indentifier"
}, },
"socialName": { "socialName": {
"type": "string" "type": "string",
"required": true
}, },
"contact": { "contact": {
"type": "string" "type": "string"

View File

@ -1,4 +1,9 @@
module.exports = function(Self) { module.exports = function(Self) {
require('../methods/greuge/filter.js')(Self); require('../methods/greuge/filter.js')(Self);
require('../methods/greuge/totalGreuge.js')(Self); require('../methods/greuge/totalGreuge.js')(Self);
Self.validatesLengthOf('description', {
max: 45,
message: 'La description debe tener maximo 45 caracteres'
});
}; };

View File

@ -14,10 +14,12 @@
"description": "Identifier" "description": "Identifier"
}, },
"description": { "description": {
"type": "String" "type": "String",
"required": true
}, },
"amount": { "amount": {
"type": "Number" "type": "Number",
"required": true
}, },
"shipped": { "shipped": {
"type": "date" "type": "date"
@ -35,7 +37,8 @@
"greugeType": { "greugeType": {
"type": "belongsTo", "type": "belongsTo",
"model": "GreugeType", "model": "GreugeType",
"foreignKey": "greugeTypeFk" "foreignKey": "greugeTypeFk",
"required": true
} }
} }
} }

View File

@ -1,6 +1,7 @@
FROM mysql:5.6.37 FROM mysql:5.6.37
ENV MYSQL_ALLOW_EMPTY_PASSWORD yes ENV MYSQL_ALLOW_EMPTY_PASSWORD yes
ENV TZ GMT-1
COPY localDB01StructureAccount.sql /docker-entrypoint-initdb.d COPY localDB01StructureAccount.sql /docker-entrypoint-initdb.d
COPY localDB02StructureVn2008.sql /docker-entrypoint-initdb.d COPY localDB02StructureVn2008.sql /docker-entrypoint-initdb.d

View File

@ -459,7 +459,7 @@ INSERT INTO `vn2008`.`empresa_grupo`(`empresa_grupo_id`, `grupo`)
INSERT INTO `vn2008`.`empresa`(`id`, `abbreviation`, `registro`, `gerente_id`, `alta`, `baja`, `logo`, `oficial`, `cyc`, `rgb`, `mail`, `cuno`, `ODBC_DATE`, `Id_Cliente`, `digito_factura`, `Id_Proveedores_account`, `morosidad`, `empresa_grupo`) INSERT INTO `vn2008`.`empresa`(`id`, `abbreviation`, `registro`, `gerente_id`, `alta`, `baja`, `logo`, `oficial`, `cyc`, `rgb`, `mail`, `cuno`, `ODBC_DATE`, `Id_Cliente`, `digito_factura`, `Id_Proveedores_account`, `morosidad`, `empresa_grupo`)
VALUES VALUES
('442', 'WAY', 'Wayne Industries, Inc. operates as a warehouse for steel products. Wayne Industries, Inc. was founded in 1989 and is based in Wayne, Michigan.', '2', '1989-11-19', NULL, NULL, '1', '1', '00FF00', 'BruceWayne@verdnatura.es', NULL, '1989-08-11 12:31:22', '10', '1', NULL, '1', '1'); (442, 'WAY', 'Wayne Industries, Inc. operates as a warehouse for steel products. Wayne Industries, Inc. was founded in 1989 and is based in Wayne, Michigan.', '2', '1989-11-19', NULL, NULL, '1', '1', '00FF00', 'BruceWayne@verdnatura.es', NULL, '1989-08-11 12:31:22', '10', '1', NULL, '1', '1');
INSERT INTO `salix`.`Ticket`(`id`, `agencyFk`, `employeeFk`, `date`, `hour`, `clientFk`, `addressFk`) INSERT INTO `salix`.`Ticket`(`id`, `agencyFk`, `employeeFk`, `date`, `hour`, `clientFk`, `addressFk`)
VALUES VALUES
@ -525,5 +525,5 @@ INSERT INTO `vn`.`mandateType`(`id`, `name`)
INSERT INTO `vn`.`mandate`(`id`, `clientFk`, `companyFk`, `code`, `created`, `mandateTypeFk`) INSERT INTO `vn`.`mandate`(`id`, `clientFk`, `companyFk`, `code`, `created`, `mandateTypeFk`)
VALUES VALUES
(1, 1, 442, '1-1', CURDATE(), 2); (1, 2, 442, '1-1', CURDATE(), 2);

View File

@ -0,0 +1,16 @@
let mysql = require('mysql');
let connection = mysql.createConnection({
multipleStatements: false,
host: 'localhost',
user: 'root',
password: '',
database: 'salix'
});
export function restoreFixtures() {
// connection.connect();
// connection.query('CALL truncateDatabase');
// connection.disconect();
// console.log('fixtures restored');
}

View File

@ -18,10 +18,10 @@
} }
}, },
"relations": { "relations": {
"taxGroup": { "taxClass": {
"type": "belongsTo", "type": "belongsTo",
"model": "TaxGroup", "model": "TaxClass",
"foreignKey": "taxGroupFk" "foreignKey": "taxClassFk"
}, },
"taxCode": { "taxCode": {
"type": "belongsTo", "type": "belongsTo",

View File

@ -1,3 +1,6 @@
module.exports = function(Self) { module.exports = function(Self) {
require('../methods/item/filter.js')(Self); require('../methods/item/filter.js')(Self);
Self.validatesPresenceOf('name', {message: 'Cannot be blank'});
Self.validatesPresenceOf('originFk', {message: 'Cannot be blank'});
}; };

View File

@ -14,7 +14,8 @@
"description": "Identifier" "description": "Identifier"
}, },
"name": { "name": {
"type": "String" "type": "String",
"required": true
}, },
"size": { "size": {
"type": "Number" "type": "Number"

View File

@ -1,9 +1,9 @@
{ {
"name": "TaxGroup", "name": "TaxClass",
"base": "VnModel", "base": "VnModel",
"options": { "options": {
"mysql": { "mysql": {
"table": "taxGroup", "table": "taxClass",
"database": "vn" "database": "vn"
} }
}, },

View File

@ -42,7 +42,7 @@
"Intrastat": { "Intrastat": {
"dataSource": "vn" "dataSource": "vn"
}, },
"TaxGroup": { "TaxClass": {
"dataSource": "vn" "dataSource": "vn"
}, },
"TaxCode": { "TaxCode": {

View File

@ -36,7 +36,7 @@ module.exports = function(app) {
for (let validation of validations[fieldName]) { for (let validation of validations[fieldName]) {
let options = validation.options; let options = validation.options;
if ((options && options.async) || if ((options && options.async) ||
(validation.validation == 'custom' && !validation.isExportable)) (validation.validation == 'custom' && !validation.isExportable))
continue; continue;

View File

@ -23,5 +23,4 @@
"connectTimeout": 20000, "connectTimeout": 20000,
"acquireTimeout": 20000 "acquireTimeout": 20000
} }
} }

View File

@ -63,7 +63,7 @@ module.exports = {
console.log('Mail sent ' + info.messageId + ' [' + info.response + ']'); console.log('Mail sent ' + info.messageId + ' [' + info.response + ']');
cb(); cb();
} catch(e) { } catch (e) {
throw e; throw e;
} }
}); });
@ -85,7 +85,7 @@ module.exports = {
params.attachments.forEach(function(attachment) { params.attachments.forEach(function(attachment) {
result.attachments.push(attachment); result.attachments.push(attachment);
}); });
this.send(result.recipient, result.subject, result.body, result.attachments, params, error => { this.send(result.recipient, result.subject, result.body, result.attachments, params, error => {
if (error) if (error)
return cb(error); return cb(error);

View File

@ -7,7 +7,7 @@ function getFile(fileName) {
try { try {
let envFile = 'datasources.development.json'; let envFile = 'datasources.development.json';
if (process.env.NODE_ENV === 'test') if (process.env.NODE_ENV === 'test')
envFile = 'datasources.test.json'; envFile = 'datasources.test.json';

View File

@ -1,4 +1,4 @@
module.exports = function(Self) { module.exports = function(Self) {
require('../methods/ticket-state/change-state.js')(Self); require('../methods/ticket-state/change-state.js')(Self);
}; };

View File

@ -1,5 +1,7 @@
require('babel-core/register')({presets: ['es2015']}); require('babel-core/register')({presets: ['es2015']});
process.env.NODE_ENV = 'test';
process.on('warning', warning => { process.on('warning', warning => {
console.log(warning.name); console.log(warning.name);
console.log(warning.message); console.log(warning.message);
@ -17,13 +19,12 @@ var jasmine = new Jasmine();
var SpecReporter = require('jasmine-spec-reporter').SpecReporter; var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
jasmine.loadConfig({ jasmine.loadConfig({
spec_dir: 'services/', spec_dir: 'services',
spec_files: [ spec_files: [
'**/specs/*[sS]pec.js' 'client/common/**/*[sS]pec.js'
], ],
helpers: [ helpers: [
// to implement '/services/utils/jasmineHelpers.js'
// '/api/utils/jasmineHelpers.js'
] ]
}); });
@ -36,6 +37,5 @@ jasmine.addReporter(new SpecReporter({
} }
})); }));
exports.start = () => { jasmine.execute();
jasmine.execute();
};