Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2195-setDeleted_itemShelving
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2020-03-25 16:14:13 +01:00
commit f231fabef1
373 changed files with 2227 additions and 3028 deletions

View File

@ -0,0 +1 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('WorkerLog', '*', 'READ', 'ALLOW', 'ROLE', 'hr');

View File

@ -0,0 +1,6 @@
ALTER TABLE `vn`.`workerLog`
ADD COLUMN `changedModel` VARCHAR(45) NULL DEFAULT NULL AFTER `description`,
ADD COLUMN `oldInstance` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,
ADD COLUMN `newInstance` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,
ADD COLUMN `changedModelId` int(11) DEFAULT NULL,
ADD COLUMN `changedModelValue` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL;

View File

@ -0,0 +1,87 @@
USE `vn`;
DROP procedure IF EXISTS `zone_getWarehouse`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `zone_getWarehouse`(vAddress INT, vLanded DATE, vWarehouse INT)
BEGIN
/**
* Devuelve el listado de agencias disponibles para la fecha,
* dirección y almacén pasados.
*
* @param vAddress
* @param vWarehouse warehouse
* @param vLanded Fecha de recogida
* @select Listado de agencias disponibles
*/
CALL zone_getFromGeo(address_getGeo(vAddress));
CALL zone_getOptionsForLanding(vLanded, FALSE);
SELECT am.id agencyModeFk,
am.name agencyMode,
am.description,
am.deliveryMethodFk,
TIMESTAMPADD(DAY, -zo.travelingDays, vLanded) shipped,
zw.warehouseFk,
z.id zoneFk
FROM tmp.zoneOption zo
JOIN zone z ON z.id = zo.zoneFk
JOIN agencyMode am ON am.id = z.agencyModeFk
JOIN zoneWarehouse zw ON zw.zoneFk = zo.zoneFk
WHERE zw.warehouseFk = vWarehouse
GROUP BY z.agencyModeFk
ORDER BY agencyMode;
DROP TEMPORARY TABLE
tmp.zone,
tmp.zoneOption;
END$$
DELIMITER ;
USE `vn`;
DROP procedure IF EXISTS `zone_getWarehouse__`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `zone_getWarehouse__`(vAddress INT, vLanded DATE, vWarehouse INT)
BEGIN
/**
* Devuelve el listado de agencias disponibles para la fecha,
* dirección y almacén pasados.
*
* @param vAddress
* @param vWarehouse warehouse
* @param vLanded Fecha de recogida
* @select Listado de agencias disponibles
*/
CALL zone_getFromGeo(address_getGeo(vAddress));
CALL zone_getOptionsForLanding(vLanded, FALSE);
SELECT am.id agencyModeFk,
am.name agencyMode,
am.description,
am.deliveryMethodFk,
TIMESTAMPADD(DAY, -zo.travelingDays, vLanded) shipped,
zw.warehouseFk,
z.id zoneFk
FROM tmp.zoneOption zo
JOIN zone z ON z.id = zo.zoneFk
JOIN agencyMode am ON am.id = z.agencyModeFk
JOIN zoneWarehouse zw ON zw.zoneFk = zo.zoneFk
WHERE zw.warehouseFk
GROUP BY z.agencyModeFk
ORDER BY agencyMode;
DROP TEMPORARY TABLE
tmp.zone,
tmp.zoneOption;
END$$
DELIMITER ;

View File

@ -481,19 +481,19 @@ INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaF
INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `m3Max`) INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `m3Max`)
VALUES VALUES
(1, 'Zone pickup A', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 0, 0, 0, 30.50), (1, 'Zone pickup A', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 30.50),
(2, 'Zone pickup B', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 0, 0, 0, 30.50), (2, 'Zone pickup B', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 30.50),
(3, 'Zone 247 A', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 7, 1, 2, 0, 40.50), (3, 'Zone 247 A', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 40.50),
(4, 'Zone 247 B', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 7, 1, 2, 0, 40.50), (4, 'Zone 247 B', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 40.50),
(5, 'Zone expensive A', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 8, 1, 1000, 0, 50.50), (5, 'Zone expensive A', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 50.50),
(6, 'Zone expensive B', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 8, 1, 1000, 0, 50.50), (6, 'Zone expensive B', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 50.50),
(7, 'Zone refund', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 23, 0, 0, 0, 60.50), (7, 'Zone refund', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 23, 0, 0, 0, 60.50),
(8, 'Zone others', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 10, 0, 0, 0, 60.50), (8, 'Zone others', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 10, 0, 0, 0, 60.50),
(9, 'Zone superMan', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 2, 0, 0, 0, NULL), (9, 'Zone superMan', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 2, 0, 0, 0, NULL),
(10, 'Zone teleportation', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 3, 0, 0, 0, NULL), (10, 'Zone teleportation', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 3, 0, 0, 0, NULL),
(11, 'Zone pickup C', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 1, 0, 0, 0, NULL), (11, 'Zone pickup C', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 1, 0, 0, 0, NULL),
(12, 'Zone entanglement', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 4, 0, 0, 0, NULL), (12, 'Zone entanglement', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 4, 0, 0, 0, NULL),
(13, 'Zone quantum break', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 5, 0, 0, 0, NULL); (13, 'Zone quantum break', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 5, 0, 0, 0, NULL);
INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`) INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
VALUES VALUES
@ -1912,14 +1912,10 @@ INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `dated`)
(7, 'day', DATE_ADD(CURDATE(), INTERVAL +3 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +3 DAY)),
(7, 'day', DATE_ADD(CURDATE(), INTERVAL +4 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +4 DAY)),
(7, 'day', DATE_ADD(CURDATE(), INTERVAL +5 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +5 DAY)),
(7, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY));
(8, 'day', CURDATE()),
(8, 'day', DATE_ADD(CURDATE(), INTERVAL +1 DAY)), INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `weekDays`)
(8, 'day', DATE_ADD(CURDATE(), INTERVAL +2 DAY)), VALUES (8, 'indefinitely', 'mon,tue,wed,thu,fri,sat,sun');
(8, 'day', DATE_ADD(CURDATE(), INTERVAL +3 DAY)),
(8, 'day', DATE_ADD(CURDATE(), INTERVAL +4 DAY)),
(8, 'day', DATE_ADD(CURDATE(), INTERVAL +5 DAY)),
(8, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY));
INSERT INTO `vn`.`workerTimeControl`(`userFk`, `timed`, `manual`, `direction`) INSERT INTO `vn`.`workerTimeControl`(`userFk`, `timed`, `manual`, `direction`)
VALUES VALUES

View File

@ -1,4 +1,3 @@
import {url as defaultURL} from './config';
function checkVisibility(selector) { function checkVisibility(selector) {
let selectorMatches = document.querySelectorAll(selector); let selectorMatches = document.querySelectorAll(selector);
@ -59,18 +58,12 @@ let actions = {
return document.location.hash.includes(expectedHash); return document.location.hash.includes(expectedHash);
}, {}, expectedHash); }, {}, expectedHash);
} catch (error) { } catch (error) {
throw new Error(`failed to reach URL containing: ${expectedHash}`); throw new Error(`Failed to reach URL containing: ${expectedHash}`);
} }
await this.waitForContentLoaded(); await this.waitForSpinnerLoad();
return true; return true;
}, },
waitUntilNotPresent: async function(selector) {
await this.wait(selector => {
return document.querySelector(selector) == null;
}, selector);
},
doLogin: async function(userName, password = 'nightmare') { doLogin: async function(userName, password = 'nightmare') {
await this.waitForSelector(`vn-login vn-textfield[ng-model="$ctrl.user"]`, {visible: true}); await this.waitForSelector(`vn-login vn-textfield[ng-model="$ctrl.user"]`, {visible: true});
await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.user"]`); await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.user"]`);
@ -81,27 +74,31 @@ let actions = {
}, },
login: async function(userName) { login: async function(userName) {
await this.goto(`${defaultURL}/#!/login`); let state = await this.getState();
let dialog = await this.evaluate(() => {
return document.querySelector('button[response="accept"]');
});
if (dialog)
await this.waitToClick('button[response="accept"]');
if (state != 'login') {
try {
await this.gotoState('login');
} catch (err) {
let dialog = await this.evaluate(
() => document.querySelector('button[response="accept"]'));
if (dialog)
await this.waitToClick('button[response="accept"]');
else
throw err;
}
}
await this.waitForState('login');
await this.doLogin(userName); await this.doLogin(userName);
await this.waitForFunction(() => { await this.waitForState('home');
return document.location.hash === '#!/';
}, {});
}, },
selectModule: async function(moduleName) { selectModule: async function(moduleName) {
let snakeName = moduleName.replace(/[\w]([A-Z])/g, m => { let state = `${moduleName}.index`;
return m[0] + '-' + m[1]; await this.waitToClick(`vn-home a[ui-sref="${state}"]`);
}).toLowerCase(); await this.waitForState(state);
let selector = `vn-home a[ui-sref="${moduleName}.index"]`;
await this.waitToClick(selector);
await this.expectURL(snakeName);
}, },
loginAndModule: async function(userName, moduleName) { loginAndModule: async function(userName, moduleName) {
@ -109,56 +106,73 @@ let actions = {
await this.selectModule(moduleName); await this.selectModule(moduleName);
}, },
datePicker: async function(selector, changeMonth, day) { getState: async function() {
let date = new Date(); return await this.evaluate(() => {
if (changeMonth) date.setMonth(date.getMonth() + changeMonth); let $state = angular.element(document.body).injector().get('$state');
date.setDate(day ? day : 16); return $state.current.name;
date = date.toISOString().substr(0, 10); });
await this.wait(selector);
await this.evaluate((selector, date) => {
let input = document.querySelector(selector).$ctrl.input;
input.value = date;
input.dispatchEvent(new Event('change'));
}, selector, date);
}, },
pickTime: async function(selector, time) { gotoState: async function(state, params) {
await this.wait(selector); return await this.evaluate((state, params) => {
await this.evaluate((selector, time) => { let $state = angular.element(document.body).injector().get('$state');
let input = document.querySelector(selector).$ctrl.input; return $state.go(state, params);
input.value = time; }, state, params);
input.dispatchEvent(new Event('change'));
}, selector, time);
}, },
clearTextarea: async function(selector) { waitForState: async function(state) {
await this.waitForSelector(selector, {visible: true}); await this.waitFor(state => {
await this.evaluate(inputSelector => { let $state = angular.element(document.body).injector().get('$state');
return document.querySelector(`${inputSelector} textarea`).value = ''; return !$state.transition && $state.is(state);
}, selector); }, {}, state);
await this.waitForSpinnerLoad(state);
}, },
clearInput: async function(selector) { waitForTransition: async function() {
await this.waitForSelector(selector); await this.waitFor(() => {
const $state = angular.element(document.body).injector().get('$state');
return !$state.transition;
});
},
let field = await this.evaluate(selector => { accessToSection: async function(state) {
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field; await this.waitForSelector('vn-left-menu');
}, selector); let nested = await this.evaluate(state => {
return document.querySelector(`vn-left-menu li li > a[ui-sref="${state}"]`) != null;
}, state);
if ((field != null && field != '') || field == '0') { if (nested) {
let coords = await this.evaluate(selector => { await this.waitToClick('vn-left-menu vn-item-section > vn-icon[icon=keyboard_arrow_down]');
let rect = document.querySelector(selector).getBoundingClientRect(); await this.wait('vn-left-menu .expanded');
return {x: rect.x + (rect.width / 2), y: rect.y + (rect.height / 2), width: rect.width};
}, selector);
await this.mouse.move(coords.x, coords.y);
await this.waitForSelector(`${selector} [icon="clear"]`, {visible: true});
await this.waitToClick(`${selector} [icon="clear"]`);
} }
await this.evaluate(selector => { await this.evaluate(state => {
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field == ''; let navButton = document.querySelector(`vn-left-menu li > a[ui-sref="${state}"]`);
}, selector); navButton.scrollIntoViewIfNeeded();
return navButton.click();
}, state);
await this.waitForState(state);
},
reloadSection: async function(state) {
await this.click('vn-icon[icon="desktop_windows"]');
await this.accessToSection(state);
},
forceReloadSection: async function(sectionRoute) {
await this.waitToClick('vn-icon[icon="desktop_windows"]');
await this.waitToClick('button[response="accept"]');
await this.wait('vn-card.summary');
await this.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
},
accessToSearchResult: async function(searchValue) {
await this.clearInput('vn-searchbar');
await this.write('vn-searchbar', searchValue);
await this.waitToClick('vn-searchbar vn-icon[icon="search"]');
await this.waitForTransition();
await this.waitFor('.vn-descriptor');
}, },
getProperty: async function(selector, property) { getProperty: async function(selector, property) {
@ -320,12 +334,16 @@ let actions = {
}, },
hideSnackbar: async function() { hideSnackbar: async function() {
await this.waitFor(750); // holds up for the snackbar to be visible for a small period of time. // Holds up for the snackbar to be visible for a small period of time.
if (process.env.DEBUG)
await this.waitFor(300);
await this.evaluate(() => { await this.evaluate(() => {
let hideButton = document.querySelector('#shapes .shown button'); let hideButton = document.querySelector('#shapes .shown button');
if (hideButton) if (hideButton)
return document.querySelector('#shapes .shown button').click(); return document.querySelector('#shapes .shown button').click();
}); });
await this.waitFor('#shapes > .shape', {hidden: true});
}, },
waitForLastSnackbar: async function() { waitForLastSnackbar: async function() {
@ -341,50 +359,64 @@ let actions = {
return snackBarText; return snackBarText;
}, },
accessToSearchResult: async function(searchValue) { pickDate: async function(selector, date) {
await this.clearInput('vn-searchbar'); date = date || new Date();
await this.write('vn-searchbar', searchValue);
await this.waitToClick('vn-searchbar vn-icon[icon="search"]'); const tzoffset = date.getTimezoneOffset() * 60000;
await this.waitForNumberOfElements('.search-result', 1); const localIso = (new Date(date.getTime() - tzoffset))
await this.waitForContentLoaded(); .toISOString();
await this.evaluate(() => {
return document.querySelector('.search-result').click(); await this.wait(selector);
}); await this.evaluate((selector, localIso) => {
await this.waitForContentLoaded(); let input = document.querySelector(selector).$ctrl.input;
input.value = localIso.substr(0, 10);
input.dispatchEvent(new Event('change'));
}, selector, localIso);
}, },
accessToSection: async function(sectionRoute) { pickTime: async function(selector, time) {
await this.waitForSelector('vn-left-menu'); await this.wait(selector);
let nested = await this.evaluate(sectionRoute => { await this.evaluate((selector, time) => {
return document.querySelector(`vn-left-menu li li > a[ui-sref="${sectionRoute}"]`) != null; let input = document.querySelector(selector).$ctrl.input;
}, sectionRoute); input.value = time;
input.dispatchEvent(new Event('change'));
}, selector, time);
},
if (nested) { clearTextarea: async function(selector) {
await this.waitToClick('vn-left-menu vn-item-section > vn-icon[icon=keyboard_arrow_down]'); await this.waitForSelector(selector, {visible: true});
await this.wait('vn-left-menu .expanded'); await this.evaluate(inputSelector => {
return document.querySelector(`${inputSelector} textarea`).value = '';
}, selector);
},
clearInput: async function(selector) {
await this.waitForSelector(selector);
let field = await this.evaluate(selector => {
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field;
}, selector);
if ((field != null && field != '') || field == '0') {
let coords = await this.evaluate(selector => {
let rect = document.querySelector(selector).getBoundingClientRect();
return {x: rect.x + (rect.width / 2), y: rect.y + (rect.height / 2), width: rect.width};
}, selector);
await this.mouse.move(coords.x, coords.y);
await this.waitForSelector(`${selector} [icon="clear"]`, {visible: true});
await this.waitToClick(`${selector} [icon="clear"]`);
} }
await this.evaluate(sectionRoute => { await this.evaluate(selector => {
let navButton = document.querySelector(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`); return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field == '';
navButton.scrollIntoViewIfNeeded(); }, selector);
return navButton.click();
}, sectionRoute);
await this.waitForNavigation({waitUntil: ['networkidle0']});
await this.waitForContentLoaded();
}, },
autocompleteSearch: async function(selector, searchValue) { autocompleteSearch: async function(selector, searchValue) {
let builtSelector = await this.selectorFormater(selector); let builtSelector = await this.selectorFormater(selector);
await this.waitForContentLoaded();
await this.waitToClick(selector); await this.waitToClick(selector);
await this.waitForSelector(selector => { await this.write('.vn-drop-down.shown vn-textfield', searchValue);
document
.querySelector(`${selector} vn-drop-down`).$ctrl.content
.querySelectorAll('li');
}, selector);
await this.write('.vn-drop-down.vn-popover.vn-popup.shown vn-textfield', searchValue);
try { try {
await this.waitForFunction((selector, searchValue) => { await this.waitForFunction((selector, searchValue) => {
@ -396,7 +428,7 @@ let actions = {
}, {}, selector, searchValue); }, {}, selector, searchValue);
} catch (error) { } catch (error) {
let inputValue = await this.evaluate(() => { let inputValue = await this.evaluate(() => {
return document.querySelector('.vn-drop-down.vn-popover.vn-popup.shown vn-textfield input').value; return document.querySelector('.vn-drop-down.shown vn-textfield input').value;
}); });
throw new Error(`${builtSelector} value is ${inputValue}! ${error}`); throw new Error(`${builtSelector} value is ${inputValue}! ${error}`);
} }
@ -407,28 +439,7 @@ let actions = {
}, {}, builtSelector, searchValue); }, {}, builtSelector, searchValue);
await this.waitForMutation('.vn-drop-down', 'childList'); await this.waitForMutation('.vn-drop-down', 'childList');
await this.waitForContentLoaded(); await this.waitFor('.vn-drop-down', {hidden: true});
},
reloadSection: async function(sectionRoute) {
await this.waitForContentLoaded();
await Promise.all([
this.waitForNavigation({waitUntil: 'networkidle0'}),
this.click('vn-icon[icon="desktop_windows"]', {}),
]);
await Promise.all([
this.waitForNavigation({waitUntil: 'networkidle0'}),
this.click(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`, {}),
]);
await this.waitForContentLoaded();
},
forceReloadSection: async function(sectionRoute) {
await this.waitToClick('vn-icon[icon="desktop_windows"]');
await this.waitToClick('button[response="accept"]');
await this.wait('vn-card.summary');
await this.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
}, },
checkboxState: async function(selector) { checkboxState: async function(selector) {
@ -462,7 +473,7 @@ let actions = {
}, },
waitForSpinnerLoad: async function() { waitForSpinnerLoad: async function() {
await this.waitUntilNotPresent('vn-topbar vn-spinner'); await this.waitFor('vn-topbar vn-spinner', {hidden: true});
}, },
waitForWatcherData: async function(selector) { waitForWatcherData: async function(selector) {
@ -514,35 +525,42 @@ let actions = {
closePopup: async function(selector) { closePopup: async function(selector) {
await Promise.all([ await Promise.all([
this.keyboard.press('Escape'), this.keyboard.press('Escape'),
this.waitForSelector('.vn-popup', {hidden: true}), this.waitFor('.vn-popup', {hidden: true}),
]); ]);
}, },
waitForContentLoaded: async function() {
await this.waitFor(1000);
},
respondToDialog: async function(response) { respondToDialog: async function(response) {
await this.waitForSelector('.vn-dialog.vn-popup.shown'); await this.waitForSelector('.vn-dialog.shown');
const firstCount = await this.evaluate(text => { const firstCount = await this.evaluate(text => {
const dialogs = document.querySelectorAll('.vn-dialog.vn-popup'); const dialogs = document.querySelectorAll('.vn-dialog');
const dialogOnTop = dialogs[dialogs.length - 1]; const dialogOnTop = dialogs[dialogs.length - 1];
const button = dialogOnTop.querySelector(`div.buttons [response="${text}"]`); const button = dialogOnTop.querySelector(`div.buttons [response="${text}"]`);
button.click(); button.click();
return dialogs.length; return dialogs.length;
}, response); }, response);
this.waitForFunction(firstCount => { await this.waitForFunction(firstCount => {
const dialogs = document.querySelectorAll('.vn-dialog.vn-popup'); const dialogs = document.querySelectorAll('.vn-dialog');
return dialogs.length < firstCount; return dialogs.length < firstCount;
}, {}, firstCount); }, {}, firstCount);
},
waitForContentLoaded: async function() {
// await this.waitFor(250);
} }
}; };
export function extendPage(page) { export function extendPage(page) {
for (let name in actions) { for (let name in actions) {
page[name] = async(...args) => { page[name] = async(...args) => {
return await actions[name].call(page, ...args); try {
return await actions[name].apply(page, args);
} catch (err) {
let stringArgs = args
.map(i => typeof i == 'function' ? 'Function' : i)
.join(', ');
throw new Error(`.${name}(${stringArgs}): ${err.message}`);
}
}; };
} }

View File

@ -4,16 +4,22 @@ import {extendPage} from './extensions';
import {url as defaultURL} from './config'; import {url as defaultURL} from './config';
export async function getBrowser() { export async function getBrowser() {
let headless = !process.env.E2E_SHOW; const args = [
`--no-sandbox`,
`--window-size=${ 1920 },${ 1080 }`
];
if (process.env.DEBUG)
args.push('--auto-open-devtools-for-tabs');
const headless = !(process.env.E2E_SHOW || process.env.DEBUG);
const browser = await Puppeteer.launch({ const browser = await Puppeteer.launch({
args: [ args,
'--no-sandbox',
`--window-size=${ 1920 },${ 1080 }`
],
defaultViewport: null, defaultViewport: null,
headless: headless, headless: headless,
slowMo: 0, // slow down by ms slowMo: 0, // slow down by ms
}); });
let page = (await browser.pages())[0]; let page = (await browser.pages())[0];
await page.evaluateOnNewDocument(() => { await page.evaluateOnNewDocument(() => {
Object.defineProperty(navigator, 'language', { Object.defineProperty(navigator, 'language', {
@ -28,8 +34,8 @@ export async function getBrowser() {
}); });
}); });
page = extendPage(page); page = extendPage(page);
page.setDefaultTimeout(10000); page.setDefaultTimeout(4000);
await page.goto(defaultURL, {waitUntil: 'networkidle0'}); await page.goto(defaultURL, {waitUntil: 'load'});
return {page, close: browser.close.bind(browser)}; return {page, close: browser.close.bind(browser)};
} }

View File

@ -208,7 +208,7 @@ export default {
createItemButton: `vn-float-button`, createItemButton: `vn-float-button`,
firstSearchResult: 'vn-item-index a:nth-child(1)', firstSearchResult: 'vn-item-index a:nth-child(1)',
searchResult: 'vn-item-index a.vn-tr', searchResult: 'vn-item-index a.vn-tr',
searchResultPreviewButton: 'vn-item-index .buttons > [icon="desktop_windows"]', firstResultPreviewButton: 'vn-item-index vn-tbody > :nth-child(1) .buttons > [icon="desktop_windows"]',
searchResultCloneButton: 'vn-item-index .buttons > [icon="icon-clone"]', searchResultCloneButton: 'vn-item-index .buttons > [icon="icon-clone"]',
acceptClonationAlertButton: '.vn-confirm.shown [response="accept"]', acceptClonationAlertButton: '.vn-confirm.shown [response="accept"]',
topbarSearch: 'vn-topbar', topbarSearch: 'vn-topbar',
@ -260,7 +260,6 @@ export default {
secondRequestDecline: 'vn-item-request vn-tbody > vn-tr:nth-child(1) vn-icon-button[icon="thumb_down"]', secondRequestDecline: 'vn-item-request vn-tbody > vn-tr:nth-child(1) vn-icon-button[icon="thumb_down"]',
declineReason: 'vn-textarea[ng-model="$ctrl.denyObservation"]', declineReason: 'vn-textarea[ng-model="$ctrl.denyObservation"]',
acceptDeclineReason: 'button[response="accept"]', acceptDeclineReason: 'button[response="accept"]',
}, },
itemBasicData: { itemBasicData: {
basicDataButton: 'vn-left-menu a[ui-sref="item.card.basicData"]', basicDataButton: 'vn-left-menu a[ui-sref="item.card.basicData"]',
@ -369,7 +368,7 @@ export default {
newTicketButton: 'vn-ticket-index a', newTicketButton: 'vn-ticket-index a',
searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr', searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr', searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr',
searchResultDate: 'vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(5)', searchResultDate: 'vn-ticket-summary [label=Landed] span',
topbarSearch: 'vn-searchbar', topbarSearch: 'vn-searchbar',
advancedSearchButton: 'vn-ticket-search-panel button[type=submit]', advancedSearchButton: 'vn-ticket-search-panel button[type=submit]',
searchButton: 'vn-searchbar vn-icon[icon="search"]', searchButton: 'vn-searchbar vn-icon[icon="search"]',

View File

@ -12,32 +12,42 @@ describe('Login path', async() => {
await browser.close(); await browser.close();
}); });
it('should receive an error when the username is incorrect', async() => { describe('Bad login', async() => {
await page.doLogin('badUser', ''); it('should receive an error when the username is incorrect', async() => {
const result = await page.waitForLastSnackbar(); await page.doLogin('badUser', '');
const result = await page.waitForLastSnackbar();
const state = await page.getState();
expect(result.length).toBeGreaterThan(0); expect(result.length).toBeGreaterThan(0);
expect(state).toBe('login');
});
it('should receive an error when the username is blank', async() => {
await page.doLogin('', '');
const result = await page.waitForLastSnackbar();
const state = await page.getState();
expect(result.length).toBeGreaterThan(0);
expect(state).toBe('login');
});
it('should receive an error when the password is incorrect', async() => {
await page.doLogin('employee', 'badPassword');
const result = await page.waitForLastSnackbar();
const state = await page.getState();
expect(result.length).toBeGreaterThan(0);
expect(state).toBe('login');
});
}); });
it('should receive an error when the username is blank', async() => { describe('Successful login', async() => {
await page.doLogin('', ''); it('should log in', async() => {
const result = await page.waitForLastSnackbar(); await page.doLogin('employee', 'nightmare');
await page.waitForNavigation();
const state = await page.getState();
expect(result.length).toBeGreaterThan(0); expect(state).toBe('home');
}); });
it('should receive an error when the password is incorrect', async() => {
await page.doLogin('employee', 'badPassword');
const result = await page.waitForLastSnackbar();
expect(result.length).toBeGreaterThan(0);
});
it('should log in', async() => {
await page.doLogin('employee', 'nightmare');
await page.waitForNavigation();
let url = await page.expectURL('#!/');
expect(url).toBe(true);
}); });
}); });

View File

@ -25,10 +25,7 @@ describe('Client create path', async() => {
it('should now access to the create client view by clicking the create-client floating button', async() => { it('should now access to the create client view by clicking the create-client floating button', async() => {
await page.waitToClick(selectors.clientsIndex.createClientButton); await page.waitToClick(selectors.clientsIndex.createClientButton);
await page.wait(selectors.createClientView.createButton); await page.waitForState('client.create');
let url = await page.expectURL('#!/client/create');
expect(url).toBe(true);
}); });
it('should receive an error when clicking the create button having all the form fields empty', async() => { it('should receive an error when clicking the create button having all the form fields empty', async() => {
@ -105,15 +102,11 @@ describe('Client create path', async() => {
await page.wait(selectors.globalItems.applicationsMenuVisible); await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.clientsButton); await page.waitToClick(selectors.globalItems.clientsButton);
await page.wait(selectors.clientsIndex.createClientButton); await page.wait(selectors.clientsIndex.createClientButton);
let url = await page.expectURL('#!/client/index'); await page.waitForState('client.index');
expect(url).toBe(true);
}); });
it(`should search for the user Carol Danvers to confirm it exists`, async() => { it(`should search for the user Carol Danvers to confirm it exists`, async() => {
await page.accessToSearchResult('Carol Danvers'); await page.accessToSearchResult('Carol Danvers');
let url = await page.expectURL('#!/client/114/summary'); await page.waitForState('client.card.summary');
expect(url).toBe(true);
}); });
}); });

View File

@ -36,9 +36,7 @@ describe('Client Edit fiscalData path', () => {
it(`should click on the fiscal data button`, async() => { it(`should click on the fiscal data button`, async() => {
await page.waitToClick(selectors.clientFiscalData.fiscalDataButton); await page.waitToClick(selectors.clientFiscalData.fiscalDataButton);
let url = await page.expectURL('fiscal-data'); await page.waitForState('client.card.fiscalData');
expect(url).toBe(true);
}); });
it('should not be able to edit the verified data checkbox', async() => { it('should not be able to edit the verified data checkbox', async() => {
@ -124,9 +122,7 @@ describe('Client Edit fiscalData path', () => {
// 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`, async() => { it(`should click on the addresses button to access to the client's addresses`, async() => {
await page.waitToClick(selectors.clientAddresses.addressesButton); await page.waitToClick(selectors.clientAddresses.addressesButton);
let url = await page.expectURL('/address/index'); await page.waitForState('client.card.address.index');
expect(url).toBe(true);
}); });
// confirm all addresses have now EQtax checked step 2 // confirm all addresses have now EQtax checked step 2
@ -261,9 +257,7 @@ describe('Client Edit fiscalData path', () => {
// 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`, async() => { it(`should click on the addresses button to access to the client's addresses`, async() => {
await page.waitToClick(selectors.clientAddresses.addressesButton); await page.waitToClick(selectors.clientAddresses.addressesButton);
let url = await page.expectURL('/address/index'); await page.waitForState('client.card.address.index');
expect(url).toBe(true);
}); });
// 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

View File

@ -18,9 +18,7 @@ describe('Client Add address path', () => {
it(`should click on the add new address button to access to the new address form`, async() => { it(`should click on the add new address button to access to the new address form`, async() => {
await page.waitToClick(selectors.clientAddresses.createAddress); await page.waitToClick(selectors.clientAddresses.createAddress);
let url = await page.expectURL('address/create'); await page.waitForState('client.card.address.create');
expect(url).toBe(true);
}); });
it('should receive an error after clicking save button as consignee, street and town fields are empty', async() => { it('should receive an error after clicking save button as consignee, street and town fields are empty', async() => {
@ -72,9 +70,7 @@ describe('Client Add address path', () => {
}); });
it(`should navigate back to the addresses index`, async() => { it(`should navigate back to the addresses index`, async() => {
let url = await page.expectURL('/address/index'); await page.waitForState('client.card.address.index');
expect(url).toBe(true);
}); });
it(`should confirm the new address exists and it's the default one`, async() => { it(`should confirm the new address exists and it's the default one`, async() => {
@ -101,9 +97,7 @@ describe('Client Add address path', () => {
it(`should click on the edit icon of the default address`, async() => { it(`should click on the edit icon of the default address`, async() => {
await page.waitForTextInElement(selectors.clientAddresses.defaultAddress, 'Somewhere in Thailand'); await page.waitForTextInElement(selectors.clientAddresses.defaultAddress, 'Somewhere in Thailand');
await page.waitToClick(selectors.clientAddresses.firstEditAddress); await page.waitToClick(selectors.clientAddresses.firstEditAddress);
let url = await page.expectURL('/edit'); await page.waitForState('client.card.address.edit');
expect(url).toBe(true);
}); });
it(`should click on the active checkbox and receive an error to save it because it is the default address`, async() => { it(`should click on the active checkbox and receive an error to save it because it is the default address`, async() => {
@ -119,8 +113,6 @@ describe('Client Add address path', () => {
await page.waitForSelector('#shapes .shown', {hidden: true}); await page.waitForSelector('#shapes .shown', {hidden: true});
await page.waitToClick(selectors.clientAddresses.cancelEditAddressButton); await page.waitToClick(selectors.clientAddresses.cancelEditAddressButton);
await page.waitToClick('.vn-confirm.shown button[response="accept"]'); await page.waitToClick('.vn-confirm.shown button[response="accept"]');
let url = await page.expectURL('address/index'); await page.waitForState('client.card.address.index');
expect(url).toBe(true);
}); });
}); });

View File

@ -19,9 +19,7 @@ describe('Client add address notes path', () => {
it(`should click on the edit icon of the default address`, async() => { it(`should click on the edit icon of the default address`, async() => {
await page.waitForTextInElement(selectors.clientAddresses.defaultAddress, '20 Ingram Street'); await page.waitForTextInElement(selectors.clientAddresses.defaultAddress, '20 Ingram Street');
await page.waitToClick(selectors.clientAddresses.firstEditAddress); await page.waitToClick(selectors.clientAddresses.firstEditAddress);
let url = await page.expectURL('/edit'); await page.waitForState('client.card.address.edit');
expect(url).toBe(true);
}); });
it('should not save a description without observation type', async() => { it('should not save a description without observation type', async() => {

View File

@ -17,16 +17,12 @@ describe('Client Add notes path', () => {
}); });
it(`should reach the notes index`, async() => { it(`should reach the notes index`, async() => {
let url = await page.expectURL('/note'); await page.waitForState('client.card.note.index');
expect(url).toBe(true);
}); });
it(`should click on the add note button`, async() => { it(`should click on the add note button`, async() => {
await page.waitToClick(selectors.clientNotes.addNoteFloatButton); await page.waitToClick(selectors.clientNotes.addNoteFloatButton);
let url = await page.expectURL('/note/create'); await page.waitForState('client.card.note.create');
expect(url).toBe(true);
}); });
it(`should create a note`, async() => { it(`should create a note`, async() => {

View File

@ -18,9 +18,7 @@ describe('Client Add credit path', () => {
it(`should click on the add credit button`, async() => { it(`should click on the add credit button`, async() => {
await page.waitToClick(selectors.clientCredit.addCreditFloatButton); await page.waitToClick(selectors.clientCredit.addCreditFloatButton);
let url = await page.expectURL('/credit/create'); await page.waitForState('client.card.credit.create');
expect(url).toBe(true);
}); });
it(`should edit the credit`, async() => { it(`should edit the credit`, async() => {

View File

@ -18,9 +18,7 @@ describe('Client Add greuge path', () => {
it(`should click on the add greuge button`, async() => { it(`should click on the add greuge button`, async() => {
await page.waitToClick(selectors.clientGreuge.addGreugeFloatButton); await page.waitToClick(selectors.clientGreuge.addGreugeFloatButton);
let url = await page.expectURL('greuge/create'); await page.waitForState('client.card.greuge.create');
expect(url).toBe(true);
}); });
it(`should receive an error if all fields are empty but date and type on submit`, async() => { it(`should receive an error if all fields are empty but date and type on submit`, async() => {

View File

@ -109,7 +109,7 @@ describe('Client lock verified data path', () => {
await page.waitToClick(selectors.clientFiscalData.saveButton); await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();
expect(result).toEqual(jasmine.arrayContaining([`You can't make changes on a client with verified data`])); expect(result).toEqual(`You can't make changes on a client with verified data`);
}); });
}); });

View File

@ -27,9 +27,7 @@ describe('Client log path', () => {
it('should navigate to the log section', async() => { it('should navigate to the log section', async() => {
await page.waitToClick(selectors.clientLog.logButton); await page.waitToClick(selectors.clientLog.logButton);
let url = await page.expectURL('log'); await page.waitForState('client.card.log');
expect(url).toBe(true);
}); });
it('should check the previous value of the last logged change', async() => { it('should check the previous value of the last logged change', async() => {
@ -46,7 +44,6 @@ describe('Client log path', () => {
let lastModificationCurrentValue = await page. let lastModificationCurrentValue = await page.
waitToGetProperty(selectors.clientLog.lastModificationCurrentValue, 'innerText'); waitToGetProperty(selectors.clientLog.lastModificationCurrentValue, 'innerText');
expect(lastModificationPreviousValue).toEqual('name: DavidCharlesHaller'); expect(lastModificationPreviousValue).toEqual('name: DavidCharlesHaller');
expect(lastModificationCurrentValue).toEqual('name: this is a test'); expect(lastModificationCurrentValue).toEqual('name: this is a test');
}); });

View File

@ -41,9 +41,7 @@ describe('Client balance path', () => {
it('should click the new payment button', async() => { it('should click the new payment button', async() => {
await page.closePopup(); await page.closePopup();
await page.reloadSection('client.card.balance.index'); await page.reloadSection('client.card.balance.index');
let url = await page.expectURL('/balance'); await page.waitForState('client.card.balance.index');
expect(url).toBe(true);
}); });
it('should create a new payment that clears the debt', async() => { it('should create a new payment that clears the debt', async() => {
@ -110,28 +108,13 @@ describe('Client balance path', () => {
await page.wait(selectors.globalItems.applicationsMenuVisible); await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.clientsButton); await page.waitToClick(selectors.globalItems.clientsButton);
await page.wait(selectors.clientsIndex.createClientButton); await page.wait(selectors.clientsIndex.createClientButton);
let url = await page.expectURL('#!/client/index'); await page.waitForState('client.index');
expect(url).toBe(true);
}); });
it('should now search for the user Petter Parker', async() => { it('should now search for the user Petter Parker', async() => {
await page.write(selectors.clientsIndex.topbarSearch, 'Petter Parker'); await page.accessToSearchResult('Petter Parker');
await page.waitToClick(selectors.clientsIndex.searchButton);
await page.waitForNumberOfElements(selectors.clientsIndex.searchResult, 1);
let resultCount = await page.countElement(selectors.clientsIndex.searchResult);
expect(resultCount).toEqual(1);
});
it(`should click on the search result to access to the client's balance`, async() => {
await page.waitForTextInElement(selectors.clientsIndex.searchResult, 'Petter Parker');
await page.waitToClick(selectors.clientsIndex.searchResult);
await page.waitForContentLoaded();
await page.waitToClick(selectors.clientBalance.balanceButton); await page.waitToClick(selectors.clientBalance.balanceButton);
let url = await page.expectURL('/balance'); await page.waitForState('client.card.balance.index');
expect(url).toBe(true);
}); });
it('should not be able to click the new payment button as it isnt present', async() => { it('should not be able to click the new payment button as it isnt present', async() => {

View File

@ -17,9 +17,7 @@ describe('Client summary path', () => {
}); });
it('should reach the first route summary section', async() => { it('should reach the first route summary section', async() => {
let url = await page.expectURL('#!/client/102/summary'); await page.waitForState('client.card.summary');
expect(url).toBe(true);
}); });
it('should display details from the client on the header', async() => { it('should display details from the client on the header', async() => {

View File

@ -16,9 +16,7 @@ describe('Worker summary path', () => {
}); });
it('should reach the employee summary section', async() => { it('should reach the employee summary section', async() => {
const url = await page.expectURL('#!/worker/3/summary'); await page.waitForState('worker.card.summary');
expect(url).toBe(true);
}); });
it('should check the summary contains the name and userName on the header', async() => { it('should check the summary contains the name and userName on the header', async() => {

View File

@ -316,16 +316,12 @@ describe('Worker time control path', () => {
it('should search for a worker and access to its summary', async() => { it('should search for a worker and access to its summary', async() => {
await page.accessToSearchResult('HankPym'); await page.accessToSearchResult('HankPym');
let url = await page.expectURL('/summary'); await page.waitForState('worker.card.summary');
expect(url).toBe(true);
}); });
it('should access to the time control section', async() => { it('should access to the time control section', async() => {
await page.accessToSection('worker.card.timeControl'); await page.accessToSection('worker.card.timeControl');
let url = await page.expectURL('/time-control'); await page.waitForState('worker.card.timeControl');
expect(url).toBe(true);
}); });
it('should lovingly scan in Hank Pym', async() => { it('should lovingly scan in Hank Pym', async() => {

View File

@ -16,17 +16,11 @@ describe('Item summary path', () => {
it('should search for an item', async() => { it('should search for an item', async() => {
await page.clearInput(selectors.itemsIndex.topbarSearch); await page.clearInput(selectors.itemsIndex.topbarSearch);
await page.write(selectors.itemsIndex.topbarSearch, 'Ranged weapon longbow 2m'); await page.write(selectors.itemsIndex.topbarSearch, 'Ranged weapon');
await page.waitToClick(selectors.itemsIndex.searchButton); await page.waitToClick(selectors.itemsIndex.searchButton);
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1); await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3);
const result = await page.countElement(selectors.itemsIndex.searchResult); await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Ranged weapon');
await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton);
expect(result).toEqual(1);
});
it(`should click on the search result summary button to open the item summary popup`, async() => {
await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Ranged weapon longbow 2m');
await page.waitToClick(selectors.itemsIndex.searchResultPreviewButton);
const isVisible = await page.isVisible(selectors.itemSummary.basicData); const isVisible = await page.isVisible(selectors.itemSummary.basicData);
expect(isVisible).toBeTruthy(); expect(isVisible).toBeTruthy();
@ -74,25 +68,18 @@ describe('Item summary path', () => {
it('should search for other item', async() => { it('should search for other item', async() => {
await page.clearInput('vn-searchbar'); await page.clearInput('vn-searchbar');
await page.waitToClick(selectors.itemsIndex.searchButton); await page.write(selectors.itemsIndex.topbarSearch, 'Melee Reinforced');
await page.write(selectors.itemsIndex.topbarSearch, 'Melee weapon combat fist 15cm'); await page.keyboard.press('Enter');
await page.waitToClick(selectors.itemsIndex.searchButton); await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2);
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1); await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton);
const result = await page.countElement(selectors.itemsIndex.searchResult);
expect(result).toEqual(1);
});
it(`should now click on the search result summary button to open the item summary popup`, async() => {
await page.waitToClick(selectors.itemsIndex.searchResultPreviewButton);
await page.waitForSelector(selectors.itemSummary.basicData, {visible: true}); await page.waitForSelector(selectors.itemSummary.basicData, {visible: true});
}); });
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() => {
await page.waitForTextInElement(selectors.itemSummary.basicData, 'Melee weapon combat fist 15cm'); await page.waitForTextInElement(selectors.itemSummary.basicData, 'Melee Reinforced weapon combat fist 15cm');
const result = await page.waitToGetProperty(selectors.itemSummary.basicData, 'innerText'); const result = await page.waitToGetProperty(selectors.itemSummary.basicData, 'innerText');
expect(result).toContain('Melee weapon combat fist 15cm'); expect(result).toContain('Melee Reinforced weapon combat fist 15cm');
}); });
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() => {
@ -102,13 +89,6 @@ describe('Item summary path', () => {
expect(result).toContain('Silver'); expect(result).toContain('Silver');
}); });
it(`should now check the item summary preview shows fields from niche`, async() => {
await page.waitForTextInElement(selectors.itemSummary.niche, 'A4');
const result = await page.waitToGetProperty(selectors.itemSummary.niche, 'innerText');
expect(result).toContain('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() => {
await page.waitForTextInElement(selectors.itemSummary.botanical, '-'); await page.waitForTextInElement(selectors.itemSummary.botanical, '-');
const result = await page.waitToGetProperty(selectors.itemSummary.botanical, 'innerText'); const result = await page.waitToGetProperty(selectors.itemSummary.botanical, 'innerText');
@ -116,23 +96,14 @@ describe('Item summary path', () => {
expect(result).toContain('-'); expect(result).toContain('-');
}); });
it(`should now check the item summary preview shows fields from barcode`, async() => {
await page.waitForTextInElement(selectors.itemSummary.barcode, '4');
const result = await page.waitToGetProperty(selectors.itemSummary.barcode, 'innerText');
expect(result).toContain('4');
});
it(`should now close the summary popup`, async() => { it(`should now close the summary popup`, async() => {
await page.closePopup(); await page.closePopup();
await page.waitForSelector(selectors.itemSummary.basicData, {hidden: true}); await page.waitForSelector(selectors.itemSummary.basicData, {hidden: true});
}); });
it(`should navigate to the one of the items detailed section`, async() => { it(`should navigate to the one of the items detailed section`, async() => {
await page.waitToClick(selectors.itemsIndex.searchResult); await page.accessToSearchResult('Melee weapon combat fist 15cm');
let url = await page.expectURL('summary'); await page.waitForState('item.card.summary');
expect(url).toBe(true);
}); });
it(`should check the descritor edit button is not visible for employee`, async() => { it(`should check the descritor edit button is not visible for employee`, async() => {

View File

@ -27,23 +27,17 @@ describe('Item Create/Clone path', () => {
it('should access to the create item view by clicking the create floating button', async() => { it('should access to the create item view by clicking the create floating button', async() => {
await page.waitToClick(selectors.itemsIndex.createItemButton); await page.waitToClick(selectors.itemsIndex.createItemButton);
let url = await page.expectURL('#!/item/create'); await page.waitForState('item.create');
expect(url).toBe(true);
}); });
it('should return to the item index by clickig the cancel button', async() => { it('should return to the item index by clickig the cancel button', async() => {
await page.waitToClick(selectors.itemCreateView.cancelButton); await page.waitToClick(selectors.itemCreateView.cancelButton);
let url = await page.expectURL('#!/item/index'); await page.waitForState('item.index');
expect(url).toBe(true);
}); });
it('should now access to the create item view by clicking the create floating button', async() => { it('should now access to the create item view by clicking the create floating button', async() => {
await page.waitToClick(selectors.itemsIndex.createItemButton); await page.waitToClick(selectors.itemsIndex.createItemButton);
let url = await page.expectURL('#!/item/create'); await page.waitForState('item.create');
expect(url).toBe(true);
}); });
it('should create the Infinity Gauntlet item', async() => { it('should create the Infinity Gauntlet item', async() => {
@ -63,7 +57,6 @@ describe('Item Create/Clone path', () => {
expect(result).toEqual('Infinity Gauntlet'); expect(result).toEqual('Infinity Gauntlet');
result = await page result = await page
.waitToGetProperty(selectors.itemBasicData.type, 'value'); .waitToGetProperty(selectors.itemBasicData.type, 'value');
@ -81,13 +74,14 @@ describe('Item Create/Clone path', () => {
}); });
}); });
describe('clone', () => { // Issue #2201
// When there is just one result you're redirected automatically to it, so
// it's not possible to use the clone option.
xdescribe('clone', () => {
it('should return to the items index by clicking the return to items button', async() => { it('should return to the items index by clicking the return to items button', async() => {
await page.waitToClick(selectors.itemBasicData.goToItemIndexButton); await page.waitToClick(selectors.itemBasicData.goToItemIndexButton);
await page.wait(selectors.itemsIndex.createItemButton); await page.wait(selectors.itemsIndex.createItemButton);
let url = await page.expectURL('#!/item/index'); await page.waitForState('item.index');
expect(url).toBe(true);
}); });
it(`should search for the item Infinity Gauntlet`, async() => { it(`should search for the item Infinity Gauntlet`, async() => {
@ -104,9 +98,7 @@ describe('Item Create/Clone path', () => {
await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Infinity Gauntlet'); await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Infinity Gauntlet');
await page.waitToClick(selectors.itemsIndex.searchResultCloneButton); await page.waitToClick(selectors.itemsIndex.searchResultCloneButton);
await page.waitToClick(selectors.itemsIndex.acceptClonationAlertButton); await page.waitToClick(selectors.itemsIndex.acceptClonationAlertButton);
let url = await page.expectURL('tags'); await page.waitForState('item.tags');
expect(url).toBe(true);
}); });
it('should search for the item Infinity Gauntlet and find two', async() => { it('should search for the item Infinity Gauntlet and find two', async() => {

View File

@ -33,20 +33,8 @@ describe('Item regularize path', () => {
}); });
it('should search for an specific item', async() => { it('should search for an specific item', async() => {
await page.write(selectors.itemsIndex.topbarSearch, 'Ranged weapon pistol 9mm'); await page.accessToSearchResult('Ranged weapon pistol 9mm');
await page.waitToClick(selectors.itemsIndex.searchButton); await page.waitForState('item.card.summary');
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1);
const resultCount = await page.countElement(selectors.itemsIndex.searchResult);
expect(resultCount).toEqual(1);
});
it(`should click on the search result to access to the summary`, async() => {
await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Ranged weapon pistol 9mm');
await page.waitToClick(selectors.itemsIndex.searchResult);
let url = await page.expectURL('/summary');
expect(url).toBe(true);
}); });
it('should open the regularize dialog and check the warehouse matches the local user settings', async() => { it('should open the regularize dialog and check the warehouse matches the local user settings', async() => {
@ -73,9 +61,7 @@ describe('Item regularize path', () => {
page.waitForNavigation({waitUntil: ['load', 'networkidle0', 'domcontentloaded']}), page.waitForNavigation({waitUntil: ['load', 'networkidle0', 'domcontentloaded']}),
page.waitToClick(selectors.globalItems.ticketsButton) page.waitToClick(selectors.globalItems.ticketsButton)
]); ]);
let url = await page.expectURL('#!/ticket/index'); await page.waitForState('ticket.index');
expect(url).toBe(true);
}); });
it('should clear the user local settings now', async() => { it('should clear the user local settings now', async() => {
@ -89,20 +75,8 @@ describe('Item regularize path', () => {
it('should search for the ticket with alias missing', async() => { it('should search for the ticket with alias missing', async() => {
await page.keyboard.press('Escape'); await page.keyboard.press('Escape');
await page.write(selectors.ticketsIndex.topbarSearch, 'missing'); await page.accessToSearchResult('missing');
await page.keyboard.press('Enter'); await page.waitForState('ticket.card.summary');
await page.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1);
const result = await page.countElement(selectors.ticketsIndex.searchResult);
expect(result).toEqual(1);
});
it(`should click on the search result to access to the ticket summary`, async() => {
await page.waitForTextInElement(selectors.ticketsIndex.searchResult, 'Missing');
await page.waitToClick(selectors.ticketsIndex.searchResult);
let url = await page.expectURL('/summary');
expect(url).toBe(true);
}); });
it(`should check the ticket sale quantity is showing a negative value`, async() => { it(`should check the ticket sale quantity is showing a negative value`, async() => {
@ -124,27 +98,12 @@ describe('Item regularize path', () => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton); await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible); await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.itemsButton); await page.waitToClick(selectors.globalItems.itemsButton);
let url = await page.expectURL('#!/item/index'); await page.waitForState('item.index');
expect(url).toBe(true);
}); });
it('should search for the item once again', async() => { it('should search for the item once again', async() => {
await page.clearInput(selectors.itemsIndex.topbarSearch); await page.accessToSearchResult('Ranged weapon pistol 9mm');
await page.write(selectors.itemsIndex.topbarSearch, 'Ranged weapon pistol 9mm'); await page.waitForState('item.card.summary');
await page.waitToClick(selectors.itemsIndex.searchButton);
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1);
const resultCount = await page.countElement(selectors.itemsIndex.searchResult);
expect(resultCount).toEqual(1);
});
it(`should click on the search result to access to the item tax`, async() => {
await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Ranged weapon pistol 9mm');
await page.waitToClick(selectors.itemsIndex.searchResult);
let url = await page.expectURL('/summary');
expect(url).toBe(true);
}); });
it('should regularize the item once more', async() => { it('should regularize the item once more', async() => {
@ -166,26 +125,12 @@ describe('Item regularize path', () => {
page.waitToClick(selectors.globalItems.ticketsButton) page.waitToClick(selectors.globalItems.ticketsButton)
]); ]);
await page.waitForTransitionEnd('vn-searchbar'); await page.waitForTransitionEnd('vn-searchbar');
let url = await page.expectURL('#!/ticket/index'); await page.waitForState('ticket.index');
expect(url).toBe(true);
}); });
it('should search for the ticket with id 25 once again', async() => { it('should search for the ticket with id 25 once again', async() => {
await page.write(selectors.ticketsIndex.topbarSearch, '25'); await page.accessToSearchResult('25');
await page.waitToClick(selectors.ticketsIndex.searchButton); await page.waitForState('ticket.card.summary');
await page.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1);
const result = await page.countElement(selectors.ticketsIndex.searchResult);
expect(result).toEqual(1);
});
it(`should now click on the search result to access to the ticket summary`, async() => {
await page.waitForTextInElement(selectors.ticketsIndex.searchResult, '25');
await page.waitToClick(selectors.ticketsIndex.searchResult);
let url = await page.expectURL('/summary');
expect(url).toBe(true);
}); });
it(`should check the ticket contains now two sales`, async() => { it(`should check the ticket contains now two sales`, async() => {

View File

@ -25,9 +25,7 @@ describe('Item log path', () => {
it('should access to the create item view by clicking the create floating button', async() => { it('should access to the create item view by clicking the create floating button', async() => {
await page.waitToClick(selectors.itemsIndex.createItemButton); await page.waitToClick(selectors.itemsIndex.createItemButton);
let url = await page.expectURL('#!/item/create'); await page.waitForState('item.create');
expect(url).toBe(true);
}); });
it('should create the Knowledge artifact item', async() => { it('should create the Knowledge artifact item', async() => {
@ -44,17 +42,13 @@ describe('Item log path', () => {
it('should return to the items index by clicking the return to items button', async() => { it('should return to the items index by clicking the return to items button', async() => {
await page.waitToClick(selectors.itemBasicData.goToItemIndexButton); await page.waitToClick(selectors.itemBasicData.goToItemIndexButton);
await page.wait(selectors.itemsIndex.createItemButton); await page.wait(selectors.itemsIndex.createItemButton);
let url = await page.expectURL('#!/item/index'); await page.waitForState('item.index');
expect(url).toBe(true);
}); });
it(`should search for the created item and navigate to it's log section`, async() => { it(`should search for the created item and navigate to it's log section`, async() => {
await page.accessToSearchResult('Knowledge artifact'); await page.accessToSearchResult('Knowledge artifact');
await page.accessToSection('item.card.log'); await page.accessToSection('item.card.log');
let url = await page.expectURL('/log'); await page.waitForState('item.card.log');
expect(url).toBe(true);
}); });
it(`should confirm the log is showing 5 entries`, async() => { it(`should confirm the log is showing 5 entries`, async() => {

View File

@ -16,9 +16,7 @@ describe('Item request path', () => {
}); });
it('should reach the item request section', async() => { it('should reach the item request section', async() => {
const result = await page.expectURL('/item/request'); await page.waitForState('item.request');
expect(result).toBe(true);
}); });
it('should fill the id and quantity then check the concept was updated', async() => { it('should fill the id and quantity then check the concept was updated', async() => {
@ -38,9 +36,8 @@ describe('Item request path', () => {
it('should now click on the second declain request icon then type the reason', async() => { it('should now click on the second declain request icon then type the reason', async() => {
await page.waitToClick(selectors.itemRequest.secondRequestDecline); await page.waitToClick(selectors.itemRequest.secondRequestDecline);
await page.write(selectors.itemRequest.declineReason, 'not quite as expected'); await page.write(selectors.itemRequest.declineReason, 'Not quite as expected');
await page.waitToClick(selectors.itemRequest.acceptDeclineReason); await page.respondToDialog('accept');
await page.waitForContentLoaded();
let status = await page.waitToGetProperty(selectors.itemRequest.firstRequestStatus, 'innerText'); let status = await page.waitToGetProperty(selectors.itemRequest.firstRequestStatus, 'innerText');
expect(status).toContain('Denegada'); expect(status).toContain('Denegada');

View File

@ -19,8 +19,9 @@ describe('Ticket expeditions and log path', () => {
it(`should delete a former expedition and confirm the remaining expedition are the expected ones`, async() => { it(`should delete a former expedition and confirm the remaining expedition are the expected ones`, async() => {
await page.waitToClick(selectors.ticketExpedition.secondExpeditionRemoveButton); await page.waitToClick(selectors.ticketExpedition.secondExpeditionRemoveButton);
await page.waitToClick(selectors.ticketExpedition.acceptDeleteRowButton), await page.waitToClick(selectors.ticketExpedition.acceptDeleteRowButton);
await page.reloadSection('ticket.card.expedition'); await page.reloadSection('ticket.card.expedition');
await page.waitForSelector(selectors.ticketExpedition.expeditionRow, {}); await page.waitForSelector(selectors.ticketExpedition.expeditionRow, {});
const result = await page const result = await page
.countElement(selectors.ticketExpedition.expeditionRow); .countElement(selectors.ticketExpedition.expeditionRow);

View File

@ -21,9 +21,7 @@ describe('Ticket Create new tracking state path', () => {
it('should access to the create state view by clicking the create floating button', async() => { it('should access to the create state view by clicking the create floating button', async() => {
await page.waitToClick(selectors.ticketTracking.createStateButton); await page.waitToClick(selectors.ticketTracking.createStateButton);
await page.waitForSelector(selectors.createStateView.state, {visible: true}); await page.waitForSelector(selectors.createStateView.state, {visible: true});
let url = await page.expectURL('tracking/edit'); await page.waitForState('ticket.card.tracking.edit');
expect(url).toBe(true);
}); });
it(`should attempt create a new state but receive an error if state is empty`, async() => { it(`should attempt create a new state but receive an error if state is empty`, async() => {
@ -51,9 +49,7 @@ describe('Ticket Create new tracking state path', () => {
it('should now access to the create state view by clicking the create floating button', async() => { it('should now access to the create state view by clicking the create floating button', async() => {
await page.waitToClick(selectors.ticketTracking.createStateButton); await page.waitToClick(selectors.ticketTracking.createStateButton);
let url = await page.expectURL('tracking/edit'); await page.waitForState('ticket.card.tracking.edit');
expect(url).toBe(true);
}); });
it(`should attemp to create an state for which salesPerson doesn't have permissions`, async() => { it(`should attemp to create an state for which salesPerson doesn't have permissions`, async() => {

View File

@ -68,9 +68,7 @@ describe('Ticket Edit basic data path', () => {
it(`should click next`, async() => { it(`should click next`, async() => {
await page.waitToClick(selectors.ticketBasicData.nextStepButton); await page.waitToClick(selectors.ticketBasicData.nextStepButton);
let url = await page.expectURL('data/step-two'); await page.waitForState('ticket.card.basicData.stepTwo');
expect(url).toBe(true);
}); });
it(`should have a price diference`, async() => { it(`should have a price diference`, async() => {
@ -83,8 +81,6 @@ describe('Ticket Edit basic data path', () => {
it(`should select a new reason for the changes made then click on finalize`, async() => { it(`should select a new reason for the changes made then click on finalize`, async() => {
await page.waitToClick(selectors.ticketBasicData.chargesReason); await page.waitToClick(selectors.ticketBasicData.chargesReason);
await page.waitToClick(selectors.ticketBasicData.finalizeButton); await page.waitToClick(selectors.ticketBasicData.finalizeButton);
let url = await page.expectURL('summary'); await page.waitForState('ticket.card.summary');
expect(url).toBe(true);
}); });
}); });

View File

@ -41,9 +41,7 @@ describe('Ticket descriptor path', () => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton); await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible); await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton); await page.waitToClick(selectors.globalItems.ticketsButton);
let url = await page.expectURL('#!/ticket/index'); await page.waitForState('ticket.index');
expect(url).toBe(true);
}); });
it('should confirm the ticket 11 was added to thursday', async() => { it('should confirm the ticket 11 was added to thursday', async() => {
@ -57,25 +55,12 @@ describe('Ticket descriptor path', () => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton); await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible); await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton); await page.waitToClick(selectors.globalItems.ticketsButton);
let url = await page.expectURL('#!/ticket/index'); await page.waitForState('ticket.index');
expect(url).toBe(true);
}); });
it('should now search for the ticket 11', async() => { it('should now search for the ticket 11', async() => {
await page.write(selectors.ticketsIndex.topbarSearch, '11'); await page.accessToSearchResult('11');
await page.waitToClick(selectors.ticketsIndex.searchButton); await page.waitForState('ticket.card.summary');
await page.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1);
const result = await page.countElement(selectors.ticketsIndex.searchResult);
expect(result).toEqual(1);
});
it(`should click on the search result to access to the ticket`, async() => {
await page.waitToClick(selectors.ticketsIndex.searchResult);
let url = await page.expectURL('/summary');
expect(url).toBe(true);
}); });
it('should add the ticket to saturday turn using the descriptor more menu', async() => { it('should add the ticket to saturday turn using the descriptor more menu', async() => {
@ -91,9 +76,7 @@ describe('Ticket descriptor path', () => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton); await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible); await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton); await page.waitToClick(selectors.globalItems.ticketsButton);
let url = await page.expectURL('#!/ticket/index'); await page.waitForState('ticket.index');
expect(url).toBe(true);
}); });
it('should confirm the ticket 11 was added on saturday', async() => { it('should confirm the ticket 11 was added on saturday', async() => {

View File

@ -30,13 +30,10 @@ describe('Ticket purchase request path', () => {
}); });
it('should have been redirected to the request index', async() => { it('should have been redirected to the request index', async() => {
let url = await page.expectURL('/request'); await page.waitForState('ticket.card.request.index');
expect(url).toBe(true);
}); });
it(`should edit the third request quantity as it's state is still new`, async() => { it(`should edit the third request quantity as it's state is still new`, async() => {
await page.waitFor(2000); // looks like it needs more than a single second some times to load
await page.write(selectors.ticketRequests.thirdRequestQuantity, '9'); await page.write(selectors.ticketRequests.thirdRequestQuantity, '9');
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();

View File

@ -28,7 +28,7 @@ xdescribe('Ticket diary path', () => {
it(`should click on the search result to access to the ticket summary`, async() => { it(`should click on the search result to access to the ticket summary`, async() => {
await page.waitForTextInElement(selectors.ticketsIndex.searchResult, 'Bat cave'); await page.waitForTextInElement(selectors.ticketsIndex.searchResult, 'Bat cave');
await page.waitToClick(selectors.ticketsIndex.searchResult); await page.waitToClick(selectors.ticketsIndex.searchResult);
let url = await page.expectURL('/summary'); let url = await page.expectURL('/summary'); // use waitForState instead
expect(url).toBe(true); expect(url).toBe(true);
}); });
@ -37,7 +37,7 @@ xdescribe('Ticket diary path', () => {
await page.waitToClick(selectors.ticketSummary.firstSaleItemId); await page.waitToClick(selectors.ticketSummary.firstSaleItemId);
await page.waitForTransitionEnd('.vn-popover'); await page.waitForTransitionEnd('.vn-popover');
await page.waitToClick(selectors.ticketSummary.popoverDiaryButton); await page.waitToClick(selectors.ticketSummary.popoverDiaryButton);
let url = await page.expectURL('/diary'); let url = await page.expectURL('/diary'); // use waitForState instead
expect(url).toBe(true); expect(url).toBe(true);
}); });

View File

@ -17,20 +17,8 @@ describe('Ticket descriptor path', () => {
describe('Delete ticket', () => { describe('Delete ticket', () => {
it('should search for an specific ticket', async() => { it('should search for an specific ticket', async() => {
await page.write(selectors.ticketsIndex.topbarSearch, '18'); await page.accessToSearchResult('18');
await page.waitToClick(selectors.ticketsIndex.searchButton); await page.waitForState('ticket.card.summary');
await page.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1);
const result = await page.countElement(selectors.ticketsIndex.searchResult);
expect(result).toEqual(1);
});
it(`should click on the search result to access to the ticket summary`, async() => {
await page.waitForTextInElement(selectors.ticketsIndex.searchResult, 'Cerebro');
await page.waitToClick(selectors.ticketsIndex.searchResult);
let url = await page.expectURL('/summary');
expect(url).toBe(true);
}); });
it(`should update the shipped hour using the descriptor menu`, async() => { it(`should update the shipped hour using the descriptor menu`, async() => {
@ -60,16 +48,13 @@ describe('Ticket descriptor path', () => {
}); });
it('should have been relocated to the ticket index', async() => { it('should have been relocated to the ticket index', async() => {
let url = await page.expectURL('#!/ticket/index'); await page.waitForState('ticket.index');
expect(url).toBe(true);
}); });
it(`should search for the deleted ticket and check it's date`, async() => { it(`should search for the deleted ticket and check it's date`, async() => {
await page.write(selectors.ticketsIndex.topbarSearch, '18'); await page.write(selectors.ticketsIndex.topbarSearch, '18');
await page.waitToClick(selectors.ticketsIndex.searchButton); await page.waitToClick(selectors.ticketsIndex.searchButton);
await page.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1); await page.waitForState('ticket.card.summary');
await page.wait(selectors.ticketsIndex.searchResultDate);
const result = await page.waitToGetProperty(selectors.ticketsIndex.searchResultDate, 'innerText'); const result = await page.waitToGetProperty(selectors.ticketsIndex.searchResultDate, 'innerText');
expect(result).toContain(2000); expect(result).toContain(2000);
@ -78,21 +63,8 @@ describe('Ticket descriptor path', () => {
describe('add stowaway', () => { describe('add stowaway', () => {
it('should search for a ticket', async() => { it('should search for a ticket', async() => {
await page.clearInput(selectors.ticketsIndex.topbarSearch); await page.accessToSearchResult('16');
await page.write(selectors.ticketsIndex.topbarSearch, '16'); await page.waitForState('ticket.card.summary');
await page.waitToClick(selectors.ticketsIndex.searchButton);
await page.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1);
const result = await page.countElement(selectors.ticketsIndex.searchResult);
expect(result).toEqual(1);
});
it(`should now click on the search result to access to the ticket summary`, async() => {
await page.waitForTextInElement(selectors.ticketsIndex.searchResult, 'Many Places');
await page.waitToClick(selectors.ticketsIndex.searchResult);
let url = await page.expectURL('/summary');
expect(url).toBe(true);
}); });
it('should open the add stowaway dialog', async() => { it('should open the add stowaway dialog', async() => {
@ -123,9 +95,7 @@ describe('Ticket descriptor path', () => {
it(`should navigate back to the added ticket using the descriptors ship button`, async() => { it(`should navigate back to the added ticket using the descriptors ship button`, async() => {
await page.waitToClick(selectors.ticketDescriptor.shipButton); await page.waitToClick(selectors.ticketDescriptor.shipButton);
let url = await page.expectURL('#!/ticket/17/summary'); await page.waitForState('ticket.card.summary');
expect(url).toBe(true);
}); });
it('should delete the stowaway', async() => { it('should delete the stowaway', async() => {
@ -149,9 +119,7 @@ describe('Ticket descriptor path', () => {
await page.loginAndModule('adminBoss', 'ticket'); await page.loginAndModule('adminBoss', 'ticket');
await page.accessToSearchResult(invoiceableTicketId); await page.accessToSearchResult(invoiceableTicketId);
let url = await page.expectURL(`ticket/${invoiceableTicketId}/summary`); await page.waitForState('ticket.card.summary');
expect(url).toBe(true);
}); });
it(`should make sure the ticket doesn't have an invoiceOutFk yet`, async() => { it(`should make sure the ticket doesn't have an invoiceOutFk yet`, async() => {

View File

@ -44,9 +44,6 @@ describe('Ticket services path', () => {
await page.loginAndModule('administrative', 'ticket'); await page.loginAndModule('administrative', 'ticket');
await page.accessToSearchResult(editableTicketId); await page.accessToSearchResult(editableTicketId);
await page.accessToSection('ticket.card.service'); await page.accessToSection('ticket.card.service');
let url = await page.expectURL('/service');
expect(url).toBe(true);
}); });
it('should click on the add button to prepare the form to create a new service', async() => { it('should click on the add button to prepare the form to create a new service', async() => {

View File

@ -17,15 +17,16 @@ describe('Ticket create path', () => {
it('should open the new ticket form', async() => { it('should open the new ticket form', async() => {
await page.waitToClick(selectors.ticketsIndex.newTicketButton); await page.waitToClick(selectors.ticketsIndex.newTicketButton);
let url = await page.expectURL('#!/ticket/create'); await page.waitForState('ticket.create');
expect(url).toBe(true);
}); });
it('should succeed to create a ticket', async() => { it('should succeed to create a ticket', async() => {
const nextMonth = new Date();
nextMonth.setMonth(nextMonth.getMonth() + 1);
await page.autocompleteSearch(selectors.createTicketView.client, 'Tony Stark'); await page.autocompleteSearch(selectors.createTicketView.client, 'Tony Stark');
await page.autocompleteSearch(selectors.createTicketView.address, 'Tony Stark'); await page.autocompleteSearch(selectors.createTicketView.address, 'Tony Stark');
await page.datePicker(selectors.createTicketView.deliveryDate, 1, null); await page.pickDate(selectors.createTicketView.deliveryDate, nextMonth);
await page.autocompleteSearch(selectors.createTicketView.warehouse, 'Warehouse One'); await page.autocompleteSearch(selectors.createTicketView.warehouse, 'Warehouse One');
await page.autocompleteSearch(selectors.createTicketView.agency, 'Silla247'); await page.autocompleteSearch(selectors.createTicketView.agency, 'Silla247');
await page.waitToClick(selectors.createTicketView.createButton); await page.waitToClick(selectors.createTicketView.createButton);
@ -35,8 +36,6 @@ describe('Ticket create path', () => {
}); });
it('should check the url is now the summary of the ticket', async() => { it('should check the url is now the summary of the ticket', async() => {
let url = await page.expectURL('/summary'); await page.waitForState('ticket.card.summary');
expect(url).toBe(true);
}); });
}); });

View File

@ -19,9 +19,7 @@ describe('Ticket create from client path', () => {
it('should click the create simple ticket on the descriptor menu', async() => { it('should click the create simple ticket on the descriptor menu', async() => {
await page.waitToClick(selectors.clientDescriptor.moreMenu); await page.waitToClick(selectors.clientDescriptor.moreMenu);
await page.waitToClick(selectors.clientDescriptor.simpleTicketButton); await page.waitToClick(selectors.clientDescriptor.simpleTicketButton);
let url = await page.expectURL('clientFk=102'); await page.waitForState('ticket.create');
expect(url).toBe(true);
}); });
it('should check if the client details are the expected ones', async() => { it('should check if the client details are the expected ones', async() => {
@ -31,7 +29,6 @@ describe('Ticket create from client path', () => {
const address = await page const address = await page
.waitToGetProperty(selectors.createTicketView.address, 'value'); .waitToGetProperty(selectors.createTicketView.address, 'value');
expect(client).toContain('Petter Parker'); expect(client).toContain('Petter Parker');
expect(address).toContain('20 Ingram Street'); expect(address).toContain('20 Ingram Street');
}); });

View File

@ -18,9 +18,7 @@ describe('Ticket Summary path', () => {
it('should navigate to the target ticket summary section', async() => { it('should navigate to the target ticket summary section', async() => {
await page.loginAndModule('employee', 'ticket'); await page.loginAndModule('employee', 'ticket');
await page.accessToSearchResult(ticketId); await page.accessToSearchResult(ticketId);
let url = await page.expectURL('/summary'); await page.waitForState('ticket.card.summary');
expect(url).toBe(true);
}); });
it(`should display details from the ticket and it's client on the top of the header`, async() => { it(`should display details from the ticket and it's client on the top of the header`, async() => {
@ -75,9 +73,7 @@ describe('Ticket Summary path', () => {
it('should log in as production then navigate to the summary of the same ticket', async() => { it('should log in as production then navigate to the summary of the same ticket', async() => {
await page.loginAndModule('production', 'ticket'); await page.loginAndModule('production', 'ticket');
await page.accessToSearchResult(ticketId); await page.accessToSearchResult(ticketId);
let url = await page.expectURL('/summary'); await page.waitForState('ticket.card.summary');
expect(url).toBe(true);
}); });
it('should click on the SET OK button', async() => { it('should click on the SET OK button', async() => {

View File

@ -19,9 +19,7 @@ describe('Ticket log path', () => {
await page.loginAndModule('employee', 'ticket'); await page.loginAndModule('employee', 'ticket');
await page.accessToSearchResult(ticketId); await page.accessToSearchResult(ticketId);
await page.accessToSection('ticket.card.observation'); await page.accessToSection('ticket.card.observation');
let url = await page.expectURL('/observation'); await page.waitForState('ticket.card.observation');
expect(url).toBe(true);
}); });
it('should create a new note for the test', async() => { it('should create a new note for the test', async() => {
@ -36,9 +34,7 @@ describe('Ticket log path', () => {
it('should navigate to the log section', async() => { it('should navigate to the log section', async() => {
await page.accessToSection('ticket.card.log'); await page.accessToSection('ticket.card.log');
let url = await page.expectURL('/log'); await page.waitForState('ticket.card.log');
expect(url).toBe(true);
}); });
it('should set the viewport width to 1920 to see the table full width', async() => { it('should set the viewport width to 1920 to see the table full width', async() => {

View File

@ -27,13 +27,11 @@ describe('Claim edit basic data path', () => {
await page.waitToClick(selectors.claimBasicData.saveButton); await page.waitToClick(selectors.claimBasicData.saveButton);
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();
expect(result).toEqual(jasmine.arrayContaining(['Data saved!'])); expect(result).toEqual('Data saved!');
}); });
it(`should have been redirected to the next section of claims as the role is salesAssistant`, async() => { it(`should have been redirected to the next section of claims as the role is salesAssistant`, async() => {
let url = await page.expectURL('/detail'); await page.waitForState('claim.card.detail');
expect(url).toBe(true);
}); });
it('should confirm the claim state was edited', async() => { it('should confirm the claim state was edited', async() => {
@ -58,6 +56,6 @@ describe('Claim edit basic data path', () => {
await page.waitToClick(selectors.claimBasicData.saveButton); await page.waitToClick(selectors.claimBasicData.saveButton);
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();
expect(result).toEqual(jasmine.arrayContaining(['Data saved!'])); expect(result).toEqual('Data saved!');
}); });
}); });

View File

@ -32,9 +32,7 @@ describe('Claim development', () => {
}); });
it(`should redirect to the next section of claims as the role is salesAssistant`, async() => { it(`should redirect to the next section of claims as the role is salesAssistant`, async() => {
let url = await page.expectURL('/action'); await page.waitForState('claim.card.action');
expect(url).toBe(true);
}); });
it('should edit a development', async() => { it('should edit a development', async() => {

View File

@ -56,7 +56,7 @@ xdescribe('Claim detail', () => {
await page.loginAndModule('salesAssistant', 'claim'); await page.loginAndModule('salesAssistant', 'claim');
await page.accessToSearchResult('1'); await page.accessToSearchResult('1');
await page.accessToSection('claim.card.detail'); await page.accessToSection('claim.card.detail');
let url = await page.expectURL('/detail'); let url = await page.expectURL('/detail'); // replace with waitForState
expect(url).toBe(true); expect(url).toBe(true);
}); });
@ -99,7 +99,7 @@ xdescribe('Claim detail', () => {
}); });
it(`should have been redirected to the next section in claims`, async() => { it(`should have been redirected to the next section in claims`, async() => {
let url = await page.expectURL('development'); let url = await page.expectURL('development'); // replace with waitForState
expect(url).toBe(true); expect(url).toBe(true);
}); });

View File

@ -67,7 +67,7 @@ describe('Claim action path', () => {
await page.waitToClick(selectors.claimAction.isPaidWithManaCheckbox); await page.waitToClick(selectors.claimAction.isPaidWithManaCheckbox);
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();
expect(result).toEqual(jasmine.arrayContaining(['Data saved!'])); expect(result).toEqual('Data saved!');
}); });
it('should confirm the "is paid with mana" checkbox is checked', async() => { it('should confirm the "is paid with mana" checkbox is checked', async() => {

View File

@ -18,9 +18,7 @@ describe('claim Summary path', () => {
it('should navigate to the target claim summary section', async() => { it('should navigate to the target claim summary section', async() => {
await page.loginAndModule('employee', 'claim'); await page.loginAndModule('employee', 'claim');
await page.accessToSearchResult(claimId); await page.accessToSearchResult(claimId);
let url = await page.expectURL('/summary'); await page.waitForState('claim.card.summary');
expect(url).toBe(true);
}); });
it(`should display details from the claim and it's client on the top of the header`, async() => { it(`should display details from the claim and it's client on the top of the header`, async() => {

View File

@ -18,9 +18,7 @@ describe('claim Descriptor path', () => {
it('should now navigate to the target claim summary section', async() => { it('should now navigate to the target claim summary section', async() => {
await page.loginAndModule('employee', 'claim'); await page.loginAndModule('employee', 'claim');
await page.accessToSearchResult(claimId); await page.accessToSearchResult(claimId);
let url = await page.expectURL('/summary'); await page.waitForState('claim.card.summary');
expect(url).toBe(true);
}); });
it(`should not be able to see the delete claim button of the descriptor more menu`, async() => { it(`should not be able to see the delete claim button of the descriptor more menu`, async() => {
@ -31,9 +29,7 @@ describe('claim Descriptor path', () => {
it(`should log in as salesAssistant and navigate to the target claim`, async() => { it(`should log in as salesAssistant and navigate to the target claim`, async() => {
await page.loginAndModule('salesAssistant', 'claim'); await page.loginAndModule('salesAssistant', 'claim');
await page.accessToSearchResult(claimId); await page.accessToSearchResult(claimId);
let url = await page.expectURL('/summary'); await page.waitForState('claim.card.summary');
expect(url).toBe(true);
}); });
it(`should be able to see the delete claim button of the descriptor more menu`, async() => { it(`should be able to see the delete claim button of the descriptor more menu`, async() => {
@ -50,9 +46,7 @@ describe('claim Descriptor path', () => {
}); });
it(`should have been relocated to the claim index`, async() => { it(`should have been relocated to the claim index`, async() => {
let url = await page.expectURL('/claim/index'); await page.waitForState('claim.index');
expect(url).toBe(true);
}); });
it(`should search for the deleted claim to find no results`, async() => { it(`should search for the deleted claim to find no results`, async() => {

View File

@ -16,9 +16,7 @@ describe('Order summary path', () => {
}); });
it('should reach the order summary section', async() => { it('should reach the order summary section', async() => {
const url = await page.expectURL('#!/order/16/summary'); await page.waitForState('order.card.summary');
expect(url).toBe(true);
}); });
it('should check the summary contains the order id', async() => { it('should check the summary contains the order id', async() => {

View File

@ -4,7 +4,6 @@ import getBrowser from '../../helpers/puppeteer';
describe('Order edit basic data path', () => { describe('Order edit basic data path', () => {
let browser; let browser;
let page; let page;
const today = new Date().getDate();
beforeAll(async() => { beforeAll(async() => {
browser = await getBrowser(); browser = await getBrowser();
@ -40,9 +39,7 @@ describe('Order edit basic data path', () => {
await page.accessToSearchResult(orderId); await page.accessToSearchResult(orderId);
await page.accessToSection('order.card.basicData'); await page.accessToSection('order.card.basicData');
await page.waitForSelector(selectors.orderBasicData.observation, {visible: true}); await page.waitForSelector(selectors.orderBasicData.observation, {visible: true});
let url = await page.expectURL(`#!/order/${orderId}/basic-data`); await page.waitForState('order.card.basicData');
expect(url).toBe(true);
}); });
it('should not be able to change anything', async() => { it('should not be able to change anything', async() => {
@ -60,26 +57,20 @@ describe('Order edit basic data path', () => {
await page.waitToClick(selectors.orderBasicData.acceptButton); await page.waitToClick(selectors.orderBasicData.acceptButton);
await page.waitForContentLoaded(); await page.waitForContentLoaded();
await page.waitToClick(selectors.ordersIndex.createOrderButton); await page.waitToClick(selectors.ordersIndex.createOrderButton);
let url = await page.expectURL('#!/order/create'); await page.waitForState('order.create');
expect(url).toBe(true);
}); });
it('should now create a new one', async() => { it('should now create a new one', async() => {
await page.autocompleteSearch(selectors.createOrderView.client, 'Jessica Jones'); await page.autocompleteSearch(selectors.createOrderView.client, 'Jessica Jones');
await page.datePicker(selectors.createOrderView.landedDatePicker, 0, today); await page.pickDate(selectors.createOrderView.landedDatePicker);
await page.autocompleteSearch(selectors.createOrderView.agency, 'Other agency'); await page.autocompleteSearch(selectors.createOrderView.agency, 'Other agency');
await page.waitToClick(selectors.createOrderView.createButton); await page.waitToClick(selectors.createOrderView.createButton);
let url = await page.expectURL('/catalog'); await page.waitForState('order.card.catalog');
expect(url).toBe(true);
}); });
it('should navigate to the basic data section of the new order', async() => { it('should navigate to the basic data section of the new order', async() => {
await page.accessToSection('order.card.basicData'); await page.accessToSection('order.card.basicData');
let url = await page.expectURL('/basic-data'); await page.waitForState('order.card.basicData');
expect(url).toBe(true);
}); });
it('should be able to modify all the properties', async() => { it('should be able to modify all the properties', async() => {

View File

@ -41,10 +41,7 @@ describe('Order lines', () => {
it('should confirm the whole order and redirect to ticket index filtered by clientFk', async() => { it('should confirm the whole order and redirect to ticket index filtered by clientFk', async() => {
await page.waitToClick(selectors.orderLine.confirmOrder); await page.waitToClick(selectors.orderLine.confirmOrder);
let hashPartOne = await page.expectURL('ticket/index'); await page.expectURL('ticket/index');
let hashPartTwo = await page.expectURL('clientFk'); await page.expectURL('clientFk');
expect(hashPartOne).toBe(true);
expect(hashPartTwo).toBe(true);
}); });
}); });

View File

@ -17,21 +17,15 @@ describe('Order catalog', () => {
it('should open the create new order form', async() => { it('should open the create new order form', async() => {
await page.waitToClick(selectors.ordersIndex.createOrderButton); await page.waitToClick(selectors.ordersIndex.createOrderButton);
let url = await page.expectURL('order/create'); await page.waitForState('order.create');
expect(url).toBe(true);
}); });
it('should create a new order', async() => { it('should create a new order', async() => {
let today = new Date().getDate();
await page.autocompleteSearch(selectors.createOrderView.client, 'Tony Stark'); await page.autocompleteSearch(selectors.createOrderView.client, 'Tony Stark');
await page.datePicker(selectors.createOrderView.landedDatePicker, 0, today); await page.pickDate(selectors.createOrderView.landedDatePicker);
await page.autocompleteSearch(selectors.createOrderView.agency, 'Other agency'); await page.autocompleteSearch(selectors.createOrderView.agency, 'Other agency');
await page.waitToClick(selectors.createOrderView.createButton); await page.waitToClick(selectors.createOrderView.createButton);
let url = await page.expectURL('/catalog'); await page.waitForState('order.card.catalog');
expect(url).toBe(true);
}); });
it('should add the realm and type filters and obtain results', async() => { it('should add the realm and type filters and obtain results', async() => {

View File

@ -17,9 +17,7 @@ describe('Route summary path', () => {
}); });
it('should reach the first route summary section', async() => { it('should reach the first route summary section', async() => {
let url = await page.expectURL('#!/route/1/summary'); await page.waitForState('route.card.summary');
expect(url).toBe(true);
}); });
it(`should display details from the route on the header`, async() => { it(`should display details from the route on the header`, async() => {

View File

@ -18,9 +18,12 @@ describe('Route basic Data path', () => {
}); });
it('should edit the route basic data', async() => { it('should edit the route basic data', async() => {
const nextMonth = new Date();
nextMonth.setMonth(nextMonth.getMonth() + 1);
await page.autocompleteSearch(selectors.routeBasicData.worker, 'adminBossNick'); await page.autocompleteSearch(selectors.routeBasicData.worker, 'adminBossNick');
await page.autocompleteSearch(selectors.routeBasicData.vehicle, '1111-IMK'); await page.autocompleteSearch(selectors.routeBasicData.vehicle, '1111-IMK');
await page.datePicker(selectors.routeBasicData.createdDate, 1, null); await page.pickDate(selectors.routeBasicData.createdDate, nextMonth);
await page.clearInput(selectors.routeBasicData.kmStart); await page.clearInput(selectors.routeBasicData.kmStart);
await page.write(selectors.routeBasicData.kmStart, '1'); await page.write(selectors.routeBasicData.kmStart, '1');
await page.clearInput(selectors.routeBasicData.kmEnd); await page.clearInput(selectors.routeBasicData.kmEnd);
@ -37,7 +40,6 @@ describe('Route basic Data path', () => {
await page.reloadSection('route.card.basicData'); await page.reloadSection('route.card.basicData');
const worker = await page.waitToGetProperty(selectors.routeBasicData.worker, 'value'); const worker = await page.waitToGetProperty(selectors.routeBasicData.worker, 'value');
expect(worker).toEqual('adminBoss - adminBossNick'); expect(worker).toEqual('adminBoss - adminBossNick');
}); });

View File

@ -19,9 +19,7 @@ describe('Route create path', () => {
it('should click on the add new route button and open the creation form', async() => { it('should click on the add new route button and open the creation form', async() => {
await page.waitForContentLoaded(); await page.waitForContentLoaded();
await page.waitToClick(selectors.routeIndex.addNewRouteButton); await page.waitToClick(selectors.routeIndex.addNewRouteButton);
let url = await page.expectURL('#!/route/create'); await page.waitForState('route.create');
expect(url).toBe(true);
}); });
it(`should attempt to create a new route but fail since employee has no access rights`, async() => { it(`should attempt to create a new route but fail since employee has no access rights`, async() => {
@ -41,14 +39,12 @@ describe('Route create path', () => {
it('should again click on the add new route button and open the creation form', async() => { it('should again click on the add new route button and open the creation form', async() => {
await page.waitToClick(selectors.routeIndex.addNewRouteButton); await page.waitToClick(selectors.routeIndex.addNewRouteButton);
let url = await page.expectURL('#!/route/create'); await page.waitForState('route.create');
expect(url).toBe(true);
}); });
it(`should create a new route`, async() => { it(`should create a new route`, async() => {
await page.autocompleteSearch(selectors.createRouteView.worker, 'teamManagerNick'); await page.autocompleteSearch(selectors.createRouteView.worker, 'teamManagerNick');
await page.datePicker(selectors.createRouteView.createdDatePicker, 0, null); await page.pickDate(selectors.createRouteView.createdDatePicker);
await page.autocompleteSearch(selectors.createRouteView.vehicleAuto, '4444-IMK'); await page.autocompleteSearch(selectors.createRouteView.vehicleAuto, '4444-IMK');
await page.autocompleteSearch(selectors.createRouteView.agency, 'Teleportation device'); await page.autocompleteSearch(selectors.createRouteView.agency, 'Teleportation device');
await page.write(selectors.createRouteView.description, 'faster faster!!'); await page.write(selectors.createRouteView.description, 'faster faster!!');
@ -59,9 +55,7 @@ describe('Route create path', () => {
}); });
it(`should confirm the redirection to the created route summary`, async() => { it(`should confirm the redirection to the created route summary`, async() => {
let url = await page.expectURL('/summary'); await page.waitForState('route.card.summary');
expect(url).toBe(true);
}); });
}); });
}); });

View File

@ -17,9 +17,7 @@ describe('InvoiceOut summary path', () => {
}); });
it('should reach the summary section', async() => { it('should reach the summary section', async() => {
const result = await page.expectURL('/summary'); await page.waitForState('invoiceOut.card.summary');
expect(result).toBe(true);
}); });
it('should contain the company from which the invoice is emited', async() => { it('should contain the company from which the invoice is emited', async() => {

View File

@ -20,10 +20,7 @@ describe('InvoiceOut descriptor path', () => {
await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton); await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton);
await page.write(selectors.ticketsIndex.advancedSearchInvoiceOut, 'T2222222'); await page.write(selectors.ticketsIndex.advancedSearchInvoiceOut, 'T2222222');
await page.waitToClick(selectors.ticketsIndex.advancedSearchButton); await page.waitToClick(selectors.ticketsIndex.advancedSearchButton);
await page.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1); await page.waitForState('ticket.card.summary');
const result = await page.countElement(selectors.ticketsIndex.searchResult);
expect(result).toEqual(1);
}); });
it('should navigate to the invoiceOut index', async() => { it('should navigate to the invoiceOut index', async() => {
@ -31,25 +28,12 @@ describe('InvoiceOut descriptor path', () => {
await page.wait(selectors.globalItems.applicationsMenuVisible); await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.invoiceOutButton); await page.waitToClick(selectors.globalItems.invoiceOutButton);
await page.wait(selectors.invoiceOutIndex.topbarSearch); await page.wait(selectors.invoiceOutIndex.topbarSearch);
let url = await page.expectURL('#!/invoice-out/index'); await page.waitForState('invoiceOut.index');
expect(url).toBe(true);
});
it('should search for the target invoiceOut', async() => {
await page.write(selectors.invoiceOutIndex.topbarSearch, 'T2222222');
await page.waitToClick(selectors.invoiceOutIndex.searchButton);
await page.waitForNumberOfElements(selectors.invoiceOutIndex.searchResult, 1);
const result = await page.countElement(selectors.invoiceOutIndex.searchResult);
expect(result).toEqual(1);
}); });
it(`should click on the search result to access to the invoiceOut summary`, async() => { it(`should click on the search result to access to the invoiceOut summary`, async() => {
await page.accessToSearchResult('T2222222'); await page.accessToSearchResult('T2222222');
let url = await page.expectURL('/summary'); await page.waitForState('invoiceOut.card.summary');
expect(url).toBe(true);
}); });
it('should delete the invoiceOut using the descriptor more menu', async() => { it('should delete the invoiceOut using the descriptor more menu', async() => {
@ -62,9 +46,7 @@ describe('InvoiceOut descriptor path', () => {
}); });
it('should have been relocated to the invoiceOut index', async() => { it('should have been relocated to the invoiceOut index', async() => {
let url = await page.expectURL('#!/invoice-out/index'); await page.waitForState('invoiceOut.index');
expect(url).toBe(true);
}); });
it(`should search for the deleted invouceOut to find no results`, async() => { it(`should search for the deleted invouceOut to find no results`, async() => {
@ -80,13 +62,10 @@ describe('InvoiceOut descriptor path', () => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton); await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible); await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton); await page.waitToClick(selectors.globalItems.ticketsButton);
let url = await page.expectURL('#!/ticket/index'); await page.waitForState('ticket.index');
expect(url).toBe(true);
}); });
it('should search for tickets with an specific invoiceOut to find no results', async() => { it('should search for tickets with an specific invoiceOut to find no results', async() => {
await page.waitFor(2000);
await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton); await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton);
await page.write(selectors.ticketsIndex.advancedSearchInvoiceOut, 'T2222222'); await page.write(selectors.ticketsIndex.advancedSearchInvoiceOut, 'T2222222');
await page.waitToClick(selectors.ticketsIndex.advancedSearchButton); await page.waitToClick(selectors.ticketsIndex.advancedSearchButton);
@ -101,16 +80,12 @@ describe('InvoiceOut descriptor path', () => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton); await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible); await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.invoiceOutButton); await page.waitToClick(selectors.globalItems.invoiceOutButton);
let url = await page.expectURL('#!/invoice-out/index'); await page.waitForState('invoiceOut.index');
expect(url).toBe(true);
}); });
it(`should search and access to the invoiceOut summary`, async() => { it(`should search and access to the invoiceOut summary`, async() => {
await page.accessToSearchResult('T1111111'); await page.accessToSearchResult('T1111111');
let url = await page.expectURL('/summary'); await page.waitForState('invoiceOut.card.summary');
expect(url).toBe(true);
}); });
it(`should check the invoiceOut is booked in the summary data`, async() => { it(`should check the invoiceOut is booked in the summary data`, async() => {

View File

@ -18,16 +18,12 @@ describe('Travel thermograph path', () => {
}); });
it('should reach the thermograph section', async() => { it('should reach the thermograph section', async() => {
const result = await page.expectURL('/thermograph/index'); await page.waitForState('travel.card.thermograph.index');
expect(result).toBe(true);
}); });
it('should click the add thermograph floating button', async() => { it('should click the add thermograph floating button', async() => {
await page.waitToClick(selectors.travelThermograph.add); await page.waitToClick(selectors.travelThermograph.add);
const result = await page.expectURL('/thermograph/create'); await page.waitForState('travel.card.thermograph.create');
expect(result).toBe(true);
}); });
it('should select the thermograph and then the file to upload', async() => { it('should select the thermograph and then the file to upload', async() => {

View File

@ -18,13 +18,14 @@ describe('Travel basic data path', () => {
}); });
it('should reach the thermograph section', async() => { it('should reach the thermograph section', async() => {
const result = await page.expectURL('/basic-data'); await page.waitForState('travel.card.basicData');
expect(result).toBe(true);
}); });
it('should set a wrong delivery date then receive an error on submit', async() => { it('should set a wrong delivery date then receive an error on submit', async() => {
await page.datePicker(selectors.travelBasicDada.deliveryDate, -1, null); const lastMonth = new Date();
lastMonth.setMonth(lastMonth.getMonth() - 1);
await page.pickDate(selectors.travelBasicDada.deliveryDate, lastMonth);
await page.waitToClick(selectors.travelBasicDada.save); await page.waitToClick(selectors.travelBasicDada.save);
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();
@ -89,9 +90,7 @@ describe('Travel basic data path', () => {
it('should navigate to the travel logs', async() => { it('should navigate to the travel logs', async() => {
await page.accessToSection('travel.card.log'); await page.accessToSection('travel.card.log');
const result = await page.expectURL('/log'); await page.waitForState('travel.card.log');
expect(result).toBe(true);
}); });
it('should check the 1st log contains details from the changes made', async() => { it('should check the 1st log contains details from the changes made', async() => {

View File

@ -18,9 +18,7 @@ describe('Zone basic data path', () => {
}); });
it('should reach the basic data section', async() => { it('should reach the basic data section', async() => {
let url = await page.expectURL('#!/zone/10/basic-data'); await page.waitForState('zone.card.basicData');
expect(url).toBe(true);
}); });
it('should edit de form and then save', async() => { it('should edit de form and then save', async() => {
@ -31,7 +29,7 @@ describe('Zone basic data path', () => {
await page.clearInput(selectors.zoneBasicData.travelingDays); await page.clearInput(selectors.zoneBasicData.travelingDays);
await page.write(selectors.zoneBasicData.travelingDays, '1'); await page.write(selectors.zoneBasicData.travelingDays, '1');
await page.clearInput(selectors.zoneBasicData.closing); await page.clearInput(selectors.zoneBasicData.closing);
await page.type(selectors.zoneBasicData.closing, '2100'); await page.pickTime(selectors.zoneBasicData.closing, '21:00');
await page.clearInput(selectors.zoneBasicData.price); await page.clearInput(selectors.zoneBasicData.price);
await page.write(selectors.zoneBasicData.price, '999'); await page.write(selectors.zoneBasicData.price, '999');
await page.clearInput(selectors.zoneBasicData.bonus); await page.clearInput(selectors.zoneBasicData.bonus);
@ -40,14 +38,13 @@ describe('Zone basic data path', () => {
await page.write(selectors.zoneBasicData.inflation, '200'); await page.write(selectors.zoneBasicData.inflation, '200');
await page.waitToClick(selectors.zoneBasicData.volumetric); await page.waitToClick(selectors.zoneBasicData.volumetric);
await page.waitToClick(selectors.zoneBasicData.saveButton); await page.waitToClick(selectors.zoneBasicData.saveButton);
await page.waitForContentLoaded(); const result = await page.waitForLastSnackbar();
expect(result).toEqual('Data saved!');
}); });
it('should now reload the section', async() => { it('should now reload the section', async() => {
await page.reloadSection('zone.card.basicData'); await page.reloadSection('zone.card.basicData');
let url = await page.expectURL('#!/zone/10/basic-data');
expect(url).toBe(true);
}); });
it('should confirm the name was updated', async() => { it('should confirm the name was updated', async() => {

View File

@ -17,9 +17,7 @@ describe('Entry summary path', () => {
}); });
it('should reach the second entry summary section', async() => { it('should reach the second entry summary section', async() => {
let url = await page.expectURL('#!/entry/2/summary'); await page.waitForState('entry.card.summary');
expect(url).toBe(true);
}); });
it(`should display details from the entry on the header`, async() => { it(`should display details from the entry on the header`, async() => {

View File

@ -17,9 +17,7 @@ describe('Entry descriptor path', () => {
}); });
it('should reach the second entry summary section', async() => { it('should reach the second entry summary section', async() => {
let url = await page.expectURL('#!/entry/2/summary'); await page.waitForState('entry.card.summary');
expect(url).toBe(true);
}); });
it('should show some entry information', async() => { it('should show some entry information', async() => {
@ -30,32 +28,22 @@ describe('Entry descriptor path', () => {
it('should click the travels button to be redirected to the travels index filtered by the current agency', async() => { it('should click the travels button to be redirected to the travels index filtered by the current agency', async() => {
await page.waitToClick(selectors.entryDescriptor.travelsQuicklink); await page.waitToClick(selectors.entryDescriptor.travelsQuicklink);
const url = await page.expectURL('/travel/index'); await page.expectURL('/travel/index');
const filter = await page.expectURL('agencyFk'); await page.expectURL('agencyFk');
expect(url).toBe(true);
expect(filter).toBe(true);
}); });
it('should go back to the entry summary', async() => { it('should go back to the entry summary', async() => {
await page.waitToClick(selectors.globalItems.homeButton); await page.waitToClick(selectors.globalItems.homeButton);
await page.selectModule('entry'); await page.selectModule('entry');
await page.accessToSearchResult('2'); await page.accessToSearchResult('2');
let url = await page.expectURL('#!/entry/2/summary'); await page.waitForState('entry.card.summary');
expect(url).toBe(true);
}); });
it('should click the entries button to be redirected to the entries index filtered by the current supplier', async() => { it('should click the entries button to be redirected to the entries index filtered by the current supplier', async() => {
await page.waitToClick(selectors.entryDescriptor.entriesQuicklink); await page.waitToClick(selectors.entryDescriptor.entriesQuicklink);
const url = await page.expectURL('/entry/index'); await page.expectURL('/entry/index');
const supplierFilter = await page.expectURL('supplierFk'); await page.expectURL('supplierFk');
const toFilter = await page.expectURL('to'); await page.expectURL('to');
const fromFilter = await page.expectURL('from'); await page.expectURL('from');
expect(url).toBe(true);
expect(supplierFilter).toBe(true);
expect(toFilter).toBe(true);
expect(fromFilter).toBe(true);
}); });
}); });

View File

@ -29,13 +29,16 @@ export default class DropDown extends Popover {
} }
set search(value) { set search(value) {
let oldValue = this._search; function nullify(value) {
return value == '' || value == undefined ? null : value;
}
let oldValue = nullify(this._search);
this._search = value; this._search = value;
if (!this.shown) return; if (!this.shown) return;
value = value == '' || value == null ? null : value; value = nullify(value);
oldValue = oldValue == '' || oldValue == null ? null : oldValue;
if (value === oldValue && this.modelData != null) return; if (value === oldValue && this.modelData != null) return;
if (value != null) if (value != null)
@ -45,7 +48,8 @@ export default class DropDown extends Popover {
if (this.model) { if (this.model) {
this.model.clear(); this.model.clear();
if (!this.data) {
if (this.model instanceof CrudModel) {
this.searchTimeout = this.$timeout(() => { this.searchTimeout = this.$timeout(() => {
this.refreshModel(); this.refreshModel();
this.searchTimeout = null; this.searchTimeout = null;
@ -353,6 +357,7 @@ export default class DropDown extends Popover {
set model(value) { set model(value) {
this.linkEvents({_model: value}, {dataChange: this.onDataChange}); this.linkEvents({_model: value}, {dataChange: this.onDataChange});
this.onDataChange(); this.onDataChange();
this.search = this.search;
} }
get url() { get url() {
@ -362,10 +367,9 @@ export default class DropDown extends Popover {
set url(value) { set url(value) {
this._url = value; this._url = value;
if (value) { if (value) {
this.model = new CrudModel(this.$q, this.$http); let model = new CrudModel(this.$q, this.$http);
this.model.autoLoad = false; model.url = value;
this.model.url = value; this.initModel(model);
this.model.$onInit();
} }
} }
@ -376,13 +380,18 @@ export default class DropDown extends Popover {
set data(value) { set data(value) {
this._data = value; this._data = value;
if (value) { if (value) {
this.model = new ArrayModel(this.$q, this.$filter); let model = new ArrayModel(this.$q, this.$filter);
this.model.autoLoad = false; model.orgData = value;
this.model.orgData = value; this.initModel(model);
this.model.$onInit();
} }
} }
initModel(model) {
model.autoLoad = false;
model.$onInit();
this.model = model;
}
refreshModel() { refreshModel() {
let model = this.model; let model = this.model;

View File

@ -13,19 +13,31 @@ import './style.scss';
* *
* @property {Object} filter A key-value object with filter parameters * @property {Object} filter A key-value object with filter parameters
* @property {SearchPanel} panel The panel used for advanced searches * @property {SearchPanel} panel The panel used for advanced searches
* @property {Function} onSearch Function to call when search is submited
* @property {CrudModel} model The model used for searching
* @property {Function} exprBuilder If defined, is used to build each non-null param expresion
*/ */
export default class Controller extends Component { export default class Searchbar extends Component {
constructor($element, $) { constructor($element, $) {
super($element, $); super($element, $);
this.searchState = '.'; this.searchState = '.';
this.autoState = true;
let criteria = {};
this.deregisterCallback = this.$transitions.onSuccess( this.deregisterCallback = this.$transitions.onSuccess(
criteria, () => this.onStateChange()); {}, transition => this.onStateChange(transition));
} }
$postLink() { $postLink() {
this.onStateChange(); if (this.autoState) {
if (!this.baseState) {
let stateParts = this.$state.current.name.split('.');
this.baseState = stateParts[0];
}
this.searchState = `${this.baseState}.index`;
}
this.fetchStateFilter(this.autoLoad);
} }
$onDestroy() { $onDestroy() {
@ -56,7 +68,16 @@ export default class Controller extends Component {
if (value == null) this.params = []; if (value == null) this.params = [];
} }
onStateChange() { onStateChange(transition) {
let ignoreHandler =
!this.element.parentNode
|| transition == this.transition;
if (ignoreHandler) return;
this.fetchStateFilter();
}
fetchStateFilter(autoLoad) {
let filter = null; let filter = null;
if (this.$state.is(this.searchState)) { if (this.$state.is(this.searchState)) {
@ -68,10 +89,11 @@ export default class Controller extends Component {
} }
} }
focus(this.element.querySelector('vn-textfield input')); if (!filter && autoLoad)
filter = {};
} }
this.filter = filter; this.doSearch(filter, 'state');
} }
openPanel(event) { openPanel(event) {
@ -100,25 +122,16 @@ export default class Controller extends Component {
this.$.popover.hide(); this.$.popover.hide();
filter = compact(filter); filter = compact(filter);
filter = filter != null ? filter : {}; filter = filter != null ? filter : {};
this.doSearch(filter); this.doSearch(filter, 'panel');
} }
onSubmit() { onSubmit() {
this.doSearch(this.fromBar()); this.doSearch(this.fromBar(), 'bar');
} }
removeParam(index) { removeParam(index) {
this.params.splice(index, 1); this.params.splice(index, 1);
this.doSearch(this.fromBar()); this.doSearch(this.fromBar(), 'bar');
}
doSearch(filter) {
this.filter = filter;
let opts = this.$state.is(this.searchState)
? {location: 'replace'} : null;
this.$state.go(this.searchState,
{q: JSON.stringify(filter)}, opts);
} }
fromBar() { fromBar() {
@ -171,111 +184,137 @@ export default class Controller extends Component {
this.params.push({chip, key, value}); this.params.push({chip, key, value});
}); });
} }
doSearch(filter, source) {
if (filter === this.filter) return;
let promise = this.onSearch({$params: filter});
promise = promise || this.$q.resolve();
promise.then(data => this.onFilter(filter, source, data));
}
onFilter(filter, source, data) {
let state;
let params;
let opts;
if (filter) {
let isOneResult = this.autoState
&& source != 'state'
&& !angular.equals(filter, {})
&& data
&& data.length == 1;
if (isOneResult) {
let baseDepth = this.baseState.split('.').length;
let stateParts = this.$state.current.name
.split('.')
.slice(baseDepth);
let subState = stateParts[0];
switch (subState) {
case 'card':
subState += `.${stateParts[1]}`;
if (stateParts.length >= 3)
subState += '.index';
break;
default:
subState = 'card.summary';
}
if (this.stateParams)
params = this.stateParams({$row: data[0]});
state = `${this.baseState}.${subState}`;
filter = null;
} else {
state = this.searchState;
if (filter)
params = {q: JSON.stringify(filter)};
if (this.$state.is(state))
opts = {location: 'replace'};
}
}
this.filter = filter;
if (!filter && this.model)
this.model.clear();
if (source != 'state')
this.transition = this.$state.go(state, params, opts).transition;
if (source != 'bar')
focus(this.element.querySelector('vn-textfield input'));
}
// Default search handlers
stateParams(params) {
return {id: params.$row.id};
}
onSearch(args) {
if (!this.model) return;
let filter = args.$params;
if (filter === null) {
this.model.clear();
return;
}
let where = null;
let params = null;
if (this.exprBuilder) {
where = buildFilter(filter,
(param, value) => this.exprBuilder({param, value}));
} else {
params = Object.assign({}, filter);
if (this.fetchParams)
params = this.fetchParams({$params: params});
}
return this.model.applyFilter(where ? {where} : null, params)
.then(() => this.model.data);
}
} }
ngModule.vnComponent('vnSearchbar', { ngModule.vnComponent('vnSearchbar', {
controller: Controller, controller: Searchbar,
template: require('./searchbar.html'), template: require('./searchbar.html'),
bindings: { bindings: {
searchState: '@?',
filter: '<?', filter: '<?',
suggestedFilter: '<?', suggestedFilter: '<?',
panel: '@', panel: '@',
info: '@?' info: '@?',
onSearch: '&?',
baseState: '@?',
autoState: '<?',
stateParams: '&?',
model: '<?',
exprBuilder: '&?',
fetchParams: '&?'
} }
}); });
/**
* @property {CrudModel} model The model used for searching
* @property {Function} exprBuilder If defined, is used to build each non-null param expresion
* @property {Function} onSearch Function to call when search is submited
*/
class AutoSearch { class AutoSearch {
constructor($state, $transitions) { constructor(vnSlotService) {
this.$state = $state; this.vnSlotService = vnSlotService;
this.$transitions = $transitions;
let criteria = {to: this.$state.current.name};
this.deregisterCallback = this.$transitions.onSuccess(criteria,
() => this.onStateChange());
this.fetchFilter();
} }
$postLink() { $postLink() {
if (this.filter !== null) let searchbar = this.vnSlotService.getContent('topbar');
this.doSearch(); if (searchbar && searchbar.$ctrl instanceof Searchbar)
} this.model = searchbar.$ctrl.model;
$onDestroy() {
this.deregisterCallback();
}
fetchFilter() {
if (this.$state.params.q) {
try {
this.filter = JSON.parse(this.$state.params.q);
} catch (e) {
console.error(e);
}
} else
this.filter = null;
}
onStateChange() {
this.fetchFilter();
this.doSearch();
}
doSearch() {
let filter = this.filter;
if (filter == null && this.autoload)
filter = {};
if (this.onSearch)
this.onSearch({$params: filter});
if (this.model) {
if (filter !== null) {
let where = buildFilter(filter,
(param, value) => this.exprBuilder({param, value}));
let userParams = {};
let hasParams = false;
if (this.paramBuilder) {
for (let param in filter) {
let value = filter[param];
if (value == null) continue;
let expr = this.paramBuilder({param, value});
if (expr) {
Object.assign(userParams, expr);
hasParams = true;
}
}
}
this.model.applyFilter(
where ? {where} : null,
hasParams ? userParams : null
);
} else
this.model.clear();
}
}
exprBuilder(param, value) {
return {[param]: value};
} }
} }
AutoSearch.$inject = ['$state', '$transitions']; AutoSearch.$inject = ['vnSlotService'];
ngModule.vnComponent('vnAutoSearch', { ngModule.vnComponent('vnAutoSearch', {
controller: AutoSearch, controller: AutoSearch,
bindings: { bindings: {
model: '<?', model: '=?'
onSearch: '&?',
exprBuilder: '&?',
paramBuilder: '&?'
} }
}); });

View File

@ -8,9 +8,35 @@ describe('Component vnSearchbar', () => {
let $scope; let $scope;
let filter = {id: 1, search: 'needle'}; let filter = {id: 1, search: 'needle'};
beforeEach(ngModule('vnCore')); beforeEach(ngModule('vnCore', $stateProvider => {
$stateProvider
.state('foo', {
abstract: true
})
.state('foo.index', {
url: '/foo/index'
})
.state('foo.card', {
abstract: true
})
.state('foo.card.summary', {
url: '/foo/:id/summary'
})
.state('foo.card.bar', {
url: '/foo/:id/bar'
})
.state('foo.card.baz', {
abstract: true
})
.state('foo.card.baz.index', {
url: '/foo/:id/baz/index'
})
.state('foo.card.baz.edit', {
url: '/foo/:id/baz/:bazId/edit'
});
}));
beforeEach(angular.mock.inject(($componentController, $rootScope, _$state_) => { beforeEach(inject(($componentController, $rootScope, _$state_) => {
$scope = $rootScope.$new(); $scope = $rootScope.$new();
$state = _$state_; $state = _$state_;
$params = $state.params; $params = $state.params;
@ -19,25 +45,26 @@ describe('Component vnSearchbar', () => {
$element = angular.element(`<div></div>`); $element = angular.element(`<div></div>`);
controller = $componentController('vnSearchbar', {$element, $scope}); controller = $componentController('vnSearchbar', {$element, $scope});
controller.panel = 'vn-client-search-panel';
})); }));
describe('$postLink()', () => { describe('$postLink()', () => {
it(`should fetch the filter from the state if it's in the filter state`, () => { it(`should fetch the filter from the state if it's in the filter state`, () => {
jest.spyOn(controller, 'doSearch');
controller.autoState = false;
controller.$postLink(); controller.$postLink();
expect(controller.filter).toEqual(filter); expect(controller.doSearch).toHaveBeenCalledWith(filter, 'state');
expect(controller.searchString).toBe('needle');
expect(controller.params.length).toBe(1);
}); });
it(`should not fetch the filter from the state if not in the filter state`, () => { it(`should not fetch the filter from the state if not in the filter state`, () => {
jest.spyOn(controller, 'doSearch');
controller.autoState = false;
controller.searchState = 'other.state'; controller.searchState = 'other.state';
controller.$postLink(); controller.$postLink();
expect(controller.filter).toBeNull(); expect(controller.doSearch).toHaveBeenCalledWith(null, 'state');
expect(controller.searchString).toBeNull();
expect(controller.params.length).toBe(0);
}); });
}); });
@ -67,6 +94,14 @@ describe('Component vnSearchbar', () => {
expect(chips.negated).toBe('not negated'); expect(chips.negated).toBe('not negated');
expect(chips.myObjectProp).toBe('myObjectProp'); expect(chips.myObjectProp).toBe('myObjectProp');
}); });
it(`should clear the filter when null`, () => {
controller.filter = null;
expect(controller.filter).toBeNull();
expect(controller.searchString).toBeNull();
expect(controller.params.length).toBe(0);
});
}); });
describe('shownFilter() getter', () => { describe('shownFilter() getter', () => {
@ -98,6 +133,7 @@ describe('Component vnSearchbar', () => {
describe('onPanelSubmit()', () => { describe('onPanelSubmit()', () => {
it(`should compact and define the filter`, () => { it(`should compact and define the filter`, () => {
controller.$.popover = {hide: jasmine.createSpy('hide')}; controller.$.popover = {hide: jasmine.createSpy('hide')};
jest.spyOn(controller, 'doSearch');
const filter = { const filter = {
id: 1, id: 1,
@ -110,42 +146,110 @@ describe('Component vnSearchbar', () => {
}; };
controller.onPanelSubmit(filter); controller.onPanelSubmit(filter);
expect(controller.filter).toEqual({ expect(controller.doSearch).toHaveBeenCalledWith({
id: 1, id: 1,
myObject: {keepThis: true}, myObject: {keepThis: true},
myArray: [true] myArray: [true]
}); }, 'panel');
}); });
}); });
describe('onSubmit()', () => { describe('onSubmit()', () => {
it(`should define the filter`, () => { it(`should define the filter`, () => {
jest.spyOn(controller, 'doSearch');
controller.filter = filter; controller.filter = filter;
controller.searchString = 'mySearch'; controller.searchString = 'mySearch';
controller.onSubmit(); controller.onSubmit();
expect(controller.filter).toEqual({id: 1, search: 'mySearch'}); expect(controller.doSearch).toHaveBeenCalledWith({
id: 1,
search: 'mySearch'
}, 'bar');
}); });
}); });
describe('removeParam()', () => { describe('removeParam()', () => {
it(`should remove the parameter from the filter`, () => { it(`should remove the parameter from the filter`, () => {
jest.spyOn(controller, 'doSearch');
controller.filter = filter; controller.filter = filter;
controller.removeParam(0); controller.removeParam(0);
expect(controller.filter).toEqual({search: 'needle'}); expect(controller.doSearch).toHaveBeenCalledWith({
search: 'needle'
}, 'bar');
}); });
}); });
describe('doSearch()', () => { describe('doSearch()', () => {
it(`should go to the search state and pass the filter as query param`, () => { it(`should do the filter`, () => {
jest.spyOn(controller, 'onSearch');
jest.spyOn(controller, 'onFilter');
controller.doSearch(filter, 'any');
$scope.$apply();
expect(controller.onSearch).toHaveBeenCalledWith({$params: filter});
expect(controller.onFilter).toHaveBeenCalledWith(filter, 'any', undefined);
});
});
describe('onFilter()', () => {
it(`should go to the summary state when one result`, () => {
jest.spyOn($state, 'go'); jest.spyOn($state, 'go');
let data = [{id: 1}];
controller.baseState = 'foo';
controller.onFilter(filter, 'any', data);
$scope.$apply();
expect($state.go).toHaveBeenCalledWith('foo.card.summary', {id: 1}, undefined);
expect(controller.filter).toEqual(null);
});
it(`should keep the same card state when one result and it's already inside any card state`, () => {
$state.go('foo.card.bar', {id: 1});
$scope.$apply();
jest.spyOn($state, 'go');
let data = [{id: 1}];
controller.baseState = 'foo';
controller.onFilter(filter, 'any', data);
$scope.$apply();
expect($state.go).toHaveBeenCalledWith('foo.card.bar', {id: 1}, undefined);
expect(controller.filter).toEqual(null);
});
it(`should keep the same card state but index when one result and it's already in card state but inside more than three-nested states`, () => {
$state.go('foo.card.baz.edit', {id: 1, bazId: 1});
$scope.$apply();
jest.spyOn($state, 'go');
let data = [{id: 1}];
controller.baseState = 'foo';
controller.onFilter(filter, 'any', data);
$scope.$apply();
expect($state.go).toHaveBeenCalledWith('foo.card.baz.index', {id: 1}, undefined);
expect(controller.filter).toEqual(null);
});
it(`should go to the search state when multiple results and pass the filter as query param`, () => {
jest.spyOn($state, 'go');
controller.autoState = false;
controller.searchState = 'search.state'; controller.searchState = 'search.state';
controller.doSearch(filter); controller.onFilter(filter, 'any');
$scope.$apply();
let queryParams = {q: JSON.stringify(filter)}; let queryParams = {q: JSON.stringify(filter)};
expect($state.go).toHaveBeenCalledWith('search.state', queryParams, null); expect($state.go).toHaveBeenCalledWith('search.state', queryParams, undefined);
expect(controller.filter).toEqual(filter); expect(controller.filter).toEqual(filter);
}); });
}); });

View File

@ -67,6 +67,12 @@ export class SlotService {
$content.remove(); $content.remove();
} }
getContent(slot) {
if (this.slots[slot])
return this.slots[slot].$element[0].firstElementChild;
return null;
}
refreshContent(slot) { refreshContent(slot) {
if (!this.slots[slot]) return; if (!this.slots[slot]) return;
let $content = this.stacks[slot][0]; let $content = this.stacks[slot][0];

View File

@ -6,9 +6,8 @@ import './style.scss';
* A simple component to show non-obstructive notifications to the user. * A simple component to show non-obstructive notifications to the user.
*/ */
export default class Controller extends Component { export default class Controller extends Component {
constructor($element, $translate) { constructor($element, $) {
super($element); super($element, $);
this.$translate = $translate;
this.snackbar = $element[0].firstChild; this.snackbar = $element[0].firstChild;
this.$snackbar = angular.element(this.snackbar); this.$snackbar = angular.element(this.snackbar);
} }
@ -19,38 +18,54 @@ export default class Controller extends Component {
* @return {Object} Created snackbar shape * @return {Object} Created snackbar shape
*/ */
createShape(data) { createShape(data) {
let shape = document.createElement('div'); let shape = Object.assign({
shape.className = 'shape'; nMessages: 1
}, data);
let element = document.createElement('div');
element.className = 'shape';
setTimeout(() => element.classList.add('shown'), 30);
shape.element = element;
if (shape.type)
element.classList.add(shape.type);
let button = document.createElement('button'); let button = document.createElement('button');
button.addEventListener('click', () => this.onButtonClick(shape));
element.appendChild(button);
let buttonText = data.actionText || this.$translate.instant('Hide'); let buttonText = shape.actionText || this.$t('Hide');
buttonText = document.createTextNode(buttonText); buttonText = document.createTextNode(buttonText);
button.appendChild(buttonText); button.appendChild(buttonText);
button.addEventListener('click', () => {
this.onButtonClick(shape);
});
shape.appendChild(button);
let shapeText = document.createElement('div'); let shapeText = document.createElement('div');
shapeText.setAttribute('class', 'text'); shapeText.setAttribute('class', 'text');
shape.appendChild(shapeText); element.appendChild(shapeText);
let text = document.createTextNode(data.message); let text = document.createTextNode(shape.message);
shapeText.appendChild(text); shapeText.appendChild(text);
if (data.shapeType) let chip = document.createElement('vn-chip');
shape.classList.add(data.shapeType); chip.className = 'warning small';
chip.style.visibility = 'hidden';
let parent = this.snackbar.querySelectorAll('.shape')[0]; let chipWrapper = document.createElement('div');
chip.append(chipWrapper);
let span = document.createElement('span');
chipWrapper.append(span);
let chipText = document.createTextNode(shape.nMessages);
span.append(chipText);
shapeText.appendChild(chip);
let parent = this.snackbar.querySelector('.shape');
if (parent) if (parent)
this.snackbar.insertBefore(shape, parent); this.snackbar.insertBefore(element, parent);
else else
this.snackbar.appendChild(shape); this.snackbar.appendChild(element);
return shape; return shape;
} }
@ -61,58 +76,28 @@ export default class Controller extends Component {
* @param {Object} data The message data * @param {Object} data The message data
*/ */
show(data) { show(data) {
this.actionHandler = data.actionHandler; let shape = this.lastShape;
let shape; const isEqual = shape
&& shape.type == data.type
&& shape.message == data.message;
const lastShape = this.lastShape; if (isEqual) {
const lastShapeData = lastShape && lastShape.data; shape.nMessages++;
const isEqual = lastShape && (lastShapeData.shapeType == data.shapeType && lastShapeData.message == data.message);
if (lastShape && isEqual) { const chip = shape.element.querySelector('.text vn-chip');
shape = lastShape.element; chip.style.visibility = 'visible';
const shapeText = shape.querySelector('.text'); const span = chip.querySelector('span');
let chip = shapeText.querySelector('vn-chip'); span.innerHTML = shape.nMessages;
} else
if (chip) {
const text = chip.querySelector('span');
const number = parseInt(text.innerHTML);
text.innerHTML = number + 1;
} else {
chip = document.createElement('vn-chip');
chip.setAttribute('class', 'warning small');
let parent = document.createElement('div');
let span = document.createElement('span');
let text = document.createTextNode(1);
span.append(text);
parent.append(span);
chip.append(parent);
shapeText.appendChild(chip);
}
lastShape.element.classList.add('shown');
if (this.hideTimeout)
clearTimeout(this.hideTimeout);
} else {
shape = this.createShape(data); shape = this.createShape(data);
setTimeout(() => clearTimeout(shape.hideTimeout);
shape.classList.add('shown'), 30); shape.hideTimeout = setTimeout(
} () => this.hide(shape), shape.timeout || 3000);
this.hideTimeout = setTimeout(() => { this.lastShape = shape;
this.hide(shape);
this.lastShape = null;
}, data.timeout || 3000);
this.lastShape = {
data: data,
element: shape
};
} }
/** /**
@ -121,8 +106,7 @@ export default class Controller extends Component {
* @param {Object} data The message data * @param {Object} data The message data
*/ */
showError(data) { showError(data) {
data.shapeType = 'error'; data.type = 'error';
this.show(data); this.show(data);
} }
@ -132,8 +116,7 @@ export default class Controller extends Component {
* @param {Object} data The message data * @param {Object} data The message data
*/ */
showSuccess(data) { showSuccess(data) {
data.shapeType = 'success'; data.type = 'success';
this.show(data); this.show(data);
} }
@ -142,8 +125,11 @@ export default class Controller extends Component {
* @param {Object} shape Snackbar element * @param {Object} shape Snackbar element
*/ */
hide(shape) { hide(shape) {
setTimeout(() => shape.classList.remove('shown'), 30); if (this.lastShape == shape)
setTimeout(() => shape.remove(), 250); this.lastShape = null;
shape.element.classList.remove('shown');
setTimeout(() => shape.element.remove(), 250);
} }
onSnackbarClick(event) { onSnackbarClick(event) {
@ -151,13 +137,12 @@ export default class Controller extends Component {
} }
onButtonClick(shape) { onButtonClick(shape) {
if (this.actionHandler) if (shape.actionHandler)
this.actionHandler(); shape.actionHandler();
else else
this.hide(shape); this.hide(shape);
} }
} }
Controller.$inject = ['$element', '$translate'];
ngModule.component('vnSnackbar', { ngModule.component('vnSnackbar', {
template: require('./snackbar.html'), template: require('./snackbar.html'),

View File

@ -2,12 +2,12 @@
import isMobile from './is-mobile'; import isMobile from './is-mobile';
export default function focus(element) { export default function focus(element) {
if (isMobile) return; if (isMobile || !element) return;
setTimeout(() => element.focus(), 10); setTimeout(() => element.focus(), 10);
} }
export function select(element) { export function select(element) {
if (isMobile) return; if (isMobile || !element) return;
setTimeout(() => { setTimeout(() => {
element.focus(); element.focus();
if (element.select) if (element.select)

View File

@ -7,6 +7,11 @@ export default class Section extends Component {
super($element, $); super($element, $);
this.element.classList.add('vn-section'); this.element.classList.add('vn-section');
} }
stopEvent(event) {
event.preventDefault();
event.stopImmediatePropagation();
}
} }
ngModule.vnComponent('vnSection', { ngModule.vnComponent('vnSection', {

View File

@ -63,9 +63,12 @@ export function config($translatePartialLoaderProvider, $httpProvider, $compileP
$httpProvider.interceptors.push('vnInterceptor'); $httpProvider.interceptors.push('vnInterceptor');
$compileProvider $compileProvider
.debugInfoEnabled(false)
.commentDirectivesEnabled(false) .commentDirectivesEnabled(false)
.cssClassDirectivesEnabled(false); .cssClassDirectivesEnabled(false);
let env = process.env.NODE_ENV;
if (env && env !== 'development')
$compileProvider.debugInfoEnabled(false);
} }
ngModule.config(config); ngModule.config(config);

View File

@ -17,8 +17,8 @@ core.run(vnInterceptor => {
vnInterceptor.setApiPath(null); vnInterceptor.setApiPath(null);
}); });
window.ngModule = function(moduleName) { window.ngModule = function(moduleName, ...args) {
return angular.mock.module(moduleName, function($provide, $translateProvider) { let fns = [moduleName, function($provide, $translateProvider) {
// Avoid unexpected request warnings caused by angular translate // Avoid unexpected request warnings caused by angular translate
// https://angular-translate.github.io/docs/#/guide/22_unit-testing-with-angular-translate // https://angular-translate.github.io/docs/#/guide/22_unit-testing-with-angular-translate
$provide.factory('customLocaleLoader', function($q) { $provide.factory('customLocaleLoader', function($q) {
@ -30,5 +30,10 @@ window.ngModule = function(moduleName) {
}); });
$translateProvider.useLoader('customLocaleLoader'); $translateProvider.useLoader('customLocaleLoader');
}); }];
if (args.length)
fns = fns.concat(args);
return angular.mock.module(...fns);
}; };

View File

@ -1,16 +1,12 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { export default class Controller extends Section {
constructor($stateParams, $scope, $http, $translate, vnApp, $httpParamSerializer) { constructor($element, $) {
this.$stateParams = $stateParams; super($element, $);
this.$ = $scope;
this.$http = $http;
this.$translate = $translate;
this.vnApp = vnApp;
this.$httpParamSerializer = $httpParamSerializer;
this.filter = { this.filter = {
where: {claimFk: $stateParams.id}, where: {claimFk: this.$params.id},
include: [ include: [
{relation: 'sale', {relation: 'sale',
scope: { scope: {
@ -34,9 +30,7 @@ class Controller {
} }
getClaimedSales() { getClaimedSales() {
let json = encodeURIComponent(JSON.stringify(this.claim.id)); let query = `ClaimBeginnings/${this.claim.id}`;
let query = `ClaimBeginnings/${json}`;
this.$http.get(query).then(res => { this.$http.get(query).then(res => {
if (res.data) if (res.data)
this.claimedSales = res.data; this.claimedSales = res.data;
@ -54,8 +48,7 @@ class Controller {
} }
deleteClaimedSale(id) { deleteClaimedSale(id) {
let json = encodeURIComponent(JSON.stringify(id)); let query = `ClaimEnds/${id}`;
let query = `ClaimEnds/${json}`;
this.$http.delete(query).then(() => { this.$http.delete(query).then(() => {
this.$.model.refresh(); this.$.model.refresh();
this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
@ -63,7 +56,7 @@ class Controller {
} }
importToNewRefundTicket() { importToNewRefundTicket() {
let query = `ClaimBeginnings/${this.$stateParams.id}/importToNewRefundTicket`; let query = `ClaimBeginnings/${this.$params.id}/importToNewRefundTicket`;
return this.$http.post(query).then(() => { return this.$http.post(query).then(() => {
this.$.model.refresh(); this.$.model.refresh();
this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
@ -112,7 +105,7 @@ class Controller {
} }
importTicketLines(ticketFk) { importTicketLines(ticketFk) {
let data = {claimFk: this.$stateParams.id, ticketFk: ticketFk}; let data = {claimFk: this.$params.id, ticketFk: ticketFk};
let query = `ClaimEnds/importTicketSales`; let query = `ClaimEnds/importTicketSales`;
this.$http.post(query, data).then(() => { this.$http.post(query, data).then(() => {
@ -123,7 +116,7 @@ class Controller {
} }
regularize() { regularize() {
let data = {claimFk: this.$stateParams.id}; let data = {claimFk: this.$params.id};
let query = `Claims/regularizeClaim`; let query = `Claims/regularizeClaim`;
return this.$http.post(query, data).then(() => { return this.$http.post(query, data).then(() => {
if (this.claim.responsibility >= Math.ceil(this.maxResponsibility) / 2) if (this.claim.responsibility >= Math.ceil(this.maxResponsibility) / 2)
@ -137,9 +130,8 @@ class Controller {
getGreugeTypeId() { getGreugeTypeId() {
const params = {filter: {where: {code: 'freightPickUp'}}}; const params = {filter: {where: {code: 'freightPickUp'}}};
const serializedParams = this.$httpParamSerializer(params); const query = `GreugeTypes/findOne`;
const query = `GreugeTypes/findOne?${serializedParams}`; return this.$http.get(query, {params}).then(res => {
return this.$http.get(query).then(res => {
this.greugeTypeFreightId = res.data.id; this.greugeTypeFreightId = res.data.id;
return res; return res;
@ -188,7 +180,7 @@ class Controller {
} }
saveResponsibility(value) { saveResponsibility(value) {
let query = `Claims/${this.$stateParams.id}/updateClaimAction`; let query = `Claims/${this.$params.id}/updateClaimAction`;
this.$http.post(query, {responsibility: value}).then(() => { this.$http.post(query, {responsibility: value}).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
@ -196,7 +188,7 @@ class Controller {
} }
saveMana(value) { saveMana(value) {
let query = `Claims/${this.$stateParams.id}/updateClaimAction`; let query = `Claims/${this.$params.id}/updateClaimAction`;
this.$http.post(query, {isChargedToMana: value}).then(() => { this.$http.post(query, {isChargedToMana: value}).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
@ -208,8 +200,6 @@ class Controller {
} }
} }
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp', '$httpParamSerializer'];
ngModule.component('vnClaimAction', { ngModule.component('vnClaimAction', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,

View File

@ -18,7 +18,8 @@ describe('claim', () => {
$state = _$state_; $state = _$state_;
$state.params.id = 1; $state.params.id = 1;
controller = $componentController('vnClaimAction', {$state, $scope}); const $element = angular.element('<vn-claim-action></vn-claim-action>');
controller = $componentController('vnClaimAction', {$element, $scope});
controller.claim = {ticketFk: 1}; controller.claim = {ticketFk: 1};
controller.$.model = {refresh: () => {}}; controller.$.model = {refresh: () => {}};
controller.$.addSales = { controller.$.addSales = {

View File

@ -2,7 +2,7 @@
vn-id="watcher" vn-id="watcher"
data="$ctrl.claim" data="$ctrl.claim"
form="form" form="form"
url="Claims/{{$ctrl.$stateParams.id}}/updateClaim" url="Claims/{{$ctrl.$params.id}}/updateClaim"
save="post"> save="post">
</vn-watcher> </vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md"> <form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
@ -55,6 +55,9 @@
</vn-card> </vn-card>
<vn-button-bar> <vn-button-bar>
<vn-submit label="Save"></vn-submit> <vn-submit label="Save"></vn-submit>
<vn-button label="Undo changes" ng-if="$ctrl.$scope.form.$dirty" ng-click="watcher.loadOriginalData()"></vn-button> <vn-button label="Undo changes"
ng-if="$ctrl.$.form.$dirty"
ng-click="watcher.loadOriginalData()">
</vn-button>
</vn-button-bar> </vn-button-bar>
</form> </form>

View File

@ -1,24 +1,16 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { class Controller extends Section {
constructor($scope, $state, aclService) {
this.$scope = $scope;
this.$state = $state;
this.$stateParams = $state.params;
this.aclService = aclService;
}
onSubmit() { onSubmit() {
this.$scope.watcher.submit().then(() => { this.$.watcher.submit().then(() => {
if (this.aclService.hasAny(['salesAssistant'])) if (this.aclService.hasAny(['salesAssistant']))
this.$state.go('claim.card.detail'); this.$state.go('claim.card.detail');
}); });
} }
} }
Controller.$inject = ['$scope', '$state', 'aclService'];
ngModule.component('vnClaimBasicData', { ngModule.component('vnClaimBasicData', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,

View File

@ -11,12 +11,13 @@ describe('Claim', () => {
beforeEach(angular.mock.inject(($componentController, $rootScope) => { beforeEach(angular.mock.inject(($componentController, $rootScope) => {
$scope = $rootScope.$new(); $scope = $rootScope.$new();
$scope.watcher = watcher; $scope.watcher = watcher;
let aclService = {hasAny: () => true}; const $element = angular.element('<vn-claim-basic-data></vn-claim-basic-data>');
controller = $componentController('vnClaimBasicData', {$scope, aclService}); controller = $componentController('vnClaimBasicData', {$element, $scope});
})); }));
describe('onSubmit()', () => { describe('onSubmit()', () => {
it(`should redirect to 'claim.card.detail' state`, () => { it(`should redirect to 'claim.card.detail' state`, () => {
jest.spyOn(controller.aclService, 'hasAny').mockReturnValue(true);
jest.spyOn(controller.$state, 'go'); jest.spyOn(controller.$state, 'go');
controller.onSubmit(); controller.onSubmit();

View File

@ -2,8 +2,8 @@ import ngModule from '../module';
import Component from 'core/lib/component'; import Component from 'core/lib/component';
class Controller extends Component { class Controller extends Component {
constructor($element, $scope, $httpParamSerializer) { constructor($element, $, $httpParamSerializer) {
super($element, $scope); super($element, $);
this.$httpParamSerializer = $httpParamSerializer; this.$httpParamSerializer = $httpParamSerializer;
this.moreOptions = [ this.moreOptions = [

View File

@ -1,17 +1,13 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { class Controller extends Section {
constructor($state, $, $http, $translate, vnApp, aclService) { constructor($element, $) {
this.$state = $state; super($element, $);
this.$ = $;
this.$http = $http;
this.$translate = $translate;
this.vnApp = vnApp;
this.aclService = aclService;
this.edit = {}; this.edit = {};
this.filter = { this.filter = {
where: {claimFk: $state.params.id}, where: {claimFk: this.$params.id},
include: [ include: [
{ {
relation: 'sale', relation: 'sale',
@ -173,7 +169,7 @@ class Controller {
} }
} }
Controller.$inject = ['$state', '$scope', '$http', '$translate', 'vnApp', 'aclService']; Controller.$inject = ['$element', '$scope'];
ngModule.component('vnClaimDetail', { ngModule.component('vnClaimDetail', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -6,12 +6,10 @@ describe('claim', () => {
let $scope; let $scope;
let controller; let controller;
let $httpBackend; let $httpBackend;
let $state;
let aclService;
beforeEach(ngModule('claim')); beforeEach(ngModule('claim'));
beforeEach(angular.mock.inject(($componentController, _$state_, _$httpBackend_, $rootScope) => { beforeEach(angular.mock.inject(($componentController, _$httpBackend_, $rootScope) => {
$scope = $rootScope.$new(); $scope = $rootScope.$new();
$scope.descriptor = { $scope.descriptor = {
show: () => {} show: () => {}
@ -19,9 +17,8 @@ describe('claim', () => {
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$httpBackend.whenGET('Claims/ClaimBeginnings').respond({}); $httpBackend.whenGET('Claims/ClaimBeginnings').respond({});
$httpBackend.whenGET(`Tickets/1/isEditable`).respond(true); $httpBackend.whenGET(`Tickets/1/isEditable`).respond(true);
$state = _$state_; const $element = angular.element('<vn-claim-detail></vn-claim-detail>');
aclService = {hasAny: () => true}; controller = $componentController('vnClaimDetail', {$element, $scope});
controller = $componentController('vnClaimDetail', {$state, aclService, $scope});
controller.claim = {ticketFk: 1}; controller.claim = {ticketFk: 1};
controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}]; controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}];
controller.salesClaimed = [{id: 1, sale: {}}]; controller.salesClaimed = [{id: 1, sale: {}}];
@ -33,6 +30,7 @@ describe('claim', () => {
controller.$.editPopover = { controller.$.editPopover = {
hide: () => {} hide: () => {}
}; };
jest.spyOn(controller.aclService, 'hasAny').mockReturnValue(true);
})); }));
describe('openAddSalesDialog()', () => { describe('openAddSalesDialog()', () => {
@ -111,7 +109,6 @@ describe('claim', () => {
quantity: 10}}; quantity: 10}};
controller.newDiscount = 10; controller.newDiscount = 10;
jest.spyOn(controller.vnApp, 'showSuccess'); jest.spyOn(controller.vnApp, 'showSuccess');
jest.spyOn(controller, 'calculateTotals'); jest.spyOn(controller, 'calculateTotals');
jest.spyOn(controller, 'clearDiscount'); jest.spyOn(controller, 'clearDiscount');

View File

@ -2,7 +2,7 @@
vn-id="model" vn-id="model"
url="ClaimDevelopments" url="ClaimDevelopments"
fields="['id', 'claimFk', 'claimReasonFk', 'claimResultFk', 'claimResponsibleFk', 'workerFk', 'claimRedeliveryFk']" fields="['id', 'claimFk', 'claimReasonFk', 'claimResultFk', 'claimResponsibleFk', 'workerFk', 'claimRedeliveryFk']"
link="{claimFk: $ctrl.$state.params.id}" link="{claimFk: $ctrl.$params.id}"
filter="$ctrl.filter" filter="$ctrl.filter"
data="claimDevelopments" data="claimDevelopments"
auto-load="true"> auto-load="true">

View File

@ -1,18 +1,13 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { class Controller extends Section {
constructor($state, $scope, aclService) {
this.$state = $state;
this.$scope = $scope;
this.aclService = aclService;
}
onSubmit() { onSubmit() {
this.$scope.watcher.check(); this.$.watcher.check();
this.$scope.model.save().then(() => { this.$.model.save().then(() => {
this.$scope.watcher.notifySaved(); this.$.watcher.notifySaved();
this.$scope.watcher.updateOriginalData(); this.$.watcher.updateOriginalData();
if (this.aclService.hasAny(['salesAssistant'])) if (this.aclService.hasAny(['salesAssistant']))
this.$state.go('claim.card.action'); this.$state.go('claim.card.action');
@ -20,8 +15,6 @@ class Controller {
} }
} }
Controller.$inject = ['$state', '$scope', 'aclService'];
ngModule.component('vnClaimDevelopment', { ngModule.component('vnClaimDevelopment', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,

View File

@ -6,7 +6,6 @@ describe('Claim', () => {
describe('Component vnClaimDevelopment', () => { describe('Component vnClaimDevelopment', () => {
let controller; let controller;
let $scope; let $scope;
let aclService;
beforeEach(ngModule('claim')); beforeEach(ngModule('claim'));
@ -14,13 +13,15 @@ describe('Claim', () => {
$scope = $rootScope.$new(); $scope = $rootScope.$new();
$scope.watcher = watcher; $scope.watcher = watcher;
$scope.model = crudModel; $scope.model = crudModel;
aclService = {hasAny: () => true}; const $element = angular.element('<vn-claim-development></vn-claim-development>');
controller = $componentController('vnClaimDevelopment', {$scope, aclService}); controller = $componentController('vnClaimDevelopment', {$element, $scope});
})); }));
describe('onSubmit()', () => { describe('onSubmit()', () => {
it(`should redirect to 'claim.card.action' state`, () => { it(`should redirect to 'claim.card.action' state`, () => {
jest.spyOn(controller.aclService, 'hasAny').mockReturnValue(true);
jest.spyOn(controller.$state, 'go'); jest.spyOn(controller.$state, 'go');
controller.onSubmit(); controller.onSubmit();
expect(controller.$state.go).toHaveBeenCalledWith('claim.card.action'); expect(controller.$state.go).toHaveBeenCalledWith('claim.card.action');

View File

@ -1,31 +0,0 @@
@import "./variables";
vn-claim-dms-index {
.drop-zone {
color: $color-font-secondary;
box-sizing: border-box;
border-radius: 0.5em;
text-align: center;
min-height: 100%;
.empty-rows {
padding: 5em $spacing-md;
font-size: 1.4em
}
vn-icon {
font-size: 3em
}
}
.photo-list {
padding: $spacing-md;
min-height: 100%;
.photo {
width: 32em;
height: 18em;
}
}
}

View File

@ -1,13 +1,5 @@
<vn-crud-model
vn-id="model"
url="Claims/filter"
limit="20"
data="claims"
order="claimStateFk ASC, created DESC"
auto-load="true">
</vn-crud-model>
<vn-auto-search <vn-auto-search
on-search="$ctrl.onSearch($params)"> model="model">
</vn-auto-search> </vn-auto-search>
<vn-data-viewer <vn-data-viewer
model="model" model="model"
@ -26,7 +18,7 @@
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<a <a
ng-repeat="claim in claims" ng-repeat="claim in model.data"
class="{{::$ctrl.compareDate(ticket.shipped)}} clickable vn-tr search-result" class="{{::$ctrl.compareDate(ticket.shipped)}} clickable vn-tr search-result"
ui-sref="claim.card.summary({id: claim.id})"> ui-sref="claim.card.summary({id: claim.id})">
<vn-td number>{{::claim.id}}</vn-td> <vn-td number>{{::claim.id}}</vn-td>

View File

@ -1,11 +1,7 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section';
export default class Controller { export default class Controller extends Section {
constructor($scope) {
this.$ = $scope;
this.ticketSelected = null;
}
stateColor(claim) { stateColor(claim) {
switch (claim.description) { switch (claim.description) {
case 'Pendiente': case 'Pendiente':
@ -43,17 +39,8 @@ export default class Controller {
onDescriptorLoad() { onDescriptorLoad() {
this.$.popover.relocate(); this.$.popover.relocate();
} }
onSearch(params) {
if (params)
this.$.model.applyFilter(null, params);
else
this.$.model.clear();
}
} }
Controller.$inject = ['$scope'];
ngModule.component('vnClaimIndex', { ngModule.component('vnClaimIndex', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller controller: Controller

View File

@ -1,8 +1,15 @@
<vn-crud-model
vn-id="model"
url="Claims/filter"
limit="20"
order="claimStateFk ASC, created DESC"
auto-load="true">
</vn-crud-model>
<vn-portal slot="topbar"> <vn-portal slot="topbar">
<vn-searchbar <vn-searchbar
search-state="claim.index"
panel="vn-claim-search-panel" panel="vn-claim-search-panel"
info="Search claim by id or client name"> info="Search claim by id or client name"
model="model">
</vn-searchbar> </vn-searchbar>
</vn-portal> </vn-portal>
<vn-portal slot="menu"> <vn-portal slot="menu">

View File

@ -1,10 +1,9 @@
<vn-crud-model vn-id="model" auto-load="true" <vn-crud-model vn-id="model" auto-load="true"
url="ClaimDms" url="ClaimDms"
link="{claimFk: $ctrl.$stateParams.id}" link="{claimFk: $ctrl.$params.id}"
limit="20" limit="20"
data="$ctrl.photos"> data="$ctrl.photos">
</vn-crud-model> </vn-crud-model>
<vn-horizontal class="photo-list drop-zone" vn-droppable="$ctrl.onDrop($event)"> <vn-horizontal class="photo-list drop-zone" vn-droppable="$ctrl.onDrop($event)">
<section class="empty-rows" ng-if="!$ctrl.photos.length"> <section class="empty-rows" ng-if="!$ctrl.photos.length">
<section><vn-icon icon="image"></vn-icon></section> <section><vn-icon icon="image"></vn-icon></section>
@ -12,8 +11,8 @@
</section> </section>
<section class="photo" ng-repeat="photo in $ctrl.photos"> <section class="photo" ng-repeat="photo in $ctrl.photos">
<section class="image vn-shadow" on-error-src <section class="image vn-shadow" on-error-src
ng-style="{'background': 'url(/api/dms/' + photo.dmsFk + '/downloadFile?access_token=' + $ctrl.accessToken + ')'}" ng-style="{'background': 'url(/api/dms/' + photo.dmsFk + '/downloadFile?access_token=' + $ctrl.vnToken.token + ')'}"
zoom-image="/api/dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}"> zoom-image="/api/dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.vnToken.token}}">
</section> </section>
<section class="actions"> <section class="actions">
<vn-button <vn-button

View File

@ -1,17 +1,8 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { class Controller extends Section {
constructor($stateParams, $scope, $http, $translate, vnToken, vnApp, vnConfig) {
this.$stateParams = $stateParams;
this.$ = $scope;
this.$http = $http;
this.$translate = $translate;
this.accessToken = vnToken.token;
this.vnApp = vnApp;
this.vnConfig = vnConfig;
}
showWorkerDescriptor(event, workerFk) { showWorkerDescriptor(event, workerFk) {
event.preventDefault(); event.preventDefault();
event.stopImmediatePropagation(); event.stopImmediatePropagation();
@ -106,8 +97,6 @@ class Controller {
} }
} }
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnToken', 'vnApp', 'vnConfig'];
ngModule.component('vnClaimPhotos', { ngModule.component('vnClaimPhotos', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,

View File

@ -3,7 +3,6 @@ import crudModel from 'core/mocks/crud-model';
describe('Claim', () => { describe('Claim', () => {
describe('Component vnClaimPhotos', () => { describe('Component vnClaimPhotos', () => {
let $componentController;
let $scope; let $scope;
let $httpBackend; let $httpBackend;
let controller; let controller;
@ -11,12 +10,12 @@ describe('Claim', () => {
beforeEach(ngModule('claim')); beforeEach(ngModule('claim'));
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$httpParamSerializer_) => { beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
$componentController = _$componentController_;
$httpParamSerializer = _$httpParamSerializer_; $httpParamSerializer = _$httpParamSerializer_;
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$scope = $rootScope.$new(); $scope = $rootScope.$new();
controller = $componentController('vnClaimPhotos', {$: $scope}); const $element = angular.element('<vn-claim-photos></vn-claim-photos>');
controller = $componentController('vnClaimPhotos', {$element, $scope});
controller.$.model = crudModel; controller.$.model = crudModel;
controller.claim = { controller.claim = {
id: 1, id: 1,

View File

@ -86,8 +86,8 @@
<vn-horizontal class="photo-list"> <vn-horizontal class="photo-list">
<section class="photo" ng-repeat="photo in photos"> <section class="photo" ng-repeat="photo in photos">
<section class="image" on-error-src <section class="image" on-error-src
ng-style="{'background': 'url(/api/dms/' + photo.dmsFk + '/downloadFile?access_token=' + $ctrl.accessToken + ')'}" ng-style="{'background': 'url(/api/dms/' + photo.dmsFk + '/downloadFile?access_token=' + $ctrl.vnToken.token + ')'}"
zoom-image="/api/dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}"> zoom-image="/api/dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.vnToken.token}}">
</section> </section>
</section> </section>
</vn-horizontal> </vn-horizontal>

View File

@ -1,19 +1,17 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { class Controller extends Section {
constructor($scope, $http, $stateParams, vnToken) { $onChanges() {
this.$http = $http; if (this.claim && this.claim.id)
this.$ = $scope; this.getSummary();
this.$stateParams = $stateParams;
this.accessToken = vnToken.token;
} }
get claim() { get claim() {
return this._claim; return this._claim;
} }
set claim(value) { set claim(value) {
this._claim = value; this._claim = value;
@ -35,11 +33,6 @@ class Controller {
}); });
} }
$onChanges() {
if (this.claim && this.claim.id)
this.getSummary();
}
showItemDescriptor(event, itemFk) { showItemDescriptor(event, itemFk) {
this.$.itemDescriptor.itemFk = itemFk; this.$.itemDescriptor.itemFk = itemFk;
this.$.itemDescriptor.parent = event.target; this.$.itemDescriptor.parent = event.target;
@ -59,8 +52,6 @@ class Controller {
} }
} }
Controller.$inject = ['$scope', '$http', '$stateParams', 'vnToken'];
ngModule.component('vnClaimSummary', { ngModule.component('vnClaimSummary', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,

View File

@ -5,12 +5,15 @@ describe('Claim', () => {
describe('Component summary', () => { describe('Component summary', () => {
let controller; let controller;
let $httpBackend; let $httpBackend;
let $scope;
beforeEach(ngModule('claim')); beforeEach(ngModule('claim'));
beforeEach(angular.mock.inject(($componentController, _$httpBackend_) => { beforeEach(angular.mock.inject(($componentController, _$httpBackend_, $rootScope) => {
$scope = $rootScope.$new();
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
controller = $componentController('vnClaimSummary'); const $element = angular.element('<vn-claim-summary></vn-claim-summary>');
controller = $componentController('vnClaimSummary', {$element, $scope});
controller.claim = {id: 1}; controller.claim = {id: 1};
controller.$.model = crudModel; controller.$.model = crudModel;
})); }));
@ -29,6 +32,7 @@ describe('Claim', () => {
describe('$onChanges()', () => { describe('$onChanges()', () => {
it('should call getSummary when item.id is defined', () => { it('should call getSummary when item.id is defined', () => {
jest.spyOn(controller, 'getSummary'); jest.spyOn(controller, 'getSummary');
controller.$onChanges(); controller.$onChanges();
expect(controller.getSummary).toHaveBeenCalledWith(); expect(controller.getSummary).toHaveBeenCalledWith();

View File

@ -11,7 +11,7 @@
vn-id="model" vn-id="model"
url="AddressObservations" url="AddressObservations"
fields="['id', 'addressFk', 'observationTypeFk', 'description']" fields="['id', 'addressFk', 'observationTypeFk', 'description']"
link="{addressFk: $ctrl.$stateParams.addressId}" link="{addressFk: $ctrl.$params.addressId}"
data="observations" data="observations"
auto-load="true"> auto-load="true">
</vn-crud-model> </vn-crud-model>

View File

@ -1,7 +1,7 @@
import ngModule from '../../module'; import ngModule from '../../module';
import Component from 'core/lib/component'; import Section from 'salix/components/section';
export default class Controller extends Component { export default class Controller extends Section {
constructor($element, $) { constructor($element, $) {
super($element, $); super($element, $);

View File

@ -1,7 +1,7 @@
import ngModule from '../../module'; import ngModule from '../../module';
import Component from 'core/lib/component'; import Section from 'salix/components/section';
export default class Controller extends Component { export default class Controller extends Section {
removeObservation(index) { removeObservation(index) {
this.$.watcher.setDirty(); this.$.watcher.setDirty();
this.$.model.remove(index); this.$.model.remove(index);

View File

@ -1,6 +1,6 @@
<vn-crud-model <vn-crud-model
vn-id="model" vn-id="model"
url="Clients/{{$ctrl.$stateParams.id}}/addresses" url="Clients/{{$ctrl.$params.id}}/addresses"
filter="$ctrl.filter" filter="$ctrl.filter"
limit="10" limit="10"
data="$ctrl.addresses" data="$ctrl.addresses"

View File

@ -1,13 +1,10 @@
import ngModule from '../../module'; import ngModule from '../../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { class Controller extends Section {
constructor($http, $scope, $stateParams, $translate, vnApp) { constructor($element, $) {
this.$http = $http; super($element, $);
this.$scope = $scope;
this.$stateParams = $stateParams;
this.$translate = $translate;
this.vnApp = vnApp;
this.filter = { this.filter = {
fields: [ fields: [
'id', 'id',
@ -47,7 +44,7 @@ class Controller {
} }
setDefault(address) { setDefault(address) {
let query = `Clients/${this.$stateParams.id}`; let query = `Clients/${this.$params.id}`;
let params = {defaultAddressFk: address.id}; let params = {defaultAddressFk: address.id};
this.$http.patch(query, params).then(res => { this.$http.patch(query, params).then(res => {
if (res.data) { if (res.data) {
@ -72,7 +69,7 @@ class Controller {
}); });
} }
} }
Controller.$inject = ['$http', '$scope', '$stateParams', '$translate', 'vnApp']; Controller.$inject = ['$element', '$scope'];
ngModule.component('vnClientAddressIndex', { ngModule.component('vnClientAddressIndex', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -15,9 +15,10 @@ describe('Client', () => {
$stateParams.id = 1; $stateParams.id = 1;
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$scope = $rootScope.$new(); $scope = $rootScope.$new();
controller = $componentController('vnClientAddressIndex', {$stateParams, $scope}); const $element = angular.element('<vn-client-address-index></vn-client-address-index>');
controller = $componentController('vnClientAddressIndex', {$element, $scope});
controller.client = {id: 101, defaultAddressFk: 121}; controller.client = {id: 101, defaultAddressFk: 121};
controller.$scope.model = crudModel; controller.$.model = crudModel;
})); }));
describe('setDefault()', () => { describe('setDefault()', () => {

View File

@ -1,19 +1,15 @@
import ngModule from '../../module'; import ngModule from '../../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { class Controller extends Section {
constructor($scope, $state, $http, vnApp, $translate, vnConfig) { constructor($element, $) {
this.$http = $http; super($element, $);
this.$ = $scope;
this.$state = $state;
this.vnApp = vnApp;
this.$translate = $translate;
this.receipt = { this.receipt = {
payed: new Date(), payed: new Date(),
clientFk: this.$state.params.id, clientFk: this.$params.id,
companyFk: vnConfig.companyFk, companyFk: this.vnConfig.companyFk,
bankFk: vnConfig.bankFk bankFk: this.vnConfig.bankFk
}; };
} }
@ -57,7 +53,7 @@ class Controller {
getAmountPaid() { getAmountPaid() {
let filter = { let filter = {
where: { where: {
clientFk: this.$state.params.id, clientFk: this.$params.id,
companyFk: this.receipt.companyFk companyFk: this.receipt.companyFk
} }
}; };
@ -86,7 +82,6 @@ class Controller {
}); });
} }
} }
Controller.$inject = ['$scope', '$state', '$http', 'vnApp', '$translate', 'vnConfig'];
ngModule.component('vnClientBalanceCreate', { ngModule.component('vnClientBalanceCreate', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -97,7 +97,7 @@
<vn-td center shrink> <vn-td center shrink>
<a ng-show="balance.hasPdf" <a ng-show="balance.hasPdf"
target="_blank" target="_blank"
href="InvoiceOuts/{{::balance.id}}/download?access_token={{::$ctrl.accessToken}}"> href="InvoiceOuts/{{::balance.id}}/download?access_token={{::$ctrl.vnToken.token}}">
<vn-icon-button <vn-icon-button
icon="cloud_download" icon="cloud_download"
title="{{'Download PDF' | translate}}"> title="{{'Download PDF' | translate}}">

View File

@ -1,14 +1,10 @@
import ngModule from '../../module'; import ngModule from '../../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { class Controller extends Section {
constructor($stateParams, $translate, $scope, vnToken, $http, vnConfig) { constructor($element, $) {
this.$http = $http; super($element, $);
this.$ = $scope;
this.$stateParams = $stateParams;
this.$translate = $translate;
this.accessToken = vnToken.token;
this.vnConfig = vnConfig;
this.filter = { this.filter = {
include: { include: {
relation: 'company', relation: 'company',
@ -46,17 +42,16 @@ class Controller {
getData() { getData() {
return this.$.model.applyFilter(null, { return this.$.model.applyFilter(null, {
clientId: this.$stateParams.id, clientId: this.$params.id,
companyId: this.companyId companyId: this.companyId
}).then(() => this.$.riskModel.applyFilter({ }).then(() => this.$.riskModel.applyFilter({
where: { where: {
clientFk: this.$stateParams.id, clientFk: this.$params.id,
companyFk: this.companyId companyFk: this.companyId
} }
})).then(() => this.getBalances()); })).then(() => this.getBalances());
} }
getCurrentBalance() { getCurrentBalance() {
const clientRisks = this.$.riskModel.data; const clientRisks = this.$.riskModel.data;
const selectedCompany = this.companyId; const selectedCompany = this.companyId;
@ -79,7 +74,6 @@ class Controller {
}); });
} }
openCreateDialog() { openCreateDialog() {
this.$.balanceCreateDialog.companyFk = this.companyId; this.$.balanceCreateDialog.companyFk = this.companyId;
this.$.balanceCreateDialog.onResponse = () => this.getData(); this.$.balanceCreateDialog.onResponse = () => this.getData();
@ -110,7 +104,7 @@ class Controller {
} }
} }
Controller.$inject = ['$stateParams', '$translate', '$scope', 'vnToken', '$http', 'vnConfig']; Controller.$inject = ['$element', '$scope'];
ngModule.component('vnClientBalanceIndex', { ngModule.component('vnClientBalanceIndex', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -2,15 +2,14 @@ import './index';
describe('Client', () => { describe('Client', () => {
describe('Component vnClientBalanceIndex', () => { describe('Component vnClientBalanceIndex', () => {
let $componentController;
let controller; let controller;
beforeEach(ngModule('client')); beforeEach(ngModule('client'));
beforeEach(angular.mock.inject((_$componentController_, $rootScope) => { beforeEach(angular.mock.inject(($componentController, $rootScope) => {
$componentController = _$componentController_;
let $scope = $rootScope.$new(); let $scope = $rootScope.$new();
controller = $componentController('vnClientBalanceIndex', {$scope}); const $element = angular.element('<vn-client-balance-index></vn-client-balance-index>');
controller = $componentController('vnClientBalanceIndex', {$element, $scope});
controller.$.model = {applyFilter: () => {}}; controller.$.model = {applyFilter: () => {}};
controller.$.riskModel = { controller.$.riskModel = {
applyFilter: () => {}, applyFilter: () => {},
@ -30,7 +29,7 @@ describe('Client', () => {
describe('getData()', () => { describe('getData()', () => {
it('should apply the filters on he models and get the client balance', () => { it('should apply the filters on he models and get the client balance', () => {
controller._companyId = 442; controller._companyId = 442;
controller.$stateParams.id = 101; controller.$params.id = 101;
jest.spyOn(controller, 'getBalances').mockReturnThis(); jest.spyOn(controller, 'getBalances').mockReturnThis();
jest.spyOn(controller.$.model, 'applyFilter').mockReturnValue(Promise.resolve()); jest.spyOn(controller.$.model, 'applyFilter').mockReturnValue(Promise.resolve());
jest.spyOn(controller.$.riskModel, 'applyFilter').mockReturnValue(Promise.resolve()); jest.spyOn(controller.$.riskModel, 'applyFilter').mockReturnValue(Promise.resolve());

View File

@ -1,7 +1,9 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section';
ngModule.component('vnClientBasicData', { ngModule.component('vnClientBasicData', {
template: require('./index.html'), template: require('./index.html'),
controller: Section,
bindings: { bindings: {
client: '<' client: '<'
} }

View File

@ -2,7 +2,7 @@
vn-id="model" vn-id="model"
url="ClientContacts" url="ClientContacts"
fields="['id', 'name', 'phone', 'clientFk']" fields="['id', 'name', 'phone', 'clientFk']"
link="{clientFk: $ctrl.$stateParams.id}" link="{clientFk: $ctrl.$params.id}"
data="contacts" data="contacts"
auto-load="true"> auto-load="true">
</vn-crud-model> </vn-crud-model>

Some files were not shown because too many files have changed in this diff Show More