Using different URLs for local and CI testing - continuous-integration

I want to use Cypress to test locally and on CI at the same time. On CI, I would like to test a production version of my application, which has a different baseUrl than the local version, obviously. I am using the https://github.com/bjowes/cypress-ntlm-auth package to ause windows authentication for the CI, and to do so I have to call cy.ntlm line in my tests. I want to make an IF function that calls the cy.ntlm line ONLY if the baseUrl matches the production one. If the baseUrl is localhost then I would like the cy.ntlm line to be ignored. So my bottom line questions are, how do I let cypress know that I want to use 2 different URLs and how do I pack that into an IF statement? Thank you

You can check the baseUrl to conditionally call cy.ntlm,
const baseUrl = Cypress.config('baseUrl')! // use non-null assertion operator
const isLocal = baseUrl.includes('localhost')
if (!isLocal) {
cy.ntlm(...)
}
When using Typescript with Cypress you will get complaints because Typescript has no idea if you have set the baseUrl configuration or not.
You can overcome that by adding ! after getting the baseUrl value.
Ref Typescript - Non-null assertion operator
I separated the steps to make it clearer.

Assuming your cypress config file has the baseUrl. You can then update the baseUrl using the CLI during run time. For this create two different scripts with the staging and production URL's in your package.json like this:
"scripts": {
"test:local": "cypress run --config baseUrl=https://example.com/staging",
"test:ci": "cypress run --config baseUrl=https://example.com/production"
}
Then to run the scripts in CI use npm run test:ci and for local use npm run test:local.

Related

How to pass values from command line to cypress spec file?

I have a few different environments in which I am running Cypress tests (i.e. envA, envB, envC)
I run the tests like so:
npm run cypress:open -- --env apiEndpoint=https://app-envA.mySite.com
npm run cypress:open -- --env apiEndpoint=https://app-envB.mySite.com
npm run cypress:open -- --env apiEndpoint=https://app-envC.mySite.com
As you can see, the apiEndpoint varies based on the environment.
In one of my Cypress tests, I am testing a value that changes based on the environment being tested.
For example:
expect(resourceTiming.name).to.eq('https://cdn-envA.net/myPage.html')
As you can see the text envA appears in this assertion.
The issue I'm facing is that if I run this test in envB, it will fail like so:
Expected: expect(resourceTiming.name).to.eq('https://cdn-envB.net/myPage.html')
Actual: expect(resourceTiming.name).to.eq('https://cdn-envA.net/myPage.html')
My question is - how can I update the spec files so that the correct URL is asserted when I run in the different environments?
I am wondering if there's a way to pass a value from the command line to the spec file to tell the spec file which environment I'm in, but I'm not sure if that's possible.
You can directly use the Cypress.env('apiEndpoint') in your assertions, so that whatever you're passing via CLI, your spec files has the same value -
expect(resourceTiming.name).to.eq(Cypress.env('apiEndpoint'))
And if you want to check that when you pass https://app-envA.mySite.com and the url you expect in the spec file is https://cdn-envA.net/myPage.html, You can use:
expect(resourceTiming.name).to.eq(Cypress.env('apiEndpoint').replace('app', 'cdn').replace('mySite.com', 'net') + '/myPage.html')
Your best bet, in my opinion, is to utilize environment configs (envA.json, envB.json, etc)
Keep all of the property names in the configs identical, and then apply the values based on the environment:
// envA.json file
"env": {
"baseUrl": "yourUrlForEnvA.com"
}
// envB.json file
"env": {
"baseUrl": "yourUrlForEnvB.com"
}
That way, you can call Cypress.env('baseUrl') in your test, and no matter what, the right property should be loaded in.
You would call your environment from the command line with the following syntax:
"cypress run --config-file cypress\\config\\envA.json",
This sets up the test run to grab the right config from the start.
Calling the url for login, for example, would be something like:
cy.login(Cypress.env('baseUrl'))
Best of luck to you!

jestjs - how to parametrize test execution from cli in ci?

i have 4 environments :
dev (developers area)
test (test area)
preprod (pre production environment)
production (production environment)
these environments needs different configuration to execute tests (differents urls, usernames, assets, and so on).
how to pass there configurations to jest as a parameter in continous integration?
As you can read here, jest would not permits to pass custom arguments you can use to handle custom configuration loaded at runtime.
i propose a workaround working for me.
create a configuration file, e.g. config.js
edit config.js and exports modules switching for the environment
switch (env) {
case "test":
module.exports = {
baseUrl: 'https://test.website.com'
}
break;
case "production":
module.exports = {
baseUrl: 'https://production.website.com'
}
break;
}
create a javascript files for every environment you need
test-configuration.js
production-configuration.js
edit these files writing in the environment variables
for example test-configuration.js will be
process.env.ENVIRONMENT = "test"
load configuration for your test files as it was a static file
const config = require('./config.js')
use jest setupFiles to add a setupFiles that load the environment variables.
for example, running
jest --setupFiles=./test-configuration.js
jest will load the test-configuration.js file that will set "test" on the "process.env.ENVIRONMENT" variables, so config.js file will "switch" on the "test" environment and all your test will use it.
so now you can (or CI can) loads configuration as needed.
For anyone facing the same issue – can't pass environment url to your custom setup file and tests. The solution might be dumb but it works without modifying the code much.
In package.json modify your scripts to export environment before running jest:
"scripts": {
"test": "jest",
"test:dev": "export ENVIRONMENT=https://dev.environment/ && jest",
"test:prod": "export ENVIRONMENT=https://prod.environment/ && jest"
}
Then you can access your code:
const page = await browser.newPage();
await page.goto(process.env.ENVIRONMENT);
console.log(process.env.ENVIRONMENT);

How can I use different Cypress.env() variables for Circle testing?

I am doing some automatic testing on Circleci, with different enviromental variables: I need one port for my local testing and a different one for Circleci.
How can I make Cypress do that? I tried making cypress.env.circle, but that does not seem to work
The cypress docs explain 5 ways to set variables.
To use one port locally and one on CircleCI I would:
Add a default port to cypress.json under the env section for local use so you don't have to think about it, and anyone else contributing will have a working version.
Set an environment variable in CircleCI named cypress_VAR_NAME which will override default in cypress.json
cypress.json example
{
"env": {
"the_port": 5000
}
}
CircleCI variable would then be cypress_the_port and you would read it in your specs as parseInt(Cypress.env('the_port')) (assuming your spec needs an integer for port)

How to reference script files in webpack deploy?

I am using webpack and electron and while I can reference my script files fine locally (app/scripts/scriptname.sh), when it comes to the production deploy, I get an error: Can't open app/components/scripts/scriptname.sh.
It's unclear to me if this is an electron-dependent issue or a webpack-issue.
I am running these using node child_process as:
var ls = spawn('sh', ['app/components/scripts/scriptname.sh']);
I don't necessarily need the scripts to be in their own folder it would just be helpful.
You need to provide the complete absolute path to the script. To do that you can use the app.getAppPath() API of electron
app.getAppPath()
Returns String - The current application directory.
So your code would be something like:
var scriptAbsolutePath = app.getAppPath() + '/app/components/scripts/scriptname.sh';
var ls = spawn('sh', [scriptAbsolutePath]);
You can also have a look at app.getPath(name) API if it satisfies your particular requirement.

How to use Mocha require option in Karma

I've been trying to use the mocha require option:
mocha mytest.js --require myglobals.js
But I don't know how to do it from karma. The idea is to run karma start and it will automatically require myglobals.js.
Is that possible to do it from within karma.conf.js or somehow else?
Maybe I'm not using karma/mocha in the right way.
My idea is:
I want to have unit/integration tests for both the client (react) and the server (node/express)
I want to just run karma start and both client and server tests are tested
I found very useful to have the following file pre-required, in order to avoid requiring some things in all tests:
myglobals.js:
const chai = require('chai');
// Load Chai assertions
global.expect = chai.expect;
global.assert = chai.assert;
chai.should();
// Load Sinon
global.sinon = require('sinon');
// Initialize Chai plugins
chai.use(require('sinon-chai'));
chai.use(require('chai-as-promised'));
chai.use(require('chai-things'));
For the server side I've made it work using the command:
mocha mytest.js --require myglobals.js
But still, I wanted to keep it running under the npm run test (which calls karma start) instead of creating another npm run test:server command.
Furthermore, I wanted to do the same on the client. I'm using webpack there as a preprocessor.
Any ideas if it is possible to accomplish that? Or maybe I'm in the wrong way?
Short Answer
Mocha in the browser does not support an equivalent of the --require option, but you do not need it. You can just load whatever you need ahead of your tests listing the files you want to load in files in front of your test files. Or if you use a loader like RequireJS, write a test-main.js that loads the modules you would load with --require first, and then load your test files.
Long Answer
If you look at Mocha's code you'll see that the only place --require is used is in the bin/_mocha file. This option is not passed further into the Mocha code but is immediately used to load the requested modules:
requires.forEach(function(mod) {
require(mod);
});
When you run Mocha in the browser, none of this code is run, and if you look in the rest of the Mocha code you won't find a similar facility anywhere else. Why?
Because it would serve no purpose. The --require option is very useful at the command line. Without it, the only way to load modules before Mocha loads the test files would be to either write custom code to start Mocha or put the necessary require calls at the start of every single test file.
In the browser, if you do not use a module loader, you can just load the code you'd load using --require by putting the script elements that load them in front of the script elements that load your tests. In Karma, this means putting these files earlier in the list of files you have in your karma.conf.js. Or if you use RequireJS, for instance, you write test-main.js so that the loading is done in two phases: one that loads the modules you'd load through --require on the command-line, and a second that loads your test files. It could be something like:
const allTestFiles = [];
const TEST_REGEXP = /test\/test.*\.js$/i;
Object.keys(window.__karma__.files).forEach((file) => {
if (TEST_REGEXP.test(file)) {
const normalizedTestModule = file.replace(/^\/base\/|\.js$/g, "");
allTestFiles.push(normalizedTestModule);
}
});
require.config({
baseUrl: "/base",
paths: {
...
},
});
// This guarantees that "a", "b", "c" loads before any other module
require(["a", "b", "c", ...], () => {
require(allTestFiles, window.__karma__.start);
});

Resources