How to make Nightwatch use xpath by default in page object files - xpath

All my page objects look something like this:
elements: {
header: {
locateStrategy: 'xpath',
selector: "//h3[text()='Welcome']"
},
loginButton: {
locateStrategy: 'xpath',
selector: "//button[text()='Login']"
},
forgotPasswordLink: {
locateStrategy: 'xpath',
selector: "//a[text()='Forgot Password?']"
},
signupButton: {
locateStrategy: 'xpath',
selector: "//button[text()='Signup']"
}
It would be way better if I could just say "use xpath everywhere" - that would all collapse mightily
The docs say that you should be able to set "use_xpath" : true in your "test settings", but I have tried that in all the places I can see in nightwatch.json, and it doesn't have any effect.
(It's not completely clear if they mean that this setting will affect declarations in page object files, in any case: the example only shows it affecting subequent assert calls in the test case).

You can just use a javascript function like this (depending on your favourite way to create objects):
var xSelector = function (selector) {
return {
selector: selector,
locateStrategy: 'xpath'
}
};
And then use it like so:
elements: {
xxx: xSelector('//a[text()="Bank Details"]')
createStepButton: { selector: '#menu-create-item' },
}
Hint: In the sample above the createStepButton is still using the css selector strategy. Consider also creating a cssSelector function for uniform readability of the elements section.

Try to set:
"use_xpath": true
in nightwatch.conf.js file, not nightwatch.json
Worked for me :)

Perhaps it'll help someone.
Try to set:
"use_xpath": true
in your nightwatch.json

To get around this you can loop over your elements and set any given locate strategy for each element, like this:
var pageObject = {
url: 'https://google.com',
elements: {
myFirstElement: {
selector: "//div[#class='my-first-el']"
},
mySecondElement: {
selector: "//div[#class='my-seconds-el']"
}
}
};
for (var el in pageObject.elements){
pageObject.elements[el]["locateStrategy"] = "xpath";
}
module.exports = pageObject;

Related

GraphQL Apollo pagination and type policies

I am really struggling with this concept. I hope someone can help me understand it better.
The documentations uses a simple example and it's not 100% clear to me how it works.
I have tried using keyArgs, but they didn't work, so I adopted to use the args parameter in the read and merge functions. First, let me explain my scenario.
I have a couple of search endpoints that use the same parameters:
{
search:
{
searchTerm: "*",
includePartialMatch: true,
page: 1,
itemsToShow: 2,
filters: {},
facets: [],
orderBy: {}
}
}
So I have setup my type policies like this:
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
searchCategories: typePolicy,
searchBrands: typePolicy,
searchPages: typePolicy,
searchProducts: typePolicy,
},
},
},
});
And I was using a generic typePolicy for them all.
At first, I tried this:
const typePolicy = {
keyArgs: [
"search",
[
"identifier",
"searchTerm",
"includePartialMatches",
"filters",
"orderBy",
"facets",
],
],
// Concatenate the incoming list items with
// the existing list items.
merge(existing: any, incoming: any) {
console.log("existing", existing);
console.log("incoming", incoming);
if (!existing?.items) console.log("--------------");
if (!existing?.items) return { ...incoming }; // First request
const items = existing.items.concat(incoming.items);
const item = { ...existing, ...incoming };
item.items = items;
console.log("merged", item);
console.log("--------------");
return item;
},
};
But this does not do what I want.
What I would like, is for apollo to work as it does normally, but when the "page" changes for any field, it appends it instead of caching a new request.
Does anyone know what I am doing wrong or can provide me with a better example that what is on the documentation?

How to extend the NavigationListItem control in SAPUI5?

I want to extend the NavigationListItem control to accept sap.ui.core.Control objects in it's aggregation. I have created a separate file to extend the control and added a new aggregation called 'rows' with type sap.ui.core.Control in the metadata section. The extended control is getting called in the view, but it is not displaying any child controls which were added to the new aggregation 'rows'. Please advise, if I need to add anything more to the extension file.
Extension code:
sap.ui.define(["sap/ui/core/Control",
"sap/tnt/NavigationListItem"],
function(Control, NavigationListItem) {
"use strict";
return NavigationListItem.extend("ajacontrolExt.control.NavigationCustomListItem", {
metadata: {
properties: {
},
defaultAggregation: "rows",
aggregations: {
rows: {
type: "sap.ui.core.Control",
multiple: true,
singularName: "row"
}
}
}
});
});

d3 chart update automatically when data change by using vue

I want every time my mock changes and paesss to dataa, the barchart can re-render or updated. I watch dataa in barchart component, but it didn't work.
"console.log('this', this.dataa);" never trigger. I have no idea which part is wrong.
here is my code:
<sr-bar-chart
:title= "descriptionText.title_traffic"
:dataa= "mock"
:unit="descriptionText.avg7d_unit_people"
:index="'1'"
:barColor="'#adadad'"
and in bar chart component
export default {
name: 'sceneBarChart',
props: ['title', 'dataa', 'unit', 'index', 'barColor'],
data() {
return {
count: 0
};
},
watchers: {
dataa() {
console.log('this', this.dataa);
this.drawMap();
}
},
methods: {
drawMap() {
....
}
},
mounted() {
this.drawMap();
}
};
Thanks!
Use watch rather than watcher and just for good measure I'd add the newValue parameter as well.
watch: {
dataa(newValue) {
console.log('this', this.count);
this.drawMap();
}
here is more info on watched properties: https://v2.vuejs.org/v2/guide/computed.html#Watchers

Remove buttons md-autofocus from a custom md-dialog

I have a this md-dialog https://codepen.io/patapron/pen/oLaxap
<md-button ng-click="answer('not useful')" >
Not Useful
</md-button>
<md-button ng-click="answer('useful')" style="margin-right:20px;" >
Useful
</md-button>
How do to I get remove the md-autofocus from the buttons?
Objetive: Any button must be pre-selected paint in grey.
There is an easier way to do this without having to write a custom directive. Angular Material has the ability to remove autofocus built-in.
In your controller where you are writing the .show function, set the focusOnOpen to false focusOnOpen: false
The documentation explains it here $mdDialog
Here is an example of how mine looks
function deleteMediaDialog() {
var dialogData = {
};
$mdDialog.show({
controller : 'deleteMediaDialogController',
controllerAs : 'vm',
templateUrl : 'app/main/apps/scala-media/dialogs/delete/delete-dialog.html',
parent : angular.element($document.body),
focusOnOpen : false,
clickOutsideToClose: true,
locals : {
dialogData: dialogData
}
});
}
I solved by mysleft. Directive magic
scope.$watch(function () { return ele.attr('class'); }, function () {
if (ele.hasClass('md-focused')) {
ele.removeClass('md-focused');
}
});

Translating JSON into custom dijit objects

I am looking for an example where JSON constructed from the server side is used to represent objects that are then translated into customized widgets in dojo. The JSON would have to be very specific in its structure, so it would not be a very general solution. Could someone point me to an example of this. It would essentially be the reverse of this
http://docs.dojocampus.org/dojo/formToJson
First of all let me point out that JSON produced by dojo.formToJson() is not enough to recreate the original widgets:
{"field1": "value1", "field2": "value2"}
field1 can be literally anything: a checkbox, a radio button, a select, a text area, a text box, or anything else. You have to be more specific what widgets to use to represent fields. And I am not even touching the whole UI presentation layer: placement, styling, and so on.
But it is possible to a certain degree.
If we want to use Dojo widgets (Dijits), we can leverage the fact that they all are created uniformly:
var myDijit = new dijit.form.DijitName(props, node);
In this line:
dijit.form.DijitName is a dijit's class.
props is a dijit-specific properties.
node is an anchor node where to place this dijit. It is optional, and you don't need to specify it, but at some point you have to insert your dijit manually.
So let's encode this information as a JSON string taking this dijit snippet as an example:
var myDijit = new dijit.form.DropDownSelect({
options: [
{ label: 'foo', value: 'foo', selected: true },
{ label: 'bar', value: 'bar' }
]
}, "myNode");
The corresponding JSON can be something like that:
{
type: "DropDownSelect",
props: {
options: [
{ label: 'foo', value: 'foo', selected: true },
{ label: 'bar', value: 'bar' }
]
},
node: "myNode"
}
And the code to parse it:
function createDijit(json){
if(!json.type){
throw new Error("type is missing!");
}
var cls = dojo.getObject(json.type, false, dijit.form);
if(!cls){
// we couldn't find the type in dijit.form
// dojox widget? custom widget? let's try the global scope
cls = dojo.getObject(json.type, false);
}
if(!cls){
throw new Error("cannot find your widget type!");
}
var myDijit = new cls(json.props, json.node);
return myDijit;
}
That's it. This snippet correctly handles the dot notation in types, and it is smart enough to check the global scope too, so you can use JSON like that for your custom dijits:
{
type: "my.form.Box",
props: {
label: "The answer is:",
value: 42
},
node: "answer"
}
You can treat DOM elements the same way by wrapping dojo.create() function, which unifies the creation of DOM elements:
var myWidget = dojo.create("input", {
type: "text",
value: "42"
}, "myNode", "replace");
Obviously you can specify any placement option, or no placement at all.
Now let's repeat the familiar procedure and create our JSON sample:
{
tag: "input",
props: {
type: "text",
value: 42
},
node: "myNode",
pos: "replace"
}
And the code to parse it is straightforward:
function createNode(json){
if(!json.tag){
throw new Error("tag is missing!");
}
var myNode = dojo.create(json.tag, json.props, json.node, json.pos);
return myNode;
}
You can even categorize JSON items dynamically:
function create(json){
if("tag" in json){
// this is a node definition
return createNode(json);
}
// otherwise it is a dijit definition
return createDijit(json);
}
You can represent your form as an array of JSON snippets we defined earlier and go over it creating your widgets:
function createForm(array){
dojo.forEach(array, create);
}
All functions are trivial and essentially one-liners — just how I like it ;-)
I hope it'll give you something to build on your own custom solution.

Resources