Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 03b7db6

Browse files
committed
test(ngOptions): fix flaky test on Firefox 54+
1 parent 56ac2a7 commit 03b7db6

File tree

1 file changed

+51
-6
lines changed

1 file changed

+51
-6
lines changed

test/ng/directive/ngOptionsSpec.js

+51-6
Original file line numberDiff line numberDiff line change
@@ -2931,15 +2931,54 @@ describe('ngOptions', function() {
29312931
var _selected = [];
29322932

29332933
// Set up spies
2934+
var optionProto = Object.getPrototypeOf(options[0]);
2935+
var originalSelectedDescriptor = isFunction(Object.getOwnPropertyDescriptor) &&
2936+
Object.getOwnPropertyDescriptor(optionProto, 'selected');
2937+
var addSpiesOnProto = originalSelectedDescriptor && originalSelectedDescriptor.configurable;
2938+
29342939
forEach(options, function(option, i) {
2935-
optionsSetSelected[i] = jasmine.createSpy('optionSetSelected' + i);
2936-
_selected[i] = option.selected;
2937-
Object.defineProperty(option, 'selected', {
2938-
get: function() { return _selected[i]; },
2939-
set: optionsSetSelected[i].and.callFake(function(value) { _selected[i] = value; })
2940-
});
2940+
var setSelected = function(value) { _selected[i] = value; };
2941+
optionsSetSelected[i] = jasmine.createSpy('optionSetSelected' + i).and.callFake(setSelected);
2942+
setSelected(option.selected);
29412943
});
29422944

2945+
if (!addSpiesOnProto) {
2946+
forEach(options, function(option, i) {
2947+
Object.defineProperty(option, 'selected', {
2948+
get: function() { return _selected[i]; },
2949+
set: optionsSetSelected[i]
2950+
});
2951+
});
2952+
} else {
2953+
// Support: Firefox 54+
2954+
// We cannot use the above (simpler) method on all browsers because of Firefox 54+, which
2955+
// is very flaky when the getter/setter property is defined on the element itself and not
2956+
// the prototype. (Possibly the result of some (buggy?) optimization.)
2957+
var getSelected = function(index) { return _selected[index]; };
2958+
var setSelected = function(index, value) { optionsSetSelected[index](value); };
2959+
var getSelectedOriginal = function(option) {
2960+
return originalSelectedDescriptor.get.call(option);
2961+
};
2962+
var setSelectedOriginal = function(option, value) {
2963+
originalSelectedDescriptor.set.call(option, value);
2964+
};
2965+
var getIndexAndCall = function(option, foundFn, notFoundFn, value) {
2966+
for (var i = 0, ii = options.length; i < ii; ++i) {
2967+
if (options[i] === option) return foundFn(i, value);
2968+
}
2969+
return notFoundFn(option, value);
2970+
};
2971+
2972+
Object.defineProperty(optionProto, 'selected', {
2973+
get: function() {
2974+
return getIndexAndCall(this, getSelected, getSelectedOriginal);
2975+
},
2976+
set: function(value) {
2977+
return getIndexAndCall(this, setSelected, setSelectedOriginal, value);
2978+
}
2979+
});
2980+
}
2981+
29432982
// Select `optionA`
29442983
scope.$apply('selected = [values[0]]');
29452984

@@ -2999,6 +3038,12 @@ describe('ngOptions', function() {
29993038
expect(options[1].selected).toBe(false);
30003039
optionsSetSelected[0].calls.reset();
30013040
optionsSetSelected[1].calls.reset();
3041+
3042+
// Support: Firefox 54+
3043+
// Restore `originalSelectedDescriptor`
3044+
if (addSpiesOnProto) {
3045+
Object.defineProperty(optionProto, 'selected', originalSelectedDescriptor);
3046+
}
30023047
});
30033048

30043049
if (window.MutationObserver) {

0 commit comments

Comments
 (0)