Skip to content
This repository has been archived by the owner on Aug 29, 2023. It is now read-only.

Commit

Permalink
fix(tests): support for Angular 1.4 and improved use of angular-mocks.
Browse files Browse the repository at this point in the history
Fix checkbox, switch, and tooltip to link before ngAria
- since ngAgria increased its directive priority.
test-utils.js now decorates $$rAF and $mdAria
  • Loading branch information
ThomasBurleson committed Apr 28, 2015
1 parent 02a4af5 commit 48ee986
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 91 deletions.
53 changes: 44 additions & 9 deletions config/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,30 @@ beforeEach(function() {
* Create a fake version of $$rAF that does things synchronously
*/
module('ng', function($provide) {
$provide.value('$$rAF', mockRaf);
/**
* Add throttle() and wrap .flush() to catch `no callbacks present`
* errors
*/
$provide.decorator('$$rAF', function throttleInjector($delegate){

function mockRaf(cb) {
cb();
}
mockRaf.throttle = function(cb) {
return function() {
cb.apply(this, arguments);
$delegate.throttle = function(cb) {
return function() {
cb.apply(this, arguments);
};
};
};
mockRaf.flush = angular.noop;

var ngFlush = $delegate.flush;
$delegate.flush = function() {
try { ngFlush(); }
catch(e) { ; }
};

return $delegate;
});

});


jasmine.addMatchers({

toHaveClass: function() {
Expand Down Expand Up @@ -120,3 +130,28 @@ beforeEach(function() {
});

});


beforeEach(function() {

/**
* Create a fake version of $$rAF that does things synchronously
*/
module('material.core', function($provide) {

/**
* Intercept to make .expectWithText() to be synchronous
*/
$provide.decorator('$mdAria', function($delegate){

$delegate.expectWithText = function(element, attrName){
$delegate.expect(element, attrName, element.text().trim());
};

return $delegate;
});

});


});
1 change: 1 addition & 0 deletions src/components/checkbox/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ function MdCheckboxDirective(inputDirective, $mdInkRipple, $mdAria, $mdConstant,
restrict: 'E',
transclude: true,
require: '?ngModel',
priority:210, // Run before ngAria
template:
'<div class="md-container" md-ink-ripple md-ink-ripple-checkbox>' +
'<div class="md-icon"></div>' +
Expand Down
98 changes: 49 additions & 49 deletions src/components/checkbox/checkbox.spec.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,52 @@

describe('mdCheckbox', function() {
var CHECKED_CSS = 'md-checked';
var $compile, $rootScope;

beforeEach(module('material.components.checkbox'));
beforeEach(module('ngAria'));
beforeEach(module('material.components.checkbox'));

beforeEach( inject(function(_$compile_, _$rootScope_){
$compile = _$compile_;
$rootScope = _$rootScope_;
}));

function buildInstance (template, scope){
var element = $compile(template)(scope || $rootScope);
$rootScope.$apply();

return element;
}

it('should warn developers they need a label', inject(function($compile, $rootScope, $log){
spyOn($log, "warn");

var element = $compile('<div>' +
var element = buildInstance('<div>' +
'<md-checkbox ng-model="blue">' +
'</md-checkbox>' +
'</div>')($rootScope);
'</div>');

expect($log.warn).toHaveBeenCalled();
}));

it('should copy text content to aria-label', inject(function($compile, $rootScope){
var element = $compile('<div>' +
var element = buildInstance('<div>' +
'<md-checkbox ng-model="blue">' +
'Some text' +
'</md-checkbox>' +
'</div>')($rootScope);
'</div>');

var cbElements = element.find('md-checkbox');
expect(cbElements.eq(0).attr('aria-label')).toBe('Some text');
}));

it('should set checked css class and aria-checked attributes', inject(function($compile, $rootScope) {
var element = $compile('<div>' +
var element = buildInstance('<div>' +
'<md-checkbox ng-model="blue">' +
'</md-checkbox>' +
'<md-checkbox ng-model="green">' +
'</md-checkbox>' +
'</div>')($rootScope);
'</div>');

$rootScope.$apply(function(){
$rootScope.blue = false;
Expand All @@ -50,14 +63,14 @@ describe('mdCheckbox', function() {
}));

it('should be disabled with ngDisabled attr', inject(function($compile, $rootScope) {
var element = $compile('<div>' +
var element = buildInstance('<div>' +
'<md-checkbox ng-disabled="isDisabled" ng-model="blue">' +
'</md-checkbox>' +
'</div>')($rootScope);
'</div>');

var checkbox = element.find('md-checkbox');
$rootScope.$apply('isDisabled = true');

$rootScope.$apply('isDisabled = true');
$rootScope.$apply('blue = false');

checkbox.triggerHandler('click');
Expand All @@ -70,20 +83,20 @@ describe('mdCheckbox', function() {
}));

it('should preserve existing tabindex', inject(function($compile, $rootScope) {
var element = $compile('<div>' +
var element = buildInstance('<div>' +
'<md-checkbox ng-model="blue" tabindex="2">' +
'</md-checkbox>' +
'</div>')($rootScope);
'</div>');

var checkbox = element.find('md-checkbox');
expect(checkbox.attr('tabindex')).toBe('2');
}));

it('should disable with tabindex=-1', inject(function($compile, $rootScope) {
var element = $compile('<div>' +
var element = buildInstance('<div>' +
'<md-checkbox ng-disabled="isDisabled" ng-model="blue">' +
'</md-checkbox>' +
'</div>')($rootScope);
'</div>');

var checkbox = element.find('md-checkbox');

Expand All @@ -95,24 +108,24 @@ describe('mdCheckbox', function() {
}));

it('should not set focus state on mousedown', inject(function($compile, $rootScope) {
var checkbox = $compile('<md-checkbox ng-model="blue">')($rootScope.$new());
$rootScope.$apply();
var checkbox = buildInstance('<md-checkbox ng-model="blue">',$rootScope.$new());

checkbox.triggerHandler('mousedown');
expect(checkbox[0]).not.toHaveClass('md-focused');
}));

it('should set focus state on focus and remove on blur', inject(function($compile, $rootScope) {
var checkbox = $compile('<md-checkbox ng-model="blue">')($rootScope.$new());
$rootScope.$apply();
var checkbox = buildInstance('<md-checkbox ng-model="blue">',$rootScope.$new());

checkbox.triggerHandler('focus');
expect(checkbox[0]).toHaveClass('md-focused');
checkbox.triggerHandler('blur');
expect(checkbox[0]).not.toHaveClass('md-focused');
}));

it('should set focus state on keyboard interaction after clicking', inject(function($compile, $rootScope, $mdConstant) {
var checkbox = $compile('<md-checkbox ng-model="blue">')($rootScope.$new());
$rootScope.$apply();
var checkbox = buildInstance('<md-checkbox ng-model="blue">',$rootScope.$new());

checkbox.triggerHandler('mousedown');
checkbox.triggerHandler({
type: 'keypress',
Expand All @@ -123,89 +136,76 @@ describe('mdCheckbox', function() {

describe('ng core checkbox tests', function() {

var inputElm;
var scope;
var $compile;

beforeEach(inject(function(_$compile_, _$rootScope_) {
scope = _$rootScope_;
$compile = _$compile_;
}));

function compileInput(html) {
inputElm = $compile(html)(scope);
}

function isChecked(cbEl) {
return cbEl.hasClass(CHECKED_CSS);
}

it('should format booleans', function() {
compileInput('<md-checkbox ng-model="name" />');
var inputElm = buildInstance('<md-checkbox ng-model="name" />');

scope.$apply("name = false");
$rootScope.$apply("name = false");
expect(isChecked(inputElm)).toBe(false);

scope.$apply("name = true");
$rootScope.$apply("name = true");
expect(isChecked(inputElm)).toBe(true);
});


it('should support type="checkbox" with non-standard capitalization', function() {
compileInput('<md-checkbox ng-model="checkbox" />');
var inputElm = buildInstance('<md-checkbox ng-model="checkbox" />');

inputElm.triggerHandler('click');
expect(scope.checkbox).toBe(true);
expect($rootScope.checkbox).toBe(true);

inputElm.triggerHandler('click');
expect(scope.checkbox).toBe(false);
expect($rootScope.checkbox).toBe(false);
});


it('should allow custom enumeration', function() {
compileInput('<md-checkbox ng-model="name" ng-true-value="\'y\'" ' +
var inputElm = buildInstance('<md-checkbox ng-model="name" ng-true-value="\'y\'" ' +
'ng-false-value="\'n\'">');

scope.$apply("name = 'y'");
$rootScope.$apply("name = 'y'");
expect(isChecked(inputElm)).toBe(true);

scope.$apply("name = 'n'");
$rootScope.$apply("name = 'n'");
expect(isChecked(inputElm)).toBe(false);

scope.$apply("name = 'something else'");
$rootScope.$apply("name = 'something else'");
expect(isChecked(inputElm)).toBe(false);

inputElm.triggerHandler('click');
expect(scope.name).toEqual('y');
expect($rootScope.name).toEqual('y');

inputElm.triggerHandler('click');
expect(scope.name).toEqual('n');
expect($rootScope.name).toEqual('n');
});


it('should throw if ngTrueValue is present and not a constant expression', function() {
expect(function() {
compileInput('<md-checkbox ng-model="value" ng-true-value="yes" />');
buildInstance('<md-checkbox ng-model="value" ng-true-value="yes" />');
}).toThrow();
});


it('should throw if ngFalseValue is present and not a constant expression', function() {
expect(function() {
compileInput('<md-checkbox ng-model="value" ng-false-value="no" />');
buildInstance('<md-checkbox ng-model="value" ng-false-value="no" />');
}).toThrow();
});


it('should not throw if ngTrueValue or ngFalseValue are not present', function() {
expect(function() {
compileInput('<md-checkbox ng-model="value" />');
buildInstance('<md-checkbox ng-model="value" />');
}).not.toThrow();
});


it('should be required if false', function() {
compileInput('<md-checkbox ng:model="value" required />');
var inputElm = buildInstance('<md-checkbox ng:model="value" required />');

inputElm.triggerHandler('click');
expect(isChecked(inputElm)).toBe(true);
Expand Down
3 changes: 2 additions & 1 deletion src/components/dialog/dialog.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ describe('$mdDialog', function() {
expect(dialog.attr('role')).toBe('dialog');
}));

it('should create an ARIA label if one is missing', inject(function($mdDialog, $rootScope) {
it('should create an ARIA label if one is missing', inject(function($mdDialog, $rootScope, $$rAF) {
var template = '<md-dialog>Hello</md-dialog>';
var parent = angular.element('<div>');

Expand All @@ -497,6 +497,7 @@ describe('$mdDialog', function() {
$rootScope.$apply();
angular.element(parent[0].querySelector('.md-dialog-container')).triggerHandler('transitionend');
$rootScope.$apply();
$$rAF.flush();

var dialog = angular.element(parent[0].querySelector('md-dialog'));
expect(dialog.attr('aria-label')).toEqual(dialog.text());
Expand Down
Loading

0 comments on commit 48ee986

Please sign in to comment.