#2026 Implemented & tests passed
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Juan Ferrer 2020-03-25 20:44:59 +01:00
parent 77e8bbc2ce
commit 0bd09492d1
8 changed files with 115 additions and 99 deletions

View File

@ -65,15 +65,6 @@ let actions = {
}, },
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.clearInput(`vn-login vn-textfield[ng-model="$ctrl.user"]`);
await this.write(`vn-login vn-textfield[ng-model="$ctrl.user"]`, userName);
await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.password"]`);
await this.write(`vn-login vn-textfield[ng-model="$ctrl.password"]`, password);
await this.waitToClick('vn-login button[type=submit]');
},
login: async function(userName) {
let state = await this.getState(); let state = await this.getState();
if (state != 'login') { if (state != 'login') {
@ -91,6 +82,16 @@ let actions = {
} }
await this.waitForState('login'); await this.waitForState('login');
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.write(`vn-login vn-textfield[ng-model="$ctrl.user"]`, userName);
await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.password"]`);
await this.write(`vn-login vn-textfield[ng-model="$ctrl.password"]`, password);
await this.waitToClick('vn-login button[type=submit]');
},
login: async function(userName) {
await this.doLogin(userName); await this.doLogin(userName);
await this.waitForState('home'); await this.waitForState('home');
}, },
@ -114,10 +115,11 @@ let actions = {
}, },
gotoState: async function(state, params) { gotoState: async function(state, params) {
return await this.evaluate((state, params) => { await this.evaluate((state, params) => {
let $state = angular.element(document.body).injector().get('$state'); let $state = angular.element(document.body).injector().get('$state');
return $state.go(state, params); return $state.go(state, params);
}, state, params); }, state, params);
await this.waitForSpinnerLoad();
}, },
waitForState: async function(state) { waitForState: async function(state) {
@ -125,7 +127,7 @@ let actions = {
let $state = angular.element(document.body).injector().get('$state'); let $state = angular.element(document.body).injector().get('$state');
return !$state.transition && $state.is(state); return !$state.transition && $state.is(state);
}, {}, state); }, {}, state);
await this.waitForSpinnerLoad(state); await this.waitForSpinnerLoad();
}, },
waitForTransition: async function() { waitForTransition: async function() {
@ -181,6 +183,12 @@ let actions = {
}, selector, property); }, selector, property);
}, },
getClassName: async function(selector) {
const element = await this.$(selector);
const handle = await element.getProperty('className');
return await handle.jsonValue();
},
waitPropertyLength: async function(selector, property, minLength) { waitPropertyLength: async function(selector, property, minLength) {
await this.waitForFunction((selector, property, minLength) => { await this.waitForFunction((selector, property, minLength) => {
const element = document.querySelector(selector); const element = document.querySelector(selector);
@ -339,24 +347,42 @@ let actions = {
await this.waitFor(300); await this.waitFor(300);
await this.evaluate(() => { await this.evaluate(() => {
let hideButton = document.querySelector('#shapes .shown button'); let hideButton = document
.querySelector('vn-snackbar .shape.shown button');
if (hideButton) if (hideButton)
return document.querySelector('#shapes .shown button').click(); return hideButton.click();
}); });
await this.waitFor('#shapes > .shape', {hidden: true}); await this.waitFor('vn-snackbar .shape.shown', {hidden: true});
},
waitForSnackbar: async function() {
const selector = 'vn-snackbar .shape.shown';
await this.waitForSelector(selector);
let message = await this.evaluate(selector => {
const shape = document.querySelector(selector);
const message = {
text: shape.querySelector('.text').innerText
};
const types = ['error', 'success'];
for (let type of types) {
if (shape.classList.contains(type)) {
message.type = type;
break;
}
}
return message;
}, selector);
await this.hideSnackbar();
return message;
}, },
waitForLastSnackbar: async function() { waitForLastSnackbar: async function() {
const selector = 'vn-snackbar .shown .text'; const message = await this.waitForSnackbar();
return message.text;
await this.waitForSelector(selector);
let snackBarText = await this.evaluate(selector => {
const shape = document.querySelector(selector);
return shape.innerText;
}, selector);
await this.hideSnackbar();
return snackBarText;
}, },
pickDate: async function(selector, date) { pickDate: async function(selector, date) {
@ -438,7 +464,6 @@ let actions = {
.includes(searchValue.toLowerCase()); .includes(searchValue.toLowerCase());
}, {}, builtSelector, searchValue); }, {}, builtSelector, searchValue);
await this.waitForMutation('.vn-drop-down', 'childList');
await this.waitFor('.vn-drop-down', {hidden: true}); await this.waitFor('.vn-drop-down', {hidden: true});
}, },

View File

@ -2,6 +2,8 @@
export default { export default {
globalItems: { globalItems: {
applicationsMenuButton: '#apps', applicationsMenuButton: '#apps',
userMenuButton: '#user',
logoutButton: '#logout',
applicationsMenuVisible: '.modules-menu', applicationsMenuVisible: '.modules-menu',
clientsButton: '.modules-menu > li[ui-sref="client.index"]', clientsButton: '.modules-menu > li[ui-sref="client.index"]',
itemsButton: '.modules-menu > li[ui-sref="item.index"]', itemsButton: '.modules-menu > li[ui-sref="item.index"]',
@ -10,7 +12,6 @@ export default {
claimsButton: '.modules-menu > li[ui-sref="claim.index"]', claimsButton: '.modules-menu > li[ui-sref="claim.index"]',
returnToModuleIndexButton: 'a[ui-sref="order.index"]', returnToModuleIndexButton: 'a[ui-sref="order.index"]',
homeButton: 'vn-topbar > div.side.start > a', homeButton: 'vn-topbar > div.side.start > a',
userMenuButton: '#user',
userLocalWarehouse: '.user-popover vn-autocomplete[ng-model="$ctrl.localWarehouseFk"]', userLocalWarehouse: '.user-popover vn-autocomplete[ng-model="$ctrl.localWarehouseFk"]',
userLocalBank: '.user-popover vn-autocomplete[ng-model="$ctrl.localBankFk"]', userLocalBank: '.user-popover vn-autocomplete[ng-model="$ctrl.localBankFk"]',
userLocalCompany: '.user-popover vn-autocomplete[ng-model="$ctrl.localCompanyFk"]', userLocalCompany: '.user-popover vn-autocomplete[ng-model="$ctrl.localCompanyFk"]',
@ -338,8 +339,8 @@ export default {
}, },
itemDiary: { itemDiary: {
secondTicketId: 'vn-item-diary vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(2) > span', secondTicketId: 'vn-item-diary vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(2) > span',
fourthBalance: 'vn-item-diary vn-tbody > vn-tr:nth-child(4) > vn-td.balance > span',
firstBalance: 'vn-item-diary vn-tbody > vn-tr:nth-child(1) > vn-td.balance', firstBalance: 'vn-item-diary vn-tbody > vn-tr:nth-child(1) > vn-td.balance',
fourthBalance: 'vn-item-diary vn-tbody > vn-tr:nth-child(4) > vn-td.balance',
warehouse: 'vn-item-diary vn-autocomplete[ng-model="$ctrl.warehouseFk"]', warehouse: 'vn-item-diary vn-autocomplete[ng-model="$ctrl.warehouseFk"]',
}, },
itemLog: { itemLog: {
@ -352,7 +353,7 @@ export default {
route: 'vn-ticket-summary vn-label-value[label="Route"] > section > span > span', route: 'vn-ticket-summary vn-label-value[label="Route"] > section > span > span',
total: 'vn-ticket-summary vn-one.taxes > p:nth-child(3) > strong', total: 'vn-ticket-summary vn-one.taxes > p:nth-child(3) > strong',
sale: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr', sale: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr',
firstSaleItemId: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span', firstSaleItemId: 'vn-ticket-summary [name="sales"] vn-table vn-tbody > :nth-child(1) > vn-td:nth-child(2) > span',
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img', firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor', itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
itemDescriptorPopoverItemDiaryButton: 'vn-item-descriptor a[href="#!/item/2/diary?warehouseFk=5&ticketFk=20"]', itemDescriptorPopoverItemDiaryButton: 'vn-item-descriptor a[href="#!/item/2/diary?warehouseFk=5&ticketFk=20"]',

View File

@ -1,3 +1,4 @@
import selectors from '../../helpers/selectors';
import getBrowser from '../../helpers/puppeteer'; import getBrowser from '../../helpers/puppeteer';
describe('Login path', async() => { describe('Login path', async() => {
@ -13,41 +14,54 @@ describe('Login path', async() => {
}); });
describe('Bad login', async() => { describe('Bad login', async() => {
it('should receive an error when the username is incorrect', async() => { it('should receive an error when the password is invalid', async() => {
await page.doLogin('badUser', ''); await page.doLogin('employee', 'badPassword');
const result = await page.waitForLastSnackbar(); const message = await page.waitForSnackbar();
const state = await page.getState(); const state = await page.getState();
expect(result.length).toBeGreaterThan(0); expect(message.type).toBe('error');
expect(state).toBe('login');
});
it('should receive an error when the username is invalid', async() => {
await page.doLogin('badUser', '');
const message = await page.waitForSnackbar();
const state = await page.getState();
expect(message.type).toBe('error');
expect(state).toBe('login'); expect(state).toBe('login');
}); });
it('should receive an error when the username is blank', async() => { it('should receive an error when the username is blank', async() => {
await page.doLogin('', ''); await page.doLogin('', '');
const result = await page.waitForLastSnackbar(); const message = await page.waitForSnackbar();
const state = await page.getState(); const state = await page.getState();
expect(result.length).toBeGreaterThan(0); expect(message.type).toBe('error');
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'); expect(state).toBe('login');
}); });
}); });
describe('Successful login', async() => { describe('Successful login', async() => {
it('should log in', async() => { it('should log in and go to home state', async() => {
await page.doLogin('employee', 'nightmare'); await page.doLogin('employee');
await page.waitForNavigation(); await page.waitFor('vn-home');
const state = await page.getState(); const state = await page.getState();
expect(state).toBe('home'); expect(state).toBe('home');
}); });
}); });
describe('Logout', async() => {
it('should logout and return to login state', async() => {
await page.doLogin('employee');
await page.waitToClick(selectors.globalItems.userMenuButton);
await page.waitToClick(selectors.globalItems.logoutButton);
await page.waitFor('vn-login');
const state = await page.getState();
expect(state).toBe('login');
});
});
}); });

View File

@ -1,9 +1,10 @@
import selectors from '../../helpers/selectors'; import selectors from '../../helpers/selectors';
import getBrowser from '../../helpers/puppeteer'; import getBrowser from '../../helpers/puppeteer';
describe('Client create path', async() => { describe('Client create path', () => {
let browser; let browser;
let page; let page;
beforeAll(async() => { beforeAll(async() => {
browser = await getBrowser(); browser = await getBrowser();
page = browser.page; page = browser.page;
@ -92,9 +93,9 @@ describe('Client create path', async() => {
await page.clearInput(selectors.createClientView.postcode); await page.clearInput(selectors.createClientView.postcode);
await page.write(selectors.createClientView.postcode, '46000'); await page.write(selectors.createClientView.postcode, '46000');
await page.waitToClick(selectors.createClientView.createButton); await page.waitToClick(selectors.createClientView.createButton);
const result = await page.waitForLastSnackbar(); const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!'); expect(message.type).toEqual('success');
}); });
it('should click on the Clients button of the top bar menu', async() => { it('should click on the Clients button of the top bar menu', async() => {

View File

@ -1,66 +1,30 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer'; import getBrowser from '../../helpers/puppeteer';
// #2026 Fallo en relocate de descriptor popover describe('Ticket diary path', () => {
xdescribe('Ticket diary path', () => {
let browser;
let page; let page;
beforeAll(async() => { beforeAll(async() => {
browser = await getBrowser(); page = (await getBrowser()).page;
page = browser.page;
await page.loginAndModule('employee', 'ticket'); await page.loginAndModule('employee', 'ticket');
}); });
afterAll(async() => { afterAll(async() => {
await browser.close(); await page.browser().close();
}); });
it('should search for a specific ticket', async() => { it(`should navigate to item diary from ticket sale and check the lines`, async() => {
await page.write(selectors.ticketsIndex.topbarSearch, '1'); await page.accessToSearchResult('1');
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 click on the search result to access to the ticket summary`, async() => {
await page.waitForTextInElement(selectors.ticketsIndex.searchResult, 'Bat cave');
await page.waitToClick(selectors.ticketsIndex.searchResult);
let url = await page.expectURL('/summary'); // use waitForState instead
expect(url).toBe(true);
});
it(`should navigate to the item diary from the 1st sale item id descriptor popover`, async() => {
await page.waitToClick(selectors.ticketSummary.firstSaleItemId); await page.waitToClick(selectors.ticketSummary.firstSaleItemId);
await page.waitForTransitionEnd('.vn-popover');
await page.waitToClick(selectors.ticketSummary.popoverDiaryButton); await page.waitToClick(selectors.ticketSummary.popoverDiaryButton);
let url = await page.expectURL('/diary'); // use waitForState instead await page.waitForState('item.card.diary');
expect(url).toBe(true); const secondIdClass = await page.getClassName(selectors.itemDiary.secondTicketId);
}); const fourthBalanceClass = await page.getClassName(selectors.itemDiary.fourthBalance);
const firstBalanceClass = await page.getClassName(selectors.itemDiary.firstBalance);
it(`should check the second line id is marked as message`, async() => { expect(secondIdClass).toContain('message');
const result = await page expect(fourthBalanceClass).toContain('message');
.waitToGetProperty(selectors.itemDiary.secondTicketId, 'className'); expect(firstBalanceClass).toContain('balance');
expect(result).toContain('message');
});
it(`should check the third line balance is marked as message`, async() => {
const result = await page
.waitToGetProperty(`${selectors.itemDiary.fourthBalance} > span`, 'className');
expect(result).toContain('message');
});
it(`should change to the warehouse two and check there are sales marked as negative balance`, async() => {
await page.autocompleteSearch(selectors.itemDiary.warehouse, 'Warehouse Two');
const result = await page
.waitToGetProperty(selectors.itemDiary.firstBalance, 'className');
expect(result).toContain('balance');
}); });
}); });

View File

@ -45,8 +45,11 @@ export default class Auth {
} }
login(user, password, remember) { login(user, password, remember) {
if (!user) if (!user) {
return this.$q.reject(new UserError('Please enter your username')); let err = new UserError('Please enter your username');
err.code = 'EmptyLogin';
return this.$q.reject(err);
}
let params = { let params = {
user, user,

View File

@ -181,6 +181,13 @@ function e2eSingleRun() {
return gulp.src(specFiles).pipe(jasmine({ return gulp.src(specFiles).pipe(jasmine({
errorOnFail: false, errorOnFail: false,
timeout: 30000, timeout: 30000,
config: {
random: false,
// TODO: Waiting for this option to be implemented
// https://github.com/jasmine/jasmine/issues/1533
stopSpecOnExpectationFailure: false
},
reporter: [ reporter: [
new SpecReporter({ new SpecReporter({
spec: { spec: {

View File

@ -3,6 +3,7 @@ vn-item-descriptor {
display: block; display: block;
img[ng-src] { img[ng-src] {
min-height: 16em;
height: 100%; height: 100%;
width: 100%; width: 100%;
display: block; display: block;