How can I ignore the actual dotenv (.env) file while running in jenkins - node.js

In cypress how can I ignore the dotenv (.env) file while running in jenkins, as jenkins run on actual environment variables. Now I am getting No such file or directory open/student-proj/.env
How can I check if it is running in jenkins then use actual env variables else use .env ?
plugins/index.js
const configEnv = require('dotenv').config();
const cucumber = require('cypress-cucumber-preprocessor').default;
module.exports = (on, config) => {
on('file:preprocessor', cucumber());
if (configEnv.error) {
throw configEnv.error;
}
const env = { ...config.env, ...configEnv.parsed };
const envData = { ...config, env };
return envData;
}

why not just use a jenkins env variable specific in your code e.g. JOB_NAME ... if the value returns null... that means its not running on jenkins

Related

NodeJS + WebPack setting client static data

I have a NodeJS/React/WebPack application that I'm trying to take environment variables that are present at build time and export them as variables that are available to the client without having to request them with AJAX.
What is currently setup is a /browser/index.js file with a method that is exported however the variables are not getting expanded when webpack runs.
function applicationSetup()
{
const config = JSON.parse(process.env.CONFIG);
const APPLICATION_ID = process.env.APPLICATION_ID;
.........
}
During the build process we run node node_modules/webpack/bin/webpack.js --mode production with npm.
What do I need to do in order to expand the environment variable to be their actual values when webpack creates the .js file?
Edit 8/23
I've tried adding it in the webpack.DefinePlugin section of the webpack.config.js file however it's still doesn't seem to be available in the client side code. What am I missing?
Edit #2 (webpack.config.js)
const getClientConfig = (env, mode) => {
return {
plugins: [
new webpack.DefinePlugin({
__isBrowser__: 'false',
__Config__: process.env.CONFIG,
__ApplicationID__:process.env.APPLICATION_ID
})]
}
module.exports = (env, options) => {
const configs = [
getClientConfig(options.env, options.mode)
];
return configs;
};

Where do i need to set karate.config.dir to run my tests in multiple environments

My current config file looks something like this:
function() {
var env = karate.env;
karate.log('karate.env system property was:', env);
karate.configure('ssl', true);
if (!env) {
env = 'dev';
}
var config = {
env: env,
internalGateway: 'https://gateway.com.au',
externalGateway: 'https://gateway.com.au',
GatewayManagerURL: 'https://manager.com.au'
}
if (env == 'dev') {
}
else if (env == 'e2e') {
}
return config;
}
This is the only file I have for environments. I am unsure as to how can I run my tests in multiple environments.
Do I need to create a new karate.config.<env>.js file (as per the docs) to run my tests in a new environment?
You need only this one file. Now the config JSON returned has some default values set. What you can do now is have different values for e2e, for example:
else if (env == 'e2e') {
config.internalGateway = 'https://gateway-e2e.com.au';
}
And when you run your tests, you switch environments on the command-line. This is just setting a Java System Property. There are many other ways to do this:
mvn test -DargLine="-Dkarate.env=e2e"
All this is explained here: https://github.com/intuit/karate#switching-the-environment

Test process.env with Jest

I have an application that depends on environmental variables like:
const APP_PORT = process.env.APP_PORT || 8080;
And I would like to test that for example:
APP_PORT can be set by a Node.js environment variable.
or that an Express.js application is running on the port set with process.env.APP_PORT
How can I achieve this with Jest? Can I set these process.env variables before each test or should I mock it somehow maybe?
The way I did it can be found in this Stack Overflow question.
It is important to use resetModules before each test and then dynamically import the module inside the test:
describe('environmental variables', () => {
const OLD_ENV = process.env;
beforeEach(() => {
jest.resetModules() // Most important - it clears the cache
process.env = { ...OLD_ENV }; // Make a copy
});
afterAll(() => {
process.env = OLD_ENV; // Restore old environment
});
test('will receive process.env variables', () => {
// Set the variables
process.env.NODE_ENV = 'dev';
process.env.PROXY_PREFIX = '/new-prefix/';
process.env.API_URL = 'https://new-api.com/';
process.env.APP_PORT = '7080';
process.env.USE_PROXY = 'false';
const testedModule = require('../../config/env').default
// ... actual testing
});
});
If you look for a way to load environment values before running the Jest look for the answer below. You should use setupFiles for that.
Jest's setupFiles is the proper way to handle this, and you need not install dotenv, nor use an .env file at all, to make it work.
jest.config.js:
module.exports = {
setupFiles: ["<rootDir>/.jest/setEnvVars.js"]
};
.jest/setEnvVars.js:
process.env.MY_CUSTOM_TEST_ENV_VAR = 'foo'
That's it.
Another option is to add it to the jest.config.js file after the module.exports definition:
process.env = Object.assign(process.env, {
VAR_NAME: 'varValue',
VAR_NAME_2: 'varValue2'
});
This way it's not necessary to define the environment variables in each .spec file and they can be adjusted globally.
In ./package.json:
"jest": {
"setupFiles": [
"<rootDir>/jest/setEnvVars.js"
]
}
In ./jest/setEnvVars.js:
process.env.SOME_VAR = 'value';
You can use the setupFiles feature of the Jest configuration. As the documentation said that,
A list of paths to modules that run some code to configure or set up
the testing environment. Each setupFile will be run once per test
file. Since every test runs in its own environment, these scripts will
be executed in the testing environment immediately before executing
the test code itself.
npm install dotenv dotenv that uses to access environment variable.
Create your .env file to the root directory of your application and add this line into it:
#.env
APP_PORT=8080
Create your custom module file as its name being someModuleForTest.js and add this line into it:
// someModuleForTest.js
require("dotenv").config()
Update your jest.config.js file like this:
module.exports = {
setupFiles: ["./someModuleForTest"]
}
You can access an environment variable within all test blocks.
test("Some test name", () => {
expect(process.env.APP_PORT).toBe("8080")
})
Expanding a bit on Serhan C.'s answer...
According to the blog post How to Setup dotenv with Jest Testing - In-depth Explanation, you can include "dotenv/config" directly in setupFiles, without having to create and reference an external script that calls require("dotenv").config().
I.e., simply do
module.exports = {
setupFiles: ["dotenv/config"]
}
In test file:
const APP_PORT = process.env.APP_PORT || 8080;
In the test script of ./package.json:
"scripts": {
"test": "jest --setupFiles dotenv/config",
}
In ./env:
APP_PORT=8080
In my opinion, it's much cleaner and easier to understand if you extract the retrieval of environment variables into a utility (you probably want to include a check to fail fast if an environment variable is not set anyway), and then you can just mock the utility.
// util.js
exports.getEnv = (key) => {
const value = process.env[key];
if (value === undefined) {
throw new Error(`Missing required environment variable ${key}`);
}
return value;
};
// app.test.js
const util = require('./util');
jest.mock('./util');
util.getEnv.mockImplementation(key => `fake-${key}`);
test('test', () => {...});
Depending on how you can organize your code, another option can be to put the environment variable within a function that's executed at runtime.
In this file, the environment variable is set at import time and requires dynamic requires in order to test different environment variables (as described in this answer):
const env = process.env.MY_ENV_VAR;
const envMessage = () => `MY_ENV_VAR is set to ${env}!`;
export default myModule;
In this file, the environment variable is set at envMessage execution time, and you should be able to mutate process.env directly in your tests:
const envMessage = () => {
const env = process.env.MY_VAR;
return `MY_ENV_VAR is set to ${env}!`;
}
export default myModule;
Jest test:
const vals = [
'ONE',
'TWO',
'THREE',
];
vals.forEach((val) => {
it(`Returns the correct string for each ${val} value`, () => {
process.env.MY_VAR = val;
expect(envMessage()).toEqual(...
you can import this in your jest.config.js
require('dotenv').config()
this work for me
All the above methods work if you're using require("dotenv").config within the jest.config.js file, a NodeJS application without TypeScript such as what Jialx or Henry Tipantuna has suggested.
But if you're using ts-jest and within the jest.config.ts file.
import dotenv from "dotenv"
dotenv.config()
/* config options below */
When using Typescript the following works for me:
in root:
jest.config.js
/* eslint-disable #typescript-eslint/no-var-requires */
const { pathsToModuleNameMapper } = require('ts-jest');
const { compilerOptions } = require('./tsconfig.paths.json');
module.exports = {
// [...]
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' }),
};
process.env = Object.assign(process.env, {
env_name: 'dev',
another_var: 'abc123',
});
To build upon #HenryTipantuña's suggestion is to import dotenv in your jest.config.js and use a .env.test file in the config path
require('dotenv').config({
path: '.env.test'
})
Building on top of #jahller's answer.
I made it responsive so you don't need to keep the files in sync as things change.
Put this at the bottom of your jest.config.js file.
const arr = require('fs')
.readFileSync('.env', 'utf8')
.split('\n')
.reduce((vars, i) => {
const [variable, value] = i.split('=')
vars[variable] = value
return vars
}, {})
process.env = Object.assign(process.env, arr)
It reads the contents of your .env file, splits every new line and reduces it all back down to an object where you then assign it to process.env
OR
just use dotenv in jest.setup.js 🤷‍♂️
i have most simple for implementation env (specialy test.env)
require("dotenv").config({ path: './test.env' });
const { sum } = require('./sum.js');
describe('sum', () => {
beforeEach(() => {
jest.resetModules(); // remove cache
})
test('should success', () => {
expect(sum(1, 3)).toEqual(4);
})
})
I think you could try this too:
const currentEnv = process.env;
process.env = { ENV_NODE: 'whatever' };
// test code...
process.env = currentEnv;
This works for me and you don't need module things

Set NODE_ENV from Grunt task

I would like to set the NODE_ENV variable at the beginning of a Grunt task, to development or production, but it looks it's not as simple as I thought.
The reason, why I would like this is that I use grunt-webpack, which expects NODE_ENV to be set correctly to "development" or "production". But I also would like to initialize my tasks exclusively from grunt, if possible.
I created the following test Gruntfile, using the grunt-shell and cross-env modules:
function log(err, stdout, stderr, cb, e) {
if (err) {
cb(err);
return;
}
console.log(process.env.NODE_ENV);
console.log(stdout);
cb();
}
module.exports = function(grunt) {
grunt.initConfig({
shell: {
dev: {
command : 'cross-env NODE_ENV="development"',
options: {
callback: log
}
},
dist: {
command : 'cross-env NODE_ENV="production"',
options: {
callback: log
}
}
}
});
grunt.loadNpmTasks('grunt-shell');
};
Line 6 of log() should echo the actual value of process.env.NODE_ENV, but it constantly says undefined, even if I check it manually in the node console.
If I set it manually from the terminal, like set NODE_ENV=production (set is for Windows), everywhere echoes the value production, as I would like it to.
Your test won't work because grunt-shell runs a child_process and your callback runs after it ends and under the main process.
Same thing would happen with cross-env.
If you want to pass an environment variable to grunt-shell, you should use the options configuration according to the documentation.
For example:
grunt.initConfig({
shell: {
dev: {
command : 'echo %NODE_ENV%', //windows syntax
options: {
execOptions: {
env: {
'NODE_ENV': 'dev'
}
},
callback: log
}
}
}
});
This will still print undefined for process.env.NODE_ENV, but the value of NODE_ENV will be available in the stdout because of the echo.
On a side note, it sounds like you're trying to run a process (grunt-shell), which runs a process (cross-env), which runs a process (webpack or grunt-webpack).
Why not just use the cross-env example usage? It looks pretty close to what you need.
Or you can just define the variable in the task config itself and lose all of these wrappers.
LifeQuery's answer helped me a lot to find out what the problem actually was. I first realized that webpack.DefinePlugin() actually doesn't change anything on process.env.NODE_ENV (and it would be too late anyway, as it transforms code parsed by webpack after all loaders).
After this I created a solution, which does what I want. This is how my customized Gruntfile.js begins:
'use strict';
const path = require('path');
const webpack = require('webpack');
module.exports = function (grunt) {
// Setting the node environment based on the tasks's name or target
let set_NODE_ENV = function () {
const devTasks = ['webpack-dev-server', 'dev', 'hmr', 'watch'],
devTargets = [':dev'],
task = grunt.cli.tasks[0], // The name of the (first) task we initialized grunt with ('webpack-dev-server' if started 'grunt webpack-dev-server)
target = ':'+grunt.option('target'),
devEnv = (devTasks.indexOf(task) > -1 || devTargets.indexOf(target) > -1);
process.env.NODE_ENV = devEnv ? 'development' : 'production';
}();
const webpackConfig = require('../assets/webpack.config');
grunt.initConfig({
// ...usual Gruntfile content
});
};
I created a whitelist of grunt task names and targets when I set the process.env.NODE_ENV. As it is placed before the grunt.initConfig(), the configuration object can use process.env.NODE_ENV with the desired state.
It will set NODE_ENV to "development" if starting definitely webpack-dev-server, dev, hmr or watch tasks, or any other tasks with the :dev target.

gulp.js+browserify: Dynamically generate development-specific files

I have an application that has some development-specific debugging code in it. Currently, all development code is guarded by a variable called dev at the top of the file. Here's an example of what my app does:
var dev = true;
if (dev) {
console.log("Hello developer");
} else {
console.log("Hello production");
}
When I go to deploy my application, I have to manually change the dev variable form true to false. This sucks.
I'm in the middle of migrating from hand-rolled builds to gulp.js and I want to solve this development vs. production build problem cleanly. I'm thinking about the following:
// Inside main.js
var dev = require('./isdev');
if (dev) //...
// Inside isdev.js:
module.exports = true;
Now, when I build for production, instead of manually setting the dev flag to false, I want to replace isdev.js from module.exports = true; to module.exports = false;. My specific question is, how do I automate gulp such that gulp development produces a file with dev = true and gulp production produces a file with dev = false.
Here's an update to those who are curious.
First, I have an options.js:
exports.dev = false;
I also have a options_dev.js:
exports.dev = true;
Inside of gulpfile.js, I have the following code that parses input arguments:
// Parse the arguments. Use `gulp --prod` to build a production extension
var argv = parseArgs(process.argv.slice(2));
var dev = !argv['prod']; // Whether to build a development extension or not
Finally, when I pipe to browserify, I have the following:
var resolve = require('browser-resolve');
// ...
.pipe(browserify({
debug: dev,
resolve: function(pkg, opts) {
// Replace options.js with options_dev.js if this is a dev build
if (dev) {
opts.modules['./options'] = 'src/options_dev.js';
}
return resolve.apply(this, arguments);
}
}))
The magic happens by using a custom resolve function, dynamically swapping ./options with options_dev for development builds. The browserify docs say:
You can give browserify a custom opts.resolve() function or by default it uses browser-resolve.
When we run gulp, we build a development version. When we run gulp --prod, we build a production version. The value of require('./options').dev allows us to dynamically change things like server endpoints, etc. Cool!
The way that I've seen this done is to set the environment variable on the command line before the execution command. An example of doing this with the Node.JS CLI (in a bash-like environment) would be:
ENV=dev node
> process.env.ENV
'dev'
Then in your code, you could do:
var dev = process.env.ENV === 'dev'
So with gulp, you could use:
ENV=dev gulp <task name>
I tested this out with the following snippet, and it works:
gulp.task('dev', function(){
if (process.env.ENV === 'dev')
console.log("IT WORKED");
else
console.log("NO DICE");
});
Edit:
You can write out the environment to the file isdev right before building:
var fs = require('fs');
gulp.task('build', function(){
if (process.env.ENV === 'dev')
fs.writeFileSync('isdev', 'module.exports = true');
else
fs.writeFileSync('isdev', 'module.exports = false');
// kick off build
});
Now, the correct value will be present in isdev for any require call in the built bundle. You could extend this to other specified environments as well (or to other configuration flags).

Resources