Unable to update protractor config at runtime - selenium-webdriver

I am trying to update protractor config on the run time, because spec file are being read from external excel file.
Below is my config:
export let config = {
allScriptsTimeout: RunConfig.allScriptsTimeout,
capabilities: {
browserName: RunConfig.browser
},
directConnect: true,
baseUrl: RunConfig.baseUrl,
framework: RunConfig.framework,
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: RunConfig.defaultTimeoutInterval,
print: function () {
}
},
onPrepare() {
bot.fullScreen();
Xlsx.readExcel();
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
},
beforeLaunch() {
let spec = new Promise((resolve) => {
resolve({
specs: Xlsx.readSpecs()
});
});
},
resultJsonOutputFile: RunConfig.resultFile
}
According to this it should update config in beforeLaunch
==========================
ReadSpec Function
readSpecs() {
fs.readFile(RunConfig.runManager, (err, buf) => {
if(!err && buf) {
let wb = XLSX.read(buf, { type: 'buffer' });
let sheet = wb.Sheets[sheetNames.specs]; //reading specs
let specArr = XLSX.utils.sheet_to_json(sheet);
let spec;
specArr.forEach(element => {
spec.push(element.spec);
});
return spec;
} else {
return [];
}
});
}

I add explanation inline:
XLSX = require('xlsx');
// change readSpecs() to sync style
readSpecs() {
let wb = XLSX.readFile(RunConfig.runManager);
let sheet = wb.Sheets[sheetNames.specs]; //reading specs
let specArr = XLSX.utils.sheet_to_json(sheet);
let spec;
specArr.forEach(element => {
spec.push(element.spec);
});
return spec;
}
export let config = {
// specify value for `specs`, and it require `Xlsx.readSpecs()`
// does not return promise-like object.
specs: Xlsx.readSpecs(),
onPrepare() {
bot.fullScreen();
// you need to move Xlsx.readExcel(); to the top
// when protractor run into onPrepare() function,
// it means protractor runner had accepted your passed-in config
// the runner won't accept any changes to the config once it accepted.
// Xlsx.readExcel();
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: true
}
}));
},
// beforeLaunch() is unnecessary
// beforeLaunch() {
// let spec = new Promise((resolve) => {
// resolve({
// specs: Xlsx.readSpecs()
// });
// });
// },
};
beforeLaunch() can't change the config yet. There is no hooks can change the config before protractor read it. The only way is to give a pre-know value to specs and not allow promise-like value.
If your Xlsx.readExcel() or Xlsx.readSpecs() return promise, you have to use another way to implement it.

You aren't using the local variable spec for anything in the beforeLaunch function. The example in the link you posted is returning the resolved promise. You need to get rid of the local variable and return the promise like this:
beforeLaunch() {
return new Promise((resolve) => {
resolve({
specs: Xlsx.readSpecs()
});
});
}

Related

gulp watch resulting in an endless loop after upgrading to gulp 4

I have upgraded my gulpfile.js to gulp 4. gulp dev is working fine. But whenever I am editing any file the reload and inject tasks are entering into an endless loop.
My gulpfile.js:
var gulp = require('gulp'),
sass = require('gulp-sass'),
symlink = require('gulp-symlink'),
jshint = require('gulp-jshint'),
browserSync = require('browser-sync').create(),
concat = require('gulp-concat'),
useref = require('gulp-useref'),
replace = require('gulp-replace'),
templateCache = require('gulp-angular-templatecache'),
gulpif = require('gulp-if'),
gulpUtil = require('gulp-util'),
uglify = require('gulp-uglify'),
minifyCss = require('gulp-clean-css'),
merge = require('merge-stream'),
clean = require('gulp-clean'),
inject = require('gulp-inject'),
svgSprite = require('gulp-svg-sprite'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer');
webfonts = require('gulp-font');
/* DEV */
gulp.task('dev-serve', function () {
browserSync.init({
server: './'
});
gulp.watch('app/**/*.scss', gulp.parallel('sass'));
gulp.watch('app/**/*.html', gulp.series('inject', 'reload'));
gulp.watch('app/**/*.js', gulp.parallel('inject', 'reload'));
gulp.watch('app/images/svg-sprite/*', gulp.parallel('svg-sprite', 'reload'));
gulp.watch('app/images/**/*', gulp.parallel('reload'));
gulp.watch('app/fonts/*', gulp.parallel('reload'));
});
/* PROD */
gulp.task('prod-serve', function () {
browserSync.init({
server: './www'
});
gulp.watch('app/**/*.scss', gulp.parallel('sass', 'build-html'));
gulp.watch('app/**/*.html', gulp.parallel('inject', 'minify-scripts', 'reload'));
gulp.watch('app/**/*.js', gulp.parallel('inject', 'minify-scripts', 'reload'));
gulp.watch('app/images/**/*', gulp.parallel('copy-images', 'reload'));
gulp.watch('app/fonts/*', gulp.parallel('copy-fonts', 'reload'));
});
// SVG SPRITE
gulp.task('svg-sprite', function () {
var svgPath = 'app/images/svg-sprite/*.svg';
return gulp.src(svgPath)
.pipe(svgSprite({
shape: {
spacing: {
padding: 0
}
},
mode: {
css: {
dest: './',
layout: 'diagonal',
sprite: 'app/images/sprite.svg',
bust: false,
render: {
scss: {
dest: 'app/styles/tools/_sprite.scss',
template: 'app/styles/tools/_sprite-template.tpl'
}
}
}
},
variables: {
mapname: 'icons'
}
}))
.pipe(gulp.dest('./'));
});
// SCSS
gulp.task('sass', function (done) {
gulp.task('sass', function () {
return gulp.src('app/**/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(concat('style.css'))
.pipe(postcss([autoprefixer()]))
.pipe(gulp.dest('app'))
.pipe(browserSync.stream());
});
done();
});
// INJECT
gulp.task('inject', function () {
return gulp.src('app/index.html')
.pipe(inject(gulp.src(['app/**/*.module.js', 'app/**/*.js', '!app/vendor/**/*.js'], {read: false}), {relative: true}))
.pipe(gulp.dest('./app'));
});
// HTML
gulp.task('build-html', function () {
return gulp.src('app/index.html')
.pipe(replace('href="/app/"', 'href="/"')) // replace base href
.pipe(useref())
.pipe(gulpif('*.js', uglify().on('error', gulpUtil.log)))
.pipe(gulpif('*.css', minifyCss()))
.pipe(gulp.dest('www'));
});
// IMAGES
gulp.task('copy-images', function () {
return gulp.src(['app/images/*'])
.pipe(gulp.dest('www/images'));
});
// FONTS
gulp.task('copy-fonts', function () {
return gulp.src(['app/fonts/*'])
.pipe(gulp.dest('www/fonts'));
});
// TEMPLATES
gulp.task('bundle-templates', function () {
return gulp.src(['app/**/*.html', '!app/index.html'])
.pipe(gulpif('*.html', templateCache({module: 'jibbar'})))
.pipe(concat('templates.min.js'))
.pipe(gulp.dest('www/tmp'));
});
// COMPONENTS
gulp.task('bundle-components', function () {
return gulp.src(['app/**/*.module.js', 'app/**/*.js', '!app/vendor/**/*.js'])
.pipe(concat('script.min.js'))
.pipe(gulp.dest('www'));
});
// MERGE TEMPLATES AND COMPONENTS
gulp.task('merge-templates-and-components', gulp.parallel('bundle-templates', 'bundle-components'), function () {
return gulp.src(['www/script.min.js', 'www/tmp/templates.min.js'])
.pipe(concat('script.min.js'))
.pipe(gulp.dest('www'))
});
// MINIFY SCRIPTS
gulp.task('minify-scripts', gulp.parallel('merge-templates-and-components', 'bundle-templates', 'bundle-components'), function () {
return gulp.src('www/script.min.js')
.pipe(uglify().on('error', gulpUtil.log))
.pipe(gulp.dest('www'))
});
// CLEAN TEMP
gulp.task('clean', gulp.parallel('bundle-templates', 'bundle-components', 'merge-templates-and-components'), function () {
return gulp.src('www/tmp', {read: false})
.pipe(clean());
});
// RELOAD BROWSER
gulp.task('reload', gulp.series('inject'), function () {
browserSync.reload();
});
//COPY IFRAME
gulp.task('copy-iframe', function () {
return gulp.src('app/components/builder/iframe/*')
.pipe(gulp.dest('www/app/components/builder/iframe'));
});
//COPY TINYMCE
gulp.task('copy-tinymce', function () {
return gulp.src('app/vendor/tinymce/**/*')
.pipe(gulp.dest('www/app/vendor/tinymce'));
});
//COPY VENDOR FILES
gulp.task('copy-vendor-files', function () {
return gulp.src(['app/vendor/angular.js','app/vendor/bootstrap.css','app/vendor/tooltip.css','app/vendor/jquery.js'])
.pipe(gulp.dest('www/app/vendor'));
});
//COPY APP IMAGES
gulp.task('copy-app-images', function () {
return gulp.src(['app/images/builder-image.svg','app/images/builder-dimensions.svg','app/images/info_icon.svg'])
.pipe(gulp.dest('www/app/images'));
});
gulp.task('dev', gulp.series(
'inject',
'svg-sprite',
'sass',
'dev-serve'
));
gulp.task('prod', gulp.series(
'inject',
'sass',
'copy-iframe',
'copy-tinymce',
'copy-vendor-files',
'copy-app-images',
'build-html',
'copy-images',
'copy-fonts',
'minify-scripts',
'clean',
'prod-serve'
));
The following image shows the endless loop
Can anyone please help me to find out what I am doing wrong here.
Thanks in advance.
In addition to my comment above, this is probably a problem:
// RELOAD BROWSER
gulp.task('reload', gulp.series('inject'), function () {
browserSync.reload();
});
In your watch statements you call inject and reload, and then in the reload task you call inject first which updates your html files (timestamp if nothing else) and so the html watch is retiggered which calls inject and reload again, etc.
Just use:
// RELOAD BROWSER
gulp.task('reload', function () {
browserSync.reload();
});
and change all your watch's to gulp.series. Since you call reload last there is no need to call inject within the reload task again.
/* PROD */
gulp.task('prod-serve', function () {
browserSync.init({
server: './www'
});
gulp.watch('app/**/*.scss', gulp.series('sass', 'build-html'));
gulp.watch('app/**/*.html', gulp.series('inject', 'minify-scripts', 'reload'));
gulp.watch('app/**/*.js', gulp.series('inject', 'minify-scripts', 'reload'));
gulp.watch('app/images/**/*', gulp.series('copy-images', 'reload'));
gulp.watch('app/fonts/*', gulp.series('copy-fonts', 'reload'));
});
and do the same for your 'dev-serve' task.
[Edit to fix will only run once]
Change to:
// RELOAD BROWSER
gulp.task('reload', gulp.series('inject'), function (done) {
browserSync.reload();
done();
});
Also I'm pretty sure you need to use this form:
// RELOAD BROWSER
//--------------------------------------|
gulp.task('reload', gulp.series('inject', function (done) {
browserSync.reload();
done();
}));
// another ) at the end above too.
See how the last anonymous function is included in the gulp.series call. You need to make that change in quite a few of your tasks.

extjs 6 build async loaded scripts

I'm using extjs6 to developing something, some of scripts is async loaded after I click a button to add a tab to tab panel, this scripts did not include in the build directory when I build my app via sencha app build. What way is right when build the application at this situation?
any help, thanks.
Depending if the scripts should be dynamic i would use the Ext.loader functionalities.
If not, simply include them in your index.html.
The dynamic way could look like this:
Ext.define('muzkatMap.Module', {
singleton: true,
loadAssets: function () {
return this.loadMapScripts();
},
filesLoaded: false,
scriptPaths: [
'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.css',
'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js',
'https://cdnjs.cloudflare.com/ajax/libs/leaflet-providers/1.1.17/leaflet-providers.js'
],
loadMapScripts: function () {
var loadingArray = [], me = this;
return new Ext.Promise(function (resolve, reject) {
Ext.Array.each(me.scriptPaths, function (url) {
loadingArray.push(me.loadMapScript(url));
});
Ext.Promise.all(loadingArray).then(function (success) {
console.log('artefacts were loaded successfully');
resolve('Loading was successful');
},
function (error) {
reject('Error during artefact loading...');
});
});
},
loadMapScript: function (url) {
return new Ext.Promise(function (resolve, reject) {
Ext.Loader.loadScript({
url: url,
onLoad: function () {
console.log(url + ' was loaded successfully');
resolve();
},
onError: function (error) {
reject('Loading was not successful for: ' + url);
}
});
});
}
});
And you simply call in you code:
muzkatMap.Module.loadAssets().then(function(){
// do something with the newly available components
})

setting proxy or backend URL while doing gulp build:dist

We have some code in Angular JS which is build using gulp (babel).
We have necessity to redirect the api service calls to a different server.
Hence, which development we run gulp server and with that add the api-host server in the proxy argument while running gulp server, as follows:
gulp serve:dist --mock no --proxy http://<host-name>:8090
Now, after development, we build and distribute the same bundle to different host (not the same host where the api services are hosted). Now we are not able to connect to the api server. The command we use to build is
gulp build:dist --mock no
Even if we add the proxy argument here, it doesn't works.
gulp build:dist --mock no --proxy http://<host-name>:8090
We tried customizing the "gulpfile.babel.js" file. but no result.
The following is the "gulpfile.babel.js" used:
'use strict';
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var runSequence = require('run-sequence');
var del = require('del');
var _ = require('lodash');
var historyApiFallback = require('connect-history-api-fallback');
var path = require('path');
var args = require('yargs').argv;
var proxyMiddleware = require('http-proxy-middleware');
var merge = require('merge-stream');
// browserSync
var browserSync = require('browser-sync');
var reload = browserSync.reload;
// config & testing
var config = require('./build/build.config.js');
var protractorConfig = require('./build/protractor.config.js');
var karmaConfig = require('./build/karma.config.js');
var KarmaServer = require('karma').Server;
var pkg = require('./package');
/* jshint camelcase:false*/
var webdriverStandalone = require('gulp-protractor').webdriver_standalone;
var webdriverUpdate = require('gulp-protractor').webdriver_update;
//update webdriver if necessary, this task will be used by e2e task
gulp.task('webdriver:update', webdriverUpdate);
// util functions
function sortModulesFirst(a, b) {
var module = /\.module\.js$/;
var aMod = module.test(a.path);
var bMod = module.test(b.path);
// inject *.module.js first
if (aMod === bMod) {
// either both modules or both non-modules, so just sort normally
if (a.path < b.path) {
return -1;
}
if (a.path > b.path) {
return 1;
}
return 0;
} else {
return (aMod ? -1 : 1);
}
}
// serve app in dev mode or prod mode
function serverOptions(logPrefix) {
var proxy = args.proxy;
var options = {
notify: false,
logPrefix: pkg.name,
server: {
baseDir: ['build', 'client']
}
};
// use a proxy server to serve '/api/**'' and '/auth' routes
if (proxy && args.mock === 'no') {
options.server.middleware = [
proxyMiddleware(['/auth', '/api'], {
target: proxy
}),
historyApiFallback()
];
} else {
// use Angular's $httpBackend as the server
options.server.middleware = [
historyApiFallback()
];
}
if (logPrefix) {
options.logPrefix = pkg.name;
}
return options;
}
// run unit tests and watch files
gulp.task('tdd', function(cb) {
new KarmaServer(_.assign({}, karmaConfig, {
singleRun: false,
action: 'watch',
browsers: ['PhantomJS']
}), cb).start();
});
// run unit tests with travis CI
gulp.task('travis', ['build'], function(cb) {
new KarmaServer(_.assign({}, karmaConfig, {
singleRun: true,
browsers: ['PhantomJS']
}), cb).start();
});
// optimize images and put them in the dist folder
gulp.task('images', function() {
return gulp.src(config.images, {
base: config.base
})
.pipe($.imagemin({
progressive: true,
interlaced: true
}))
.pipe(gulp.dest(config.dist))
.pipe($.size({
title: 'images'
}));
});
//generate angular templates using html2js
gulp.task('templates', function() {
return gulp.src(config.tpl)
.pipe($.changed(config.tmp))
.pipe($.html2js({
outputModuleName: 'templates',
base: 'client',
useStrict: true
}))
.pipe($.concat('templates.js'))
.pipe(gulp.dest(config.tmp))
.pipe($.size({
title: 'templates'
}));
});
//generate css files from scss sources
gulp.task('sass', function() {
return gulp.src(config.mainScss)
.pipe($.sass())
.pipe($.autoprefixer({
browsers: ['last 2 versions'],
cascade: false
}))
.on('error', $.sass.logError)
.pipe(gulp.dest(config.tmp))
.pipe($.size({
title: 'sass'
}));
});
//generate a minified css files, 2 js file, change theirs name to be unique, and generate sourcemaps
gulp.task('html', function() {
let useminConfig = {
path: '{build,client}',
css: [$.csso(), $.rev()],
vendorJs: [$.uglify({
mangle: false
}), $.rev()],
mainJs: [$.ngAnnotate(), $.uglify({
mangle: false
}), $.rev()]
};
if (args.mock === 'no') {
// Don't include mock vendor js
useminConfig.mockVendorJs = [];
return gulp.src(config.index)
.pipe($.usemin(useminConfig))
.pipe($.replace('<script src="assets/js/mock-vendor.js"></script>', ''))
.pipe(gulp.dest(config.dist))
.pipe($.size({
title: 'html'
}));
} else {
// Include mock vendor js
useminConfig.mockVendorJs = [$.uglify({
mangle: false
}), $.rev()];
return gulp.src(config.index)
.pipe($.usemin(useminConfig))
.pipe(gulp.dest(config.dist))
.pipe($.size({
title: 'html'
}));
}
});
// clean up mock vendor js
gulp.task('clean:mock', function(cb) {
if (args.mock === 'no') {
let paths = [path.join(config.dist, 'assets/js/mock-vendor.js')];
del(paths).then(() => {
cb();
});
} else {
cb();
}
});
//copy assets in dist folder
gulp.task('copy:assets', function() {
return gulp.src(config.assets, {
dot: true,
base: config.base
})
//.pipe(gulp.dest(config.dist + '/assets'))
.pipe(gulp.dest(config.dist))
.pipe($.size({
title: 'copy:assets'
}));
});
//copy assets in dist folder
gulp.task('copy', function() {
return gulp.src([
config.base + '/*',
'!' + config.base + '/*.html',
'!' + config.base + '/src',
'!' + config.base + '/test',
'!' + config.base + '/bower_components'
])
.pipe(gulp.dest(config.dist))
.pipe($.size({
title: 'copy'
}));
});
//clean temporary directories
gulp.task('clean', del.bind(null, [config.dist, config.tmp]));
//lint files
gulp.task('jshint', function() {
return gulp.src(config.js)
.pipe(reload({
stream: true,
once: true
}))
.pipe($.jshint())
.pipe($.jshint.reporter('jshint-stylish'))
.pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});
// babel
gulp.task('transpile', function() {
return gulp.src(config.js)
.pipe($.sourcemaps.init())
.pipe($.babel({
presets: ['es2015']
}))
.pipe($.sourcemaps.write('.'))
.pipe(gulp.dest(
path.join(config.tmp, 'src')
));
});
// inject js
gulp.task('inject:js', () => {
var injectJs = args.mock === 'no' ?
config.injectJs :
config.injectJs.concat(config.mockJS);
return gulp.src(config.index)
.pipe($.inject(
gulp
.src(injectJs, {
read: false
})
.pipe($.sort(sortModulesFirst)), {
starttag: '<!-- injector:js -->',
endtag: '<!-- endinjector -->',
transform: (filepath) => '<script src="' + filepath.replace('/client', 'tmp') + '"></script>'
}))
.pipe(gulp.dest(config.base));
});
/** ===================================
build tasks
======================================*/
//build files for development
gulp.task('build', ['clean'], function(cb) {
runSequence(['sass', 'templates', 'transpile', 'inject:js'], cb);
});
//build files for creating a dist release
gulp.task('build:dist', ['clean'], function(cb) {
//runSequence(['jshint', 'build', 'copy', 'copy:assets', 'images', 'test:unit'], 'html', cb);
runSequence(['jshint', 'build', 'copy', 'copy:assets', 'images'], 'html', 'clean:mock', cb);
});
// For aniden internal usage
// changed app root for labs server
gulp.task('labs:aniden', function() {
let base = `/hpe/mvno_portal/build/v${pkg.version}/`;
let html = gulp.src(config.dist + '/index.html', {
base: config.dist
})
.pipe($.replace('<base href="/">', `<base href="${base}">`))
.pipe(gulp.dest(config.dist));
let css = gulp.src(config.dist + '/**/*.css', {
base: config.dist
})
.pipe($.replace('url(/', `url(${base}`))
.pipe($.replace('url("/', `url("${base}`))
.pipe(gulp.dest(config.dist));
let js = gulp.src(config.dist + '/**/*.js', {
base: config.dist
})
.pipe($.replace('href="/"', `href="${base}"`))
.pipe(gulp.dest(config.dist));
return merge(html, css, js);
});
/** ===================================
tasks supposed to be public
======================================*/
//default task
gulp.task('default', ['serve']); //
//run unit tests and exit
gulp.task('test:unit', ['build'], function(cb) {
new KarmaServer(_.assign({}, karmaConfig, {
singleRun: true
}), cb).start();
});
// Run e2e tests using protractor, make sure serve task is running.
gulp.task('test:e2e', ['webdriver:update'], function() {
return gulp.src(protractorConfig.config.specs)
.pipe($.protractor.protractor({
configFile: 'build/protractor.config.js'
}))
.on('error', function(e) {
throw e;
});
});
//run the server, watch for file changes and redo tests.
gulp.task('serve:tdd', function(cb) {
runSequence(['serve', 'tdd'], cb);
});
//run the server after having built generated files, and watch for changes
gulp.task('serve', ['build'], function() {
browserSync(serverOptions());
gulp.watch(config.html, reload);
gulp.watch(config.scss, ['sass', reload]);
gulp.watch(config.js, ['jshint', 'transpile']);
gulp.watch(config.tpl, ['templates', reload]);
gulp.watch(config.assets, reload);
});
//run the app packed in the dist folder
gulp.task('serve:dist', ['build:dist'], function() {
browserSync(serverOptions());
});
You can use gulp-ng-config to add constant in you app module.
Or you a JSON as a config file inside your gulp:
//Gulp file
var fs = require('fs');
var settings = JSON.parse(fs.readFileSync('./config/config.json', 'utf8'));
....
gulp.task('statics', g.serve({
port: settings.frontend.ports.development,
...
}));
gulp.task('production', g.serve({
port: settings.frontend.ports.production,
root: ['./dist'],
...
}));

Karma unit test cases not getting executed

Karma unit test cases not getting executed. There are no errors when I run the karma start my.conf.js command. There is nothing displayed in the DEBUG console. Can anyone tell what can be the issue?
Here is my controller file :
define('',['angular', 'moment', '../module'], function (ng, moment) {
'use strict';
ng
.module('PatientRecord.controllers')
.controller('PatientRecordController', ["$scope", "PatientRecordService", 'globalConfig',
function ($scope, PatientRecordService, globalConfig) {
$scope.addSubmitted = false;
$scope.updateSubmitted = false;
$scope.shareSubmitted = false;
$scope.deleteSubmitted = false;
$scope.patientRecords = [];
$scope.modalRecord = {};
$scope.sharedDoctors = [];
$scope.potentialDoctors = [];
$scope.medicalRecordsList = false;
$scope.disableShareButton = true;
$scope.validation = {
success:{
status:false,
message:""
},
error:{
status:false,
message:""
}
};
$scope.file = {};
var patientRecordService = new PatientRecordService();
$scope.getRecord = function () {
$scope.patientRecords.length = 0;
patientRecordService.getRecords().then(function (response) {
$scope.patientRecords = response;
if ($scope.patientRecords.length) {
$scope.medicalRecordsList = true;
}
});
$('body').tooltip({
selector: '.action-icon'
});
};
$scope.addPatientRecord = function ($event) {
$scope.addSubmitted =true;
$scope.patientRecord.shared = [];
$scope.patientRecord.file = $scope.addRecordFileUpload;
patientRecordService.addPatientrecorddata($scope.patientRecord)
.then(function (response) {
$scope.addSubmitted = false;
clearAddRecordFields();
$("#add-record").modal("hide");
$scope.getRecord();
if(response){
$scope.validation.success.status = true;
$scope.validation.success.message = "Record added successfully";
$scope.addForm.$setPristine();
$scope.addForm.addRecordFileUpload.$error.required = true;
$scope.patientRecord.medicalRecordTypeId ="";
$scope.addRecordFileUpload = "";
}else{
$scope.validation.error.status = true;
$scope.validation.error.message = "Confirmation is unsuccessful. Please try again";
}
});
};
$scope.closeAddDialog = function () {
clearAddRecordFields();
$("#add-record").modal("hide");
};
var clearAddRecordFields = function(){
$scope.patientRecord.name = "";
$scope.patientRecord.dateOfRecord = "";
$scope.patientRecord.comments = "";
$scope.patientRecord.medicalRecordType = "";
$scope.patientRecord.addRecordFileName = "";
$("#patientRecord_name").val("");
$("#dateOfRecord").val("");
$("#patientRecord_comments").val("");
$("#medicalRecordType").val("");
$("#addRecordFileName").html("");
}
var dispalyFileName = function (FileControlId, placeholderId) {
if ($scope.currntFileObject) {
$('#' + placeholderId).empty().html($scope.currntFileObject.name);
}
};
$scope.openupdateModal = function (record) {
$scope.modalRecord = _.clone(record);
var dateOfRecord = moment($scope.modalRecord.date_of_record).format("DD MMM, YYYY");
$scope.modalRecord.date_of_record = dateOfRecord;
$scope.disableShareButton = true;
$("#updateRecordFileName").html("");
//Get Shared Doctors Data
patientRecordService.getSharedDoctorsByRecordId(record.id).then(function (response) {
$scope.sharedDoctors = _.where(response, { isShared: true })
$scope.potentialDoctors = _.where(response, { isShared: false })
});
};
$scope.updatePatientrecord = function (index) {
$scope.updateSubmitted = true;
$scope.modalRecord.medicalRecordTypeId = $("#update_recordtype").val();
$scope.modalRecord.file = $scope.updateRecordFileUpload;
patientRecordService.updatePatientdata($scope.modalRecord)
.then(function (response) {
$scope.updateSubmitted = false;
$scope.getRecord();
});
};
angular.element("#selectDoctorToShare_foreditDialog").change(function () {
var selectedDoctorId = $("#selectDoctorToShare_foreditDialog").val();
$scope.$apply(function () {
if (selectedDoctorId != 0) {
$scope.disableShareButton = false;
} else {
$scope.disableShareButton = true;
}
});
});
$scope.closeUpdateDialog = function () {
$("#patientRecord_name").val("");
$("#datetimepicker1").val("");
$("#patientRecord_comments").val("");
$("#medicalRecordType").val("");
$("#addRecordFileName").html("");
$("#modify-record").modal("hide");
$scope.getRecord();
};
$scope.openShareDialog = function (data) {
$scope.modalRecord = data;
$scope.disableShareButton = true;
patientRecordService.getSharedDoctorsByRecordId(data.id)
.then(function (response) {
$scope.sharedDoctors = _.where(response, { isShared: true })
$scope.potentialDoctors = _.where(response, { isShared: false })
});
}
$scope.sharePatientRecord = function(doctorDropdownId,recordId){
$scope.shareSubmitted = true;
var selectedDoctorId = $("#"+doctorDropdownId).val();
patientRecordService.sharePatientData(recordId, selectedDoctorId).then(function(response){
$scope.shareSubmitted = false;
if(response){
if(doctorDropdownId == "selectDoctorToShare_forShareDialog") {
$("#share-record").modal("hide");
}
alert("Record shared successfully");
patientRecordService.getSharedDoctorsByRecordId($scope.modalRecord.id)
.then(function(response) {
$scope.sharedDoctors = _.where(response, {isShared: true})
$scope.potentialDoctors = _.where(response, {isShared: false})
});
$scope.disableShareButton = true;
} else {
alert("Something went wrong! Try again")
}
});
};
angular.element("#selectDoctorToShare_forShareDialog").change(function () {
var selectedDoctorId = $("#selectDoctorToShare_forShareDialog").val();
$scope.$apply(function () {
if (selectedDoctorId != 0) {
$scope.disableShareButton = false;
} else {
$scope.disableShareButton = true;
}
});
});
$scope.OpenDeleteModal = function (data, index) {
$scope.modalRecord = data;
$scope.index = index;
$("#delete-record-modal").modal("show");
}
$scope.deletePatientrecord = function (data, index) {
$scope.deleteSubmitted = true;
var patientRecordService = new PatientRecordService();
patientRecordService.deletePatientdata(data.id).then(function (response) {
$scope.deleteSubmitted = false;
$("#delete-record-modal").modal("hide");
$scope.getRecord();
if(response){
$scope.validation.success.status = true;
$scope.validation.success.message = "Record deleted successfully";
}else{
$scope.validation.error.status = true;
$scope.validation.error.message = "Record could not be deleted";
}
});
};
$scope.getRecord();
}
]);
});
Test file for controller:
// Testing PatientRecordController
define('',['angular', 'moment', '../module'], function (ng, moment) {
describe("Controller: PatientRecordController", function() {
// load the controller's module
beforeEach(module('PatientRecord.controllers'));
var PatientRecordController,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
PatientRecordController = $controller('PatientRecordController', {
'$scope': scope
});
}));
// Check if controller is defined
it("should have a PatientRecordController as controller", function() {
expect(PatientRecord.controllers.PatientRecordController).toBeDefined();
console.log('controllers defined');
});
});
});
my.conf.js file:
module.exports = function(config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// frameworks to use
frameworks: ['jasmine','requirejs'],
// list of files / patterns to load in the browser
files: [
'app/modules/PatientRecord/controllers/PatientRecordController.js'
],
// list of files to exclude
exclude: [
],
// test results reporter to use
// possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
reporters: ['progress','coverage','html'],
htmlReporter: {
outputFile: 'tests/units.html'
},
preprocessors: {
// source files, that you wanna generate coverage for
// do not include tests or libraries
// (these files will be instrumented by Istanbul)
'src/**/*.js': ['coverage']
},
// optionally, configure the reporter
coverageReporter: {
type : 'html',
dir : 'coverage/',
file:'coverageds.txt'
},
// 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_INFO,
// enable / disable watching file and executing tests whenever any file changes
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
});
};
The problem is in the files section of your karma configuration file. First, you need to include all your application's library dependencies (like Jquery, Angular, Bootstrap) if you are using any. Second, you need to include the files that you are testing. Include your application's initialization file (app.js) and submodules first. Last, you need to include that actual tests themselves. The order in which you include things does matter. A lot of people use RequireJS for this, but I don't think that's completely necessary unless you have a large and complex project.

Can't get test through the end with protractor

I have simple test doing login and trying to check if it's success:
describe('My Angular App', function () {
describe('visiting the main homepage', function () {
beforeEach(function () {
browser.get('/');
element(By.id("siteLogin")).click();
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
element(By.id("formLoginButton")).click().then(function() {
browser.getCurrentUrl().then(function(url){
expect(url).toContain("profile");
});
});
});
});
});
It goes well until that last part where I'm checking URL, and in Selenium Server I get:
INFO - Executing: [execute async script: try { return (function (rootSelector, callback) {
var el = document.querySelector(rootSelector);
try {
if (window.getAngularTestability) {
window.getAngularTestability(el).whenStable(callback);
return;
}
if (!window.angular) {
throw new Error('angular could not be found on the window');
}
if (angular.getTestability) {
angular.getTestability(el).whenStable(callback);
} else {
if (!angular.element(el).injector()) {
throw new Error('root element (' + rootSelector + ') has no injector.' +
' this may mean it is not inside ng-app.');
}
angular.element(el).injector().get('$browser').
notifyWhenNoOutstandingRequests(callback);
}
} catch (err) {
callback(err.message);
}
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]])
and also I get:
Failures:
1) My Angular App visiting the main homepage should login successfully
Message:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
My protractor-conf.js:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
baseUrl: 'http://localhost:8080/Mysite',
capabilities: {
'browserName': 'firefox' // muste use firefox because I can't get .click() to work in Chrome
},
specs: [
'spec-e2e/*.js'
],
framework: 'jasmine2',
jasmineNodeOpts: {
isVerbose: true,
showColors: true,
defaultTimeoutInterval: 30000
}
};
I appreciate any help on this one.
Thanks
Looks like there is a non-Angular page opened after a click. If this is the case, you need to turn the synchronization between Protractor and Angular off:
afterEach(function () {
browser.ignoreSynchronization = false;
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
browser.ignoreSynchronization = true;
element(By.id("formLoginButton")).click().then(function() {
expect(browser.getCurrentUrl()).toContain("profile");
});
});
Note that you don't need to explicitly resolve the promise returned by getCurrentUrl and can let the expect() do that for you implicitly.
You may also need to wait for the URL to change:
var urlChanged = function(desiredUrl) {
return browser.getCurrentUrl().then(function(url) {
return url == desiredUrl;
});
};
browser.wait(urlChanged("my desired url"), 5000);

Resources