Confirm URL using POM Nightwatch - selenium

New to nightwatch and js in general and I'm struggling to figure out how to validate a url using pom pattern. I know this is wrong. Any suggestions are greatly appreciated, including useful links for me to rtfm as I'm struggling to find robust examples of pom nightwatch.
test.js
module.exports = {
"tags": ['sanity'],
'confirm navigation to example.com' : function (client) {
var landingPage = client.page.landing();
landingPage.navigate();
landingPage.confirmOnLandingPage();
client.end();
}
};
page.js
var landingCommands = {
navigate:function(){
url: 'example.com/'
},
confirmOnLandingPage:function(){
this.expect.element('body')
.to.be.present.before(1000)
.url(function(result)
{
this.assert.equal(result.value, 'example.com/', 'On Landing Page.')
});
}
}
Running: confirm navigation to example.com
✖ TypeError:
this.expect.element(...).to.be.present.before(...).url is not a
function
at Page.confirmOnLandingPage (/Users/Home/Development/NWQA/pages/page.js:9:10)
at Object.confirm navigation to example.com (/Users/Home/Development/NWQA/tests/test.js:7:21)
FAILED: 1 errors (18ms)

After running .expect you break the Nightwatch command chain and start Expect.js chain so after you call this.expect.element('body').to.be.present.before(1000) you get Expect.js object and not Nightwatch browser object.
To fix just start a new chain and change this.url call to this.api.url since url() is not available within the page object:
confirmOnLandingPage: function(){
this.expect.element('body').to.be.present.before(1000);
this.api.url(function(result)
{
this.assert.equal(result.value, 'example.com/', 'On Landing Page.')
});
}
Update:
I just noticed you incorrectly declared URL for your page object. navigate is internal function, you only need to provide url property:
var landingCommands = {
url: 'example.com/',
...
};

Related

Cypress auto submit on login page from beforeEach in second test

I'm working on a Cypress test for the Polish Wikipedia plugin, and I have this code in my cypress test:
Cypress.Commands.overwrite('visit', (orig, path, options) => {
return orig(`https://pl.wikipedia.org/${path}`);
});
Cypress.Commands.add('login', (pass) => {
cy.visit('/w/index.php?title=Specjalna:Zaloguj');
cy.get('#wpName1').type('<username>');
cy.get('#wpPassword1').type(pass);
cy.get('#userloginForm form').submit();
});
Cypress.Commands.add('dark_vector_wait', (pass) => {
cy.get('.vector-menu-content-list > li:nth-child(7)', { timeout: 10000 }).should('be.visible');
});
And in my spec:
describe('dark vector test', () => {
beforeEach('login', () => {
cy.login(Cypress.env('WIKI_PASSWORD'));
});
it('test discussion', () => {
cy.visit('/wiki/Dyskusja_wikipedysty:<username>');
cy.dark_vector_wait();
cy.matchImageSnapshot('discussion');
});
it('testing-page page', () => {
cy.visit('/wiki/Wikipedysta:<username>/testing-page');
cy.dark_vector_wait();
cy.matchImageSnapshot('testing-page');
});
});
And the second test is failing because as soon as Cypress type the password it automatically submits a form so cy.get('#userloginForm form').submit(); is executing after Cypress visits the home page (default redirect) and fail to find a form.
What's wrong? Why does Cypress auto-submit a form after a second time? This is not what Wikipedia is doing since the login form doesn't have any JavaScript code and you need to click login to be able to login to Wikipedia.
EDIT:
I've tried to
Use BaseURL and remove overwrite of visit.
Add type('{enter}'), but this only shows an error: cy.type() failed because this element is detached from the DOM.
EDIT 2
This is the screenshot of the action taken by cypress, second test has a page load without {enter} action and without form submit.
The problem is in Cypress.Commands.overwrite('visit').
You pass the parameter with a leading slash '/wiki/Dyskusja_wikipedysty:<username>' but concatinate to base which also has a trailing slash https://pl.wikipedia.org/${path}, so now the full path is
https://pl.wikipedia.org//wiki/Dyskusja_wikipedysty:<username>
If you set baseUrl in configuration, Cypress sorts it out for you
cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
baseUrl: 'https://pl.wikipedia.org'
}
})
Then remove the Cypress.Commands.overwrite('visit').
With these changes, I was able to pass both tests.
Using cy.session()
The problem might be one specific to locality, I do not have any steps missing in the Cypress log.
You can try adding a session cache so that the first login is re-used.
Cypress.Commands.add('login', (pass) => {
cy.session('login', () => { // login occurs only once
// credentials are cached
cy.visit('/w/index.php?title=Specjalna:Zaloguj');
cy.get('#wpName1').type('Jack Bosko');
cy.get('#wpPassword1').type(pass);
cy.get('#userloginForm form').submit();
// for good measure, confirm login was successful
// by checking for your name on the page
cy.contains('span', 'Jack Bosko')
})
})
So the problem was the weird IME keyboard that is part of MediaWiki. I somehow got it enabled on my system even when I was not logged in. Maybe added globally with cookies or something.
I noticed that keyboard when I was asking questions on the MediaWiki support page.
This is not related to Cypress. I'm investigating why the keyboard is there, and why clean environment it.

Refresh statically generated page (data) once it has loaded on client

For example I have some page in Nuxt:
data() {
return {
items: []
};
},
asyncData() {
return axios.get('site.com/url')
.then((response) => {
return {
items: response.data
};
});
},
Then I run npm run generate and get statically generated html-page with data (items) from backend server. And when I open this page in browser I see that injected data into the page.
But these items might be updated on the backend so I need to see them once I have got refreshed the page with F5 and without running again npm run generate.
So looks like I should refetch data in mounted() section. Maybe Nuxt has something more suitable for this?
The only option is use crawler: false property in your nuxt.config.js file. It will disable static content generation from you dynamic pages. Here is the documentation.

Not able to add a custom command

I want to create a custom command in a typescript webdriverIO project. But no matter what I do, the command always ends up with the error :
TypeError: browser.waitAndClick is not a function.
Basically I wanted to add the same function they mentioned in webdriverIO doc. I am adding it from beforeAll() in my specs.
import { DEFAULT_TIMEOUT } from "../constants";
class CustomCommand {
private static alreadyAdded = false;
static addCommands(){
if(!this.alreadyAdded) {
browser.addCommand('waitAndClick', (el: WebdriverIO.Element) => {
el.waitForDisplayed({timeout: DEFAULT_TIMEOUT});
el.click();
}, true);
browser.addCommand('waitAndSetValue', (el: WebdriverIO.Element, text: string) => {
el.waitForDisplayed({timeout: DEFAULT_TIMEOUT});
el.setValue(text);
}, true);
this.alreadyAdded = true;
}
}
}
export default CustomCommand;
And I am calling this addCommands() function from beforeAll() of a spec. But no luck!
One nice person from slack channel helped me to find out the exact reason. Actually I overlooked something in doc : If you register a custom command to the browser scope, the command won’t be accessible for elements. Likewise, if you register a command to the element scope, it won’t be accessible in the browser scope. Turned out this is the reason. It is resolved now.
Passing false as third parameter in addCommand() fixed it.
Welcome to stack-overflow!
Please note that there is no 'beforeAll' hook in webdriverio as per the docs here.
It should work if you call this in before hook.
based on the webdriverio docs: https://webdriver.io/docs/api/browser/addCommand/
Note: don't forget to wrap inside before hook as ex bellow:
before: async function (capabilities, specs) {
browser.addCommand('waitAndClick', async function (selector) {
try {
await $(selector).waitForExist();
await $(selector).click();
} catch (error) {
throw new Error(`Could not click on selector: ${selector}`);
}
});
},

Aurelia - Trying to switch root and it cannot find the location

I have been following a variety of sources in particular Mathew James Davis with THIS blog entry and others.
I had in my boot.ts (main in other examples etc):
aurelia
.start()
.then(function () { return aurelia.setRoot(PLATFORM.moduleName("public/public/public")); });
});
which worked.
I am now running two roots and checking if a JWT exists in localstorage. It gets the jwt and stores it OK and I even obtain it correctly but it now doesnt recognise the root and I think I have a syntax error of some sort..
This is what I now have:
aurelia.start().then(() => {
var auth = aurelia.container.get(AuthService);
let root = auth.isAuthenticated() ? 'app/app/app' : 'public/public/public';
return aurelia.setRoot(PLATFORM.moduleName(root));
});
I am getting the following error:
Uncaught (in promise) Error: Unable to find module with ID: public/public/public
I do not know why it now doesnt work when the exact same path worked when entered directly..
UPDATE
Ok so I thought I would refactor this and utilise the section of code that works:
This is what I changed it to:
var auth = aurelia.container.get(AuthService);
let authenticated = auth.isAuthenticated();
console.log("authenticated: ", authenticated);
if (authenticated) {
aurelia
.start()
.then(function () { return aurelia.setRoot(PLATFORM.moduleName("app/app/app")); });
} else {
aurelia
.start()
.then(function () { return aurelia.setRoot(PLATFORM.moduleName("public/public/public")); });
}
Now it shows a blank loading page with "loading" and shows this at in the console:
authenticated: false
aurelia-logging-console.js:27 INFO [aurelia] Aurelia Started
client.js:82 [HMR] connected
Note - if just have the original code with app/app/app in it and authentication= true then it also shows correctly.
So both roots work but not with a check..
Finally fixed this. I eventually changed my original code:
aurelia.start().then(function () {
var auth = aurelia.container.get(AuthService);
var root = auth.isAuthenticated() ? "app/app/app" : "public/public/public";
aurelia.setRoot(root);
to:
aurelia.start().then(() => {
var auth = aurelia.container.get(AuthService);
let root: string = auth.isAuthenticated() ? PLATFORM.moduleName('app/app/app') : PLATFORM.moduleName('public/public/public');
aurelia.setRoot(root, document.body)
});
and it now works. In the end it was my lack of programming skills however if anybody else has a problem they might try this for switching routes.

ng-2 and ionic 2: Error while waiting for Protractor to sync with the page: "window.angular is undefined

I'm running a pretty basic Protractor test with Page Object scheming set up. But when I run my tests, I get the error described in the title. This is my spec file.
var tabs = require('../../pages/tabBar.page.js');
var dashboard = require('../../pages/dashboard.page.js');
describe('Dashboard - Nav', function() {
beforeEach(function() {
browser.ignoreSynchronization = false;
browser.waitForAngular();
})
it('Given I open the dashboard tab', function() {
browser.get('http://localhost:8100');
browser.refresh();
browser.sleep(2000);
expect(dashboard.salesButton.isDisplayed()).toBe(true);
browser.sleep(1000);
})
})
I can get it to run by setting ignoreSync to true, but the test is a lot slower due to some dependencies, and I don't see why I should have to anyway, it's all angular2/ionic2. Anyone able to help?
Homer Simpson: DOH
It would probably help if I loaded my page before waiting for Angular huh?
Thanks everyone for humoring me on this. As you were.