2018-10-25 14:44:03 +00:00
|
|
|
/* eslint no-invalid-this: "off" */
|
|
|
|
|
2017-09-15 10:24:37 +00:00
|
|
|
import config from './config.js';
|
|
|
|
import Nightmare from 'nightmare';
|
2018-02-20 09:00:19 +00:00
|
|
|
import {URL} from 'url';
|
2017-09-15 10:24:37 +00:00
|
|
|
|
2017-10-31 07:14:33 +00:00
|
|
|
|
2018-11-21 15:59:09 +00:00
|
|
|
Nightmare.asyncAction = function(name, func) {
|
|
|
|
Nightmare.action(name, function(...args) {
|
|
|
|
let done = args[arguments.length - 1];
|
|
|
|
func.apply(this, args)
|
|
|
|
.then(result => done(null, result))
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
Nightmare.asyncAction('clearInput', async function(selector) {
|
2018-10-25 14:44:03 +00:00
|
|
|
const backSpaces = [];
|
2018-10-31 10:58:10 +00:00
|
|
|
for (let i = 0; i < 50; i += 1)
|
2017-09-15 10:24:37 +00:00
|
|
|
backSpaces.push('\u0008');
|
2018-10-31 10:58:10 +00:00
|
|
|
|
2018-11-21 15:59:09 +00:00
|
|
|
await this.wait(selector)
|
|
|
|
.type(selector, backSpaces.join(''));
|
2017-09-15 10:24:37 +00:00
|
|
|
});
|
|
|
|
|
2018-11-22 11:34:20 +00:00
|
|
|
let actions = {
|
|
|
|
login: function(userName, done) {
|
|
|
|
this.goto(`${config.url}auth/?apiKey=salix`)
|
|
|
|
.wait(`vn-login input[name=user]`)
|
|
|
|
.write(`vn-login input[name=user]`, userName)
|
|
|
|
.write(`vn-login input[name=password]`, 'nightmare')
|
|
|
|
.click(`vn-login input[type=submit]`)
|
|
|
|
// FIXME: Wait for dom to be ready: https://github.com/segmentio/nightmare/issues/481
|
|
|
|
.wait(1000)
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
|
|
|
|
|
|
|
changeLanguageToEnglish: function(done) {
|
|
|
|
this.wait('#lang')
|
|
|
|
.evaluate(selector => {
|
|
|
|
return document.querySelector(selector).title;
|
|
|
|
}, '#lang')
|
|
|
|
.then(title => {
|
|
|
|
if (title === 'Change language') {
|
|
|
|
this.then(done)
|
|
|
|
.catch(done);
|
|
|
|
} else {
|
|
|
|
this.click('#lang')
|
|
|
|
.click('vn-main-menu [vn-id="langs-menu"] ul > li[name="en"]')
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForLogin: function(userName, done) {
|
|
|
|
this.login(userName)
|
|
|
|
.waitForURL('#!/')
|
|
|
|
.url()
|
|
|
|
.changeLanguageToEnglish()
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
|
|
|
|
2018-11-23 07:05:57 +00:00
|
|
|
selectModule: function(moduleName, done) {
|
|
|
|
this.waitToClick(`body > vn-app > vn-vertical > vn-vertical > vn-home > div > div > a[ui-sref="${moduleName}.index"]`)
|
|
|
|
.waitForURL(moduleName)
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
|
|
|
|
|
|
|
loginAndModule: function(userName, moduleName, done) {
|
|
|
|
this.waitForLogin(userName)
|
|
|
|
.selectModule(moduleName)
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
|
|
|
|
2018-11-22 11:34:20 +00:00
|
|
|
parsedUrl: function(done) {
|
|
|
|
this.url()
|
|
|
|
.then(url => {
|
|
|
|
done(null, new URL(url));
|
|
|
|
}).catch(done);
|
|
|
|
},
|
|
|
|
|
|
|
|
getProperty: function(selector, property, done) {
|
|
|
|
this.evaluate_now((selector, property) => {
|
|
|
|
return document.querySelector(selector)[property].replace(/\s+/g, ' ').trim();
|
|
|
|
}, done, selector, property);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitPropertyLength: function(selector, property, minLength, done) {
|
|
|
|
this.wait((selector, property, minLength) => {
|
|
|
|
const element = document.querySelector(selector);
|
|
|
|
return element && element[property] != null && element[property] !== '' && element[property].length >= minLength;
|
|
|
|
}, selector, property, minLength)
|
|
|
|
.getProperty(selector, property)
|
|
|
|
.then(result => done(null, result), done);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitToGetProperty: function(selector, property, done) {
|
|
|
|
this.wait((selector, property) => {
|
|
|
|
const element = document.querySelector(selector);
|
|
|
|
return element && element[property] != null && element[property] !== '';
|
|
|
|
}, selector, property)
|
|
|
|
.getProperty(selector, property)
|
|
|
|
.then(result => done(null, result), done);
|
|
|
|
},
|
|
|
|
|
|
|
|
write: function(selector, text, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.type(selector, text)
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
2017-09-15 10:24:37 +00:00
|
|
|
|
2018-11-22 11:34:20 +00:00
|
|
|
waitToClick: function(selector, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.click(selector)
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
|
|
|
|
|
|
|
isVisible: function(selector, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.evaluate_now(elementSelector => {
|
|
|
|
const selectorMatches = document.querySelectorAll(elementSelector);
|
|
|
|
const element = selectorMatches[0];
|
|
|
|
if (selectorMatches.length > 1)
|
|
|
|
throw new Error(`multiple matches of ${elementSelector} found`);
|
|
|
|
|
|
|
|
let isVisible = false;
|
|
|
|
if (element) {
|
|
|
|
const eventHandler = event => {
|
|
|
|
event.preventDefault();
|
|
|
|
isVisible = true;
|
|
|
|
};
|
|
|
|
element.addEventListener('mouseover', eventHandler);
|
|
|
|
const elementBoundaries = element.getBoundingClientRect();
|
|
|
|
const x = elementBoundaries.left + element.offsetWidth / 2;
|
|
|
|
const y = elementBoundaries.top + element.offsetHeight / 2;
|
|
|
|
const elementInCenter = document.elementFromPoint(x, y);
|
|
|
|
const elementInTopLeft = document.elementFromPoint(elementBoundaries.left, elementBoundaries.top);
|
|
|
|
const elementInBottomRight = document.elementFromPoint(elementBoundaries.right, elementBoundaries.bottom);
|
|
|
|
const e = new MouseEvent('mouseover', {
|
|
|
|
view: window,
|
|
|
|
bubbles: true,
|
|
|
|
cancelable: true,
|
|
|
|
});
|
|
|
|
if (elementInCenter)
|
|
|
|
elementInCenter.dispatchEvent(e);
|
|
|
|
|
|
|
|
if (elementInTopLeft)
|
|
|
|
elementInTopLeft.dispatchEvent(e);
|
|
|
|
|
|
|
|
if (elementInBottomRight)
|
|
|
|
elementInBottomRight.dispatchEvent(e);
|
|
|
|
|
|
|
|
element.removeEventListener('mouseover', eventHandler);
|
|
|
|
}
|
|
|
|
return isVisible;
|
|
|
|
}, done, selector);
|
|
|
|
},
|
|
|
|
|
|
|
|
countElement: function(selector, done) {
|
|
|
|
this.evaluate_now(selector => {
|
|
|
|
return document.querySelectorAll(selector).length;
|
2018-10-25 14:44:03 +00:00
|
|
|
}, done, selector);
|
2018-11-22 11:34:20 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
waitForNumberOfElements: function(selector, count, done) {
|
|
|
|
this.wait((selector, count) => {
|
|
|
|
return document.querySelectorAll(selector).length === count;
|
|
|
|
}, selector, count)
|
|
|
|
.then(done)
|
|
|
|
.catch(err => {
|
|
|
|
done(new Error(`.waitForNumberOfElements() for ${selector}, count ${count} timed out`));
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForClassNotPresent: function(selector, className, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.wait((selector, className) => {
|
|
|
|
if (!document.querySelector(selector).classList.contains(className))
|
|
|
|
return true;
|
|
|
|
}, selector, className)
|
|
|
|
.then(done)
|
|
|
|
.catch(() => {
|
|
|
|
done(new Error(`.waitForClassNotPresent() for ${selector}, class ${className} timed out`));
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForClassPresent: function(selector, className, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.wait((selector, className) => {
|
|
|
|
if (document.querySelector(selector).classList.contains(className))
|
|
|
|
return true;
|
|
|
|
}, selector, className)
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForTextInElement: function(selector, name, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.wait((selector, name) => {
|
|
|
|
return document.querySelector(selector).innerText.toLowerCase().includes(name.toLowerCase());
|
|
|
|
}, selector, name)
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForTextInInput: function(selector, name, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.wait((selector, name) => {
|
|
|
|
return document.querySelector(selector).value.toLowerCase().includes(name.toLowerCase());
|
|
|
|
}, selector, name)
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForInnerText: function(selector, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.wait(selector => {
|
|
|
|
const innerText = document.querySelector(selector).innerText;
|
|
|
|
return innerText != null && innerText != '';
|
|
|
|
}, selector)
|
|
|
|
.evaluate_now(selector => {
|
|
|
|
return document.querySelector(selector).innerText;
|
|
|
|
}, done, selector);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForEmptyInnerText: function(selector, done) {
|
|
|
|
this.wait(selector => {
|
|
|
|
return document.querySelector(selector).innerText == '';
|
2018-10-25 14:44:03 +00:00
|
|
|
}, selector)
|
2018-11-22 11:34:20 +00:00
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
2018-09-10 08:23:26 +00:00
|
|
|
|
2018-11-22 11:34:20 +00:00
|
|
|
waitForURL: function(hashURL, done) {
|
|
|
|
this.wait(hash => {
|
|
|
|
return document.location.hash.includes(hash);
|
|
|
|
}, hashURL)
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForShapes: function(selector, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.evaluate_now(selector => {
|
|
|
|
const shapes = document.querySelectorAll(selector);
|
|
|
|
const shapesList = [];
|
|
|
|
|
|
|
|
for (const shape of shapes)
|
|
|
|
shapesList.push(shape.innerText);
|
|
|
|
|
|
|
|
|
|
|
|
return shapesList;
|
|
|
|
}, done, selector);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForSnackbar: function(done) {
|
|
|
|
this.wait(500).waitForShapes('vn-snackbar .shape .text')
|
|
|
|
.then(shapes => {
|
|
|
|
done(null, shapes);
|
|
|
|
}).catch(done);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForLastShape: function(selector, done) {
|
|
|
|
this.wait(selector)
|
|
|
|
.evaluate_now(selector => {
|
|
|
|
const shape = document.querySelector(selector);
|
|
|
|
|
|
|
|
return shape.innerText;
|
|
|
|
}, done, selector);
|
|
|
|
},
|
|
|
|
|
|
|
|
waitForLastSnackbar: function(done) {
|
|
|
|
this.wait(500).waitForLastShape('vn-snackbar .shape .text')
|
|
|
|
.then(shapes => {
|
|
|
|
done(null, shapes);
|
|
|
|
}).catch(done);
|
2018-11-23 07:05:57 +00:00
|
|
|
},
|
|
|
|
|
2018-12-02 23:45:34 +00:00
|
|
|
accessToSearchResult: function(searchValue, done) {
|
|
|
|
this.wait(`vn-searchbar input`)
|
|
|
|
.type(`vn-searchbar input`, searchValue)
|
|
|
|
.click(`vn-searchbar vn-icon[icon="search"]`)
|
|
|
|
.evaluate(() => {
|
|
|
|
return document.querySelector('ui-view vn-card vn-table') != null;
|
|
|
|
})
|
|
|
|
.then(result => {
|
|
|
|
if (result)
|
|
|
|
return this.waitToClick('ui-view vn-card vn-td');
|
|
|
|
|
|
|
|
return this.waitToClick('ui-view vn-card a');
|
|
|
|
})
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
|
|
|
},
|
2018-11-23 07:05:57 +00:00
|
|
|
|
2018-12-02 23:45:34 +00:00
|
|
|
accessToSection: function(sectionRoute, done) {
|
|
|
|
this.wait(`vn-left-menu`)
|
|
|
|
.evaluate(sectionRoute => {
|
|
|
|
return document.querySelector(`vn-left-menu ul li ul li > a[ui-sref="${sectionRoute}"]`) != null;
|
|
|
|
}, sectionRoute)
|
|
|
|
.then(nested => {
|
|
|
|
if (!nested)
|
|
|
|
return this.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
|
|
|
|
|
|
|
|
return this.waitToClick('vn-left-menu .collapsed')
|
|
|
|
.wait('vn-left-menu .expanded')
|
|
|
|
.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
|
|
|
|
})
|
|
|
|
.then(done)
|
|
|
|
.catch(done);
|
2019-01-07 08:33:07 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
autocompleteSearch: function(autocompleteSelector, searchValue, done) {
|
|
|
|
this.wait(autocompleteSelector)
|
|
|
|
.waitToClick(`${autocompleteSelector} input`)
|
|
|
|
.type(`${autocompleteSelector} vn-drop-down input`, searchValue)
|
|
|
|
.waitToClick(`${autocompleteSelector} li.active`)
|
|
|
|
.wait((autocompleteSelector, searchValue) => {
|
|
|
|
return document.querySelector(`${autocompleteSelector} input`).value.toLowerCase().includes(searchValue.toLowerCase());
|
|
|
|
}, autocompleteSelector, searchValue)
|
|
|
|
.then(done)
|
|
|
|
.catch(() => {
|
|
|
|
done(new Error(`.autocompleteSearch() for ${autocompleteSelector}, timed out`));
|
|
|
|
});
|
2019-01-16 07:52:56 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
datePicker: function(datePickerSelector, changeMonth, done) {
|
|
|
|
this.wait(datePickerSelector)
|
|
|
|
.mousedown(datePickerSelector)
|
|
|
|
.wait('div.flatpickr-calendar.open');
|
|
|
|
if (changeMonth > 0)
|
|
|
|
this.mousedown('body > div > div.flatpickr-months > span.flatpickr-next-month > svg');
|
|
|
|
|
|
|
|
|
|
|
|
if (changeMonth < 0)
|
|
|
|
this.mousedown('body > div > div.flatpickr-months > span.flatpickr-prev-month > svg');
|
|
|
|
|
|
|
|
const daySelector = 'div.flatpickr-calendar.open span.flatpickr-day:nth-child(16)';
|
|
|
|
|
|
|
|
this.wait(selector => {
|
|
|
|
return document.querySelector(selector);
|
|
|
|
}, daySelector)
|
|
|
|
.evaluate(selector => {
|
|
|
|
let event = new MouseEvent('mousedown', {
|
|
|
|
bubbles: true,
|
|
|
|
cancelable: true,
|
|
|
|
view: window
|
|
|
|
});
|
|
|
|
document.querySelector(selector).dispatchEvent(event);
|
|
|
|
}, daySelector)
|
|
|
|
.then(done)
|
|
|
|
.catch(() => {
|
|
|
|
done(new Error(`.datePicker(), for ${daySelector} timed out`));
|
|
|
|
});
|
2018-12-02 23:45:34 +00:00
|
|
|
}
|
2018-11-22 11:34:20 +00:00
|
|
|
};
|
2018-09-10 08:23:26 +00:00
|
|
|
|
2018-11-22 11:34:20 +00:00
|
|
|
Object.keys(actions).forEach(function(name) {
|
|
|
|
let fn = actions[name];
|
|
|
|
Nightmare.action(name, fn);
|
2018-09-10 08:23:26 +00:00
|
|
|
});
|