@@ -2082,4 +2082,188 @@ describe('$route', function() {
2082
2082
expect ( function ( ) { $route . updateParams ( ) ; } ) . toThrowMinErr ( 'ngRoute' , 'norout' ) ;
2083
2083
} ) ) ;
2084
2084
} ) ;
2085
+
2086
+ describe ( 'testability' , function ( ) {
2087
+ it ( 'should wait for $resolve promises before calling callbacks' , function ( ) {
2088
+ var deferred ;
2089
+
2090
+ module ( function ( $provide , $routeProvider ) {
2091
+ $routeProvider . when ( '/path' , {
2092
+ template : '' ,
2093
+ resolve : {
2094
+ a : function ( $q ) {
2095
+ deferred = $q . defer ( ) ;
2096
+ return deferred . promise ;
2097
+ }
2098
+ }
2099
+ } ) ;
2100
+ } ) ;
2101
+
2102
+ inject ( function ( $location , $route , $rootScope , $httpBackend , $$testability ) {
2103
+ $location . path ( '/path' ) ;
2104
+ $rootScope . $digest ( ) ;
2105
+
2106
+ var callback = jasmine . createSpy ( 'callback' ) ;
2107
+ $$testability . whenStable ( callback ) ;
2108
+ expect ( callback ) . not . toHaveBeenCalled ( ) ;
2109
+
2110
+ deferred . resolve ( ) ;
2111
+ $rootScope . $digest ( ) ;
2112
+ expect ( callback ) . toHaveBeenCalled ( ) ;
2113
+ } ) ;
2114
+ } ) ;
2115
+
2116
+ it ( 'should call callback after $resolve promises are rejected' , function ( ) {
2117
+ var deferred ;
2118
+
2119
+ module ( function ( $provide , $routeProvider ) {
2120
+ $routeProvider . when ( '/path' , {
2121
+ template : '' ,
2122
+ resolve : {
2123
+ a : function ( $q ) {
2124
+ deferred = $q . defer ( ) ;
2125
+ return deferred . promise ;
2126
+ }
2127
+ }
2128
+ } ) ;
2129
+ } ) ;
2130
+
2131
+ inject ( function ( $location , $route , $rootScope , $httpBackend , $$testability ) {
2132
+ $location . path ( '/path' ) ;
2133
+ $rootScope . $digest ( ) ;
2134
+
2135
+ var callback = jasmine . createSpy ( 'callback' ) ;
2136
+ $$testability . whenStable ( callback ) ;
2137
+ expect ( callback ) . not . toHaveBeenCalled ( ) ;
2138
+
2139
+ deferred . reject ( ) ;
2140
+ $rootScope . $digest ( ) ;
2141
+ expect ( callback ) . toHaveBeenCalled ( ) ;
2142
+ } ) ;
2143
+ } ) ;
2144
+
2145
+ it ( 'should wait for resolveRedirectTo promises before calling callbacks' , function ( ) {
2146
+ var deferred ;
2147
+
2148
+ module ( function ( $provide , $routeProvider ) {
2149
+ $routeProvider . when ( '/path' , {
2150
+ resolveRedirectTo : function ( $q ) {
2151
+ deferred = $q . defer ( ) ;
2152
+ return deferred . promise ;
2153
+ }
2154
+ } ) ;
2155
+ } ) ;
2156
+
2157
+ inject ( function ( $location , $route , $rootScope , $httpBackend , $$testability ) {
2158
+ $location . path ( '/path' ) ;
2159
+ $rootScope . $digest ( ) ;
2160
+
2161
+ var callback = jasmine . createSpy ( 'callback' ) ;
2162
+ $$testability . whenStable ( callback ) ;
2163
+ expect ( callback ) . not . toHaveBeenCalled ( ) ;
2164
+
2165
+ deferred . resolve ( ) ;
2166
+ $rootScope . $digest ( ) ;
2167
+ expect ( callback ) . toHaveBeenCalled ( ) ;
2168
+ } ) ;
2169
+ } ) ;
2170
+
2171
+ it ( 'should call callback after resolveRedirectTo promises are rejected' , function ( ) {
2172
+ var deferred ;
2173
+
2174
+ module ( function ( $provide , $routeProvider ) {
2175
+ $routeProvider . when ( '/path' , {
2176
+ resolveRedirectTo : function ( $q ) {
2177
+ deferred = $q . defer ( ) ;
2178
+ return deferred . promise ;
2179
+ }
2180
+ } ) ;
2181
+ } ) ;
2182
+
2183
+ inject ( function ( $location , $route , $rootScope , $httpBackend , $$testability ) {
2184
+ $location . path ( '/path' ) ;
2185
+ $rootScope . $digest ( ) ;
2186
+
2187
+ var callback = jasmine . createSpy ( 'callback' ) ;
2188
+ $$testability . whenStable ( callback ) ;
2189
+ expect ( callback ) . not . toHaveBeenCalled ( ) ;
2190
+
2191
+ deferred . reject ( ) ;
2192
+ $rootScope . $digest ( ) ;
2193
+ expect ( callback ) . toHaveBeenCalled ( ) ;
2194
+ } ) ;
2195
+ } ) ;
2196
+
2197
+ it ( 'should wait for all route promises before calling callbacks' , function ( ) {
2198
+ var deferreds = { } ;
2199
+
2200
+ module ( function ( $provide , $routeProvider ) {
2201
+ // While normally `$browser.defer()` modifies the `outstandingRequestCount`, the mocked
2202
+ // version (provided by `ngMock`) does not. This doesn't matter in most tests, but in this
2203
+ // case we need the `outstandingRequestCount` logic to ensure that we don't call the
2204
+ // `$$testability.whenStable()` callbacks part way through a `$rootScope.$evalAsync` block.
2205
+ // See ngRoute's commitRoute()'s finally() block for details.
2206
+ $provide . decorator ( '$browser' , function ( $delegate ) {
2207
+ var oldDefer = $delegate . defer ;
2208
+ var newDefer = function ( fn , delay ) {
2209
+ var requestCountAwareFn = function ( ) { $delegate . $$completeOutstandingRequest ( fn ) ; } ;
2210
+ $delegate . $$incOutstandingRequestCount ( ) ;
2211
+ return oldDefer . call ( $delegate , requestCountAwareFn , delay ) ;
2212
+ } ;
2213
+
2214
+ $delegate . defer = angular . extend ( newDefer , oldDefer ) ;
2215
+
2216
+ return $delegate ;
2217
+ } ) ;
2218
+
2219
+ addRouteWithAsyncRedirect ( '/foo' , '/bar' ) ;
2220
+ addRouteWithAsyncRedirect ( '/bar' , '/baz' ) ;
2221
+ addRouteWithAsyncRedirect ( '/baz' , '/qux' ) ;
2222
+ $routeProvider . when ( '/qux' , {
2223
+ template : '' ,
2224
+ resolve : {
2225
+ a : function ( $q ) {
2226
+ var deferred = deferreds [ '/qux' ] = $q . defer ( ) ;
2227
+ return deferred . promise ;
2228
+ }
2229
+ }
2230
+ } ) ;
2231
+
2232
+ // Helpers
2233
+ function addRouteWithAsyncRedirect ( fromPath , toPath ) {
2234
+ $routeProvider . when ( fromPath , {
2235
+ resolveRedirectTo : function ( $q ) {
2236
+ var deferred = deferreds [ fromPath ] = $q . defer ( ) ;
2237
+ return deferred . promise . then ( function ( ) { return toPath ; } ) ;
2238
+ }
2239
+ } ) ;
2240
+ }
2241
+ } ) ;
2242
+
2243
+ inject ( function ( $browser , $location , $rootScope , $route , $$testability ) {
2244
+ $location . path ( '/foo' ) ;
2245
+ $rootScope . $digest ( ) ;
2246
+
2247
+ var callback = jasmine . createSpy ( 'callback' ) ;
2248
+ $$testability . whenStable ( callback ) ;
2249
+ expect ( callback ) . not . toHaveBeenCalled ( ) ;
2250
+
2251
+ deferreds [ '/foo' ] . resolve ( ) ;
2252
+ $browser . defer . flush ( ) ;
2253
+ expect ( callback ) . not . toHaveBeenCalled ( ) ;
2254
+
2255
+ deferreds [ '/bar' ] . resolve ( ) ;
2256
+ $browser . defer . flush ( ) ;
2257
+ expect ( callback ) . not . toHaveBeenCalled ( ) ;
2258
+
2259
+ deferreds [ '/baz' ] . resolve ( ) ;
2260
+ $browser . defer . flush ( ) ;
2261
+ expect ( callback ) . not . toHaveBeenCalled ( ) ;
2262
+
2263
+ deferreds [ '/qux' ] . resolve ( ) ;
2264
+ $browser . defer . flush ( ) ;
2265
+ expect ( callback ) . toHaveBeenCalled ( ) ;
2266
+ } ) ;
2267
+ } ) ;
2268
+ } ) ;
2085
2269
} ) ;
0 commit comments