@@ -2931,15 +2931,54 @@ describe('ngOptions', function() {
2931
2931
var _selected = [ ] ;
2932
2932
2933
2933
// 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
+
2934
2939
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 ) ;
2941
2943
} ) ;
2942
2944
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
+
2943
2982
// Select `optionA`
2944
2983
scope . $apply ( 'selected = [values[0]]' ) ;
2945
2984
@@ -2999,6 +3038,12 @@ describe('ngOptions', function() {
2999
3038
expect ( options [ 1 ] . selected ) . toBe ( false ) ;
3000
3039
optionsSetSelected [ 0 ] . calls . reset ( ) ;
3001
3040
optionsSetSelected [ 1 ] . calls . reset ( ) ;
3041
+
3042
+ // Support: Firefox 54+
3043
+ // Restore `originalSelectedDescriptor`
3044
+ if ( addSpiesOnProto ) {
3045
+ Object . defineProperty ( optionProto , 'selected' , originalSelectedDescriptor ) ;
3046
+ }
3002
3047
} ) ;
3003
3048
3004
3049
if ( window . MutationObserver ) {
0 commit comments