cucumber-compatibility-kit 11.3.0 → 13.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/features/attachments/attachments.feature +3 -0
  3. data/features/attachments/attachments.feature.ndjson +77 -67
  4. data/features/attachments/attachments.feature.rb +9 -3
  5. data/features/attachments/cucumber.jpeg +0 -0
  6. data/features/attachments/document.pdf +0 -0
  7. data/features/cdata/cdata.feature.ndjson +1 -1
  8. data/features/data-tables/data-tables.feature.ndjson +1 -1
  9. data/features/data-tables/data-tables.feature.rb +2 -0
  10. data/features/examples-tables/examples-tables.feature.ndjson +1 -1
  11. data/features/examples-tables/examples-tables.feature.rb +2 -0
  12. data/features/hooks/hooks.feature.ndjson +1 -1
  13. data/features/hooks/hooks.feature.rb +2 -0
  14. data/features/markdown/markdown.feature.md.ndjson +1 -1
  15. data/features/minimal/minimal.feature.ndjson +1 -1
  16. data/features/minimal/minimal.feature.rb +3 -1
  17. data/features/parameter-types/parameter-types.feature.ndjson +1 -1
  18. data/features/parameter-types/parameter-types.feature.rb +2 -1
  19. data/features/pending/pending.feature.ndjson +1 -1
  20. data/features/pending/pending.feature.rb +3 -1
  21. data/features/retry/retry.feature.ndjson +1 -1
  22. data/features/retry/retry.feature.rb +2 -0
  23. data/features/rules/rules.feature.ndjson +1 -1
  24. data/features/rules/rules.feature.rb +2 -0
  25. data/features/skipped/skipped.feature.ndjson +1 -1
  26. data/features/skipped/skipped.feature.rb +3 -1
  27. data/features/stack-traces/stack-traces.feature.ndjson +1 -1
  28. data/features/stack-traces/stack-traces.feature.rb +2 -0
  29. data/features/undefined/undefined.feature.ndjson +1 -1
  30. data/features/undefined/undefined.feature.rb +3 -1
  31. data/features/unknown-parameter-type/unknown-parameter-type.feature.ndjson +1 -1
  32. data/features/unknown-parameter-type/unknown-parameter-type.feature.rb +3 -1
  33. data/lib/cucumber-compatibility-kit.rb +2 -0
  34. data/lib/keys_checker.rb +51 -15
  35. data/lib/messages_comparator.rb +2 -0
  36. data/lib/shared_examples.rb +8 -3
  37. data/spec/capture_warnings.rb +6 -5
  38. data/spec/cucumber-compatibility-kit_spec.rb +9 -7
  39. data/spec/keys_checker_spec.rb +13 -24
  40. data/spec/messages_comparator_spec.rb +22 -11
  41. metadata +64 -12
@@ -1,4 +1,4 @@
1
- {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.2.0"},"os":{"name":"darwin","version":"22.4.0"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"19.7.0"}}}
1
+ {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.3.0"},"os":{"name":"linux","version":"5.15.0-84-generic"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"18.18.0"}}}
2
2
  {"source":{"data":"Feature: Pending steps\n\n During development, step definitions can signal at runtime that they are\n not yet implemented (or \"pending\") by returning or throwing a particular\n value.\n\n This causes subsequent steps in the scenario to be skipped, and the overall\n result to be treated as a failure.\n\n Scenario: Unimplemented step signals pending status\n Given a step that isnt implemented yet\n\n Scenario: Steps before unimplemented steps are executed\n Given an implemented step\n When a step that isnt implemented yet\n\n Scenario: Steps after unimplemented steps are skipped\n Given a step that isnt implemented yet\n Then a step that we expect to be skipped\n","mediaType":"text/x.cucumber.gherkin+plain","uri":"samples/pending/pending.feature"}}
3
3
  {"gherkinDocument":{"comments":[],"feature":{"children":[{"scenario":{"description":"","examples":[],"id":"4","keyword":"Scenario","location":{"column":3,"line":10},"name":"Unimplemented step signals pending status","steps":[{"id":"3","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":11},"text":"a step that isnt implemented yet"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"7","keyword":"Scenario","location":{"column":3,"line":13},"name":"Steps before unimplemented steps are executed","steps":[{"id":"5","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":14},"text":"an implemented step"},{"id":"6","keyword":"When ","keywordType":"Action","location":{"column":5,"line":15},"text":"a step that isnt implemented yet"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"10","keyword":"Scenario","location":{"column":3,"line":17},"name":"Steps after unimplemented steps are skipped","steps":[{"id":"8","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":18},"text":"a step that isnt implemented yet"},{"id":"9","keyword":"Then ","keywordType":"Outcome","location":{"column":5,"line":19},"text":"a step that we expect to be skipped"}],"tags":[]}}],"description":" During development, step definitions can signal at runtime that they are\n not yet implemented (or \"pending\") by returning or throwing a particular\n value.\n\n This causes subsequent steps in the scenario to be skipped, and the overall\n result to be treated as a failure.","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Pending steps","tags":[]},"uri":"samples/pending/pending.feature"}}
4
4
  {"pickle":{"astNodeIds":["4"],"id":"12","language":"en","name":"Unimplemented step signals pending status","steps":[{"astNodeIds":["3"],"id":"11","text":"a step that isnt implemented yet","type":"Context"}],"tags":[],"uri":"samples/pending/pending.feature"}}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Given('an implemented step') do
2
4
  # no-op
3
5
  end
@@ -8,4 +10,4 @@ end
8
10
 
9
11
  Given('a step that isnt implemented yet') do
10
12
  'pending'
11
- end
13
+ end
@@ -1,4 +1,4 @@
1
- {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.2.0"},"os":{"name":"darwin","version":"22.4.0"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"19.7.0"}}}
1
+ {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.3.0"},"os":{"name":"linux","version":"5.15.0-84-generic"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"18.18.0"}}}
2
2
  {"source":{"data":"Feature: Retry\n\n Some Cucumber implementations support a Retry mechanism, where test cases that fail\n can be retried up to a limited number of attempts in the same test run.\n\n Non-passing statuses other than FAILED don't trigger a retry - they are not going to pass\n however many times we attempt them.\n\n Scenario: test case passes on the first attempt\n Given a step that always passes\n\n Scenario: test case passes on the second attempt\n Given a step that passes the second time\n\n Scenario: test case passes on the final attempt\n Given a step that passes the third time\n\n Scenario: test case fails on every attempt\n Given a step that always fails\n\n Scenario: don't retry on UNDEFINED\n Given a non-existent step\n","mediaType":"text/x.cucumber.gherkin+plain","uri":"samples/retry/retry.feature"}}
3
3
  {"gherkinDocument":{"comments":[],"feature":{"children":[{"scenario":{"description":"","examples":[],"id":"5","keyword":"Scenario","location":{"column":3,"line":9},"name":"test case passes on the first attempt","steps":[{"id":"4","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":10},"text":"a step that always passes"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"7","keyword":"Scenario","location":{"column":3,"line":12},"name":"test case passes on the second attempt","steps":[{"id":"6","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":13},"text":"a step that passes the second time"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"9","keyword":"Scenario","location":{"column":3,"line":15},"name":"test case passes on the final attempt","steps":[{"id":"8","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":16},"text":"a step that passes the third time"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"11","keyword":"Scenario","location":{"column":3,"line":18},"name":"test case fails on every attempt","steps":[{"id":"10","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":19},"text":"a step that always fails"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"13","keyword":"Scenario","location":{"column":3,"line":21},"name":"don't retry on UNDEFINED","steps":[{"id":"12","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":22},"text":"a non-existent step"}],"tags":[]}}],"description":" Some Cucumber implementations support a Retry mechanism, where test cases that fail\n can be retried up to a limited number of attempts in the same test run.\n\n Non-passing statuses other than FAILED don't trigger a retry - they are not going to pass\n however many times we attempt them.","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Retry","tags":[]},"uri":"samples/retry/retry.feature"}}
4
4
  {"pickle":{"astNodeIds":["5"],"id":"15","language":"en","name":"test case passes on the first attempt","steps":[{"astNodeIds":["4"],"id":"14","text":"a step that always passes","type":"Context"}],"tags":[],"uri":"samples/retry/retry.feature"}}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Given('a step that always passes') do
2
4
  # no-op
3
5
  end
@@ -1,4 +1,4 @@
1
- {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.2.0"},"os":{"name":"darwin","version":"22.4.0"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"19.7.0"}}}
1
+ {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.3.0"},"os":{"name":"linux","version":"5.15.0-84-generic"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"18.18.0"}}}
2
2
  {"source":{"data":"Feature: Rules\n You can place scenarios inside rules. This makes is possible to structure\n Gherkin documents in the same way as [example maps](https://cucumber.io/blog/bdd/example-mapping-introduction/).\n You can also use the Examples synonym for Scenario to make them even more similar.\n\n Rule: a sale cannot happen if change cannot be returned\n # sad path\n Example: no change\n Given there are 5 0.20 coins inside\n When the customer tries to buy a 0.85 chocolate with a 1 coin\n Then the sale should not happen\n\n # happy path\n Example: exact change\n Given there are 5 0.20 coins inside\n And there are 3 chocolates inside\n When the customer tries to buy a 0.80 chocolate with a 1 coin\n Then the customer's change should be 1 0.20 coin\n\n @some-tag\n Rule: a sale cannot happen if we're out of stock\n # sad path\n Example: no chocolates left\n Given there are no chocolates inside\n But there are 10 0.5 coins inside\n When the customer tries to buy a 0.85 chocolate with a 1 coin\n Then the sale should not happen\n","mediaType":"text/x.cucumber.gherkin+plain","uri":"samples/rules/rules.feature"}}
3
3
  {"gherkinDocument":{"comments":[{"location":{"column":1,"line":7},"text":" # sad path"},{"location":{"column":1,"line":13},"text":" # happy path"},{"location":{"column":1,"line":22},"text":" # sad path"}],"feature":{"children":[{"rule":{"children":[{"scenario":{"description":"","examples":[],"id":"9","keyword":"Example","location":{"column":5,"line":8},"name":"no change","steps":[{"id":"6","keyword":"Given ","keywordType":"Context","location":{"column":7,"line":9},"text":"there are 5 0.20 coins inside"},{"id":"7","keyword":"When ","keywordType":"Action","location":{"column":7,"line":10},"text":"the customer tries to buy a 0.85 chocolate with a 1 coin"},{"id":"8","keyword":"Then ","keywordType":"Outcome","location":{"column":7,"line":11},"text":"the sale should not happen"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"14","keyword":"Example","location":{"column":5,"line":14},"name":"exact change","steps":[{"id":"10","keyword":"Given ","keywordType":"Context","location":{"column":7,"line":15},"text":"there are 5 0.20 coins inside"},{"id":"11","keyword":"And ","keywordType":"Conjunction","location":{"column":7,"line":16},"text":"there are 3 chocolates inside"},{"id":"12","keyword":"When ","keywordType":"Action","location":{"column":7,"line":17},"text":"the customer tries to buy a 0.80 chocolate with a 1 coin"},{"id":"13","keyword":"Then ","keywordType":"Outcome","location":{"column":7,"line":18},"text":"the customer's change should be 1 0.20 coin"}],"tags":[]}}],"description":"","id":"15","keyword":"Rule","location":{"column":3,"line":6},"name":"a sale cannot happen if change cannot be returned","tags":[]}},{"rule":{"children":[{"scenario":{"description":"","examples":[],"id":"20","keyword":"Example","location":{"column":5,"line":23},"name":"no chocolates left","steps":[{"id":"16","keyword":"Given ","keywordType":"Context","location":{"column":7,"line":24},"text":"there are no chocolates inside"},{"id":"17","keyword":"But ","keywordType":"Conjunction","location":{"column":7,"line":25},"text":"there are 10 0.5 coins inside"},{"id":"18","keyword":"When ","keywordType":"Action","location":{"column":7,"line":26},"text":"the customer tries to buy a 0.85 chocolate with a 1 coin"},{"id":"19","keyword":"Then ","keywordType":"Outcome","location":{"column":7,"line":27},"text":"the sale should not happen"}],"tags":[]}}],"description":"","id":"22","keyword":"Rule","location":{"column":3,"line":21},"name":"a sale cannot happen if we're out of stock","tags":[{"id":"21","location":{"column":3,"line":20},"name":"@some-tag"}]}}],"description":" You can place scenarios inside rules. This makes is possible to structure\n Gherkin documents in the same way as [example maps](https://cucumber.io/blog/bdd/example-mapping-introduction/).\n You can also use the Examples synonym for Scenario to make them even more similar.","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Rules","tags":[]},"uri":"samples/rules/rules.feature"}}
4
4
  {"pickle":{"astNodeIds":["9"],"id":"26","language":"en","name":"no change","steps":[{"astNodeIds":["6"],"id":"23","text":"there are 5 0.20 coins inside","type":"Context"},{"astNodeIds":["7"],"id":"24","text":"the customer tries to buy a 0.85 chocolate with a 1 coin","type":"Action"},{"astNodeIds":["8"],"id":"25","text":"the sale should not happen","type":"Outcome"}],"tags":[],"uri":"samples/rules/rules.feature"}}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Given('there are {int} {float} coins inside') do |count, coin_type|
2
4
  expect(count).not_to be_nil
3
5
  expect(coin_type.to_s).not_to be_empty
@@ -1,4 +1,4 @@
1
- {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.2.0"},"os":{"name":"darwin","version":"22.4.0"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"19.7.0"}}}
1
+ {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.3.0"},"os":{"name":"linux","version":"5.15.0-84-generic"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"18.18.0"}}}
2
2
  {"source":{"data":"Feature: Skipping scenarios\n\n Hooks and step definitions are able to signal at runtime that the scenario should\n be skipped by returning or throwing a particular value.\n\n This can be useful when e.g. the current environment doesn't have the right conditions\n for running the scenario.\n\n @skip\n Scenario: Skipping from a Before hook\n Given a step that we expect to be skipped\n\n Scenario: Skipping from a step doesn't affect the previous steps\n Given an implemented step\n When a step that skips\n\n Scenario: Skipping from a step causes the rest of the scenario to be skipped\n Given a step that skips\n When a step that we expect to be skipped\n","mediaType":"text/x.cucumber.gherkin+plain","uri":"samples/skipped/skipped.feature"}}
3
3
  {"gherkinDocument":{"comments":[],"feature":{"children":[{"scenario":{"description":"","examples":[],"id":"6","keyword":"Scenario","location":{"column":3,"line":10},"name":"Skipping from a Before hook","steps":[{"id":"4","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":11},"text":"a step that we expect to be skipped"}],"tags":[{"id":"5","location":{"column":3,"line":9},"name":"@skip"}]}},{"scenario":{"description":"","examples":[],"id":"9","keyword":"Scenario","location":{"column":3,"line":13},"name":"Skipping from a step doesn't affect the previous steps","steps":[{"id":"7","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":14},"text":"an implemented step"},{"id":"8","keyword":"When ","keywordType":"Action","location":{"column":5,"line":15},"text":"a step that skips"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"12","keyword":"Scenario","location":{"column":3,"line":17},"name":"Skipping from a step causes the rest of the scenario to be skipped","steps":[{"id":"10","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":18},"text":"a step that skips"},{"id":"11","keyword":"When ","keywordType":"Action","location":{"column":5,"line":19},"text":"a step that we expect to be skipped"}],"tags":[]}}],"description":" Hooks and step definitions are able to signal at runtime that the scenario should\n be skipped by returning or throwing a particular value.\n\n This can be useful when e.g. the current environment doesn't have the right conditions\n for running the scenario.","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Skipping scenarios","tags":[]},"uri":"samples/skipped/skipped.feature"}}
4
4
  {"pickle":{"astNodeIds":["6"],"id":"14","language":"en","name":"Skipping from a Before hook","steps":[{"astNodeIds":["4"],"id":"13","text":"a step that we expect to be skipped","type":"Context"}],"tags":[{"astNodeId":"5","name":"@skip"}],"uri":"samples/skipped/skipped.feature"}}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Before('@skip') do
2
4
  'skipped'
3
5
  end
@@ -12,4 +14,4 @@ end
12
14
 
13
15
  Given('a step that skips') do
14
16
  'skipped'
15
- end
17
+ end
@@ -1,4 +1,4 @@
1
- {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.2.0"},"os":{"name":"darwin","version":"22.4.0"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"19.7.0"}}}
1
+ {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.3.0"},"os":{"name":"linux","version":"5.15.0-84-generic"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"18.18.0"}}}
2
2
  {"source":{"data":"Feature: Stack traces\n Nothing beats stack traces when it comes to diagnosing the source of a bug.\n Cucumber provides helpful stack traces that:\n \n - Include a stack frame from the Gherkin document\n - Remove uninteresting frames by default\n\n The first line of the stack trace must contain the feature file.\n\n Scenario: A failing step\n When a step throws an exception\n","mediaType":"text/x.cucumber.gherkin+plain","uri":"samples/stack-traces/stack-traces.feature"}}
3
3
  {"gherkinDocument":{"comments":[],"feature":{"children":[{"scenario":{"description":"","examples":[],"id":"2","keyword":"Scenario","location":{"column":3,"line":10},"name":"A failing step","steps":[{"id":"1","keyword":"When ","keywordType":"Action","location":{"column":5,"line":11},"text":"a step throws an exception"}],"tags":[]}}],"description":" Nothing beats stack traces when it comes to diagnosing the source of a bug.\n Cucumber provides helpful stack traces that:\n \n - Include a stack frame from the Gherkin document\n - Remove uninteresting frames by default\n\n The first line of the stack trace must contain the feature file.","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Stack traces","tags":[]},"uri":"samples/stack-traces/stack-traces.feature"}}
4
4
  {"pickle":{"astNodeIds":["2"],"id":"4","language":"en","name":"A failing step","steps":[{"astNodeIds":["1"],"id":"3","text":"a step throws an exception","type":"Action"}],"tags":[],"uri":"samples/stack-traces/stack-traces.feature"}}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When('a step throws an exception') do
2
4
  raise StandardError, 'An exception is raised here'
3
5
  end
@@ -1,4 +1,4 @@
1
- {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.2.0"},"os":{"name":"darwin","version":"22.4.0"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"19.7.0"}}}
1
+ {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.3.0"},"os":{"name":"linux","version":"5.15.0-84-generic"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"18.18.0"}}}
2
2
  {"source":{"data":"Feature: Undefined steps\n\n At runtime, Cucumber may encounter a step in a scenario that it cannot match to a\n step definition. In these cases, the scenario cannot run and so the step status\n will be UNDEFINED, with subsequent steps being skipped and the overall result treated\n as a failure.\n\n Scenario: Undefined step causes failure\n Given a step that isnt implemented yet\n\n Scenario: Steps before undefined steps are executed\n Given an implemented step\n When a step that isnt implemented yet\n\n Scenario: Steps after undefined steps are skipped\n Given a step that isnt implemented yet\n Then a step that we expect to be skipped\n","mediaType":"text/x.cucumber.gherkin+plain","uri":"samples/undefined/undefined.feature"}}
3
3
  {"gherkinDocument":{"comments":[],"feature":{"children":[{"scenario":{"description":"","examples":[],"id":"3","keyword":"Scenario","location":{"column":3,"line":8},"name":"Undefined step causes failure","steps":[{"id":"2","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":9},"text":"a step that isnt implemented yet"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"6","keyword":"Scenario","location":{"column":3,"line":11},"name":"Steps before undefined steps are executed","steps":[{"id":"4","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":12},"text":"an implemented step"},{"id":"5","keyword":"When ","keywordType":"Action","location":{"column":5,"line":13},"text":"a step that isnt implemented yet"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"9","keyword":"Scenario","location":{"column":3,"line":15},"name":"Steps after undefined steps are skipped","steps":[{"id":"7","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":16},"text":"a step that isnt implemented yet"},{"id":"8","keyword":"Then ","keywordType":"Outcome","location":{"column":5,"line":17},"text":"a step that we expect to be skipped"}],"tags":[]}}],"description":" At runtime, Cucumber may encounter a step in a scenario that it cannot match to a\n step definition. In these cases, the scenario cannot run and so the step status\n will be UNDEFINED, with subsequent steps being skipped and the overall result treated\n as a failure.","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Undefined steps","tags":[]},"uri":"samples/undefined/undefined.feature"}}
4
4
  {"pickle":{"astNodeIds":["3"],"id":"11","language":"en","name":"Undefined step causes failure","steps":[{"astNodeIds":["2"],"id":"10","text":"a step that isnt implemented yet","type":"Context"}],"tags":[],"uri":"samples/undefined/undefined.feature"}}
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Given('an implemented step') do
2
4
  # no-op
3
5
  end
4
6
 
5
7
  Given('a step that we expect to be skipped') do
6
8
  # no-op
7
- end
9
+ end
@@ -1,4 +1,4 @@
1
- {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.2.0"},"os":{"name":"darwin","version":"22.4.0"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"19.7.0"}}}
1
+ {"meta":{"ci":{"buildNumber":"154666429","git":{"remote":"https://github.com/cucumber-ltd/shouty.rb.git","revision":"99684bcacf01d95875834d87903dcb072306c9ad"},"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429"},"cpu":{"name":"x64"},"implementation":{"name":"fake-cucumber","version":"16.3.0"},"os":{"name":"linux","version":"5.15.0-84-generic"},"protocolVersion":"22.0.0","runtime":{"name":"node.js","version":"18.18.0"}}}
2
2
  {"source":{"data":"Feature: Parameter Types\n Cucumber will generate an error message if a step definition registers\n an unknown parameter type, but the suite will run.\n\n Scenario: undefined parameter type\n Given CDG is closed because of a strike","mediaType":"text/x.cucumber.gherkin+plain","uri":"samples/unknown-parameter-type/unknown-parameter-type.feature"}}
3
3
  {"gherkinDocument":{"comments":[],"feature":{"children":[{"scenario":{"description":"","examples":[],"id":"1","keyword":"Scenario","location":{"column":3,"line":5},"name":"undefined parameter type","steps":[{"id":"0","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":6},"text":"CDG is closed because of a strike"}],"tags":[]}}],"description":" Cucumber will generate an error message if a step definition registers\n an unknown parameter type, but the suite will run.","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Parameter Types","tags":[]},"uri":"samples/unknown-parameter-type/unknown-parameter-type.feature"}}
4
4
  {"pickle":{"astNodeIds":["1"],"id":"3","language":"en","name":"undefined parameter type","steps":[{"astNodeIds":["0"],"id":"2","text":"CDG is closed because of a strike","type":"Context"}],"tags":[],"uri":"samples/unknown-parameter-type/unknown-parameter-type.feature"}}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Given('{airport} is closed because of a strike') do |airport|
2
4
  raise StandardError, 'Should not be called because airport type not defined'
3
- end
5
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'shared_examples'
2
4
 
3
5
  module Cucumber::CompatibilityKit
data/lib/keys_checker.rb CHANGED
@@ -1,28 +1,64 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CCK
2
4
  class KeysChecker
3
- def self.compare(found, expected)
4
- KeysChecker.new.compare(found, expected)
5
+ def self.compare(detected, expected)
6
+ new(detected, expected).compare
5
7
  end
6
8
 
7
- def compare(found, expected)
8
- errors = []
9
-
10
- found_keys = found.to_h(reject_nil_values: true).keys
11
- expected_keys = expected.to_h(reject_nil_values: true).keys
12
-
13
- return errors if found_keys.sort == expected_keys.sort
9
+ attr_reader :detected, :expected
14
10
 
15
- missing_keys = (expected_keys - found_keys)
11
+ def initialize(detected, expected)
12
+ @detected = detected
13
+ @expected = expected
14
+ end
16
15
 
17
- extra_keys = (found_keys - expected_keys).reject { |key|
18
- ENV['CI'] && found.class == Cucumber::Messages::Meta && key == :ci
19
- }
16
+ def compare
17
+ return [] if identical_keys?
20
18
 
21
- errors << "Found extra keys in message #{found.class.name}: #{extra_keys}" unless extra_keys.empty?
22
- errors << "Missing keys in message #{found.class.name}: #{missing_keys}" unless missing_keys.empty?
19
+ errors << "Detected extra keys in message #{message_name}: #{extra_keys}" if extra_keys.any?
20
+ errors << "Missing keys in message #{message_name}: #{missing_keys}" if missing_keys.any?
23
21
  errors
24
22
  rescue StandardError => e
25
23
  ["Unexpected error: #{e.message}"]
26
24
  end
25
+
26
+ private
27
+
28
+ def detected_keys
29
+ @detected_keys ||= ordered_uniq_hash_keys(detected)
30
+ end
31
+
32
+ def expected_keys
33
+ @expected_keys ||= ordered_uniq_hash_keys(expected)
34
+ end
35
+
36
+ def identical_keys?
37
+ detected_keys == expected_keys
38
+ end
39
+
40
+ def missing_keys
41
+ (expected_keys - detected_keys).reject { |key| meta_message? && key == :ci }
42
+ end
43
+
44
+ def extra_keys
45
+ (detected_keys - expected_keys).reject { |key| meta_message? && key == :ci }
46
+ end
47
+
48
+ def meta_message?
49
+ detected.instance_of?(Cucumber::Messages::Meta)
50
+ end
51
+
52
+ def message_name
53
+ detected.class.name
54
+ end
55
+
56
+ def ordered_uniq_hash_keys(object)
57
+ object.to_h(reject_nil_values: true).keys.sort
58
+ end
59
+
60
+ def errors
61
+ @errors ||= []
62
+ end
27
63
  end
28
64
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'keys_checker'
2
4
 
3
5
  module CCK
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
  require 'rspec'
3
5
  require 'cucumber/messages'
@@ -10,8 +12,8 @@ RSpec.shared_examples 'cucumber compatibility kit' do
10
12
  # let(:example) { } # the name of the example to test
11
13
  # let(:messages) { } # the messages to validate
12
14
 
13
- let(:example) { raise "`example` missing: add `let(:example) { example_name }` to your spec" }
14
- let(:messages) { raise "`messages` missing: add `let(:messages) { ndjson }` to your spec" }
15
+ let(:example) { raise '`example` missing: add `let(:example) { example_name }` to your spec' }
16
+ let(:messages) { raise '`messages` missing: add `let(:messages) { ndjson }` to your spec' }
15
17
 
16
18
  let(:example_path) { Cucumber::CompatibilityKit.example_path(example) }
17
19
 
@@ -45,7 +47,10 @@ def parse_ndjson(ndjson)
45
47
  end
46
48
 
47
49
  def message_type(message)
48
- message.to_h.keys.first
50
+ # TODO: This is duplicate code - from messages_comparator:45 - It should live in a common helper methods module
51
+ message.to_h.each do |key, value|
52
+ return key unless value.nil?
53
+ end
49
54
  end
50
55
 
51
56
  def debug_lists(expected, obtained)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # With thanks to @myronmarston
3
4
  # https://github.com/vcr/vcr/blob/master/spec/capture_warnings.rb
4
5
 
@@ -18,14 +19,14 @@ module CaptureWarnings
18
19
  end
19
20
 
20
21
  # Until they fix https://bugs.ruby-lang.org/issues/10661
21
- if RUBY_VERSION == "2.2.0"
22
+ if RUBY_VERSION == '2.2.0'
22
23
  project_warnings = project_warnings.reject { |w| w =~ /warning: possible reference to past scope/ }
23
24
  end
24
25
 
25
26
  if project_warnings.any?
26
27
  puts "#{ project_warnings.count } warnings detected"
27
28
  print_warnings('cucumber-expressions', project_warnings)
28
- fail "Please remove all cucumber-expressions warnings."
29
+ fail 'Please remove all cucumber-expressions warnings.'
29
30
  end
30
31
 
31
32
  ensure_system_exit_if_required
@@ -56,11 +57,11 @@ module CaptureWarnings
56
57
 
57
58
  def print_warnings(type, warnings)
58
59
  puts
59
- puts "-" * 30 + " #{type} warnings: " + "-" * 30
60
+ puts '-' * 30 + " #{type} warnings: " + '-' * 30
60
61
  puts
61
62
  puts warnings.join("\n")
62
63
  puts
63
- puts "-" * 75
64
+ puts '-' * 75
64
65
  puts
65
66
  end
66
67
 
@@ -69,6 +70,6 @@ module CaptureWarnings
69
70
  end
70
71
 
71
72
  def capture_system_exit
72
- @system_exit = $!
73
+ @system_exit = $ERROR_INFO
73
74
  end
74
75
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'cucumber-compatibility-kit'
2
4
 
3
5
  describe Cucumber::CompatibilityKit do
@@ -28,7 +30,7 @@ describe Cucumber::CompatibilityKit do
28
30
 
29
31
  describe '#examples_path' do
30
32
  it 'returns the path of the features folder' do
31
- expect(Cucumber::CompatibilityKit.examples_path)
33
+ expect(described_class.examples_path)
32
34
  .to eq(features_path)
33
35
  end
34
36
  end
@@ -36,14 +38,14 @@ describe Cucumber::CompatibilityKit do
36
38
  describe '#example_path' do
37
39
  context 'with an existing example' do
38
40
  it 'returns the path of the folder of the example' do
39
- expect(Cucumber::CompatibilityKit.example_path('hooks'))
41
+ expect(described_class.example_path('hooks'))
40
42
  .to eq("#{features_path}/hooks")
41
43
  end
42
44
  end
43
45
 
44
46
  context 'with an unexisting example' do
45
47
  it 'raises ArgumentError' do
46
- expect { Cucumber::CompatibilityKit.example_path('should-not-exists') }
48
+ expect { described_class.example_path('should-not-exists') }
47
49
  .to raise_error(ArgumentError)
48
50
  end
49
51
  end
@@ -51,22 +53,22 @@ describe Cucumber::CompatibilityKit do
51
53
 
52
54
  describe '#gherkin_examples' do
53
55
  it 'returns the list of gherkin examples' do
54
- expect(Cucumber::CompatibilityKit.gherkin_examples)
56
+ expect(described_class.gherkin_examples)
55
57
  .to match_array(gherkin_examples)
56
58
  end
57
59
  end
58
60
 
59
61
  describe '#markdown_examples' do
60
62
  it 'returns the list of markdown examples' do
61
- expect(Cucumber::CompatibilityKit.markdown_examples)
63
+ expect(described_class.markdown_examples)
62
64
  .to match_array(markdown_examples)
63
65
  end
64
66
  end
65
67
 
66
68
  describe '#all_examples' do
67
69
  it 'returns the list of all available examples' do
68
- expect(Cucumber::CompatibilityKit.all_examples)
70
+ expect(described_class.all_examples)
69
71
  .to match_array(gherkin_examples + markdown_examples)
70
72
  end
71
73
  end
72
- end
74
+ end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rspec'
2
4
  require 'cucumber/messages'
3
5
  require_relative '../lib/keys_checker'
4
6
 
5
7
  describe CCK::KeysChecker do
6
- let(:subject) { CCK::KeysChecker }
8
+ let(:subject) { described_class }
7
9
 
8
10
  describe '#compare' do
9
11
  let(:complete) do
@@ -14,15 +16,11 @@ describe CCK::KeysChecker do
14
16
  end
15
17
 
16
18
  let(:missing_data_table) do
17
- Cucumber::Messages::PickleStepArgument.new(
18
- doc_string: '1'
19
- )
19
+ Cucumber::Messages::PickleStepArgument.new(doc_string: '1')
20
20
  end
21
21
 
22
22
  let(:missing_doc_string) do
23
- Cucumber::Messages::PickleStepArgument.new(
24
- data_table: '12'
25
- )
23
+ Cucumber::Messages::PickleStepArgument.new(data_table: '12')
26
24
  end
27
25
 
28
26
  let(:wrong_values) do
@@ -40,14 +38,14 @@ describe CCK::KeysChecker do
40
38
 
41
39
  it 'finds extra keys' do
42
40
  expect(subject.compare(complete, missing_doc_string)).to eq(
43
- ['Found extra keys in message Cucumber::Messages::PickleStepArgument: [:doc_string]']
41
+ ['Detected extra keys in message Cucumber::Messages::PickleStepArgument: [:doc_string]']
44
42
  )
45
43
  end
46
44
 
47
45
  it 'finds extra and missing' do
48
46
  expect(subject.compare(missing_doc_string, missing_data_table)).to contain_exactly(
49
47
  'Missing keys in message Cucumber::Messages::PickleStepArgument: [:doc_string]',
50
- 'Found extra keys in message Cucumber::Messages::PickleStepArgument: [:data_table]'
48
+ 'Detected extra keys in message Cucumber::Messages::PickleStepArgument: [:data_table]'
51
49
  )
52
50
  end
53
51
 
@@ -64,9 +62,7 @@ describe CCK::KeysChecker do
64
62
  end
65
63
 
66
64
  let(:default_not_set) do
67
- Cucumber::Messages::Duration.new(
68
- nanos: 12
69
- )
65
+ Cucumber::Messages::Duration.new(nanos: 12)
70
66
  end
71
67
 
72
68
  it 'does not raise an exception' do
@@ -75,26 +71,19 @@ describe CCK::KeysChecker do
75
71
  end
76
72
 
77
73
  context 'when executed as part of a CI' do
78
- before do
79
- allow(ENV).to receive(:[]).with('CI').and_return(true)
80
- end
74
+ before { allow(ENV).to receive(:[]).with('CI').and_return(true) }
81
75
 
82
76
  it 'ignores actual CI related messages' do
83
- found = Cucumber::Messages::Meta.new(
84
- ci: Cucumber::Messages::Ci.new(name: 'Some CI')
85
- )
86
-
77
+ detected = Cucumber::Messages::Meta.new(ci: Cucumber::Messages::Ci.new(name: 'Some CI'))
87
78
  expected = Cucumber::Messages::Meta.new
88
79
 
89
- expect(subject.compare(found, expected)).to be_empty
80
+ expect(subject.compare(detected, expected)).to be_empty
90
81
  end
91
82
  end
92
83
 
93
- context 'when an unexcpected error occurs' do
84
+ context 'when an unexpected error occurs' do
94
85
  it 'does not raise error' do
95
- expect {
96
- subject.compare(nil, nil)
97
- }.not_to raise_error
86
+ expect { subject.compare(nil, nil) }.not_to raise_error
98
87
  end
99
88
 
100
89
  it 'returns the error' do
@@ -1,26 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rspec'
2
4
  require 'cucumber/messages'
3
5
  require_relative '../lib/messages_comparator'
4
6
 
5
7
  describe CCK::MessagesComparator do
6
- subject() { CCK::MessagesComparator }
7
-
8
8
  context 'when executed as part of a CI' do
9
- before do
10
- allow(ENV).to receive(:[]).with('CI').and_return(true)
9
+ before { allow(ENV).to receive(:[]).with('CI').and_return(true) }
10
+
11
+ it 'ignores any detected CI messages' do
12
+ detected_message_ci = Cucumber::Messages::Ci.new(name: 'Some CI')
13
+ detected_message_meta = Cucumber::Messages::Meta.new(ci: detected_message_ci)
14
+ detected_message_envelope = Cucumber::Messages::Envelope.new(meta: detected_message_meta)
15
+
16
+ expected_message_meta = Cucumber::Messages::Meta.new
17
+ expected_message_envelope = Cucumber::Messages::Envelope.new(meta: expected_message_meta)
18
+
19
+ comparator = described_class.new(CCK::KeysChecker, [detected_message_envelope], [expected_message_envelope])
20
+
21
+ expect(comparator.errors).to be_empty
11
22
  end
12
23
 
13
- it 'ignores actual CI related messages' do
14
- found_message_ci = Cucumber::Messages::Ci.new(name: 'Some CI')
15
- found_message_meta = Cucumber::Messages::Meta.new(ci: found_message_ci)
16
- found_message_envelope = Cucumber::Messages::Envelope.new(meta: found_message_meta)
24
+ it 'ignores any expected CI messages' do
25
+ detected_message_meta = Cucumber::Messages::Meta.new
26
+ detected_message_envelope = Cucumber::Messages::Envelope.new(meta: detected_message_meta)
17
27
 
18
- expected_message_meta = Cucumber::Messages::Meta.new()
28
+ expected_message_ci = Cucumber::Messages::Ci.new(name: 'Some CI')
29
+ expected_message_meta = Cucumber::Messages::Meta.new(ci: expected_message_ci)
19
30
  expected_message_envelope = Cucumber::Messages::Envelope.new(meta: expected_message_meta)
20
31
 
21
- comparator = subject.new(CCK::KeysChecker, [found_message_envelope], [expected_message_envelope])
32
+ comparator = described_class.new(CCK::KeysChecker, [detected_message_envelope], [expected_message_envelope])
22
33
 
23
34
  expect(comparator.errors).to be_empty
24
35
  end
25
36
  end
26
- end
37
+ end