Разрешить вызов шагов из определений шагов.
https://github.com/cucumber/cucumber/wiki/Calling-Steps-from-Step-Definitions
Когда это будет реализовано, имейте в виду, что мы планируем объявить устаревшим все, кроме #steps
, для этого в огурце-rb. См. https://github.com/cucumber/cucumber/issues/68 .
Спасибо, Мэтт. -js будет поддерживать только шаги().
Мне это нравится!
Есть ли прогресс в этом? Кажется, это довольно важная функция.
Это не планируется как часть текущей вехи (0.3). Это _должно_ быть частью 0.4.
@mattwynne Думаю, мы тоже хотим поддержать step()
. Я прав?
@jbpros, я думаю. Может быть, вы могли бы начать с #step
. Его проще реализовать, потому что вы просто вызываете шаг, а не анализируете корнишон.
Я лично был бы рад использовать Cucumber без этой функции, я никогда не использую ее и считаю это плохой практикой. Вместо этого я всегда предпочитаю делегировать методы.
В конечном счете, если мы собираемся поддерживать это, я бы предпочел, чтобы это было реализовано в Gherkin, чтобы у вас был способ определить макрошаг, который сопоставляется с кучей других низкоуровневых шагов. Затем Cucumber просто получает указание вызывать более низкие уровни, и ему вряд ли нужно знать, что происходит какое-либо сопоставление. Это было бы моим предпочтением.
TL;DR: Должны ли мы действительно добавить steps()
/ step()
в Cucumber.js (и -jvm, -ruby 2 и т. д.)?
Я полностью согласен с тобой, Мэтт. _К сожалению_, сейчас это самая востребованная функция на Cucumber.js.
Насколько я понимаю, многие считают определения шагов _методами_ или _функциями_. На мой взгляд, это сопоставления между некоторыми беглыми языковыми предложениями и фрагментами кода языка программирования, не более того. Это имеет глубокие последствия для того, как мы относимся к этим зверям.
Однако с точки зрения программиста определения шагов выглядят точно так же, как и методы. Сегодня я вижу в этом слабость Cucumber_s_. Определения шагов не должны быть представлены как API, а скорее как явная карта перевода, так сказать, словарь.
У @msassak уже были интересные мысли по этому поводу, и я думаю, что он проделал отличную работу, перемоделировав эти «отображения» в Cucumber 2.0.
Я должен сказать, что не хочу работать над этой проблемой в Cucumber.js прямо сейчас. С другой стороны, я не хочу сохранять функции только из-за своих личных вкусов/мнений.
:-1: :-1: :-1: :-1: :-1:
Вызов шагов из stepdefs — это одна из тех функций, которые я бы никогда не добавил в Cucumber (-Ruby), потому что это дает людям столько веревок, на которых они могут повеситься. Это произошло из-за того, что пошаговые определения Ruby используют анонимные замыкания, которые вы не можете вызывать откуда-либо еще (если только вы не пройдете через обручи).
С JavaScript ситуация другая; Определения шагов используют первоклассные функции!
function x_is_something(x, cb) {
console.log('x', x);
cb();
}
Given(/x is (.*)/, x_is_something);
Given(/super x/, function(cb) {
x_is_something(97, cb);
});
CLOSED (WONTFIX)
:молоток:
Я не уверен, что понимаю, чем здесь step()
будет лучше, чем простой вызов функции JS. Разве это не то, что он в конечном итоге сделает, с дополнительным уровнем косвенности (т.е. определение шага для выполнения запроса GET для конкретного пользователя, который все еще необходимо преобразовать в функцию JS)?
Я заметил, что вы написали _поскольку у меня нет возможности запустить сценарий_, вы имели в виду шаг или это преднамеренный сценарий (в последнем случае я вижу, что вы пытаетесь сделать, я думаю).
Вы по-прежнему можете определять пользователей в фоновом режиме и перебирать их на шаге When
.
Feature:
Background:
Given a valid user called Simon
And a valid user called Sarah
And a valid user called Johnny
Scenario Outline:
When each valid user sends a GET request to /search<query>
Then everyone's request response code is 400
And everyone's request response body starts with <body>
Examples:
| query | body |
| ?foo=1 | ... |
И да, это означает сохранение ответов на запросы в массиве и повторение их. Это так плохо?
Что ж, если у вас есть какой-то поток (например, процесс оформления заказа) и вы хотите перейти на страницу окончательного подтверждения, вы можете пройти через шаги, определенные (где-то) в определениях шагов.
Я согласен с тем, что вы также можете где-то определить функцию и вызвать ее из определения шага. Но это сводит к минимуму усилия по перемещению его от шагов к функционированию. Если вы где-то в BDD описали какой-то поток, вам не нужно тратить дополнительное время на перенос его в отдельную библиотеку, вы можете просто вызывать определения шагов.
Вызов одного единственного шага почти бесполезен. Я думал о портировании всех функций ruby step(s) здесь. Но так как мой запрос закрылся, я бы не стал тратить на него время.
Спасибо.
Так грустно, что это не исправит, как говорит @cono : вызов одного шага почти бесполезен, реальные случаи - более сложные операции.
Было бы очень полезно создать несколько мелкозернистых сценариев, а затем другие сценарии, повторяющие эти операции. В частности, когда шаги определены более чем в одном файле, в этом случае альтернатива повторного использования функций не совсем проста и не чиста.
Хай! Я создал библиотеку, которая делает именно то, что вы просите (вызовите шаг из другого шага), посмотрите здесь: https://github.com/hackhat/cucumberry
Обратная связь приветствуется!
@hackhat Выглядит очень круто. Обычно мне нравится синхронизирующая часть определения шага. Огурец-про только плагин для огурца.js?
@ jlin412 Я действительно не знаю, как звонить, но это как помощник для огурца. Спасибо за отзыв
@hackhat Чтобы создать шаг синхронизации, мне нужно будет использовать синтаксис: this.addStep(...)? Нужно ли будет использовать selenium-sync вместо protractor.js/webdriver.js?
@ jlin412 вы можете использовать только плагин синхронизации, посмотрите в документации, как это сделать. Я на мобильном телефоне, поэтому не могу дать вам точные шаги. Если вы можете подождать, я объясню лучше около 23:30 по Португалии.
@hackhat, пожалуйста, измените название вашего проекта на другое. См. хакхат/огурец-про#1
@aslakhellesoy Изменено имя на https://github.com/hackhat/cucumberry
@aslakhellesoy Тогда как связать пошаговые вызовы? Нравится следить?
function x_is_something(x, cb) {
console.log('x', x);
this.x = x;
cb();
}
function y_is_something(y, cb) {
console.log('y', y);
this.y = y;
cb();
}
Given(/super z/, function(cb) {
x_is_something(97, cb);
y_is_something(8, cb);
});
Это не очень хорошо работает, так как x_is_something
вызовет обратный вызов до того, как y_is_something
успеет завершить свою работу.
А также, если шаг хранит переменную в мировом контексте, она будет заканчиваться каждый раз при вызове функции, нам нужно связать ее следующим образом:
Given(/super z/, function(cb) {
x_is_something.bind(this)(97, cb);
y_is_something.bind(this)(8, cb);
});
У кого-нибудь были решения этих проблем?
Вам нужно использовать асинхронность и использовать параллельную функцию. Таким образом вы вызываете
основной cb только после завершения обоих подвызовов.
О привязке вы можете использовать это с привязкой или использовать переменную закрытия.
Чт, 14 мая 2015 г., 00:15 Юн Цзя, [email protected] написал:
@aslakhellesoy https://github.com/aslakhellesoy Тогда как связать
пошаговые звонки? Нравится следить?функция x_is_something(x, cb) {
console.log('х', х);
это.х = х;
КБ();
} функция y_is_something (y, cb) {
console.log('у', у);
это.у = у;
КБ();
}Учитывая (/супер z/, функция (cb) {
x_is_something(97, cb);
y_is_something(8, cb);
});Это не очень хорошо работает, так как x_is_something вызвал бы
обратный вызов до того, как y_is_something сможет завершить свою работу.А также, если шаг хранит переменную в мировом контексте, это закончится
каждый раз, когда мы вызываем функцию, нам нужно связать ее следующим образом:Учитывая (/супер z/, функция (cb) {
x_is_something.bind(this)(97, cb);
y_is_something.bind(this)(8, cb);
});У кого-нибудь были решения этих проблем?
—
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/cucumber/cucumber-js/issues/11#issuecomment -101845619
.
+1, это должно быть частью библиотеки.
Что предложил @mattwynne (добавьте функцию корнишона, которая поддерживает повторное использование кода):
When a
Then x
When b
Then y
---------------------------------
Define x
Then p
And y
And q
---------------------------------
Step a
...
Step b
...
Step p
...
Step q
...
Step y
...
---------------------------------
Что предложил @aslakhellesoy (извлечение дублированного кода в функции js):
When a
Then x
When b
Then y
---------------------------------
Step a
...
Step b
...
Step x
...
Call f(p)
...
Step y
Call f(p)
---------------------------------
Function f(p)
...
---------------------------------
Вызов шагов из определений шагов
When a
Then x
When b
Then y
---------------------------------
Step a
...
Step b
...
Step x
...
Call y(p)
...
Step y
...
---------------------------------
Я до сих пор не понимаю, зачем нам еще один ненужный уровень абстракции, у вас есть какое-то объяснение?
@yunjia это базовая теория обратного вызова:
Given(/super z/, function(cb) {
x_is_something(97, function () {
y_is_something(8, cb);
});
});
Что касается проблемы привязки, вы должны определить эти функции как методы в вашем мире :
function World(callback) {
this.x_is_something = function (x, callback) {
this.x = ...
};
this.y_is_something = function (y, callback) {
this.y = ...
};
callback(); // tell Cucumber we're finished and to use 'this' as the world instance
};
}
module.exports.World = World;
Затем в ваших определениях шага:
Given(/super z/, function(cb) {
var self = this;
self.x_is_something(97, function () {
self.y_is_something(8, cb);
});
});
Также обратите внимание, что определения синхронных шагов поддерживаются Cucumber.js 0.5+:
Given(/super z/, function() {
this.x_is_something(97);
this.y_is_something(8);
});
Определения шагов @inf3rno представляют собой тонкий слой перевода между простым английским языком и кодом JS. Разрешая вызывать шаги из шагов, мы делаем этот слой толще. Ступени становятся связанными друг с другом, что делает их чрезвычайно сложными в обслуживании.
Он также побуждает людей использовать Gherkin в качестве языка сценариев, чем он вовсе не является.
@inf3rno , если вы хотите повторно использовать код в stepdef, переместите тело stepdef в обычную функцию javascript и повторно используйте ее.
@jbpros
Он также побуждает людей использовать Gherkin в качестве языка сценариев, чем он вовсе не является.
Можете ли вы уточнить, пожалуйста. Я не понимаю, какая связь, так как определения шага нет в корнишоне, только текстовый шаблон, что похоже.
@inf3rno inf3rno , если вы можете вызывать шаги из шагов, вы снова прыгаете в «Огурец»: имена шагов необходимо проанализировать и сопоставить с определениями шагов, которые могут быть выполнены. По сути, вы пишете сценарии корнишонов внутри корнишонов (они скрыты в определениях шагов JS, но это деталь, которая делает его еще хуже от точки зрения обслуживания).
@aslakhellesoy @jbpros Идея состоит в том, что шаги должны быть алгебраическими составными типами, а это не так.
@jbpros , я собираюсь использовать ваше решение, так как я привык программировать на Java и не беспокоиться об обещаниях :)
Кто-нибудь когда-нибудь придумывал расширение для огурца для определения шагов с точки зрения других шагов? Что-то типа
Understand I log in to {site} as {user}, {pass}
I visit {site}
I log in as {user}, {pass}
Размышляю над тем, является ли это расширение полезным для лучшего описания длительных путешествий пользователя по системе, и предпочел бы работать с любым предшествующим уровнем техники.
Эта ветка была автоматически заблокирована, так как после ее закрытия не было никаких действий в последнее время. Пожалуйста, откройте новую проблему для связанных ошибок.
Самый полезный комментарий
:-1: :-1: :-1: :-1: :-1:
Вызов шагов из stepdefs — это одна из тех функций, которые я бы никогда не добавил в Cucumber (-Ruby), потому что это дает людям столько веревок, на которых они могут повеситься. Это произошло из-за того, что пошаговые определения Ruby используют анонимные замыкания, которые вы не можете вызывать откуда-либо еще (если только вы не пройдете через обручи).
С JavaScript ситуация другая; Определения шагов используют первоклассные функции!