Selectors when passed using # notation from the test function to the page object are not working.
Here's my homepage object.
module.exports = {
url: function () {
return this.api.launchUrl;
},
elements: {
dropdownSelector: {
selector: '#input-13',
locateStrategy: 'css selector'
},
dropdownAuthSelector: {
selector: '#list-item-18-5 > span > span.ml-1',
locateStrategy: 'css selector'
},
},
commands: [{
setDropdown(selector, value) {
let { selectDropdown } = require('../modules/Utils.js');
selectDropdown(this.api, selector, value);
return this;
}
}]
};
Utils.js
module.exports.selectDropdown = function (self,selector,value) {
return self.click(selector).click(value);
}
Test js file.
module.exports = {
'#tags': ['home'],
'Dashboard Dropdown test'(browser) {
const homePage = browser.page.homepage();
homePage
.navigate()
//.setDropdown(homePage.elements.dropdownSelector.selector, homePage.elements.dropdownAuthSelector.selector)
.setDropdown('#dropdownSelector', '#dropdownAuthSelector')
.assert.urlContains('Authentication').end();
}
};
So basically
setDropdown(homePage.elements.dropdownSelector.selector, homePage.elements.dropdownAuthSelector.selector) Works fine, but when I use # notation it doesn't work
.setDropdown('#dropdownSelector', '#dropdownAuthSelector') and throws below error
Error
Error while running .locateMultipleElements() protocol action: invalid selector: An invalid or illegal selector was specified
Error while running .locateMultipleElements() protocol action: invalid selector: An invalid or illegal selector was specified
I don't think they can be access directly thru # due to the queueing behavior of nightwatch. Page object commands are not autoadded to the main queue. Also, why not define custom command HomePage page object, where you can access them directly and then just invoke that command in test?
Related
I am learning cypress and javascript and have come across this type error.
TypeError: _testElements.default.selectionRow is not a function
I looked at some documentation with cypress and can't see a mistake I am making in the code, so was hoping someone with javascript and cypress experience may know why this error is being outputted.
Code:
First the class where it gets the element:
class testElements {
selectionRow() {
return cy.get('.selectionRow')
}
typeButton() {
return cy.get('.typeButton')
}
}
export default testElements
And then the code it's referring the error to is below:
import { Given, When, Then } from "cypress-cucumber-preprocessor/steps";
import testElements from '../elements/testElements';
When ("User selects a row", () => {
testElements.selectionRow()
.within(() => {
testElements.typeButton().not(".disabled");
})
})
You should first create a class instance to use the methods:
const testElem = new testElements();
testElem.selectionRow()
And I suggest to use uppercase name convention for class TestElements.
If you don't want to instantiating the class, you can use static methods
I've some problem, in my project I need to add Sanitize.js on my project, I've copied to my own 3rd party folder ex vendor
to import it I'm using
import {san} from '../../vendor/Sanitize' //There's No error when compiling this one
but there's an error when I run the page, I'm trying to call the function from Sanitize.js as in readme saying to use it just do like this
var s = new san.Sanitize({
elements: ['a', 'span'],
attributes: {
a: ['href', 'title'],
span: ['class']
},
protocols: {
a: { href: ['http', 'https', 'mailto'] }
}
});
s.clean_node(p);
The Error is
san.Sanitize is not a function/ class constructor
Any idea why this is happening? or did I miss something? There's no Error in compiling process, the error only occurs when I try to run the web page,
Because Sanitize.js is not a module.
Maybe you can try the following solution:
Add export default Sanitize; in end of sanitize.js.
Use import Sanitize from "./sanitize"; to import it.
Remove the following code from sanitize.js.
if ( typeof define === "function" ) {
define( "sanitize", [], function () { return Sanitize; } );
}
During execution, unable to link locator using # symbol from elements.
ERROR: Unable to locate element: "#queryInput" using: xpath
Code:
import * as config from 'config';
import { NightWatchClient, PageObject } from 'nightwatch';
const pageConfig = config.get<IPageConfig>('pages.google');
const page: PageObject = {
url: pageConfig.url,
elements: {
queryInput: {
selector: '//input[#name="q"]',
locateStrategy: 'xpath'
}
},
commands: [
{
enterQuery: (client: NightWatchClient, query: string) => {
return client
.waitForElementVisible('//input[#name="q"]', 5000)
//.setValue('//input[#name="q"]', [query, client.Keys.ENTER])
.setValue('#queryInput', [query, client.Keys.ENTER])
.waitForElementVisible('//*[#id="res"]', 5000);
},
},
]
};
export = page;
Complete code
Link
You don't need to pass in the nightwatch client. It is already available to you in the page object class by using this or this.api. Try dumping this to the console in your page object and you will see all the properties that are available to you. This works for JS so it should work the same way in TS.
You can get your selector to work by changing your function to something like the following:
enterQuery: (query: string) => {
return this
.waitForElementVisible('//input[#name="q"]', 5000)
.setValue('#queryInput', [query, client.Keys.ENTER])
.waitForElementVisible('//*[#id="res"]', 5000);
}
In Geb and WATIR there are certain keywords which we use to visit to the page_url which we have specified in page class. E.g. to keyword in Geb and visit keyword in WATIR.
What similar we can use in nightwatch.js. This is what I have tried but it gives error:
I have tried:
module.exports = {
url: function () {
return this.api.globals.launchUrl + "/goto/desiredPage.html";
},
commands: [pageCommands],
elements: {}
};
In page class I am using it as:
desiredPage
.url()
.foo()
.bar();
client.end();
but it is giving error .url is not a function.
You can see the nightwatch examples inside the nightwatch folder for example:
[page-objects/home.js]
var searchCommands = {
submit: function() {
this.waitForElementVisible('#submitButton', 3000)
.click('#submitButton')
.api.pause(1000);
return this; // Return page object for chaining
}
};
module.exports = {
url: 'http://google.com',
commands: [searchCommands],
elements: {
searchBar: { selector: 'input[name=q]' },
submitButton: { selector: 'button[type=submit]' }
}
};
and then in the test:
/* jshint expr: true */
module.exports = {
'Demo Google search test using page objects' : function (client) {
var homePage = client.page.home();
homePage.navigate();
homePage.expect.element('#searchBar').to.be.enabled;
homePage
.setValue('#searchBar', 'Nightwatch.js')
.submit();
var resultsPage = client.page.searchResults();
resultsPage.expect.element('#results').to.be.present.after(2000);
resultsPage.expect.element('#results').to.contain.text('Nightwatch.js');
resultsPage.expect.section('#menu').to.be.visible;
var menuSection = resultsPage.section.menu;
menuSection.expect.element('#web').to.be.visible;
menuSection.expect.element('#video').to.be.visible;
menuSection.expect.element('#images').to.be.visible;
menuSection.expect.element('#shopping').to.be.visible;
menuSection.productIsSelected('#web', function(result) {
this.assert.ok(result, 'Web results are shown by default on search results page');
});
client.end();
}
};
so "url()" command in pages does not exist you need to define the url in te page and the use "navigate()" instead.
I have a problems changing elements properties from js file. In my program I have main element with that structure:
import "main.js" as Main
ApplicationWindow
{
id: applicationWindow
VK {
id: vk
onReplyReady: {
if (typeof document === "string") {
var obj = JSON.parse(document)
console.log(typeof obj.response,typeof obj.count)
Main.processReply(obj.response)
} else {
Debug.log("VK UNKNOWN ERROR")
}
}
}
initialPage: Component { Auth { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml")
}
In the component Auth I have that code:
Page {
id: messangesPage
Button {
id: mycoolbutton
text: "button"
onClicked: {
vk.getMessanges("lol",0)
}
}
Component.onCompleted: {
vk.getMessanges("lol",0)
}
}
So the idea of my code is pretty simple - I have vk object, that must be global. When I call vk.getMessanges, vk send request to the server and after that emit replyReady signal. In onReplyReady I just parse the reply from server and call function in main.js, where I want to execute that function:
function processReply(reply) {
mycoolbutton.text = "mycoolbutton"
}
However I got an error:
main.js:8: ReferenceError: mycoolbutton is not defined
I noticed that if I call processReply() function from component Auth, than everything works fine, but when I call from element applicationWindow than I got that error. I tried to add property alias mycoolbuttonptr : mycoolbutton in the applicationWindow, but I got another error. What I must do in that case?
Are you aware that main.js is instantiated once for every import you make? If you import main.js from several QML files, you are getting several instances of Main, so if you set a reference to mycoolbutton in one of that instances, that reference is only set on that instance.
If you want to have only one Main instance, you have to declare it at the begining of the JS file with
.pragma library
You can't access Items by id from JS file. You should pass button as parameter, for example:
function processReply(reply, btn) {
btn.text = "mycoolbutton"
}
".pragma library" can be helpful, but doesn't solve problem.