Conversation
…inclusion to Capybara JS execution
| second_answer = create(:answer, question: question, user: user) | ||
| visit question_path(question) | ||
| within("#answer-#{second_answer.id}") { click_on 'Star' } | ||
| sleep 0.1 |
There was a problem hiding this comment.
Я не совсем понял, из-за чего точно, но таймаут капибары перестал успевать примерно на 100мс. Видимо, как раз в это время Сфинкс перестраивает дельта-индексы. Считаю, что костыль, но ничего умнее придумать не смог. И почему-то проявилось только в этом тесте.
There was a problem hiding this comment.
Ох, ну тут с тестом проблемка, конечно. Зачем нам проверять id элемента? Это уже не пользовательский сценарий, а кодерский. Надо проверять контент, используя have_content, который автоматически подождет до появления контента и избавить от костыля в виде sleep.
There was a problem hiding this comment.
Да, правда, можно было проще проверить. И, действительно, после переделки на have_content стало дожидаться. Не задумался, видимо, когда писал, что ждет именно он.
There was a problem hiding this comment.
Вот рано я обрадовался. Вызов have_content вообще не помогает, ну, точно Сфинкс перестраивает дельты и блокирует объект в транзакции, его надо еще ждать.
Получилось так: заметил, что CI показывает битые тесты. Посмотрел. API стало работать иначе -- порядок Answer-ов в ответе API поменялся на обратный. Так как явно он нигде не задавался, подумал, и поставил уж для большего педантизма default_scope во всех моделях, которые что-то отображают. Спеки API прошли. А этот тест снова стал заваливаться.
В итоге вернул sleep 0.1, так как единственный вариант получается -- делать флаг ожидания индексации Сфинкса или завершения транзакции, и все равно делать в спеке вызов ожидания. Так как готовность Сфинкса и так проверяется через 100мс, то пусть уж лучше тут будет sleep, медленнее от него точно не станет по сравнению с предложенным методом.
There was a problem hiding this comment.
have_content сам за тебя ждет, столько, сколько нужно. Ты как-то неправильно его используешь, значит. Ты, вероятно, оставил что-то вроде expect(page.first('div')).to have_content(...)?
Нужно так:
# сужаем область, в которой будет производится поиск элементов
within "#answers div:first-child" do # а лучше использовать имя класса "#answers .answer:first-child"
expect(page).to have_content(...)
endКогда ты делаешь page.first(...), то возвращается тот элемент, который был первым в момент вызова, и тут уже не помогает have_content.
There was a problem hiding this comment.
Вообще, я это понял, исключил даже within и для проверки сделал вот так:
# sleep 0.1
expect(page).to have_content second_answer.bodyИ без комментарием тест работает, с комментарием -- валится. Но с #answers div:first-child мне вариант больше нравится, переделаю на него. C #answers .answer хоть и лаконичнее, но хуже читается, менее понятно, что выделяется.
There was a problem hiding this comment.
Попробовал, не получается ни с #answers div:first-child, ни c #answers .answer (у меня в текущей ветке нет класса answer, но для эксперимента я его добавил). Всегда валится на Capybara::Ambiguous, например с: Ambiguous match, found 2 elements matching css "#answers .answer". Пробую из JS-консоли: один элемент. Странно.
В итоге sleep оставил, и have_content перед ним тоже, хотя, он не спасает совершенно. Думаю, варианты с селекторами, даже если он их смэтчит правильно, не пройдут тоже.
В итоге, это лучшее, что работает.
| end | ||
| end | ||
|
|
||
| shared_examples :sphinx_search_controller_with_params do |entity, attribute, search_type, validity = true| |
There was a problem hiding this comment.
Возможно, здесь с shared example-ом я немного "перехимичил", зато получилось весьма лаконичная сама спека
There was a problem hiding this comment.
"Перехимичил", разве что, с расположением примеров.
В данном случае лучше сами shared_examples объявить в файле-спеке самого контроллера. Сейчас спека контроллера – сплошная магия, ее нельзя взять и прочитать, как спецификацию.
There was a problem hiding this comment.
Самое смешное, что я так их и писал, потом выносил в отдельный файл. Именно, чтобы пока пишешь, не запутаться )). Понял, вернул в спеку.
app/models/search_service.rb
Outdated
| @@ -0,0 +1,28 @@ | |||
| class SearchService | |||
There was a problem hiding this comment.
Ну уверен, что правильнее: помещать сервисный объект в модели, или делать еще одну папку в /app и прописывать её в пути загрузки приложения? Пока объект всего один, положил в модели, чтобы не разветвлять дерево проекта.
app/models/search_service.rb
Outdated
| @@ -0,0 +1,28 @@ | |||
| class SearchService | |||
app/models/search_service.rb
Outdated
| private | ||
|
|
||
| def klass(type) | ||
| case type |
There was a problem hiding this comment.
Не очень мне нравится такой подход, у нас все-таки Ruby, можно применить что-нибудь из мета-программирования.
Например, получать с клиента не однобуквенные типы, а полные ("question", "answer"), и делать classify.constantize, предварительно фильтруя, конечно.
There was a problem hiding this comment.
Да, это я понимаю, даже хотел так и сделать сначала, но тут немного меня смущает, то, что "снаружи" будет видно, какой класс у нас внутри приложения. Пока в нашем примере, они очевидны, то это все же не очень страшно, но если они будут более заковыристыми, я бы не рискнул их пользователю показывать в GET-запросах. Ок, это переделаю, даже спеки попроще станут.
There was a problem hiding this comment.
Сделал, спеки лаконичнее сильно не стали, но зато вынес в константу сервис-объекта допустимые значения.
| second_answer = create(:answer, question: question, user: user) | ||
| visit question_path(question) | ||
| within("#answer-#{second_answer.id}") { click_on 'Star' } | ||
| sleep 0.1 |
There was a problem hiding this comment.
Ох, ну тут с тестом проблемка, конечно. Зачем нам проверять id элемента? Это уже не пользовательский сценарий, а кодерский. Надо проверять контент, используя have_content, который автоматически подождет до появления контента и избавить от костыля в виде sleep.
| end | ||
| end | ||
|
|
||
| shared_examples :sphinx_search_controller_with_params do |entity, attribute, search_type, validity = true| |
There was a problem hiding this comment.
"Перехимичил", разве что, с расположением примеров.
В данном случае лучше сами shared_examples объявить в файле-спеке самого контроллера. Сейчас спека контроллера – сплошная магия, ее нельзя взять и прочитать, как спецификацию.
|
Несмотря на проблему с тестом, в котором приходится спать 100мс, думаю, можно двигаться дальше, PR пока оставлю открытым, но в мастер зарибейжу. Если что надо будет поправить -- поправлю в следующих ветках или между ними. |
No description provided.