Merge branch 'dev' of https://git.verdnatura.es/salix into dev

This commit is contained in:
joan 2018-11-05 15:06:24 +01:00
commit 0ffa39e55b
38 changed files with 1304 additions and 1746 deletions

4
.vscode/launch.json vendored
View File

@ -4,7 +4,9 @@
{ {
"type": "node", "type": "node",
"request": "attach", "request": "attach",
"name": "Attach" "name": "Attach",
"restart": true,
"timeout": 50000
}, { }, {
"type": "node", "type": "node",
"request": "attach", "request": "attach",

View File

@ -3,11 +3,18 @@
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one
label="Name" label="General search"
model="filter.name" model="filter.search"
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Name"
model="filter.name">
</vn-textfield>
</vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete
vn-one vn-one

View File

@ -3,11 +3,18 @@
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one
label="Client" label="General search"
model="filter.client" model="filter.search"
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Client"
model="filter.client">
</vn-textfield>
</vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one

View File

@ -7,83 +7,4 @@
data="$ctrl.logs"> data="$ctrl.logs">
</vn-crud-model> </vn-crud-model>
<vn-vertical> <vn-log model="model"></vn-log>
<vn-card pad-large>
<vn-vertical>
<vn-title>History</vn-title>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="creationDate" default-order="DESC">Date</vn-th>
<vn-th field="userFk" class="expendable">Changed by</vn-th>
<vn-th field="changedModel" class="expendable">Model</vn-th>
<vn-th field="action" class="expendable">Action</vn-th>
<vn-th field="changedModelValue" class="expendable">Instance</vn-th>
<vn-th>Before</vn-th>
<vn-th>After</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="clientLog in $ctrl.logs">
<vn-td>
{{::clientLog.creationDate | date:'dd/MM/yyyy HH:mm'}}
<div class="changes">
<div>
<span translate class="label">Changed by</span><span class="label">: </span>
<span translate class="value">{{::clientLog.user.name}}</span>
</div>
<div>
<span translate class="label">Model</span><span class="label">: </span>
<span translate class="value">{{::clientLog.changedModel}}</span>
</div>
<div>
<span translate class="label">Action</span><span class="label">: </span>
<span translate class="value">{{::clientLog.action}}</span>
</div>
<div>
<span translate class="label">Instance</span><span class="label">: </span>
<span translate class="value">{{::clientLog.changedModelValue}}</span>
</div>
</div>
</vn-td>
<vn-td class="expendable">
{{::clientLog.user.name}}
</vn-td>
<vn-td class="expendable">
{{::clientLog.changedModel}}
</vn-td>
<vn-td translate class="expendable">
{{::clientLog.action}}
</vn-td>
<vn-td class="expendable">
{{::clientLog.changedModelValue}}
</vn-td>
<vn-td class="before">
<vn-one ng-repeat="old in clientLog.oldProperties">
<div>
<span translate class="label">{{::old.key}}</span><span class="label">: </span>
<span translate class="value">{{::old.value}}</span>
</div>
</vn-one>
</vn-td>
<vn-td class="after">
<vn-one ng-repeat="new in clientLog.newProperties">
<div>
<span translate class="label">{{::new.key}}</span><span class="label">: </span>
<span translate class="value">{{::new.value}}</span>
</div>
</vn-one>
</vn-td>
</vn-tr>
</vn-tbody>
<vn-empty-rows ng-if="model.data.length === 0" translate>
No results
</vn-empty-rows>
</vn-table>
</vn-vertical>
<vn-pagination
model="model"
scroll-selector="ui-view">
</vn-pagination>
</vn-card>
</vn-vertical>

View File

@ -1,5 +1,4 @@
import ngModule from '../module'; import ngModule from '../module';
import './style.scss';
class Controller { class Controller {
constructor($scope, $stateParams) { constructor($scope, $stateParams) {
@ -22,18 +21,17 @@ class Controller {
set logs(value) { set logs(value) {
this._logs = value; this._logs = value;
if (this.logs) { if (this.logs)
this.logs.forEach((log) => { this.logs.forEach(log => {
log.oldProperties = this.getInstance(log.oldInstance); log.oldProperties = this.getInstance(log.oldInstance);
log.newProperties = this.getInstance(log.newInstance); log.newProperties = this.getInstance(log.newInstance);
}); });
}
} }
getInstance(instance) { getInstance(instance) {
const properties = []; const properties = [];
Object.keys(instance).forEach((property) => { Object.keys(instance).forEach(property => {
properties.push({key: property, value: instance[property]}); properties.push({key: property, value: instance[property]});
}); });

View File

@ -1,22 +1,61 @@
<div pad-large style="min-width: 30em"> <div pad-large style="min-width: 30em">
<form ng-submit="$ctrl.onSearch()"> <form ng-submit="$ctrl.onSearch()">
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Client id" model="filter.id" vn-focus></vn-textfield> <vn-textfield
<vn-textfield vn-one label="Tax number" model="filter.fi"></vn-textfield> vn-one
label="General search"
model="filter.search"
vn-focus>
</vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Name" model="filter.name"></vn-textfield> <vn-textfield
vn-one
label="Client id"
model="filter.id">
</vn-textfield>
<vn-textfield
vn-one
label="Tax number"
model="filter.fi">
</vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Social name" model="filter.socialName"></vn-textfield> <vn-textfield
vn-one label="Name"
model="filter.name">
</vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Town/City" model="filter.city"></vn-textfield> <vn-textfield
<vn-textfield vn-one label="Postcode" model="filter.postcode"></vn-textfield> vn-one
label="Social name"
model="filter.socialName">
</vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Email" model="filter.email"></vn-textfield> <vn-textfield
<vn-textfield vn-one label="Phone" model="filter.phone"></vn-textfield> vn-one
label="Town/City"
model="filter.city">
</vn-textfield>
<vn-textfield
vn-one
label="Postcode"
model="filter.postcode">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Email"
model="filter.email">
</vn-textfield>
<vn-textfield
vn-one
label="Phone"
model="filter.phone">
</vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal margin-large-top> <vn-horizontal margin-large-top>
<vn-submit label="Search"></vn-submit> <vn-submit label="Search"></vn-submit>

View File

@ -135,14 +135,14 @@ export default class CrudModel extends ModelProxy {
if (!this.isChanged) if (!this.isChanged)
return null; return null;
let create = []; let deletes = [];
let update = []; let updates = [];
let remove = []; let creates = [];
let pk = this.primaryKey; let pk = this.primaryKey;
for (let row of this.removed) for (let row of this.removed)
remove.push(row.$orgRow[pk]); deletes.push(row.$orgRow[pk]);
for (let row of this._data) for (let row of this._data)
if (row.$isNew) { if (row.$isNew) {
@ -150,22 +150,22 @@ export default class CrudModel extends ModelProxy {
for (let prop in row) for (let prop in row)
if (prop.charAt(0) !== '$') if (prop.charAt(0) !== '$')
data[prop] = row[prop]; data[prop] = row[prop];
create.push(data); creates.push(data);
} else if (row.$oldData) { } else if (row.$oldData) {
let data = {}; let data = {};
for (let prop in row.$oldData) for (let prop in row.$oldData)
data[prop] = row[prop]; data[prop] = row[prop];
update.push({ updates.push({
data, data,
where: {[pk]: row.$orgRow[pk]} where: {[pk]: row.$orgRow[pk]}
}); });
} }
let changes = { let changes = {deletes, updates, creates};
create: create,
update: update, for (let prop in changes)
delete: remove if (changes[prop].length === 0)
}; changes[prop] = undefined;
return changes; return changes;
} }

View File

@ -42,3 +42,4 @@ import './chip';
import './input-number'; import './input-number';
import './input-time'; import './input-time';
import './fetched-tags'; import './fetched-tags';
import './log';

View File

@ -0,0 +1,80 @@
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>History</vn-title>
<vn-table model="$ctrl.model">
<vn-thead>
<vn-tr>
<vn-th field="creationDate" default-order="DESC">Date</vn-th>
<vn-th field="userFk" class="expendable">Changed by</vn-th>
<vn-th field="changedModel" class="expendable">Model</vn-th>
<vn-th field="action" class="expendable">Action</vn-th>
<vn-th field="changedModelValue" class="expendable">Instance</vn-th>
<vn-th>Before</vn-th>
<vn-th>After</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="log in $ctrl.model.data">
<vn-td>
{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}
<div class="changes">
<div>
<span translate class="label">Changed by</span><span class="label">: </span>
<span translate class="value">{{::log.user.name}}</span>
</div>
<div>
<span translate class="label">Model</span><span class="label">: </span>
<span translate class="value">{{::log.changedModel}}</span>
</div>
<div>
<span translate class="label">Action</span><span class="label">: </span>
<span translate class="value">{{::log.action}}</span>
</div>
<div>
<span translate class="label">Instance</span><span class="label">: </span>
<span translate class="value">{{::log.changedModelValue}}</span>
</div>
</div>
</vn-td>
<vn-td class="expendable">
{{::log.user.name}}
</vn-td>
<vn-td class="expendable">
{{::log.changedModel}}
</vn-td>
<vn-td translate class="expendable">
{{::log.action}}
</vn-td>
<vn-td class="expendable">
{{::log.changedModelValue}}
</vn-td>
<vn-td class="before">
<vn-one ng-repeat="old in log.oldProperties">
<div>
<span translate class="label">{{::old.key}}</span><span class="label">: </span>
<span translate class="value">{{::old.value}}</span>
</div>
</vn-one>
</vn-td>
<vn-td class="after">
<vn-one ng-repeat="new in log.newProperties">
<div>
<span translate class="label">{{::new.key}}</span><span class="label">: </span>
<span translate class="value">{{::new.value}}</span>
</div>
</vn-one>
</vn-td>
</vn-tr>
</vn-tbody>
<vn-empty-rows ng-if="$ctrl.model.data.length === 0" translate>
No results
</vn-empty-rows>
</vn-table>
</vn-vertical>
<vn-pagination
model="$ctrl.model"
scroll-selector="ui-view">
</vn-pagination>
</vn-card>
</vn-vertical>

View File

@ -0,0 +1,9 @@
import ngModule from '../../module';
import './style.scss';
ngModule.component('vnLog', {
template: require('./index.html'),
bindings: {
model: '<'
}
});

View File

@ -1,6 +1,6 @@
@import 'colors'; @import 'colors';
vn-client-log { vn-log {
vn-td { vn-td {
vertical-align: initial !important; vertical-align: initial !important;
} }

View File

@ -159,14 +159,13 @@ export default class Controller extends Component {
let regex = /((([\w_]+):([\w_]+))|([\w_]+):\(([\w_ ]+)\))/gi; let regex = /((([\w_]+):([\w_]+))|([\w_]+):\(([\w_ ]+)\))/gi;
let findPattern = searchString.match(regex); let findPattern = searchString.match(regex);
let remnantString = searchString.replace(regex, '').trim(); let remnantString = searchString.replace(regex, '').trim();
if (findPattern) { if (findPattern)
for (let i = 0; i < findPattern.length; i++) { for (let i = 0; i < findPattern.length; i++) {
let aux = findPattern[i].split(':'); let aux = findPattern[i].split(':');
let property = aux[0]; let property = aux[0];
let value = aux[1].replace(/\(|\)/g, ''); let value = aux[1].replace(/\(|\)/g, '');
result[property] = value.trim(); result[property] = value.trim();
} }
}
if (remnantString) if (remnantString)
result.search = remnantString; result.search = remnantString;
} }

View File

@ -12,4 +12,5 @@ Next: Next
Finalize: Finalize Finalize: Finalize
Previous: Back Previous: Back
Load more: Load more Load more: Load more
Auto-scroll interrupted, please adjust the search: Auto-scroll interrupted, please adjust the search Auto-scroll interrupted, please adjust the search: Auto-scroll interrupted, please adjust the search
General search: General search

View File

@ -23,4 +23,5 @@ Value can't be null: El valor no puede ser nulo
Value should be %s characters long: El valor debe ser de %s carácteres de longitud Value should be %s characters long: El valor debe ser de %s carácteres de longitud
Value should have a length between %s and %s: El valor debe tener una longitud de entre %s y %s Value should have a length between %s and %s: El valor debe tener una longitud de entre %s y %s
Value should have at least %s characters: El valor debe tener al menos %s carácteres Value should have at least %s characters: El valor debe tener al menos %s carácteres
Value should have at most %s characters: El valor debe tener un máximo de %s carácteres Value should have at most %s characters: El valor debe tener un máximo de %s carácteres
General search: Busqueda general

View File

@ -4,10 +4,17 @@
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one
label="Id" label="General search"
model="filter.id" model="filter.search"
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Id"
model="filter.id">
</vn-textfield>
<vn-textfield <vn-textfield
vn-one vn-one
label="Name" label="Name"

View File

@ -1,5 +1,13 @@
<div pad-large style="min-width: 30em"> <div pad-large style="min-width: 30em">
<form ng-submit="$ctrl.onSearch()"> <form ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-textfield
vn-one
label="General search"
model="filter.search"
vn-focus>
</vn-textfield>
</vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one

View File

@ -21,5 +21,5 @@ window.ngModule = function(moduleName) {
}); });
}; };
var testsContext = require.context('./', true, /\.spec\.js$/); let testsContext = require.context('./', true, /\.spec\.js$/);
testsContext.keys().forEach(testsContext); testsContext.keys().forEach(testsContext);

View File

@ -3,11 +3,18 @@
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one
label="Nickname" label="General search"
model="filter.nickname" model="filter.search"
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Nickname"
model="filter.nickname">
</vn-textfield>
</vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one

View File

@ -8,11 +8,6 @@
auto-save="true" auto-save="true"
on-save="$ctrl.onSave()"> on-save="$ctrl.onSave()">
</vn-crud-model> </vn-crud-model>
<vn-watcher
vn-id="watcher"
data="weeklies"
form="form">
</vn-watcher>
<form name="form"> <form name="form">
<div margin-medium> <div margin-medium>
<vn-card margin-medium-v pad-medium> <vn-card margin-medium-v pad-medium>

View File

@ -2,30 +2,36 @@ import ngModule from '../module';
import './style.scss'; import './style.scss';
export default class Controller { export default class Controller {
constructor($scope) { constructor($scope, vnApp, $translate) {
this.$scope = $scope; this.$scope = $scope;
this.vnApp = vnApp;
this._ = $translate;
this.ticketSelected = null; this.ticketSelected = null;
this.filter = { this.filter = {
include: [ include: {
{relation: 'ticket', relation: 'ticket',
scope: { scope: {
fields: ['id', 'clientFk', 'companyFk', 'warehouseFk'], fields: ['id', 'clientFk', 'companyFk', 'warehouseFk'],
include: [ include: [
{relation: 'client', {
scope: { relation: 'client',
fields: ['salesPersonFk', 'name'], scope: {
include: { fields: ['salesPersonFk', 'name'],
relation: 'salesPerson', include: {
fields: ['firstName', 'name'] relation: 'salesPerson',
scope: {
fields: ['id', 'firstName', 'name']
} }
} }
}, }
{relation: 'warehouse'} },
] {relation: 'warehouse'}
} ]
} }
] }
}; };
this.weekdays = [ this.weekdays = [
{id: 0, name: 'Monday'}, {id: 0, name: 'Monday'},
{id: 1, name: 'Tuesday'}, {id: 1, name: 'Tuesday'},
@ -38,7 +44,7 @@ export default class Controller {
} }
onSave() { onSave() {
this.$scope.watcher.notifySaved(); this.vnApp.showSuccess(this._.instant('Data saved!'));
} }
showClientDescriptor(event, clientFk) { showClientDescriptor(event, clientFk) {
@ -65,17 +71,9 @@ export default class Controller {
this.expeditionId = expedition.id; this.expeditionId = expedition.id;
this.$scope.deleteWeekly.show(); this.$scope.deleteWeekly.show();
} }
onSubmit() {
this.$scope.watcher.check();
this.$scope.model.save().then(() => {
this.$scope.watcher.notifySaved();
this.$scope.model.refresh();
});
}
} }
Controller.$inject = ['$scope']; Controller.$inject = ['$scope', 'vnApp', '$translate'];
ngModule.component('vnTicketWeekly', { ngModule.component('vnTicketWeekly', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -6,409 +6,356 @@ describe('Client Edit fiscalData path', () => {
describe('as employee', () => { describe('as employee', () => {
beforeAll(() => { beforeAll(() => {
return nightmare return nightmare
.waitForLogin('employee'); .waitForLogin('employee');
}); });
it('should click on the Clients button of the top bar menu', done => { it('should click on the Clients button of the top bar menu', async () => {
return nightmare const url = await nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton) .waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible) .wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.clientsButton) .waitToClick(selectors.globalItems.clientsButton)
.wait(selectors.clientsIndex.createClientButton) .wait(selectors.clientsIndex.createClientButton)
.parsedUrl() .parsedUrl();
.then(url => {
expect(url.hash).toEqual('#!/client/index'); expect(url.hash).toEqual('#!/client/index');
done();
}).catch(done.fail);
}); });
it('should search for the user Bruce Banner', done => { it('should search for the user Bruce Banner', async () => {
return nightmare const resultCount = await nightmare
.wait(selectors.clientsIndex.searchResult) .wait(selectors.clientsIndex.searchResult)
.type(selectors.clientsIndex.searchClientInput, 'Bruce Banner') .type(selectors.clientsIndex.searchClientInput, 'Bruce Banner')
.click(selectors.clientsIndex.searchButton) .click(selectors.clientsIndex.searchButton)
.waitForNumberOfElements(selectors.clientsIndex.searchResult, 1) .waitForNumberOfElements(selectors.clientsIndex.searchResult, 1)
.countElement(selectors.clientsIndex.searchResult) .countElement(selectors.clientsIndex.searchResult);
.then(result => {
expect(result).toEqual(1); expect(resultCount).toEqual(1);
done();
}).catch(done.fail);
}); });
// Confirms all addresses have EQtax false for future propagation test step 1 // Confirms all addresses have EQtax false for future propagation test step 1
it(`should click on the search result to access to the client's addresses`, () => { it(`should click on the search result to access to the client's addresses`, async () => {
return nightmare const url = await nightmare
.waitForTextInElement(selectors.clientsIndex.searchResult, 'Bruce Banner') .waitForTextInElement(selectors.clientsIndex.searchResult, 'Bruce Banner')
.waitToClick(selectors.clientsIndex.searchResult) .waitToClick(selectors.clientsIndex.searchResult)
.waitToClick(selectors.clientAddresses.addressesButton) .waitToClick(selectors.clientAddresses.addressesButton)
.waitForURL('/address/index') .waitForURL('/address/index')
.url() .url();
.then(url => {
expect(url).toContain('/address/index'); expect(url).toContain('/address/index');
});
}); });
// Confirms all addresses have EQtax false for future propagation test step 2 // Confirms all addresses have EQtax false for future propagation test step 2
it(`should click on the 1st edit icon to check EQtax isnt checked`, () => { it(`should click on the 1st edit icon to check EQtax isnt checked`, async () => {
return nightmare const result = await nightmare
.waitToClick(selectors.clientAddresses.firstEditButton) .waitToClick(selectors.clientAddresses.firstEditButton)
.wait(selectors.clientAddresses.equalizationTaxCheckboxLabel) .wait(selectors.clientAddresses.equalizationTaxCheckboxLabel)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientAddresses.equalizationTaxCheckboxLabel) }, selectors.clientAddresses.equalizationTaxCheckboxLabel);
.then(value => {
expect(value).toBeFalsy(); expect(result).toBeFalsy();
});
}); });
// Confirms all addresses have EQtax false for future propagation test step 3 // Confirms all addresses have EQtax false for future propagation test step 3
it(`should go back to addresses then select the second one and confirm the EQtax isnt checked`, () => { it(`should go back to addresses then select the second one and confirm the EQtax isnt checked`, async () => {
return nightmare const result = await nightmare
.waitToClick(selectors.clientAddresses.addressesButton) .waitToClick(selectors.clientAddresses.addressesButton)
.waitToClick(selectors.clientAddresses.secondEditButton) .waitToClick(selectors.clientAddresses.secondEditButton)
.wait(selectors.clientAddresses.equalizationTaxCheckboxLabel) .wait(selectors.clientAddresses.equalizationTaxCheckboxLabel)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientAddresses.equalizationTaxCheckboxLabel) }, selectors.clientAddresses.equalizationTaxCheckboxLabel);
.then(value => {
expect(value).toBeFalsy(); expect(result).toBeFalsy();
});
}); });
it(`should click on the fiscal data button`, () => { it(`should click on the fiscal data button`, async () => {
return nightmare const url = await nightmare
.waitToClick(selectors.clientFiscalData.fiscalDataButton) .waitToClick(selectors.clientFiscalData.fiscalDataButton)
.waitForURL('fiscal-data') .waitForURL('fiscal-data')
.url() .url();
.then(url => {
expect(url).toContain('fiscal-data'); expect(url).toContain('fiscal-data');
});
}); });
it('should not be able to edit the verified data checkbox', done => { it('should not be able to edit the verified data checkbox', async () => {
return nightmare const result = await nightmare
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).disabled; return document.querySelector(selector).disabled;
}, selectors.clientFiscalData.verifiedDataCheckboxInput) }, selectors.clientFiscalData.verifiedDataCheckboxInput);
.then(value => {
expect(value).toBeTruthy(); expect(result).toBeTruthy();
done();
}).catch(done.fail);
}); });
}); });
describe('as administrative', () => { describe('as administrative', () => {
beforeAll(() => { beforeAll(() => {
return nightmare return nightmare
.waitForLogin('administrative'); .waitForLogin('administrative');
}); });
it('should now click on the Clients button of the top bar menu', done => { it('should now click on the Clients button of the top bar menu', async () => {
return nightmare const url = await nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton) .waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible) .wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.clientsButton) .waitToClick(selectors.globalItems.clientsButton)
.wait(selectors.clientsIndex.createClientButton) .wait(selectors.clientsIndex.createClientButton)
.parsedUrl() .parsedUrl();
.then(url => {
expect(url.hash).toEqual('#!/client/index'); expect(url.hash).toEqual('#!/client/index');
done();
}).catch(done.fail);
}); });
it('should now search for the user Bruce Banner', done => { it('should now search for the user Bruce Banner', async () => {
return nightmare const resultCount = await nightmare
.wait(selectors.clientsIndex.searchResult) .wait(selectors.clientsIndex.searchResult)
.type(selectors.clientsIndex.searchClientInput, 'Bruce Banner') .type(selectors.clientsIndex.searchClientInput, 'Bruce Banner')
.click(selectors.clientsIndex.searchButton) .click(selectors.clientsIndex.searchButton)
.waitForNumberOfElements(selectors.clientsIndex.searchResult, 1) .waitForNumberOfElements(selectors.clientsIndex.searchResult, 1)
.countElement(selectors.clientsIndex.searchResult) .countElement(selectors.clientsIndex.searchResult);
.then(result => {
expect(result).toEqual(1); expect(resultCount).toEqual(1);
done();
}).catch(done.fail);
}); });
it(`should access to the client fiscal data`, () => { it(`should access to the client fiscal data`, async () => {
return nightmare const url = await nightmare
.waitForTextInElement(selectors.clientsIndex.searchResult, 'Bruce Banner') .waitForTextInElement(selectors.clientsIndex.searchResult, 'Bruce Banner')
.waitToClick(selectors.clientsIndex.searchResult) .waitToClick(selectors.clientsIndex.searchResult)
.waitToClick(selectors.clientFiscalData.fiscalDataButton) .waitToClick(selectors.clientFiscalData.fiscalDataButton)
.waitForURL('fiscal-data') .waitForURL('fiscal-data')
.url() .url();
.then(url => {
expect(url).toContain('fiscal-data'); expect(url).toContain('fiscal-data');
});
}); });
it('should edit the clients fiscal data', done => { it('should edit the clients fiscal data', async () => {
return nightmare const result = await nightmare
.wait(selectors.clientFiscalData.socialNameInput) .wait(selectors.clientFiscalData.socialNameInput)
.clearInput(selectors.clientFiscalData.socialNameInput) .clearInput(selectors.clientFiscalData.socialNameInput)
.type(selectors.clientFiscalData.socialNameInput, 'SMASH!') .type(selectors.clientFiscalData.socialNameInput, 'SMASH!')
.waitForTextInInput(selectors.clientFiscalData.socialNameInput, 'SMASH!') .waitForTextInInput(selectors.clientFiscalData.socialNameInput, 'SMASH!')
.clearInput(selectors.clientFiscalData.fiscalIdInput) .clearInput(selectors.clientFiscalData.fiscalIdInput)
.type(selectors.clientFiscalData.fiscalIdInput, '94980061C') .type(selectors.clientFiscalData.fiscalIdInput, '94980061C')
.clearInput(selectors.clientFiscalData.addressInput) .clearInput(selectors.clientFiscalData.addressInput)
.type(selectors.clientFiscalData.addressInput, 'Somewhere edited') .type(selectors.clientFiscalData.addressInput, 'Somewhere edited')
.clearInput(selectors.clientFiscalData.postcodeInput) .clearInput(selectors.clientFiscalData.postcodeInput)
.type(selectors.clientFiscalData.postcodeInput, '12345') .type(selectors.clientFiscalData.postcodeInput, '12345')
.clearInput(selectors.clientFiscalData.cityInput) .clearInput(selectors.clientFiscalData.cityInput)
.type(selectors.clientFiscalData.cityInput, 'N/A') .type(selectors.clientFiscalData.cityInput, 'N/A')
.waitToClick(selectors.clientFiscalData.countryInput) .waitToClick(selectors.clientFiscalData.countryInput)
.waitToClick(selectors.clientFiscalData.countryThirdOption) .waitToClick(selectors.clientFiscalData.countryThirdOption)
.waitToClick(selectors.clientFiscalData.provinceInput) .waitToClick(selectors.clientFiscalData.provinceInput)
.waitToClick(selectors.clientFiscalData.provinceFifthOption) .waitToClick(selectors.clientFiscalData.provinceFifthOption)
.waitToClick(selectors.clientFiscalData.activeCheckboxLabel) .waitToClick(selectors.clientFiscalData.activeCheckboxLabel)
.waitToClick(selectors.clientFiscalData.frozenCheckboxLabel) .waitToClick(selectors.clientFiscalData.frozenCheckboxLabel)
.waitToClick(selectors.clientFiscalData.hasToInvoiceCheckboxLabel) .waitToClick(selectors.clientFiscalData.hasToInvoiceCheckboxLabel)
.waitToClick(selectors.clientFiscalData.viesCheckboxInput) .waitToClick(selectors.clientFiscalData.viesCheckboxInput)
.waitToClick(selectors.clientFiscalData.invoiceByMailCheckboxLabel) .waitToClick(selectors.clientFiscalData.invoiceByMailCheckboxLabel)
.waitToClick(selectors.clientFiscalData.invoiceByAddressCheckboxInput) .waitToClick(selectors.clientFiscalData.invoiceByAddressCheckboxInput)
.waitToClick(selectors.clientFiscalData.equalizationTaxCheckboxLabel) .waitToClick(selectors.clientFiscalData.equalizationTaxCheckboxLabel)
.waitToClick(selectors.clientFiscalData.verifiedDataCheckboxInput) .waitToClick(selectors.clientFiscalData.verifiedDataCheckboxInput)
.click(selectors.clientFiscalData.saveButton) .click(selectors.clientFiscalData.saveButton)
.waitForLastSnackbar() .waitForLastSnackbar();
.then(result => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
done();
}).catch(done.fail);
}); });
it('should propagate the Equalization tax', done => { it('should propagate the Equalization tax', async () => {
return nightmare const result = await nightmare
.waitToClick(selectors.clientFiscalData.acceptPropagationButton) .waitToClick(selectors.clientFiscalData.acceptPropagationButton)
.waitForLastSnackbar() .waitForLastSnackbar();
.then(result => {
expect(result).toEqual('Equivalent tax spreaded'); expect(result).toEqual('Equivalent tax spreaded');
done();
}).catch(done.fail);
}); });
// confirm all addresses have now EQtax checked step 1 // confirm all addresses have now EQtax checked step 1
it(`should click on the addresses button to access to the client's addresses`, () => { it(`should click on the addresses button to access to the client's addresses`, async () => {
return nightmare const url = await nightmare
.waitToClick(selectors.clientAddresses.addressesButton) .waitToClick(selectors.clientAddresses.addressesButton)
.waitForURL('/address/index') .waitForURL('/address/index')
.url() .url();
.then(url => {
expect(url).toContain('/address/index'); expect(url).toContain('/address/index');
});
}); });
// confirm all addresses have now EQtax checked step 2 // confirm all addresses have now EQtax checked step 2
it(`should click on the 1st edit icon to confirm EQtax is checked`, () => { it(`should click on the 1st edit icon to confirm EQtax is checked`, async () => {
return nightmare const result = await nightmare
.waitToClick(selectors.clientAddresses.firstEditButton) .waitToClick(selectors.clientAddresses.firstEditButton)
.wait(selectors.clientAddresses.equalizationTaxCheckboxLabel) .wait(selectors.clientAddresses.equalizationTaxCheckboxLabel)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientAddresses.equalizationTaxCheckboxLabel) }, selectors.clientAddresses.equalizationTaxCheckboxLabel);
.then(value => {
expect(value).toBeTruthy(); expect(result).toBeTruthy();
});
}); });
// confirm all addresses have now EQtax checked step 3 // confirm all addresses have now EQtax checked step 3
it(`should go back to addresses then select the second one and confirm the EQtax is checked`, () => { it(`should go back to addresses then select the second one and confirm the EQtax is checked`, async () => {
return nightmare const result = await nightmare
.waitToClick(selectors.clientAddresses.addressesButton) .waitToClick(selectors.clientAddresses.addressesButton)
.waitToClick(selectors.clientAddresses.secondEditButton) .waitToClick(selectors.clientAddresses.secondEditButton)
.wait(selectors.clientAddresses.equalizationTaxCheckboxLabel) .wait(selectors.clientAddresses.equalizationTaxCheckboxLabel)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientAddresses.equalizationTaxCheckboxLabel) }, selectors.clientAddresses.equalizationTaxCheckboxLabel);
.then(value => {
expect(value).toBeTruthy(); expect(result).toBeTruthy();
});
}); });
it('should navigate back to fiscal data to confirm its name have been edited', done => { it('should navigate back to fiscal data to confirm its name have been edited', async () => {
return nightmare const result = await nightmare
.waitToClick(selectors.clientFiscalData.fiscalDataButton) .waitToClick(selectors.clientFiscalData.fiscalDataButton)
.wait(selectors.clientFiscalData.socialNameInput) .wait(selectors.clientFiscalData.socialNameInput)
.getInputValue(selectors.clientFiscalData.socialNameInput) .getInputValue(selectors.clientFiscalData.socialNameInput);
.then(result => {
expect(result).toEqual('SMASH!'); expect(result).toEqual('SMASH!');
done();
}).catch(done.fail);
}); });
it('should confirm the fiscal id have been edited', done => { it('should confirm the fiscal id have been edited', async () => {
return nightmare const result = await nightmare
.getInputValue(selectors.clientFiscalData.fiscalIdInput) .getInputValue(selectors.clientFiscalData.fiscalIdInput);
.then(result => {
expect(result).toEqual('94980061C'); expect(result).toEqual('94980061C');
done();
}).catch(done.fail);
}); });
it('should confirm the address have been edited', done => { it('should confirm the address have been edited', async () => {
return nightmare const result = await nightmare
.getInputValue(selectors.clientFiscalData.addressInput) .getInputValue(selectors.clientFiscalData.addressInput);
.then(result => {
expect(result).toEqual('Somewhere edited'); expect(result).toEqual('Somewhere edited');
done();
}).catch(done.fail);
}); });
it('should confirm the postcode have been edited', done => { it('should confirm the postcode have been edited', async () => {
return nightmare const result = await nightmare
.getInputValue(selectors.clientFiscalData.postcodeInput) .getInputValue(selectors.clientFiscalData.postcodeInput);
.then(result => {
expect(result).toEqual('12345'); expect(result).toEqual('12345');
done();
}).catch(done.fail);
}); });
it('should confirm the city have been edited', done => { it('should confirm the city have been edited', async () => {
return nightmare const result = await nightmare
.getInputValue(selectors.clientFiscalData.cityInput) .getInputValue(selectors.clientFiscalData.cityInput);
.then(result => {
expect(result).toEqual('N/A'); expect(result).toEqual('N/A');
done();
}).catch(done.fail);
}); });
it(`should confirm the country have been selected`, () => { it(`should confirm the country have been selected`, async () => {
return nightmare const result = await nightmare
.getInputValue(selectors.clientFiscalData.countryInput) .getInputValue(selectors.clientFiscalData.countryInput);
.then(result => {
expect(result).toEqual('Francia'); expect(result).toEqual('Francia');
});
}); });
it(`should confirm the province have been selected`, () => { it(`should confirm the province have been selected`, async () => {
return nightmare const result = await nightmare
.getInputValue(selectors.clientFiscalData.provinceInput) .getInputValue(selectors.clientFiscalData.provinceInput);
.then(result => {
expect(result).toEqual('Province two'); expect(result).toEqual('Province two');
});
}); });
it('should confirm active checkbox is unchecked', done => { it('should confirm active checkbox is unchecked', async () => {
return nightmare const result = await nightmare
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientFiscalData.activeCheckboxLabel) }, selectors.clientFiscalData.activeCheckboxLabel);
.then(value => {
expect(value).toBeFalsy(); expect(result).toBeFalsy();
done();
}).catch(done.fail);
}); });
it('should confirm frozen checkbox is unchecked', done => { it('should confirm frozen checkbox is unchecked', async () => {
return nightmare const result = await nightmare
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientFiscalData.frozenCheckboxLabel) }, selectors.clientFiscalData.frozenCheckboxLabel);
.then(value => {
expect(value).toBeFalsy(); expect(result).toBeFalsy();
done();
}).catch(done.fail);
}); });
it('should confirm Has to invoice checkbox is unchecked', done => { it('should confirm Has to invoice checkbox is unchecked', async () => {
return nightmare const result = await nightmare
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientFiscalData.hasToInvoiceCheckboxLabel) }, selectors.clientFiscalData.hasToInvoiceCheckboxLabel);
.then(value => {
expect(value).toBeFalsy(); expect(result).toBeFalsy();
done();
}).catch(done.fail);
}); });
it('should confirm Vies checkbox is checked', done => { it('should confirm Vies checkbox is checked', async () => {
return nightmare const result = await nightmare
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientFiscalData.viesCheckboxInput) }, selectors.clientFiscalData.viesCheckboxInput);
.then(value => {
expect(value).toBeTruthy(); expect(result).toBeTruthy();
done();
}).catch(done.fail);
}); });
it('should confirm Invoice by mail checkbox is unchecked', done => { it('should confirm Invoice by mail checkbox is unchecked', async () => {
return nightmare const result = await nightmare
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientFiscalData.invoiceByMailCheckboxLabel) }, selectors.clientFiscalData.invoiceByMailCheckboxLabel);
.then(value => {
expect(value).toBeFalsy(); expect(result).toBeFalsy();
done();
}).catch(done.fail);
}); });
it('should confirm invoice by address checkbox is unchecked', done => { it('should confirm invoice by address checkbox is unchecked', async () => {
return nightmare const result = await nightmare
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientFiscalData.invoiceByAddressCheckboxInput) }, selectors.clientFiscalData.invoiceByAddressCheckboxInput);
.then(value => {
expect(value).toBeFalsy(); expect(result).toBeFalsy();
done();
}).catch(done.fail);
}); });
it('should confirm Equalization tax checkbox is checked', done => { it('should confirm Equalization tax checkbox is checked', async () => {
return nightmare const result = await nightmare
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientFiscalData.equalizationTaxCheckboxLabel) }, selectors.clientFiscalData.equalizationTaxCheckboxLabel);
.then(value => {
expect(value).toBeTruthy(); expect(result).toBeTruthy();
done();
}).catch(done.fail);
}); });
it('should confirm Verified data checkbox is checked', done => { it('should confirm Verified data checkbox is checked', async () => {
return nightmare const result = await nightmare
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientFiscalData.verifiedDataCheckboxInput) }, selectors.clientFiscalData.verifiedDataCheckboxInput);
.then(value => {
expect(value).toBeTruthy(); expect(result).toBeTruthy();
done();
}).catch(done.fail);
}); });
// confirm invoice by address checkbox gets checked if the EQtax differs between addresses step 1 // confirm invoice by address checkbox gets checked if the EQtax differs between addresses step 1
it(`should click on the addresses button to access to the client's addresses`, () => { it(`should click on the addresses button to access to the client's addresses`, async () => {
return nightmare const url = await nightmare
.waitToClick(selectors.clientAddresses.addressesButton) .waitToClick(selectors.clientAddresses.addressesButton)
.waitForURL('/address/index') .waitForURL('/address/index')
.url() .url();
.then(url => {
expect(url).toContain('/address/index'); expect(url).toContain('/address/index');
});
}); });
// confirm invoice by address checkbox gets checked if the EQtax differs between addresses step 2 // confirm invoice by address checkbox gets checked if the EQtax differs between addresses step 2
it(`should click on the 1st edit icon to access the address details and uncheck EQtax checkbox`, () => { it(`should click on the 1st edit icon to access the address details and uncheck EQtax checkbox`, async () => {
return nightmare const result = await nightmare
.waitToClick(selectors.clientAddresses.firstEditButton) .waitToClick(selectors.clientAddresses.firstEditButton)
.waitToClick(selectors.clientAddresses.equalizationTaxCheckboxLabel) .waitToClick(selectors.clientAddresses.equalizationTaxCheckboxLabel)
.click(selectors.clientAddresses.saveButton) .click(selectors.clientAddresses.saveButton)
.waitForLastSnackbar() .waitForLastSnackbar()
.then(result => { .then(result => {
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
}); });
}); });
// confirm invoice by address checkbox gets checked if the EQtax differs between addresses step 3 // confirm invoice by address checkbox gets checked if the EQtax differs between addresses step 3
it('should navigate back to fiscal data to confirm invoice by address is now checked', done => { it('should navigate back to fiscal data to confirm invoice by address is now checked', async () => {
return nightmare const result = await nightmare
.waitToClick(selectors.clientFiscalData.fiscalDataButton) .waitToClick(selectors.clientFiscalData.fiscalDataButton)
.wait(selectors.clientFiscalData.invoiceByAddressCheckboxInput) .wait(selectors.clientFiscalData.invoiceByAddressCheckboxInput)
.evaluate(selector => { .evaluate(selector => {
return document.querySelector(selector).checked; return document.querySelector(selector).checked;
}, selectors.clientFiscalData.invoiceByAddressCheckboxInput) }, selectors.clientFiscalData.invoiceByAddressCheckboxInput);
.then(value => {
expect(value).toBeTruthy(); expect(result).toBeTruthy();
done();
}).catch(done.fail);
}); });
}); });
}); });

View File

@ -1,214 +1,212 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/nightmare'; import createNightmare from '../../helpers/nightmare';
describe('Item', () => { describe('Item summary path', () => {
describe('Summary path', () => { const nightmare = createNightmare();
const nightmare = createNightmare();
beforeAll(() => { beforeAll(() => {
nightmare nightmare
.waitForLogin('employee'); .waitForLogin('employee');
}); });
it('should access to the items index by clicking the items button', async () => { it('should access to the items index by clicking the items button', async () => {
const url = await nightmare const url = await nightmare
.click(selectors.moduleAccessView.itemsSectionButton) .click(selectors.moduleAccessView.itemsSectionButton)
.wait(selectors.itemsIndex.createItemButton) .wait(selectors.itemsIndex.createItemButton)
.parsedUrl(); .parsedUrl();
expect(url.hash).toEqual('#!/item/index'); expect(url.hash).toEqual('#!/item/index');
}); });
it('should search for the item Gem of Time', async () => { it('should search for the item Gem of Time', async () => {
const result = await nightmare const result = await nightmare
.wait(selectors.itemsIndex.searchResult) .wait(selectors.itemsIndex.searchResult)
.type(selectors.itemsIndex.searchItemInput, 'Gem of Time') .type(selectors.itemsIndex.searchItemInput, 'Gem of Time')
.click(selectors.itemsIndex.searchButton) .click(selectors.itemsIndex.searchButton)
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1) .waitForNumberOfElements(selectors.itemsIndex.searchResult, 1)
.countElement(selectors.itemsIndex.searchResult); .countElement(selectors.itemsIndex.searchResult);
expect(result).toEqual(1); expect(result).toEqual(1);
}); });
it(`should click on the search result summary button to open the item summary popup`, async () => { it(`should click on the search result summary button to open the item summary popup`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time') .waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time')
.isVisible(selectors.itemSummary.basicData) .isVisible(selectors.itemSummary.basicData)
.then((result) => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
return nightmare return nightmare
.waitToClick(selectors.itemsIndex.searchResultPreviewButton) .waitToClick(selectors.itemsIndex.searchResultPreviewButton)
.isVisible(selectors.itemSummary.basicData); .isVisible(selectors.itemSummary.basicData);
}); });
expect(result).toBeTruthy(); expect(result).toBeTruthy();
}); });
it(`should check the item summary preview shows fields from basic data`, async () => { it(`should check the item summary preview shows fields from basic data`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.basicData, 'Name: Gem of Time') .waitForTextInElement(selectors.itemSummary.basicData, 'Name: Gem of Time')
.getInnerText(selectors.itemSummary.basicData); .getInnerText(selectors.itemSummary.basicData);
expect(result).toContain('Name: Gem of Time'); expect(result).toContain('Name: Gem of Time');
}); });
it(`should check the item summary preview shows fields from tags`, async () => { it(`should check the item summary preview shows fields from tags`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.tags, 'Color: Yellow') .waitForTextInElement(selectors.itemSummary.tags, 'Color: Yellow')
.getInnerText(selectors.itemSummary.tags); .getInnerText(selectors.itemSummary.tags);
expect(result).toContain('Color: Yellow'); expect(result).toContain('Color: Yellow');
}); });
it(`should check the item summary preview shows fields from niche`, async () => { it(`should check the item summary preview shows fields from niche`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.niche, 'Warehouse One: A1') .waitForTextInElement(selectors.itemSummary.niche, 'Warehouse One: A1')
.getInnerText(selectors.itemSummary.niche); .getInnerText(selectors.itemSummary.niche);
expect(result).toContain('Warehouse One: A1'); expect(result).toContain('Warehouse One: A1');
}); });
it(`should check the item summary preview shows fields from botanical`, async () => { it(`should check the item summary preview shows fields from botanical`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.botanical, 'Botanical: Hedera helix') .waitForTextInElement(selectors.itemSummary.botanical, 'Botanical: Hedera helix')
.getInnerText(selectors.itemSummary.botanical); .getInnerText(selectors.itemSummary.botanical);
expect(result).toContain('Botanical: Hedera helix'); expect(result).toContain('Botanical: Hedera helix');
}); });
it(`should check the item summary preview shows fields from barcode`, async () => { it(`should check the item summary preview shows fields from barcode`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.barcode, '1') .waitForTextInElement(selectors.itemSummary.barcode, '1')
.getInnerText(selectors.itemSummary.barcode); .getInnerText(selectors.itemSummary.barcode);
expect(result).toContain('1'); expect(result).toContain('1');
}); });
it(`should close the summary popup`, async () => { it(`should close the summary popup`, async () => {
const result = await nightmare const result = await nightmare
.waitToClick(selectors.itemsIndex.closeItemSummaryPreview) .waitToClick(selectors.itemsIndex.closeItemSummaryPreview)
.isVisible(selectors.itemSummary.basicData); .isVisible(selectors.itemSummary.basicData);
expect(result).toBeFalsy(); expect(result).toBeFalsy();
}); });
it('should search for the item Gem of Mind', async () => { it('should search for the item Gem of Mind', async () => {
const result = await nightmare const result = await nightmare
.clearInput('body > vn-app > vn-vertical > vn-vertical > ui-view > vn-item-index > div > div > vn-card:nth-child(1) > div > vn-searchbar > form > vn-horizontal > vn-textfield > div > div > div.infix > input') .clearInput('body > vn-app > vn-vertical > vn-vertical > ui-view > vn-item-index > div > div > vn-card:nth-child(1) > div > vn-searchbar > form > vn-horizontal > vn-textfield > div > div > div.infix > input')
.click(selectors.itemsIndex.searchButton) .click(selectors.itemsIndex.searchButton)
.type(selectors.itemsIndex.searchItemInput, 'Gem of Mind') .type(selectors.itemsIndex.searchItemInput, 'Gem of Mind')
.click(selectors.itemsIndex.searchButton) .click(selectors.itemsIndex.searchButton)
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1) .waitForNumberOfElements(selectors.itemsIndex.searchResult, 1)
.countElement(selectors.itemsIndex.searchResult); .countElement(selectors.itemsIndex.searchResult);
expect(result).toEqual(1); expect(result).toEqual(1);
}); });
it(`should now click on the search result summary button to open the item summary popup`, async () => { it(`should now click on the search result summary button to open the item summary popup`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Mind') .waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Mind')
.isVisible(selectors.itemSummary.basicData) .isVisible(selectors.itemSummary.basicData)
.then((result) => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
return nightmare return nightmare
.waitToClick(selectors.itemsIndex.searchResultPreviewButton) .waitToClick(selectors.itemsIndex.searchResultPreviewButton)
.isVisible(selectors.itemSummary.basicData); .isVisible(selectors.itemSummary.basicData);
}); });
expect(result).toBeTruthy(); expect(result).toBeTruthy();
}); });
it(`should now check the item summary preview shows fields from basic data`, async () => { it(`should now check the item summary preview shows fields from basic data`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.basicData, 'Name: Gem of Mind') .waitForTextInElement(selectors.itemSummary.basicData, 'Name: Gem of Mind')
.getInnerText(selectors.itemSummary.basicData); .getInnerText(selectors.itemSummary.basicData);
expect(result).toContain('Name: Gem of Mind'); expect(result).toContain('Name: Gem of Mind');
}); });
it(`should now check the item summary preview shows fields from tags`, async () => { it(`should now check the item summary preview shows fields from tags`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.tags, 'Color: Red') .waitForTextInElement(selectors.itemSummary.tags, 'Color: Red')
.getInnerText(selectors.itemSummary.tags); .getInnerText(selectors.itemSummary.tags);
expect(result).toContain('Color: Red'); expect(result).toContain('Color: Red');
}); });
it(`should now check the item summary preview shows fields from niche`, async () => { it(`should now check the item summary preview shows fields from niche`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.niche, 'Warehouse One: A4') .waitForTextInElement(selectors.itemSummary.niche, 'Warehouse One: A4')
.getInnerText(selectors.itemSummary.niche); .getInnerText(selectors.itemSummary.niche);
expect(result).toContain('Warehouse One: A4'); expect(result).toContain('Warehouse One: A4');
}); });
it(`should now check the item summary preview shows fields from botanical`, async () => { it(`should now check the item summary preview shows fields from botanical`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.botanical, 'Botanical: -') .waitForTextInElement(selectors.itemSummary.botanical, 'Botanical: -')
.getInnerText(selectors.itemSummary.botanical); .getInnerText(selectors.itemSummary.botanical);
expect(result).toContain('Botanical: -'); expect(result).toContain('Botanical: -');
}); });
it(`should now check the item summary preview shows fields from barcode`, async () => { it(`should now check the item summary preview shows fields from barcode`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.barcode, '4') .waitForTextInElement(selectors.itemSummary.barcode, '4')
.getInnerText(selectors.itemSummary.barcode); .getInnerText(selectors.itemSummary.barcode);
expect(result).toContain('4'); expect(result).toContain('4');
}); });
it(`should now close the summary popup`, async () => { it(`should now close the summary popup`, async () => {
const result = await nightmare const result = await nightmare
.waitToClick(selectors.itemsIndex.closeItemSummaryPreview) .waitToClick(selectors.itemsIndex.closeItemSummaryPreview)
.isVisible(selectors.itemSummary.basicData); .isVisible(selectors.itemSummary.basicData);
expect(result).toBeFalsy(); expect(result).toBeFalsy();
}); });
it(`should navigate to the one of the items detailed section`, async () => { it(`should navigate to the one of the items detailed section`, async () => {
const url = await nightmare const url = await nightmare
.waitToClick(selectors.itemsIndex.searchResult) .waitToClick(selectors.itemsIndex.searchResult)
.waitForURL('summary') .waitForURL('summary')
.parsedUrl(); .parsedUrl();
expect(url.hash).toContain('summary'); expect(url.hash).toContain('summary');
}); });
it(`should check the item summary shows fields from basic data section`, async () => { it(`should check the item summary shows fields from basic data section`, async () => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.itemSummary.basicData, 'Name: Gem of Mind') .waitForTextInElement(selectors.itemSummary.basicData, 'Name: Gem of Mind')
.getInnerText(selectors.itemSummary.basicData); .getInnerText(selectors.itemSummary.basicData);
expect(result).toContain('Name: Gem of Mind'); expect(result).toContain('Name: Gem of Mind');
}); });
it(`should check the item summary shows fields from tags section`, async () => { it(`should check the item summary shows fields from tags section`, async () => {
const result = await nightmare const result = await nightmare
.getInnerText(selectors.itemSummary.tags); .getInnerText(selectors.itemSummary.tags);
expect(result).toContain('Color: Red'); expect(result).toContain('Color: Red');
}); });
it(`should check the item summary shows fields from niches section`, async () => { it(`should check the item summary shows fields from niches section`, async () => {
const result = await nightmare const result = await nightmare
.getInnerText(selectors.itemSummary.niche); .getInnerText(selectors.itemSummary.niche);
expect(result).toContain('Warehouse One: A4'); expect(result).toContain('Warehouse One: A4');
}); });
it(`should check the item summary shows fields from botanical section`, async () => { it(`should check the item summary shows fields from botanical section`, async () => {
const result = await nightmare const result = await nightmare
.getInnerText(selectors.itemSummary.botanical); .getInnerText(selectors.itemSummary.botanical);
expect(result).toContain('Botanical: -'); expect(result).toContain('Botanical: -');
}); });
it(`should check the item summary shows fields from barcodes section`, async () => { it(`should check the item summary shows fields from barcodes section`, async () => {
const result = await nightmare const result = await nightmare
.getInnerText(selectors.itemSummary.barcode); .getInnerText(selectors.itemSummary.barcode);
expect(result).toContain('4'); expect(result).toContain('4');
});
}); });
}); });

View File

@ -1,84 +1,82 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/nightmare'; import createNightmare from '../../helpers/nightmare';
describe('Item', () => { describe('Item edit tax path', () => {
describe('Edit tax path', () => { const nightmare = createNightmare();
const nightmare = createNightmare();
beforeAll(() => { beforeAll(() => {
return nightmare return nightmare
.waitForLogin('buyer'); .waitForLogin('buyer');
}); });
it('should access to the items index by clicking the items button', async () => { it('should access to the items index by clicking the items button', async () => {
const url = await nightmare const url = await nightmare
.click(selectors.moduleAccessView.itemsSectionButton) .click(selectors.moduleAccessView.itemsSectionButton)
.wait(selectors.itemsIndex.createItemButton) .wait(selectors.itemsIndex.createItemButton)
.parsedUrl(); .parsedUrl();
expect(url.hash).toEqual('#!/item/index'); expect(url.hash).toEqual('#!/item/index');
}); });
it('should search for the item Gem of Time', async () => { it('should search for the item Gem of Time', async () => {
const resultCount = await nightmare const resultCount = await nightmare
.wait(selectors.itemsIndex.searchResult) .wait(selectors.itemsIndex.searchResult)
.type(selectors.itemsIndex.searchItemInput, 'Gem of Time') .type(selectors.itemsIndex.searchItemInput, 'Gem of Time')
.click(selectors.itemsIndex.searchButton) .click(selectors.itemsIndex.searchButton)
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1) .waitForNumberOfElements(selectors.itemsIndex.searchResult, 1)
.countElement(selectors.itemsIndex.searchResult); .countElement(selectors.itemsIndex.searchResult);
expect(resultCount).toEqual(1); expect(resultCount).toEqual(1);
}); });
it(`should click on the search result to access to the item tax`, async () => { it(`should click on the search result to access to the item tax`, async () => {
const url = await nightmare const url = await nightmare
.waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time') .waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time')
.waitToClick(selectors.itemsIndex.searchResult) .waitToClick(selectors.itemsIndex.searchResult)
.waitToClick(selectors.itemTax.taxButton) .waitToClick(selectors.itemTax.taxButton)
.waitForURL('tax') .waitForURL('tax')
.url(); .url();
expect(url).toContain('tax'); expect(url).toContain('tax');
}); });
it(`should add the item tax to all countries`, async () => { it(`should add the item tax to all countries`, async () => {
const result = await nightmare const result = await nightmare
.waitToClick(selectors.itemTax.firstClassSelect) .waitToClick(selectors.itemTax.firstClassSelect)
.waitToClick(selectors.itemTax.firstClassSelectOptionTwo) .waitToClick(selectors.itemTax.firstClassSelectOptionTwo)
.waitToClick(selectors.itemTax.secondClassSelect) .waitToClick(selectors.itemTax.secondClassSelect)
.waitToClick(selectors.itemTax.secondClassSelectOptionOne) .waitToClick(selectors.itemTax.secondClassSelectOptionOne)
.waitToClick(selectors.itemTax.thirdClassSelect) .waitToClick(selectors.itemTax.thirdClassSelect)
.waitToClick(selectors.itemTax.thirdClassSelectOptionTwo) .waitToClick(selectors.itemTax.thirdClassSelectOptionTwo)
.click(selectors.itemTax.submitTaxButton) .click(selectors.itemTax.submitTaxButton)
.waitForLastSnackbar(); .waitForLastSnackbar();
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
}); });
it(`should confirm the first item tax class was edited`, async () => { it(`should confirm the first item tax class was edited`, async () => {
const firstVatType = await nightmare const firstVatType = await nightmare
.click(selectors.itemTags.tagsButton) .click(selectors.itemTags.tagsButton)
.wait(selectors.itemTags.firstTagDisabled) .wait(selectors.itemTags.firstTagDisabled)
.click(selectors.itemTax.taxButton) .click(selectors.itemTax.taxButton)
.waitToClick(selectors.itemTax.taxButton) .waitToClick(selectors.itemTax.taxButton)
.waitForTextInInput(selectors.itemTax.firstClassSelect, 'reduced') .waitForTextInInput(selectors.itemTax.firstClassSelect, 'reduced')
.getInputValue(selectors.itemTax.firstClassSelect); .getInputValue(selectors.itemTax.firstClassSelect);
expect(firstVatType).toEqual('Reduced VAT'); expect(firstVatType).toEqual('Reduced VAT');
}); });
it(`should confirm the second item tax class was edited`, async () => { it(`should confirm the second item tax class was edited`, async () => {
const secondVatType = await nightmare const secondVatType = await nightmare
.getInputValue(selectors.itemTax.secondClassSelect); .getInputValue(selectors.itemTax.secondClassSelect);
expect(secondVatType).toEqual('General VAT'); expect(secondVatType).toEqual('General VAT');
}); });
it(`should confirm the third item tax class was edited`, async () => { it(`should confirm the third item tax class was edited`, async () => {
const thirdVatType = await nightmare const thirdVatType = await nightmare
.getInputValue(selectors.itemTax.thirdClassSelect); .getInputValue(selectors.itemTax.thirdClassSelect);
expect(thirdVatType).toEqual('Reduced VAT'); expect(thirdVatType).toEqual('Reduced VAT');
});
}); });
}); });

View File

@ -1,54 +1,47 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/nightmare'; import createNightmare from '../../helpers/nightmare';
describe('Item', () => { describe('Item create tags path', () => {
describe('Create tags path', () => { const nightmare = createNightmare();
const nightmare = createNightmare();
beforeAll(() => { beforeAll(() => {
return nightmare return nightmare
.waitForLogin('buyer'); .waitForLogin('buyer');
}); });
it('should access to the items index by clicking the items button', done => { it('should access to the items index by clicking the items button', async () => {
return nightmare const url = await nightmare
.click(selectors.moduleAccessView.itemsSectionButton) .click(selectors.moduleAccessView.itemsSectionButton)
.wait(selectors.itemsIndex.createItemButton) .wait(selectors.itemsIndex.createItemButton)
.parsedUrl() .parsedUrl();
.then(url => {
expect(url.hash).toEqual('#!/item/index');
done();
}).catch(done.fail);
});
it('should search for the item Gem of Time', done => { expect(url.hash).toEqual('#!/item/index');
return nightmare });
it('should search for the item Gem of Time', async () => {
const resultCount = await nightmare
.wait(selectors.itemsIndex.searchResult) .wait(selectors.itemsIndex.searchResult)
.type(selectors.itemsIndex.searchItemInput, 'Gem of Time') .type(selectors.itemsIndex.searchItemInput, 'Gem of Time')
.click(selectors.itemsIndex.searchButton) .click(selectors.itemsIndex.searchButton)
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1) .waitForNumberOfElements(selectors.itemsIndex.searchResult, 1)
.countElement(selectors.itemsIndex.searchResult) .countElement(selectors.itemsIndex.searchResult);
.then(result => {
expect(result).toEqual(1);
done();
}).catch(done.fail);
});
it(`should click on the search result to access to the item tags`, done => { expect(resultCount).toEqual(1);
return nightmare });
it(`should click on the search result to access to the item tags`, async () => {
const url = await nightmare
.waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time') .waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time')
.waitToClick(selectors.itemsIndex.searchResult) .waitToClick(selectors.itemsIndex.searchResult)
.waitToClick(selectors.itemTags.tagsButton) .waitToClick(selectors.itemTags.tagsButton)
.waitForURL('tags') .waitForURL('tags')
.url() .url();
.then(url => {
expect(url).toContain('tags');
done();
}).catch(done.fail);
});
it(`should create a new tag and delete a former one`, done => { expect(url).toContain('tags');
return nightmare });
it(`should create a new tag and delete a former one`, async () => {
const result = await nightmare
.waitToClick(selectors.itemTags.firstRemoveTagButton) .waitToClick(selectors.itemTags.firstRemoveTagButton)
.waitToClick(selectors.itemTags.addItemTagButton) .waitToClick(selectors.itemTags.addItemTagButton)
.waitToClick(selectors.itemTags.seventhTagSelect) .waitToClick(selectors.itemTags.seventhTagSelect)
@ -57,69 +50,65 @@ describe('Item', () => {
.clearInput(selectors.itemTags.seventhRelevancyInput) .clearInput(selectors.itemTags.seventhRelevancyInput)
.type(selectors.itemTags.seventhRelevancyInput, '1') .type(selectors.itemTags.seventhRelevancyInput, '1')
.click(selectors.itemTags.submitItemTagsButton) .click(selectors.itemTags.submitItemTagsButton)
.waitForLastSnackbar() .waitForLastSnackbar();
.then(result => {
expect(result).toEqual('Data saved!');
done();
}).catch(done.fail);
});
it(`should reload tags form to check that the changes are saved`, () => { expect(result).toEqual('Data saved!');
return nightmare });
it(`should confirm the first row data is the expected one`, async () => {
let result = await nightmare
.click(selectors.itemBasicData.basicDataButton) .click(selectors.itemBasicData.basicDataButton)
.wait(selectors.itemBasicData.nameInput) .wait(selectors.itemBasicData.nameInput)
.click(selectors.itemTags.tagsButton) .click(selectors.itemTags.tagsButton)
.wait('vn-item-tags'); .wait('vn-item-tags')
}); .getProperty(selectors.itemTags.firstTagSelect, 'value');
it(`should confirm the first row data is the expected one`, async() => { expect(result).toEqual('Ancho de la base');
let tag = await nightmare.getProperty(selectors.itemTags.firstTagSelect, 'value'); result = await nightmare.getProperty(selectors.itemTags.firstValueInput, 'value');
let value = await nightmare.getProperty(selectors.itemTags.firstValueInput, 'value');
let relevancy = await nightmare.getProperty(selectors.itemTags.firstRelevancyInput, 'value');
expect(tag).toEqual('Ancho de la base'); expect(result).toEqual('50');
expect(value).toEqual('50'); result = await nightmare.getProperty(selectors.itemTags.firstRelevancyInput, 'value');
expect(relevancy).toEqual('1');
});
it(`should confirm the second row data is the expected one`, async() => { expect(result).toEqual('1');
let tag = await nightmare.getProperty(selectors.itemTags.secondTagSelect, 'value'); });
let value = await nightmare.getProperty(selectors.itemTags.secondValueInput, 'value');
let relevancy = await nightmare.getProperty(selectors.itemTags.secondRelevancyInput, 'value');
expect(tag).toEqual('Variedad'); it(`should confirm the second row data is the expected one`, async () => {
expect(value).toEqual('Gem1'); let tag = await nightmare.getProperty(selectors.itemTags.secondTagSelect, 'value');
expect(relevancy).toEqual('2'); let value = await nightmare.getProperty(selectors.itemTags.secondValueInput, 'value');
}); let relevancy = await nightmare.getProperty(selectors.itemTags.secondRelevancyInput, 'value');
it(`should confirm the second row data is the expected one`, async() => { expect(tag).toEqual('Variedad');
let tag = await nightmare.getProperty(selectors.itemTags.thirdTagSelect, 'value'); expect(value).toEqual('Gem1');
let value = await nightmare.getProperty(selectors.itemTags.thirdValueInput, 'value'); expect(relevancy).toEqual('2');
let relevancy = await nightmare.getProperty(selectors.itemTags.thirdRelevancyInput, 'value'); });
expect(tag).toEqual('Longitud(cm)'); it(`should confirm the third row data is the expected one`, async () => {
expect(value).toEqual('5'); let tag = await nightmare.getProperty(selectors.itemTags.thirdTagSelect, 'value');
expect(relevancy).toEqual('3'); let value = await nightmare.getProperty(selectors.itemTags.thirdValueInput, 'value');
}); let relevancy = await nightmare.getProperty(selectors.itemTags.thirdRelevancyInput, 'value');
it(`should confirm the fourth row data is the expected one`, async() => { expect(tag).toEqual('Longitud(cm)');
let tag = await nightmare.getProperty(selectors.itemTags.fourthTagSelect, 'value'); expect(value).toEqual('5');
let value = await nightmare.getProperty(selectors.itemTags.fourthValueInput, 'value'); expect(relevancy).toEqual('3');
let relevancy = await nightmare.getProperty(selectors.itemTags.fourthRelevancyInput, 'value'); });
expect(tag).toEqual('Proveedor'); it(`should confirm the fourth row data is the expected one`, async () => {
expect(value).toEqual('Marvel1'); let tag = await nightmare.getProperty(selectors.itemTags.fourthTagSelect, 'value');
expect(relevancy).toEqual('4'); let value = await nightmare.getProperty(selectors.itemTags.fourthValueInput, 'value');
}); let relevancy = await nightmare.getProperty(selectors.itemTags.fourthRelevancyInput, 'value');
it(`should confirm the fifth row data is the expected one`, async() => { expect(tag).toEqual('Proveedor');
let tag = await nightmare.getProperty(selectors.itemTags.fifthTagSelect, 'value'); expect(value).toEqual('Marvel1');
let value = await nightmare.getProperty(selectors.itemTags.fifthValueInput, 'value'); expect(relevancy).toEqual('4');
let relevancy = await nightmare.getProperty(selectors.itemTags.fifthRelevancyInput, 'value'); });
expect(tag).toEqual('Color'); it(`should confirm the fifth row data is the expected one`, async () => {
expect(value).toEqual('Yellow'); let tag = await nightmare.getProperty(selectors.itemTags.fifthTagSelect, 'value');
expect(relevancy).toEqual('5'); let value = await nightmare.getProperty(selectors.itemTags.fifthValueInput, 'value');
}); let relevancy = await nightmare.getProperty(selectors.itemTags.fifthRelevancyInput, 'value');
expect(tag).toEqual('Color');
expect(value).toEqual('Yellow');
expect(relevancy).toEqual('5');
}); });
}); });

View File

@ -1,111 +1,93 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/nightmare'; import createNightmare from '../../helpers/nightmare';
describe('Item', () => { describe('Item create niche path', () => {
describe('Create niche path', () => { const nightmare = createNightmare();
const nightmare = createNightmare();
beforeAll(() => { beforeAll(() => {
return nightmare return nightmare
.waitForLogin('buyer'); .waitForLogin('buyer');
}); });
it('should access to the items index by clicking the items button', done => { it('should access to the items index by clicking the items button', async () => {
return nightmare const url = await nightmare
.click(selectors.moduleAccessView.itemsSectionButton) .click(selectors.moduleAccessView.itemsSectionButton)
.wait(selectors.itemsIndex.createItemButton) .wait(selectors.itemsIndex.createItemButton)
.parsedUrl() .parsedUrl();
.then(url => {
expect(url.hash).toEqual('#!/item/index');
done();
}).catch(done.fail);
});
it('should search for the item Gem of Time', done => { expect(url.hash).toEqual('#!/item/index');
return nightmare });
it('should search for the item Gem of Time', async () => {
const resultCount = await nightmare
.wait(selectors.itemsIndex.searchResult) .wait(selectors.itemsIndex.searchResult)
.type(selectors.itemsIndex.searchItemInput, 'Gem of Time') .type(selectors.itemsIndex.searchItemInput, 'Gem of Time')
.click(selectors.itemsIndex.searchButton) .click(selectors.itemsIndex.searchButton)
.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1) .waitForNumberOfElements(selectors.itemsIndex.searchResult, 1)
.countElement(selectors.itemsIndex.searchResult) .countElement(selectors.itemsIndex.searchResult);
.then(result => {
expect(result).toEqual(1);
done();
}).catch(done.fail);
});
it(`should click on the search result to access to the item niches`, done => { expect(resultCount).toEqual(1);
return nightmare });
it(`should click on the search result to access to the item niches`, async () => {
const url = await nightmare
.waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time') .waitForTextInElement(selectors.itemsIndex.searchResult, 'Gem of Time')
.waitToClick(selectors.itemsIndex.searchResult) .waitToClick(selectors.itemsIndex.searchResult)
.waitToClick(selectors.itemNiches.nicheButton) .waitToClick(selectors.itemNiches.nicheButton)
.waitForURL('niche') .waitForURL('niche')
.url() .url();
.then(url => {
expect(url).toContain('niche');
done();
}).catch(done.fail);
});
it(`should click create a new niche and delete a former one`, done => { expect(url).toContain('niche');
return nightmare });
it(`should click create a new niche and delete a former one`, async () => {
const result = await nightmare
.waitToClick(selectors.itemNiches.addNicheButton) .waitToClick(selectors.itemNiches.addNicheButton)
.waitToClick(selectors.itemNiches.secondNicheRemoveButton) .waitToClick(selectors.itemNiches.secondNicheRemoveButton)
.waitToClick(selectors.itemNiches.thirdWarehouseSelect) .waitToClick(selectors.itemNiches.thirdWarehouseSelect)
.waitToClick(selectors.itemNiches.thirdWarehouseSelectFourthOption) .waitToClick(selectors.itemNiches.thirdWarehouseSelectFourthOption)
.type(selectors.itemNiches.thirdCodeInput, 'A4') .type(selectors.itemNiches.thirdCodeInput, 'A4')
.click(selectors.itemNiches.submitNichesButton) .click(selectors.itemNiches.submitNichesButton)
.waitForLastSnackbar() .waitForLastSnackbar();
.then(result => {
expect(result).toEqual('Data saved!');
done();
}).catch(done.fail);
});
it(`should confirm the first niche is the expected one`, done => { expect(result).toEqual('Data saved!');
return nightmare });
it(`should confirm the first niche is the expected one`, async () => {
let result = await nightmare
.click(selectors.itemBasicData.basicDataButton) .click(selectors.itemBasicData.basicDataButton)
.wait(selectors.itemBasicData.nameInput) .wait(selectors.itemBasicData.nameInput)
.click(selectors.itemNiches.nicheButton) .click(selectors.itemNiches.nicheButton)
.waitForTextInInput(selectors.itemNiches.firstWarehouseSelect, 'Warehouse One') .waitForTextInInput(selectors.itemNiches.firstWarehouseSelect, 'Warehouse One')
.getInputValue(selectors.itemNiches.firstWarehouseSelect) .getInputValue(selectors.itemNiches.firstWarehouseSelect);
.then(result => {
expect(result).toEqual('Warehouse One');
return nightmare
.getInputValue(selectors.itemNiches.firstCodeInput);
})
.then(result => {
expect(result).toEqual('A1');
done();
}).catch(done.fail);
});
it(`should confirm the second niche is the expected one`, done => { expect(result).toEqual('Warehouse One');
return nightmare result = await nightmare
.getInputValue(selectors.itemNiches.secondWarehouseSelect) .getInputValue(selectors.itemNiches.firstCodeInput);
.then(result => {
expect(result).toEqual('Warehouse Three');
return nightmare
.getInputValue(selectors.itemNiches.secondCodeInput);
})
.then(result => {
expect(result).toEqual('A3');
done();
}).catch(done.fail);
});
it(`should confirm the third niche is the expected one`, done => { expect(result).toEqual('A1');
return nightmare });
.getInputValue(selectors.itemNiches.thirdWarehouseSelect)
.then(result => { it(`should confirm the second niche is the expected one`, async () => {
expect(result).toEqual('Warehouse Two'); let result = await nightmare
return nightmare .getInputValue(selectors.itemNiches.secondWarehouseSelect);
.getInputValue(selectors.itemNiches.thirdCodeInput);
}) expect(result).toEqual('Warehouse Three');
.then(result => { result = await nightmare
expect(result).toEqual('A4'); .getInputValue(selectors.itemNiches.secondCodeInput);
done();
}).catch(done.fail);
}); expect(result).toEqual('A3');
});
it(`should confirm the third niche is the expected one`, async () => {
let result = await nightmare
.getInputValue(selectors.itemNiches.thirdWarehouseSelect);
expect(result).toEqual('Warehouse Two');
result = await nightmare
.getInputValue(selectors.itemNiches.thirdCodeInput);
expect(result).toEqual('A4');
}); });
}); });

View File

@ -38,7 +38,7 @@ let defaultPort = proxyConf.defaultPort;
// Development // Development
gulp.task('default', () => { gulp.task('default', () => {
return gulp.start('environment', 'services', 'client'); return gulp.start('services', 'client');
}); });
gulp.task('environment', async () => { gulp.task('environment', async () => {
@ -55,13 +55,13 @@ gulp.task('client', ['build-clean'], async () => {
* Starts all backend services, including the nginx proxy and the database. * Starts all backend services, including the nginx proxy and the database.
*/ */
gulp.task('services', async () => { gulp.task('services', async () => {
await runSequenceP('environment', 'docker-start', 'services-only', 'nginx'); await runSequenceP('docker-start', 'services-only', 'nginx');
}); });
/** /**
* Starts backend services. * Starts backend services.
*/ */
gulp.task('services-only', async () => { gulp.task('services-only', ['environment'], async () => {
const services = await getServices(); const services = await getServices();
for (let service of services) for (let service of services)
require(service.index).start(service.port); require(service.index).start(service.port);
@ -88,13 +88,13 @@ gulp.task('e2e-only', () => {
process.env.E2E_SHOW = true; process.env.E2E_SHOW = true;
return gulp.src('./e2e_tests.js') return gulp.src('./e2e_tests.js')
.pipe(jasmine({reporter: 'none'})); .pipe(jasmine({reporter: 'none'}));
}); });
gulp.task('smokes-only', () => { gulp.task('smokes-only', () => {
const jasmine = require('gulp-jasmine'); const jasmine = require('gulp-jasmine');
return gulp.src('./smokes_tests.js') return gulp.src('./smokes_tests.js')
.pipe(jasmine({reporter: 'none'})); .pipe(jasmine({reporter: 'none'}));
}); });
/** /**
@ -354,10 +354,9 @@ gulp.task('webpack-dev-server', function() {
const webpackConfig = require('./webpack.config.js'); const webpackConfig = require('./webpack.config.js');
let configCopy = Object.create(webpackConfig); let configCopy = Object.create(webpackConfig);
for (let entry in configCopy.entry) { for (let entry in configCopy.entry)
configCopy.entry[entry] configCopy.entry[entry]
.unshift(`webpack-dev-server/client?http://127.0.0.1:${devServerPort}/`); .unshift(`webpack-dev-server/client?http://127.0.0.1:${devServerPort}/`);
}
let compiler = webpack(configCopy); let compiler = webpack(configCopy);
new WebpackDevServer(compiler, { new WebpackDevServer(compiler, {

689
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -64,7 +64,7 @@
"mysql2": "^1.6.1", "mysql2": "^1.6.1",
"nightmare": "^3.0.1", "nightmare": "^3.0.1",
"node-sass": "^4.9.3", "node-sass": "^4.9.3",
"nodemon": "^1.18.4", "nodemon": "^1.18.5",
"plugin-error": "^1.0.1", "plugin-error": "^1.0.1",
"raw-loader": "*", "raw-loader": "*",
"run-sequence": "^2.2.1", "run-sequence": "^2.2.1",
@ -79,6 +79,6 @@
"test": "nodemon -q services_tests.js -w services", "test": "nodemon -q services_tests.js -w services",
"dbtest": "nodemon -q db_tests.js -w services/db/tests", "dbtest": "nodemon -q db_tests.js -w services/db/tests",
"lint": "eslint ./ --cache --ignore-pattern .gitignore", "lint": "eslint ./ --cache --ignore-pattern .gitignore",
"services": "node --inspect ./node_modules/gulp/bin/gulp.js services" "services": "nodemon --inspect -w services ./node_modules/gulp/bin/gulp.js services"
} }
} }

View File

@ -325,19 +325,19 @@ INSERT INTO `vn`.`bankEntity`(`id`, `countryFk`, `name`, `bic`)
INSERT INTO `vn`.`company`(`id`, `code`, `supplierAccountFk`, `workerManagerFk`, `companyCode`, `sage200Company`) INSERT INTO `vn`.`company`(`id`, `code`, `supplierAccountFk`, `workerManagerFk`, `companyCode`, `sage200Company`)
VALUES VALUES
( 69 , 'CCs', NULL, 30, NULL, 1), ( 69 , 'CCs', NULL, 30, NULL, 0),
( 442 , 'VNL', 241, 30, 2 , 2), ( 442 , 'VNL', 241, 30, 2 , 1),
( 567 , 'VNH', NULL, 30, NULL, 3), ( 567 , 'VNH', NULL, 30, NULL, 4),
( 791 , 'FTH', NULL, 30, NULL, 4), ( 791 , 'FTH', NULL, 30, NULL, 3),
( 1381, 'ORN', NULL, 30, NULL, 5); ( 1381, 'ORN', NULL, 30, NULL, 7);
INSERT INTO `vn`.`invoiceOut`(`id`, `ref`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `pdf`) INSERT INTO `vn`.`invoiceOut`(`id`,`ref`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `pdf`)
VALUES VALUES
( 1, 'T1111111' , 'T', 500 , DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 101, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), ( 1, '1', 'T', 500 , DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 101, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1),
( 2, 'V2222222' , 'V', 350.50 , DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 102, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), ( 2, '1', 'V', 350.50 , DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 102, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1),
( 3, 'E3333333' , 'E', 90.30 , CURDATE(), 103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), ( 3, '1', 'E', 90.30 , CURDATE(), 103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1),
( 4, 'E4444444' , 'E', 290.30 , DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), ( 4, '1', 'E', 290.30 , DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1),
( 5, 'E5555555' , 'E', 190.30 , DATE_ADD(CURDATE(), INTERVAL +2 MONTH), 103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1); ( 5, '1', 'R', 190.30 , DATE_ADD(CURDATE(), INTERVAL +2 MONTH), 103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1);
INSERT INTO `vn`.`ticket`(`id`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `created`) INSERT INTO `vn`.`ticket`(`id`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `created`)
VALUES VALUES

View File

@ -1,4 +0,0 @@
module.exports = State => {
var serverFilter = {where: {order: {gt: 0}}, order: 'order, name'};
State.defineScope(serverFilter);
};

View File

@ -1,58 +0,0 @@
module.exports = Self => {
/**
* Catches database errors overriding
* model.create() and model.upsert() methods
* @param {Object} replaceErrFunc - Callback
*/
Self.rewriteDbError = function(replaceErrFunc) {
this.once('attached', () => {
let realUpsert = this.upsert;
this.upsert = async(data, options, cb) => {
if (options instanceof Function) {
cb = options;
options = null;
}
try {
await realUpsert.call(this, data, options);
if (cb) cb();
} catch (err) {
let myErr = replaceErr(err, replaceErrFunc);
if (cb)
cb(myErr);
else
throw myErr;
}
};
let realCreate = this.create;
this.create = async(data, options, cb) => {
if (options instanceof Function) {
cb = options;
options = null;
}
try {
await realCreate.call(this, data, options);
if (cb) cb();
} catch (err) {
let myErr = replaceErr(err, replaceErrFunc);
if (cb)
cb(myErr);
else
throw myErr;
}
};
});
};
function replaceErr(err, replaceErrFunc) {
if (Array.isArray(err)) {
let errs = [];
for (let e of err)
errs.push(replaceErrFunc(e));
return errs;
}
return replaceErrFunc(err);
}
};

View File

@ -8,13 +8,11 @@ describe('Model crud()', () => {
expect(ItemBarcode.crud).toBeDefined(); expect(ItemBarcode.crud).toBeDefined();
}); });
it('should create a new instance', async() => { it('should create a new instance', async () => {
let data = {code: '500', itemFk: '1'}; let data = {code: '500', itemFk: '1'};
let creates = [data];
crudObject = { await ItemBarcode.crud(null, null, creates);
create: [data]
};
await ItemBarcode.crud(crudObject);
let instance = await ItemBarcode.findOne({where: data}); let instance = await ItemBarcode.findOne({where: data});
insertId = instance.id; insertId = instance.id;
@ -22,24 +20,21 @@ describe('Model crud()', () => {
expect(instance.code).toEqual('500'); expect(instance.code).toEqual('500');
}); });
it('should update the instance', async() => { it('should update the instance', async () => {
crudObject = { let updates = [{
update: [{ where: {id: insertId},
where: {id: insertId}, data: {code: '501', itemFk: 1}
data: {code: '501', itemFk: 1} }];
}]
}; await ItemBarcode.crud(null, updates);
await ItemBarcode.crud(crudObject);
let instance = await ItemBarcode.findById(insertId); let instance = await ItemBarcode.findById(insertId);
expect(instance.code).toEqual('501'); expect(instance.code).toEqual('501');
}); });
it('should delete the created instance', async() => { it('should delete the created instance', async () => {
crudObject = { let deletes = [insertId];
delete: [insertId] await ItemBarcode.crud(deletes);
};
await ItemBarcode.crud(crudObject);
let instance = await ItemBarcode.findById(insertId); let instance = await ItemBarcode.findById(insertId);
expect(instance).toEqual(null); expect(instance).toEqual(null);

View File

@ -1,10 +0,0 @@
module.exports = function(Self) {
Self.validateBinded = function(propertyName, validatorFn, options) {
var customValidator = function(err) {
if (!validatorFn(this[propertyName])) err();
};
options.isExportable = true;
options.bindedFunction = validatorFn;
this.validate(propertyName, customValidator, options);
};
};

View File

@ -1,5 +1,4 @@
module.exports = Self => { module.exports = Self => {
Self.defineScope({where: {isManaged: {neq: 0}}});
require('../methods/agency/landsThatDay')(Self); require('../methods/agency/landsThatDay')(Self);
require('../methods/agency/getFirstShipped')(Self); require('../methods/agency/getFirstShipped')(Self);
}; };

View File

@ -1,6 +1,4 @@
module.exports = Self => { module.exports = Self => {
require('../methods/state/list')(Self);
/** /**
* Checks if the alertLevel of a state is 0. * Checks if the alertLevel of a state is 0.
* *

View File

@ -5,261 +5,267 @@ const UserError = require('../helpers').UserError;
module.exports = function(Self) { module.exports = function(Self) {
Self.ParameterizedSQL = ParameterizedSQL; Self.ParameterizedSQL = ParameterizedSQL;
require('../methods/vn-model/validateBinded')(Self);
require('../methods/vn-model/rewriteDbError')(Self);
require('../methods/vn-model/getSetValues')(Self); require('../methods/vn-model/getSetValues')(Self);
Self.setup = function() { Object.assign(Self, {
Self.super_.setup.call(this); setup() {
Self.super_.setup.call(this);
// Register field ACL validation // Register field ACL validation
this.beforeRemote('prototype.patchAttributes', ctx => this.checkUpdateAcls(ctx)); this.beforeRemote('prototype.patchAttributes', ctx => this.checkUpdateAcls(ctx));
this.beforeRemote('updateAll', ctx => this.checkUpdateAcls(ctx)); this.beforeRemote('updateAll', ctx => this.checkUpdateAcls(ctx));
this.beforeRemote('patchOrCreate', ctx => this.checkInsertAcls(ctx)); this.beforeRemote('patchOrCreate', ctx => this.checkInsertAcls(ctx));
this.beforeRemote('create', ctx => this.checkInsertAcls(ctx)); this.beforeRemote('create', ctx => this.checkInsertAcls(ctx));
this.beforeRemote('replaceById', ctx => this.checkInsertAcls(ctx)); this.beforeRemote('replaceById', ctx => this.checkInsertAcls(ctx));
this.beforeRemote('replaceOrCreate', ctx => this.checkInsertAcls(ctx)); this.beforeRemote('replaceOrCreate', ctx => this.checkInsertAcls(ctx));
this.remoteMethod('crud', { this.remoteMethod('crud', {
description: 'Create, update or/and delete instances from model with a single request', description: `Create, update or/and delete instances from model with a single request`,
accessType: 'WRITE', accessType: 'WRITE',
accepts: [ accepts: [
{ {
arg: 'actions', arg: 'deletes',
type: 'Object', description: `Identifiers of instances to delete`,
require: true, type: ['Integer']
description: 'Instances to update, example: {create: [instances], update: [instances], delete: [ids]}', }, {
http: {source: 'body'} arg: 'updates',
} description: `Instances to update with it's identifier {where, data}`,
], type: ['Object']
http: { }, {
path: `/crud`, arg: 'creates',
verb: 'POST' description: `Instances to create`,
} type: ['Object']
}); }
}; ]
Self.defineScope = function(serverFilter) {
this.remoteMethodCtx('list', {
accepts: [
{
arg: 'filter',
type: 'object',
description: 'Filter defining where'
}
],
returns: {
type: [this.modelName],
root: true
},
http: {
verb: 'get',
path: '/list'
}
});
this.list = function(ctx, clientFilter, cb) {
let clientFields = (clientFilter && clientFilter.fields) ? clientFilter.fields : [];
let serverFields = (serverFilter && serverFilter.fields) ? serverFilter.fields : [];
let fields = clientFields.filter(itemC => {
return serverFields.some(itemS => itemS === itemC);
}); });
let and = []; },
let order;
let limit;
let filter = {order: order, limit: limit};
if (clientFilter && clientFilter.where) async crud(deletes, updates, creates) {
and.push(clientFilter.where); let transaction = await this.beginTransaction({});
if (serverFilter && serverFilter.where) let options = {transaction};
and.push(serverFilter.where);
if (clientFilter && clientFilter.order) try {
order = clientFilter.order; if (deletes) {
else if (serverFilter && serverFilter.order)
order = serverFilter.order;
if (serverFilter && serverFilter.limit)
limit = serverFilter.limit;
else if (clientFilter && clientFilter.limit)
limit = clientFilter.limit;
filter.where = (and.length > 0) && {and: and};
filter.fields = fields;
this.find(filter, function(err, states) {
if (err)
cb(err, null);
else
cb(null, states);
});
};
};
Self.remoteMethodCtx = function(methodName, args) {
let ctx = {
arg: 'context',
type: 'object',
http: function(ctx) {
return ctx;
}
};
if (args.accepts === undefined)
args.accepts = [];
else if (!Array.isArray(args.accepts))
args.accepts = [args.accepts];
args.accepts.unshift(ctx);
this.remoteMethod(methodName, args);
};
Self.getConnection = function(cb) {
this.dataSource.connector.client.getConnection(cb);
};
Self.connectToService = function(ctx, dataSource) {
this.app.dataSources[dataSource].connector.remotes.auth = {
bearer: new Buffer(ctx.req.accessToken.id).toString('base64'),
sendImmediately: true
};
};
Self.disconnectFromService = function(dataSource) {
this.app.dataSources[dataSource].connector.remotes.auth = {
bearer: new Buffer('').toString('base64'),
sendImmediately: true
};
};
Self.crud = async function(actions) {
let transaction = await this.beginTransaction({});
let options = {transaction: transaction};
try {
if (actions.delete && actions.delete.length)
await this.destroyAll({id: {inq: actions.delete}}, options);
if (actions.update) {
try {
let promises = []; let promises = [];
actions.update.forEach(toUpdate => { for (let id of deletes)
promises.push(this.upsertWithWhere(toUpdate.where, toUpdate.data, options)); promises.push(this.destroyById(id, options));
});
await Promise.all(promises); await Promise.all(promises);
} catch (error) {
throw error;
} }
} if (updates) {
if (actions.create && actions.create.length) { let promises = [];
try { for (let update of updates)
await this.create(actions.create, options); promises.push(this.upsertWithWhere(update.where, update.data, options));
} catch (error) { await Promise.all(promises);
throw error[error.length - 1];
} }
if (creates && creates.length)
try {
await this.create(creates, options);
} catch (error) {
throw error[error.length - 1];
}
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
} }
await transaction.commit(); },
} catch (error) {
await transaction.rollback(); /**
throw error; * Wrapper for remoteMethod() but adding the context as
* extra argument at the beginning of arguments list.
*
* @param {String} methodName The method name
* @param {Object} options The method options
*/
remoteMethodCtx(methodName, options) {
if (options.accepts === undefined)
options.accepts = [];
else if (!Array.isArray(options.accepts))
options.accepts = [options.accepts];
options.accepts.unshift({
arg: 'ctx',
type: 'Object',
http: {source: 'context'}
});
this.remoteMethod(methodName, options);
},
/**
* Adds a validation, marking it as exportable to the browser.
* Exportable validation functions should be synchronous and totally
* independent from other code because they are parsed in the browser
* using eval().
*
* @param {String} propertyName The property name
* @param {Function} validatorFn The validation function
* @param {Object} options The validation options
*/
validateBinded(propertyName, validatorFn, options) {
let customValidator = function(err) {
if (!validatorFn(this[propertyName])) err();
};
options.isExportable = true;
options.bindedFunction = validatorFn;
this.validate(propertyName, customValidator, options);
},
/**
* Catches database errors overriding create() and upsert() methods.
*
* @param {Function} replaceErrFunc - Callback
*/
rewriteDbError(replaceErrFunc) {
function replaceErr(err, replaceErrFunc) {
if (Array.isArray(err)) {
let errs = [];
for (let e of err)
errs.push(replaceErrFunc(e));
return errs;
}
return replaceErrFunc(err);
}
this.once('attached', () => {
let realUpsert = this.upsert;
this.upsert = async (data, options, cb) => {
if (options instanceof Function) {
cb = options;
options = null;
}
try {
await realUpsert.call(this, data, options);
if (cb) cb();
} catch (err) {
let myErr = replaceErr(err, replaceErrFunc);
if (cb)
cb(myErr);
else
throw myErr;
}
};
let realCreate = this.create;
this.create = async (data, options, cb) => {
if (options instanceof Function) {
cb = options;
options = null;
}
try {
await realCreate.call(this, data, options);
if (cb) cb();
} catch (err) {
let myErr = replaceErr(err, replaceErrFunc);
if (cb)
cb(myErr);
else
throw myErr;
}
};
});
},
/*
* Shortcut to VnMySQL.executeP()
*/
rawSql(query, params, options, cb) {
return this.dataSource.connector.executeP(query, params, options, cb);
},
/*
* Shortcut to VnMySQL.executeStmt()
*/
rawStmt(stmt, options) {
return this.dataSource.connector.executeStmt(stmt, options);
},
/*
* Shortcut to VnMySQL.makeLimit()
*/
makeLimit(filter) {
return this.dataSource.connector.makeLimit(filter);
},
/*
* Shortcut to VnMySQL.makeSuffix()
*/
makeSuffix(filter) {
return this.dataSource.connector.makeSuffix(filter);
},
/*
* Shortcut to VnMySQL.buildModelSuffix()
*/
buildSuffix(filter, tableAlias) {
return this.dataSource.connector.buildModelSuffix(this.modelName, filter, tableAlias);
},
async checkAcls(ctx, actionType) {
let userId = ctx.req.accessToken.userId;
let models = this.app.models;
let userRoles = await models.Account.getRoles(userId);
let data = ctx.args.data;
let modelAcls;
function modifiedProperties(data) {
let properties = [];
for (property in data)
properties.push(property);
return properties;
}
modelAcls = await models.FieldAcl.find({
where: {
and: [
{model: this.modelName},
{role: {inq: userRoles}},
{property: '*'},
{or: [{actionType: '*'}, {actionType: actionType}]}
]
}
});
let allowedAll = modelAcls.find(acl => {
return acl.property == '*';
});
if (allowedAll)
return;
modelAcls = await models.FieldAcl.find({
where: {
and: [
{model: this.modelName},
{role: {inq: userRoles}},
{property: {inq: modifiedProperties(data)}},
{or: [{actionType: '*'}, {actionType: actionType}]}
]
}
});
let propsHash = {};
for (let acl of modelAcls)
propsHash[acl.property] = true;
let allowedProperties = Object.keys(data).every(property => {
return propsHash[property];
});
if (!allowedProperties)
throw new UserError(`You don't have enough privileges`);
},
checkUpdateAcls(ctx) {
return this.checkAcls(ctx, 'update');
},
checkInsertAcls(ctx) {
return this.checkAcls(ctx, 'insert');
} }
}; });
Self.checkAcls = async function(ctx, actionType) {
let userId = ctx.req.accessToken.userId;
let models = this.app.models;
let userRoles = await models.Account.getRoles(userId);
let data = ctx.args.data;
let modelAcls;
function modifiedProperties(data) {
let properties = [];
for (property in data)
properties.push(property);
return properties;
}
modelAcls = await models.FieldAcl.find({
where: {
and: [
{model: this.modelName},
{role: {inq: userRoles}},
{property: '*'},
{or: [{actionType: '*'}, {actionType: actionType}]}
]
}
});
let allowedAll = modelAcls.find(acl => {
return acl.property == '*';
});
if (allowedAll)
return;
modelAcls = await models.FieldAcl.find({
where: {
and: [
{model: this.modelName},
{role: {inq: userRoles}},
{property: {inq: modifiedProperties(data)}},
{or: [{actionType: '*'}, {actionType: actionType}]}
]
}
});
let propsHash = {};
for (let acl of modelAcls)
propsHash[acl.property] = true;
let allowedProperties = Object.keys(data).every(property => {
return propsHash[property];
});
if (!allowedProperties)
throw new UserError(`You don't have enough privileges`);
};
Self.checkUpdateAcls = function(ctx) {
return this.checkAcls(ctx, 'update');
};
Self.checkInsertAcls = function(ctx) {
return this.checkAcls(ctx, 'insert');
};
/*
* Shortcut to VnMySQL.executeP()
*/
Self.rawSql = function(query, params, options, cb) {
return this.dataSource.connector.executeP(query, params, options, cb);
};
/*
* Shortcut to VnMySQL.executeStmt()
*/
Self.rawStmt = function(stmt, options) {
return this.dataSource.connector.executeStmt(stmt, options);
};
/*
* Shortcut to VnMySQL.makeLimit()
*/
Self.makeLimit = function(filter) {
return this.dataSource.connector.makeLimit(filter);
};
/*
* Shortcut to VnMySQL.makeSuffix()
*/
Self.makeSuffix = function(filter) {
return this.dataSource.connector.makeSuffix(filter);
};
/*
* Shortcut to VnMySQL.buildModelSuffix()
*/
Self.buildSuffix = function(filter, tableAlias) {
return this.dataSource.connector.buildModelSuffix(this.modelName, filter, tableAlias);
};
}; };

View File

@ -1,18 +1,11 @@
const mysql = require('mysql'); const mysql = require('mysql');
const loopbackConnector = require('loopback-connector'); const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const SqlConnector = loopbackConnector.SqlConnector;
const ParameterizedSQL = loopbackConnector.ParameterizedSQL;
const MySQL = require('loopback-connector-mysql').MySQL; const MySQL = require('loopback-connector-mysql').MySQL;
const EnumFactory = require('loopback-connector-mysql').EnumFactory; const EnumFactory = require('loopback-connector-mysql').EnumFactory;
const fs = require('fs'); const fs = require('fs');
class VnMySQL extends MySQL { class VnMySQL extends MySQL {
constructor(settings) {
super();
SqlConnector.call(this, 'mysql', settings);
}
toColumnValue(prop, val) { toColumnValue(prop, val) {
if (val == null || !prop || prop.type !== Date) if (val == null || !prop || prop.type !== Date)
return MySQL.prototype.toColumnValue.call(this, prop, val); return MySQL.prototype.toColumnValue.call(this, prop, val);
@ -237,12 +230,11 @@ exports.initialize = function initialize(dataSource, callback) {
dataSource.EnumFactory = EnumFactory; dataSource.EnumFactory = EnumFactory;
if (callback) { if (callback)
if (dataSource.settings.lazyConnect) { if (dataSource.settings.lazyConnect) {
process.nextTick(function() { process.nextTick(function() {
callback(); callback();
}); });
} else } else
dataSource.connector.connect(callback); dataSource.connector.connect(callback);
}
}; };