test-automation-pack
Version:
framework for test automation using selenium with gherkin support
827 lines (752 loc) • 26.9 kB
JavaScript
/**
* http://usejsdoc.org/
*/
const { assert, expect } = require('chai');
const { until } = require('selenium-webdriver');
const jsonfile = require('jsonfile');
const { log } = require('debugging-logger');
const WebElement = require('./WebElement');
const {
getDriver,
activateTab,
closeTabAndSwitch,
getURL,
getTitle,
} = require('./driver');
const {
populateInput,
populateClick,
populateSelect,
populateRichTextField,
} = require('./populate');
const config = require('./config');
function PageObject(pageNameInput, pageNameDirectoryInput) {
const that = {};
that.pageName = pageNameInput;
that.pageDefinitionFileName = pageNameDirectoryInput + pageNameInput;
that.pageElements = new Map(); // a hash of all of the web elements for this page.
that.driver = getDriver();
const addElement = (elementName, elements) => that.pageElements.set(elementName, elements);
const getElement = async (elementName) => that.pageElements.get(elementName);
const hasElement = async (elementName) => that.pageElements.has(elementName);
const loadPageDefinitionFile = (fullFileName) => {
const elements = jsonfile.readFileSync(fullFileName);
Object.values(elements.webElements).forEach((element) => addElement(element.name, element));
};
const addDynamicElement = async (elementName, additionalDescription) => {
if (await hasElement(elementName)) {
if (typeof additionalDescription !== 'undefined') {
const newElementName = `${elementName} ${additionalDescription}`;
if (!(await hasElement(newElementName))) {
const dynamicElement = { ...(await getElement(elementName)) };
dynamicElement.name = newElementName;
dynamicElement.definition = dynamicElement.definition.replace(
'<ReplaceText>',
additionalDescription,
);
addElement(newElementName, dynamicElement);
}
return newElementName;
}
return elementName;
}
assert.fail(
`ERROR: WebElement ${elementName} not found in PageElements for adding dynamic element.`,
);
return elementName;
};
const genericAssertElement = async (elementName, value) => {
let retval;
let WebElementObject = '';
let WebElementData = {};
if (await hasElement(elementName)) {
WebElementData = await getElement(elementName);
// eslint-disable-next-line no-use-before-define
await switchFrame(WebElementData.frame);
WebElementObject = await WebElement(WebElementData);
const { implicit } = await getDriver().manage().getTimeouts();
switch (value.toLowerCase()) {
case 'notvisible':
case 'notdisplayed':
await getDriver().manage().setTimeouts({
implicit: 5000,
});
retval = await WebElementObject.elementDisplayed();
await getDriver().manage().setTimeouts({
implicit,
});
break;
case 'visible':
case 'displayed':
retval = await WebElementObject.elementDisplayed();
break;
case 'disabled':
retval = await WebElementObject.elementDisabled();
break;
case 'exists':
await getDriver().manage().setTimeouts({
implicit: 5000,
});
retval = await WebElementObject.getWebElements();
await getDriver().manage().setTimeouts({
implicit,
});
log.info(`Found ${retval.length} matching elements on page.`);
retval = retval.length > 0;
break;
default:
}
} else {
assert.fail(
`ERROR: WebElement ${elementName} not found in PageElements during AssertElement() attempt.`,
);
}
return retval;
};
const switchFrame = async (elementName) => {
await that.driver.switchTo().defaultContent();
if (elementName === 'default') {
// if frame name is default then see above
} else if (typeof elementName === 'number') {
log.debug(`Switching to frame number ${elementName}`);
await that.driver.wait(
until.ableToSwitchToFrame(elementName, config.timeout),
);
} else {
log.debug(`Switching to frame ${elementName}`);
if (await genericAssertElement(elementName, 'displayed')) {
const WebElementData = await getElement(elementName);
const WebElementObject = await WebElement(WebElementData);
const webElement = await WebElementObject.getWebElement();
await that.driver.wait(
until.ableToSwitchToFrame(webElement, config.timeout),
);
}
}
};
const genericPopulateElement = async (elementName, value) => {
let WebElementObject = '';
let WebElementData = {};
if (await hasElement(elementName)) {
WebElementData = await getElement(elementName);
const actionElement = {};
// Setup all underlying required objects to take action on for this action
actionElement.element = WebElementData;
// if (WebElementData && WebElementData.waitForElementToBeInvisible) {
// if (await hasElement(WebElementData.waitForElementToBeInvisible)) {
// const elementToWaitToBeInvisible = await getElement(WebElementData.waitForElementToBeInvisible);
// actionElement.elementToWaitToBeInvisible = elementToWaitToBeInvisible;
// }
// }
// if (WebElementData && WebElementData.waitToBeVisible) {
// if (await hasElement(WebElementData.waitToBeVisible)) {
// const waitToBeVisible = await getElement(WebElementData.waitToBeVisible);
// actionElement.waitToBeVisible = waitToBeVisible;
// }
// }
// If need to hit a iframe, do it
await switchFrame(WebElementData.frame);
WebElementObject = await WebElement(WebElementData);
actionElement.webElement = WebElementObject;
const webElement = await WebElementObject.getWebElement();
const tagName = await webElement.getTagName();
switch (tagName.toLowerCase()) {
case 'input':
case 'textarea':
if (value === 'click') {
await populateClick(webElement, value, actionElement);
} else {
await populateInput(webElement, value, actionElement);
}
break;
case 'a':
case 'button':
case 'div':
case 'span':
case 'ul':
case 'li':
case 'th':
case 'h2':
case 'section':
if (value === 'click') {
await populateClick(webElement, value, actionElement);
} else {
await populateRichTextField(webElement, value, actionElement);
}
break;
case 'svg':
if (value === 'click') {
await populateClick(webElement, value, actionElement);
} else {
await populateSelect(webElement, value, actionElement);
}
break;
case 'select':
case 'p':
await populateSelect(webElement, value, actionElement);
break;
case 'label':
case 'option':
await populateClick(webElement, value, actionElement);
break;
default:
assert.fail(`ERROR: We tried to populate an unknown tag(${tagName}) of
element(${elementName}) with data in populateGenericElement()\n\tWe failed.`);
}
} else {
assert.fail(
`ERROR: WebElement ${elementName} not found in PageElements during PopulateElement() attempt.`,
);
}
};
const genericPopulateDatable = async (table) => {
log.debug('I populated table');
const rows = table.raw();
const numberOfColumns = rows[0].length;
const numberOfRows = rows.length - 1;
for (let rowIndex = 1; rowIndex < numberOfRows; rowIndex += 1) {
for (
let columnIndex = 0;
columnIndex < numberOfColumns;
columnIndex += 1
) {
log.debug('TABLE: ', rows[0][columnIndex], rows[rowIndex][columnIndex]);
// eslint-disable-next-line no-await-in-loop
await genericPopulateElement(
rows[0][columnIndex],
rows[rowIndex][columnIndex],
);
}
}
};
const getWebElements = async (elementName, replaceText) => {
let elementList;
const element = await addDynamicElement(elementName, replaceText);
if (await hasElement(element)) {
let WebElementData = {};
WebElementData = await getElement(element);
await switchFrame(WebElementData.frame);
const WebElementObject = await WebElement(WebElementData);
elementList = await WebElementObject.getWebElements();
return elementList;
}
assert.fail(`Element ${element} not found.`);
return elementList;
};
// const generateDataTable = async (padLength) => {
// const localPadLength = padLength || 0;
// const _NA = '| NA'.padEnd(localPadLength + 1);
// console.log(`\nGenerating data table for ${that.pageName} \n`);
// try {
// // Return a | delimited list of the field names in the pageDefs file for this PageObject
// console.log(`|${that.pageElements.keyList('|', localPadLength)}`);
// // Generate a list of NA for the page object.
// let NAList = '';
// let i;
// const elementCount = that.pageElements.length;
// for (i = 0; i < elementCount; i++) {
// NAList += _NA;
// }
// console.log(`${NAList}|`);
// } catch (err) {
// log.error(err.stack);
// throw err;
// }
// };
// to be revisited
const scrollElementIntoView = async (elementName, replaceText) => {
let retval;
let WebElementObject = '';
let WebElementData = {};
const element = await addDynamicElement(elementName, replaceText);
log.debug(`Scrolling element: ${element} into view.`);
if (await hasElement(element)) {
WebElementData = await getElement(element);
const actionElement = {};
await switchFrame(WebElementData.frame);
WebElementObject = await WebElement(WebElementData);
actionElement.webElement = WebElementObject;
log.info(
`Info: Page Element ${element} retrieved from Page Elements collection for exists check.`,
);
return WebElementObject.scrollIntoView();
}
assert.fail(
`ERROR: WebElement ${element} not found in PageElements during scrollElementIntoView() attempt.`,
);
return retval;
};
const checkElementExists = async (elementName, replaceText) => {
const element = await addDynamicElement(elementName, replaceText);
if (await genericAssertElement(element, 'exists')) {
log.info(`Web Element ${element} is displayed on page.`);
return true;
}
log.info(`Web Element ${element} is not displayed on page.`);
return false;
};
const assertElementExists = async (elementName, replaceText) => {
const element = await addDynamicElement(elementName, replaceText);
if (await genericAssertElement(element, 'exists')) {
log.info(`Web Element ${element} is displayed on page. PASS`);
} else {
assert.fail(`Web Element ${element} is not displayed on page.`);
}
};
const assertElementDoesNotExist = async (elementName, replaceText) => {
const element = await addDynamicElement(elementName, replaceText);
if (await genericAssertElement(element, 'exists')) {
assert.fail(`Web Element ${element} is displayed on page.`);
} else {
log.info(`Web Element ${element} is not displayed on page. PASS`);
}
};
const assertElementDisabled = async (elementName, replaceText) => {
const element = await addDynamicElement(elementName, replaceText);
if (await genericAssertElement(element, 'disabled')) {
log.info(`Web Element ${element} is disabled. PASS`);
} else {
assert.fail(`Web Element ${element} is not disabled.`);
}
};
// to be revisited
const genericGetAttribute = async (elementName, attributeName) => {
let returnValue;
if (await hasElement(elementName)) {
let WebElementData = {};
WebElementData = await getElement(elementName);
await switchFrame(WebElementData.frame);
const WebElementObject = await WebElement(WebElementData);
const webElement = await WebElementObject.getWebElement();
if (attributeName === undefined) {
// eslint-disable-next-line no-param-reassign
attributeName = 'textContent';
}
if (attributeName.toLowerCase() === 'text') {
returnValue = await webElement.getText();
} else if (attributeName === 'selected') {
returnValue = await webElement.isSelected();
} else {
returnValue = await webElement.getAttribute(attributeName);
}
log.info(
`Attribute "${attributeName}" value for element "${elementName}" is "${returnValue}".`,
);
return returnValue;
}
assert.fail(
`ERROR: WebElement ${elementName} not found in PageElements during GetAttributeValue() attempt.`,
);
return returnValue;
};
const getAttributeValue = async (elementName, replaceText, attributeName) => {
if (attributeName === undefined && replaceText !== undefined) {
// eslint-disable-next-line no-param-reassign
attributeName = replaceText;
}
const element = await addDynamicElement(elementName, replaceText);
try {
return await genericGetAttribute(element, attributeName);
} catch (err) {
log.error(err.stack);
throw err;
}
};
const getText = async (elementName, replaceText) => {
const element = await addDynamicElement(elementName, replaceText);
try {
return await genericGetAttribute(element);
} catch (err) {
log.error(err.stack);
throw err;
}
};
const assertText = async (elementName, replaceText, expectedValue) => {
if (expectedValue === undefined && replaceText !== undefined) {
// eslint-disable-next-line no-param-reassign
expectedValue = replaceText;
}
const element = await addDynamicElement(elementName, replaceText);
try {
const actualValue = await genericGetAttribute(element);
log.info(`Asserting text for "${element}".`);
if (await expect(actualValue).to.equal(expectedValue)) {
log.info(
`Actual value "${actualValue}" equals Expected value "${expectedValue}". PASS`,
);
}
} catch (err) {
log.error(err.stack);
throw err;
}
};
const assertTextIncludes = async (
elementName,
replaceText,
expectedValue,
) => {
if (expectedValue === undefined && replaceText !== undefined) {
// eslint-disable-next-line no-param-reassign
expectedValue = replaceText;
}
const element = await addDynamicElement(elementName, replaceText);
try {
const actualValue = await genericGetAttribute(element);
log.info(`Asserting text for "${element}".`);
if (await expect(actualValue).to.include(expectedValue)) {
log.info(
`Actual value "${actualValue}" includes Expected value "${expectedValue}". PASS`,
);
}
} catch (err) {
log.error(err.stack);
throw err;
}
};
const assertTextDoesNotInclude = async (
elementName,
replaceText,
expectedValue,
) => {
if (expectedValue === undefined && replaceText !== undefined) {
// eslint-disable-next-line no-param-reassign
expectedValue = replaceText;
}
const element = await addDynamicElement(elementName, replaceText);
try {
const actualValue = await genericGetAttribute(element);
log.info(`Asserting text for "${element}" does not exist`);
if (await expect(actualValue).to.not.include(expectedValue)) {
log.info(
`Actual value "${actualValue}" includes Expected value "${expectedValue}". PASS`,
);
}
} catch (err) {
log.error(err.stack);
throw err;
}
};
const genericWaitForElement = async (elementName, condition, timeout) => {
let WebElementObject = '';
let WebElementData = {};
let retval;
if (await hasElement(elementName)) {
WebElementData = await getElement(elementName);
await switchFrame(WebElementData.frame);
WebElementObject = await WebElement(WebElementData);
switch (condition.toLowerCase()) {
case 'visibility':
retval = await WebElementObject.waitForVisibility(timeout);
break;
case 'invisibility':
retval = await WebElementObject.waitForInvisibility(timeout);
break;
default:
assert.fail(`Only visibility and invisibility suppoorted.
${condition} kind of wait is not defined.`);
}
} else {
assert.fail(
`ERROR: WebElement ${elementName} not found in PageElements during WaitForElement() attempt.`,
);
}
return retval;
};
const waitForElementVisibility = async (
elementName,
replaceText,
timeoutInSeconds,
) => {
const element = await addDynamicElement(elementName, replaceText);
const timeout = timeoutInSeconds || 120;
if (await genericWaitForElement(element, 'visibility', timeout)) {
log.info(`Web Element ${element} is visible on page. PASS`);
} else {
assert.fail(
`Web Element ${element} is not visible on page after ${timeout} second wait. FAIL`,
);
}
};
const waitForElementInvisibility = async (
elementName,
replaceText,
timeoutInSeconds,
) => {
const element = await addDynamicElement(elementName, replaceText);
const timeout = timeoutInSeconds || 120;
if (await genericWaitForElement(element, 'invisibility', timeout)) {
log.info(`Web Element ${element} is not visible on page. PASS`);
} else {
assert.fail(
`Web Element ${element} is visible on page after ${timeout} second wait. FAIL`,
);
}
};
const populateElement = async (elementName, replaceText, strValue) => {
if (strValue === undefined && replaceText !== undefined) {
// eslint-disable-next-line no-param-reassign
strValue = replaceText;
}
const element = await addDynamicElement(elementName, replaceText);
try {
log.info(
`Starting populate the web element: ${element} with value ${strValue}`,
);
await genericPopulateElement(element, strValue);
} catch (err) {
log.error(err.stack);
throw err;
}
};
const clickElement = async (elementName, replaceText) => {
const element = await addDynamicElement(elementName, replaceText);
try {
log.info(`Starting click the web element: ${element}`);
await genericPopulateElement(element, 'click');
} catch (err) {
log.error(err.stack);
throw err;
}
};
const switchToTab = async (tabName) => {
try {
log.debug(`Switching to tab : ${tabName}`);
if (!(await activateTab(tabName))) {
assert.fail(`${tabName} tab was not found. FAIL`);
}
} catch (err) {
log.error(err.stack);
throw err;
}
};
const closeTab = async (tabName) => {
try {
log.debug(`Closing tab : ${tabName}`);
await closeTabAndSwitch(tabName);
} catch (err) {
log.error(err.stack);
throw err;
}
};
const getCurrentURL = async () => {
try {
log.debug('Getting URL of the current tab.');
return await getURL();
} catch (err) {
log.error(err.stack);
throw err;
}
};
const getPageTitle = async () => {
try {
log.debug('Getting the title of the current tab.');
return await getTitle();
} catch (err) {
log.error(err.stack);
throw err;
}
};
const assertPageTitle = async (expectedValue) => {
try {
const actualValue = await getPageTitle();
log.info('Asserting page title match for current tab.');
if (await expect(actualValue).to.equal(expectedValue)) {
log.info(
`Actual value "${actualValue}" equals Expected value "${expectedValue}". PASS`,
);
}
} catch (err) {
log.error(err.stack);
throw err;
}
};
const assertPageTitleIncludes = async (expectedValue) => {
try {
const actualValue = await getPageTitle();
log.info('Asserting page title partial match for current tab.');
if (await expect(actualValue).to.include(expectedValue)) {
log.info(
`Actual value "${actualValue}" includes Expected value "${expectedValue}". PASS`,
);
}
} catch (err) {
log.error(err.stack);
throw err;
}
};
const genericAlertOperations = async (operation) => {
let retval;
if (await that.driver.wait(until.alertIsPresent())) {
const alert = that.driver.switchTo().alert();
switch (operation.toLowerCase()) {
case 'accept':
retval = await alert.accept();
break;
case 'dismiss':
retval = await alert.dismiss();
break;
case 'text':
retval = alert.getText();
break;
default:
assert.fail(
`ERROR: ${operation} is not implemented in genericAlertOperations().`,
);
}
} else {
assert.fail('ERROR: Assert pop up was not displayed.');
}
return retval;
};
const acceptAlert = async () => {
await genericAlertOperations('accept');
log.info('Accepted alert popup.');
};
const dismissAlert = async () => {
await genericAlertOperations('dismiss');
log.info('Dismissed alert popup.');
};
const getAlertText = async () => {
log.debug('Getting text in alert popup.');
const actualValue = await genericAlertOperations('text');
log.info(`${actualValue} is displayed in the alert popup.`);
return actualValue;
};
const assertAlertText = async (expectedValue) => {
log.debug('Asserting text in alert popup.');
const actualValue = await genericAlertOperations('text');
if (actualValue === expectedValue) {
log.info(
`Actual value "${actualValue}" matches Expected value "${expectedValue}". PASS`,
);
} else {
assert.fail(
`Actual value "${actualValue}" does not match Expected value "${expectedValue}". FAIL`,
);
}
};
const assertAlertTextIncludes = async (expectedValue) => {
log.debug('Asserting text in alert popup.');
const actualValue = await genericAlertOperations('text');
if (actualValue.includes(expectedValue)) {
log.info(
`Actual value "${actualValue}" includes Expected value "${expectedValue}". PASS`,
);
} else {
assert.fail(
`Actual value "${actualValue}" does not include Expected value "${expectedValue}". FAIL`,
);
}
};
const dragAndDrop = async (
dragElementName,
dropElementName,
dragReplaceText,
dropReplaceText,
) => {
let From;
let To;
let WebElementObject = '';
let WebElementData = {};
const fromElementName = await addDynamicElement(
dragElementName,
dragReplaceText,
);
if (await genericAssertElement(fromElementName, 'displayed')) {
log.info(
`Target Web Element "${fromElementName}" is displayed on page. PASS`,
);
} else {
assert.fail(
`Target Web Element "${fromElementName}" is not displayed on page.`,
);
}
if (await hasElement(fromElementName)) {
WebElementData = await getElement(fromElementName);
await switchFrame(WebElementData.frame);
WebElementObject = await WebElement(WebElementData);
await WebElementObject.scrollIntoView();
From = await WebElementObject.getWebElement();
}
const toElementName = await addDynamicElement(
dropElementName,
dropReplaceText,
);
if (await genericAssertElement(toElementName, 'displayed')) {
log.info(
`Destination Web Element "${toElementName}" is displayed on page. PASS`,
);
} else {
assert.fail(
`Destination Web Element "${toElementName}" is not displayed on page.`,
);
}
if (await hasElement(toElementName)) {
WebElementData = await getElement(toElementName);
await switchFrame(WebElementData.frame);
WebElementObject = await WebElement(WebElementData);
await WebElementObject.scrollIntoView();
To = await WebElementObject.getWebElement();
}
try {
const actions = getDriver().actions({ bridge: true });
await actions.dragAndDrop(From, To).perform();
log.debug(
`Dropped element "${fromElementName}" on element "${toElementName}". PASS`,
);
} catch (err) {
assert.fail(
`Unable to perform drag and drop operation due to error. FAIL. Error ${err}`,
);
}
};
const waitClick = async (elementName, replaceText, timeoutInSeconds) => {
await waitForElementVisibility(elementName, replaceText, timeoutInSeconds);
await clickElement(elementName, replaceText);
};
const waitPopulate = async (elementName, replaceText, timeoutInSeconds) => {
await waitForElementVisibility(elementName, replaceText, timeoutInSeconds);
await populateElement(elementName, replaceText);
};
that.acceptAlert = acceptAlert;
that.dismissAlert = dismissAlert;
that.getAlertText = getAlertText;
that.assertAlertText = assertAlertText;
that.assertAlertTextIncludes = assertAlertTextIncludes;
that.assertText = assertText;
that.assertTextIncludes = assertTextIncludes;
that.assertTextDoesNotInclude = assertTextDoesNotInclude;
that.assertElementDisabled = assertElementDisabled;
that.getElement = getElement;
that.hasElement = hasElement;
that.getDriver = getDriver;
that.populate = populateElement;
that.waitPopulate = waitPopulate;
that.click = clickElement;
that.waitClick = waitClick;
that.getAttributeValue = getAttributeValue;
that.populateFromDataTable = genericPopulateDatable;
that.populateDatatable = genericPopulateDatable;
that.checkElementExists = checkElementExists;
that.assertElementExists = assertElementExists;
that.assertElementDoesNotExist = assertElementDoesNotExist;
that.getWebElements = getWebElements;
// that.generateDataTable = generateDataTable;
that.scrollElementIntoView = scrollElementIntoView;
that.getText = getText;
that.switchToTab = switchToTab;
that.closeTab = closeTab;
that.getCurrentURL = getCurrentURL;
that.getPageTitle = getPageTitle;
that.assertPageTitle = assertPageTitle;
that.assertPageTitleIncludes = assertPageTitleIncludes;
that.addDynamicElement = addDynamicElement;
that.waitForElementVisibility = waitForElementVisibility;
that.waitForElementInvisibility = waitForElementInvisibility;
that.dragAndDrop = dragAndDrop;
loadPageDefinitionFile(that.pageDefinitionFileName);
return that;
}
module.exports = {
PageObject,
};