2012-12-22 3 views
3

Я использую ChaiJS с моим плагином Casper-Chai, и я не уверен, как решить конкретную проблему, с которой я сталкиваюсь.Как (и нужно ли) модифицировать объект в цепочке Chai BDD

Я хотел бы иметь возможность писать тесты, такие как:

expect(casper).selector("#waldo").to.be.visible; 

Это довольно просто, с вызовом, такие как

utils.addChainableMethod(chai.Assertion.prototype, 'selector', 
    selectorMethod, selectorChainableMethod); 

utils.addMethod(chai.Assertion.prototype, 'visible', visibleMethod); 

Где *Method ссылки являются функции, которые выполняют соответствующие тесты или цепочки вызовов.

Мой вопрос - лучший способ иметь, например, «селектор» изменяет потомков в цепочке. Два варианта приходит на ум:

  1. использование utils.flag(chai, 'object') изменить его к селектору; или

  2. создать новый флаг, например. utils.flag(chai, 'casper-selector')

Когда вызывается «видимый», он может читать соответствующий флаг. Если модификация «объекта», по-видимому, полезна, при вызове, например, «длина» позже. Тем не менее, я несколько обеспокоен неожиданными побочными эффектами изменения «объекта».

Я также могу изменить объект, для испытаний «длиной», вниз по цепочке, например:

// 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- Чай должен быть плагином Chai, а не просто альтернативой существующему API Каспер. Каспер - обертка вокруг браузера PhantomJS без головы, и таким образом Каспер запускает две эффективно две различные виртуальные машины: A «Контроллер» и безгласный веб-браузер.

В контроллере нет объекта DOM или "document" или "window"; Контроллер в этом отношении очень похож на Node.js, хотя и использует парсер WebKit javascript. Параллельно PhantomJS запускает безгласный веб-браузер. Затем контроллер может взаимодействовать с API-интерфейсом PhantomJS/Casper в браузере без браузера. Контроллер может сказать безгласному браузеру, какие страницы загружать, какой javascript запускать (что похоже на ввод javascript в консоль) и даже имитировать такие события, как ввод с клавиатуры и щелчки мышью. В браузере без гарнитуры есть полный стек DOM и javascript: это веб-страница, загруженная в WebKit. Вы можете capture screenshots того, что визуализировал WebKit.

Casper-Chai запускается в контроллере. Тесты, созданные в Mocha + Chai в контроллере, предназначены для оценки состояния безгласного браузера. Хотя мы можем скопировать состояние из браузера в контроллер и запустить тесты в этом скопированном состоянии, мои ограниченные эксперименты с этим дизайном выявили проблемы, присущие дизайну (например, эффективность, условия гонки, производительность и потенциальные побочные эффекты). Проблема в том, что состояние браузера является динамичным, сложным и может быть громоздким.

Так что, принимая пример Джона, expect(casper.find("#waldo")).to.be.visible не будет работать, так как нет DOM, если объект, возвращенный Каспером, не сделал своего рода ленивую оценку/посредничество. Даже если мы сериализовали и скопировали HTML-элемент там, в контроллере нет CSS. Тогда, даже если бы существовали CSS для #waldo, невозможно проверить иерархию, как если бы это был веб-браузер. Нам пришлось бы копировать значительную часть DOM и все CSS, а затем реплицировать веб-браузер, чтобы проверить, видно ли #waldo - для каждого отдельного теста. Каспер-Чай должен избегать этой проблемы, выполнив тесты в браузере.

Просто для небольшого дополнительного освещения тривиальное сравнение позволяет получить количество элементов, соответствующих селектору. Можно написать expect(casper.evaluate(function() {return __utils__.findAll('.my_class')}).to.have.length(4), где casper.evaluate запускает данную функцию в браузере без заголовка и возвращает список элементов DOM, соответствующих селектору в виде строк; и вы можете думать о __utils__ как версия jQuery Каспера. В качестве альтернативы можно было бы написать expect(casper).selector('.my_class').to.have.length(4), где selector становится «объектом» и имеет геттер .length, который вызывает «casper.evaluate (function() {return utils .findAll ('. My_class'). Length`. Только целая длина возвращается, для небольшого числа тестов либо работает нормально, но для большего числа тестов эта характеристика производительности становится эффективной (здесь, в этой упрощенной форме и, возможно, в значительно большей степени в более сложных случаях).

может, конечно, написать expect(casper.evaluate(function() { __utils__.findAll('.my_class').length }).equal(4), но если вы собираетесь писать такие тесты, зачем беспокоиться о BDD/Chai? Это исключает преимущества читаемости, которые предлагает Chai.

Также стоит отметить, что в контроллере может быть несколько экземпляров Каспера, соответствующих нескольким страницам PhantomJS. Думайте о них как о жутких вкладках.

Так что, учитывая ответ Доменика о том, что изменение флага «объект» является подходящим способом для этого, это кажется наиболее практичным способом - с учетом любых мыслей в свете приведенного выше описания.

Надеюсь, что выше описано, почему Каспер-Чай должен быть плагином, а не просто расширением API для Каспера. Я также запустил это автор Каспера, чтобы узнать, есть ли у него какие-либо данные.

Это может быть не идеальное отношение, но я надеюсь, что Каспер & Chai может ладить с удовольствием. :)

ответ

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) 
+0

Благодаря @John - это хорошая мысль, и, конечно, возможность –

+0

я сделал правку (извините за длину) на вопрос, который описывает обоснование для плагина. Я думаю, что то, что вы предлагаете, по-прежнему может быть лучшим вариантом, чем изменение «объекта»; вопрос может заключаться в том, вводим ли мы посредника в цепочку Чай (что не должно быть ленивым), или у Каспера есть нативный ленивый посредник. Я должен подумать об этом еще немного. :) –

+0

Вот как бы я это сделал: https://gist.github.com/4365642 – John

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 флаг для. Chai даже делает это, чтобы сделать утверждения, как

myObj.should.have.property("foo").that.equals("bar") 

работы скважины:

https://github.com/chaijs/chai/blob/49a465517331308695c3d8262cdad42c3ac591ef/lib/chai/core/assertions.js#L773

+0

Спасибо Domenic. Я рад слышать, что флаг «объект» предназначен для этой цели. Я внес изменения в вопрос, который может дать небольшое представление о проблеме ... но я думаю, что вы и Джон предложили, возможно, лучший вариант. С правильным посредником, означает ли это, что нам не нужен плагин Каспер-Чай? :) –

+0

Я думаю, что ключ здесь - это смысловое значение двух стилей, которые вы рассматриваете. В частности, мой пример синтаксиса 'should' помогает выявить проблемы с первым подходом. Что касается желаемого плагина Каспер-Чая, то это зависит от того, хотите ли вы получить пользовательские утверждения или нет. Например, у John's Chai-jQuery есть некоторые действительно прекрасные пользовательские утверждения, поэтому, если для Каспера есть похожие специфичные для домена, тогда было бы целесообразно построить плагин. – Domenic

+0

Спасибо Доминик. Я просто размышлял над необходимостью пользовательских утверждений. Вероятно, есть некоторые, и в любом случае семантика некоторых собственных тестов (например, «match») различна для селекторов, поэтому мне, возможно, придется переписать их для проверки для селекторов. Я думаю, что Chai-jQuery - хороший прецедент, спасибо - я буду читать, что @John сделал там. –

 Смежные вопросы

  • Нет связанных вопросов^_^