gherkin_system 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +17 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +174 -0
- data/lib/gherkin_system/checker.rb +58 -0
- data/lib/gherkin_system/cli.rb +42 -0
- data/lib/gherkin_system/configuration.rb +64 -0
- data/lib/gherkin_system/data_table.rb +24 -0
- data/lib/gherkin_system/errors.rb +95 -0
- data/lib/gherkin_system/executor.rb +95 -0
- data/lib/gherkin_system/feature_loader.rb +52 -0
- data/lib/gherkin_system/hooks.rb +86 -0
- data/lib/gherkin_system/parameter_registry.rb +34 -0
- data/lib/gherkin_system/parser.rb +122 -0
- data/lib/gherkin_system/rails.rb +3 -0
- data/lib/gherkin_system/railtie.rb +7 -0
- data/lib/gherkin_system/scenario.rb +37 -0
- data/lib/gherkin_system/scenario_run.rb +42 -0
- data/lib/gherkin_system/snippet.rb +23 -0
- data/lib/gherkin_system/step_definition.rb +53 -0
- data/lib/gherkin_system/step_registry.rb +47 -0
- data/lib/gherkin_system/steps.rb +39 -0
- data/lib/gherkin_system/tag_filter.rb +24 -0
- data/lib/gherkin_system/test_class_builder.rb +82 -0
- data/lib/gherkin_system/version.rb +6 -0
- data/lib/gherkin_system.rb +79 -0
- data/lib/rails/commands/gherkin/gherkin_command.rb +68 -0
- data/sig/gherkin_system.rbs +64 -0
- data/skills/gherkin-system/SKILL.md +128 -0
- metadata +139 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/command"
|
|
4
|
+
require "gherkin_system"
|
|
5
|
+
|
|
6
|
+
module Rails
|
|
7
|
+
module Command
|
|
8
|
+
# Facade over `bin/rails test`. Subcommands are methods, matching `test:system`.
|
|
9
|
+
class GherkinCommand < Base
|
|
10
|
+
class_option :tags, type: :string, desc: "Cucumber tag expression"
|
|
11
|
+
|
|
12
|
+
desc "gherkin [PATH]", "Run Gherkin system tests"
|
|
13
|
+
def perform(*args)
|
|
14
|
+
prepare!(args)
|
|
15
|
+
Rails::Command.invoke("test", [GherkinSystem::Cli.test_file, *args])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc "check [PATH]", "Validate Gherkin features without a browser"
|
|
19
|
+
def check(*args)
|
|
20
|
+
prepare!(args)
|
|
21
|
+
load_definitions
|
|
22
|
+
report(GherkinSystem::Checker.call)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc "list [PATH]", "List compiled Gherkin scenarios"
|
|
26
|
+
def list(*args)
|
|
27
|
+
prepare!(args)
|
|
28
|
+
scenarios.each { |scenario| puts scenario_line(scenario) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def prepare!(args)
|
|
34
|
+
GherkinSystem::Cli.prepare_test_env!
|
|
35
|
+
GherkinSystem::Cli.apply_filters!(args, tags: options[:tags])
|
|
36
|
+
boot_application!
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def load_definitions
|
|
40
|
+
test_dir = Rails.root.join("test").to_s
|
|
41
|
+
$LOAD_PATH.unshift(test_dir) unless $LOAD_PATH.include?(test_dir)
|
|
42
|
+
path = GherkinSystem::Cli.test_file
|
|
43
|
+
raise GherkinSystem::ConfigurationError, "Missing #{path}" unless File.exist?(path)
|
|
44
|
+
|
|
45
|
+
require path
|
|
46
|
+
rescue GherkinSystem::Error => e
|
|
47
|
+
warn e.message
|
|
48
|
+
exit!(1)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def report(result)
|
|
52
|
+
io = result.ok? ? $stdout : $stderr
|
|
53
|
+
io.puts(result.ok? ? "Gherkin check passed" : result.report)
|
|
54
|
+
io.flush
|
|
55
|
+
exit!(result.ok? ? 0 : 1)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def scenarios
|
|
59
|
+
loaded = GherkinSystem::FeatureLoader.load
|
|
60
|
+
GherkinSystem::TagFilter.apply(loaded, GherkinSystem.config.tags)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def scenario_line(scenario)
|
|
64
|
+
"#{scenario.uri}:#{scenario.line} #{scenario.test_name}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module GherkinSystem
|
|
2
|
+
VERSION: String
|
|
3
|
+
|
|
4
|
+
def self.config: () -> Configuration
|
|
5
|
+
def self.configure: () { (Configuration) -> void } -> void
|
|
6
|
+
def self.reset_configuration!: () -> void
|
|
7
|
+
def self.load!: (?String glob, ?base: Class?) -> Array[Class]
|
|
8
|
+
def self.step_registry: () -> StepRegistry
|
|
9
|
+
def self.parameter_registry: () -> ParameterRegistry
|
|
10
|
+
def self.hook_registry: () -> HookRegistry
|
|
11
|
+
|
|
12
|
+
class Configuration
|
|
13
|
+
attr_reader step_modules: Array[Module]
|
|
14
|
+
attr_writer features: String
|
|
15
|
+
attr_writer base_test_class: Class?
|
|
16
|
+
attr_writer strict: bool
|
|
17
|
+
attr_writer test_file: String
|
|
18
|
+
|
|
19
|
+
def features: () -> String
|
|
20
|
+
def base_test_class: () -> Class?
|
|
21
|
+
def strict: () -> bool
|
|
22
|
+
def test_file: () -> String
|
|
23
|
+
def tags: () -> String?
|
|
24
|
+
def tags=: (String?) -> void
|
|
25
|
+
def include_steps: (Module) -> void
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class Error < StandardError
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class ConfigurationError < Error
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class CompilationError < Error
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class DuplicateStep < Error
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class UndefinedStep < Error
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class AmbiguousStep < Error
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class StepFailure < Error
|
|
47
|
+
attr_reader cause: Exception
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class DataTable
|
|
51
|
+
def initialize: (Array[Array[String]]) -> void
|
|
52
|
+
def raw: () -> Array[Array[String]]
|
|
53
|
+
def hashes: () -> Array[Hash[String, String]]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Checker
|
|
57
|
+
def self.call: (?String? glob) -> Result
|
|
58
|
+
|
|
59
|
+
class Result
|
|
60
|
+
def ok?: () -> bool
|
|
61
|
+
def report: () -> String
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gherkin-system
|
|
3
|
+
description: >-
|
|
4
|
+
Write and run Rails system tests as Gherkin features with the gherkin_system
|
|
5
|
+
gem. Use when adding or changing user-facing Rails behavior, acceptance
|
|
6
|
+
tests, .feature files, step definitions, or bin/rails gherkin commands.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# gherkin_system
|
|
10
|
+
|
|
11
|
+
Gherkin describes the behavior. Rails runs it. Each scenario becomes a Minitest method on the app's `ApplicationSystemTestCase`.
|
|
12
|
+
|
|
13
|
+
Do not add cucumber-rails, a Cucumber World, or a second test runner. Do not use this skill to change the gem's own compiler. Gem development follows `AGENTS.md`.
|
|
14
|
+
|
|
15
|
+
## Add a scenario
|
|
16
|
+
|
|
17
|
+
1. Write the feature under `features/system/**/*.feature`.
|
|
18
|
+
2. Bind steps in `test/support/gherkin/*_steps.rb`.
|
|
19
|
+
3. Require that file from `test/system/gherkin_test.rb` before `GherkinSystem.load!`.
|
|
20
|
+
4. Run `bin/rails gherkin:check`.
|
|
21
|
+
5. Run the scenario with `bin/rails gherkin path/to/file.feature:LINE`.
|
|
22
|
+
|
|
23
|
+
Create the loader once if it is missing:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
# test/system/gherkin_test.rb
|
|
27
|
+
require "application_system_test_case"
|
|
28
|
+
require_relative "../support/gherkin/checkout_steps"
|
|
29
|
+
require "gherkin_system/rails"
|
|
30
|
+
|
|
31
|
+
GherkinSystem.configure do |config|
|
|
32
|
+
config.include_steps CheckoutSteps
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
GherkinSystem.load!(base: ApplicationSystemTestCase)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`base:` must be the application's system test class. The generated tests subclass it.
|
|
39
|
+
|
|
40
|
+
## Write behavior
|
|
41
|
+
|
|
42
|
+
One scenario proves one outcome. Name it for the condition and the result.
|
|
43
|
+
|
|
44
|
+
```gherkin
|
|
45
|
+
Feature: Subscription purchase
|
|
46
|
+
|
|
47
|
+
Scenario: Customer purchases Pro
|
|
48
|
+
Given I am signed in
|
|
49
|
+
When I purchase the "Pro" plan
|
|
50
|
+
Then my subscription should be active
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Use a Scenario Outline only when each row is the same rule with different data. Each row becomes its own test.
|
|
54
|
+
|
|
55
|
+
Assert the outcome the user was promised. Drive it through the browser and the real application. Do not mock models, controllers, jobs, or mailers to make the scenario pass.
|
|
56
|
+
|
|
57
|
+
## Bind steps
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
module CheckoutSteps
|
|
61
|
+
extend GherkinSystem::Steps
|
|
62
|
+
|
|
63
|
+
Given("I am signed in") do
|
|
64
|
+
sign_in users(:customer)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
When("I purchase the {string} plan") do |plan|
|
|
68
|
+
visit plans_path
|
|
69
|
+
click_on plan
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
Then("my subscription should be active") do
|
|
73
|
+
assert_text "Purchase complete"
|
|
74
|
+
assert_predicate users(:customer).reload.subscription, :active?
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- `Given`, `When`, `Then`, `And`, and `But` share one registry.
|
|
80
|
+
- Blocks run with `instance_exec` on the system test. `visit`, fixtures, routes, assertions, and `@ivars` are that test instance.
|
|
81
|
+
- Call `config.include_steps` when the module also defines helper methods.
|
|
82
|
+
- Prefer Cucumber Expressions (`{string}`, `{int}`). Use a regex only to match an existing definition.
|
|
83
|
+
- Data tables arrive as an object with `#hashes` (string keys) and `#raw`. Doc strings arrive as the content string.
|
|
84
|
+
|
|
85
|
+
## Hooks
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
module CheckoutHooks
|
|
89
|
+
extend GherkinSystem::Hooks
|
|
90
|
+
|
|
91
|
+
Before("@admin") do
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
After do |scenario|
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
Around("@external") do |scenario|
|
|
98
|
+
scenario.run
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Require the hook file before `load!`. Rails `setup` runs before these hooks. Rails `teardown` and failure screenshots run after them. An `Around` hook must call `scenario.run`.
|
|
104
|
+
|
|
105
|
+
## Commands
|
|
106
|
+
|
|
107
|
+
| Command | Use |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `bin/rails gherkin:check` | Parse and resolve steps. No browser. Run this before executing a scenario. |
|
|
110
|
+
| `bin/rails gherkin PATH:LINE` | Run the scenario at that line. |
|
|
111
|
+
| `bin/rails gherkin --tags "@critical and not @slow"` | Cucumber tag expression. |
|
|
112
|
+
| `bin/rails gherkin:list` | Show compiled scenarios. |
|
|
113
|
+
| `bin/rails test:system` | Run every system test, including compiled scenarios. |
|
|
114
|
+
|
|
115
|
+
`GHERKIN_TAGS` left set in the environment also filters `bin/rails test:system`. Unset it to compile every scenario.
|
|
116
|
+
|
|
117
|
+
## When check fails
|
|
118
|
+
|
|
119
|
+
- Undefined step: add the suggested definition, then re-run check.
|
|
120
|
+
- Ambiguous step: delete or narrow one of the matching definitions.
|
|
121
|
+
- Duplicate pattern: the same string or regex is registered twice.
|
|
122
|
+
- Invalid Gherkin or tag expression: the message includes the feature path.
|
|
123
|
+
|
|
124
|
+
A missing step fails that scenario before the driver starts. Other scenarios still run.
|
|
125
|
+
|
|
126
|
+
## Done
|
|
127
|
+
|
|
128
|
+
`gherkin:check` exits 0, and the scenario exits 0 through `bin/rails gherkin` or `bin/rails test:system`. A check or execution that cannot run is a failure, not a skipped acceptance test.
|
metadata
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: gherkin_system
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- David Paluy
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: cucumber-cucumber-expressions
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '17'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '21'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '17'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '21'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: cucumber-gherkin
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '28'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '40'
|
|
42
|
+
type: :runtime
|
|
43
|
+
prerelease: false
|
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '28'
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '40'
|
|
52
|
+
- !ruby/object:Gem::Dependency
|
|
53
|
+
name: cucumber-tag-expressions
|
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '6'
|
|
59
|
+
- - "<"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '12'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '6'
|
|
69
|
+
- - "<"
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '12'
|
|
72
|
+
description: gherkin_system turns Gherkin scenarios into Minitest methods on the application's
|
|
73
|
+
ApplicationSystemTestCase. Rails owns execution. Gherkin describes behavior.
|
|
74
|
+
email:
|
|
75
|
+
- dpaluy@users.noreply.github.com
|
|
76
|
+
executables: []
|
|
77
|
+
extensions: []
|
|
78
|
+
extra_rdoc_files:
|
|
79
|
+
- CHANGELOG.md
|
|
80
|
+
- LICENSE.txt
|
|
81
|
+
- README.md
|
|
82
|
+
files:
|
|
83
|
+
- CHANGELOG.md
|
|
84
|
+
- LICENSE
|
|
85
|
+
- LICENSE.txt
|
|
86
|
+
- README.md
|
|
87
|
+
- lib/gherkin_system.rb
|
|
88
|
+
- lib/gherkin_system/checker.rb
|
|
89
|
+
- lib/gherkin_system/cli.rb
|
|
90
|
+
- lib/gherkin_system/configuration.rb
|
|
91
|
+
- lib/gherkin_system/data_table.rb
|
|
92
|
+
- lib/gherkin_system/errors.rb
|
|
93
|
+
- lib/gherkin_system/executor.rb
|
|
94
|
+
- lib/gherkin_system/feature_loader.rb
|
|
95
|
+
- lib/gherkin_system/hooks.rb
|
|
96
|
+
- lib/gherkin_system/parameter_registry.rb
|
|
97
|
+
- lib/gherkin_system/parser.rb
|
|
98
|
+
- lib/gherkin_system/rails.rb
|
|
99
|
+
- lib/gherkin_system/railtie.rb
|
|
100
|
+
- lib/gherkin_system/scenario.rb
|
|
101
|
+
- lib/gherkin_system/scenario_run.rb
|
|
102
|
+
- lib/gherkin_system/snippet.rb
|
|
103
|
+
- lib/gherkin_system/step_definition.rb
|
|
104
|
+
- lib/gherkin_system/step_registry.rb
|
|
105
|
+
- lib/gherkin_system/steps.rb
|
|
106
|
+
- lib/gherkin_system/tag_filter.rb
|
|
107
|
+
- lib/gherkin_system/test_class_builder.rb
|
|
108
|
+
- lib/gherkin_system/version.rb
|
|
109
|
+
- lib/rails/commands/gherkin/gherkin_command.rb
|
|
110
|
+
- sig/gherkin_system.rbs
|
|
111
|
+
- skills/gherkin-system/SKILL.md
|
|
112
|
+
homepage: https://github.com/dpaluy/gherkin_system
|
|
113
|
+
licenses:
|
|
114
|
+
- MIT
|
|
115
|
+
metadata:
|
|
116
|
+
rubygems_mfa_required: 'true'
|
|
117
|
+
homepage_uri: https://github.com/dpaluy/gherkin_system
|
|
118
|
+
documentation_uri: https://rubydoc.info/gems/gherkin_system
|
|
119
|
+
source_code_uri: https://github.com/dpaluy/gherkin_system
|
|
120
|
+
changelog_uri: https://github.com/dpaluy/gherkin_system/blob/master/CHANGELOG.md
|
|
121
|
+
bug_tracker_uri: https://github.com/dpaluy/gherkin_system/issues
|
|
122
|
+
rdoc_options: []
|
|
123
|
+
require_paths:
|
|
124
|
+
- lib
|
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - ">="
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: 3.2.0
|
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
|
+
requirements:
|
|
132
|
+
- - ">="
|
|
133
|
+
- !ruby/object:Gem::Version
|
|
134
|
+
version: '0'
|
|
135
|
+
requirements: []
|
|
136
|
+
rubygems_version: 4.0.20
|
|
137
|
+
specification_version: 4
|
|
138
|
+
summary: Compile Gherkin features into Rails system tests.
|
|
139
|
+
test_files: []
|