我正在使用ChaiJS我的Casper-Chai插件,我不知道如何解决我遇到的特定问题。
我希望能够编写如下测试:
expect(casper).selector("#waldo").to.be.visible;
这很简单,只需要调用
utils.addChainableMethod(chai.Assertion.prototype, 'selector',
selectorMethod, selectorChainableMethod);
utils.addMethod(chai.Assertion.prototype, 'visible', visibleMethod);
*Method
引用是指执行相应测试或可链接调用的函数。
我的问题是,最好的方法是什么? 'selector'修改链中的后代。我想到了两个选择:
使用utils.flag(chai, 'object')
将其更改为选择器;或
创建一个新标志,例如utils.flag(chai, 'casper-selector')
当调用'visible'时,它可以读取相应的标志。修改'对象'似乎有用的地方是调用例如'长度'后来。但是,我担心改变'对象'的意外副作用。
我可能还想修改对象,对于'长度'测试,在链中,例如:
// there can be only one!
expect(casper).selector("#waldo").length(1)
// but that one has 4 classes
expect(casper).selector("#waldo").class.to.have.length(4)
感谢任何想法和意见。
---- 编辑 ----
好的,所以这里是Casper-Chai的根本概念挑战,需要对Casper是什么以及为什么Casper-Chai应该是Chai插件的描述,而不仅仅是现有Casper API的替代品。 Casper是PhantomJS无头网络浏览器的包装器,因此Casper有效运行两个不同的虚拟机:A “控制器”和无头网络浏览器。
控制器中没有DOM或“文档”或“窗口”对象;虽然使用了WebKit javascript解析器,但Controller在这方面很像Node.js。与此同时,PhantomJS启动了无头网络浏览器。然后,Controller可以通过PhantomJS / Casper API与无头浏览器进行通信。 Controller可以告诉无头浏览器要加载哪些页面,运行什么javascript(这就像在控制台中输入javascript),甚至模仿键盘输入和鼠标点击等事件。无头浏览器有一个完整的DOM和javascript堆栈:它是一个在WebKit中加载的网页。您可以capture screenshots WebKit将呈现的内容。
Casper-Chai在Controller中运行。在Controller中的Mocha + Chai中创建的测试旨在评估无头浏览器的状态。虽然我们可以将状态从浏览器复制到Controller并在该复制状态下运行测试,但我对该设计的有限实验揭示了设计固有的问题(即效率,竞争条件,性能和潜在的副作用)。问题是浏览器状态是动态的,复杂的,并且可能很笨拙。
所以以John为例,expect(casper.find("#waldo")).to.be.visible
不起作用,因为没有DOM,除非Casper返回的对象做了某种懒惰的评估/调解。即使我们序列化并复制HTML元素,Controller中也没有CSS。然后,即使有#waldo
的CSS,也无法像对待Web浏览器那样测试层次结构。我们必须复制大部分DOM和所有CSS,然后复制一个Web浏览器来测试#waldo
是否可见 - 对于每个单独的测试。 Casper-Chai旨在通过在浏览器中运行测试来避免此问题。
只是为了一点额外的照明,一个微不足道的比较就是获得与选择器匹配的元素数量。可以编写expect(casper.evaluate(function () {return __utils__.findAll('.my_class')}).to.have.length(4)
,其中casper.evaluate
在无头浏览器中运行给定函数,并返回与选择器匹配的DOM元素列表作为字符串;您可以将__utils__
视为Casper的jQuery版本。或者,可以写expect(casper).selector('.my_class').to.have.length(4)
selector
成为'对象',它有一个调用'{1}},调用'casper.evaluate(function(){return utils .findAll('。my_class')。length`。只返回整数长度。对于少数测试要么工作正常,但对于大量测试,这种性能特征会产生影响(这里,这种简单的形式,和在更复杂的情况下可能在更大程度上)。
当然可以写.length
,但是如果要编写这样的测试,为什么要打扰BDD / Chai?它消除了Chai提供的可读性的好处。
值得注意的是,Controller中可能有多个Casper实例,对应多个PhantomJS页面。把它们想象成怪异的标签。
因此,考虑到Domenic的回答,修改'对象'标志是适当的方式,这似乎是最实用的方式 - 根据上述描述的任何想法。
我希望上面描述为什么Casper-Chai应该是一个插件,而不仅仅是Casper的API扩展。我也将由Casper的作者运行,看看他是否有任何意见。
这可能不是一个完美的关系,但我希望Casper&柴可以轻松相处。 :)
答案 0 :(得分:2)
困难源于casper具有高度程序化的API,使用Casper#click(String selector)
和Casper#fetchText(String selector)
等方法。为了与chai自然地匹配,需要面向对象的API,例如, Casper#find(String selector)
(返回CasperSelection
个对象),CasperSelection#click()
,CasperSelection#text()
等
因此,我建议您extend the casper object itself使用find
或selector
方法返回一个可以作为断言基础的对象。然后你不需要改变对象标志。
expect(casper.find("#waldo")).to.be.visible;
expect(casper.find("#waldo")).to.have.length(1)
expect(casper.find("#waldo").class).to.have.length(4)
答案 1 :(得分:1)
我基本同意@John。你正在对其他一些对象表达你的期望,所以说
expect(casper).select("#waldo").to.have.length(1)
非常奇怪。您对casper
没有任何期待,您期待的是casper.find("#waldo")
。还要考虑should
语法:
casper.should.select("#waldo").have.length(1)
// vs.
casper.find("#waldo").should.have.length(1)
也就是说,如果您已经设置了这种API,那么这正是object
标志的用途。 Cha甚至做到这一点,做出像
myObj.should.have.property("foo").that.equals("bar")
运作良好: