我正在为我的新聚合物项目建造脚手架,并正在考虑进行单元测试。我想我将使用业力/茉莉花组合。在http://japhr.blogspot.co.uk/2014/03/polymer-page-objects-and-jasmine-20.html有一篇有趣的帖子,我理解这个帖子足以让我开始,但我必须解决的关键问题是,我没有找到任何标准的方法来模拟ajax调用。< / p>
当我在JQuery Mobile项目中使用jasmine,standalone时,我能够直接使用Jasmine SpyOn来模拟JQuery.ajax调用。 Polymer有类似的东西吗?
我遇到了一个元素<polymer-mock-data>
,但没有真正的文档,所以我无法弄清楚它们是否可以提供帮助
答案 0 :(得分:3)
不要导入core-ajax/core-ajax.html
,而是创建自己的core-ajax元素。
<polymer-element name="core-ajax" attributes="response">
<script>
Polymer('core-ajax', {
attached: function() {
this.response = ['a', 'b', 'c'];
}
});
</script>
</polymer-element>
显然,这只是一个例子,实际的实现取决于所需的模拟行为。
这只是解决问题的一种方法,还有很多其他方法。我很有兴趣听到你在(方便)找到的东西。
答案 1 :(得分:1)
事实证明,Jasmine2.0有一个Jasmine-ajax插件,可以模拟全局XMLHttpRequest。 core-ajax在引擎盖下使用它,所以我可以直接接听电话。
效果很好,在您调用beforeEach
套件顶部的jasmine.Ajax.install
函数和afterEach
函数中调用jasmine.Ajax.uninstall
,它会自动替换XMLHttpRequest
时序也很重要,因为你需要确保在被测元素使用它之前模拟了Ajax调用。我使用一个单独的函数来实现它,以专门加载包含被测元素的fixture,该元素在调用jasmine.Ajax.install
后调用。我使用特殊的安装脚本
(function(){
var PolymerTests = {};
//I am not sure if we can just do this once, or for every test. I am hoping just once
var script = document.createElement("script");
script.src = "/base/components/platform/platform.js";
document.getElementsByTagName("head")[0].appendChild(script);
var POLYMER_READY = false;
var container; //Used to hold fixture
PolymerTests.loadFixture = function(fixture,done) {
window.addEventListener('polymer-ready', function(){
POLYMER_READY = true;
done();
});
container = document.createElement("div");
container.innerHTML = window.__html__[fixture];
document.body.appendChild(container);
if (POLYMER_READY) done();
};
//After every test, we remove the fixture
afterEach(function(){
document.body.removeChild(container);
});
window.PolymerTests = PolymerTests;
})();
这里唯一需要注意的是,夹具文件已由karma html2js预处理器加载,后者将它们加载到window.__html__
数组中,我们使用该代码将其添加到测试上下文< / p>
我的测试套件就是这样
describe('<smf-auth>',function(){
beforeEach(function(done){
jasmine.Ajax.install();
PolymerTests.loadFixture('client/smf-auth/smf-auth-fixture.html',done);
});
afterEach(function(){
jasmine.Ajax.uninstall();
});
describe("The element authenticates",function(){
it("Should Make an Ajax Request to the url given in the login Attribute",function(){
var req = jasmine.Ajax.requests;
expect(req.mostRecent().url).toBe('/football/auth_json.php'); //Url declared in our fixture
});
})
});
答案 2 :(得分:0)
对于这个答案,我采取了完全不同的方法。灵感来自Web Component Tester,其中包括sinon的功能。 sinon包括调用sinon.useFakeXMLHttpRequest来替换core-ajax使用的标准xhr对象并返回其上的响应的能力。
据我所知,还没有完全运行使用它的模块测试,Web Component Tester在node.js上下文中运行sinon所以随它提供的sinon的构建可以“需要”各种sinon组件。在普通的浏览器环境中,这不起作用,我正在寻找一种方法,允许我手动运行我正在开发的应用程序,而没有运行php的服务器..
但是,从Bower下载并安装来自sinonjs.org网站的实际版本,确实提供了一个完全构建的sinon,它将在Web服务器的上下文中运行。
所以我可以在主index.html文件中包含以下脚本
<!--build:remove -->
<script type="text/javascript" src="/bower_components/sinon-1.14.1/index.js"></script>
<script type="text/javascript" src="/fake/fake.js"></script>
<!--endbuild-->
这是由gulp构建scrips自动删除,然后假JS有以下内容
var PAS = (function (my) {
'use strict';
my.Faker = my.Faker || {};
var getLocation = function(href) {
var a = document.createElement('a');
a.href = href;
return a;
};
sinon.FakeXMLHttpRequest.useFilters = true;
sinon.FakeXMLHttpRequest.addFilter(function(method,url){
if(method === 'POST' && getLocation(url).pathname.substring(0,7) === '/serve/') {
return false;
}
return true;
});
var server = sinon.fakeServer.create();
server.autoRespond = true;
my.Faker.addRoute = function(route,params,notfound){
server.respondWith('POST','/serve/' + route + '.php',function(request){
var postParams = JSON.parse(request.requestBody);
var foundMatch = false;
var allMatch;
/*
* First off, we will work our way through the parameter list seeing if we got a parameter
* which matches the parameters received from our post. If all components of a parameter match,
* then we found one
*/
for(var i=0; i <params.length; i++) {
//check to see parameter is in request
var p = params[i][0];
allMatch = true; //start of optimisic
for(var cp in p ) {
//see if this parameter was in the request body
if(typeof postParams[cp] === 'undefined') {
allMatch = false;
break;
}
if(p[cp] !== postParams[cp]) {
allMatch = false;
break;
}
}
if (allMatch) {
request.respond(200,{'Content-Type':'application/json'},JSON.stringify(params[i][1]));
foundMatch = true;
break;
}
}
//see if we found a match. If not, then we will have to respond with the not found option
if (!foundMatch) {
request.respond(200,{'Content-Type':'application/json'},JSON.stringify(notfound));
}
});
};
return my;
})(PAS||{});
/**********************************************************************
Thses are all the routinee we have and their responses.
**********************************************************************/
PAS.Faker.addRoute('logon',[
[{password:'password1',username:'alan'},{isLoggedOn:true,userID:1,name:'Alan',token:'',keys:['A','M']}],
[{username:'alan'},{isLoggedIn:false,userID:1,name:'Alan'}],
[{password:'password2',username:'babs'},{isLoggedOn:true,userID:2,name:'Barbara',token:'',keys:['M']}],
[{username:'babs'},{isLoggedIn:false,userID:2,name:'Barbara'}]
],{isLoggedOn:false,userID:0,name:''});
PAS函数初始化一个sinon假服务器,并提供一种使用addRoute函数提供测试用例的方法。对于给定的路由,它会检查可能的POST参数组合列表,一旦找到它,就会发出响应。
在这种情况下,测试/serve/logon.php以获取用户名和密码的各种组合。它只检查特定条目中的实际参数。
因此,如果username =“alan”和password =“password1”,则会发出第一个响应,但如果用户名是“alan”并且提供了任何其他密码 - 因为未选中,则第二个模式匹配并且响应制定了这种模式。
如果非模式匹配,则最后一个“notfound”参数是所做的响应模式。
我相信如果我愿意的话,我可以在我的模块测试装置中使用相同的技术,但我更有可能做更具体的sinon间谍并检查该模式下的实际参数
答案 3 :(得分:0)
对于0.8,link显示如何使用sinon。
由于SO不喜欢仅限链接的答案,因此我在下面复制了他们的代码。但是我强烈建议你去上面链接的源码,因为0.8组件目前处于高通量状态。
var jsonResponseHeaders = {
'Content-Type': 'application/json'
};
var ajax;
var request;
var server;
setup(function () {
server = sinon.fakeServer.create();
server.respondWith(
'GET',
'/responds_to_get_with_json',
[
200,
jsonResponseHeaders,
'{"success":true}'
]
);
server.respondWith(
'POST',
'/responds_to_post_with_json',
[
200,
jsonResponseHeaders,
'{"post_success":true}'
]
);
ajax = fixture('TrivialGet');
});
teardown(function () {
server.restore();
});
suite('when making simple GET requests for JSON', function () {
test('has sane defaults that love you', function () {
request = ajax.generateRequest();
server.respond();
expect(request.response).to.be.ok;
expect(request.response).to.be.an('object');
expect(request.response.success).to.be.equal(true);
});
test('will be asynchronous by default', function () {
expect(ajax.toRequestOptions().async).to.be.eql(true);
});
});