Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Scenario Outlines / Examples #75

Closed
wants to merge 11 commits into from
@hairyhum

Hello. I made some work on scenario outline and examples. Maybe it can be useful

@jbpros
Owner

Thanks @hairyhum for the pull request. This is on my TODO list.

@jbpros
Owner

This is a potential resolution for #10.

@darrhiggs

May you let me know an estimate time to inclusion? @jbpros

@sheebz

+1

@darrhiggs

@jbpros what is the hold up with this?

@mattwynne
Owner

@darrhiggs what are you, his project manager?

@jbpros
Owner

@darrhiggs I've been waiting for some traction from users on this particular feature before considering its implementation. It should land in 0.3.1. ETA unknown. As with all core features, it has to be carefully tested through cucumber-tck. .

@darrhiggs

@jbpros
Ok, thanks for the response.
As I don't follow you on twitter so I wasn't able to raise my hand a few months back when you did a poll to gauge interest

@mattwynne
No, why?

@sivad77

+1 here.

@mummybot

+1 :)

@jbpros
Owner

Lots of plus ones!

Would you guys mind describing some use cases for scenario outlines/examples (some example features would be the best). I'm picky on this but I rarely see good uses of them. Please, convince me it's not as bad as I think :grin:

BTW, be reassured it will eventually land in cukejs. It's quite on top of the priorities, in fact.

@darrhiggs

@jbpros let me know if I can do anything to help this along, or far that matter any part of this project. Currently I am using tags to associate the expanded versions of these with the Scenario Outline versions that are currently sat idle in a folder.

@jbpros
Owner

@aslakhellesoy totally.

@darrhiggs thank you! I know I'm a complete foreigner to the domain of that scenario but could you tell me what is the rationale behind those numbers? They seem to come out of the blue and I'd have to do some reverse maths to understand the business rules.

@darrhiggs

@jbpros I have sent you an email.

@sivad77

hey mate, i find scenarios outlines useful to eliminate repetition in my scenarios. we can easily refactor the repetition into a table where the information is communicated concisely. i understand some may say scenario outlines are a code smell however i use cucumber for integration testing (full system stack) where i may have many happy paths which can be tested easily using a table! thanks for the awesome work!!!!

@jbpros
Owner

@darrhiggs thanks!

@sivad77 Thank you for your insights. In a way, that's the argument I'm afraid of :) The DRY principle is not terribly important in Gherkin features, imo. Repetition should indeed be as rare as possible but it should not hinder communication. The funny thing is, because of Scenario Outlines, there are many unwanted repetitions! Sometimes, the exact same behaviour is described through scenario examples, only with different parameters that happen to be implementation details.

Consider this:

Scenario Outline: shipping fees
  When I buy <amount> items
  Then the shipping fees are <shipping_fee> dollars

  Examples:
    | amount | shipping_fee |
    |      1 |           15 |
    |      2 |           10 |
    |      3 |            5 |
    |      4 |            0 |
    |      5 |            0 |
    |      6 |            0 |

You might think this is a stupid example, but I've seen such things before.

As you can see, we are actually running 6 scenarios here, when two would have sufficed:

Scenario: regular shipping fees
  When I buy less than 4 items
  Then shipping fees are applied

Scenario: free shipping fees
  When I buy 4 items or more
  Then the shipping is free

Not only did we reduce the feature suite by 4 scenarios, we also expressed the business rules more clearly (and it's less boring to read).

You might argue that we lose some details related to the acceptance criteria. That's correct in a way, but don't forget we are writing unit tests that should exhaustively describe the little details of the business process. Also, the step definitions should still run reliable assertions.

@JRedgrave

@jbpros I understand that having two scenarios makes sense in your example however, i have to agree with @sivad77 . I too need to test more complex scenarios where repeated scenarios currently is the only way of solving this.

If in your example above it wasn't as straightforward as a one to one mapping between the amount and the fee, say for example the fees could be adjusted further by being in a specific loyalty scheme / discount club.

Scenario Outline: shipping fees
  When I buy <amount> items
  And I am a member of the <discount> group
  Then the shipping fees are <shipping_fee> dollars

Examples:
    | amount | discount | shipping_fee  |
    |      1     |  premier  |  15   |
    |      1     |  standard  |  10   |
    |      1     |  staff  |  5   |
    |      4     |   premier  |  4   |
    |      4     |   standard   | 2 |
    |      4     |   staff      |  0  |

If there were more factors that adjusted the fee this would mean more and more scenarios rather than an outline with the examples listed.

@darrhiggs

@jbpros to expand on @JRedgrave's example you could show what the discounts mean more clearly using multiple tables:

Scenario Outline: shipping fees

  Users that buy 4 or more items they will get a ten dollar discount on shipping.
  Also a user that belongs to a discount group will receive a further monetary discount.

  When I buy <amount> items
  And I am a member of the <discount> group
  Then the shipping fees are <shipping_fee> dollars

  Examples:  no discount group, but qty discount.
  |    amount    |    discount    |    shipping_fee    |
  |    1    |    none    |    20    |
  |    4    |    none    |    10    |

  Examples: premier discounts are $5
  |    amount    |    discount    |    shipping_fee    |
  |    1    |    premier    |    15    |
  |    4    |    premier    |     5    |

  Examples: staff discounts are $10
  |    amount    |    discount    |    shipping_fee    |
  |    1    |    staff    |    10    |
  |    4    |    staff    |    0    |

Now this is rather simple, but would this not have been 6 scenarios otherwise? with hidden complexity of the qty discount if it was not repeated to the user in the last four scenarios? To me it allows the developer to be more concise and expressive.

@jbpros
Owner

@JRedgrave @darrhiggs Let's say you are my customer and want to add those two discount groups to the system. This is how the existing feature could end up:

Scenario: regular shipping fees
  When I buy less than 4 items
  Then shipping fees are applied

Scenario: free shipping fees
  When I buy 4 items or more
  Then the shipping is free

Scenario: premier discount on shipping fees
  Given I am a member of the premier discount group
  When I buy less than 4 items
  Then I get the premier discount on the shipping fees

Scenario: staff discount on shipping fees
  Given I am a member of the staff discount group
  When I buy less than 4 items
  Then I get the staff discount on the shipping fees

This declarative style has some advantages:

  1. As stated above, it does express the business rules in a much clearer fashion, in my opinion (this is definitely a subjective concern though).

  2. The $5 and $10 discounts are just configuration values. They are implementation details. Let's say the system is running live for more than 6 months and suddenly you - the customer - decide to change the staff discount from $10 to $12.

    It does not alter the behaviour of the system at all, what's in these scenarios would still hold true. It's just a matter of updating a value somewhere in the code (constant)/configuration. The scenarios don't need any changes, only the corresponding configuration value/constant in the corresponding step definition/Cucumber world.

    You may even deploy several instances of the application with different discount values for the same group, the scenarios would still be valid. The behaviour is common, the configuration isn't anymore.

    When scenarios evolve a lot (I've been working on a startup project recently where the behaviour was changing regularly), you have to go through many scenarios and check they are still valid. This is a daunting task when you have to read numbers and infer business rules stashed behind those figures. When the business logic is expressed in such an implementation detail-less way, it makes things easier.

    To be completely consistent with my claims, the value "4" should not appear in the scenarios neither.

    In short: this is a kind of decoupling.

  3. The examples you suggest intermix several business rules. Both the "no shipping fees for more than 4" and the "discount groups" are amalgamated together, making them hard to isolate, comprehend and maintain.

    I think, wherever possible, a scenario should express one and only one concern/business rule. In some rare cases, this is not possible though.

    In short: separation of concerns.

  4. No need of relying on external documentation. In your example, the actual behaviour is not described in the scenario steps but rather in the scenario outline description. This is, in fact, outside of the automated specification. This, like any classic type of documentation, might get out of date without anyone noticing (Gojko Adzik calls Cucumber features "living documentation", the only dead parts of a Gherkin file are the scenario/feature descriptions and comments).

    Basically, the validity of the most important explicit piece of information in your Cucumber feature is not guaranteed. Aren't we missing the point here?

  5. Again, only 4 scenarios instead of 6, each one expressing one single business rule. My (fast) unit tests are there to make sure all edge cases are ok.

Scenario outlines and examples really push many of us into thinking in terms of state instead of behaviour (like in Behaviour-Driven Development). It's quite a difficult exercise to make that mind shift because you have to force yourself into understanding the underlying business rules. All. The. Time.

But it does help! It helps expressing the real business logic and the expected outcomes: you don't care if it's a 4 or a 6, you want to know if you get that staff discount, whatever it is today. And by you I mean you the developer and also everyone else involved. We, developers, are not weird animals, our tendencies of focusing on state is natural and shared with other human beings. Customers and stakeholders do that all the time too.

Therefore, asking why? (e.g. "why 4, could it be 6 instead?") all the time will also help them. They will understand what, how and why the system behaves a certain way, question it and tell you if it's actually wrong, removing uncertainty and assumptions in everybody's heads.

Now, I'm not saying this is the way everyone should write features (wait... yes, they should :grin:). This is based on my personal experience writing a lot of scenarios for OSS, customer and private projects.

As I said, Scenario Outlines and Examples will eventually land in Cucumber.js. I promise.

P.S.: This really reminds me of the old "mocks are good vs. mocks suck" debate: state vs. behaviour!

@sivad77

@jbpros i have to say, you have an excellent argument! i agree with you 100% (in an ideal world) however, writing excellent features does not come easily to me (i am new to cucumber). i prefer the pragmatic route, get most of my system under test (using scenario outlines). with time i will get better at writing these things and eventually my features will read really nice...

@jbpros
Owner

@sivad77 I understand your point of view. Writing scenarios in such a way is not easy task at first and it takes time to learn it. But in my experience, it has been a great way to suppress many assumptions and understand better the business domains; this really fits within the deliberate discovery process as described by Dan North.

Also, keep in mind this really is about capturing specifications and driving the development in a automated fashion. The testing aspect of it is only a (very useful) side-effect, in my opinion.

@mattwynne
Owner

Great arguments @jbpros, this needs to go into a blog post, or better still onto a page on the new cukes.info docs site!

Nevertheless, there are definitely times when a table is the best way to communicate a set of examples. When the rules are complex, you need several real examples written down to make sure that everyone is clear what the expected behaviour is. I find that as your domain learning progresses, you can often distill these into more declarative style scenarios, but it's not always the case.

In the end, Cucumber is a communication tool. Pushing too much detail down into step definitions can sometimes make scenarios less communicative. It all depends on the type of reader you have: a technically-inclinde reader (e.g. a financial trader) will want more detail while less technically minded people tend to prefer a declarative style. I'm glad that Gherkin supports both.

@jbpros
Owner

@mattwynne Agreed! This kind of discussion is often concluded with something along the lines of "use whatever (tool/method/machinery) that works for you".

Therefore:

Use scenario outlines/examples if it works for you and your team. My advice would be: don't forget to question it from time to time, maybe there's a better way.

@jmonschke

@jbpros I agree that many times, it is not advisable to use the scenario outlines, but there are situations where it makes total sense to do so, and it shortens the number of lines in the feature files, as it removes much copy and paste coding.

Our application is a multi-homed and multiple-design web-platform that implements the same basic pages across multiple front-end designs that each have overridden the base styling to differentiate the designs. We are currently using SpecFlow and Selenium in .Net to automate the testing across the multiple designs with Scenario Outlines, allowing us to write the scenario outline once, and then list the designs that support the functionality being tested in the Examples.

From what I have seen, the outlines allow us to more-clearly and concisely define the scenarios under test, and when there is a change that needs to be made to the steps of the test, we are able to easily adjust those in one place instead of once for every design.

I am hopeful that the Scenario Outlines will be implemented soon into Cucumber-js so that we will be able to move our Selenium testing to Cucumber-js.

@jbpros
Owner

@jmonschke thanks for sharing your experience, that's helpful and motivating.

@JRedgrave

@jpbros I wondered if there was any progress in regards to the support of scenario outlines?

@jbpros
Owner

@JRedgrave not really. I had a quick spike at the testing aspect of it but that's all.

@mattwynne are you still interested in pairing with me on this?

@mattwynne
Owner
@jbpros
Owner

@mattwynne that's an interesting idea (:

@manuels

Are there any news? Scenario outlines would really be great for testing form validations
(e.g. http://stackoverflow.com/questions/5920017/should-all-validation-rules-be-tested-within-a-cucumber-feature)

@jbpros
Owner

Ok folks. I think it's time to take care of this once and for all. ETA: May 20.

@manuels

Great, thanks @jbpros!

@nik-kor

waiting passionately)

@jbpros
Owner

I :heart: passionate people :D

@JRedgrave

Has there been any progress on scenario outlines?

@neilD2

+1

@jbpros
Owner

Yep, I made some progress. Still working on it :)

@JRedgrave

Julien , any idea when we are likely to see this?

@aslakhellesoy

@jbpros: You could consider holding off on this until gherkin3.js is done - it precompiles scenario outlines (and background) into regular scenarios, making the cucumber code a lot simpler.

gherkin3 is still in early stages, but the js implementation is the one that has made the most progress (over java/c/ruby).

If you want to play with it, check out the gherkin branch in the bool repo where it currently lives.

@jbpros
Owner

Thanks for the heads up Aslak. I'm in the middle of this work but I'll have a look at gherkin 3 then.

This is the most requested feature atm. Holding it off for some more months could annoy (to say the least) some people ;)

Due to cucumber.js's decoupled architecture, moving to gherkin3 shouldn't be of a big issue, hopefully. It means we can implement outlines/examples the old way for now (the same way I implemented backgrounds: as simple macros to prepend/append steps/scenarios) and move to gherkin3 when it's ready.

@JRedgrave

Yes please don't hold off on this any longer, I have been waiting patiently for several months now and i am sure i am not alone :)

@aslakhellesoy

Gherkin3 is several months away, so don't let it hold up this PR. As you say we can swap it out later.

@toolness

Hey, I just bought The Cucumber Book and am attempting to go through its second chapter with cucumber-js instead of the Ruby version. Unfortunately, section 2.8 (page 22) involves converting their scenario into a scenario outline, which fails on cucumber-js and points me here. While I really appreciate it pointing me here (instead of exploding in confusion), it'd be really great if the feature worked.

TL;DR: I guess this is just another +1. :)

@maciejblinkbox

@jbpros I think we can still use scenario outlines here:

So instead of having the following:

Scenario: premier discount on shipping fees
  Given I am a member of the premier discount group
  When I buy less than 4 items
  Then I get the premier discount on the shipping fees

Scenario: staff discount on shipping fees
  Given I am a member of the staff discount group
  When I buy less than 4 items
  Then I get the staff discount on the shipping fees

We could have one scenario outline:

Scenario Outline: <GROUP> discount on shipping fees
  Given I am a member of the <GROUP> discount group
  When I buy less than 4 items
  Then I get the <GROUP> discount on the shipping fees

Examples:
  | GROUP   |
  | premier |
  | staff   |
@JRedgrave

Julien, are we any closer to getting scenario outlines in place?

@niclashoyer

@jbpros @aslakhellesoy @hairyhum
I also bought the cucumber book as a guidance for writing features. Now that I have my first scenarios (and scenario outlines) in place I wondered about failing builds. Also giving :thumbsup: for not holding this any longer, because more and more people might read the book and fail to implement the features with JavaScript which leads to frustration.

@niclashoyer niclashoyer referenced this pull request in semfact/garret
Merged

Feature for Typed Middlewares #42

@christian-bromann

@jbpros I read this thread and see advantages and disadvantages on both sides. In my opinion the user should decide if he wants to use scenario outlines or not. I'ld appreciate this feature!

Anyway, thanks for your great work!

@mattwynne
Owner

Folks, all of you sending +1s, are you thinking this is going to help Julien to code faster?

Why not send him a Gittip instead?

@the-simian

I would really love to see Scenario Outlines implemented as a feature in cucumber.js Unfortunately this is a non-starter for my shop until that happens. I hope things are going well, and this will come soon.

@manuels

a.k.a. I wanna make money, so spend your weekend writing code for me!

@Fandekasp

Same here, was really excited when I saw that RTD was integrating cucumber, but seeing that Scenario outlines and examples are not yet implemented (after 2 years), I'll skip it.

@vantreeseba

So, I've got this working again on my local fork.

The question I have about this implementation is...

It builds steps individually and runs them outside of the scenario context (i.e. instead of building a scenario per example row, it builds the steps themselves to run).

I know that @jbpros is working on an implementation of this, or was, so what I was wondering was if the implementation is changed to produce entire scenarios, renaming them based on the scenario outline, would this make a more acceptable implementation of this feature?

For example:

Feature: testing scenarios
        Background:
          Given a background step

        Scenario Outline: outline
          When a <some> step
          Then i get <result>
        Examples:
          | some    | result  |
          | passing | passed  |
          | failing | skipped |

is not producing multiple scenarios, but instead only generating many steps like ..

when a passing step, then i get passed,
when a failing step, then i get skipped.

Instead, I am proposing that internally it would look more like

Feature: testing scenarios
        Background:
          Given a background step

        Scenario: outline #1
          When a passing step
          Then i get passed

        Scenario: outline #2
          When a failing step
          Then i get skipped

This would allow all of the formatters and other tools to continue using the same data structures without needing to account for outlines in specific.

I would appreciate any feedback on this.

Thanks!

As a side note, I don't know how the ruby implementation deals with outlines, so I'm going to do some digging into that as well.

@jbpros
Owner

@vantreeseba thanks for sharing your thoughts. Your proposed solution is almost exactly what I'd like to end up with. Scenario outline examples yielding scenarios is the cleanest solution, imo. Actually, the gherkin syntax for scenario outlines and examples itself has always looked as a kind of macro set to generate scenarios on the fly, to me.

The only thing I wouldn't do is to change the generated scenario names as I don't want it to be some arbitrary string end users have no control over.

Based on your example, here is the resulting feature (and this would be the output of the pretty formatter):

Feature: testing scenarios
  Background:
    Given a background step

  Scenario: outline
    When a passing step
    Then i get passed

  Scenario: outline
    When a failing step
    Then i get skipped

The visited AST objects would still carry the original outline/example data, meaning we can still use those information within XML/JSON/whatever formatters/listeners.

@mattwynne
Owner

Bear in mind that you could have multiple examples tables, and that examples tables can have names.

In Cucumber Ruby 2.0, we're generating names for the test cases based on the names of the outline, examples table and the row.

See https://github.com/cucumber/cucumber-ruby-core/blob/master/spec/cucumber/core/test/case_spec.rb#L77-L110 for details.

I suggest you follow the same principle.

@the-simian

@vantreeseba and I are working on this,
@jbpros Thank you for that clarification, and we are in complete agreement, though I think that we will follow the spec proposed in cucumber ruby 2.0 by @mattwynne. We are looking at that code now and will work on that today.

@jbpros
Owner

@JesseHarlin @vantreeseba thank you chaps. I'm looking forward to seeing your work!

@the-simian

@jbpros @mattwynne just a quick update:

@vantreeseba and I have had some success with this yesterday and today. In addition to getting Scenario Outlines working, we also worked in the snippet_builder to make sure the suggested step definitions look correct. We're doing some ex post facto cleanup before we submit the pull request. Thanks for your help, thusfar.

@vantreeseba vantreeseba referenced this pull request
Closed

Scenario outlines redux #155

@jfstephe

Hi all,
It's great that so much effort is being put into this. Scenario outlines are a big deal for us and I'm wondering roughly when (a day/a week/a month/a year) it is expected that this feature will be merged in? Knowing this would give me something to placate the management.

I'm also confused by #155. Do this and #155 do the same thing exactly? Is there some coordination so that multiple people aren't doing the same work? Honestly, I don't much care - I just would like the functionality! :-).

Please don't take this the wrong way and please keep up your great efforts!
Thanks,
John

@the-simian

@jfstephe they achieve the same goal of implementing scenario outlines, but do not achieve that goal the exact same way. #155 is the more recent fix, and is linked because it also would resolve this issue when it is pulled in. I wouldn't worry about duplicate work. The project leads have been commenting on the work thusfar, and this thread - the one we are posting in is many years old anyways.

Go to #155 and start there to further discuss or review this feature, as it is the most up to date.

@jbpros jbpros closed this pull request from a commit
@vantreeseba vantreeseba Add support for scenario outlines and examples (close #155)
Also closes #10 and closes #75.

Squashed commit of the following:

commit aeb2630
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 24 17:26:14 2014 -0600

    fixing spec for assembler

commit 4f76479
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 24 17:25:09 2014 -0600

    removing duplicated step insertion

commit e7e2198
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Tue Feb 18 17:07:41 2014 -0600

    added dependency to underscore.string, changed snippet builder to camelize outline variables when put into arguments list

commit 66b9f7d
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 17 09:43:11 2014 -0600

    adding error message when a user tries to use examples outside of a scenario outline

commit 04b984d
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 17 09:32:09 2014 -0600

    updating version of connect in package.json to 2.13.0

commit a038071
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Tue Feb 11 14:33:28 2014 -0600

    fixing some issues with cli step / json formatter feature on windows

commit bc7b840
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 10 21:30:06 2014 -0600

    removing step_definition_snippet_steps that were not implemented

commit d8efad6
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 10 21:25:29 2014 -0600

    cleaning up travis to remove trying to install bundler, actually implemented scenario outline steps, implemented snipper builder steps for example outline snippets

commit 60b437c
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 10 11:08:51 2014 -0600

    trying to get bundler installed globally for rvm.

commit 28224ef
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 10 10:32:19 2014 -0600

    fixing specs on payloadType

commit 1cd669c
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 10 10:30:06 2014 -0600

    changing payload_type to payloadType

commit aa471b3
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 10 10:24:18 2014 -0600

    making buildScenarios 'polymorphic'

commit 35a5462
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 10 10:14:04 2014 -0600

    renaming scenarios parts of feature to featureElements

commit 28ce292
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Mon Feb 10 10:01:19 2014 -0600

    changing name of stored scenarios in feature to feature elements

commit 65039bd
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Sat Feb 8 17:40:16 2014 -0600

    apparently sudo install is wrong on travis gems :P

commit f4803c6
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Sat Feb 8 17:37:39 2014 -0600

    adding bundler install step to travis.yml

commit 4a39f81
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Sat Feb 8 17:34:45 2014 -0600

    removing stupid .orig files

commit ed2812d
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Sat Feb 8 17:28:36 2014 -0600

    adding more assembler tests

commit 17715a5
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Sat Feb 8 16:57:04 2014 -0600

    cleaning up steps a little, cleaning up assembler functions for scenario_outlines

commit d10585d
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Sat Feb 8 16:43:07 2014 -0600

    adding specs for outline_step and changes to step

commit afdf537
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Sat Feb 8 16:36:11 2014 -0600

    making current tests pass

commit 8359996
Author: unknown <jharlin@NormanDev2.telogical.com>
Date:   Fri Feb 7 19:06:06 2014 -0600

    adding back steps

commit 8d4439e
Author: unknown <jharlin@NormanDev2.telogical.com>
Date:   Fri Feb 7 19:04:59 2014 -0600

    Added better suggestion output for missing scenario outline steps

commit 3ba5088
Author: unknown <jharlin@NormanDev2.telogical.com>
Date:   Fri Feb 7 18:06:36 2014 -0600

    basic scenario outline functionality completed

commit f3659a3
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Fri Feb 7 09:29:28 2014 -0600

    more specs on scenario outline

commit 5168174
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Thu Feb 6 22:01:45 2014 -0600

    started on scenario_outline specs, and finished example_specs

commit f8b8d35
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Thu Feb 6 20:24:58 2014 -0600

    got all scenario_outline.feature passing

commit 25269b7
Author: unknown <jharlin@NormanDev2.telogical.com>
Date:   Thu Feb 6 16:12:32 2014 -0600

    trying to get to the bottom of stack overflow error

commit 323500a
Author: unknown <jharlin@NormanDev2.telogical.com>
Date:   Thu Feb 6 16:02:36 2014 -0600

    Fixing jasmine specs for ast_tree_walker visiting scenarios

commit d993e88
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Thu Feb 6 15:22:55 2014 -0600

    commenting out failing features

commit 084da1a
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Thu Feb 6 14:36:57 2014 -0600

    re-adding scenario outline feature, cleaning up some steps, cleanin up scenario outline and data table

commit 77d4caf
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Wed Feb 5 15:55:38 2014 -0600

    trying to get scenario outlines working

commit b013d39
Merge: 1967b21 b5bd31a
Author: Ben Van Treese <vantreeseba@gmail.com>
Date:   Wed Feb 5 15:21:39 2014 -0600

    trying to merge in master

commit 1967b21
Author: Fedotov Daniil <hairyhum@gmail.com>
Date:   Wed Jun 27 15:08:07 2012 +0400

    [+] Prepared for pull request

commit 09c25ee
Author: Fedotov Daniil <hairyhum@gmail.com>
Date:   Wed Jun 27 15:01:45 2012 +0400

    [+] Fixing index

commit 7699725
Author: Fedotov Daniil <hairyhum@gmail.com>
Date:   Sat Jun 9 17:06:49 2012 +0400

    [*] Added scenario outline test

commit d940ac2
Author: Fedotov Daniil <hairyhum@gmail.com>
Date:   Sat Jun 9 15:25:49 2012 +0400

    [+] added cucumber tests for scenarios and outlines
    [*] Fixed data table example mapping

commit 9965ff9
Author: Fedotov Daniil <fedotov.danil@gmail.com>
Date:   Fri Jun 8 22:20:35 2012 +0400

    [*] Fixing some collection calls

commit fc08ef8
Author: Fedotov Daniil <hairyhum@gmail.com>
Date:   Mon Jun 4 18:12:10 2012 +0400

    [*] witnessNewScenario every example row

commit d563a1d
Author: Fedotov Daniil <hairyhum@gmail.com>
Date:   Fri Jun 1 15:23:22 2012 +0400

    [*] Changed example row reporting

commit f8b27ea
Author: Fedotov Daniil <hairyhum@gmail.com>
Date:   Wed May 30 19:16:16 2012 +0400

    outline fix

commit db6d9c5
Author: Fedotov Daniil <hairyhum@gmail.com>
Date:   Wed May 30 15:19:43 2012 +0400

    [*] Scenarios and outlines events

commit e437a70
Author: Fedotov Daniil <hairyhum@gmail.com>
Date:   Wed May 30 12:12:06 2012 +0400

    [*] Prepared UIA version

commit 016df31
Author: Fedotov Daniil <fedotov.danil@gmail.com>
Date:   Mon May 28 01:00:35 2012 +0400

    [+] Added step definitions and examples
c2a9916
@jbpros jbpros closed this in c2a9916
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 27, 2012
  1. @fedotov-danil
Commits on May 30, 2012
  1. @hairyhum

    [*] Prepared UIA version

    hairyhum authored
  2. @hairyhum
  3. @hairyhum

    outline fix

    hairyhum authored
Commits on Jun 1, 2012
  1. @hairyhum
Commits on Jun 4, 2012
  1. @hairyhum
Commits on Jun 8, 2012
  1. @fedotov-danil
Commits on Jun 9, 2012
  1. @hairyhum

    [+] added cucumber tests for scenarios and outlines

    hairyhum authored
    [*] Fixed data table example mapping
  2. @hairyhum
Commits on Jun 27, 2012
  1. @hairyhum

    [+] Fixing index

    hairyhum authored
  2. @hairyhum

    [+] Prepared for pull request

    hairyhum authored
This page is out of date. Refresh to see the latest.
View
70 features/scenario_outlines.feature
@@ -0,0 +1,70 @@
+Feature: Scenario Outlines and Examples
+
+ Scenario: Basic outline
+ Given the following feature:
+ """
+ Feature: testing scenarios
+ Background:
+ Given a background step
+
+ Scenario Outline: outline
+ When a <some> step
+ Then i get <result>
+ Examples:
+ | some | result |
+ | passing | passed |
+ | failing | skipped |
+ """
+ And the step "a background step" has a passing mapping
+ And the step "a passing step" has a passing mapping
+ And the step "a failing step" has a failing mapping
+ And the step "i get passed" has a passing mapping
+ And the step "i get skipped" has a passing mapping
+ When Cucumber runs the feature
+ Then the scenario called "outline" is reported as failing
+ And the step "a background step" passes
+ And the step "a passing step" passes
+ And the step "a failing step" passes
+ And the step "i get passed" passes
+ And the step "i get skipped" is skipped
+
+ Scenario: Outline with table
+ Given the following feature:
+ """
+ Feature: testing scenarios
+ Scenario Outline: outline
+ When a table step:
+ | first | second |
+ | <first> | <second> |
+ Examples:
+ | first | second |
+ | 1 | 2 |
+ """
+ And the step "a table step:" has a passing mapping that receives a data table
+ When Cucumber runs the feature
+ Then the received data table array equals the following:
+ """
+ [["first","second"],["1","2"]]
+ """
+
+ Scenario: Outline with doc string
+ Given the following feature:
+ """
+ Feature: testing scenarios
+ Scenario Outline: outline
+ When a doc sting step:
+ \"\"\"
+ I am doc string in <example> example
+ And there are <string> string
+ \"\"\"
+ Examples:
+ | example | string |
+ | first | some |
+ """
+ And the step "a doc sting step:" has a passing mapping that receives a doc string
+ When Cucumber runs the feature
+ Then the received doc string equals the following:
+ """
+ I am doc string in first example
+ And there are some string
+ """
View
13 features/step_definitions/cucumber_steps.js
@@ -128,6 +128,14 @@ setTimeout(callback.pending, 10);\
callback();
});
+ Given(/^the step "([^"]*)" has a passing mapping that receives a doc string$/, function(stepName, callback) {
+ this.stepDefinitions += "Given(/^" + stepName + "$/, function(docString, callback) {\
+ world.docString = docString;\
+ callback();\
+});";
+ callback();
+ });
+
Given(/^the following data table in a step:$/, function(dataTable, callback) {
this.featureSource += "Feature:\n";
this.featureSource += " Scenario:\n";
@@ -315,6 +323,11 @@ callback();\
callback();
});
+ Then(/^the received doc string equals the following:$/, function(docString, callback) {
+ this.assertEqual(docString, World.mostRecentInstance.docString);
+ callback();
+ });
+
this.Then(/^the explicit World object function should have been called$/, function(callback) {
this.assertTrue(this.explicitWorldFunctionCalled);
callback();
View
2  lib/cucumber/ast.js
@@ -7,6 +7,8 @@ Ast.Feature = require('./ast/feature');
Ast.Features = require('./ast/features');
Ast.Filter = require('./ast/filter');
Ast.Scenario = require('./ast/scenario');
+Ast.ScenarioOutline = require('./ast/scenario_outline');
+Ast.Examples = require('./ast/examples');
Ast.Step = require('./ast/step');
Ast.Tag = require('./ast/tag');
module.exports = Ast;
View
7 lib/cucumber/ast/assembler.js
@@ -1,4 +1,4 @@
-var Assembler = function(features, filter) {
+var Assembler = function (features, filter) {
var currentFeature, currentScenarioOrBackground, currentStep;
var stashedTags = [];
@@ -81,6 +81,11 @@ var Assembler = function(features, filter) {
currentFeature.addScenario(scenario);
}
},
+ insertExamples: function insertExamples(examples) {
+ var currentScenarioOrBackground = self.getCurrentScenarioOrBackground();
+ currentScenarioOrBackground.setExamples(examples);
+ self.setCurrentStep(examples);
+ },
insertStep: function insertStep(step) {
self.setCurrentStep(step);
View
10 lib/cucumber/ast/data_table.js
@@ -12,8 +12,16 @@ var DataTable = function() {
return self;
},
+ getRows: function getRows(){
+ var newRows = Cucumber.Type.Collection();
+ rows.syncForEach(function(row){
+ newRows.add(row);
+ });
+ return newRows;
+ },
+
raw: function raw() {
- rawRows = [];
+ var rawRows = [];
rows.syncForEach(function(row) {
var rawRow = row.raw();
rawRows.push(rawRow);
View
4 lib/cucumber/ast/data_table/row.js
@@ -4,7 +4,11 @@ var Row = function(cells, line) {
self = {
raw: function raw() {
return cells;
+ },
+ getLine: function getLine(){
+ return line;
}
+
};
return self;
}
View
49 lib/cucumber/ast/examples.js
@@ -0,0 +1,49 @@
+var Examples = function (keyword, name, description, line) {
+ var Cucumber = require('../../cucumber'),
+ dataTable,
+ self;
+ return self = {
+ getKeyword: function getKeyword() {
+ return keyword;
+ },
+
+ getName: function getName() {
+ return name;
+ },
+
+ getDescription: function getKeyword() {
+ return keyword;
+ },
+
+ getLine: function getLine() {
+ return line;
+ },
+
+ getDataTable: function getDataTable() {
+ return dataTable;
+ },
+
+ hasDataTable: function hasDataTable() {
+ return !!dataTable;
+ },
+
+ attachDataTable: function attachDataTable(_dataTable) {
+ dataTable = _dataTable;
+ },
+
+ attachDataTableRow: function attachDataTableRow(row) {
+ self.ensureDataTableIsAttached();
+ var dataTable = self.getDataTable();
+ dataTable.attachRow(row);
+ },
+
+ ensureDataTableIsAttached: function ensureDataTableIsAttached() {
+ var dataTable = self.getDataTable();
+ if (!dataTable) {
+ dataTable = Cucumber.Ast.DataTable();
+ self.attachDataTable(dataTable);
+ }
+ }
+ }
+};
+module.exports = Examples;
View
5 lib/cucumber/ast/scenario.js
@@ -6,6 +6,7 @@ var Scenario = function(keyword, name, description, line) {
var tags = [];
var self = {
+ payload_type: 'scenario',
setBackground: function setBackground(newBackground) {
background = newBackground;
},
@@ -40,6 +41,10 @@ var Scenario = function(keyword, name, description, line) {
return steps.getLast();
},
+ getSteps: function getSteps(){
+ return steps;
+ },
+
addTags: function setTags(newTags) {
tags = tags.concat(newTags);
},
View
88 lib/cucumber/ast/scenario_outline.js
@@ -0,0 +1,88 @@
+var ScenarioOutline = function (keyword, name, description, line) {
+ var Cucumber = require('../../cucumber'),
+ self = Cucumber.Ast.Scenario(keyword, name, description, line),
+ examples;
+ self.payload_type = 'scenarioOutline';
+ self.setExamples = function (newExamples) {
+ examples = newExamples;
+ };
+ self.getExamples = function () {
+ return examples;
+ };
+ function applyExampleRow(example, steps) {
+ return steps.syncMap(function (outline) {
+ var name = outline.getName(),
+ table = Cucumber.Ast.DataTable(),
+ rows = [],
+ hasDocString = outline.hasDocString(),
+ hasDataTable = outline.hasDataTable(),
+ oldDocString = hasDocString ? outline.getDocString() : null,
+ docString = hasDocString ? oldDocString.getContents() : null,
+ hashKey;
+ if (hasDataTable){
+ rows = [];
+ outline.getDataTable().getRows().syncForEach(function(row){
+ rows.push(
+ { line: row.getLine(), cells: JSON.stringify(row.raw()) }
+ );
+ });
+
+ }
+ for (hashKey in example) {
+ if (Object.prototype.hasOwnProperty.call(example, hashKey)) {
+ name = name.replace('<' + hashKey + '>', example[hashKey]);
+ if (hasDataTable) {
+ rows = rows.map(function(row){
+ return {line:row.line, cells:row.cells.replace('<' + hashKey + '>', example[hashKey])};
+ });
+ }
+ if (hasDocString) {
+ docString = docString.replace('<' + hashKey + '>', example[hashKey]);
+ }
+ }
+ }
+ var step = Cucumber.Ast.Step(outline.getKeyword(), name, outline.getLine());
+ if (hasDataTable) {
+ rows.forEach(function(row){
+ table.attachRow( Cucumber.Ast.DataTable.Row( JSON.parse(row.cells), row.line) );
+ });
+ step.attachDataTable(table);
+ }
+ if (hasDocString) {
+ step.attachDocString( Cucumber.Ast.DocString(oldDocString.getContentType(), docString, oldDocString.getLine()));
+ }
+ return step;
+ });
+ }
+ self.acceptVisitor = function (visitor, callback) {
+ var rows = examples.getDataTable().getRows(),
+ first_row = rows.shift().raw();
+ rows.syncForEach(function(row, index){
+ var length = first_row.length,
+ i;
+ row.example = {};
+ row.id = index.toString();
+ for (i = 0; i < length; i++){
+ row.example[first_row[i]] = row.raw()[i];
+ }
+ });
+
+ rows.forEach(function (row, iterate){
+ self.instructVisitorToVisitRowSteps(visitor, row, iterate);
+ },callback)
+ };
+ self.instructVisitorToVisitRowSteps = function (visitor, row, callback) {
+ visitor.visitRow(row, self, callback);
+
+ };
+ self.visitRowSteps = function (visitor, row, callback) {
+ self.instructVisitorToVisitBackgroundSteps(visitor, function () {
+ var newSteps = self.applyExampleRow(row.example, self.getSteps());
+ self.instructVisitorToVisitSteps(visitor, newSteps, callback);
+ });
+ };
+
+ return self;
+};
+module.exports = ScenarioOutline;
+
View
36 lib/cucumber/listener/progress_formatter.js
@@ -22,6 +22,24 @@ var ProgressFormatter = function(options) {
options = {};
if (options['logToConsole'] == undefined)
options['logToConsole'] = true;
+
+ function handleAfterScenarioEvent(payload){
+ return function(event, callback){
+ if (self.isCurrentScenarioFailing()) {
+ var scenario = event.getPayloadItem(payload);
+ self.storeFailedScenario(scenario);
+ self.witnessFailedScenario();
+ } else if (self.isCurrentScenarioUndefined()) {
+ self.witnessUndefinedScenario();
+ } else if (self.isCurrentScenarioPending()) {
+ self.witnessPendingScenario();
+ } else {
+ self.witnessPassedScenario();
+ }
+ callback();
+ }
+ }
+
var self = {
log: function log(string) {
logs += string;
@@ -67,6 +85,9 @@ var ProgressFormatter = function(options) {
callback();
},
+ handleBeforeScenarioOutlineEvent: this.handleBeforeScenarioEvent,
+ handleAfterScenarioOutlineEvent: handleAfterScenarioEvent('scenarioOutline'),
+
handleStepResultEvent: function handleStepResult(event, callback) {
var stepResult = event.getPayloadItem('stepResult');
if (stepResult.isSuccessful())
@@ -118,20 +139,7 @@ var ProgressFormatter = function(options) {
callback();
},
- handleAfterScenarioEvent: function handleAfterScenarioEvent(event, callback) {
- if (self.isCurrentScenarioFailing()) {
- var scenario = event.getPayloadItem('scenario');
- self.storeFailedScenario(scenario);
- self.witnessFailedScenario();
- } else if (self.isCurrentScenarioUndefined()) {
- self.witnessUndefinedScenario();
- } else if (self.isCurrentScenarioPending()) {
- self.witnessPendingScenario();
- } else {
- self.witnessPassedScenario();
- }
- callback();
- },
+ handleAfterScenarioEvent: handleAfterScenarioEvent('scenario'),
prepareBeforeScenario: function prepareBeforeScenario() {
currentScenarioFailing = false;
View
12 lib/cucumber/parser.js
@@ -25,8 +25,11 @@ var Parser = function(featureSources, astFilter) {
feature: self.handleFeature,
row: self.handleDataTableRow,
scenario: self.handleScenario,
+ scenario_outline: self.handleScenarioOutline,
+ examples: self.handleExamples,
step: self.handleStep,
tag: self.handleTag
+
};
},
@@ -63,7 +66,14 @@ var Parser = function(featureSources, astFilter) {
var scenario = Cucumber.Ast.Scenario(keyword, name, description, line);
astAssembler.insertScenario(scenario);
},
-
+ handleScenarioOutline: function handleScenarioOutline(keyword, name, description, line) {
+ var outline = Cucumber.Ast.ScenarioOutline(keyword, name, description, line);
+ astAssembler.insertScenario(outline);
+ },
+ handleExamples: function handleExamples(keyword, name, description, line) {
+ var examples = Cucumber.Ast.Examples(keyword, name, description, line);
+ astAssembler.insertExamples(examples);
+ },
handleStep: function handleStep(keyword, name, line) {
var step = Cucumber.Ast.Step(keyword, name, line);
astAssembler.insertStep(step);
View
20 lib/cucumber/runtime/ast_tree_walker.js
@@ -43,8 +43,9 @@ var AstTreeWalker = function(features, supportCodeLibrary, listeners) {
supportCodeLibrary.instantiateNewWorld(function(world) {
self.setWorld(world);
self.witnessNewScenario();
- var payload = { scenario: scenario };
- var event = AstTreeWalker.Event(AstTreeWalker.SCENARIO_EVENT_NAME, payload);
+ var payload = { };
+ payload[scenario.payload_type] = scenario;
+ var event = AstTreeWalker.Event(AstTreeWalker[scenario.payload_type.toUpperCase() + '_EVENT_NAME'], payload);
var hookedUpScenarioVisit = supportCodeLibrary.hookUpFunction(
function(callback) { scenario.acceptVisitor(self, callback); },
scenario,
@@ -57,7 +58,18 @@ var AstTreeWalker = function(features, supportCodeLibrary, listeners) {
);
});
},
-
+ visitRow: function visitRow(row, scenario,callback){
+ var payload = {exampleRow:row},
+ event = AstTreeWalker.Event(AstTreeWalker.ROW_EVENT_NAME, payload);
+ self.witnessNewScenario();
+ self.broadcastEventAroundUserFunction(
+ event,
+ function(callback){
+ scenario.visitRowSteps(self, row, callback);
+ },
+ callback
+ );
+ },
visitStep: function visitStep(step, callback) {
var payload = { step: step };
var event = AstTreeWalker.Event(AstTreeWalker.STEP_EVENT_NAME, payload);
@@ -190,8 +202,10 @@ AstTreeWalker.FEATURES_EVENT_NAME = 'Features';
AstTreeWalker.FEATURE_EVENT_NAME = 'Feature';
AstTreeWalker.BACKGROUND_EVENT_NAME = 'Background';
AstTreeWalker.SCENARIO_EVENT_NAME = 'Scenario';
+AstTreeWalker.SCENARIOOUTLINE_EVENT_NAME = 'ScenarioOutline';
AstTreeWalker.STEP_EVENT_NAME = 'Step';
AstTreeWalker.STEP_RESULT_EVENT_NAME = 'StepResult';
+AstTreeWalker.ROW_EVENT_NAME = 'ExampleRow';
AstTreeWalker.BEFORE_EVENT_NAME_PREFIX = 'Before';
AstTreeWalker.AFTER_EVENT_NAME_PREFIX = 'After';
AstTreeWalker.NON_EVENT_LEADING_PARAMETERS_COUNT = 0;
View
5 lib/cucumber/support_code/library.js
@@ -51,8 +51,9 @@ var Library = function(supportCodeDefinition) {
},
instantiateNewWorld: function instantiateNewWorld(callback) {
- var world = new worldConstructor(function(explicitWorld) {
- process.nextTick(function() { // release the constructor
+ var world;
+ world = new worldConstructor(function (explicitWorld) {
+ process.nextTick(function () { // release the constructor
callback(explicitWorld || world);
});
});
View
8 lib/cucumber/type/collection.js
@@ -3,6 +3,7 @@ var Collection = function() {
var self = {
add: function add(item) { items.push(item); },
unshift: function unshift(item) { items.unshift(item); },
+ shift: function shift() { return items.shift(); },
getLast: function getLast() { return items[items.length-1]; },
syncForEach: function syncForEach(userFunction) { items.forEach(userFunction); },
forEach: function forEach(userFunction, callback) {
@@ -22,6 +23,13 @@ var Collection = function() {
};
iterate();
},
+ syncMap: function map(userFunction) {
+ var newCollection = Collection();
+ items.map(function(item){
+ newCollection.add(userFunction(item));
+ });
+ return newCollection;
+ },
length: function length() { return items.length; }
};
return self;
View
4 lib/cucumber/util/exception.js
@@ -2,14 +2,14 @@ var Exception = {
registerUncaughtExceptionHandler: function registerUncaughtExceptionHandler(exceptionHandler) {
if (process.on)
process.on('uncaughtException', exceptionHandler);
- else
+ else if (typeof(window) != 'undefined')
window.onerror = exceptionHandler;
},
unregisterUncaughtExceptionHandler: function unregisterUncaughtExceptionHandler(exceptionHandler) {
if (process.removeListener)
process.removeListener('uncaughtException', exceptionHandler);
- else
+ else if (typeof(window) != 'undefined')
window.onerror = void(0);
}
};
View
115 package.json
@@ -1,48 +1,69 @@
-{ "name" : "cucumber"
-, "description" : "The official JavaScript implementation of Cucumber."
-, "keywords" : [ "testing", "bdd", "cucumber", "gherkin", "tests" ]
-, "version" : "0.2.15"
-, "homepage" : "http://github.com/cucumber/cucumber-js"
-, "author" : "Julien Biezemans <jb@jbpros.com> (http://jbpros.net)"
-, "contributors" : [
- "Julien Biezemans <jb@jbpros.com> (http://jbpros.net)"
- , "Fernando Acorreia <fernandoacorreia@gmail.com>"
- , "Paul Jensen <paulbjensen@gmail.com>"
- , "Kushal Pisavadia"
- , "Olivier Melcher <olivier.melcher@gmail.com>"
- , "Tristan Dunn <tristanzdunn@gmail.com>"
- , "Ted de Koning"
- ]
-, "repository" :
- { "type" : "git"
- , "url" : "git://github.com/cucumber/cucumber-js.git"
- }
-, "bugs" :
- { "mail" : "cukes@googlegroups.com"
- , "url" : "http://github.com/cucumber/cucumber-js/issues"
- }
-, "directories" : { "lib" : "./lib" }
-, "main" : "./lib/cucumber"
-, "engines" : { "node" : "0.4 || 0.5 || 0.6" }
-, "dependencies" :
- { "gherkin" : "2.6.8"
- , "jasmine-node" : "1.0.13"
- , "connect" : "1.8.1"
- , "browserify" : "1.8.1"
- , "nopt" : "1.0.10"
- , "underscore" : "1.2.2"
- , "rimraf" : "1.0.8"
- , "mkdirp" : "0.2.1"
- , "cucumber-html": "0.2.0"
- , "findit": "0.1.1"
- , "coffee-script": "1.1.2"
- }
-, "scripts" :
- { "test" : "./bin/cucumber.js && jasmine-node spec" }
-, "bin": { "cucumber.js": "./bin/cucumber.js", "cucumber-js": "./bin/cucumber.js" }
-, "licenses" :
- [ { "type" : "MIT"
- , "url" : "http://github.com/cucumber/cucumber.js/LICENSE"
+{
+ "name": "cucumber",
+ "description": "The official JavaScript implementation of Cucumber.",
+ "keywords": [
+ "testing",
+ "bdd",
+ "cucumber",
+ "gherkin",
+ "tests"
+ ],
+ "version": "0.2.18",
+ "homepage": "http://github.com/cucumber/cucumber-js",
+ "author": "Julien Biezemans <jb@jbpros.com> (http://jbpros.net)",
+ "contributors": [
+ "Julien Biezemans <jb@jbpros.com> (http://jbpros.net)",
+ "Fernando Acorreia <fernandoacorreia@gmail.com>",
+ "Paul Jensen <paulbjensen@gmail.com>",
+ "Kushal Pisavadia",
+ "Olivier Melcher <olivier.melcher@gmail.com>",
+ "Tristan Dunn <tristanzdunn@gmail.com>",
+ "Ted de Koning",
+ "@renier",
+ "Aslak Hellesøy <aslak.hellesoy@gmail.com>",
+ "Aaron Garvey"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/cucumber/cucumber-js.git"
+ },
+ "bugs": {
+ "email": "cukes@googlegroups.com",
+ "url": "http://github.com/cucumber/cucumber-js/issues"
+ },
+ "directories": {
+ "lib": "./lib"
+ },
+ "main": "./lib/cucumber",
+ "engines": {
+ "node": "0.6 || 0.7 || 0.8"
+ },
+ "dependencies": {
+ "gherkin": "2.11.0",
+ "jasmine-node": "1.0.26",
+ "connect": "2.3.2",
+ "browserify": "1.13.2",
+ "nopt": "1.0.10",
+ "underscore": "1.3.3",
+ "rimraf": "2.0.2",
+ "mkdirp": "0.3.3",
+ "cucumber-html": "0.2.0",
+ "walkdir": "0.0.4",
+ "coffee-script": "1.3.3"
+ },
+ "scripts": {
+ "test": "./bin/cucumber.js && jasmine-node spec"
+ },
+ "bin": {
+ "cucumber.js": "./bin/cucumber.js",
+ "cucumber-js": "./bin/cucumber.js"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "http://github.com/cucumber/cucumber.js/LICENSE"
}
- ]
-}
+ ],
+ "devDependencies": {},
+ "optionalDependencies": {}
+}
Something went wrong with that request. Please try again.