Mink: wait for page to load in #BeforeStep - selenium

I want to execute some javascript on page in #BeforeStep hook that depends on jQuery. However jQuery is not defined at that time, in fact page is blank.
Here's what I am trying to achive:
/**
* #BeforeStep #javascript
*/
public function registerAjaxEventHandlers()
{
$javascript = <<<JS
window.jQuery(document).ready(function () {
if (window.__ajaxStatus !== undefined) {
return;
}
window.__ajaxStatus = 'none';
$('body').ajaxStop(function() {
window.__ajaxStatus = 'idle';
});
$('body').ajaxStart(function() {
window.__ajaxStatus = 'in-flight';
});
});
JS;
//$this->getSession()->wait(5000, 'window.jQuery !== undefined');
$this->getSession()->executeScript($javascript);
}
I figured maybe I could wait for the page to load jQuery first (commented line), but it is not true. Seems like execution is halted until that hook is processed.
What is the right place in behat/mink ecosystem to execute javascript on page?

How about this?
$this->getSession()->wait(5000, 'typeof window.jQuery == "function"');

Your javascript is execute before the step, i.e. before the page is loaded. But if you load a page, all kinds of ondomload/pageload JavaScript will be firing already as well.
If you are happy to run it after the initial page, you can use #AfterStep like this:
/**
* #AfterStep
*/
public function set_selenium_css_selector (Behat\Behat\Event\StepEvent $event) {
$this->getSession()->wait(10, 'jQuery ("body").addClass ("selenium")');
}

Related

Nuxt add parameters without page and without reload the page

I have a page with big list of data and some buttons for filtering.
for example 2 buttons to filter by status:
Complete status
Cancel status
I want when the user clicked on the complete the url to be changed to
http://demo.com/list?filter=complete
the page does not reloading, it just for get specific url foreach filter button.
How can I implement the code in Nuxt application?
You cannot use $route or $router to change url, it set a new html5 history state and reload the page. So, to change url without reloading, history.replaceState do the job. In your page or component:
methods: {
onClickComplete() {
if (!process.server) { // I'm not sure it's necessary
history.replaceState({}, null, window.location + '?filter=complete') // or use your own application logic: globalSiteUrl, $route... or queryString some vars...
}
}
}
At first you should change your route with "$route.push" or click on
these ways change the route without reloading
After than you can use "pages watchquery" to handle event of changing route
https://nuxtjs.org/api/pages-watchquery/
first create this helper function
export function getAbsoluteUrl(to) {
const path = $nuxt.$router.resolve(to).href
return window.location.origin + path
}
this is example for my tabs
watch: {
tab(value) {
if (!process.server) {
const url = getAbsoluteUrl({
params: { ...this.$route.params, activeTab: value }
})
history.replaceState({}, null, url) // or use your own application logic: globalSiteUrl, $route... or queryString some vars...
}
}
},

Ionic 3 infinite-scroll simulate in e2e test jasmine/protractor

If you go here: http://ionicframework.com/docs/api/components/infinite-scroll/InfiniteScroll/
Inspect the demo and click the last item on the list:
Then in the console type: $0.scrollIntoView()
Infinite Scroll is never triggered.
Is there a way to programmatically trigger infinite-scroll in protractor context?
The implementation of the scroll in your example rely on the speed/velocity of the scroll which I guess falls far from the expected range when scrollIntoView is called.
One workaround is to simulates a smooth scroll by emitting multiple scroll events over a reasonable time. The idea is to reproduce as close as possible the behavior of a real user.
Some browsers already provides the option via scrollIntoView (supported by Chrome 62) :
$0.scrollIntoView({behavior: "smooth", block: "end"});
Using the accepted answer, in my case, I used ion-infinite-scroll as the argument.
Complete test to check if more content is loaded in Ionic:
describe('Scroll', () => {
it('should load more when reached end', async () => {
let list = getList();
let currentCount = await list.count();
const refresher = element(by.tagName('ion-infinite-scroll')).getWebElement();
let count = 0;
while(true){
browser.executeScript(`arguments[0].scrollIntoView({behavior: "smooth", block: "end"});`, refresher);
browser.sleep(1000); // wait for data to be loaded from api
list = getList();
let newCount = await list.count();
expect(newCount).toBeGreaterThanOrEqual(currentCount)
expect(newCount).toBeLessThanOrEqual(currentCount * 2)
if(newCount === currentCount){
break;
}
currentCount = newCount;
count++;
}
expect(count).toBeGreaterThan(0);
})
});
function getList() {
return element(by.className(pageId + ' list')).all(by.tagName('ion-item'));
}

Wait until page is fully loaded with selenium and intern js

I am trying to create a UI automation test with intern js , but i m getting problem on waiting until the page is fully loaded. My code starts searching for element before the page is loaded. Can some one help me on this.
My code:
define([
'intern!object',
'intern/chai!assert',
'Automation/ConfigFiles/dataurl',
'Automation/pages/login/loginpage',
'intern/dojo/node!fs',
'intern/dojo/node!leadfoot/helpers/pollUntil'
], function (registerSuite, assert,dataurl, LoginPage,fs,pollUntil) {
registerSuite(function () {
var loginPage;
var values;
return {
setup: function () {
var data = fs.readFileSync(loginpage, 'utf8');
json=JSON.parse(data);
console.log('###########Setting Up Login Page Test##########')
this.remote
.get(require.toUrl(json.locator.URL))
.then(pollUntil(this.remote.findById('uname').isDisplayed(),6000)// here i want to wait until page is loaded
.waitForDeletedByClassName('loading').end().sleep(600000)// here i want to wait until loading component is disappered
values = json.values;
loginPage = new LoginPage(this.remote,json.locator);
},
'successful login': function () {
console.log('##############Login Success Test############')
return loginPage
.login(values.unamevalue,values.pwdvalue)
},
// …additional tests…
};
});
});
I m trying to use pollUntil . But I m not sure weather I should use it or not.
pollUntil is a good thing to use here, but it doesn't look like you're actually waiting for polling to finish. Your setup method needs to return the command chain that includes pollUntil so that Intern will know it needs to wait, something like:
var setupPromise = this.remote
.get(require.toUrl(json.locator.URL))...
values = json.values;
loginPage = new LoginPage(this.remote, json.locator);
return setupPromise;
Alternatively, you could pass your LoginPage class the chain:
var setupPromise = this.remote
.get(require.toUrl(json.locator.URL))...
values = json.values;
loginPage = new LoginPage(setupPromise, json.locator);
In this case Intern won't wait for setup to complete, but your LoginPage code will implicitly wait for the setupPromise to complete before doing anything else. While this will work, the intent isn't as clear as in the previous example (e.g., that Intern should wait for some setup process to complete before proceeding).

How to use callbacks in phantomjs

I am using phantomjs for testing one web application. but i am facing problem with page load means sometimes phantom script executed but dom element is not loaded. How to use callbacks for sorting this kind of issues
resourceReceived(request),resourceRequested(resource),resourceError(resource)
If you want to execute code after the page has finished loading, use this:
page.onLoadFinished = function()
{
// function body
var pageTitle = page.evaluate(function() {
console.log('Page Name: ' + document.title);
return document.title;
});
};

Yii renderpartial (proccessoutput = true) Avoid Duplicate js request

Im creating a site who works with ajaxRequest, when I click a link, it will load using ajaxRequest. When I load for example user/login UserController actionLogin, I renderPartial the view with processOUtput to true so the js needed inside that view will be generated, however if I have clientScriptRegister inside that view with events, how can I avoid to generate the scriptRegistered twice or multiple depending on the ajaxRequest? I have tried Yii::app()->clientScript->isSCriptRegistered('scriptId') to check if the script is already registered but it seems that if you used ajaxRequest, the result is always false because it will only be true after the render is finished.
Controller code
if (Yii::app()->request->isAjaxRequest)
{
$this->renderPartial('view',array('model'=>$model),false,true);
}
View Code
if (!Yii::app()->clientScript->isScriptregistered("view-script"))
Yii::app()->clientScript->registerScript("view-script","
$('.link').live('click',function(){
alert('test');
})
");
If I request for the controller for the first time, it works perfectly (alert 1 time) but if I request again for that same controller without refreshing my page and just using ajaxRequest, the alert will output twice if you click it (because it keeps on generating eventhough you already registered it once)
This is the same if you have CActiveForm inside the view with jquery functionality.. the corescript yiiactiveform will be called everytime you renderPartial.
To avoid including core scripts twice
If your scripts have already been included through an earlier request, use this to avoid including them again:
// For jQuery core, Yii switches between the human-readable and minified
// versions based on DEBUG status; so make sure to catch both of them
Yii::app()->clientScript->scriptMap['jquery.js'] = false;
Yii::app()->clientScript->scriptMap['jquery.min.js'] = false;
If you have views that are being rendered both independently and as HTML fragments to be included with AJAX, you can wrap this inside if (Yii::app()->request->isAjaxRequest) to cover all bases.
To avoid including jQuery scripts twice (JS solution)
There's also the possibility of preventing scripts from being included twice on the client side. This is not directly supported and slightly more cumbersome, but in practice it works fine and it does not require you to know on the server side what's going on at the client side (i.e. which scripts have been already included).
The idea is to get the HTML from the server and simply strip out the <script> tags with regular expression replace. The important point is you can detect if jQuery core scripts and plugins have already been loaded (because they create $ or properties on it) and do this conditionally:
function stripExistingScripts(html) {
var map = {
"jquery.js": "$",
"jquery.min.js": "$",
"jquery-ui.min.js": "$.ui",
"jquery.yiiactiveform.js": "$.fn.yiiactiveform",
"jquery.yiigridview.js": "$.fn.yiiGridView",
"jquery.ba-bbq.js": "$.bbq"
};
for (var scriptName in map) {
var target = map[scriptName];
if (isDefined(target)) {
var regexp = new RegExp('<script.*src=".*' +
scriptName.replace('.', '\\.') +
'".*</script>', 'i');
html = html.replace(regexp, '');
}
}
return html;
}
There's a map of filenames and objects that will have been defined if the corresponding script has already been included; pass your incoming HTML through this function and it will check for and remove <script> tags that correspond to previously loaded scripts.
The helper function isDefined is this:
function isDefined(path) {
var target = window;
var parts = path.split('.');
while(parts.length) {
var branch = parts.shift();
if (typeof target[branch] === 'undefined') {
return false;
}
target = target[branch];
}
return true;
}
To avoid attaching event handlers twice
You can simply use a Javascript object to remember if you have already attached the handler; if yes, do not attach it again. For example (view code):
Yii::app()->clientScript->registerScript("view-script","
window.myCustomState = window.myCustomState || {}; // initialize if not exists
if (!window.myCustomState.liveClickHandlerAttached) {
window.myCustomState.liveClickHandlerAttached = true;
$('.link').live('click',function(){
alert('test');
})
}
");
The cleanest way is to override beforeAction(), to avoid any duplicated core script:
class Controller extends CController {
protected function beforeAction($action) {
if( Yii::app()->request->isAjaxRequest ) {
Yii::app()->clientScript->scriptMap['jquery.js'] = false;
Yii::app()->clientScript->scriptMap['jquery-2.0.0.js'] = false;
Yii::app()->clientScript->scriptMap['anything.js'] = false;
}
return parent::beforeAction($action);
}
}
Note that you have to put the exact js file name, without the path.
To avoid including script files twice, try this extension: http://www.yiiframework.com/extension/nlsclientscript/
To avoid attaching event handlers twice, see Jons answer: https://stackoverflow.com/a/10188538/729324