cucumber-compatibility-kit 13.0.0 → 13.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a77442c57282b3287863433f7406e85d334313b8f32a7ebfc2ae4794665cd7d
4
- data.tar.gz: b9f629e52616779c3923bdee2dc1cdcdc6074708c04db4dcd3317b458b416113
3
+ metadata.gz: 571624730f6e04d4737391f34e4a8e04001a98d8ea71972b300393d8a3dc24a9
4
+ data.tar.gz: 98687934c3fe1a37a637696b8f362b34882479e4b6cad8630cb04309ffb61f8e
5
5
  SHA512:
6
- metadata.gz: f11fd7556d7d94b758f1802c6a0b93b3e568c3e92b087c151269bb3a2a561a2de3a6d0c7530694945c40692573a8f2c3ff12d6ad2f130ec8be422e16d952eafe
7
- data.tar.gz: 1b41eb113047d8a38ca077e4ce982dd49450c04a32d3dd043c7ff3ad1e0fb0bc04980fc635be9acd16d5c7986fe6677262da645293f0cbfd43cd989d63d36053
6
+ metadata.gz: 6faeb789cf47ac895fcd460fad7d2fff99652e3235b5d45a8d15c283acbd3bcdc35676f51ea2d414804c5822f97c17329653fb398b492b9afbb360731bd72932
7
+ data.tar.gz: fe388e4219711ecf17eefe17eda1085f8b742b48dc194208704880169f8490b25f7031b2e97f660c5dd7df55cf8174df65835cf62e9e35446c6f90461934304f
@@ -3,55 +3,44 @@
3
3
  require 'stringio'
4
4
 
5
5
  # Cucumber-JVM needs to use a Before hook in order to create attachments
6
- Before do
7
- # no-op
8
- end
9
-
10
- def attach_or_embed(world, data, media_type, filename = nil)
11
- # Backward compatibility as the steps are also used by cucumber-ruby 3 which does not support `attach`
12
- world.respond_to?(:attach) ? attach(data, media_type, filename) : embed(data, media_type)
13
- end
6
+ Before { nil }
14
7
 
15
8
  When('the string {string} is attached as {string}') do |text, media_type|
16
- attach_or_embed(self, text, media_type)
9
+ attach(text, media_type)
17
10
  end
18
11
 
19
12
  When('the string {string} is logged') do |text|
20
- # Backward compatibility
21
- self.respond_to?(:log) ? log(text) : puts(text)
22
- end
23
-
24
- When('the following string is attached as {string}:') do |media_type, doc_string|
25
- attach_or_embed(self, doc_string, media_type)
13
+ log(text)
26
14
  end
27
15
 
28
16
  When('text with ANSI escapes is logged') do
29
- text = "This displays a \x1b[31mr\x1b[0m\x1b[91ma\x1b[0m\x1b[33mi\x1b[0m\x1b[32mn\x1b[0m\x1b[34mb\x1b[0m\x1b[95mo\x1b[0m\x1b[35mw\x1b[0m"
17
+ log("This displays a \x1b[31mr\x1b[0m\x1b[91ma\x1b[0m\x1b[33mi\x1b[0m\x1b[32mn\x1b[0m\x1b[34mb\x1b[0m\x1b[95mo\x1b[0m\x1b[35mw\x1b[0m")
18
+ end
30
19
 
31
- self.respond_to?(:log) ? log(text) : puts(text)
20
+ When('the following string is attached as {string}:') do |media_type, doc_string|
21
+ attach(doc_string, media_type)
32
22
  end
33
23
 
34
24
  When('an array with {int} bytes is attached as {string}') do |size, media_type|
35
- data = (0..size-1).map {|i| [i].pack('C') }.join
36
- attach_or_embed(self, data, media_type)
25
+ data = (0..size-1).map { |i| [i].pack('C') }.join
26
+ attach(data, media_type)
37
27
  end
38
28
 
39
29
  When('a stream with {int} bytes are attached as {string}') do |size, media_type|
40
30
  stream = StringIO.new
41
31
  stream.puts (0..size).map(&:to_s).join('')
42
32
  stream.seek(0)
43
-
44
- attach_or_embed(self, stream, media_type)
33
+ attach(stream, media_type)
45
34
  end
46
35
 
47
36
  When('a JPEG image is attached') do
48
- attach_or_embed(self, File.open("#{__dir__}/cucumber.jpeg"), 'image/jpeg')
37
+ attach(File.open("#{__dir__}/cucumber.jpeg"), 'image/jpeg')
49
38
  end
50
39
 
51
40
  When('the {word} png is attached') do |filename|
52
- attach_or_embed(self, File.open("#{__dir__}/#{filename}"), 'image/png')
41
+ attach(File.open("#{__dir__}/#{filename}"), 'image/png')
53
42
  end
54
43
 
55
44
  When('a PDF document is attached and renamed') do
56
- attach_or_embed(self, File.open("#{__dir__}/document.pdf"), 'document/pdf', 'renamed.pdf')
45
+ attach(File.open("#{__dir__}/document.pdf"), 'document/pdf', 'renamed.pdf')
57
46
  end
@@ -1,10 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- def attach_or_embed(world, data, media_type)
4
- # Backward compatibility as the steps are also used by cucumber-ruby 3 which does not support `attach`
5
- world.respond_to?(:attach) ? attach(data, media_type) : embed(data, media_type)
6
- end
7
-
8
3
  Before do
9
4
  # no-op
10
5
  end
@@ -30,5 +25,5 @@ After('@some-tag or @some-other-tag') do
30
25
  end
31
26
 
32
27
  After('@with-attachment') do
33
- attach_or_embed(self, File.open("#{__dir__}/cucumber.svg"), 'image/svg+xml')
28
+ attach(File.open("#{__dir__}/cucumber.svg"), 'image/svg+xml')
34
29
  end
@@ -1,19 +1,19 @@
1
1
  Feature: Skipping scenarios
2
2
 
3
3
  Hooks and step definitions are able to signal at runtime that the scenario should
4
- be skipped by returning or throwing a particular value.
4
+ be skipped by raising a particular kind of exception status (For example PENDING or SKIPPED).
5
5
 
6
- This can be useful when e.g. the current environment doesn't have the right conditions
7
- for running the scenario.
6
+ This can be useful in certain situations e.g. the current environment doesn't have
7
+ the right conditions for running a particular scenario.
8
8
 
9
9
  @skip
10
10
  Scenario: Skipping from a Before hook
11
- Given a step that we expect to be skipped
11
+ Given a step that is skipped
12
12
 
13
13
  Scenario: Skipping from a step doesn't affect the previous steps
14
- Given an implemented step
15
- When a step that skips
14
+ Given a step that does not skip
15
+ And I skip a step
16
16
 
17
17
  Scenario: Skipping from a step causes the rest of the scenario to be skipped
18
- Given a step that skips
19
- When a step that we expect to be skipped
18
+ Given I skip a step
19
+ And a step that is skipped
@@ -1,12 +1,12 @@
1
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
- {"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
- {"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
- {"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"}}
5
- {"pickle":{"astNodeIds":["9"],"id":"17","language":"en","name":"Skipping from a step doesn't affect the previous steps","steps":[{"astNodeIds":["7"],"id":"15","text":"an implemented step","type":"Context"},{"astNodeIds":["8"],"id":"16","text":"a step that skips","type":"Action"}],"tags":[],"uri":"samples/skipped/skipped.feature"}}
6
- {"pickle":{"astNodeIds":["12"],"id":"20","language":"en","name":"Skipping from a step causes the rest of the scenario to be skipped","steps":[{"astNodeIds":["10"],"id":"18","text":"a step that skips","type":"Context"},{"astNodeIds":["11"],"id":"19","text":"a step that we expect to be skipped","type":"Action"}],"tags":[],"uri":"samples/skipped/skipped.feature"}}
7
- {"stepDefinition":{"id":"1","pattern":{"source":"an implemented step","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":7},"uri":"samples/skipped/skipped.feature.ts"}}}
8
- {"stepDefinition":{"id":"2","pattern":{"source":"a step that we expect to be skipped","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":11},"uri":"samples/skipped/skipped.feature.ts"}}}
9
- {"stepDefinition":{"id":"3","pattern":{"source":"a step that skips","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":15},"uri":"samples/skipped/skipped.feature.ts"}}}
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 raising a particular kind of exception status (For example PENDING or SKIPPED).\n\n This can be useful in certain situations e.g. the current environment doesn't have\n the right conditions for running a particular scenario.\n\n @skip\n Scenario: Skipping from a Before hook\n Given a step that is skipped\n\n Scenario: Skipping from a step doesn't affect the previous steps\n Given a step that does not skip\n And I skip a step\n\n Scenario: Skipping from a step causes the rest of the scenario to be skipped\n Given I skip a step\n And a step that is skipped\n","mediaType":"text/x.cucumber.gherkin+plain","uri":"samples/skipped/skipped.feature"}}
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 is 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":"a step that does not skip"},{"id":"8","keyword":"And ","keywordType":"Conjunction","location":{"column":5,"line":15},"text":"I skip a step"}],"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":"I skip a step"},{"id":"11","keyword":"And ","keywordType":"Conjunction","location":{"column":5,"line":19},"text":"a step that is skipped"}],"tags":[]}}],"description":" Hooks and step definitions are able to signal at runtime that the scenario should\n be skipped by raising a particular kind of exception status (For example PENDING or SKIPPED).\n\n This can be useful in certain situations e.g. the current environment doesn't have\n the right conditions for running a particular scenario.","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Skipping scenarios","tags":[]},"uri":"samples/skipped/skipped.feature"}}
4
+ {"pickle":{"astNodeIds":["6"],"id":"14","language":"en","name":"Skipping from a Before hook","steps":[{"astNodeIds":["4"],"id":"13","text":"a step that is skipped","type":"Context"}],"tags":[{"astNodeId":"5","name":"@skip"}],"uri":"samples/skipped/skipped.feature"}}
5
+ {"pickle":{"astNodeIds":["9"],"id":"17","language":"en","name":"Skipping from a step doesn't affect the previous steps","steps":[{"astNodeIds":["7"],"id":"15","text":"a step that does not skip","type":"Context"},{"astNodeIds":["8"],"id":"16","text":"I skip a step","type":"Context"}],"tags":[],"uri":"samples/skipped/skipped.feature"}}
6
+ {"pickle":{"astNodeIds":["12"],"id":"20","language":"en","name":"Skipping from a step causes the rest of the scenario to be skipped","steps":[{"astNodeIds":["10"],"id":"18","text":"I skip a step","type":"Context"},{"astNodeIds":["11"],"id":"19","text":"a step that is skipped","type":"Context"}],"tags":[],"uri":"samples/skipped/skipped.feature"}}
7
+ {"stepDefinition":{"id":"1","pattern":{"source":"a step that does not skip","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":7},"uri":"samples/skipped/skipped.feature.ts"}}}
8
+ {"stepDefinition":{"id":"2","pattern":{"source":"a step that is skipped","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":11},"uri":"samples/skipped/skipped.feature.ts"}}}
9
+ {"stepDefinition":{"id":"3","pattern":{"source":"I skip a step","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":15},"uri":"samples/skipped/skipped.feature.ts"}}}
10
10
  {"hook":{"id":"0","sourceReference":{"location":{"line":3},"uri":"samples/skipped/skipped.feature.ts"},"tagExpression":"@skip"}}
11
11
  {"testRunStarted":{"timestamp":{"nanos":0,"seconds":0}}}
12
12
  {"testCase":{"id":"23","pickleId":"14","testSteps":[{"hookId":"0","id":"21"},{"id":"22","pickleStepId":"13","stepDefinitionIds":["2"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}]}}
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Before('@skip') do
4
- 'skipped'
4
+ skip_this_scenario('')
5
5
  end
6
6
 
7
- Given('an implemented step') do
7
+ Given('a step that does not skip') do
8
8
  # no-op
9
9
  end
10
10
 
11
- Given('a step that we expect to be skipped') do
11
+ Given('a step that is skipped') do
12
12
  # no-op
13
13
  end
14
14
 
15
- Given('a step that skips') do
16
- 'skipped'
15
+ Given('I skip a step') do
16
+ skip_this_scenario('')
17
17
  end
@@ -1,11 +1,9 @@
1
1
  Feature: Stack traces
2
- Nothing beats stack traces when it comes to diagnosing the source of a bug.
3
- Cucumber provides helpful stack traces that:
4
-
5
- - Include a stack frame from the Gherkin document
6
- - Remove uninteresting frames by default
2
+ Stack traces can help you diagnose the source of a bug.
3
+ Cucumber provides helpful stack traces that includes the stack frames from the
4
+ Gherkin document and remove uninteresting frames by default
7
5
 
8
- The first line of the stack trace must contain the feature file.
6
+ The first line of the stack trace will contain a reference to the feature file.
9
7
 
10
8
  Scenario: A failing step
11
9
  When a step throws an exception
@@ -1,12 +1,12 @@
1
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
- {"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
- {"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"}}
2
+ {"source":{"data":"Feature: Stack traces\n Stack traces can help you diagnose the source of a bug.\n Cucumber provides helpful stack traces that includes the stack frames from the\n Gherkin document and remove uninteresting frames by default\n\n The first line of the stack trace will contain a reference to 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
+ {"gherkinDocument":{"comments":[],"feature":{"children":[{"scenario":{"description":"","examples":[],"id":"2","keyword":"Scenario","location":{"column":3,"line":8},"name":"A failing step","steps":[{"id":"1","keyword":"When ","keywordType":"Action","location":{"column":5,"line":9},"text":"a step throws an exception"}],"tags":[]}}],"description":" Stack traces can help you diagnose the source of a bug.\n Cucumber provides helpful stack traces that includes the stack frames from the\n Gherkin document and remove uninteresting frames by default\n\n The first line of the stack trace will contain a reference to 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"}}
5
5
  {"stepDefinition":{"id":"0","pattern":{"source":"a step throws an exception","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":3},"uri":"samples/stack-traces/stack-traces.feature.ts"}}}
6
6
  {"testRunStarted":{"timestamp":{"nanos":0,"seconds":0}}}
7
7
  {"testCase":{"id":"6","pickleId":"4","testSteps":[{"id":"5","pickleStepId":"3","stepDefinitionIds":["0"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}]}}
8
8
  {"testCaseStarted":{"attempt":0,"id":"7","testCaseId":"6","timestamp":{"nanos":1000000,"seconds":0}}}
9
9
  {"testStepStarted":{"testCaseStartedId":"7","testStepId":"5","timestamp":{"nanos":2000000,"seconds":0}}}
10
- {"testStepFinished":{"testCaseStartedId":"7","testStepId":"5","testStepResult":{"duration":{"nanos":1000000,"seconds":0},"exception":{"message":"BOOM","type":"Error"},"message":"BOOM\nsamples/stack-traces/stack-traces.feature:11","status":"FAILED"},"timestamp":{"nanos":3000000,"seconds":0}}}
10
+ {"testStepFinished":{"testCaseStartedId":"7","testStepId":"5","testStepResult":{"duration":{"nanos":1000000,"seconds":0},"exception":{"message":"BOOM","type":"Error"},"message":"BOOM\nsamples/stack-traces/stack-traces.feature:9","status":"FAILED"},"timestamp":{"nanos":3000000,"seconds":0}}}
11
11
  {"testCaseFinished":{"testCaseStartedId":"7","timestamp":{"nanos":4000000,"seconds":0},"willBeRetried":false}}
12
12
  {"testRunFinished":{"success":false,"timestamp":{"nanos":5000000,"seconds":0}}}
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  When('a step throws an exception') do
4
- raise StandardError, 'An exception is raised here'
4
+ raise 'BOOM'
5
5
  end
@@ -1,17 +1,16 @@
1
1
  Feature: Undefined steps
2
2
 
3
3
  At runtime, Cucumber may encounter a step in a scenario that it cannot match to a
4
- step definition. In these cases, the scenario cannot run and so the step status
5
- will be UNDEFINED, with subsequent steps being skipped and the overall result treated
6
- as a failure.
4
+ step definition. In these cases, the scenario is not able to run and so the step status
5
+ will be UNDEFINED, with subsequent steps being SKIPPED and the overall result will be FAILURE
7
6
 
8
- Scenario: Undefined step causes failure
9
- Given a step that isnt implemented yet
7
+ Scenario: An undefined step causes a failure
8
+ Given a step that is yet to be defined
10
9
 
11
10
  Scenario: Steps before undefined steps are executed
12
11
  Given an implemented step
13
- When a step that isnt implemented yet
12
+ And a step that is yet to be defined
14
13
 
15
14
  Scenario: Steps after undefined steps are skipped
16
- Given a step that isnt implemented yet
17
- Then a step that we expect to be skipped
15
+ Given a step that is yet to be defined
16
+ And a step that will be skipped
@@ -1,11 +1,11 @@
1
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
- {"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
- {"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
- {"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"}}
5
- {"pickle":{"astNodeIds":["6"],"id":"14","language":"en","name":"Steps before undefined steps are executed","steps":[{"astNodeIds":["4"],"id":"12","text":"an implemented step","type":"Context"},{"astNodeIds":["5"],"id":"13","text":"a step that isnt implemented yet","type":"Action"}],"tags":[],"uri":"samples/undefined/undefined.feature"}}
6
- {"pickle":{"astNodeIds":["9"],"id":"17","language":"en","name":"Steps after undefined steps are skipped","steps":[{"astNodeIds":["7"],"id":"15","text":"a step that isnt implemented yet","type":"Context"},{"astNodeIds":["8"],"id":"16","text":"a step that we expect to be skipped","type":"Outcome"}],"tags":[],"uri":"samples/undefined/undefined.feature"}}
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 is not able to run and so the step status\n will be UNDEFINED, with subsequent steps being SKIPPED and the overall result will be FAILURE\n\n Scenario: An undefined step causes a failure\n Given a step that is yet to be defined\n\n Scenario: Steps before undefined steps are executed\n Given an implemented step\n And a step that is yet to be defined\n\n Scenario: Steps after undefined steps are skipped\n Given a step that is yet to be defined\n And a step that will be skipped\n","mediaType":"text/x.cucumber.gherkin+plain","uri":"samples/undefined/undefined.feature"}}
3
+ {"gherkinDocument":{"comments":[],"feature":{"children":[{"scenario":{"description":"","examples":[],"id":"3","keyword":"Scenario","location":{"column":3,"line":7},"name":"An undefined step causes a failure","steps":[{"id":"2","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":8},"text":"a step that is yet to be defined"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"6","keyword":"Scenario","location":{"column":3,"line":10},"name":"Steps before undefined steps are executed","steps":[{"id":"4","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":11},"text":"an implemented step"},{"id":"5","keyword":"And ","keywordType":"Conjunction","location":{"column":5,"line":12},"text":"a step that is yet to be defined"}],"tags":[]}},{"scenario":{"description":"","examples":[],"id":"9","keyword":"Scenario","location":{"column":3,"line":14},"name":"Steps after undefined steps are skipped","steps":[{"id":"7","keyword":"Given ","keywordType":"Context","location":{"column":5,"line":15},"text":"a step that is yet to be defined"},{"id":"8","keyword":"And ","keywordType":"Conjunction","location":{"column":5,"line":16},"text":"a step that will 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 is not able to run and so the step status\n will be UNDEFINED, with subsequent steps being SKIPPED and the overall result will be FAILURE","keyword":"Feature","language":"en","location":{"column":1,"line":1},"name":"Undefined steps","tags":[]},"uri":"samples/undefined/undefined.feature"}}
4
+ {"pickle":{"astNodeIds":["3"],"id":"11","language":"en","name":"An undefined step causes a failure","steps":[{"astNodeIds":["2"],"id":"10","text":"a step that is yet to be defined","type":"Context"}],"tags":[],"uri":"samples/undefined/undefined.feature"}}
5
+ {"pickle":{"astNodeIds":["6"],"id":"14","language":"en","name":"Steps before undefined steps are executed","steps":[{"astNodeIds":["4"],"id":"12","text":"an implemented step","type":"Context"},{"astNodeIds":["5"],"id":"13","text":"a step that is yet to be defined","type":"Context"}],"tags":[],"uri":"samples/undefined/undefined.feature"}}
6
+ {"pickle":{"astNodeIds":["9"],"id":"17","language":"en","name":"Steps after undefined steps are skipped","steps":[{"astNodeIds":["7"],"id":"15","text":"a step that is yet to be defined","type":"Context"},{"astNodeIds":["8"],"id":"16","text":"a step that will be skipped","type":"Context"}],"tags":[],"uri":"samples/undefined/undefined.feature"}}
7
7
  {"stepDefinition":{"id":"0","pattern":{"source":"an implemented step","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":3},"uri":"samples/undefined/undefined.feature.ts"}}}
8
- {"stepDefinition":{"id":"1","pattern":{"source":"a step that we expect to be skipped","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":7},"uri":"samples/undefined/undefined.feature.ts"}}}
8
+ {"stepDefinition":{"id":"1","pattern":{"source":"a step that will be skipped","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"location":{"line":7},"uri":"samples/undefined/undefined.feature.ts"}}}
9
9
  {"testRunStarted":{"timestamp":{"nanos":0,"seconds":0}}}
10
10
  {"testCase":{"id":"19","pickleId":"11","testSteps":[{"id":"18","pickleStepId":"10","stepDefinitionIds":[],"stepMatchArgumentsLists":[]}]}}
11
11
  {"testCase":{"id":"22","pickleId":"14","testSteps":[{"id":"20","pickleStepId":"12","stepDefinitionIds":["0"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"21","pickleStepId":"13","stepDefinitionIds":[],"stepMatchArgumentsLists":[]}]}}
@@ -4,6 +4,6 @@ Given('an implemented step') do
4
4
  # no-op
5
5
  end
6
6
 
7
- Given('a step that we expect to be skipped') do
7
+ Given('a step that will be skipped') do
8
8
  # no-op
9
9
  end
@@ -3,4 +3,4 @@ Feature: Parameter Types
3
3
  an unknown parameter type, but the suite will run.
4
4
 
5
5
  Scenario: undefined parameter type
6
- Given CDG is closed because of a strike
6
+ Given CDG is closed because of a strike
@@ -1,5 +1,5 @@
1
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
- {"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"}}
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\n","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"}}
5
5
  {"undefinedParameterType":{"expression":"{airport} is closed because of a strike","name":"airport"}}
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Given('{airport} is closed because of a strike') do |airport|
4
- raise StandardError, 'Should not be called because airport type not defined'
3
+ Given('{airport} is closed because of a strike') do |_airport|
4
+ raise 'Should not be called because airport parameter type has not been defined'
5
5
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CCK
4
+ module Helpers
5
+ def message_type(message)
6
+ message.to_h.each do |key, value|
7
+ return key unless value.nil?
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CCK
4
+ class KeysChecker
5
+ def self.compare(detected, expected)
6
+ new(detected, expected).compare
7
+ end
8
+
9
+ attr_reader :detected, :expected
10
+
11
+ def initialize(detected, expected)
12
+ @detected = detected
13
+ @expected = expected
14
+ end
15
+
16
+ def compare
17
+ return [] if identical_keys?
18
+
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?
21
+ errors
22
+ rescue StandardError => e
23
+ ["Unexpected error: #{e.message}"]
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
63
+ end
64
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'keys_checker'
4
+ require_relative 'helpers'
5
+
6
+ module CCK
7
+ class MessagesComparator
8
+ include Helpers
9
+
10
+ def initialize(validator, detected, expected)
11
+ @all_errors = []
12
+ @compared = []
13
+ @validator = validator
14
+
15
+ compare(detected, expected)
16
+ end
17
+
18
+ def errors
19
+ @all_errors.flatten
20
+ end
21
+
22
+ private
23
+
24
+ def compare(detected, expected)
25
+ detected_by_type = messages_by_type(detected)
26
+ expected_by_type = messages_by_type(expected)
27
+
28
+ detected_by_type.keys.each do |type|
29
+ compare_list(detected_by_type[type], expected_by_type[type])
30
+ rescue StandardError => e
31
+ @all_errors << "Error while comparing #{type}: #{e.message}"
32
+ end
33
+ end
34
+
35
+ def messages_by_type(messages)
36
+ by_type = Hash.new { |h, k| h[k] = [] }
37
+ messages.each do |msg|
38
+ by_type[message_type(msg)] << remove_envelope(msg)
39
+ end
40
+ by_type
41
+ end
42
+
43
+ def remove_envelope(message)
44
+ message.send(message_type(message))
45
+ end
46
+
47
+ def compare_list(detected, expected)
48
+ detected.each_with_index do |message, index|
49
+ compare_message(message, expected[index])
50
+ end
51
+ end
52
+
53
+ def compare_message(detected, expected)
54
+ return if not_message?(detected)
55
+ return if ignorable?(detected)
56
+ return if incomparable?(detected)
57
+
58
+ @all_errors << @validator.compare(detected, expected)
59
+ @compared << detected.class.name
60
+ compare_sub_messages(detected, expected)
61
+ end
62
+
63
+ def not_message?(detected)
64
+ !detected.is_a?(Cucumber::Messages::Message)
65
+ end
66
+
67
+ # These messages we need to ignore because they are too large or they feature timestamps which always vary
68
+ def ignorable?(detected)
69
+ too_large_message?(detected) || time_message?(detected)
70
+ end
71
+
72
+ def too_large_message?(detected)
73
+ detected.is_a?(Cucumber::Messages::GherkinDocument) || detected.is_a?(Cucumber::Messages::Pickle)
74
+ end
75
+
76
+ def time_message?(detected)
77
+ detected.is_a?(Cucumber::Messages::Timestamp) || detected.is_a?(Cucumber::Messages::Duration)
78
+ end
79
+
80
+ # These messages we need to ignore because they are often not of identical shape/value
81
+ def incomparable?(detected)
82
+ detected.is_a?(Cucumber::Messages::Ci) || detected.is_a?(Cucumber::Messages::Git)
83
+ end
84
+
85
+ def compare_sub_messages(detected, expected)
86
+ return unless expected.respond_to? :to_h
87
+ expected.to_h.keys.each do |key|
88
+ value = expected.send(key)
89
+ if value.is_a?(Array)
90
+ compare_list(detected.send(key), value)
91
+ else
92
+ compare_message(detected.send(key), value)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'shared_examples'
4
+
5
+ module Cucumber::CompatibilityKit
6
+ class << self
7
+ def all_examples
8
+ gherkin_examples + markdown_examples
9
+ end
10
+
11
+ def gherkin_examples
12
+ Dir
13
+ .entries(examples_path)
14
+ .select do |file|
15
+ folder = File.join(examples_path, file)
16
+
17
+ file != '.' && file != '..' &&
18
+ File.directory?(folder) &&
19
+ gherkin_example?(folder)
20
+ end
21
+ end
22
+
23
+ def markdown_examples
24
+ Dir
25
+ .entries(examples_path)
26
+ .select do |file|
27
+ folder = File.join(examples_path, file)
28
+
29
+ file != '.' && file != '..' &&
30
+ File.directory?(folder) &&
31
+ markdown_example?(folder)
32
+ end
33
+ end
34
+
35
+ def examples_path
36
+ File.expand_path("#{File.dirname(__FILE__)}/../../features/")
37
+ end
38
+
39
+ def example_path(example_name)
40
+ path = File.join(examples_path, example_name)
41
+
42
+ return path if File.directory?(path)
43
+
44
+ raise ArgumentError.new
45
+ end
46
+
47
+ private
48
+
49
+ def gherkin_example?(example_folder)
50
+ Dir.entries(example_folder).select { |file| File.extname(file) == '.feature' }.count > 0
51
+ end
52
+
53
+ def markdown_example?(example_folder)
54
+ Dir.entries(example_folder).select { |file| File.extname(file) == '.md' }.count > 0
55
+ end
56
+ end
57
+ end