How can we use the On Prepare function in config File while i am trying to run multiple Spec files - protractor

In the Config File i am using the On Prepare Function for the purpose of assigning the property data test id as value
But for the first spec file execution the on prepare is picked up
but on the next execution of the Spec , the on prepare function is not getting picked up
import { Config } from "protractor/built/config";
import { by } from "protractor";
// import { encode } from "punycode";
function encode(file) {
var stream = require('fs').readFileSync(file);
return new Buffer(stream).toString('base64');
}
export let config: Config = {
// The address of a running selenium server.
//seleniumAddress: 'http://localhost:4444/wd/hub',
directConnect:true,
allScriptsTimeout:1500000,
// Capabilities to be passed to the webdriver instance.
capabilities: {
browserName: 'chrome',
'chromeOptions': {
'extensions': [encode('C:/Users/koanand/Documents/Protractor/ASR/2.2.9_0.crx')]
}
},
onPrepare: function () {
by.addLocator('testId', function(value, parentElement) {
parentElement = parentElement || document;
var nodes = parentElement.querySelectorAll('[data-test-id]');
return Array.prototype.filter.call(nodes, function(node) {
return (node.getAttribute('data-test-id') === value);
});
});
},
// Spec patterns are relative to the configuration file location passed
// to protractor (in this example conf.js).
// They may include glob patterns.
specs: ['C:/Users/anand/Documents/Protractor/ASR/TS-Output/specs/directasr.js',
'C:/Users/anand/Documents/Protractor/ASR/TS-Output/specs/products.js'
],
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true, // Use colors in the command line report.
defaultTimeoutInterval : 150000
}
};
i am observing the below error
Message:
Failed: protractor_1.by.testID is not a function
Stack:
TypeError: protractor_1.by.testID is not a function
at new productlist (C:\Users\koanand\Documents\Protractor\ASR\pageobject\productlist.ts:19:45)
at product.selectingproductlist (C:\Users\koanand\Documents\Protractor\ASR\specs\classproductlist.ts:14:32)
at UserContext.<anonymous> (C:\Users\koanand\Documents\Protractor\ASR\specs\products.ts:21:21)
at C:\Users\koanand\Documents\Protractor\ASR\node_modules\jasminewd2\index.js:108:15
at new ManagedPromise (C:\Users\koanand\Documents\Protractor\ASR\node_modules\selenium-webdriver\lib\promise.js:1077:7)
at ControlFlow.promise (C:\Users\koanand\Documents\Protractor\ASR\node_modules\selenium-webdriver\lib\promise.js:2505:12)
at schedulerExecute (C:\Users\koanan
d\Docume

Use BeforeAll() in each spec file & write whatever you want to execute before each spec starts

May following link help you to clear your doubts for onPrepare and what to use in pace of it.
OnPrepare function in Protractor

Related

Protractor to dynamically choose browser based on input

I am new to protractor and I want to be able to run my chrome browser painted or headless.
So I set up something like this
let chrome = {
browserName: 'chrome',
platform: 'MAC',
'max-duration': '1800',
};
let chromeHeadless = {
browserName: 'chrome',
chromeOptions: {
args: [ "--headless", "--disable-gpu", "--window-size=800,600" ]
}
};
browserDefault = browser.params.browserToUse
exports.config = {
params: {
'browserToUse': "get from user'
},
capabilities: browserDefault,
}
and i ran this code as
protractor config.js --params.browserToUse='chromeHeadless'
But this does not work. Protractor fails saying it does not understand "browser.params.browserInput". Whats the right way to make protractor dynamically choose chrome or chromeheadless based on the input
The global variable browser is only init when code run into onPrepare(). You used browser outside onPrepare() function, browser have not been inited, it is undefined, so you met the error.
Another point you need to get it's when the variable browser inited, a browser window has been opened, means protractor has know which capabilities to launch the browser. Therefore you can't use browser.params.xxx to specify which capabilities, you need to tell protractor the capabilities before it init the browser variable.
let capabilitiesMap = {
'chrome-headful' : {
browserName: 'chrome',
platform: 'MAC',
'max-duration': '1800',
},
'chrome-headless': {
browserName: 'chrome',
chromeOptions: {
args: [ "--headless", "--disable-gpu", "--window-size=800,600" ]
}
}
};
let browserToUse = 'chrome-headful'; // set default value
// extract the browserToUse value from cli
process.argv.slice(3).forEach(function(arg) {
var name = arg.split('=')[0];
var value = arg.split('=')[1];
var name = name.replace('--', '');
if (name === 'browserToUse') {
if (Object.prototype.hasOwnProperty.call(capabilitiesMap, value) ) {
browserToUse = value;
}
}
});
let config = {
seleniumAddress: '',
specs: [],
onPrepare: function() {}
};
config.capabilities = capabilitiesMap[browserToUse];
exports.config = config;
CLI example: protractor conf.js --browserToUse=chrome-headless
I also came across this issue and soleved it using the getMultiCapabilities() function in your conf.js
const _ = require('lodash');
let capabilities = {
chrome: {
browserName: 'chrome',
platform: 'MAC',
'max-duration': '1800',
},
chromeHeadless : {
browserName: 'chrome',
chromeOptions: {
args: [ "--headless", "--disable-gpu", "--window-size=800,600" ]
}
}
}
getMultiCapabilities() {
const browsers = this.params.browserToUse.split(',');//if you pass more than one browser e.g chrome,chromeHeadless
const cap = _(capabilities).pick(browsers).values().value(); //this uses the lodash npm module
return cap;
},
In a testing context working with just Chrome, I did the following. In capabilities:
chromeOptions: {
args: []
}
beforeLaunch: function() {
//at this point browser is not yet defined, so process command line directly
if (process.argv[process.argv.length-1].search('headless=true')>-1){
config.capabilities.chromeOptions.args.push("--headless");
config.capabilities.chromeOptions.args.push("--disable-gpu");
config.capabilities.chromeOptions.args.push("--window-size=1600,1000");
}
}
That way by the time the browser was launched, it had the right configuration. Where I have "headless=true", you might want "Chrome-headless."
And then on the command line I call it like you do with --params.headless=falseso that should I want to find it in the script itself later (after the browser has launched), it is readily available.
Note I had just one command line parameter and control of the command line, so it felt okay to assume this parameter was the last.

Protractor - invalid SSL certificate

We have an application and testing this locally shows an invalid SSL certificate warning. Normally I would just add an exception and get on with it. However is there anyway for protractor to ignore this?
I've seen some capabilities in selenium where SSL can be ignored but can't seem to find any in protractor.
This works for me, (in conf file):
capabilities: {
browserName : 'firefox',
marionette : true,
acceptInsecureCerts : true
}
Hope that helps.
capabilities: {
browserName: 'chrome',
chromeOptions: {
// for ci test
args: ['--headless', 'no-sandbox', "--disable-browser-side-navigation",
"--allow-insecure-localhost"
/// for https sites: ignore ssl on https://localhost...
/// further args please see https://peter.sh/experiments/chromium-command-line-switches/
]
}
}
maybe you want to take some screenshots to test where the error occurs
import fs from 'fs';
function writeScreenShot(data, filename) {
const stream = fs.createWriteStream(filename);
stream.write(new Buffer(data, 'base64'));
stream.end();
}
export function takeScreenshot(browser, path){
browser.takeScreenshot().then((png) => {
writeScreenShot(png, path);
});
}
But for the long run, I would suggest migrating to cypress (https://www.cypress.io/), because it have many other features out of the box: video, screenshot, etc. And believe me, it is worth it ;)
try
webdriver-manager update --ignore_ssl
or configure protractor.conf.js for firefox
var makeFirefoxProfile = function(preferenceMap) {
var profile = new FirefoxProfile();
for (var key in preferenceMap) {
profile.setPreference(key, preferenceMap[key]);
}
return q.resolve({
browserName: 'firefox',
marionette: true,
firefox_profile: profile
});
};
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
framework: 'jasmine2',
getMultiCapabilities: function() {
return q.all([
makeFirefoxProfile(
{
'browser.acceptSslCerts': true
}
)
]);
},
}

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',
]
}

browserify/karma/angular.js "TypeError: Cannot read property '$injector' of null" when second test uses "angular.mock.inject", "currentSpec" is null

I have an Angular.js app and am experimenting with using it with Browserify. The app works, but I want to run tests too, I have two jasmine tests that I run with karma. I user browserify to give me access to angular.js and angular-mocks.js and other test fixtures within the tests.
Versions are:-
"angular": "^1.4.0",
"angular-mocks": "^1.4.0",
"browserify": "^10.2.3",
"karma": "^0.12.32",
"karma-browserify": "^4.2.1",
"karma-chrome-launcher": "^0.1.12",
"karma-coffee-preprocessor": "^0.2.1",
"karma-jasmine": "^0.3.5",
"karma-phantomjs-launcher": "^0.1.4",
If I run the tests individually (by commenting one or the other from the karma.conf file) they both work OK. (yey!)
But if I run them both I get this error
TypeError: Cannot read property '$injector' of null
at Object.workFn (/tmp/3efdb16f2047e981872d82fd8db9c0a8.browserify:2272:22 <- node_modules/angular-mocks/angular-mocks.js:2271:0)
looking at line 2271 of the angular.mocks.js It reads
if (currentSpec.$injector) {
So clearly currentSpec is somehow now null.
I have isolated the problem to when I call "angular.mock.inject" in the second test.
beforeEach(angular.mock.inject(function (_GridUtilService_) {
gridUtilService = _GridUtilService_;
}));
If I comment this out it works, but obviously I can't then run a test n my gridUtilService.
Does anyone know how to run two (or more :-) angular-mock jasmine tests with karma and browserify?
below are my tests, karma.conf file. the Angular services work when deployed but for this purpose they can simply be dumb services that do nothing.
karma.conf:-
// Karma configuration
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['browserify', 'jasmine'],
// list of files / patterns to load in the browser
files: [
'src/main/assets/js/**/*.js',
// 'src/test/**/*.js'
'src/test/services/SettingUtil*.js',
'src/test/services/GridUtil*.js'
],
// list of files to exclude
exclude: [
'src/main/assets/js/**/app-config.js'
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/main/assets/js/**/*.js': ['browserify'],
'src/test/**/*.js': ['browserify']
},
browserify: {
debug: true,
extensions: ['.js', '.coffee', '.hbs']
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_DEBUG,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
// browsers: ['PhantomJS', 'Chrome'],
// browsers: ['PhantomJS'],
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false
});
};
src/test/services/SettingUtilServiceTest.js:
'use strict';
describe("SettingUtilServiceTest.", function() {
it("contains spec with an expectation", function() {
expect(true).toBe(true);
});
require('angular');
require('angular-mocks');
// can't do below see error at https://github.com/xdissent/karma-browserify/issues/10
//beforeEach(module('dpServices'));
//so need todo this
beforeEach(angular.mock.module('dpServices'));
var fixtures = require('./serviceFixtures.js');
var sus = fixtures.settingUtilServiceTestFixtures;
var ts1 = sus.tablesetting1;
var ts2 = sus.tablesetting2;
var settingUtilService;
beforeEach(angular.mock.inject(function (_settingUtilService_) {
settingUtilService = _settingUtilService_;
}));
it('should return an object containing mins and maxs from function minMaxes()', function() {
expect(ts1).toBeDefined();
expect(ts2).toBeDefined();
var minMaxs = settingUtilService.minMaxs(ts1);
var mins = minMaxs.mins;
expect(mins).toBeDefined();
var maxs = minMaxs.maxs;
expect(maxs).toBeDefined();
});
});
src/test/services/GridUtilServiceTest.js:
'use strict';
describe("GridUtilServiceTest.", function() {
it("is a set of tests to test GridUtilService.", function() {
expect(true).toBe(true);
});
require('angular');
require('angular-mocks');
// can't do below see error at https://github.com/xdissent/karma-browserify/issues/10
// beforeEach(module('dpServices'));
//so need todo this
beforeEach(angular.mock.module('dpServices'));
var fixtures = require('./gridFixtures.js');
var gridFix = fixtures.gridUtilServiceTestFixtures;
var ts1 = gridFix.tablesetting1;
var ts2 = gridFix.tablesetting2;
var ts3 = gridFix.tablesetting3;
var gridUtilService;
beforeEach(angular.mock.inject(function (_GridUtilService_) {
gridUtilService = _GridUtilService_;
}));
it('should return an object containing mins and maxs from function minMaxes()', function() {
expect(ts1).toBeDefined();
expect(ts2).toBeDefined();
expect(ts3).toBeDefined();
});
});
If you need access to the angular setup I can provide it (split into multiple files using browserify's require() function and built with gulp... but as I say the app runs ok and the tests only fail when there are two tests, so I think the issue is with karma-jasmine and angular-mocks or overwriting the currentSpec variable.
If anyone knows how to split my angular tests into multiple tests (I don't want a monolithic angular test) without the error message all help is appreciated. thanks.
I had the same issue, the issue for me was because I was requiring angular and angular-mocks exactly as you were inside each describe block. I moved the two lines
require('angular');
require('angular-mocks');
above the describe blocks and made sure to only call them once.

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"