Set UserAgent in Testcafe - testing

I've searched related topics. The most significant I found is this Setting user-agent in browsers with testcafe
But it doesn't provide any real aswers.
My goal is to run the test spoofing a different OS: Since I'm in Linux and the app I'm testing isn't supported for that, it shows a couple of warnings that I would want to get rid when tests are running.
We tried cypress, in which you just add the UserAgent string on a config file and that's it. But I haven't found a straightforward way of doing it on testcafe without a CLI parameter.
Is there a way to spoof an OS or userAgent in testcafe?

You can modify user-agent using the RequestHooks mechanism.
I prepared an example to demonstrate this approach:
import { RequestHook } from 'testcafe';
class UserAgentRequestHook extends RequestHook {
onRequest (e) {
e.requestOptions.headers['user-agent'] = 'Mozilla/5.0 (Android 4.4; Tablet; rv:41.0) Gecko/41.0 Firefox/41.0';
}
onResponse (e) {
}
}
const hook = new UserAgentRequestHook();
fixture `f`
.page `https://www.whatismybrowser.com/detect/what-is-my-user-agent/`;
test.requestHooks(hook)(`test`, async t => {
await t.debug();
});
Please note that TestCafe is using UserAgent internally, so incorrect UA value can lead to unpredictable results.

Related

Testcafe - run ClientFunction code on iframe

I need to access a public object available on an iframe scope but the code that I'm running on the ClientFunction gets executed on the parent, I managed to get it working using the --disable-web-security flag and accesing the frame like this window.frames['0'].store. (Not happy with that hack TBH)
But now looks like TestCafe updated to some newer version of Chromium and there's a message telling me that the flag is not allowed anymore.
Is there any way to run client code targetting a specific iframe without needing that nasty flag?
To run ClientFunction on an iframe, you need to switch to it beforehand.
const fn = ClientFunction(() => true);
test('test', async t => {
await t.switchToIframe('#iframe');
await fn();
});

Cypress doesn't work with an external login

I'm working on e2e test with cypress on my application.
In my case the login are manage by a external service.
When I want to enter in my application's home page (https://myApplication/home), the system redirects me in different superdomains to login.
At first cypress seems to be able to change the superdomain, but once arrived in external service page for the authentication, the system go in login error (as if we have already logged in, but incorrect).
This type of behavior does not happen outside the cypress .
Are there alternative solutions to manage external access in a cypress test or is it possible to manage it directly from cypress?
I added in my cypress.json the chromeWebSecurity:false and when I call the link for login, I added the failOnStatusCode: false,
but it still doesn't work.
Assuming this is caused by SameSite cookie blocking , then I've just been fighting the same issue. I resolved it by intercepting all requests, checking if they had a set-cookie header(s) and rewriting the SameSite attribute. There's probably a neater way to do it, as this does clutter up the cypress dashboard a little.
Sadly Zachary Costa's answer no longer works as Chrome 94 removed the SameSiteByDefaultCookies flag.
You can add this as a command for easy reuse:
In your commands file:
declare namespace Cypress {
interface Chainable<Subject> {
disableSameSiteCookieRestrictions(): void;
}
}
Cypress.Commands.add('disableSameSiteCookieRestrictions', () => {
cy.intercept('*', (req) => {
req.on('response', (res) => {
if (!res.headers['set-cookie']) {
return;
}
const disableSameSite = (headerContent: string): string => {
return headerContent.replace(/samesite=(lax|strict)/ig, 'samesite=none');
}
if (Array.isArray(res.headers['set-cookie'])) {
res.headers['set-cookie'] = res.headers['set-cookie'].map(disableSameSite);
} else {
res.headers['set-cookie'] = disableSameSite(res.headers['set-cookie']);
}
})
});
});
Usage:
it('should login using third party idp', () => {
cy.disableSameSiteCookieRestrictions();
//add test body here
});
or alteratively, run it before each test:
beforeEach(() => cy.disableSameSiteCookieRestrictions());
We were encountering a similar issue, where Cypress was redirecting us to the default "You are not logged in" page after getting through the login process. I'm not certain if that's EXACTLY the issue you were experiencing, but just in case, here's our solution. In our case, the issue was caused by Chrome's "Same Site Cookies" feature interacting poorly with Cypress, so we needed to disable it. In your plugins/index.js file, you would add the following code:
module.exports = (on, config) => {
on('before:browser:launch', (browser, launchOptions) => {
if (browser.name === 'chrome') {
launchOptions.args.push('--disable-features=SameSiteByDefaultCookies');
}
return launchOptions;
});
};
Note that if you already have launchOptions being set, you can just add this code onto it so it doesn't clash at all.
Hopefully, this works for you as well!
In the current version of cypress you can't go to another domain in the same test. This is due to the fact that cypress injects its test into the browser (they are working on this issue).
So one solution today is that you need to utilize cy.request to perform the login programmatically and inject the auth secret (jwt, cookie, localstorage, token or what you have) into the browser context yourself (for cookie this would be cy.setcookie).
Always make sure to checkout the plugins if there is already an abstraction for your login. Often this is openId or ntlm.

Running tests with flags from chrome cypress

I have some test cases that use webcam and our test enviroment needs for using webcam to have set flag in chrome --unsafely-treat-insecure-origin-as-secure
How can I for some test sets have this set in chrome with cypress?
Thanks
You can pass flags to the chrome browser in Cypress by writing a Cypress plugin as seen in the official documentation here: https://docs.cypress.io/api/plugins/browser-launch-api.html#Usage.
Navigate to your cypress/plugins directory and add the following code
module.exports = (on, config) => {
on('before:browser:launch', (browser = {}, launchOptions) => {
// `args` is an array of all the arguments that will
// be passed to browsers when it launches
if (browser.name === 'chrome') {
launchOptions.args.push('--unsafely-treat-insecure-origin-as-secure');
}
// whatever you return here becomes the launchOptions
return launchOptions;
});
};

XMLHttpRequest is not defined when testing react-native app with jest

i am trying to test a apiwrapper in a react-native based app using jest (integration testing).
When i run it in the iOs simulator everything runs fine however it wont run my jest tests correctly - i always get:
ReferenceError: XMLHttpRequest is not defined
when i try to run tests using my api wrapper, eg.:
it('Login successful with correct data', () => {
let api = Api.getInstance();
return api.login("test", "testpass")
.then(result => expect(result).toEqual('login_successful'));
});
the api class i am trying to test here does use the fetch api (not vanilla xhr). I assume its something related to jest trying to mock something but have not found a way to make it work yet.
Thanks in advance.
In my case, I'm not testing the search code but only importing it somewhere in my code path, so I decided to just mock it at the global level in a setup.js file (loaded using --require at test run). The following works for me:
// needed in react-instantsearch
class XMLHttpRequest {}
global.XMLHttpRequest = XMLHttpRequest;
I had a similar problem with lokka using XMLHttpRequest. I made a mock for lokka, which my api wrapper class depends on. You could try mocking your api wrapper.
This is what my lokka mock looks like for now. I'll add more to it when I start testing error handling.
export default class {
query() {
return new Promise(resolve => {
resolve(200);
});
}
}
You might be able to mock your api wrapper with something similar:
export default class Api {
getInstance() {
\\ However you implemented getInstance
}
login(user, password) {
return new Promise(resolve => {
resolve('login_successful');
});
}
}

How do you test AngularJS cookies in an end-to-end test?

I have a simple service that sets cookies in angular, but there's no obvious way to test that they've been set in an end-to-end test.
The code to test is as simple as
var splashApp = angular.module('splashApp', ['ngCookies']);
splashApp.controller('FooterController', function ($location, $cookies) {
$cookies.some_cookie = $location.absUrl();
});
But I can't find any docs on how to test. Here's what I have found:
How to access cookies in AngularJS?
http://docs.angularjs.org/api/ngCookies.$cookies
http://docs.angularjs.org/api/ngCookies.$cookieStore
I've also tried
angular.scenario.dsl('cookies', function() {
var chain = {};
chain.get = function(name) {
return this.addFutureAction('get cookies', function($window, $document, done) {
var injector = $window.angular.element($window.document.body).inheritedData('$injector');
var cookies = injector.get('$cookies');
done(null, cookies);
});
};
return function() {
return chain;
}
});
But this returns only the cookies for the parent browser, not the page I want to test.
Any examples on how to do this?
It seems like you need to use PhantomJS.
PhantomJS is a headless WebKit scriptable with a JavaScript API. It
has fast and native support for various web standards: DOM handling,
CSS selector, JSON, Canvas, and SVG. --PhantomJS website
It has support for custom cookies in its API.
In terms of testing, this is probably your best choice.
You might also want to look at CasperJS to help test page navigation.