'use strict';
describe("angular.scenario.dsl", function() {
var element;
var $window, $root;
var eventLog;
afterEach(function() {
dealoc(element);
});
beforeEach(module('ngSanitize'));
beforeEach(inject(function($injector) {
eventLog = [];
$window = {
document: window.document.body,
angular: new angular.scenario.testing.MockAngular()
};
jqLite($window.document).data('$injector', $injector).attr('ng-app', '').addClass('html');
$root = $injector.get('$rootScope');
$root.emit = function(eventName) {
eventLog.push(eventName);
};
$root.on = function(eventName) {
eventLog.push('Listener Added for ' + eventName);
};
$root.futures = [];
$root.futureLog = [];
$root.$window = $window;
$root.addFuture = function(name, fn) {
this.futures.push(name);
fn.call(this, function(error, result) {
$root.futureError = error;
$root.futureResult = result;
$root.futureLog.push(name);
});
};
$root.dsl = {};
angular.forEach(angular.scenario.dsl, function(fn, name) {
$root.dsl[name] = function() {
return fn.call($root).apply($root, arguments);
};
});
$root.application = new angular.scenario.Application(jqLite($window.document));
$root.application.getWindow_ = function() {
return $window;
};
$root.application.navigateTo = function(url, callback) {
$window.location = url;
callback();
};
// Just use the real one since it delegates to this.addFuture
$root.addFutureAction = angular.scenario.
SpecRunner.prototype.addFutureAction;
jqLite($window.document).empty();
}));
afterEach(function(){
jqLite($window.document).removeData('$injector');
});
describe('Pause', function() {
it('should pause until resume to complete', function() {
expect($window.resume).toBeUndefined();
$root.dsl.pause();
expect(angular.isFunction($window.resume)).toBeTruthy();
expect($root.futureLog).toEqual([]);
$window.resume();
expect($root.futureLog).
toEqual(['pausing for you to resume']);
expect(eventLog).toContain('InteractivePause');
});
});
describe('Sleep', function() {
beforeEach(function() {
$root.$window.setTimeout = function(fn, value) {
$root.timerValue = value;
fn();
};
});
it('should sleep for specified seconds', function() {
$root.dsl.sleep(10);
expect($root.timerValue).toEqual(10000);
expect($root.futureResult).toEqual(10000);
});
});
describe('Expect', function() {
it('should chain and execute matcher', function() {
var future = {value: 10};
var result = $root.dsl.expect(future);
result.toEqual(10);
expect($root.futureError).toBeUndefined();
expect($root.futureResult).toBeUndefined();
result = $root.dsl.expect(future);
result.toEqual(20);
expect($root.futureError).toBeDefined();
});
});
describe('Browser', function() {
describe('Reload', function() {
it('should navigateTo', function() {
$window.location = {
href: '#foo'
};
$root.dsl.browser().reload();
expect($root.futureResult).toEqual('#foo');
expect($window.location).toEqual('#foo');
});
});
describe('NavigateTo', function() {
it('should allow a string url', function() {
$root.dsl.browser().navigateTo('http://myurl');
expect($window.location).toEqual('http://myurl');
expect($root.futureResult).toEqual('http://myurl');
});
it('should allow a future url', function() {
$root.dsl.browser().navigateTo('http://myurl', function() {
return 'http://futureUrl/';
});
expect($window.location).toEqual('http://futureUrl/');
expect($root.futureResult).toEqual('http://futureUrl/');
});
it('should complete if angular is missing from app frame', function() {
delete $window.angular;
$root.dsl.browser().navigateTo('http://myurl');
expect($window.location).toEqual('http://myurl');
expect($root.futureResult).toEqual('http://myurl');
});
});
describe('window', function() {
beforeEach(function() {
$window.location = {
href: 'http://myurl/some/path?foo=10#/bar?x=2',
pathname: '/some/path',
search: '?foo=10',
hash: '#bar?x=2'
};
});
it('should return full URL for href', function() {
$root.dsl.browser().window().href();
expect($root.futureResult).toEqual($window.location.href);
});
it('should return the pathname', function() {
$root.dsl.browser().window().path();
expect($root.futureResult).toEqual($window.location.pathname);
});
it('should return the search part', function() {
$root.dsl.browser().window().search();
expect($root.futureResult).toEqual($window.location.search);
});
it('should return the hash without the #', function() {
$root.dsl.browser().window().hash();
expect($root.futureResult).toEqual('bar?x=2');
});
});
describe('location', function() {
beforeEach(inject(function($injector) {
angular.extend($injector.get('$location'), {
url: function() {return '/path?search=a#hhh';},
path: function() {return '/path';},
search: function() {return {search: 'a'};},
hash: function() {return 'hhh';}
});
}));
it('should return full url', function() {
$root.dsl.browser().location().url();
expect($root.futureResult).toEqual('/path?search=a#hhh');
});
it('should return the pathname', function() {
$root.dsl.browser().location().path();
expect($root.futureResult).toEqual('/path');
});
it('should return the query string as an object', function() {
$root.dsl.browser().location().search();
expect($root.futureResult).toEqual({search: 'a'});
});
it('should return the hash without the #', function() {
$root.dsl.browser().location().hash();
expect($root.futureResult).toEqual('hhh');
});
});
});
describe('Element Finding', function() {
var doc;
beforeEach(inject(function($injector) {
doc = _jQuery($window.document).append('
').find('.body');
}));
describe('Select', function() {
it('should select single option', function() {
doc.append(
''
);
$root.dsl.select('test').option('A');
expect(doc.find('[ng-model="test"]').val()).toEqual('A');
});
it('should select single option using data-ng', function() {
doc.append(
''
);
$root.dsl.select('test').option('A');
expect(doc.find('[data-ng-model="test"]').val()).toEqual('A');
});
it('should select single option using x-ng', function() {
doc.append(
''
);
$root.dsl.select('test').option('A');
expect(doc.find('[x-ng-model="test"]').val()).toEqual('A');
});
it('should select option by exact name', function() {
doc.append(
''
);
$root.dsl.select('test').option('one');
expect(doc.find('[ng-model="test"]').val()).toEqual('D');
});
it('should select option by name if no exact match and name contains value', function() {
doc.append(
''
);
$root.dsl.select('test').option('one');
expect(doc.find('[ng-model="test"]').val()).toEqual('A');
});
it('should select multiple options', function() {
doc.append(
''
);
$root.dsl.select('test').options('A', 'B');
expect(doc.find('[ng-model="test"]').val()).toEqual(['A','B']);
});
it('should fail to select multiple options on non-multiple select', function() {
doc.append('');
$root.dsl.select('test').options('A', 'B');
expect($root.futureError).toMatch(/did not match/);
});
it('should fail to select an option that does not exist', function(){
doc.append(
''
);
$root.dsl.select('test').option('three');
expect($root.futureError).toMatch(/not found/);
});
});
describe('Element', function() {
it('should execute click', function() {
var clicked;
// Hash is important, otherwise we actually
// go to a different page and break the runner
doc.append('');
doc.find('a').click(function() {
clicked = true;
});
$root.dsl.element('a').click();
});
it('should navigate page if click on anchor', function() {
expect($window.location).not.toEqual('#foo');
doc.append('');
$root.dsl.element('a').click();
expect($window.location).toMatch(/#foo$/);
});
it('should not navigate if click event was cancelled', function() {
var initLocation = $window.location,
elm = jqLite('');
doc.append(elm);
elm.on('click', function(event) {
event.preventDefault();
});
$root.dsl.element('a').click();
expect($window.location).toBe(initLocation);
dealoc(elm);
});
it('should execute dblclick', function() {
var clicked;
// Hash is important, otherwise we actually
// go to a different page and break the runner
doc.append('');
doc.find('a').dblclick(function() {
clicked = true;
});
$root.dsl.element('a').dblclick();
});
it('should navigate page if dblclick on anchor', function() {
expect($window.location).not.toEqual('#foo');
doc.append('');
$root.dsl.element('a').dblclick();
expect($window.location).toMatch(/#foo$/);
});
it('should not navigate if dblclick event was cancelled', function() {
var initLocation = $window.location,
elm = jqLite('');
doc.append(elm);
elm.on('dblclick', function(event) {
event.preventDefault();
});
$root.dsl.element('a').dblclick();
expect($window.location).toBe(initLocation);
dealoc(elm);
});
it('should execute mouseover', function() {
var mousedOver;
doc.append('');
doc.find('div').mouseover(function() {
mousedOver = true;
});
$root.dsl.element('div').mouseover();
expect(mousedOver).toBe(true);
});
it('should bubble up the mouseover event', function() {
var mousedOver;
doc.append('');
doc.find('#outer').mouseover(function() {
mousedOver = true;
});
$root.dsl.element('#inner').mouseover();
expect(mousedOver).toBe(true);
});
it('should execute mousedown', function() {
var mousedDown;
doc.append('');
doc.find('div').mousedown(function() {
mousedDown = true;
});
$root.dsl.element('div').mousedown();
expect(mousedDown).toBe(true);
});
it('should bubble up the mousedown event', function() {
var mousedDown;
doc.append('');
doc.find('#outer').mousedown(function() {
mousedDown = true;
});
$root.dsl.element('#inner').mousedown();
expect(mousedDown).toBe(true);
});
it('should execute mouseup', function() {
var mousedUp;
doc.append('');
doc.find('div').mouseup(function() {
mousedUp = true;
});
$root.dsl.element('div').mouseup();
expect(mousedUp).toBe(true);
});
it('should bubble up the mouseup event', function() {
var mousedUp;
doc.append('');
doc.find('#outer').mouseup(function() {
mousedUp = true;
});
$root.dsl.element('#inner').mouseup();
expect(mousedUp).toBe(true);
});
it('should count matching elements', function() {
doc.append('');
$root.dsl.element('span').count();
expect($root.futureResult).toEqual(2);
});
it('should return count of 0 if no matching elements', function() {
$root.dsl.element('span').count();
expect($root.futureResult).toEqual(0);
});
it('should get attribute', function() {
doc.append('');
$root.dsl.element('#test').attr('class');
expect($root.futureResult).toEqual('foo');
});
it('should set attribute', function() {
doc.append('');
$root.dsl.element('#test').attr('class', 'bam');
expect(doc.find('#test').attr('class')).toEqual('bam');
});
it('should get property', function() {
doc.append('');
$root.dsl.element('#test').prop('className');
expect($root.futureResult).toEqual('foo');
});
it('should set property', function() {
doc.append('');
$root.dsl.element('#test').prop('className', 'bam');
expect(doc.find('#test').prop('className')).toEqual('bam');
});
it('should get css', function() {
doc.append('');
$root.dsl.element('#test').css('height');
expect($root.futureResult).toMatch(/30px/);
});
it('should set css', function() {
doc.append('');
$root.dsl.element('#test').css('height', '20px');
expect(doc.find('#test').css('height')).toEqual('20px');
});
it('should add all jQuery key/value methods', function() {
var METHODS = ['css', 'attr'];
var chain = $root.dsl.element('input');
angular.forEach(METHODS, function(name) {
expect(angular.isFunction(chain[name])).toBeTruthy();
});
});
it('should get val', function() {
doc.append('');
$root.dsl.element('input').val();
expect($root.futureResult).toEqual('bar');
});
it('should set val', function() {
doc.append('');
$root.dsl.element('input').val('baz');
expect(doc.find('input').val()).toEqual('baz');
});
it('should use correct future name for generated set methods', function() {
doc.append('');
$root.dsl.element('input').val(false);
expect($root.futures.pop()).toMatch(/element 'input' set val/);
});
it('should use correct future name for generated get methods', function() {
doc.append('');
$root.dsl.element('input').val();
expect($root.futures.pop()).toMatch(/element 'input' val/);
});
it('should add all jQuery property methods', function() {
var METHODS = [
'val', 'text', 'html', 'height', 'innerHeight', 'outerHeight', 'width',
'innerWidth', 'outerWidth', 'position', 'scrollLeft', 'scrollTop', 'offset'
];
var chain = $root.dsl.element('input');
angular.forEach(METHODS, function(name) {
expect(angular.isFunction(chain[name])).toBeTruthy();
});
});
it('should execute custom query', function() {
doc.append('');
$root.dsl.element('#test').query(function(elements, done) {
done(null, elements.attr('href'));
});
expect($root.futureResult).toEqual('http://example.com/myUrl');
});
it('should use the selector as label if none is given', function() {
$root.dsl.element('mySelector');
expect($root.label).toEqual('mySelector');
});
it('should include the selector in paren when a label is given', function() {
$root.dsl.element('mySelector', 'myLabel');
expect($root.label).toEqual('myLabel ( mySelector )');
});
});
describe('Repeater', function() {
var chain;
beforeEach(inject(function($compile, $rootScope) {
element = $compile(
'')($rootScope);
$rootScope.items = [{name:'misko', gender:'male'}, {name:'felisa', gender:'female'}];
$rootScope.$apply();
doc.append(element);
chain = $root.dsl.repeater('ul li');
}));
it('should get the row count', function() {
chain.count();
expect($root.futureResult).toEqual(2);
});
it('should return 0 if repeater doesnt match', inject(function($rootScope) {
$rootScope.items = [];
$rootScope.$apply();
chain.count();
expect($root.futureResult).toEqual(0);
}));
it('should get a row of bindings', function() {
chain.row(1);
expect($root.futureResult).toEqual(['felisa', 'female']);
});
it('should get a column of bindings', function() {
chain.column('i.gender');
expect($root.futureResult).toEqual(['male', 'female']);
});
it('should use the selector as label if none is given', function() {
expect($root.label).toEqual('ul li');
});
it('should include the selector in paren when a label is given', function() {
$root.dsl.repeater('mySelector', 'myLabel');
expect($root.label).toEqual('myLabel ( ul li mySelector )');
});
});
describe('Binding', function() {
var compile;
beforeEach(inject(function($compile, $rootScope) {
compile = function(html, value) {
element = $compile(html)($rootScope);
doc.append(element);
$rootScope.foo = {bar: value || 'some value'};
$rootScope.$apply();
};
}));
it('should select binding in interpolation', function() {
compile('{{ foo.bar }}');
$root.dsl.binding('foo.bar');
expect($root.futureResult).toEqual('some value');
});
it('should select binding in multiple interpolations', function() {
compile('{{ foo.bar }}
{{ true }}');
$root.dsl.binding('foo.bar');
expect($root.futureResult).toEqual('some value');
$root.dsl.binding('true');
expect($root.futureResult).toEqual('true');
});
it('should select binding by name', function() {
compile('');
$root.dsl.binding('foo.bar');
expect($root.futureResult).toEqual('some value');
});
it('should select binding by regexp', function() {
compile('some value');
$root.dsl.binding(/^foo\..+/);
expect($root.futureResult).toEqual('some value');
});
it('should return innerHTML for all the other elements', function() {
compile('', 'some value');
$root.dsl.binding('foo.bar');
expect($root.futureResult.toLowerCase()).toEqual('some value');
});
it('should select binding in template by name', function() {
compile('', 'bar');
$root.dsl.binding('foo.bar');
expect($root.futureResult).toEqual('bar');
});
it('should match bindings by substring match', function() {
compile('', 'binding value');
$root.dsl.binding('foo . bar');
expect($root.futureResult).toEqual('binding value');
});
it('should return error if no bindings in document', function() {
$root.dsl.binding('foo.bar');
expect($root.futureError).toMatch(/did not match/);
});
it('should return error if no binding matches', function() {
compile('some value');
$root.dsl.binding('foo.bar');
expect($root.futureError).toMatch(/did not match/);
});
});
describe('Using', function() {
it('should prefix selector in $document.elements()', function() {
var chain;
doc.append(
'' +
''
);
chain = $root.dsl.using('div#test2');
chain.input('test.input').enter('foo');
var inputs = _jQuery('input[ng-model="test.input"]');
expect(inputs.first().val()).toEqual('something');
expect(inputs.last().val()).toEqual('foo');
});
it('should use the selector as label if none is given', function() {
$root.dsl.using('mySelector');
expect($root.label).toEqual('mySelector');
});
it('should include the selector in paren when a label is given', function() {
$root.dsl.using('mySelector', 'myLabel');
expect($root.label).toEqual('myLabel ( mySelector )');
});
});
describe('Input', function() {
it('should change value in text input', inject(function($compile) {
runs(function() {
element = $compile('')($root);
doc.append(element);
var chain = $root.dsl.input('test.input');
chain.enter('foo');
expect(_jQuery('input[ng-model="test.input"]').val()).toEqual('foo');
});
// cleanup the event queue
waits(0);
runs(function() {
expect($root.test.input).toBe('foo');
});
}));
it('should change value in text input in dash form', function() {
doc.append('');
var chain = $root.dsl.input('test.input');
chain.enter('foo');
expect(_jQuery('input[ng-model="test.input"]').val()).toEqual('foo');
});
it('should change value in text input in data-ng form', function() {
doc.append('');
var chain = $root.dsl.input('test.input');
chain.enter('foo');
expect(_jQuery('input[data-ng-model="test.input"]').val()).toEqual('foo');
});
it('should change value in text input in x-ng form', function() {
doc.append('');
var chain = $root.dsl.input('test.input');
chain.enter('foo');
expect(_jQuery('input[x-ng-model="test.input"]').val()).toEqual('foo');
});
it('should return error if no input exists', function() {
var chain = $root.dsl.input('test.input');
chain.enter('foo');
expect($root.futureError).toMatch(/did not match/);
});
it('should toggle checkbox state', function() {
doc.append('');
expect(_jQuery('input[ng-model="test.input"]').
prop('checked')).toBe(true);
var chain = $root.dsl.input('test.input');
chain.check();
expect(_jQuery('input[ng-model="test.input"]').
prop('checked')).toBe(false);
$window.angular.reset();
chain.check();
expect(_jQuery('input[ng-model="test.input"]').
prop('checked')).toBe(true);
});
it('should return error if checkbox did not match', function() {
var chain = $root.dsl.input('test.input');
chain.check();
expect($root.futureError).toMatch(/did not match/);
});
it('should select option from radio group', function() {
doc.append(
'' +
''
);
// HACK! We don't know why this is sometimes false on chrome
_jQuery('input[ng\\:model="test.input"][value="bar"]').prop('checked', true);
expect(_jQuery('input[ng\\:model="test.input"][value="bar"]').
prop('checked')).toBe(true);
expect(_jQuery('input[ng\\:model="test.input"][value="foo"]').
prop('checked')).toBe(false);
var chain = $root.dsl.input('test.input');
chain.select('foo');
expect(_jQuery('input[ng\\:model="test.input"][value="bar"]').
prop('checked')).toBe(false);
expect(_jQuery('input[ng\\:model="test.input"][value="foo"]').
prop('checked')).toBe(true);
});
it('should return error if radio button did not match', function() {
var chain = $root.dsl.input('test.input');
chain.select('foo');
expect($root.futureError).toMatch(/did not match/);
});
describe('val', function() {
it('should return value in text input', function() {
doc.append('');
$root.dsl.input('test.input').val();
expect($root.futureResult).toEqual("something");
});
});
});
describe('Textarea', function() {
it('should change value in textarea', function() {
doc.append('');
var chain = $root.dsl.input('test.textarea');
chain.enter('foo');
expect(_jQuery('textarea[ng-model="test.textarea"]').val()).toEqual('foo');
});
it('should return error if no textarea exists', function() {
var chain = $root.dsl.input('test.textarea');
chain.enter('foo');
expect($root.futureError).toMatch(/did not match/);
});
});
});
});