Skip to content

Commit

Permalink
test: fix failing tests on MS Edge
Browse files Browse the repository at this point in the history
Includes the following fixes (per component):

* `$sniffer`: Properly determine the expected `vendorPrefix` for MS Edge
* `input`: MS Edge does not support dates with years with more than 4 digits.
      Trying to set the value of an `input[datetime-local]` to `9999-12-31T23.59.59.999` throws an
      error (probably related to converting the date to one with a year with more than 4 digits,
      due to timezone offset).
* `$sanitize`: Fix failing tests on MS Edge
* `$animateCss`: Although the detected `vendorPrefix` for MS Edge is "ms", it doesn't seem to
      recognize some vendor-prefixed CSS rules (e.g. `-ms-animation-*`). Other browsers (currently)
      recognize either vendor-prefixed rules only or both.
      Fixed by adding and retrieving styles using both prefixed and un-prefixed names.
* `$compile`: Skip failing `foreignObject` test on MS Edge.
      For unknown reasons, an `<svg>` element inside a `<foreignObject>` element on MS Edge has no
      size, causing the included `<circle>` element to also have no size and thus fails an
      assertion (relying on the element having a non-zero size).
      This seems to be an MS Edge issue; i.e. it is also reproducible without Angular.
      (Tested with MS Edge version 25.10586.0.0 on Windows 10.)

Closes angular#13686
  • Loading branch information
gkalpak committed Jan 11, 2016
1 parent 2764536 commit cb74999
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 64 deletions.
14 changes: 13 additions & 1 deletion test/helpers/privateMocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function browserSupportsCssAnimations() {
return true;
}

function createMockStyleSheet(doc) {
function createMockStyleSheet(doc, prefix) {
doc = doc ? doc[0] : document;

var node = doc.createElement('style');
Expand All @@ -62,6 +62,18 @@ function createMockStyleSheet(doc) {
}
},

addPossiblyPrefixedRule: function(selector, styles) {
if (prefix) {
var prefixedStyles = styles.split(/\s*;\s*/g).map(function(style) {
return !style ? '' : prefix + style;
}).join('; ');

this.addRule(selector, prefixedStyles);
}

this.addRule(selector, styles);
},

destroy: function() {
head.removeChild(node);
}
Expand Down
27 changes: 16 additions & 11 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ describe('$compile', function() {


describe('svg namespace transcludes', function() {
var ua = window.navigator.userAgent;
var isEdge = /Edge/.test(ua);

// this method assumes some sort of sized SVG element is being inspected.
function assertIsValidSvgCircle(elem) {
expect(isUnknownElement(elem)).toBe(false);
Expand Down Expand Up @@ -300,17 +303,19 @@ describe('$compile', function() {
}));

// NOTE: This test may be redundant.
it('should handle custom svg containers that transclude to foreignObject' +
' that transclude to custom svg containers that transclude to custom elements', inject(function() {
element = jqLite('<div><svg-container>' +
'<my-foreign-object><svg-container><svg-circle></svg-circle></svg-container></my-foreign-object>' +
'</svg-container></div>');
$compile(element.contents())($rootScope);
document.body.appendChild(element[0]);

var circle = element.find('circle');
assertIsValidSvgCircle(circle[0]);
}));
if (!isEdge) {
it('should handle custom svg containers that transclude to foreignObject' +
' that transclude to custom svg containers that transclude to custom elements', inject(function() {
element = jqLite('<div><svg-container>' +
'<my-foreign-object><svg-container><svg-circle></svg-circle></svg-container></my-foreign-object>' +
'</svg-container></div>');
$compile(element.contents())($rootScope);
document.body.appendChild(element[0]);

var circle = element.find('circle');
assertIsValidSvgCircle(circle[0]);
}));
}
}

it('should handle directives with templates that manually add the transclude further down', inject(function() {
Expand Down
2 changes: 1 addition & 1 deletion test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,7 @@ describe('input', function() {

it('should validate if max is empty', function() {
$rootScope.maxVal = undefined;
$rootScope.value = new Date(9999, 11, 31, 23, 59, 59);
$rootScope.value = new Date(3000, 11, 31, 23, 59, 59);
$rootScope.$digest();

expect($rootScope.form.alias.$error.max).toBeFalsy();
Expand Down
4 changes: 3 additions & 1 deletion test/ng/snifferSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ describe('$sniffer', function() {
inject(function($sniffer, $window) {
var expectedPrefix;
var ua = $window.navigator.userAgent.toLowerCase();
if (/chrome/i.test(ua) || /safari/i.test(ua) || /webkit/i.test(ua)) {
if (/edge/i.test(ua)) {
expectedPrefix = 'Ms';
} else if (/chrome/i.test(ua) || /safari/i.test(ua) || /webkit/i.test(ua)) {
expectedPrefix = 'Webkit';
} else if (/firefox/i.test(ua)) {
expectedPrefix = 'Moz';
Expand Down
104 changes: 56 additions & 48 deletions test/ngAnimate/animateCssSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ describe("ngAnimate $animateCss", function() {
: expect(className).not.toMatch(regex);
}

function getPossiblyPrefixedStyleValue(element, styleProp) {
var value = element.css(prefix + styleProp);
if (isUndefined(value)) value = element.css(styleProp);

return value;
}

function keyframeProgress(element, duration, delay) {
browserTrigger(element, 'animationend',
{ timeStamp: Date.now() + ((delay || 1) * 1000), elapsedTime: duration });
Expand All @@ -30,7 +37,8 @@ describe("ngAnimate $animateCss", function() {
beforeEach(module(function() {
return function($document, $sniffer, $$rAF, $animate) {
prefix = '-' + $sniffer.vendorPrefix.toLowerCase() + '-';
ss = createMockStyleSheet($document);
ss = createMockStyleSheet($document, prefix);

$animate.enabled(true);
triggerAnimationStartFrame = function() {
$$rAF.flush();
Expand Down Expand Up @@ -325,7 +333,7 @@ describe("ngAnimate $animateCss", function() {
triggerAnimationStartFrame();

runner.pause();
expect(element.css(prefix + 'animation-play-state')).toEqual('paused');
expect(getPossiblyPrefixedStyleValue(element, 'animation-play-state')).toEqual('paused');
runner.resume();
expect(element.attr('style')).toBeFalsy();
}));
Expand All @@ -346,7 +354,7 @@ describe("ngAnimate $animateCss", function() {
triggerAnimationStartFrame();

runner.pause();
expect(element.css(prefix + 'animation-play-state')).toEqual('paused');
expect(getPossiblyPrefixedStyleValue(element, 'animation-play-state')).toEqual('paused');
runner.end();
expect(element.attr('style')).toBeFalsy();
}));
Expand Down Expand Up @@ -784,8 +792,8 @@ describe("ngAnimate $animateCss", function() {

jqLite($document[0].body).append($rootElement);

ss.addRule('.ng-enter-stagger', prefix + 'animation-delay:0.2s');
ss.addRule('.ng-enter', prefix + 'animation:my_animation 2s;');
ss.addPossiblyPrefixedRule('.ng-enter-stagger', 'animation-delay:0.2s');
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:my_animation 2s;');

var i, element, elements = [];
for (i = 0; i < 5; i++) {
Expand All @@ -803,7 +811,7 @@ describe("ngAnimate $animateCss", function() {
if (i === 0) { // the first element is always run right away
expect(element.attr('style')).toBeFalsy();
} else {
expect(element.css(prefix + 'animation-play-state')).toBe('paused');
expect(getPossiblyPrefixedStyleValue(element, 'animation-play-state')).toBe('paused');
}
}
}));
Expand Down Expand Up @@ -879,7 +887,7 @@ describe("ngAnimate $animateCss", function() {
jqLite($document[0].body).append($rootElement);

ss.addRule('.ng-enter-stagger', 'transition-delay:0.2s');
ss.addRule('.transition-animation', prefix + 'animation:2s 5s my_animation;');
ss.addPossiblyPrefixedRule('.transition-animation', 'animation: 2s 5s my_animation;');

for (var i = 0; i < 5; i++) {
var elm = jqLite('<div class="transition-animation"></div>');
Expand All @@ -898,11 +906,11 @@ describe("ngAnimate $animateCss", function() {

jqLite($document[0].body).append($rootElement);

ss.addRule('.ng-enter-stagger', 'transition-delay:0.5s;' +
prefix + 'animation-delay:1s');
ss.addPossiblyPrefixedRule('.ng-enter-stagger', 'transition-delay: 0.5s; ' +
'animation-delay: 1s');

ss.addRule('.ng-enter', 'transition:10s linear all;' +
prefix + 'animation:my_animation 20s');
ss.addPossiblyPrefixedRule('.ng-enter', 'transition: 10s linear all; ' +
'animation: 20s my_animation');

var i, elm, elements = [];
for (i = 0; i < 5; i++) {
Expand Down Expand Up @@ -1258,14 +1266,14 @@ describe("ngAnimate $animateCss", function() {
// At this point, the animation should still be running (closing timeout is 7500ms ... duration * 1.5 + delay => 7.5)
$timeout.flush(7000);

expect(element.css(prefix + 'transition-delay')).toBe('3s');
expect(element.css(prefix + 'transition-duration')).toBe('3s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-delay')).toBe('3s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-duration')).toBe('3s');

// Let's flush the remaining amount of time for the timeout timer to kick in
$timeout.flush(500);

expect(element.css(prefix + 'transition-duration')).toBeOneOf('', '0s');
expect(element.css(prefix + 'transition-delay')).toBeOneOf('', '0s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-duration')).toBeOneOf('', '0s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-delay')).toBeOneOf('', '0s');
}));

it("should ignore a boolean options.delay value for the closing timeout",
Expand All @@ -1291,14 +1299,14 @@ describe("ngAnimate $animateCss", function() {
// At this point, the animation should still be running (closing timeout is 4500ms ... duration * 1.5 => 4.5)
$timeout.flush(4000);

expect(element.css(prefix + 'transition-delay')).toBeOneOf('initial', '0s');
expect(element.css(prefix + 'transition-duration')).toBe('3s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-delay')).toBeOneOf('initial', '0s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-duration')).toBe('3s');

// Let's flush the remaining amount of time for the timeout timer to kick in
$timeout.flush(500);

expect(element.css(prefix + 'transition-duration')).toBeOneOf('', '0s');
expect(element.css(prefix + 'transition-delay')).toBeOneOf('', '0s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-duration')).toBeOneOf('', '0s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-delay')).toBeOneOf('', '0s');
}));

});
Expand Down Expand Up @@ -2104,7 +2112,7 @@ describe("ngAnimate $animateCss", function() {
triggerAnimationStartFrame();


expect(element.css(prefix + 'animation-duration')).toEqual('5s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-duration')).toEqual('5s');
}));

it("should remove all inline keyframe styling when an animation completes if a custom duration was applied",
Expand Down Expand Up @@ -2145,7 +2153,7 @@ describe("ngAnimate $animateCss", function() {
triggerAnimationStartFrame();


expect(element.css(prefix + 'animation-delay')).toEqual('5s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-delay')).toEqual('5s');

browserTrigger(element, 'animationend',
{ timeStamp: Date.now() + 5000, elapsedTime: 1.5 });
Expand Down Expand Up @@ -2299,7 +2307,7 @@ describe("ngAnimate $animateCss", function() {
triggerAnimationStartFrame();


expect(element.css(prefix + 'animation-delay')).toEqual('400s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-delay')).toEqual('400s');
expect(element.attr('style')).not.toContain('transition-delay');
}));

Expand All @@ -2323,7 +2331,7 @@ describe("ngAnimate $animateCss", function() {
triggerAnimationStartFrame();


expect(element.css(prefix + 'animation-delay')).toEqual('10s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-delay')).toEqual('10s');
expect(element.css('transition-delay')).toEqual('10s');
}));

Expand Down Expand Up @@ -2363,7 +2371,7 @@ describe("ngAnimate $animateCss", function() {
var assertionsRun = false;
classSpy = function() {
assertionsRun = true;
expect(element.css(prefix + 'animation-delay')).toEqual('2s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-delay')).toEqual('2s');
expect(element.css('transition-delay')).toEqual('2s');
expect(element).not.toHaveClass('superman');
};
Expand Down Expand Up @@ -2397,8 +2405,8 @@ describe("ngAnimate $animateCss", function() {
it("should consider a negative value when delay:true is used with a keyframe animation",
inject(function($animateCss, $rootElement) {

ss.addRule('.ng-enter', prefix + 'animation:2s keyframe_animation; ' +
prefix + 'animation-delay: -1s;');
ss.addPossiblyPrefixedRule('.ng-enter', 'animation: 2s keyframe_animation; ' +
'animation-delay: -1s;');

var options = {
delay: true,
Expand All @@ -2411,7 +2419,7 @@ describe("ngAnimate $animateCss", function() {
animator.start();
triggerAnimationStartFrame();

expect(element.css(prefix + 'animation-delay')).toContain('-1s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-delay')).toContain('-1s');
}));

they("should consider a negative value when a negative option delay is provided for a $prop animation", {
Expand All @@ -2421,17 +2429,17 @@ describe("ngAnimate $animateCss", function() {
css: 'transition:2s linear all'
};
},
'keyframe': function(prefix) {
'keyframe': function() {
return {
prop: prefix + 'animation-delay',
css: prefix + 'animation:2s keyframe_animation'
prop: 'animation-delay',
css: 'animation: 2s keyframe_animation'
};
}
}, function(testDetailsFactory) {
inject(function($animateCss, $rootElement) {
var testDetails = testDetailsFactory(prefix);

ss.addRule('.ng-enter', testDetails.css);
ss.addPossiblyPrefixedRule('.ng-enter', testDetails.css);
var options = {
delay: -2,
event: 'enter',
Expand All @@ -2443,7 +2451,7 @@ describe("ngAnimate $animateCss", function() {
animator.start();
triggerAnimationStartFrame();

expect(element.css(testDetails.prop)).toContain('-2s');
expect(getPossiblyPrefixedStyleValue(element, testDetails.prop)).toContain('-2s');
});
});

Expand All @@ -2454,18 +2462,18 @@ describe("ngAnimate $animateCss", function() {
css: 'transition:5s linear all; transition-delay: -2s'
};
},
'animation': function(prefix) {
'animation': function() {
return {
event: 'animationend',
css: prefix + 'animation:5s keyframe_animation; ' + prefix + 'animation-delay: -2s;'
css: 'animation: 5s keyframe_animation; animation-delay: -2s;'
};
}
}, function(testDetailsFactory) {
inject(function($animateCss, $rootElement) {
var testDetails = testDetailsFactory(prefix);
var testDetails = testDetailsFactory();
var event = testDetails.event;

ss.addRule('.ng-enter', testDetails.css);
ss.addPossiblyPrefixedRule('.ng-enter', testDetails.css);
var options = { event: 'enter', structural: true };

var animator = $animateCss(element, options);
Expand Down Expand Up @@ -2571,15 +2579,15 @@ describe("ngAnimate $animateCss", function() {
$animateCss(element, options).start();
triggerAnimationStartFrame();

expect(element.css(prefix + 'transition-delay')).not.toEqual('4s');
expect(element.css(prefix + 'transition-duration')).not.toEqual('6s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-delay')).not.toEqual('4s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-duration')).not.toEqual('6s');

options.to = { color: 'brown' };
$animateCss(element, options).start();
triggerAnimationStartFrame();

expect(element.css(prefix + 'transition-delay')).toEqual('4s');
expect(element.css(prefix + 'transition-duration')).toEqual('6s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-delay')).toEqual('4s');
expect(getPossiblyPrefixedStyleValue(element, 'transition-duration')).toEqual('6s');
}));
});

Expand Down Expand Up @@ -2652,9 +2660,9 @@ describe("ngAnimate $animateCss", function() {
triggerAnimationStartFrame();


expect(element.css(prefix + 'animation-delay')).toEqual('50s');
expect(element.css(prefix + 'animation-duration')).toEqual('5.5s');
expect(element.css(prefix + 'animation-name')).toEqual('my_animation');
expect(getPossiblyPrefixedStyleValue(element, 'animation-delay')).toEqual('50s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-duration')).toEqual('5.5s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-name')).toEqual('my_animation');
}));

it("should be able to execute the animation if it is the only provided value",
Expand All @@ -2669,9 +2677,9 @@ describe("ngAnimate $animateCss", function() {
animator.start();
triggerAnimationStartFrame();

expect(element.css(prefix + 'animation-delay')).toEqual('10s');
expect(element.css(prefix + 'animation-duration')).toEqual('5.5s');
expect(element.css(prefix + 'animation-name')).toEqual('my_animation');
expect(getPossiblyPrefixedStyleValue(element, 'animation-delay')).toEqual('10s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-duration')).toEqual('5.5s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-name')).toEqual('my_animation');
}));
});

Expand Down Expand Up @@ -2964,7 +2972,7 @@ describe("ngAnimate $animateCss", function() {


expect(element.css('transition-duration')).toMatch('10s');
expect(element.css(prefix + 'animation-duration')).toEqual('10s');
expect(getPossiblyPrefixedStyleValue(element, 'animation-duration')).toEqual('10s');
}));
});

Expand Down Expand Up @@ -3004,7 +3012,7 @@ describe("ngAnimate $animateCss", function() {
inject(function($animateCss) {

ss.addRule('.red', 'transition: 1s linear all;');
ss.addRule('.blue', prefix + 'animation:my_keyframe 1s;');
ss.addPossiblyPrefixedRule('.blue', 'animation: 1s my_keyframe;');
var easing = 'ease-out';
var animator = $animateCss(element, { addClass: 'red blue', easing: easing });
animator.start();
Expand Down
Loading

0 comments on commit cb74999

Please sign in to comment.