We have protractor-cucumber framework as e2e test. Till now we use the conf file with statically mentioning the environment details inside the conf json. I would like to pass user defined arguments with the protractor_conf file something like below.
protractor protractor_conf.js -DbrowserName=chrome -DexecPlatform=(native/sauce)
and would like to fetch this argument inside the conf.js and substitute under the capabilities section. I could not get proper details on net, so any help/suggestions would be appreciated.
You can add Parameters in your conf.js file then pass the arugs from the command line.
Here is an example.
// The params object will be passed directly to the Protractor instance,
// and can be accessed from your test as browser.params. It is an arbitrary
// object and can contain anything you may need in your test.
// This can be changed via the command line as:
// --params.environment.Browser "Firefox"
params: {
environment: {
browser: 'Chrome',
execPlatform: 'sauce',
password: 'default'
}
}
Now from we can pass the arugs from command line
protractor conf.js --parameters.environment.browser= Firefox --parameters.environment.execPlatform=sauce --parameters.environment.password=password123
Next, you can also refer these parameters in your spec file.
describe('describe some test', function() {
it('describe some step', function() {
$('.password').sendKeys(browser.params.login.password);
});
});
There are multiple advantages to having a parameter setup.
If we know we are going to be using the same values in multiple spec files (i.e login email and password), parameters are great for removing unnecessary repetition.
Being able to change parameter values at runtime makes it easier to run the same tests with different data.
Increases security – Having passwords hardcoded in your spec files is not a great approach. Parameters give you the ability to keep them out and instead provide them at runtime.
You can use process api to parse the arguments in cmd line.
// protractor conf.js
var readParamsFromCli = function() {
var paramsPair = process.argv.slice(3).filter(function(it){
return it.startsWith('-D');
});
var params = {};
paramsPair.forEach(function(pair){
var parts = pair.split('=');
var name = parts[0].trim().replace('-D', '');
var value = parts[1] && parts[1].trim() || true;
params[name] = value;
});
return params;
};
var params = readParamsFromCli();
var capbilities = {
browserName: params.browserName || 'chrome',
platform: params.execPlatform
};
exports.config = {
...
capbilities: capbilities
};
Then you can run case as following:
protractor protractor_conf.js -DbrowserName=chrome -DexecPlatform=native
You could split the configuration up into multiple config files. For example protractor-chrome.conf.js:
const baseConf = require('./protractor.conf').config;
exports.config = Object.assign({
capabilities: {
browserName: 'chrome'
}
}, baseConf);
This will be similar to 2nd example but uses the config file directly.
const args = require('minimist')(process.argv.slice(2));
exports.config = {
//your config stuff
baseUrl: args.Url ? args.URL : <your default>,
capabilities: {
'browserName': 'chrome',
chromeOptions: {
args: [args.Options]
},
}
}
Then in your package.json script like this:
"e2e": "protractor protractor.conf.js --Url=http://test.com" --Options=--headless
Related
Consider the following.
node file1.js && react-scripts start
I am trying to make an API call to the GCP Secret Manager in file1.js. After the request is received, I want to set them as environment variables under process.env. After that, I want to access them in the frontend. The browser can't make a call to that Secret Manager without OAuth. Is there any way I can share process.env between these two scripts?
File1 code
const {SecretManagerServiceClient} = require('#google-cloud/secret-manager');
// Instantiates a client
const client = new SecretManagerServiceClient();
const firebaseKeysResourceId = 'URL'
const getFireBaseKeys=async()=> {
const [version] = await client.accessSecretVersion({
name: firebaseKeysResourceId,
});
// Extract the payload as a string.
const payload = JSON.parse(version?.payload?.data?.toString() || '');
process.env.TEST= payload.TEST
return payload
}
getFireBaseKeys()
Expanding on my comment
Method 1 - kind of neat but unneccessary
Supposing you had these vars you wanted in the environment:
const passAlong = {
FOO: 'bar',
OAUTH: 'easy-crack',
N: 'eat'
}
Then at the end of file1.js you would do this
console.log(JSON.stringify(passAlong));
Note you cannot print anything else in file1.js
Then you would call your script like this
PASSALONG=$(node file1.js) react-script start
And at the beginning of react-script you would do this to populate the passed along variables into the environment.
const passAlong = JSON.parse(process.env.PASSALONG);
Object.assign(process.env,passAlong);
Method 2 - what I would do
Using the spawn method would involve just setting process.env how you like in file1.js and then adding something like this at the end of file1.js
// somewhere along the way
process.env.FOO = 'bar';
process.env.OAUTH = 'easy-crack';
process.env.N = 'eat';
// at the end of the script
require('child_process').spawnSync(
'node', // Calling a node script is really calling node
[ // with the script path as the first argument
'/path/to/react-script', // Using relative path will be relative
'start' // to where you call this from
],
{ stdio: 'inherit' }
);
I have a grunt task that runs all of my nodejs server side test files.
grunt.registerTask('serverTest', ['env:test', 'mongoose', 'mochaTest']);
While developing tests I would like to only run the test I'm currently working on. My task is setup to run a list of all test assets in the code base:
mochaTest: {
src: testAssets.tests.server,
options: {
reporter: 'spec'
}
},
I would like to specify a filter parameter at the cli to only select a specific file from testAssets.tests.server which is a big list of tests since it's defined as modules/*/tests/server/**/*.js and returns every test in the code base.
For example if I entered the following at the command line:
grunt serverTest:*fileUnderTest.js
Grunt would filter the testAssets.tests.server and only execute the files that match *fileUnderTest.js
I've read through the documentation and seen a lot of examples but can't figure out how to do this without creating a separate target and specifying the file name in the grunt file.
There's probably a more efficient means but the following code at the start of my gruntfile got the filtering working for me.
// get regex epression from CLI
var expression = grunt.option('filter');
//filter the testAssets.tests.server array
var testFiles = filtered(getGlobbedPaths(testAssets.tests.server),expression);
// test array with regex and return array of matches
var filtered = (function(arr,pattern){
var filtered = [],
i = arr.length,
re = new RegExp(pattern);
while (i--) {
if (re.test(arr[i])) {
filtered.push(arr[i]);
}
}
return filtered;
});
And then the grunt task becomes:
mochaTest: {
src: testFiles,
options: {
reporter: 'spec'
}
}
grunt.registerTask('serverTest', ['env:test', 'mongoose', 'mochaTest']);
So a command line call such as:
grunt serverTest --filter=comment.server.model.tests.js
Will run any test file matching the filter and a command like:
grunt serverTest
Will run all test files in the project
For reference my project is based on meanjs which globs all the paths to files so I run the getGlobbedPaths() function which is defined in config.js to first expand the file path array prior to filtering:
var getGlobbedPaths = function(globPatterns, excludes) {
// URL paths regex
var urlRegex = new RegExp('^(?:[a-z]+:)?\/\/', 'i');
// The output array
var output = [];
// If glob pattern is array so we use each pattern in a recursive way, otherwise we use glob
if (_.isArray(globPatterns)) {
globPatterns.forEach(function(globPattern) {
output = _.union(output, getGlobbedPaths(globPattern, excludes));
});
} else if (_.isString(globPatterns)) {
if (urlRegex.test(globPatterns)) {
output.push(globPatterns);
} else {
glob(globPatterns, {
sync: true
}, function(err, files) {
if (excludes) {
files = files.map(function(file) {
if (_.isArray(excludes)) {
for (var i in excludes) {
file = file.replace(excludes[i], '');
}
} else {
file = file.replace(excludes, '');
}
return file;
});
}
output = _.union(output, files);
});
}
}
return output;
};
Hi I have the following simple nightwatch demo script which is looping when ran with multiple browser environment, but which works fine if I run the test with single browser.
Following arguments loops the test:
var argv = {
test: 'nightwatchgoogletest.js',
config: 'nightwatch.json',
reporter: 'junit',
env : 'default,chrome'
};
Following works fine:
var argv = {
test: 'nightwatchgoogletest.js',
config: 'nightwatch.json',
reporter: 'junit',
env : 'chrome' (or default or any single browser)
};
Following is my code, please let me know what am I doing wrong here.
nightwatchgoogletest.js :
module.exports = {
'Demo test Google' : function (client) {
client
.url('http://google.no')
.pause(1000);
// expect element to be present in 1000ms
client.expect.element('body').to.be.present.before(1000);
// expect element <#lst-ib> to have css property 'display'
client.expect.element('#lst-ib').to.have.css('display');
// expect element to have attribute 'class' which contains text 'vasq'
client.expect.element('body').to.have.attribute('class').which.contains('vasq');
// expect element <#lst-ib> to be an input tag
client.expect.element('#lst-ib').to.be.an('input');
// expect element <#lst-ib> to be visible
client.expect.element('#lst-ib').to.be.visible;
client.end();
}
};
And have written the following node script to call above test:
var Nightwatch = require('nightwatch');
function proceess_test() {
try {
var argv = {
test: 'nightwatchgoogletest.js',
config: 'nightwatch.json',
reporter: 'junit',
env : 'default,chrome'
};
console.log("\n>> Initiating Tests for ...",process.env.__NIGHTWATCH_ENV_KEY);
var settings = {};
var done = function() {console.log("done")};
Nightwatch.runner(argv, done, settings);
done();
} catch (error) {
console.log('Exception: ' + error.message);
}
}
proceess_test();
With the following nightwatch configuration:
http://www.jsoneditoronline.org/?id=7e8e1616d595417ceeafaccc6358b33d
But when I run the test, it going in an infinite testing loop as follows:
I have Gulpfile with jshint configured to use jshint-stylish reporter. I need to pass option verbose to reporter in order to display warning codes. Is it possible to do it using Gulp?
Current my gulpfile.js looks like below:
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var compass = require('gulp-compass');
var path = require('path');
require('shelljs/global');
var jsFiles = ['www/js/**/*.js', '!www/js/libraries/**/*.js', 'www/spec/**/*.js', '!www/spec/lib/**/*.js'];
var sassFiles = 'www/sass/*.scss';
gulp.task('lint', function () {
return gulp
.src(jsFiles)
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'));
});
gulp.task('compass', function () {
gulp.src(sassFiles)
.pipe(compass({
project: path.join(__dirname, 'www'),
css: 'css',
sass: 'sass',
image: 'img',
font: 'fonts'
})).on('error', function() {});
});
var phonegapBuild = function (platform) {
if (!which('phonegap')) {
console.log('phonegap command not found')
return 1;
}
exec('phonegap local build ' + platform);
};
gulp.task('build:android', ['lint', 'compass'], function () {
phonegapBuild('android');
});
gulp.task('build:ios', ['lint', 'compass'], function () {
phonegapBuild('ios');
});
gulp.task('watch', function() {
gulp.watch(jsFiles, ['lint']);
gulp.watch(sassFiles, ['compass']);
});
gulp.task('default', ['lint', 'compass']);
Well, this, plus the fact that the output of the stylish reporter is hardly readable on Windows due to the darkness of the blue text, so I have to keep going in an manually changing the colour after installing it, has made me do something about it. So you should hopefully have more luck with this reporter I've just written:
https://github.com/spiralx/jshint-summary
You basically use it like this;
var summary = require('jshint-summary');
// ...
.pipe(jshint.reporter(summary({
verbose: true,
reasonCol: 'cyan,bold',
codeCol: 'green'
})
and the summary function will initialise the function passed to JSHint with those settings - see the page on Github for a bit more documentation.
It's got some very basic tests, and the library's gulpfile.js uses it to show its own JSHint output :)
How about using similar technique, as you already did with phonegap?
var jshint = function (parameter) {
// todo: define paths with js files, or pass them as parameter too
exec('jshint ' + paths + ' ' + parameter);
};
Based on https://github.com/wearefractal/gulp-jshint/blob/master/index.js#L99 it appears that gulp-jshint doesn't facilitate passing more than the name to the reporter if you load it with a string. It seems a simple thing to extend though. I'll race you to a pull request. :D
Alternatively, try something like this:
var stylish = require('jshint-stylish');
// ...
.pipe(jshint.reporter(stylish(opt)));
I'm pretty sure I have the syntax wrong, but this may get you unstuck.
It's annoying, and makes any decent reporter somewhat tricky to use within the existing framework. I've come up with this hack for the Stylish reporter, it's just currently in my gulpfile.js:
function wrapStylishReporter(reporterOptions) {
var reporter = require(stylish).reporter,
reporterOptions = reporterOptions || {};
var wrapped = function(results, data, config) {
var opts = [config, reporterOptions].reduce(function(dest, src) {
if (src) {
for (var k in src) {
dest[k] = src[k];
}
}
return dest;
}, {});
reporter(results, data, opts);
};
return jshint.reporter(wrapped);
}
And then for the task definition itself:
gulp.task('lint', function() {
return gulp.src('+(bin|lib)/**/*.js')
.pipe(jshint())
.pipe(wrapStylishReporter({ verbose: true }))
.pipe(jshint.reporter('fail'));
});
Ideally reporters would either be a function that takes an options parameter and returns the reporter function, or a fairly basic class so you could have options as well as state.
I've been trying to use requirejs and js-test-driver along side, and I can't seen to get it working.
I have a minimal configuration like this at the root :
server: http://localhost:9876
load:
- src/main/resources/web/resources/vendor/requirejs/require.js
test:
- src/test/js/*.js
A "src/main/js/greeter.js" file defines a silly module :
define(function(require) {
myapp = {};
myapp.Greeter = function() {
};
myapp.Greeter.prototype.greet = function(name) {
return "Hello " + name + "!";
};
return myapp;
});
And I'm trying to let require load the greeter module in a "src/test/js/greeterTest.js" :
GreeterTest = TestCase("GreeterTest");
require.configure({ ???? });
require([ "src/main/js/greeter" ], function(myapp) {
GreeterTest.prototype.testGreet = function() {
var greeter = new myapp.Greeter();
assertEquals("Hello World!", greeter.greet("World"));
};
});
Whenever I run this, I get an error because myapp is not defined when creating the Greeter.
So is there a way I can configure require in this case ? I tried :
setting the baseUrl property to something like file:///.... to give the location of the file
using the gateway configuration to proxy the requests that requirejs might do (although I have no server running to serve the js files, so again I had to use file:///)
Is there something else I should try ?
Thanks
Turns out it is possible, but poorly documented :
js-test-driver has a 'serve' settings that lets the test server responds static files
once served, the files are available at localhost:42442/test/xxxx (The 'test' prefix is never mentionned, except in a comment low in the doc page).
So this works :
server: http://localhost:9876
load:
- src/main/resources/web/resources/vendor/requirejs/require.js
test:
- src/test/js/*.js
serve:
- src/main/js/*.js
And requirejs has to be configured like this :
require({
baseUrl : "/test/src/main/js"
}, [ "greeter" ], function(myapp) {
GreeterTest = TestCase("GreeterTest");
GreeterTest.prototype.testGreet = function() {
var greeter = new myapp.Greeter();
assertEquals("Hello World!", greeter.greet("World"));
};
});
Notice :
the / before the tests
the fact that you have to reuse the "src/main/js" part ; I guess that is linked to the fact that my jsTestDriver config is located at the same level as the "src" folder, and
it might needs some tweaking if placed otherwise.