Skip to content
This repository was archived by the owner on Jan 22, 2018. It is now read-only.

Commit b014b74

Browse files
author
Kamil Kisiela
committed
test(select): add angular material mocks and basic tests
1 parent fe2edbf commit b014b74

File tree

3 files changed

+317
-1
lines changed

3 files changed

+317
-1
lines changed

package.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,14 @@ Package.onTest(function(api) {
116116

117117
api.addFiles([
118118
'tests/client/test-utils.js',
119+
'tests/client/angular-material-mocks.js',
119120
'tests/client/formly-material-spec.js',
120121
// types
121122
'tests/client/types/checkbox-spec.js',
122123
'tests/client/types/chips-spec.js',
123124
'tests/client/types/datepicker-spec.js',
124125
'tests/client/types/input-spec.js',
125-
'tests/client/types/radio-spec.js'
126+
'tests/client/types/radio-spec.js',
127+
'tests/client/types/select-spec.js'
126128
], client);
127129
});
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
(function(window, angular, undefined) {
2+
3+
'use strict';
4+
5+
/**
6+
* @ngdoc module
7+
* @name ngMaterial-mock
8+
* @packageName angular-material-mocks
9+
*
10+
* @description
11+
*
12+
* The `ngMaterial-mock` module provides support
13+
*
14+
*/
15+
angular.module('ngMaterial-mock', [
16+
'ngMock',
17+
'ngAnimateMock',
18+
'material.core'
19+
])
20+
.config(['$provide', function($provide) {
21+
22+
$provide.factory('$material', ['$animate', '$timeout', function($animate, $timeout) {
23+
return {
24+
flushOutstandingAnimations: function() {
25+
// this code is placed in a try-catch statement
26+
// since 1.3 and 1.4 handle their animations differently
27+
// and there may be situations where follow-up animations
28+
// are run in one version and not the other
29+
try { $animate.flush(); } catch(e) {}
30+
},
31+
flushInterimElement: function() {
32+
this.flushOutstandingAnimations();
33+
$timeout.flush();
34+
this.flushOutstandingAnimations();
35+
$timeout.flush();
36+
this.flushOutstandingAnimations();
37+
$timeout.flush();
38+
}
39+
};
40+
}]);
41+
42+
/**
43+
* Angular Material dynamically generates Style tags
44+
* based on themes and palletes; for each ng-app.
45+
*
46+
* For testing, we want to disable generation and
47+
* <style> DOM injections. So we clear the huge THEME
48+
* styles while testing...
49+
*/
50+
$provide.constant('$MD_THEME_CSS', '/**/');
51+
52+
/**
53+
* Intercept to make .expectWithText() to be synchronous
54+
*/
55+
$provide.decorator('$mdAria', function($delegate){
56+
57+
$delegate.expectWithText = function(element, attrName){
58+
$delegate.expect(element, attrName, element.text().trim());
59+
};
60+
61+
return $delegate;
62+
});
63+
64+
/**
65+
* Add throttle() and wrap .flush() to catch `no callbacks present`
66+
* errors
67+
*/
68+
$provide.decorator('$$rAF', function throttleInjector($delegate){
69+
70+
$delegate.throttle = function(cb) {
71+
return function() {
72+
cb.apply(this, arguments);
73+
};
74+
};
75+
76+
var ngFlush = $delegate.flush;
77+
$delegate.flush = function() {
78+
try { ngFlush(); }
79+
catch(e) { ; }
80+
};
81+
82+
return $delegate;
83+
});
84+
85+
/**
86+
* Capture $timeout.flush() errors: "No deferred tasks to be flushed"
87+
* errors
88+
*/
89+
$provide.decorator('$timeout', function throttleInjector($delegate){
90+
91+
var ngFlush = $delegate.flush;
92+
$delegate.flush = function() {
93+
var args = Array.prototype.slice.call(arguments);
94+
try { ngFlush.apply($delegate, args); }
95+
catch(e) { ; }
96+
};
97+
98+
return $delegate;
99+
});
100+
101+
}])
102+
103+
/**
104+
* Stylesheet Mocks used by `animateCss.spec.js`
105+
*/
106+
window.createMockStyleSheet = function createMockStyleSheet(doc, wind) {
107+
doc = doc ? doc[0] : window.document;
108+
wind = wind || window;
109+
110+
var node = doc.createElement('style');
111+
var head = doc.getElementsByTagName('head')[0];
112+
head.appendChild(node);
113+
114+
var ss = doc.styleSheets[doc.styleSheets.length - 1];
115+
116+
return {
117+
addRule: function(selector, styles) {
118+
styles = addVendorPrefix(styles);
119+
120+
try {
121+
ss.insertRule(selector + '{ ' + styles + '}', 0);
122+
}
123+
catch (e) {
124+
try {
125+
ss.addRule(selector, styles);
126+
}
127+
catch (e2) {}
128+
}
129+
},
130+
131+
destroy: function() {
132+
head.removeChild(node);
133+
}
134+
};
135+
136+
/**
137+
* Decompose styles, attached specific vendor prefixes
138+
* and recompose...
139+
* e.g.
140+
* 'transition:0.5s linear all; font-size:100px;'
141+
* becomes
142+
* '-webkit-transition:0.5s linear all; transition:0.5s linear all; font-size:100px;'
143+
*/
144+
function addVendorPrefix(styles) {
145+
var cache = { };
146+
147+
// Decompose into cache registry
148+
styles
149+
.match(/([\-A-Za-z]*)\w\:\w*([A-Za-z0-9\.\-\s]*)/gi)
150+
.forEach(function(style){
151+
var pair = style.split(":");
152+
var key = pair[0];
153+
154+
switch(key) {
155+
case 'transition':
156+
case 'transform':
157+
case 'animation':
158+
case 'transition-duration':
159+
case 'animation-duration':
160+
cache[key] = cache['-webkit-' + key] = pair[1];
161+
break;
162+
default:
163+
cache[key] = pair[1];
164+
}
165+
});
166+
167+
// Recompose full style object (as string)
168+
styles = "";
169+
angular.forEach(cache, function(value, key) {
170+
styles = styles + key + ":" + value + "; ";
171+
});
172+
173+
return styles;
174+
}
175+
176+
};
177+
178+
})(window, window.angular);

tests/client/types/select-spec.js

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
describe("formlyMaterial - select type", () => {
2+
3+
//
4+
// vars
5+
//
6+
7+
let formlyConfig;
8+
let $compile;
9+
let $rootScope;
10+
let $scope;
11+
let $document;
12+
let $material;
13+
let form;
14+
let element;
15+
let field;
16+
17+
//
18+
// helpers
19+
//
20+
21+
function compile(options) {
22+
$scope = $rootScope.$new();
23+
$scope.fields = [angular.merge({}, {
24+
key: 'testField',
25+
type: 'select',
26+
templateOptions: {
27+
label: 'test field',
28+
multiple: true,
29+
options: [
30+
{name: 'first', nameUp: 'FIRST', value: 'f', valueUp: 'F'},
31+
{name: 'second', nameUp: 'SECOND', value: 's', valueUp: 'S'}
32+
]
33+
}
34+
}, options)];
35+
36+
form = $compile(testUtils.formTemplate)($scope);
37+
$scope.$digest();
38+
field = $scope.fields[0];
39+
element = form.find('[ng-model]');
40+
}
41+
42+
function waitForSelectOpen() {
43+
$material.flushInterimElement();
44+
}
45+
46+
function openSelect() {
47+
element.triggerHandler('click');
48+
}
49+
50+
function closeSelect() {
51+
$document.find('md-select-menu').parent().remove();
52+
}
53+
54+
function selectOptions() {
55+
openSelect();
56+
waitForSelectOpen();
57+
let selectMenu = $document.find('md-select-menu');
58+
selectMenu.hide();
59+
$document.find('.md-scroll-mask').remove();
60+
return selectMenu.find('md-option');
61+
}
62+
63+
//
64+
// tests
65+
//
66+
67+
beforeEach(() => {
68+
angular.module('testApp', ['angular-meteor', 'formly', 'formlyMaterial', 'ngMaterial-mock']);
69+
module('testApp');
70+
71+
inject((_$compile_, _$rootScope_, _formlyConfig_, _$document_, _$material_) => {
72+
$compile = _$compile_;
73+
$rootScope = _$rootScope_;
74+
formlyConfig = _formlyConfig_;
75+
$document = _$document_;
76+
$material = _$material_;
77+
});
78+
79+
const types = ['select'];
80+
const wrappers = ['label', 'messages', 'inputContainer'];
81+
82+
types.forEach((name) => {
83+
testUtils.fixTypeTemplateUrl(formlyConfig, name);
84+
});
85+
wrappers.forEach((name) => {
86+
testUtils.fixWrapperTemplateUrl(formlyConfig, name);
87+
});
88+
});
89+
90+
it('should be md-select element', () => {
91+
compile();
92+
expect(element[0].nodeName).toBe('MD-SELECT');
93+
});
94+
95+
it('should be able to pick multiple options', () => {
96+
compile();
97+
expect(element.attr('multiple')).toBeDefined();
98+
});
99+
100+
describe("check options", () => {
101+
102+
afterEach(() => {
103+
closeSelect();
104+
});
105+
106+
it('should have options with default properties for name and value', () => {
107+
compile();
108+
let optionsEl = selectOptions();
109+
110+
expect(optionsEl.length).toBe(field.templateOptions.options.length);
111+
field.templateOptions.options.forEach((option, key) => {
112+
let el = angular.element(optionsEl[key]);
113+
expect(el.attr('value')).toBe(option.value);
114+
expect(el.find('.md-text')[0].innerText).toContain(option.name);
115+
});
116+
});
117+
118+
it('should have options with custom properties for name and value', () => {
119+
compile({
120+
templateOptions: {
121+
labelProp: 'nameUp',
122+
valueProp: 'valueUp'
123+
}
124+
});
125+
let optionsEl = selectOptions();
126+
127+
expect(optionsEl.length).toBe(field.templateOptions.options.length);
128+
field.templateOptions.options.forEach((option, key) => {
129+
let el = angular.element(optionsEl[key]);
130+
expect(el.attr('value')).toBe(option.valueUp);
131+
expect(el.find('.md-text')[0].innerText).toContain(option.nameUp);
132+
});
133+
});
134+
});
135+
136+
});

0 commit comments

Comments
 (0)