Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added waitForPageToLoad function #57

Merged
merged 45 commits into from
Mar 25, 2018
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e0113a3
More code cleaning
Marketionist Mar 11, 2018
2cad97b
Added waitForLoaded function
Marketionist Mar 11, 2018
15b4188
Refactored wdio.conf.js to use steps.conf.js
Marketionist Mar 11, 2018
13ab29a
Added 'I click' step and test
Marketionist Mar 11, 2018
377ee6f
Renamed waitForPageToLoad()
Marketionist Mar 13, 2018
5e3c0e9
Refactored stepsConfig for global usage
Marketionist Mar 14, 2018
e323c9b
Fixed mocha tests to include stepsConfig
Marketionist Mar 14, 2018
5d262b4
We should not ignore .vscode/settings.json file
alexkrechik Mar 17, 2018
2942a0b
Fixed finishedLoadingConditions function
alexkrechik Mar 17, 2018
fa124c4
Fixed I click ${pageObject}$ method
alexkrechik Mar 17, 2018
0828574
Attempt to add .vscode folder
alexkrechik Mar 17, 2018
7cb8cd9
Added vscode settings.json file
alexkrechik Mar 17, 2018
9bb36e3
Removed unnecessary waiter in the end of feature
alexkrechik Mar 18, 2018
7a127c2
Separate steps config logic and values provided.
alexkrechik Mar 18, 2018
c0d1f18
Apply commands via applyStepsCommands function
alexkrechik Mar 18, 2018
81bbe4e
Using of config finishedLoadingConditions
alexkrechik Mar 18, 2018
46c7cc9
Using of const were possible
alexkrechik Mar 18, 2018
d1fed7e
Using Class for Id. Fixed mocha tests.
alexkrechik Mar 18, 2018
21ce939
Some fixes due to Dima's review
alexkrechik Mar 18, 2018
475207b
Use ecmaVersion: 2017 for linting
Marketionist Mar 20, 2018
bfdd711
Refactored 'I click' step to use async await
Marketionist Mar 20, 2018
32073a5
Switched to node.js 7 to use async await
Marketionist Mar 20, 2018
ad08727
Updated tests to be more descriptive
Marketionist Mar 20, 2018
09d9d3b
Refactored When steps to use async await
Marketionist Mar 20, 2018
fd00403
Refactored Then steps to use async await
Marketionist Mar 20, 2018
0e4594a
Refactored Given steps to use async await
Marketionist Mar 20, 2018
c535e88
Added moveToObject for click
Marketionist Mar 20, 2018
032f67e
Added 'I doubleclick' step
Marketionist Mar 20, 2018
8fe45b3
Used scroll and 2 clicks for steps with clicks
Marketionist Mar 21, 2018
a6d411a
Bumped up wdio-cucumber-framework: ^1.1.0, wdio-selenium-standalone-s…
Marketionist Mar 21, 2018
07437d0
Added checkbox with some js for tests
Marketionist Mar 21, 2018
493fab5
Added tests for 'I click', 'I doubleclick' steps
Marketionist Mar 21, 2018
d551cbd
Updated new-page with text block for doubleclick
Marketionist Mar 21, 2018
9b9cbff
Returned to moveToObject and doubleClick as it is not depricated
Marketionist Mar 21, 2018
e53491e
Updated tests for click and doubleclick
Marketionist Mar 21, 2018
d0b0266
Added loaders to new-page
Marketionist Mar 22, 2018
f906ad9
Added loaders scripts, styles, images
Marketionist Mar 22, 2018
297edb9
Added tests for waitForPageToLoad
Marketionist Mar 22, 2018
96bfce4
Used executeAsync in waitForPageToLoad
Marketionist Mar 22, 2018
3883fac
Added promise to waitForPageToLoad
Marketionist Mar 23, 2018
352a59b
Added loadingFinished
Marketionist Mar 23, 2018
821262f
Refactored defaultFinishedLoadingConditions
Marketionist Mar 24, 2018
c6f9593
Fixed loaderSelectore visibility issues.
alexkrechik Mar 25, 2018
61bc704
Fixed defaultFinishedLoadingConditions returnvalue
alexkrechik Mar 25, 2018
069847e
Fixed waitForPageToLoad function
alexkrechik Mar 25, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ node_modules
!.travis.yml
!.editorconfig
!.eslintrc.*
!.vscode
*.xml
.settings
downloads
*~
.idea
.vscode
errorShots/
23 changes: 23 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"cucumberautocomplete.steps": [
"src/steps/*.js"
],
"cucumberautocomplete.syncfeatures": "test/features/*feature",
"cucumberautocomplete.strictGherkinCompletion": true,
"cucumberautocomplete.smartSnippets": true,
"cucumberautocomplete.stepsInvariants": true,
"cucumberautocomplete.customParameters": [
{
"parameter":"(_r(",
"value":"("
},
{
"parameter":"${dictionaryObject}",
"value":"([a-zA-Z0-9_-]+ from [a-zA-Z0-9_-]+ dictionary|\"[^\"]*\")"
},
{
"parameter":"${pageObject}",
"value":"([a-zA-Z0-9_-]+ from [a-zA-Z0-9_-]+ page)"
}
],
}
5 changes: 5 additions & 0 deletions src/commands/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const waitForPageToLoad = require('./wait.for.page.to.load');

module.exports = function applyCommands () {
browser.addCommand('waitForPageToLoad', waitForPageToLoad);
};
25 changes: 25 additions & 0 deletions src/commands/wait.for.page.to.load.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* global stepsConfig */

module.exports = function waitForPageToLoad (callback) {
/**
* Wait for page to get fully loaded
* @param {callback} callback - A callback to run
*/
const timeout = 100;
const finishedLoadingConditions = stepsConfig.finishedLoadingConditions;

// If loading of the page was finished - launch callback function
// TODO - add some waiter here
if (finishedLoadingConditions()) {
callback();
}

// If loading of the page was not finished - relaunch finishedLoadingConditions() each 100 ms
const interval = setInterval(function () {
if (finishedLoadingConditions()) {
clearInterval(interval);
callback();
}
}, timeout);

};
27 changes: 14 additions & 13 deletions src/helpers/objects.processor.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint no-param-reassign: 0 */
/* eslint no-undef: 0 */
/* global stepsConfig */

const { _r } = require('./utils');

Expand All @@ -16,17 +17,17 @@ const dictionaryObjectsParts = '^(?:([a-zA-Z0-9_-]+) from ([a-zA-Z0-9_-]+) dicti
// Todo do we need this in csp-qa
function injectInto (locator, injection) {
const lastInjectionSymbol = injection.slice(-1);
const lastLocatorSumbol = locator.slice(-1);
const lastLocatorSymbol = locator.slice(-1);

if (lastInjectionSymbol !== ']') {
// Add ']' to the end of injection only if missing (for backward compatibility)
injection += ']';
}
if (lastLocatorSumbol === ')') {
if (lastLocatorSymbol === ')') {
// If our locator ends with round brackets
return injectInto(locator.replace(/\)$/, ''), injection) + ')';
}
if (lastLocatorSumbol === ']') {
if (lastLocatorSymbol === ']') {
if (locator.match(/\[[0-9]+\]$/)) {
// Locator ends with brackets, which contains some xpath num
const nums = locator.match(/\[[0-9]+\]$/)[0];
Expand All @@ -49,21 +50,21 @@ function pageObjectGetter (str) {
const page = match[2];
const object = match[1];

if (!pages[page]) {
if (!stepsConfig.pages[page]) {
throw new Error(`"${page}" page is missing`);
}
if (!pages[page][object]) {
if (!stepsConfig.pages[page][object]) {
throw new Error(`"${object}" page object is missing for the "${page}" page`);
}
return pages[page][object];
return stepsConfig.pages[page][object];
}
throw new Error(`Unknown Page Object type for "${str}"`);
}

function getPageObject (str) {
const pageObjectGetterFunc = objectsProcessor.pageObjectGetter || pageObjectGetter;
const pageObjectGetterFunc = stepsConfig.objectsProcessor.pageObjectGetter || pageObjectGetter;
const value = pageObjectGetterFunc(str);
const idValue = value.replace(_r(regDynamicId, 'g'), id.getId());
const idValue = value.replace(_r(regDynamicId, 'g'), stepsConfig.id.getId());
const injection = `not(ancestor-or-self::*[contains(@style,"visibility: hidden;")
or contains(@style,"display: none") or contains(@class,"x-hide-offsets")])`;
const injectedValue = injectInto(idValue, injection);
Expand All @@ -81,13 +82,13 @@ function dictionaryGetter (str) {
const dictionary = match[2];
const object = match[1];

if (!pages[dictionary]) {
if (!stepsConfig.pages[dictionary]) {
throw new Error(`"${dictionary}" page is missing`);
}
if (!pages[dictionary][object]) {
if (!stepsConfig.pages[dictionary][object]) {
throw new Error(`"${object}" page object is missing for the "${dictionary}" page`);
}
return pages[dictionary][object];
return stepsConfig.pages[dictionary][object];
}
if (match[3] !== undefined) {
return match[3];
Expand All @@ -96,9 +97,9 @@ function dictionaryGetter (str) {
}

function getDictionaryObject (str) {
const dictionaryGetterFunc = objectsProcessor.dictionaryGetter || dictionaryGetter;
const dictionaryGetterFunc = stepsConfig.objectsProcessor.dictionaryGetter || dictionaryGetter;
const value = dictionaryGetterFunc(str);
const idValue = value.replace(_r(regDynamicId, 'g'), id.getId());
const idValue = value.replace(_r(regDynamicId, 'g'), stepsConfig.id.getId());

return idValue;
}
Expand Down
36 changes: 36 additions & 0 deletions src/steps.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const defaultFinishedLoadingConditions = (loaderSelectors) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should rename this file to something like steps.helper.functions.js (because it looks more like a file with logic then config and we also have a second file with the same name in test/steps.conf.js - and it looks like a real config file more)?

// Check if jQuery is present on the page and if any XMLHttpRequests (AJAX) are in progress
if (typeof $ !== 'undefined' && $.active) {
return false;
}

// Check if any loaders are still present on the page
return !loaderSelectors.some((selector) => browser.execute((s) => document.querySelector(s), selector));
};

const defaultIdGenerator = () => (new Date()).getTime();

module.exports = function ({
loaderSelectors = [], // <string>[] - array of xpath selectors, that will be used by finishedLoadingConditions.
finishedLoadingConditions = defaultFinishedLoadingConditions, // <(loaderSelectors) => <boolean>>.
pages = {}, // <{[key: string]: {[key: string]: <string>}}> - object, that contains "key" -> "Page object" pairs.
defaultIdValue = '', // Default value of steps config Id.
idGenerator = defaultIdGenerator, // <() => <string|number>> - function, that will return new generated id.
objectsProcessor = {} // objectsProcessor childs could be previded here - see objects.processor.js for more details.
}) {
const id = {
value: defaultIdValue || idGenerator.call(this),
getId: () => this.value,
regenerate: () => {
this.value = idGenerator.call(this);
}
};

return {
loaderSelectors,
finishedLoadingConditions: finishedLoadingConditions.bind(this, loaderSelectors),
pages,
id,
objectsProcessor
};
};
17 changes: 15 additions & 2 deletions src/steps/when.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
/* eslint new-cap: 0 */

const { defineSupportCode } = require('cucumber');
const { dictionaryObject, getDictionaryObject } = require('../helpers/objects.processor');
const { pageObject, getPageObject, dictionaryObject, getDictionaryObject } = require('../helpers/objects.processor');
const { _r, getInteger } = require('../helpers/utils');


module.exports = function () {
defineSupportCode(({ When }) => {

When(_r(`I click ${pageObject}$`), (element) => {
/**
* Click on the element
* @param {pageObject} element - String or "page"."object" to select the element
*/
const locator = getPageObject(element);
const el = $(locator);

// TODO - using of chain here ??
el.waitForExist();
el.waitForPageToLoad();
el.click();
});

When(_r(`I wait ${dictionaryObject} ms$`), (timeObject) => {
/**
* Wait for specified amount of milliseconds
Expand Down
2 changes: 1 addition & 1 deletion test/features/dictionary_objects/values.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
let e = {};
const e = {};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This object is being changed in the next line, so it looks like it should be let instead of const

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is still better to use let here, because this object is being changed in the next line (adding property)?


e.txtTimeout = '500';

Expand Down
2 changes: 1 addition & 1 deletion test/features/page_objects/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
let e = {};
const e = {};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This object is being changed (extended with additional properties) in the next 2 lines, so it looks like it should be let instead of const

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is still better to use let here, because this object is being changed in the next line (adding property)?


e.txtHeader = '//*[@id="header"]';
e.txtNewHeader = '//*[@id="new-header"]';
Expand Down
6 changes: 5 additions & 1 deletion test/features/show.hide.timeout.feature
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ Feature: Present / Not present
Then txtHeader from main page should be present
Then I wait txtTimeout from values dictionary ms
Then divTimeout from main page should not be present
Then txtHeader from main page should be present
Then txtHeader from main page should be present

Scenario: I click step should click on the element
Given I open "http://localhost:9000"
Then I click txtHeader from main page
1 change: 0 additions & 1 deletion test/features/window.tab.manipulation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,3 @@ Feature: Window/tab
When I open new window
When I close current tab
Then txtHeader from main page should be present

7 changes: 5 additions & 2 deletions test/mocha/objects.processor.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ const { _r } = require('../../src/helpers/utils');

const realId = 12345;

global.pages = {
// Makes stepsConfig visible globally to use stepsConfig.pages, stepsConfig.id, stepsConfig.loaderSelectors
global.stepsConfig = {};

global.stepsConfig.pages = {
main: {
object: `//div[@id='${dynamicId}']`
},
Expand All @@ -21,7 +24,7 @@ global.pages = {
}
};

global.id = {
global.stepsConfig.id = {
getId: () => realId
};

Expand Down
16 changes: 16 additions & 0 deletions test/steps.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Array of selectors for loaders that appear when page is loaded or XHR/AJAX requests are done
const loaderSelectors = [
'div:not([style*="display: none"])[class*="test-loader"]',
'div:not([style*="visibility: hidden"])[class*="test-loader"]'
];

// Object that contains pathes to all page objects used for tests
const pages = {
main: require('./features/page_objects/main'),
values: require('./features/dictionary_objects/values')
};

module.exports = {
loaderSelectors,
pages
};
18 changes: 8 additions & 10 deletions test/wdio.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,18 +192,16 @@ exports.config = {
global.assert = chai.assert;
global.should = chai.should();

global.pages = {
main: require('./features/page_objects/main'),
values: require('./features/dictionary_objects/values')
};
// Makes stepsConfig visible globally to use stepsConfig vars
const stepsConfigGenerator = require('../src/steps.conf.js');
const stepsConfigPresets = require('./steps.conf.js');

global.id = {
value: '',
regenerate: () => this.value === (new Date()).getTime(),
getId: () => this.value
};
global.stepsConfig = stepsConfigGenerator(stepsConfigPresets);

global.objectsProcessor = {};
// Adds browser.waitForPageToLoad() command to wait for page to get fully loaded
const applyStepsCommands = require('../src/commands');

applyStepsCommands();

}
/**
Expand Down