Tests fixed, watcher refactor, global error handling, angular 1.7

This commit is contained in:
Juan 2018-05-25 17:25:35 +02:00
parent 756614bd27
commit 30aea3d086
39 changed files with 221 additions and 322 deletions

View File

@ -45,7 +45,7 @@ vn-login > div {
position: absolute;
width: 0;
top: .3em;
right: 4em;
right: 3em;
overflow: visible;
}
}

View File

@ -15,6 +15,7 @@ describe('Client', () => {
$componentController = _$componentController_;
$state = _$state_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$state.params.addressId = '1';
controller = $componentController('vnClientAddressEdit', {$state: $state});
}));

View File

@ -13,6 +13,7 @@ describe('Client', () => {
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnClientCreditInsuranceIndex');
}));

View File

@ -14,6 +14,7 @@ describe('Client', () => {
$componentController = _$componentController_;
let $state = {params: {classificationId: 1}};
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnClientCreditInsuranceInsuranceIndex', {$state: $state});
}));

View File

@ -34,6 +34,7 @@ describe('Client', () => {
$state = _$state_;
$state.params.id = 101;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnClientCreditCreate', {$scope: $scope}, {$state: $state});
}));
describe('onSubmit()', () => {

View File

@ -13,6 +13,7 @@ describe('Descriptor', () => {
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnClientDescriptor');
}));

View File

@ -14,6 +14,7 @@ describe('Client', () => {
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$scope = $rootScope.$new();
controller = $componentController('vnClientFiscalData', {$scope: $scope});
}));

View File

@ -66,6 +66,7 @@ describe('Component vnAutocomplete', () => {
};
let json = encodeURIComponent(JSON.stringify(filter));
$httpBackend.whenGET(`localhost?filter=${json}`).respond({});
$httpBackend.expectGET(`localhost?filter=${json}`);
controller.field = data.id;
$httpBackend.flush();

View File

@ -1,85 +0,0 @@
import './icon-menu.js';
describe('Component vnIconMenu', () => {
let $componentController;
let $element;
let $httpBackend;
let $timeout;
let $scope;
let controller;
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$timeout_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$timeout = _$timeout_;
$scope = $rootScope.$new();
$element = angular.element('<div></div>');
controller = $componentController('vnIconMenu', {$scope, $element, $httpBackend, $timeout}, {url: 'test.com'});
}));
describe('component vnIconMenu', () => {
describe('findItem()', () => {
it(`should return items empty array if the controller does not provide a url and have no items defined`, () => {
controller.url = undefined;
controller.items = undefined;
let result = controller.findItems('some search value');
expect(result).toEqual([]);
});
it(`should return items array if the controller does not provide a url`, () => {
controller.url = undefined;
controller.items = ['Batman', 'Bruce Wayne'];
controller.findItems('some search value');
expect(controller.items.length).toEqual(2);
});
it(`should perform a search and store the result in controller items`, () => {
let search = 'The Joker';
let json = JSON.stringify({where: {name: {regexp: search}}});
$httpBackend.whenGET(`${controller.url}?filter=${json}`).respond([{id: 3, name: 'The Joker'}]);
$httpBackend.expectGET(`${controller.url}?filter=${json}`);
controller.findItems(search);
$httpBackend.flush();
expect(controller.items[0]).toEqual({id: 3, name: 'The Joker'});
});
it(`should call getItems function if there's no search value`, () => {
spyOn(controller, 'getItems');
controller.findItems();
expect(controller.getItems).toHaveBeenCalledWith();
});
});
describe('getItems()', () => {
it(`should perform a query and then push elements found into controller.items`, () => {
controller.items = [];
$httpBackend.whenGET(`${controller.url}?filter={}`).respond([{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce Wayne'}]);
$httpBackend.expectGET(`${controller.url}?filter={}`);
controller.getItems();
$httpBackend.flush();
expect(controller.items).toEqual([{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce Wayne'}]);
});
it(`should perform a query and then set controller.maxRow to false if there are no items in the controller`, () => {
controller.items = [];
controller.maxRow = true;
$httpBackend.whenGET(`${controller.url}?filter={"skip":0,"limit":true,"order":"name ASC"}`).respond(controller.items);
$httpBackend.expectGET(`${controller.url}?filter={"skip":0,"limit":true,"order":"name ASC"}`);
controller.getItems();
$httpBackend.flush();
expect(controller.maxRow).toBeFalsy();
});
});
});
});

View File

@ -26,7 +26,8 @@ export default class Tooltip extends Component {
this.parent = parent;
this.$element.addClass('show');
this.relocate();
this.relocateTimeout = this.$timeout(() => this.relocate(), 200);
this.cancelTimeout();
this.relocateTimeout = this.$timeout(() => this.relocate(), 50);
}
/**
@ -34,7 +35,10 @@ export default class Tooltip extends Component {
*/
hide() {
this.$element.removeClass('show');
this.cancelTimeout();
}
cancelTimeout() {
if (this.relocateTimeout) {
this.$timeout.cancel(this.relocateTimeout);
this.relocateTimeout = null;
@ -102,6 +106,8 @@ export default class Tooltip extends Component {
}
calcCoords();
// Overflow
let axisOverflow =
axis == 'x' && (left < min || left > maxLeft) ||
axis == 'y' && (top < min || top > maxTop);
@ -124,8 +130,6 @@ export default class Tooltip extends Component {
calcCoords();
}
// Overflow
function range(coord, min, max) {
return Math.min(Math.max(coord, min), max);
}
@ -186,7 +190,7 @@ export default class Tooltip extends Component {
this.arrow = arrow;
}
$destroy() {
$onDestroy() {
this.hide();
}
}

View File

@ -12,7 +12,7 @@ import isFullEmpty from '../../lib/full-empty';
* properties are provided.
*/
export default class Watcher extends Component {
constructor($element, $scope, $state, $transitions, $http, vnApp, $translate, $attrs) {
constructor($element, $scope, $state, $transitions, $http, vnApp, $translate, $attrs, $q) {
super($element);
this.$scope = $scope;
this.$state = $state;
@ -20,6 +20,7 @@ export default class Watcher extends Component {
this.$translate = $translate;
this.$attrs = $attrs;
this.vnApp = vnApp;
this.$q = $q;
this.state = null;
this.deregisterCallback = $transitions.onStart({},
@ -64,9 +65,10 @@ export default class Watcher extends Component {
* @return {Promise} The request promise
*/
submitBack() {
return this.submit().then(
() => this.window.history.back()
);
return this.submit().then(res => {
this.window.history.back();
return res;
});
}
/**
@ -77,9 +79,10 @@ export default class Watcher extends Component {
* @return {Promise} The request promise
*/
submitGo(state, params) {
return this.submit().then(
() => this.$state.go(state, params || {})
);
return this.submit().then(res => {
this.$state.go(state, params || {});
return res;
});
}
/**
@ -88,37 +91,35 @@ export default class Watcher extends Component {
* @return {Promise} The http request promise
*/
submit() {
return this.realSubmit().then(res => {
this.vnApp.showMessage(this.$translate.instant('Data saved!'));
return res;
});
}
errorHandler(err) {
this.vnApp.showError(err.message);
return err;
}
realSubmit() {
if (this.form) {
this.form.$setSubmitted();
if (!this.form.$valid)
return new Promise(
(resolve, reject) => this.invalidForm(reject)
);
}
if (!this.dataChanged()) {
return new Promise(
(resolve, reject) => this.noChanges(reject)
);
return this.invalidForm();
}
if (!this.dataChanged())
return this.noChanges();
let isPost = (this.$attrs.save && this.$attrs.save.toLowerCase() === 'post');
let changedData = isPost
? this.data
: getModifiedData(this.data, this.orgData);
if (this.requiredField && !changedData[this.requiredField]) {
let required = this.data[this.requiredField] || this.orgData[this.requiredField];
if (required === undefined) {
return new Promise(
(resolve, reject) => this.invalidForm(reject)
);
}
changedData[this.requiredField] = required;
}
if (this.save && this.save.accept) {
this.save.model = changedData; // this.copyInNewObject(changedData);
return new Promise((resolve, reject) => {
this.save.model = changedData;
return this.$q((resolve, reject) => {
this.save.accept().then(
json => this.writeData({data: json}, resolve),
json => reject(json)
@ -131,42 +132,40 @@ export default class Watcher extends Component {
let id = this.idField ? this.orgData[this.idField] : null;
if (id) {
return new Promise((resolve, reject) => {
return this.$q((resolve, reject) => {
this.$http.patch(`${this.url}/${id}`, changedData).then(
json => this.writeData(json, resolve),
json => reject(json)
reject
);
});
}
return new Promise((resolve, reject) => {
return this.$q((resolve, reject) => {
this.$http.post(this.url, changedData).then(
json => this.writeData(json, resolve),
json => reject(json)
reject
);
});
}
noChanges() {
let message = this.$translate.instant('No changes to save');
let p = this.$q.reject(new Error(message));
console.log(p);
return p;
}
invalidForm() {
let message = this.$translate.instant('Some fields are invalid');
return this.$q.reject(new Error(message));
}
writeData(json, resolve) {
Object.assign(this.data, json.data);
this.updateOriginalData();
resolve(json);
}
noChanges(reject) {
this.vnApp.showMessage(
this.$translate.instant('No changes to save')
);
reject(new Error('No changes to save'));
}
invalidForm(reject) {
this.vnApp.showMessage(
this.$translate.instant('Some fields are invalid')
);
reject(new Error('Some fields are invalid'));
}
updateOriginalData() {
this.orgData = this.copyInNewObject(this.data);
if (this.form && this.form.$dirty)
@ -218,14 +217,13 @@ export default class Watcher extends Component {
}
}
}
Watcher.$inject = ['$element', '$scope', '$state', '$transitions', '$http', 'vnApp', '$translate', '$attrs'];
Watcher.$inject = ['$element', '$scope', '$state', '$transitions', '$http', 'vnApp', '$translate', '$attrs', '$q'];
ngModule.component('vnWatcher', {
template: require('./watcher.html'),
bindings: {
url: '@?',
idField: '@?',
requiredField: '@?',
data: '<',
form: '<',
save: '<',

View File

@ -3,6 +3,7 @@ import getModifiedData from '../../lib/modified';
describe('Component vnWatcher', () => {
let $componentController;
let $rootScope;
let $scope;
let $element;
let $state;
@ -12,25 +13,28 @@ describe('Component vnWatcher', () => {
let $translate;
let controller;
let $attrs;
let $q;
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$state_, _$transitions_, _$httpBackend_, _vnApp_, _$translate_) => {
beforeEach(angular.mock.inject((_$componentController_, _$rootScope_, _$state_, _$transitions_, _$httpBackend_, _vnApp_, _$translate_, _$q_) => {
$componentController = _$componentController_;
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$element = angular.element('<div></div>');
$state = _$state_;
vnApp = _vnApp_;
$transitions = _$transitions_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$translate = _$translate_;
$q = _$q_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$attrs = {
save: "patch"
};
controller = $componentController('vnWatcher', {$scope, $element, $state, vnApp, $transitions, $httpBackend, $translate, $attrs});
controller = $componentController('vnWatcher', {$scope, $element, $state, vnApp, $transitions, $httpBackend, $translate, $attrs, $q});
}));
describe('$onInit()', () => {
@ -52,25 +56,6 @@ describe('Component vnWatcher', () => {
});
});
describe('$onChanges()', () => {
it(`should call updateOriginalData() if controllers data is defined`, () => {
controller.data = [];
spyOn(controller, 'updateOriginalData');
controller.$onChanges();
expect(controller.updateOriginalData).toHaveBeenCalledWith();
});
});
describe('$onDestroy()', () => {
it(`should call deregisterCallback()`, () => {
spyOn(controller, 'deregisterCallback');
controller.$onDestroy();
expect(controller.deregisterCallback).toHaveBeenCalledWith();
});
});
describe('fetchData()', () => {
it(`should perform a query then store the received data into controller.data and call updateOriginalData()`, () => {
spyOn(controller, 'updateOriginalData');
@ -115,12 +100,12 @@ describe('Component vnWatcher', () => {
});
});
describe('submit()', () => {
describe('realSubmit()', () => {
describe('when controller.form', () => {
it(`should call controller.form.setSubminted if controller.form is defined`, () => {
it(`should call controller.form.setSubmited if controller.form is defined`, () => {
controller.form = {$setSubmitted: () => {}};
spyOn(controller.form, '$setSubmitted');
controller.submit();
controller.realSubmit();
expect(controller.form.$setSubmitted).toHaveBeenCalledWith();
});
@ -128,48 +113,34 @@ describe('Component vnWatcher', () => {
it(`should call controller.invalidForm if controller.form.$valid is not defined`, () => {
controller.form = {$setSubmitted: () => {}};
spyOn(controller, 'invalidForm');
controller.submit();
controller.realSubmit();
expect(controller.invalidForm).toHaveBeenCalledWith(jasmine.any(Function));
expect(controller.invalidForm).toHaveBeenCalledWith();
});
});
describe('when !controller.dataChanged()', () => {
it(`should call controller.noChanges()`, () => {
spyOn(controller, 'noChanges');
controller.submit();
controller.realSubmit();
expect(controller.noChanges).toHaveBeenCalledWith(jasmine.any(Function));
expect(controller.noChanges).toHaveBeenCalledWith();
});
});
describe('when controller.save()', () => {
it(`should set controller.save.model property`, () => {
controller.save = {accept: () => {}};
controller.save = {accept: () => $q.resolve()};
controller.data = {originalInfo: 'original data', info: 'new data'};
controller.orgData = {originalInfo: 'original data'};
controller.submit();
controller.realSubmit();
expect(controller.save.model).toEqual({info: 'new data'});
});
it(`should call controller.save.accept() then controller.writeData`, done => {
controller.save = {accept: () => {}};
controller.data = {originalInfo: 'original data', info: 'new data'};
controller.orgData = {originalInfo: 'original data'};
spyOn(controller.save, 'accept').and.returnValue(Promise.resolve());
spyOn(controller, 'writeData').and.callThrough();
controller.submit()
.then(() => {
expect(controller.save.accept).toHaveBeenCalledWith();
expect(controller.writeData).toHaveBeenCalledWith(jasmine.any(Object), jasmine.any(Function));
done();
});
});
});
describe('when id is defined', () => {
it(`should perform a query then call controller.writeData()`, () => {
it(`should perform a query then call controller.writeData()`, done => {
controller.dataChanged = () => {
return true;
};
@ -182,7 +153,7 @@ describe('Component vnWatcher', () => {
spyOn(controller, 'writeData').and.callThrough();
$httpBackend.whenPATCH(`${controller.url}/1`, changedData).respond(json);
$httpBackend.expectPATCH(`${controller.url}/1`);
controller.submit()
controller.realSubmit()
.then(() => {
expect(controller.writeData).toHaveBeenCalledWith(jasmine.any(Object), jasmine.any(Function));
done();
@ -191,7 +162,7 @@ describe('Component vnWatcher', () => {
});
});
it(`should perform a POST query then call controller.writeData()`, () => {
it(`should perform a POST query then call controller.writeData()`, done => {
controller.dataChanged = () => {
return true;
};
@ -202,7 +173,7 @@ describe('Component vnWatcher', () => {
spyOn(controller, 'writeData').and.callThrough();
$httpBackend.whenPOST(`${controller.url}`, controller.data).respond(json);
$httpBackend.expectPOST(`${controller.url}`, controller.data);
controller.submit()
controller.realSubmit()
.then(() => {
expect(controller.writeData).toHaveBeenCalledWith(jasmine.any(Object), jasmine.any(Function));
done();
@ -224,15 +195,6 @@ describe('Component vnWatcher', () => {
});
});
describe('copyInNewObject()', () => {
it(`should return newCopy object if data was an object`, () => {
let data = {id: 1, Heroname: 'Batman', name: 'Bruce Wayne'};
let result = controller.copyInNewObject(data);
expect(result).toEqual(data);
});
});
describe('callback()', () => {
describe(`when dataChanged() returns true and there's no state in the controller`, () => {
it(`should define controller.state, call controller.$scope.confirm.show() and return false`, () => {

View File

@ -9,9 +9,10 @@ describe('Directive zoomImage', () => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject(($compile, $rootScope) => {
beforeEach(angular.mock.inject(($compile, $rootScope, $httpBackend) => {
compile = $compile;
scope = $rootScope.$new();
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
}));
afterEach(() => {

View File

@ -7,9 +7,9 @@ import ngModule from '../module';
* @property {Snackbar} snackbar The main object to show messages.
*/
export default class App {
constructor($rootScope) {
constructor() {
this.loaderStatus = 0;
this.$rootScope = $rootScope;
this.loading = false;
}
showMessage(message) {
if (this.snackbar)
@ -22,14 +22,13 @@ export default class App {
pushLoader() {
this.loaderStatus++;
if (this.loaderStatus === 1)
this.$rootScope.loading = true;
this.loading = true;
}
popLoader() {
this.loaderStatus--;
if (this.loaderStatus === 0)
this.$rootScope.loading = false;
this.loading = false;
}
}
App.$inject = ['$rootScope'];
ngModule.service('vnApp', App);

View File

@ -1,6 +1,6 @@
/**
* Transforms a UTC date to JSON date without datetime.
*
*
* @param {date} date Date to format
* @return {String} Formatted date string
*/
@ -12,10 +12,10 @@ export function toJsonDate(date) {
let year = date.getFullYear();
if (day < 10)
day = `0${day}`
day = `0${day}`;
if (month < 10)
month = `0${month}`
if (month < 10)
month = `0${month}`;
return new Date(`${year}-${month}-${day}`);
}
}

View File

@ -0,0 +1,12 @@
/**
* Wraps $http error responses. This class is mainly used to
* avoid the default AngularJS behaviour, that is, stringifying all
* unhandled rejections that aren't @Error objects. More info at:
* - https://github.com/angular/angular.js/issues/14631
*/
export default class HttpError extends Error {
constructor(message, fileName, lineNumber) {
super(message, fileName, lineNumber);
this.name = 'HttpError';
}
}

View File

@ -1,7 +1,8 @@
import ngModule from '../module';
import HttpError from './http-error';
interceptor.$inject = ['$q', '$window', 'vnApp', '$translate', '$cookies'];
function interceptor($q, $window, vnApp, $translate, $cookies) {
interceptor.$inject = ['$q', 'vnApp', '$cookies'];
function interceptor($q, vnApp, $cookies) {
return {
request: function(config) {
vnApp.pushLoader();
@ -16,42 +17,14 @@ function interceptor($q, $window, vnApp, $translate, $cookies) {
return $q.reject(rejection);
},
response: function(response) {
switch (response.config.method) {
case 'PUT':
case 'POST':
case 'PATCH':
vnApp.showMessage($translate.instant('Data saved!'));
}
vnApp.popLoader();
return response;
},
responseError: function(rejection) {
vnApp.popLoader();
let data = rejection.data;
let error;
switch (rejection.xhrStatus) {
case 'timeout':
case 'abort':
return $q.reject(rejection);
}
if (data && data.error instanceof Object)
error = data.error.message;
else if (rejection.status === -1)
error = $translate.instant(`Can't contact with server`);
else
error = `${rejection.status}: ${rejection.statusText}`;
if (rejection.status === 401) {
let location = $window.location;
let continueUrl = location.pathname + location.search + location.hash;
continueUrl = encodeURIComponent(continueUrl);
$window.location = `/auth/?apiKey=${vnApp.name}&continue=${continueUrl}`;
}
vnApp.showError(error);
return $q.reject(rejection);
let err = new HttpError(rejection.statusText);
Object.assign(err, rejection);
return $q.reject(err);
}
};
}

View File

@ -15,6 +15,7 @@ describe('Item', () => {
$componentController = _$componentController_;
$state = _$state_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$state.params.id = '1';
controller = $componentController('vnItemBarcode', {$state: $state});
}));

View File

@ -14,6 +14,7 @@ describe('ItemBotanical', () => {
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$state = {
params: {
id: 123

View File

@ -6,7 +6,6 @@
vn-id="watcher"
data="$ctrl.botanical"
id-field="itemFk"
required-field="itemFk"
form="form"
save="patch">
</vn-watcher>

View File

@ -5,7 +5,7 @@ class Controller {
this.$http = $http;
this.$state = $state;
}
_getBotanical() {
let filter = {
where: {itemFk: this.$state.params.id},

View File

@ -14,6 +14,7 @@ describe('Item', () => {
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$state = {
params: {
id: 123

View File

@ -15,6 +15,7 @@ describe('Item', () => {
$componentController = _$componentController_;
$state = _$state_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnItemNiche', {$state: $state});
}));

View File

@ -15,6 +15,7 @@ describe('Item', () => {
$componentController = _$componentController_;
$state = _$state_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnItemTags', {$state: $state});
}));

View File

@ -3,7 +3,7 @@
<a ui-sref="home" title="{{'Home' | translate}}">
<img class="logo" src="./logo.svg" alt="Logo"></img>
</a>
<vn-spinner enable="$root.loading"></vn-spinner>
<vn-spinner enable="$ctrl.vnApp.loading"></vn-spinner>
<vn-main-menu></vn-main-menu>
</vn-topbar>
<vn-vertical vn-one ui-view scrollable class="main-view">

View File

@ -14,7 +14,7 @@ vn-app {
}
vn-spinner {
float: left;
padding: .4em;
padding: 1em .4em;
}
}
.main-view {

View File

@ -6,29 +6,6 @@ export const appName = 'salix';
const ngModule = ng.module('salix', ['vnCore']);
export default ngModule;
config.$inject = ['$translatePartialLoaderProvider', '$httpProvider', '$qProvider'];
export function config($translatePartialLoaderProvider, $httpProvider, $qProvider) {
$translatePartialLoaderProvider.addPart(appName);
$httpProvider.interceptors.push('vnInterceptor');
// TODO: Handle or remove unhandled rejections
// $qProvider.errorOnUnhandledRejections(false);
}
ngModule.config(config);
/*
// FIXME: Handle unhandled exceptions
exceptionHandler.$inject = ['vnApp'];
function exceptionHandler(vnApp) {
return function(exception, cause) {
console.error(exception);
};
}
ngModule.factory('$exceptionHandler', exceptionHandler);
*/
const HOOK_ABORTED_TRANSITION = 3;
run.$inject = ['$window', '$rootScope', 'vnApp', '$state'];
export function run($window, $rootScope, vnApp, $state) {
$window.validations = {};
@ -37,8 +14,58 @@ export function run($window, $rootScope, vnApp, $state) {
$rootScope.$on('$viewContentLoaded', () => {});
window.myAppErrorLog = [];
$state.defaultErrorHandler(function(error) {
if (error.type === HOOK_ABORTED_TRANSITION)
if (error.type === 3) // ABORTED_TRANSITION
window.myAppErrorLog.push(error);
});
}
ngModule.run(run);
config.$inject = ['$translatePartialLoaderProvider', '$httpProvider'];
export function config($translatePartialLoaderProvider, $httpProvider) {
$translatePartialLoaderProvider.addPart(appName);
$httpProvider.interceptors.push('vnInterceptor');
}
ngModule.config(config);
// Unhandled exceptions
$exceptionHandler.$inject = ['vnApp', '$window'];
function $exceptionHandler(vnApp, $window) {
return function(exception, cause) {
let message;
if (exception.name == 'HttpError') {
switch (exception.xhrStatus) {
case 'timeout':
case 'abort':
return;
}
let data = exception.data;
if (data && data.error instanceof Object)
message = data.error.message;
else if (exception.status === -1)
message = `Can't contact with server`;
else
message = `${exception.status}: ${exception.statusText}`;
if (exception.status === 401) {
let location = $window.location;
let continueUrl = location.pathname + location.search + location.hash;
continueUrl = encodeURIComponent(continueUrl);
$window.location = `/auth/?apiKey=${vnApp.name}&continue=${continueUrl}`;
}
} else if (exception.message) {
message = exception.message;
} else if (typeof exception == 'string') {
message = exception;
} else {
message = `Unknown error`;
console.error(exception);
}
vnApp.showError(message);
};
}
ngModule.factory('$exceptionHandler', $exceptionHandler);

View File

@ -35,14 +35,13 @@ class Controller {
addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk
};
return this.$http.post(query, data).then(res => {
if (res.data)
this.ticket.sale = res.data;
return true;
}, res => {
console.log(res);
if (res.data.error.message === 'NO_AGENCY_AVAILABLE')
this.vnApp.showError(
this.$translate.instant(`There's no available agency for this landing date`)

View File

@ -15,6 +15,7 @@ describe('ticket', () => {
$componentController = _$componentController_;
$state = _$state_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnTicketDataStepOne', {$state: $state});
}));
@ -36,6 +37,9 @@ describe('ticket', () => {
describe('onStepChange()', () => {
it('should call onStepChange method and return a NO_AGENCY_AVAILABLE signal error', async () => {
let landed = new Date();
landed.setHours(0, 0, 0, 0);
controller.ticket = {
id: 1,
clientFk: 1,
@ -43,21 +47,16 @@ describe('ticket', () => {
agencyModeFk: 1,
companyFk: 442,
shipped: new Date(),
landed: new Date()
landed: landed
};
let data = {
addressFk: 121,
agencyModeFk: 1,
landed: new Date()
};
let response = {data: {error: new Error('NO_AGENCY_AVAILABLE')}};
let response = {error: new Error('NO_AGENCY_AVAILABLE')};
$httpBackend.whenPOST(`/ticket/api/sales/1/priceDifference`, data).respond(400, response);
$httpBackend.expectPOST(`/ticket/api/sales/1/priceDifference`, data);
await controller.onStepChange();
$httpBackend.whenPOST(`/ticket/api/sales/1/priceDifference`).respond(400, response);
$httpBackend.expectPOST(`/ticket/api/sales/1/priceDifference`);
controller.onStepChange();
$httpBackend.flush();
});
});
});
});
});

View File

@ -15,6 +15,7 @@ describe('ticket', () => {
$componentController = _$componentController_;
$state = _$state_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnTicketObservation', {$state: $state});
}));

View File

@ -14,6 +14,7 @@ describe('Ticket', () => {
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_, $rootScope) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$scope = {
index: {
accept: function() {}
@ -35,11 +36,6 @@ describe('Ticket', () => {
describe('submit()', () => {
it('should perform a post', () => {
spyOn(controller.$.index, 'accept');
let packagesObj = {
delete: controller.removedPackages,
create: [],
update: []
};
let query = '/ticket/api/TicketPackagings/crudTicketPackaging';
controller.removedPackages = [];
controller.oldPackages = [];

View File

@ -15,6 +15,7 @@ describe('Ticket', () => {
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_, $rootScope) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$scope = $rootScope.$new();
$scope.index = {model: {instances: [{id: 1}, {id: 2}]}, accept: () => {
return {

View File

@ -15,6 +15,7 @@ describe('ticket', () => {
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_, $rootScope) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$scope = $rootScope.$new();
$scope.index = {model: {instances: [{id: 1}, {id: 2}]}, accept: () => {
return {

View File

@ -67,7 +67,7 @@ describe('Client', () => {
.click(selectors.createClientView.createButton)
.waitForSnackbar()
.then(result => {
expect(result).toEqual('Some fields are invalid');
expect(result).toContain('Some fields are invalid');
});
});

46
package-lock.json generated
View File

@ -103,19 +103,19 @@
"dev": true
},
"angular": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/angular/-/angular-1.6.8.tgz",
"integrity": "sha512-9WErZIOw1Cu1V5Yxdvxz/6YpND8ntdP71fdPpufPFJvZodZXqCjQBYrHqEoMZreO5i84O3D/Jw/vepoFt68Azw=="
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/angular/-/angular-1.7.0.tgz",
"integrity": "sha512-3LboCLjrOuC7dWh953O0+dI3dJ7PexYRSCIrfqoN5qoHyja/wak3eWoxPKb2Sl2qwiPbrUV5KJXwgpUQ48McBQ=="
},
"angular-cookies": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.6.4.tgz",
"integrity": "sha1-wo8/aqx6mCbB5F8daAckADblsm0="
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.7.0.tgz",
"integrity": "sha512-bxY7SAl7M+P+DazcDq4OVSFhmR0QET6KWw7bsxh4V22Ky+NcGbdyFySRNqu0TtWB5LkiGvo0wCFLd/vDyuMQOQ=="
},
"angular-mocks": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.6.6.tgz",
"integrity": "sha1-yTAY54OMbcXOrxprz5vhPIMOpRU=",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.7.0.tgz",
"integrity": "sha512-tBlj9jIEpbgiYY1VpV6XAi+5JSAO0AXFziVW4TSIFETB23fautoREI7XbOeRgy/QmOhZA4P320gs2XgpbvLd0w==",
"dev": true
},
"angular-paging": {
@ -124,19 +124,19 @@
"integrity": "sha1-cC9XTW0UBpADXqxkOV/jEfeYf7s="
},
"angular-translate": {
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.17.0.tgz",
"integrity": "sha512-SudfI0R0Hhtvngc0X3wFChXQGmw90o95i+QPZ11LhJJryneTq8LR3+3E4E7jgHA4fu6TcswgcfZ9+cp5ckbUHw==",
"version": "2.18.1",
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.18.1.tgz",
"integrity": "sha512-Mw0kFBqsv5j8ItL9IhRZunIlVmIRW6iFsiTmRs9wGr2QTt8z4rehYlWyHos8qnXc/kyOYJiW50iH50CSNHGB9A==",
"requires": {
"angular": "1.6.8"
"angular": "1.7.0"
}
},
"angular-translate-loader-partial": {
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.17.0.tgz",
"integrity": "sha512-pyRJcRc93iwiUnRnh9ZfehbQE/yxO5T6jmEqIvLEVz8gKLjDqDLKcaQFgPef9wCIN2n3e531YbStkkbSH3LYmQ==",
"version": "2.18.1",
"resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.18.1.tgz",
"integrity": "sha512-+bPzY3+F2I1tb+X5bscvZq0OGoVEVkHwPGZvaY4nhbktpshArYpvIEV+RQFUa/QNj8vQc3iQ/pruJDb8w3zIdw==",
"requires": {
"angular-translate": "2.17.0"
"angular-translate": "2.18.1"
}
},
"ansi-align": {
@ -1383,7 +1383,7 @@
"bluebird": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
"integrity": "sha1-2VUfnemPH82h5oPRfukaBgLuLrk=",
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==",
"dev": true
},
"bn.js": {
@ -10785,7 +10785,7 @@
"jasmine-spec-reporter": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz",
"integrity": "sha1-HWMq7ANBZwrTJPkrqEtLMrNeniI=",
"integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==",
"dev": true,
"requires": {
"colors": "1.1.2"
@ -10933,7 +10933,7 @@
"karma": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz",
"integrity": "sha1-hcwI6eCiLXzpzKN8ShvoJPaisa4=",
"integrity": "sha512-k5pBjHDhmkdaUccnC7gE3mBzZjcxyxYsYVaqiL2G5AqlfLyBO5nw2VdNK+O16cveEPd/gIOWULH7gkiYYwVNHg==",
"dev": true,
"requires": {
"bluebird": "3.5.1",
@ -10985,7 +10985,7 @@
"karma-chrome-launcher": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz",
"integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=",
"integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==",
"dev": true,
"requires": {
"fs-access": "1.0.1",
@ -11822,7 +11822,7 @@
"resolved": "https://registry.npmjs.org/mg-crud/-/mg-crud-1.1.2.tgz",
"integrity": "sha1-p6AWGzWSPK7/8ZpIBpS2V1vDggw=",
"requires": {
"angular": "1.6.8"
"angular": "1.7.0"
}
},
"micromatch": {
@ -19992,7 +19992,7 @@
"useragent": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz",
"integrity": "sha1-IX+UOtVAyyEoZYqyP8lg9qiMmXI=",
"integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==",
"dev": true,
"requires": {
"lru-cache": "4.1.1",

View File

@ -10,11 +10,11 @@
},
"dependencies": {
"@uirouter/angularjs": "^1.0.3",
"angular": "^1.6.8",
"angular-cookies": "^1.6.4",
"angular": "^1.7.0",
"angular-cookies": "^1.7.0",
"angular-paging": "^2.2.2",
"angular-translate": "^2.17.0",
"angular-translate-loader-partial": "^2.17.0",
"angular-translate": "^2.18.1",
"angular-translate-loader-partial": "^2.18.1",
"flatpickr": "^4.4.6",
"fs-extra": "^5.0.0",
"material-design-lite": "^1.3.0",
@ -25,7 +25,7 @@
"validator": "^6.2.1"
},
"devDependencies": {
"angular-mocks": "^1.6.6",
"angular-mocks": "^1.7.0",
"assets-webpack-plugin": "^3.5.1",
"babel": "^6.23.0",
"babel-core": "^6.26.0",

View File

@ -4,7 +4,7 @@ describe('client getMana()', () => {
it('should call the getMana method', done => {
app.models.Client.getMana(101)
.then(response => {
expect(response.mana).toEqual(30.02);
expect(response.mana).toEqual(50);
done();
});
});

View File

@ -25,14 +25,14 @@ module.exports = Self => {
}
});
Self.componentUpdate = async (ticketFk, data) => {
Self.componentUpdate = async(ticketFk, data) => {
let query = 'CALL vn.ticketComponentMakeUpdate(?, ?, ?, ?, ?, ?, ?, ?)';
let res = await Self.rawSql(query, [
ticketFk,
data.agencyModeFk,
data.addressFk,
data.warehouseFk,
data.shipped,
ticketFk,
data.agencyModeFk,
data.addressFk,
data.warehouseFk,
data.shipped,
data.landed,
data.isDeleted,
data.option

View File

@ -5,7 +5,7 @@ describe('ticket getVolume()', () => {
let ticketFk = 1;
app.models.Ticket.getVolume(ticketFk)
.then(response => {
expect(response[0][0].m3_total).toEqual(0.008);
expect(response[0][0].m3).toEqual(0.008);
done();
});
});