How we can generate html report in cucumber latest version(3.2.0) with protractor-cucumber framework - protractor

Since cucumber 3 removed the registerHandler and registerListener , how we can generate html report in cucumber 3.2.0.I have used below code for generating json report in cucumber 2.
defineSupportCode(function({ registerListener }) {
var JsonFormatter = new Cucumber.JsonFormatter();
JsonFormatter.log = function(string) {
var outputDir = 'testreports/report';
var fileName = 'cucumber-report.json';
var targetJson = path.resolve(outputDir, fileName);
if (fse.existsSync(outputDir)) {
fse.moveSync(outputDir, outputDir + '_' + moment().format('YYYYMMDD_HHmmss'), {
overwrite: true
});
}
fse.outputFileSync(targetJson, string);
};
registerListener(JsonFormatter);
});
and used below code for html report
defineSupportCode(function({ registerHandler }) {
registerHandler('AfterFeatures', function(features, callback) {
var options = {
theme: 'bootstrap',
jsonFile: 'testreports/report/cucumber-report.json',
output: 'testreports/report/cucumber-report.html',
reportSuiteAsScenarios: true,
};
reporter.generate(options);
callback();
});
});
Thanks in advance.

You have to do following changes:
1) set cucumberOpts.format in protractor conf file
cucumberOpts: {
format: ["json:reports/report/cucumber/cucumber-report.json"],
here reports/report/cucumber/cucumber-report.json is the cucumber json file path, you must specify a path at here.
framework will generate it automatically with results' json data as file content when all scenarios execute complete.
2) create parent folder of cucumber json file path before test framework load if parent folder not exist
Option 1: put create parent folder code at head of protractor conf file.
Option 2: create a Protractor plugin implement interface: setup(), which will be executed before test framework load.
// plugin: create-report-folder.js
var moment = require("moment");
var fse = require("fs-extra");
module.exports = {
setup: function() {
var reportDir = this.config.options.reportDir;
if (fse.existsSync(reportDir)) {
fse.moveSync(
reportDir,
reportDir + "_" + moment().format("YYYYMMDD_HHmmss"),
{ overwrite: true}
);
}
fse.mkdirsSync(reportDir);
}
};
Note: both options need to use Sync api to create folder.
3) create Protractor plugin implement interface: postResults which will be executeed after all scenarios execute complete.
// plugin: cucumber-html-reporter.js
var reporter = require("cucumber-html-reporter");
module.exports = {
postResults: function() {
var options = {
theme: "bootstrap",
jsonFile: this.config.options.jsonFile,
output: this.config.options.htmlFile,
reportSuiteAsScenarios: true
};
reporter.generate(options);
}
};
Note: I tried generate cucumber html report in cucumber AfterAll hook, but failed, seems Cucumber JsonFormater generate cucumber json file is Async, when AfterAll hook start execute, cucumber json file have not create yet.
I'm keeping look into formatOption, should be a way to change JsonFormater generate cucumber json file to Sync, then we can use AfterAll hook.
4) set plugins in protractor conf file
// protractor conf file
exports.config = {
plugins: [
// plugin to create report parent folder
{
path: "supports/create-report-folder.js",
options: {
reportDir: "reports/report/cucumber"
}
}
// plugin to generate cucumber html report
{
path: "supports/cucumber-html-reporter.js",
options: {
jsonFile: "reports/report/cucumber/cucumber-report.json",
htmlFile: "reports/report/cucumber/cucumber-report.html"
}
}
]
A workable scaffold for Protractor + Cucumber4 + HTML Report at my github
The scaffold for Protractor + Cucumber3 + HTML Report on my local has some dependency campatible issue, I'm looking into that in case you must use Cucumber 3.
5) If you use multiCapabilities, you can use below package to generate report:
protractor-multiple-cucumber-html-reporter-plugin

If the location of protractor.conf.js is not at the same level as node_modules then the cucumberOpts.format path would be relative to its current file location and the protractor-multiple-cucumber-html-reporter-plugin looks for the json files relative to parent root folder and warns about json file is not found.
To solve this provide absolute path of the json file to cucumberOpts.format like below. This is applicable if you're using cucumber for e2e testing in Angular applications where the protractor.conf.js is normally present inside e2e folder.
cucumberOpts: {
require: [path.resolve(process.cwd(), 'e2e/steps/*.ts')],
format: 'json:'+ path.resolve(process.cwd() + '/reports/cucumber-ui-reports.json')
}

Related

Is there any way to read protractor.conf suites names into txt file?

I have a protractor.conf file which includes suites, for example:
suites: {
login: '..PATH',
register: '..PATH',
logout: '..PATH'
}
I want to somehow get the names of the suites and make some use of them, for example putting them in txt file. So the result should be:
test-names.txt
login
register
logout
How can I do it? Thanks.
It can be easily done with nodejs.
For example, you have the protractor.conf.js file:
exports.config = {
...
suites: {
login: '..PATH',
register: '..PATH',
logout: '..PATH'
},
...
}
Create a new javascript file(e.g. writeSuiteNames.js) or wrap this snippet of code in function and put it somewhere and invoke where you need it:
const fs = require('fs');
const { config: { suites } } = require('./protractor.conf.js')
fs.writeFile("./test-names.txt", `Suites: ${Object.keys(suites)}`, err => {
if(err) return console.log(err);
console.log("The file was saved!");
});
Then run the node writeSuiteNames.js command.
The test-names.txt file was successfully created and containing the suite names:
Suites: login,register,logout

How to move/copy files during ember build

I wanted to moved some files between two folders in an ember app when build is run but I am having no success.
//ember-cli-build.js
module.exports = function (defaults) {
var app = new EmberApp(defaults, {
hinting: false,
minifyCSS: {
enabled: true
},
bless: {
enabled: true
}
});
var moveFile = new Funnel('./app/locales', {
srcDir: 'en',
files: ['test.js'],
destDir: 'en_US',
allowEmpty: true
});
return new MergeTrees([moveFile, app.toTree()]);
};
When I do the build, I get no errors but the file is also not getting moved.
UPDATE: I am trying to move the file before ember-cli puts compiles the files and puts it in the dist folder
You can use broccoli-static-compiler https://github.com/joliss/broccoli-static-compiler
In brocfile.js ( ember-cli-build.js )
// at top of file
var pickFiles = require('broccoli-static-compiler');
var mergeTrees = require('broccoli-merge-trees');
// inside exporting function
const bootstrapMap = pickFiles('bower_components/bootstrap/dist/css/',
{
srcDir: '/',
files: ['bootstrap.css.map'],
destDir: '/assets'
});
// and so on, as many times as you need
const zeroClipboard = pickFiles('bower_components/zeroclipboard/dist/',
{
srcDir: '/',
files: ['ZeroClipboard.swf'],
destDir: '/assets'
});
// at the end
return mergeTrees([
app.toTree(),
bootstrapMap,
zeroClipboard,
// ...
], { overwrite: true });
With 'broccoli build', your app is build into a destination folder, so broccoli is the wrong tool to move files in an existing folder structure. Here I'm assuming it's run with something like 'broccoli build dist' on the command line which will create a new folder 'dist' with the results of the build, and error out if the directory already exists.
So let's say your project directory looks like this:
.
|--brocfile.js
|--app/
|--locales/ <----- funnel root
|--en/ <----- srcDir
|--test.js <----- file
When you funnel from ./app/locales, your srcDir and files` are relative to that as a root. The output tree is then put into the 'destDir' under the build output directory. What that will do is this:
.
|--brocfile.js
|--app/ <----- not changed
|--dist/ <----- build output directory
|--en_US <----- destDir
|--test.js <----- file
I think you want your destDir to be locales/en_US or app/locales/en_US.

Ionic serve: how to rerun gulp task

I'm kinda new to ionic and gulp.
I was able to configure the ionic.project file in order to run the gulp tasks when I first run ionic serve.
But now when I change files I want that the gulp task will run again.. But this doesn't happen.. Is there a way to do that?
This is my ionic.project file:
{
"name": "test",
"app_id": "",
"gulpStartupTasks": [
"default"
],
"watchPatterns": [
"src/**/*",
"src/*",
"www/**/*",
"!www/lib/**/*"
]
}
I expected that when some file changes that match the wtachPatterns
it will invoke the gulp watch task, but this doesnt happen (I see that ionic see that the file has changed but nothing happen.)
this the the gulp watch task:
gulp.task('watch', function() {
gulp.watch(paths.sass, ['sass']);
gulp.watch(paths.script, ['script']);
});
Basically the task is minifying all the JS files and all the sass/scss files
and the index.html is looking on the minified files. so if the gulp task isn't invoked there are no changes in the minified file and I need to run ionic serve all over again.. Is there a proper way to do that?
UPDATE:
This is the complete gulpfile
var gulp = require('gulp');
var gutil = require('gulp-util');
var bower = require('bower');
require('require-dir')('./gulp/tasks');
var paths = {
sass: ['./scss/**/*.scss'],
style: ['./src/**/*.scss'],
script: ['./src/app.js'],
html:['./src/*.html']
};
gulp.task('default', ['sass', 'script','watch', 'html', 'style']);
gulp.task('watch', function() {
gulp.watch(paths.sass, ['sass']);
gulp.watch(paths.script, ['script']);
});
gulp.task('install', ['git-check'], function() {
return bower.commands.install()
.on('log', function(data) {
gutil.log('bower', gutil.colors.cyan(data.id), data.message);
});
});
gulp.task('git-check', function(done) {
if (!sh.which('git')) {
console.log(
' ' + gutil.colors.red('Git is not installed.'),
'\n Git, the version control system, is required to download Ionic.',
'\n Download git here:', gutil.colors.cyan('http://git- scm.com/downloads') + '.',
'\n Once git is installed, run \'' + gutil.colors.cyan('gulp install') + '\' again.'
);
process.exit(1);
}
done();
});
And this is an example of one of the files who have the actual task:
var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var stringify = require('stringify');
var paths = ['./src/app.js'];
gulp.task('script', function() {
return browserify(paths, {debug: true})
.transform(stringify(['.html']))
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('./www/js'));
});
Well So the problem was with paths I watched.
I removed the ./ and now its working
First thing first, you misunderstand the watchPatterns is for livereload, which means, the web will refresh if there is any file changed on watch. It's definitely not having any relation to gulp.
Read more at: http://ionicframework.com/docs/cli/test.html
To watch for file changes with watch, update your watch task, which is
gulp.task('watch', function() {
gulp.watch(paths.sass, ['sass']); <-- any file in paths.sass changed will trigger `gulp sass`
gulp.watch(paths.script, ['script']); <-- any file in paths.script changed will trigger `gulp script`
});
So if you want to watch more files to be processed by Gulp, just add tasks and watch them in gulp watch.
Oh hey, you are watching only files in ./scss/**/*.scss and ./src/app.js. Add more if you wish.

Maximize nw.js window from protractor doesn't work

I want to maximise the window from protractor. I am testing a nw.js app.
I added the below line in onPrepare statement in protractor-conf.js, but nothing worked
browser.driver.manage().window().maximize();
setSize also doesn't work
browser.driver.manage().window().setSize(800, 600);
In all the cases I am getting the below error.
var template = new Error(this.message);
^
UnknownError: unknown error: cannot get automation extension
from unknown error: page could not be found: chrome-extension://aapnijgdinlhnhlmodcfapnahmbfebeb/_generated_background_page.html
This is the e2e configuration,
protractor-conf.js
'use strict';
var path = require('path');
var nw = require('nw');
exports.config = {
chromeDriver: './support/chromedriver',
directConnect: true,
specs: ['e2e/**/*.js'],
rootElement: 'html',
capabilities: {
browserName: 'chrome',
chromeOptions: {
binary: nw.findpath()
}
},
onPrepare: function() {
// By default, Protractor use data:text/html,<html></html> as resetUrl, but
// location.replace (see http://git.io/tvdSIQ) from the data: to the file: protocol is not allowed
// (we'll get ‘not allowed local resource’ error), so we replace resetUrl with one
// with the file: protocol (this particular one will open system's root folder)
browser.resetUrl = 'file://';
// This isn't required and used to avoid ‘Cannot extract package’ error showed
// before Protractor have redirected node-webkit to resetUrl.
browser.driver.get('file://' + path.resolve('app/index.html'));
}
};
Is there a way to resolve this ?
I am testing this on Ubuntu.
Did you try to set the arguments for chrome inside capabilities ?
http://peter.sh/experiments/chromium-command-line-switches/
chromeOptions: {
args: [
'--start-maximized',
]
}

How do I parameterize the baseUrl property of the protractor config file

I need to run my protractor tests in different contexts with different baseUrls in the config files. I don't want to use separate config files for each situation since that is more difficult to maintain. Rather, I want to pass the base url in as a command line parameter. Here is what I have tried so far:
The protractor.conf.js:
exports.config = {
onPrepare : {
...
exports.config.baseUrl = browser.params.baseUrl;
...
}
}
And to invoke protractor:
protractor protractor.conf.js --params.baseUrl 'http://some.server.com'
This does not work since it seems like the browser instance is already configured before onPrepare is called.
Similarly, I have tried this:
exports.config = {
baseUrl : browser.params.baseUrl
}
But this doesn't work either since it seems like the browser instance is not available when the config is being generated.
It looks like I can use standard node process.argv to access all command line arguments, but that seems to be going against the spirit of protractor.
What is the best way for me to do what I need to do?
Seems like this is already possible, but the documentation is spotty in this area. Looking at the code, however, protractor does support a number of seemingly undocumented command line arguments.
So, running something like this will work:
protractor --baseUrl='http://some.server.com' my.conf.js
The other option is to use gruntfile.js and have it call the protractor config file.
//gruntfile.js
module.exports = function (grunt) {
grunt.registerTask("default", "", function () {
});
//Configure main project settings
grunt.initConfig({
//Basic settings and infor about our plugins
pkg: grunt.file.readJSON('package.json'),
//Name of plugin
cssmin: {
},
protractor: {
options: {
configFile: "conf.js", // Default config file
keepAlive: true, // If false, the grunt process stops when the test fails.
noColor: false, // If true, protractor will not use colors in its output.
args: {
baseUrl: grunt.option('baseUrl') || 'http://localhost:6034/'
}
},
your_target: { // Grunt requires at least one target to run so you can simply put 'all: {}' here too.
options: {
configFile: "conf.js", // Target-specific config file
args: {
baseUrl: grunt.option('baseUrl') || 'http://localhost:63634/'
}
}
},
},
//uglify
uglify: {
}
});
//Load the plugin
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-protractor-runner');
//Do the Task
grunt.registerTask('default', ['cssmin']);
};
the Protractor config file: conf.js
exports.config = {
directConnect: true,
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome',
'chromeOptions': {
args: ['--no-sandbox']
}
},
chromeOnly: true,
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['specs/*/*_spec.js'],
suites : {
abcIdentity : 'specs/abcIdentity/*_spec.js' //picks up all the _spec.js files
},
params: {
UserName: 'abc#test.com',
Password: '123'
},
// Options to be passed to Jasmine.
jasmineNodeOpts: {
defaultTimeoutInterval: 30000,
includeStackTrace: true
},
onPrepare: function () {
browser.driver.manage().window().maximize();
if (process.env.TEAMCITY_VERSION) {
var jasmineReporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(new jasmineReporters.TeamCityReporter());
}
}
};
//To run with default url http://localhost:6034
grunt protractor
//To run with any other url
grunt protractor --baseUrl:"http://dev.abc.com/"
I know, old one. but if anyone is still looking for a way to define a url based on capability (I had to do this because Ionic 5 will run in browser on port 8100, but in the app - unchangable - without port declaration on port 80, I use Appium)
add a baseUrl parameter inside your capability declaration.
{
browserName: 'chrome',
baseUrl: 'http://localhost:8100' //not required but as example
}
{
...
app: 'path to app.apk',
baseUrl: 'http://localhost'
...
}
and then configure your onPrepare method as follows.
async onPrepare() {
const config = await browser.getProcessedConfig();
if(config.capabilities.hasOwnProperty('baseUrl')) {
browser.baseUrl = config.capabilities.baseUrl;
}
}
OnPrepare runs for each capability you define in your multiCapabilities array. the getProcessedConfig returns the config as you defined it, with the addition of the current capability. Since that method returns a promise, I use async/await for readability.
This way, you can have multiple capabilities running, with each different a different host.
Base url should be declared baseUrl: "", in config.ts
I am using cucumber hooks and the below code is added in hooks file to pass the required url based upon the environments
if(browser.params.baseUrl==="QA"){
console.log("Hello QA")
await browser.get("https://www.google.com");
} else {
console.log("Hi Dev")
await browser.get("https://www.gmail.com");
}
run the tests using protractor command
protractor --params.baseUrl 'QA' typeScript/config/config.js --cucumberOpts.tags="#CucumberScenario"