Unable to access the url of a page in NightwatchJS - selenium

I have not been able to get the url during the test runs intermittently.
Let me give you the background: On clicking of a button on a page it navigates to the next page. Upon navigation first thing I would like to validate the url during my test.
Below is the snippet of code I have been using to fetch the url from the current page.
1. Native implementation of nightwatch for the url assertion
assertUrlContains(text) {
this.assert.urlContains(text);
return this;
}
2. Also, tried to fetch the url using the api.url with promise pattern.
getCurrentUrl() {
return new Promise((resolve) => {
this.api.url((result) => {
resolve(result.value);
});
});
}
Both of the approach have same issues and below is the stacktrace of the error:
SEARCH RESULTS URL: null
(node:12375) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'indexOf' of null
(node:12375) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
✖ TypeError: Cannot read property 'indexOf' of null
Something strange I've noticed that the browser navigate to the target page but the nightwatch unable to get the url even though the page load event completes.

You may add an explicit wait condition after you click the button to ensure that the required page has successfully loaded. You may then use one of the following approaches to validate the URL:
Use the urlEquals API for nightwatch documented here: http://nightwatchjs.org/api#assert-urlEquals
You could execute a javascript command through your test script: window.location.href to retrieve the url of the window and save it as a string. You may then perform the assertion on this string

Related

Cypress uncaught:exception handler not working with Magic.link flow

I'm using Cypress to test a login flow that uses Magic.link auth on a mobile Web device, which is encountering the ResizeObserver loop limit exceeded error, as it tries to navigate the Google Auth forms. I've looked at numerous posts, and played around with my test, but it seems the handler is not working.
The recommended Google Authentication from the Cypress docs is insufficient, because with Magic, the flow is initiated by a call to magic.oauth.loginWithRedirect, hence I was hoping to drive the process via the UI directly.
You'll see I added a test to ensure the password input is visible. Now the exception is being thrown at that part of the test. If I remove that check the error occurs on the next step where I try to type the password.
describe('my auth flow', () => {
it('can auth with google', () => {
// click login button from my site
cy.get('button')
.contains('sign-in')
.click();
cy.origin('https://accounts.google.com', () => {
// enter email address
cy.get('input[type=email]')
.type('myuser#mydomain.com');
cy.get('button')
.find('span')
.contains('Next')
.click();
// wait for password page to show
cy.get('#password')
.should('exist')
.and('be.visible'); // error here...
// enter password
// error here if above visibility check removed
cy.get('#password input[type=password]')
.type('mypassword');
cy.get('button')
.find('span')
.contains('Next')
.click();
});
});
});
In support/commands.js, I've added the global error handler, which should handle all uncaught exceptions according to the documentation.
Cypress.on(
'uncaught:exception',
(err) => false
);
Magic does have a test mode, however I really don't want to bypass the login flow. Ideally I could exercise the login flow without hacks for testing.
The cy.origin() command is an isolated sandbox with different document and window to the primary domain.
Try adding the exception handler inside the origin command (presuming the error is happening while on the google domain).
cy.origin('https://accounts.google.com', () => {
Cypress.on('uncaught:exception', (err) => false)

React Native Stack Traces that point to original files

When I have an error in my React Native app, the stack trace that is printed to the console points to index.bundle instead of the original source code (see example below). Is there a way to configure React Native to use source maps so that the logs show up correctly?
This problem only occurs when throwing an error from an asynchronous callback or something outside of rendering. If I throw an error inside a component, then the error shows the correct stack trace in the console. Interestingly, the error shows the correct stack trace all the time in LogBox.
I am running this with react-native run-android and viewing the logs through Metro. To clarify, I am trying to get this working for local debug builds, not production/release builds. Ideally the logs would show the correct stack in the console so that I do not have to symbolicate them manually or find the error in LogBox.
Example result from console.error:
Error: Connection closed
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.myapp.local&modulesOnly=false&runModule=true:261835:40)
at forEach (native)
at flushVolatile (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.myapp.local&modulesOnly=false&runModule=true:261833:33)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.myapp.local&modulesOnly=false&runModule=true:262065:20)
at apply (native)
Thank you in advance!
Answering my own question. I dug into the react-native code and discovered that LogBox symbolicates stack traces by making calls to the metro development server. Instead of replicating that logic, I made the hacky solution below that ties into LogBox. I'm sure there are better ways to do this, but it works.
import { observe as observeLogBoxLogs, symbolicateLogNow } from 'react-native/Libraries/LogBox/Data/LogBoxData';
// LogBox keeps all logs that you have not viewed yet.
// When a new log comes in, we only want to print out the new ones.
let lastCount = 0;
observeLogBoxLogs(data => {
const logs = Array.from(data.logs);
const symbolicatedLogs = logs.filter(log => log.symbolicated.stack?.length);
for (let i = lastCount; i < symbolicatedLogs.length; i++) {
// use log instead of warn/error to prevent resending error to LogBox
console.log(formatLog(symbolicatedLogs[i]));
}
lastCount = symbolicatedLogs.length;
// Trigger symbolication on remaining logs because
// logs do not symbolicate until you click on LogBox
logs.filter(log => log.symbolicated.status === 'NONE').forEach(log => symbolicateLogNow(log));
});
function formatLog(log) {
const stackLines = (log.symbolicated.stack || [])
.filter(line => !line.collapse)
.map(line => ` at ${line.methodName} (${line.file}:${line.lineNumber}:${line.column})`)
.join('\n');
return `Error has been symbolicated\nError: ${log.message.content}\n${stackLines}`;
}
The error appears twice in console, first as the original, second as the symbolicated version. Here's an example of the log output now:
WARN Error: Connection closed
Error: Connection closed
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:334491:50)
at forEach (native)
at flushVolatile (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:334489:43)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:334721:30)
at call (native)
at emitNone (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:340110:33)
at emit (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:340191:23)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:339907:24)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:339889:30)
at apply (native)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:347770:25)
at drainQueue (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:347735:45)
at apply (native)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:31681:26)
at _callTimer (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:31605:17)
at callTimers (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:31801:19)
at apply (native)
at __callFunction (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:25085:36)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:24813:31)
at __guard (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:25039:15)
at callFunctionReturnFlushedQueue (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:24812:21)
LOG Error has been symbolicated
Error: Connection closed
at Object.keys.forEach$argument_0 (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:208:28)
at flushVolatile (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:206:4)
at stream.on$argument_1 (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:477:17)
at emitNone (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:6471:4)
at emit (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:6556:14)
at Duplexify.prototype._destroy (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:6239:2)
at process.nextTick$argument_0 (/Users/georgeflug/projects/logteste/node_modules/mqtt/dist/mqtt.js:6221:4)
at Item.prototype.run (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:13143:4)
at drainQueue (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:13113:16)
If you click on the stacktrace (for example in terminal) will it pull up your vscode with all the associated files and to this location? At least that you might be able to back where the issue is in code?

problem accessing elements using id/name for login form in cypress

I am trying to login to a form written in angular js but cypress throws the following exception:
Uncaught TypeError: $(...).materialScrollTop is not a function
This error originated from your application code, not from Cypress.
When Cypress detects uncaught errors originating from your application it will automatically fail the current test.
This behavior is configurable, and you can choose to turn this off by listening to the 'uncaught:exception' event.
https://on.cypress.io/uncaught-exception-from-application
This is the cypress login code:
context('TestLogin', () => {
it('Test Login', () => {
cy.visit('url');
cy.get('input[id=Email]').type('email', {force: true});
cy.get('input[id=Password]').type('passcode', { force: true });
cy.get('button[type=submit]').click();
})
})
Since the login has a csrf token, I have used cy.request() as follows and I do get a response with status code 200 but when re-loading the site it goes back to login page.
describe("Tests for AntiForgeryToken", function () {
// variable from config, that contain Identity Server URL
const identityUrl = Cypress.config("identityServerUrl")
// command declaration that we are going to use in tests
// allows us to create request to server
Cypress.Commands.add("loginByToken", function (token, login, password) {
cy.request({
method: "POST",
failOnStatusCode: false,
url: `${identityUrl}/Account/Login`,
form: true,
body: {
email: login,
password: password,
__RequestVerificationToken: token,
RememberLogin: false
}
})
})
it("Should parse token from response body and return 200", function () {
cy.request(`${identityUrl}/Account/Login`)
.its("body")
.then((body) => {
const $html = Cypress.$(body)
// when the page is rendered
// we are trying to find the Request Token in the body of page
const token = $html.find("input[name=__RequestVerificationToken]").val()
// POST request with token and login data
// then we simply verify whether Indentity Server authorized us
cy.loginByToken(token, "test#test.com", "Test_1234")
.then((resp) => {
expect(resp.status).to.eq(200)
})
})
cy.visit(`${identityUrl}/Account/`);
})
Cypress documentation didn't provide much info about the exception.
Any insights from cypress experts are helpful.
As evident from the error, Cypress is failing the test as it found an exception in your application,this is not a cypress level exception but an uncaught exception in your app which is causing cypress to fail the test, this is pretty useful as you can check if its an actual error in your app and log it for the dev team to fix, check if you are able to reproduce this manually, either way i think the application code should be fixed to either fix the bug or catch the exception and return a valuable error message. If you want to disable this feature you can turn off all uncaught exception handling, so in your index.js or whatever file is the entry point add the following:
Cypress.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from
// failing the test
// you can also add a Debugger here to analyze the error
debugger;
return false;
});
not sure if turning this off will help as looks like there is something in your application which could be an issue, but this is just for informational purposes that you can turn this feature off if you needed to.
Here is the documentation for further reading : Cypress Events documentation
hope this helps

React native thunk "Possible unhandled promise" error despite providing onReject callback?

Using react native, getting a Possible Unhandled Promise Rejection error when using a firebase.Promise (https://firebase.google.com/docs/reference/js/firebase.Promise) in a redux action thunk (https://redux.js.org/advanced/asyncactions#actions-js-asynchronous), eg.
....
console.log(`Reuthenticating for user ${user.displayName}, ${user.email}`)
credentials = 'intentionally bad credential type'
user.reauthenticateAndRetrieveDataWithCredential(credentials)
.then(
(res) => {console.log(`Reauth complete: ${res}`)},
(error) => {console.log(`Something bad happend ${error}`)})
....
(authenticating as recommended here (https://firebase.google.com/docs/auth/web/manage-users#re-authenticate_a_user) via reauthenticateAndRetrieveDataWithCredential (https://firebase.google.com/docs/reference/js/firebase.User#reauthenticateAndRetrieveDataWithCredential)) produces the message
[18:45:12] Reuthenticating for user me, me#gmail.com
[18:45:14] Possible Unhandled Promise Rejection (id: 0):
[18:45:14] [Error: reauthenticateAndRetrieveDataWithCredential failed: First argument "credential" must be a valid credential.]
without printing the console.log() message (which indicates to me that this is not just a warning, but an actual error). Even though I am providing an onReject callback to .then() (https://firebase.google.com/docs/reference/js/firebase.Promise#then).
Some other SO posts suggest appending a .catch() to the promise (rather then providing an on onReject fallback callback in the promise's .then() like I do), but since am using a thunk action here, this is not recommended (see https://github.com/facebook/react/issues/6895#issuecomment-281405036). Anyone know what could be happening here or some steps to debug further?

Vue.js error in IE11

I am running Vue.js and have a component running on my page. The component works just fine in Chrome, Firefox etc, but in IE11 it is throwing the following error
Unhandled promise rejection SyntaxError: Invalid character
"Unhandled promise rejection"
{
[functions]: ,
__proto__: { },
description: "Invalid character",
message: "Invalid character",
name: "SyntaxError",
number: -2146827274,
stack: "SyntaxError: Invalid character
at Anonymous function (http://mydomain/js/app.js:6:21534)
at a (http://mydomain/js/app.js:7:5220)
at Anonymous function (http://mydomain/js/app.js:7:5344)
at c (http://mydomain/js/app.js:1:22805)"
}
This isn't telling me much and searching google has not helped. Does anyone know what the problem might be?
Thanks
I think your issue is that IE doesn't support promises. Any JS code that relies on using them, like
axios.get('some/url/')
.then(response => (this.dataThing = response.data));
... is going to fail. You can use polyfills to translate this into something that IE11 understands, but I am unclear on how to implement them.