Nightwatch generic step definitions without duplicationg elements in pageobjects - nightwatch.js

I have a problem: i have a step like this:
this.Then(/^I click "([^"]*)" element$/, (browser, btn) => {
var main = browser.page.main_page();
main
.waitForElementVisible('#' + btn, 3000)
.assert.visible('#' + btn)
.click('#' + btn)
});
I don't want to duplicate same step definition for other page object model. Is there possibility to create/build one big pageobject when i run test or make this page object contain required element without entering it multiply time in different page object model files.

Solution 1:
this.Then(/^I click "([^"]*)" element from "([^"]*)"$/, (browser, btn, page_name) => {
var page_obj = browser.page[page_name]();
page_obj
.waitForElementVisible('#' + btn, 3000)
.assert.visible('#' + btn)
.click('#' + btn)
});
Soluution 2:
create Given step definition and step like this:
this.Given(/^I use the "([^"]*)" page object$/, function(browser, page) {
var p = browser.page[page]
if (p) {
browser.__page = p();
}
});
this.Then(/^I click "([^"]*)" element$/, (browser, btn) => {
var main = browser.__page;
main
.waitForElementVisible('#' + btn)
.assert.visible('#' + btn)
.click('#' + btn)
});

Related

Is there a way to declare a databound function for kendo grid inside an another grid?

I want to resize my grid that inside another grid. These grids are hierarchical. I wrote something for that but this works for second click. The processes I mentioned are seen in the pictures (firstclick, secondclick). the red circle shows extand button.
The js code block I wrote for solution but it does not work properly:
// The code inside the databound function of master grid
$("#SiparisListeleGrid td a.k-icon").click(function () { // onclick for a element that opens second grid inside the row
if ($(this).hasClass("k-i-expand")) { // if the grid is expand
// uid of tr element
var tr_UID = $(this).parents("tr").data("uid");
// master grid
var ustGrid = $("#SiparisListeleGrid").data("kendoGrid");
$(ustGrid.dataSource.data()).each(function (i, item) {
if (item.uid == tr_UID) {
var altGrid = $("#Grid_SiparisSatir_" + item.SipUstID).data("kendoGrid");
var rowCount = altGrid.dataSource.view().length;
$("#Grid_SiparisSatir_" + item.SipUstID).attr("style", "height:" + (rowCount * 40 + 125) + "px;");
$("#Grid_SiparisSatir_" + item.SipUstID + " .k-grid-content").css("height", (rowCount * 40));
$("#Grid_SiparisSatir_" + item.SipUstID + " .k-grid-content-locked").css("height", (rowCount * 40));
}
});
}
});
// This code block only works on second clicking the expan button.
// Does not recognize the second grid when clicked for the firs time
// Should I use databound for second grid? However I do not know how can I do that.
firstclick
secondclick
This code block let me give databound to child grid. It is worked for me.
Solution

Handle two key event in as 2 ctrl + left click

I want to catch both the single left click and the ctrl + left click in as2.
I am using FlashDevelop and coded this (it works):
_mc._back.onRelease = function() :Void
{
var args:Array = new Array();
args.push((_root._xmouse - this._parent._posMiniMapX) * this._parent._ratio);
args.push((_root._ymouse - this._parent._posMiniMapY) * this._parent._ratio + this._parent._bpa / this._parent._ratio);
fscommand("MoveCameraMiniMap", args);
}
How can I handle the both event?
Thank you.
the approach that I've usually taken is to listen to keyboard events on the CTRL key then evaluate that onRelease to determine the correct action.
But you could simply check the key.isDown status within the onRelease
_mc._back.onRelease = function() :Void {
if(Key.isDown(17)) {
// do CTRL + mouse action
} else {
// do standard action
}
}

JqGrid next button enabled for no values are returned

We have an issue when no values are returned from Jqgrid. In this case next button of pager (jqGrid) is enabled. We have to disable it when grid is empty. Please help me in finding a solution.
To set the next button as disabled you can do the following:
$('#next_' + yourgridid + '_pager').addClass('ui-state-disabled');
To re-enable the button do:
$('#next_' + yourgridid + '_pager').removeClass('ui-state-disabled');
I suggest doing this in the loadComplete(data) event.
$("#yourgridid").jqGrid({
...
loadComplete: function(data){
var records = $('#yourgridid').jqGrid('getGridParam', 'reccount');
//note: you can also get record count via data.records or data.rows.length in this function
if (records > 0) {
$('#next_' + yourgridid + '_pager').removeClass('ui-state-disabled');
} else {
$('#next_' + yourgridid + '_pager').addClass('ui-state-disabled');
}
},
...
});
loadComplete: function (data) {
var page = $('#mygrid').jqGrid('getGridParam', 'page');
var lastpage = $("#mygrid").getGridParam('lastpage');
//note: you can also get record count via data.records or data.rows.length in this function
if (lastpage > page) {
$('#next_mygridpager').removeClass('ui-state-disabled');
$('#last_mygridpager').removeClass('ui-state-disabled');
} else {
$('#next_mygridpager').addClass('ui-state-disabled');
$('#last_mygridpager').addClass('ui-state-disabled');
}
}
I believe this is a more complete solution because you also do not want the next and last button appear when there are no more pages to move forward.

how to make jqgrid advanced search dialog keyboard accessible

Answer in how to enable enter in jqgrid advanced search window describes how to enable enter and other keys in jqgrid advanced search dialog.
After clicking Add group, Add subgrup, Delete rule or Delete group button in advanced search dialog Enter and other keys are still ignored. How set focus to added element or after delete remaining element to enable Enter and other keys?
The current version of the Advanced Searching dialog (see definition of jqFilter in the grid.filter.js) recreate all controls of the dialog on change of someone. See the code of reDraw which looks
this.reDraw = function() {
$("table.group:first",this).remove();
var t = this.createTableForGroup(p.filter, null);
$(this).append(t);
if($.isFunction(this.p.afterRedraw) ) {
this.p.afterRedraw.call(this, this.p);
}
};
How one can see the first line $("table.group:first",this).remove(); delete the content of all filter. The current focus will be lost and one have the problems which you described.
I suggest to fix the code of reDraw using document.activeElement element which was introduced in Internet Explorer originally (at least in IE4) and which is supported now in all web browsers because it's part of HTML5 standard (see here). The element which has focus originally will be destroyed and one will unable to set focus on it later. So I suggest to save the element name of the element and it's classes (like input.add-group or input.add-rule.ui-add) and to find the position of the element on the searching dialog. Later, after the dialog element will be recreated we'll set focus on the element with the same index.
I suggest to change the code of reDraw to the following
this.reDraw = function() {
var activeElement = document.activeElement, selector, $dialog, activeIndex = -1, $newElem, $buttons,
buttonClass,
getButtonClass = function (classNames) {
var arClasses = ['add-group', 'add-rule', 'delete-group', 'delete-rule'], i, n, className;
for (i = 0, n = classNames.length; i < n; i++) {
className = classNames[i];
if ($.inArray(className, arClasses) >= 0) {
return className;
}
}
return null;
};
if (activeElement) {
selector = activeElement.nodeName.toLowerCase();
buttonClass = getButtonClass(activeElement.className.split(' '));
if (buttonClass !== null) {
selector += '.' + buttonClass;
if (selector === "input.delete-rule") {
$buttons = $(activeElement).closest('table.group')
.find('input.add-rule,input.delete-rule');
activeIndex = $buttons.index(activeElement);
if (activeIndex > 0) {
// find the previous "add-rule" button
while (activeIndex--) {
$newElem = $($buttons[activeIndex]);
if ($newElem.hasClass("add-rule")) {
activeElement = $newElem[0];
selector = activeElement.nodeName.toLowerCase() + "." +
getButtonClass(activeElement.className.split(' '));
break;
}
}
}
} else if (selector === "input.delete-group") {
// change focus to "Add Rule" of the parent group
$newElem = $(activeElement).closest('table.group')
.parent()
.closest('table.group')
.find('input.add-rule');
if ($newElem.length > 1) {
activeElement = $newElem[$newElem.length-2];
selector = activeElement.nodeName.toLowerCase() + "." +
getButtonClass(activeElement.className.split(' '));
}
}
$dialog = $(activeElement).closest(".ui-jqdialog");
activeIndex = $dialog.find(selector).index(activeElement);
}
}
$("table.group:first",this).remove();
$(this).append(this.createTableForGroup(this.p.filter, null));
if($.isFunction(this.p.afterRedraw) ) {
this.p.afterRedraw.call(this, this.p);
}
if (activeElement && activeIndex >=0) {
$newElem = $dialog.find(selector + ":eq(" + activeIndex + ")");
if ($newElem.length>0) {
$newElem.focus();
} else {
$dialog.find("input.add-rule:first").focus();
}
}
};
Like one can see on the next demo the focus in the Searching Dialog stay unchanged after pressing on the "Add subgroup" or "Add rule" buttons. I set it on the "Add rule" buttons of the previous row group in case of pressing "Delete group".
One more demo use jQuery UI style of the buttons and the texts in the buttons (see the answer). After clicking on the "Delete" (rule or group) button I tried to set the focus to the previous "Add Rule" button because setting of the focus on another "Delete" (rule or group) button I find dangerous.
Additionally in the demo I use
afterShowSearch: function ($form) {
var $lastInput = $form.find(".input-elm:last");
if ($lastInput.length > 0) {
$lastInput.focus();
}
}
because it seems me meaningful to set initial focus on the last input field at the dialog opening.
UPDATED: I find additionally meaningful to set focus on the current clicked buttons "Add subgroup", "Add rule" or "Delete group". The advantage one sees in the case it one first click some button with the mouse and then want to continue the work with keyboard. So I suggest to change the line
inputAddSubgroup.bind('click',function() {
to
inputAddSubgroup.bind('click',function(e) {
$(e.target).focus();
To change the line
inputAddRule.bind('click',function() {
to
inputAddRule.bind('click',function(e) {
$(e.target).focus();
and the line
inputDeleteGroup.bind('click',function() {
to
inputDeleteGroup.bind('click',function(e) {
$(e.target).focus();
and the line
ruleDeleteInput.bind('click',function() {
to
ruleDeleteInput.bind('click',function(e) {
$(e.target).focus();

I want to combine the FormCode and AutomaticAdvance rotator types

How can I create a rotator with "FormCode" mode while being able to start that rotator automatically when the page loads? In other words, to start the rotator automatically while enabling end user to stop/start/move next/move back.
I need a complete sample code for the call.
I've used the following JavaScript/JQuery code for FormCode management:
<script type ="text/javascript">
//
function
startRotator(clickedButton, rotator, direction)
{
if
(!rotator.autoIntervalID)
{
refreshButtonsState(clickedButton, rotator);
rotator.autoIntervalID = window.setInterval(
function
()
{
rotator.showNext(direction);
}, rotator.get_frameDuration());
}
}
function
stopRotator(clickedButton, rotator)
{
if
(rotator.autoIntervalID)
{
refreshButtonsState(clickedButton, rotator)
window.clearInterval(rotator.autoIntervalID);
rotator.autoIntervalID =
null
}
}
function
showNextItem(clickedButton, rotator, direction)
{
rotator.showNext(direction);
refreshButtonsState(clickedButton, rotator);
}
// Refreshes the Stop and Start buttons
function
refreshButtonsState(clickedButton, rotator)
{
var
jQueryObject = $telerik.$;
var className = jQueryObject(clickedButton).attr("class"
);
switch
(className)
{
case "start"
:
{
// Start button is clicked
jQueryObject(clickedButton).removeClass();
jQueryObject(clickedButton).addClass(
"startSelected"
);
// Find the stop button. stopButton is a jQuery object
var stopButton = findSiblingButtonByClassName(clickedButton, "stopSelected"
);
if
(stopButton)
{
// Changes the image of the stop button
stopButton.removeClass();
stopButton.addClass(
"stop"
);
}
}
break
;
case "stop"
:
{
// Stop button is clicked
jQueryObject(clickedButton).removeClass();
jQueryObject(clickedButton).addClass(
"stopSelected"
);
// Find the start button. startButton is a jQuery object
var startButton = findSiblingButtonByClassName(clickedButton, "startSelected"
);
if
(startButton)
{
// Changes the image of the start button
startButton.removeClass();
startButton.addClass(
"start"
);
}
}
break
;
}
}
// Finds a button by its className. Returns a jQuery object
function
findSiblingButtonByClassName(buttonInstance, className)
{
var
jQuery = $telerik.$;
var ulElement = jQuery(buttonInstance).parent().parent();
// get the UL element
var allLiElements = jQuery("li", ulElement);
// jQuery selector to find all LI elements
for (var
i = 0; i < allLiElements.length; i++)
{
var
currentLi = allLiElements[i];
var currentAnchor = jQuery("A:first", currentLi);
// Find the Anchor tag
if
(currentAnchor.hasClass(className))
{
return
currentAnchor;
}
}
}
//]]>
And the following code for the calls:
<
a href="#" onclick="stopRotator(this, $find('<%= MyRotator.ClientID %>
')); return false;"
class="stopSelected" title="Stop">Stop
'), Telerik.Web.UI.RotatorScrollDirection.Left); return false;"
class="start" title="Start">Start
However, I cannot start the rotator on the page load. Tried to use this code in the in the MyRotator_DataBoud event, but did not work either:
protected void rrMyRotator_DataBound(object sender, EventArgs
e)
{
Page.RegisterClientScriptBlock(
"MyScript", " startRotator(this, $find('<%= MyRotator.ClientID %>'), Telerik.Web.UI.RotatorScrollDirection.Left);"
);
}
There are a couple of examples available in the Telerik online demos for this functionality and they have code you can use. See http://demos.telerik.com/aspnet-ajax/rotator/examples/clientapicontrol/defaultcs.aspx and http://demos.telerik.com/aspnet-ajax/button/examples/slideshow/defaultcs.aspx

Resources