次のサービスを利用できます。
_angular.module("services")
.factory("whatever", function($window) {
return {
redirect: function() {
$window.location.replace("http://www.whatever.com");
}
};
});
_
単体テストで_$window
_オブジェクトをモックして、テストの実行時にページの再読み込みを防ぐ方法は?
使ってみた
spyOn($window.location, 'replace').andReturn(true);
、しかしそれは機能しませんでした(まだ_"Some of your tests did a full page reload!"
_エラーが発生しました)そして
$provide.value('$window', {location: {replace: jasmine.createSpy()}})
、しかし、スタックトレースがangular自分のソースのみを指しているため、エラー(_Error: [ng:areq] Argument 'fn' is not a function, got Object
_)を受け取っていたので、あまり役に立ちませんでした...
Chrome(他のブラウザではテストしなかった)では、location.replaceは読み取り専用であるため、spyOnはこれを置き換えることができませんでした。
$provide.value
動作するはずです。コードのどこかが間違っているに違いありません。
これが作業ユニットテストです
describe('whatever', function() {
var $window, whatever;
beforeEach(module('services'));
beforeEach(function() {
$window = {location: { replace: jasmine.createSpy()} };
module(function($provide) {
$provide.value('$window', $window);
});
inject(function($injector) {
whatever = $injector.get('whatever');
});
});
it('replace redirects to http://www.whatever.com', function() {
whatever.redirect();
expect($window.location.replace).toHaveBeenCalledWith('http://www.whatever.com');
});
});
簡単ですが、おそらくエレガントではないソリューションを使用します。私は$ window.locationのラッパーを書いていますが、これをモックできます。それをあなたのコードに関連付けて、$ windowをモックするのではなく、whatever.redirect関数をモックします(ここでは、実際の関数はより複雑であると想定しています)。
だから私は最終的に:
angular.module("services")
.factory("whatever", function($window) {
return {
do_stuff_that_redirects: function() {
lots of code;
this.redirect("http://www.whatever.com");
maybe_more_code_maybe_not;
},
redirect: function(url) {
$window.location.replace(url);
}
};
});
その後、リダイレクトメソッドを直接モックできます。コードが1行しかないため、実際に問題が発生することはありません。
spyOn(whatever, 'redirect').andCallFake(function(){});
expect(whatever.redirect).toHaveBeenCalledWith('http:/my.expected/url');
これは私の目的には十分であり、呼び出されたURLを検証できます。
私はあなたのために働くかもしれない別のアプローチを提供します。最終的にユーザーをリダイレクトするコントローラー「アクション」のユニットテスト中に同じ問題に直面しました(フルページ読み込みですが、より大きなWebサイト/アプリケーションの別のページに)。コンテキストを与えるために、コントローラーはAJAXリクエストを発行します。レスポンスがOKの場合、$ window.location.replace()を介してユーザーを別のページにリダイレクトします。
$http.post('save', data)
.success(function(responseData, status, headers, config) {
if(responseData.redirect) {
$window.location.replace(responseData.redirect);
}
})
.error(function(responseData, status, headers, config) {
console.error("ERROR while trying to create the Event!!");
});
このコントローラー機能のテストでは、同じ「テストの一部でページ全体のリロードが行われました!」が発生しました。エラー。そこで、コントローラ仕様のbeforeEach()関数に次を追加して、$ windowサービスをモックアウトしました。
mockWindow = { location: { replace: function(url) { console.log('redirecting to: ' + url); } } };
eventCtrl = $controller('EventCtrl', { $scope: scope, $window: mockWindow });
もちろん、この解決策は、replace関数が期待された引数で呼び出されたことを(きれいに)検証することを妨げますが、私は今のところそれについて本当に気にしません。
$location.path('/someNewPath');
$ location.replace(); //または、これらを次のように連鎖できます:$ location.path( '/ someNewPath')。replace();
$window.location
を呼び出すのではなく、 $ location サービスを使用したいと思います。この機能を説明するページ全体もここにあります: http://docs.angularjs.org/guide/dev_guide.services.$location 。
これを使用すると、テストで$ locationサービスのスタブバージョンを使用するのはかなり簡単になります。