Can't get test through the end with protractor - angularjs

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);

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.

Unable to update protractor config at runtime

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()
});
});
}

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
})

Crash protractor on Chrome

I am experiencing problems when running the following script on a specific site. The script works on firefox but on chrome it crashes with the following stacktrace:
Protractor.waitForAngular() - Locator: By(css selector, *[id="loading-app-content"])
at WebDriver.schedule (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver.js:377:17)
at ProtractorBrowser.executeAsyncScript_ (/usr/local/lib/node_modules/protractor/built/browser.js:232:28)
at runWaitForAngularScript (/usr/local/lib/node_modules/protractor/built/browser.js:263:30)
at ProtractorBrowser.waitForAngular (/usr/local/lib/node_modules/protractor/built/browser.js:266:16)
at ElementArrayFinder.getWebElements (/usr/local/lib/node_modules/protractor/built/element.js:154:29)
at ElementFinder.isPresent (/usr/local/lib/node_modules/protractor/built/element.js:904:46)
at /usr/local/lib/node_modules/protractor/built/expectedConditions.js:86:20
at /usr/local/lib/node_modules/protractor/built/expectedConditions.js:63:20
at /usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver.js:716:14
at TaskQueue.execute_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:2913:14)
My protractor-conf.js
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub', // This is targetting your local running instance of the selenium webdriver
specs: [
'./features/**/*.feature'
],
capabilities: {
browserName: 'chrome',
},
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'), // Here it is
cucumberOpts: {
format: 'pretty',
require: './features/step_definitions/**/*.js' // This is where we'll be writing our actual tests
},
allScriptsTimeout: 11000,
onPrepare: function() {
browser.driver.manage().window().setSize(1400, 900);
browser.driver.manage().window().maximize();
},
useAllAngular2AppRoots: true
};
The test:
test = function() {
var EC = protractor.ExpectedConditions;
var el= element(by.className("preview-toggle"));
this.Given(/^I open up the application$/, function (callback) {
browser.get('foo.com').then(callback);
});
this.When(/^I click on add$/, function (callback) {
// Write code here that turns the phrase above into concrete actions
browser.wait(EC.invisibilityOf(element(by.id("loading-app-content"))), 30000).then(function () {
browser.wait(EC.presenceOf(element(by.css(".preview-toggle"))), 30000).then(function () {
browser.wait(EC.visibilityOf(element(by.css(".preview-toggle"))), 30000).then(function () {
browser.wait(EC.elementToBeClickable(element(by.css(".preview-toggle"))), 30000).then(function () {
el.click().then(callback);
});
});
});
});
});
this.Then(/^I should be the best$/, function (callback) {
callback();
});
};
module.exports=test;
Thing is every actions I do (even clicking on body) gives this error. Any other angular page works in chrome.
My specfic question is: what is causing chrome to crash?

ngDescribe Won't Complete Second Spec

I'm having trouble with a chained spec when using ngDescribe. The second spec never finishes and times out. If I comment out the first spec, the second spec completes successfully. So, I know each spec is valid and works.
Here is the whole test with both specs.
var baseNotes = window.__mocks__['base-data/notes'];
var baseUsers = window.__mocks__['base-data/users'];
var baseDepartments = window.__mocks__['base-data/departments'];
// Create object to describe all the mocks
var mock = {
app: {
// Mock out all required DB functionality
LocalDb: {
'service': {
dbs: [
{
notes: true
}
]
},
'getDbInfo': function($q) {
return $q.when()
},
'allDocs': function($q) {
return $q.when(baseNotes);
},
'putDoc': function($q) {
var note = {};
note._id = 'xyz123';
console.log("Here is the note now");
console.log(note);
return $q.when(note);
}
},
Users: {
getUsers: function($q) {
return $q.when(baseUsers)
}
},
Departments: {
getDepartments: function($q) {
return $q.when(baseDepartments);
}
}
}
};
ngDescribe
({
name: 'Process Generic Notes Requests',
modules: ['app'],
// Must include $rootScope so that deps.step() is available
inject: ['Notes', 'NoteFactory', '$rootScope'],
mock: mock,
tests: function(deps){
beforeEach(function() {
// Preload the service with notes
deps.Notes.notes = baseNotes;
});
it('should refresh notes from db', function(done) {
// remove the notes from the service
deps.Notes.notes = [];
expect(deps.Notes.notes.length).toEqual(0);
deps.Notes.getNotes(true).then(
function(result) {
expect(result.length).toEqual(3);
done();
}
);
deps.step();
});
it('should fetch notes from memory', function(done) {
deps.Notes.getNotes().then(
function(result) {
expect(result.length).toEqual(3);
done();
}
);
deps.step();
});
it('should get specific note', function(done) {
deps.Notes.getNote(baseNotes[0]._id).then(
function(result) {
expect(result._id).toEqual(baseNotes[0]._id);
done();
}
);
deps.step();
});
it('should get last note', function(done) {
deps.Notes.getLastNote().then(
function(result) {
expect(result._id).toEqual('1436880052000-34lekd');
done();
}
);
deps.step();
});
it('should summarize notes', function() {
var summary = deps.Notes.summarizeNotes();
expect(summary.total).toEqual(3);
expect(summary.finished).toEqual(2);
expect(summary.remaining).toEqual(1);
console.log("Done processing summarize at " + Date.now());
});
}
})({
name: 'Process Update Note Requests',
modules: ['app'],
// Must include $rootScope so that deps.step() is available
inject: ['Notes', 'NoteFactory', '$rootScope'],
mock: mock,
tests: function (deps) {
var newNote;
beforeEach(function () {
// Preload the service with notes
deps.Notes.notes = baseNotes;
// Create a new note
newNote = deps.NoteFactory.createNote();
});
it('should save a new note', function (done) {
console.log("Starting save a note at " + Date.now());
console.log("Here is the note about to be saved");
console.log(newNote);
deps.Notes.updateNote(newNote).then(
function (response) {
dump('Response from update note!');
dump(response);
expect(response._id).toEqual('xyz123');
done();
},
function (error) {
dump('Failed to update note!');
dump(error);
expect('good').toEqual('bad');
done();
}
);
deps.step();
});
}
});

Resources