Cucumber-js: Chamando etapas de definições de etapa

Criado em 1 jun. 2011  ·  31Comentários  ·  Fonte: cucumber/cucumber-js

Comentários muito úteis

:-1: :-1: :-1: :-1: :-1:

Chamar passos de stepdefs é um daqueles recursos que eu gostaria de nunca ter adicionado ao Cucumber (-Ruby), porque ele fornece muita corda para as pessoas se enforcarem. Isso aconteceu porque os stepdefs do Ruby usam encerramentos anônimos que você não pode chamar de outro lugar (a menos que você passe por aros).

Com JavaScript é uma situação diferente; Definições de etapa usam funções de primeira classe!

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);
});

Todos 31 comentários

Quando isso for implementado, tenha em mente que planejamos descontinuar tudo que não seja #steps por fazer isso em pepino-rb. Veja https://github.com/cucumber/cucumber/issues/68

Obrigado Mateus. -js suportará apenas steps() então.

Eu gosto disso!

Algum progresso nisso? Parece um recurso bastante vital.

Isso não está planejado como parte do marco atual (0,3). Ele _deve_ ser parte de 0,4.

@mattwynne Acho que queremos apoiar step() também. Estou correcto?

@jbpros eu acho. Talvez você possa começar com #step . É mais simples de implementar porque você está apenas invocando uma etapa em vez de analisar o Gherkin.

Eu pessoalmente ficaria feliz em usar um Cucumber sem esse recurso, nunca o uso e considero uma má prática. Eu sempre prefiro delegar a métodos.

Em última análise, se vamos apoiar isso, prefiro vê-lo implementado no Gherkin, para que você tenha uma maneira de definir uma etapa macro que mapeie para várias outras etapas de baixo nível. O Cucumber é instruído a invocar os de nível inferior e dificilmente precisa saber que há algum mapeamento acontecendo. Essa seria a minha preferência.

TL;DR: Devemos realmente adicionar steps() / step() a Cucumber.js (e -jvm, -ruby 2, etc.)?

Concordo plenamente com você Mateus. _Infelizmente_, este é o recurso mais procurado no momento no Cucumber.js.

Pelo que entendi, muitas pessoas consideram as definições de etapas como _métodos_ ou _funções_. A meu ver, eles são mapeamentos entre algumas frases de linguagem fluente e pedaços de código de linguagem de programação, nada mais. Isso tem implicações profundas sobre como tratamos essas bestas.

Do ponto de vista do programador, as definições de etapas parecem métodos. Eu vejo isso como uma fraqueza em Cucumber_s_ hoje. As definições de etapas não devem ser expostas como uma API, mas sim como um mapa de tradução explícito, um dicionário, por assim dizer.

@msassak já tinha pensamentos interessantes sobre isso e acho que ele fez um ótimo trabalho remodelando esses "mapeamentos" no Cucumber 2.0.

Devo dizer que estou relutante em trabalhar neste problema no Cucumber.js agora. Por outro lado, não quero fazer retenção de recursos apenas por causa de meus gostos/opiniões pessoais.

:-1: :-1: :-1: :-1: :-1:

Chamar passos de stepdefs é um daqueles recursos que eu gostaria de nunca ter adicionado ao Cucumber (-Ruby), porque ele fornece muita corda para as pessoas se enforcarem. Isso aconteceu porque os stepdefs do Ruby usam encerramentos anônimos que você não pode chamar de outro lugar (a menos que você passe por aros).

Com JavaScript é uma situação diferente; Definições de etapa usam funções de primeira classe!

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) :martelo:

Não tenho certeza se entendi como step() seria melhor do que uma simples chamada de função JS aqui. Não é isso que acabaria fazendo de qualquer maneira, com uma camada adicional de indireção (ou seja, uma definição de etapa para fazer uma solicitação GET para um usuário específico que ainda precisa ser traduzida em uma função JS)?

Percebi que você escreveu _já que não tenho como acionar um cenário_, você quis dizer passo ou é esse cenário intencionalmente (no último caso, posso ver o que você está tentando fazer, acho).

Você ainda pode definir usuários em segundo plano e iterar sobre eles em sua etapa 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 | ...  |

E sim, isso significa armazenar respostas de solicitação em uma matriz e iterar sobre elas. Isso e ruim?

Bem, se você tiver algum fluxo (por exemplo, fluxo de checkout) e quiser chegar à página de confirmação final, poderá percorrer as etapas, definidas (em algum lugar) nas definições das etapas.
Concordo que você também pode definir uma função em algum lugar e invocá-la a partir da definição da etapa. Mas é minimizar o esforço de movê-lo de etapas para função. Se você descreveu algum fluxo em algum lugar no BDD, não precisa gastar mais tempo para movê-lo para uma biblioteca separada, basta invocar definições de etapa.

Invocar um único passo é quase inútil. Eu estava pensando em portar todas as funcionalidades do(s) passo(s) do ruby ​​aqui. Mas como meu pedido foi fechado, eu não perderia tempo com isso.

Obrigado.

Tão triste que isso não vai resolver, como diz @cono : invocar uma única etapa é quase inútil, casos reais são operações mais complexas.

Isso seria realmente útil para criar alguns cenários refinados e, em seguida, os outros cenários repetindo essas operações. Especialmente quando as etapas são definidas em mais de um arquivo, nesse caso a alternativa de reutilização de funções não é muito fácil nem limpa.

Oi! Eu criei uma lib que faz exatamente o que você está pedindo (chame uma etapa de outra etapa), dê uma olhada aqui: https://github.com/hackhat/cucumberry
Comentários são bem-vindos!

@hackhat Parece muito legal. Eu costumo gostar da parte de sincronização da definição da etapa. O pepino-pro é apenas um plugin para o pepino.js?

@jlin412 Eu realmente não sei como ligar, mas é como um ajudante de pepino. Obrigado pelo feedback

@hackhat Para criar a etapa de sincronização, precisarei usar a sintaxe: this.addStep(...)? Precisarei usar a sincronização de selênio também em vez de protractor.js/webdriver.js?

@ jlin412 você só pode usar o plug-in de sincronização, veja os documentos como fazê-lo. Estou no celular, então não posso dar os passos exatos. Se puder esperar vou explicar melhor por volta das 23h30 hora de Portugal.

@hackhat , por favor, altere o nome do seu projeto para outra coisa. Veja hackhat/cucumber-pro#1

@aslakhellesoy Mudou o nome para https://github.com/hackhat/cucumberry

@aslakhellesoy Então, como encadear as chamadas de etapas? Gostou de seguir?

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);
});

Isso não funciona muito bem, pois x_is_something teria chamado o retorno de chamada antes que y_is_something tivesse a chance de terminar seu trabalho.

E também, se step armazena a variável no contexto do mundo, ela terminará toda vez que chamar a função, precisamos vinculá-la assim:

Given(/super z/, function(cb) {
  x_is_something.bind(this)(97, cb);
  y_is_something.bind(this)(8, cb);
});

Alguém teve soluções para estes problemas?

Você precisa usar assíncrono e usar a função paralela. Desta forma você chama
o cb principal somente depois que ambas as chamadas secundárias terminarem.
Sobre a ligação, você pode usar isso com ligação ou usar uma variável de fechamento.

Em quinta-feira, 14 de maio de 2015, 00:15 Yun Jia [email protected] escreveu:

@aslakhellesoy https://github.com/aslakhellesoy Então como encadear o
chamadas de passo? Gostou de seguir?

function x_is_something(x, cb) {
console.log('x', x);
este.x = x;
cb();
}função y_is_algumacoisa(y,cb){
console.log('y', y);
este.y = y;
cb();
}

Dado(/super z/, function(cb) {
x_is_something(97, cb);
y_is_alguma coisa(8, cb);
});

Isso não funciona muito bem, pois x_is_something teria chamado o
callback antes que y_is_something tenha chance de terminar seu trabalho.

E também, se o step armazena a variável no contexto do mundo, ele acabará
cada vez que chamamos a função, precisamos vinculá-la como:

Dado(/super z/, function(cb) {
x_is_something.bind(this)(97, cb);
y_is_something.bind(this)(8, cb);
});

Alguém teve soluções para estes problemas?


Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/cucumber/cucumber-js/issues/11#issuecomment -101845619
.

+1, isso deve fazer parte da lib.

O que @mattwynne sugeriu (adicione um recurso gherkin que suporte a reutilização de código):

    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
        ...

---------------------------------

O que @aslakhellesoy sugeriu (extrair o código duplicado para funções 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)
        ...

---------------------------------

Chamando etapas de definições de etapa

    When a
    Then x
    When b
    Then y

---------------------------------

    Step a
        ...
    Step b
        ...
    Step x
        ...
        Call y(p)
        ...
    Step y
        ...

---------------------------------

Ainda não entendi porque precisamos de outro nível de abstração desnecessário, você tem alguma explicação?

@yunjia esta é a teoria básica de retorno de chamada:

Given(/super z/, function(cb) {
  x_is_something(97, function () {
    y_is_something(8, cb);
  });
});

Quanto ao problema de vinculação, você deve definir essas funções como métodos em seu World :

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;

Em seguida, em suas definições de etapas:

Given(/super z/, function(cb) {
  var self = this;
  self.x_is_something(97, function () {
    self.y_is_something(8, cb);
  });
});

Além disso, observe que as definições de etapas síncronas são suportadas pelo Cucumber.js 0.5+:

Given(/super z/, function() {
  this.x_is_something(97);
  this.y_is_something(8);
});

As definições da etapa @inf3rno são uma fina camada de tradução entre o inglês simples e o código JS. Ao permitir chamar etapas de etapas, tornamos essa camada mais gorda. As etapas tornam-se acopladas entre si, tornando-as extremamente difíceis de manter.

Também incentiva as pessoas a usarem o Gherkin como uma linguagem de script, o que não é de todo.

@inf3rno se você quiser reutilizar o código em stepdefs, mova o corpo do stepdef para uma função javascript regular e reutilize isso.

@jbpros

Também incentiva as pessoas a usarem o Gherkin como uma linguagem de script, o que não é de todo.

Você pode elaborar pls. Não entendi qual é a conexão, pois as definições das etapas não estão em gherkin, apenas o padrão de texto que é semelhante.

@inf3rno se você pode chamar etapas de etapas, você está voltando novamente para "Gherkinland": os nomes das etapas precisam ser analisados, combinados com as definições de etapas que podem ser executadas. Você está basicamente escrevendo scripts gherkin dentro do gherkin (eles estão ocultos nas definições de etapas JS, mas esse é um detalhe que torna ainda pior de um POV de manutenção).

@aslakhellesoy @jbpros A ideia é que as etapas sejam do tipo algébrico e combinável, o que não é.

@jbpros , vou usar sua solução já que estou acostumado a programar em Java e não me preocupar com promessas :)

Alguém já criou uma extensão para o pepino para definir etapas em termos de outras etapas? Algo como

Understand I log in to {site} as {user}, {pass}
    I visit {site}
    I log in as {user}, {pass}

Estou ponderando se esta é uma extensão útil para descrever melhor as longas jornadas do usuário pelo sistema e preferiria trabalhar com qualquer técnica anterior.

Este tópico foi bloqueado automaticamente, pois não houve nenhuma atividade recente depois que ele foi fechado. Por favor, abra um novo problema para bugs relacionados.

Esta página foi útil?
0 / 5 - 0 avaliações