How to attach an external library to Protractor config file? - javascript

Here's the library:
//library.js
var exports = module.exports = {};
exports.login = function(user_login, user_password) {
var input;
input = element(by.model('loginInfo.login'));
input.sendKeys(user_login);
expect(input.getAttribute('value')).toBe(user_login);
input = element(by.model('loginInfo.password'));
input.sendKeys(user_password);
expect(input.getAttribute('value')).toBe(user_password);
browser.sleep(1000);
browser.driver.actions().sendKeys(protractor.Key.ENTER).perform();
browser.sleep(1000);
};
And this is my config file:
//config.js
var lib = require("./library.js");
exports.config = {
directConnect: true,
onPrepare: function() {
browser.driver.manage().window().maximize();
},
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['messages.js'],
// Options to be passed to Jasmine.
jasmineNodeOpts: {
defaultTimeoutInterval: 50000
}
};
And here's how I'm calling the login fn in the messages.js file:
lib.login('xxx', 'yyyyy');
However, this last line above is giving me an error: 'lib is not defined'

It looks like you are trying to run a protractor test from your library.js file.
Instead of doing that, following the guidelines that http://www.protractortest.org/#/ instructs. That is, the config.js file is for configuring the environment and the spec.js file is for testing. As such, try this instead:
/*
* library-spec.js
*/
var input;
describe('Login Test', function() {
it('should enter login information and send the Enter key to login', function() {
input = element(by.model('loginInfo.login'));
input.sendKeys(user_login);
expect(input.getAttribute('value')).toBe(user_login);
input = element(by.model('loginInfo.password'));
input.sendKeys(user_password);
expect(input.getAttribute('value')).toBe(user_password);
browser.sleep(1000);
browser.driver.actions().sendKeys(protractor.Key.ENTER).perform();
browser.sleep(1000);
});
});
And the config file will look like:
//config.js
exports.config = {
directConnect: true,
onPrepare: function() {
browser.driver.manage().window().maximize();
},
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['library-spec.js'],
// Options to be passed to Jasmine.
jasmineNodeOpts: {
defaultTimeoutInterval: 50000
}
};
However, if you need that library.js file to be run before each or before all your tests, put it into your messages.js file.
From your messages.js file, within your describe block you would add:
beforeEach(function() {
lib(username, password); //where username and password are string vars
});
or
beforeAll(function() {
lib(username, password); //where username and password are string vars
});
And, as a final note, if you leave your library.js file as is, here is some cleanup:
//library.js
module.exports = login;
function login(user_login, user_password) {
var input;
input = element(by.model('loginInfo.login'));
input.sendKeys(user_login);
expect(input.getAttribute('value')).toBe(user_login);
input = element(by.model('loginInfo.password'));
input.sendKeys(user_password);
expect(input.getAttribute('value')).toBe(user_password);
browser.sleep(1000);
browser.driver.actions().sendKeys(protractor.Key.ENTER).perform();
browser.sleep(1000);
};
Note how the module.exports line replaces the line that you had. Also I've changed the exports.login to function login. Then you would...
var login = require('./login');
login('user', 'pass');
where it will be needed.

Related

How to run multiCapabilities reading configuration parameters from the configuration file

I have one file of config which runs tests in one browser using capabilities.
Now I have created one more separate config file which contains multiCapabilites and will run same tests in multiple browsers.
I want to optimize configs so I second config file I write multiCapabilities for first config and used
delete firstConfig['capabilities'];
to ignore the capabilities from first config and use all other params from firstConfig and use multiCapabilities from 2nd config and run.
Expected result:
params in configs should not be duplicated in both configs, only multiCapabilities is the change, rest of config is same.
Use a base configuration file
Having a base configuration file and another file that extends from it might be a better approach. For this example, we will look at my base configuration file:
var env = require('./environment');
// This is the configuration for a smoke test for an Angular TypeScript application.
exports.config = {
seleniumAddress: env.seleniumAddress,
framework: 'jasmine',
specs: [
'ng2/async_spec.js'
],
capabilities: env.capabilities,
baseUrl: env.baseUrl,
allScriptsTimeout: 120000,
getPageTimeout: 120000,
jasmineNodeOpts: {
defaultTimeoutInterval: 120000
}
};
Create a second config from the base config
From there, we did something similar to your question where we removed the capabilities and added multicapabilities. (https://github.com/angular/protractor/blob/master/spec/ciNg2Conf.js). In addition, since we were running on Sauce Labs, we also decided to increase our timeouts.
exports.config = require('./angular2Conf.js').config;
exports.config.sauceUser = process.env.SAUCE_USERNAME;
exports.config.sauceKey = process.env.SAUCE_ACCESS_KEY;
exports.config.seleniumAddress = undefined;
// TODO: add in firefox when issue #2784 is fixed
exports.config.multiCapabilities = [{
'browserName': 'chrome',
'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
'build': process.env.TRAVIS_BUILD_NUMBER,
'name': 'Protractor suite tests',
'version': '54',
'selenium-version': '2.53.1',
'chromedriver-version': '2.26',
'platform': 'OS X 10.11'
}];
exports.config.capabilities = undefined;
exports.config.allScriptsTimeout = 120000;
exports.config.getPageTimeout = 120000;
exports.config.jasmineNodeOpts.defaultTimeoutInterval = 120000;
I hope that helps.
Update:
Per comments below, setting the config.capabilities to undefined did not work; however, setting config.capabilities to false did work.
Prepare a capabilities provider to define vary capabilities, and exports a function to return a capabilities array according to the cmd line params.
// capabilities.provider.js
var capabilities = {
chrome: {
browserName: 'chrome'
},
chrome-headless {
browserName: 'chrome',
},
firefox: {
browsername: 'firefox'
},
...
};
exports.evaluate=function(){
var caps = 'chrome';
process.argv.slice(3).forEach(function(kvp){
if(kvp.includes('--caps=')) {
caps = kvp.split('=')[1] || caps;
}
})
var _caps = [];
caps.split(',').forEach(function(cap){
if(Object.keys(capabilities).includes(cap)) {
_caps.push(capabilities[cap])
}
})
return _caps;
};
protractor config.js
var capsProvider = require('./capabilities.provider');
exports.config = {
seleniumAddress: '',
framework: 'jasmine',
specs: [
'ng2/async_spec.js'
],
params: {
},
multiCapabilities: capsProvider.evaluate(),
baseUrl: env.baseUrl,
allScriptsTimeout: 120000,
getPageTimeout: 120000,
jasmineNodeOpts: {
defaultTimeoutInterval: 120000
}
};
Specify caps from cmd line:
protractor config.js --caps=chrome,firefox,ie,safari

Cannot Cannot read property from protractor-image-comparison

I'm new to frontend world, I would like to write some test using protractor-image-comparison. I followed installation instructions from https://github.com/wswebcreation/protractor-image-comparison. Also I make configuration according to this page.
When I try to use functions form this lib I get following error: "TypeError: Cannot read property 'checkFullPageScreen' of undefined". I'm getting a warrning in protractor.conf.js in
const protractorImageComparison = require('protractor-image-comparison');
"Could not find a declaration file for module
'protractor-image-comparison'.
'/home/rafa/repos/example/src/example/node_modules/protractor-image-comparison/index.js'
implicitly has an 'any' type. Try npm install
#types/protractor-image-comparison if it exists or add a new
declaration (.d.ts) file containing declare module
'protractor-image-comparison';"
So I did, I made simple *.d.ts file with `declare module protractor-image-comparison' in it, but it didn't solve the problem just the warning disappear. It's propably the config issue, but I can't handle it or maybe I made wrong declaration. This is my config file :
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const reporter = require("cucumber-html-reporter");
const path = require("path");
const jsonReports = path.join(process.cwd(), "/reports/json");
const htmlReports = path.join(process.cwd(), "/reports/html");
const targetJson = jsonReports + "/cucumber_report.json";
const cucumberReporterOptions = {
jsonFile: targetJson,
output: htmlReports + "/cucumber_reporter.html",
reportSuiteAsScenarios: true,
theme: "bootstrap",
};
exports.config = {
allScriptsTimeout: 110000,
restartBrowserBetweenTests: true,
//SELENIUM_PROMISE_MANAGER: false,
specs: [
'./e2e/**/login.feature'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'),
cucumberOpts: {
format: "json:" + targetJson,
require: ['./e2e/steps/*.ts', "./e2e/timeout.ts"],
},
useAllAngular2AppRoots: true,
onPrepare: () => {
browser.ignoreSynchronization = true;
const protractorImageComparison = require('protractor-image-comparison');
browser.protractorImageComparison = new protractorImageComparison(
{
baselineFolder: "report/screens/baseline",
screenshotPath: "report/screens/actual"
}
);
},
beforeLaunch: function() {
require('ts-node').register({
project: 'e2e'
});
},
onComplete: () => {
reporter.generate(cucumberReporterOptions);
}
};
Ok, I solved it. The reason why I was getting this TypeError is that I lunched few test scenarios and onPrepare was lunched only in the begining. I move config of protractor-image-comparison to cucumber befor hook and everything works fine now.

Unable to Add a TypeScript service to an Angular 1.X application

I have created a TypeScript service named hello-world.ts in my Angular 1.X application. It looks like this:
export default class HelloWorld {
hello() {
console.log("hello world");
}
}
I am importing it using the following:
import HelloWorld from './hello-world';
angular.module('exac.helloWorld', []).service('HelloWorld', HelloWorld);
When I pass the imported HelloWorld to console.log() in the above code snippet, I get an empty Object when I should be expecting a function.
Below is my relevant gulpfile config:
// cache, packageCache, fullPaths are necessary for watchify
var browserifyArgs = {
cache: {},
packageCache: {},
// supposedly must be true for watchify, but false seems to work:
fullPaths: false,
basedir: 'app/source',
// generate source maps
debug: true,
};
var bundler = browserify('./index.js', browserifyArgs);
// TypeScript support
bundler.plugin(tsify, {noImplicitAny: true});
bundler.transform('babelify', {
extensions: ['.js', '.ts'],
});
bundler.transform('browserify-ngannotate');
function bundle() {
// If we process.cwd('app') here this will generate perfect source maps
// even with includeContent: false; unfortunately, that affects the cwd for
// all tasks in the gulpfile.
return bundler.bundle()
// log errors if they happen
.on('error', console.log.bind(gutil, 'Browserify Error'))
.pipe(source('index.js'))
.pipe(buffer())
.pipe(sourcemaps.init({
loadMaps: true
}))
.pipe(sourcemaps.write('./', {
includeContent: true,
sourceRoot: '..'
}))
.pipe(gulp.dest('app/js/'));
}
gulp.task('js', bundle);
I have also tried the following:
// cache, packageCache, fullPaths are necessary for watchify
var browserifyArgs = {
cache: {},
packageCache: {},
// supposedly must be true for watchify, but false seems to work:
fullPaths: false,
extensions: ['.js', '.ts'],
basedir: 'app/source',
// generate source maps
debug: true,
transform: [
'babelify',
['browserify-ngannotate'],
]
};
var bundler = browserify('./index.js', browserifyArgs).plugin(tsify);
function bundle() {
...
Gulp watchify completes with no errors, but my browser generates the error angular.js:13920 Error: [ng:areq] Argument 'fn' is not a function, got Object.
As I wrote before, when I import the HelloWorld class from hello-world.ts, I am not seeing the expected value. Instead, I get an empty object. What is going on?
EDIT:
Here is the source code generated by browserify / tsify. Perhaps this holds a clue as to what may be wrong in my gulp / browserify / tsify environment?
System.register([], function (exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var HelloWorld;
return {
setters: [],
execute: function execute() {
HelloWorld = function () {
function HelloWorld() {}
HelloWorld.prototype.hello = function () {
console.log("hello world");
};
return HelloWorld;
}();
exports_1("default", HelloWorld);
}
};
});

Why is Cucumber not executing my step definitions?

Working on Windows I have installed Ruby and the Ruby DevKit to get things working with Cucumber. Now I have the following basic setup:
/app
/features
example.feature
/step_definitions
example.steps.js
In the example.feature file I have:
Feature: This is an example feature
In order to learn Cucumber
As a developer
I want to make this feature pass
Scenario: wrote my first scenario
Given a variable set to 1
When I increment the variable by 2
Then the variable should contain 3
And in the example.step.js file I have:
'use strict';
module.exports = function () {
this.givenNumber = 0;
this.Given(/^a variable set to (\d+)$/, function(number, next) {
this.givenNumber = parseInt(number);
next();
});
this.When(/^I increment the variable by (\d+)$/, function (number, next) {
this.givenNumber = this.givenNumber + parseInt(number);
next();
});
this.Then(/^the variable should contain (\d+)$/, function (number, next) {
if (this.givenNumber != number)
throw(new Error("This test didn't pass, givenNumber is " + this.givenNumber + " expected 0"));
next();
});
};
Now, when I run 'cucumber' from the /app dir I keep getting the folowing output:
1 scenario (1 undefined)
3 steps (3 undefined)
0m0.004s
I tried moving around the files, adding the --require option, etc. but nothing seems to be helping.
Any ideas?
Apparently this cannot be executed directly using the 'cucumber' command.
Settings things up using grunt and the grunt-cucumber task seems to be working as expected:
My Gruntfile.js
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
cucumberjs: {
src: 'features',
options: {
steps: 'features/step_definitions',
format: 'pretty'
}
}
});
grunt.loadNpmTasks('grunt-cucumber');
grunt.registerTask('default', ['cucumberjs']);
};
Additionally: if you are using protractor. It has cucumber build in. Just create the right config for protractor (protractor.conf.js):
exports.config = {
specs: [
//'e2e/features/*.feature'
'**/*.feature'
],
capabilities: {
'browserName': 'chrome'
},
baseUrl: 'http://localhost:9000/',
framework: 'cucumber'
}

Mocha unit tests running with Karma - done() is not defined

I'm trying to get tests written with Mocha to work running Karma, and they sort of work, but I cannot use the done() method to implement async tests, which essentially makes the tools useless to me. What am I missing?
karma.conf.js
module.exports = function(config) {
config.set({
basePath: '../..',
frameworks: ['mocha', 'requirejs', 'qunit'],
client: {
mocha: {
ui: 'bdd'
}
},
files: [
{pattern: 'libs/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'tests/mocha/mocha.js', included: false},
{pattern: 'tests/should/should.js', included: false},
{pattern: 'tests/**/*Spec.js', included: false},
'tests/karma/test-main.js'
],
exclude: [
'src/main.js'
],
// test results reporter to use
// possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
reporters: ['progress', 'dots'],
port: 9876,
colors: true,
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_WARN,
autoWatch: true,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera (has to be installed with `npm install karma-opera-launcher`)
// - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`)
// - PhantomJS
// - IE (only Windows; has to be installed with `npm install karma-ie-launcher`)
browsers: ['Chrome'],
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};
test-main.js (configuring RequireJS)
var allTestFiles = [];
var pathToModule = function(path) {
return path.replace(/^\/base\//, '../').replace(/\.js$/, '');
};
Object.keys(window.__karma__.files).forEach(function(file) {
if (/Spec\.js$/.test(file)) {
// Normalize paths to RequireJS module names.
allTestFiles.push(pathToModule(file));
}
});
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base/src',
paths: {
'should': '../tests/should/should',
'mocha': '../tests/mocha/mocha',
'pubsub': '../libs/pubsub/pubsub',
'jquery': '../libs/jquery/jquery-1.10.2',
'jquery-mobile': '//code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min'
},
// dynamically load all test files
deps: allTestFiles,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
tests/fooSpec.js
define(['music/note'], function(Note) {
describe('nothing', function(done) {
it('a silly test', function() {
var note = new Note;
note.should.not.eql(32);
});
done();
});
...
Though this is a contrived example, it succeeds if I remove the done() call. As it is, I get:
Uncaught TypeError: undefined is not a function
at /Library/WebServer/Documents/vg/tests/mocha/fooSpec.js:8
This is the done() line. How/why is this not defined? I'm not understanding where else to configure Mocha (or with what options). Is there some sort of global namespace or meta-programming magic causing RequireJS to interfere with Mocha?
I'm running the tests in Chrome 33 on OS X 10.9.2, in case that is at all relevant. I've killed a ton of time on this and am ready to give up on automated testing :( -- had similar brick walls with QUnit/Karma/RequireJS and have not been able to find any alternative to successfully automate tests. I feel like an idiot.
In Mocha, the done callback is for it, before, after, beforeEach, afterEach. So:
describe('nothing', function() {
it('a silly test', function(done) {
var note = new Note;
note.should.not.eql(32);
done();
});
});
Here's the doc.
The test you are running in that example doesn't require the done() callback. It is not asynchronous. An example of when the done callback is need....
describe('Note', function() {
it('can be retrieved from database', function(done) {
var note = new Note();
cb = function(){
note.contents.should.eql("stuff retrieved from database");
done()
}
//cb is passed into the async function to be called when it's finished
note.retrieveFromDatabaseAsync(cb)
});
});
Your test should not have a done callback
describe('nothing', function() {
it('umm...', function() {
var note = new Note;
note.should.not.eql(32);
});
});
Only the 'it' function provides a done callback. describe does not. Your problem does not rest with karma. Your mocha tests are not defined correctly.
Holy %$##!
I would never in a million years have thought this would barf:
describe('nothing', function(done) {
it('umm...', function() {
var note = new Note;
note.should.not.eql(32);
});
done(); // throws error that undefined is not a function
});
But this works just fine:
describe('nothing', function(done) {
it('umm...', function() {
var note = new Note;
note.should.not.eql(32);
});
setTimeout(function() {
done(); // MAGIC == EVIL.
}, 1000);
});

Categories

Resources