betagouv-cucumber-steps 0.0.1 → 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 +4 -4
- data/.rubocop.yml +13 -0
- data/.rubocop_todo.yml +18 -0
- data/README.md +33 -4
- data/Rakefile +13 -0
- data/lib/betagouv/cucumber/debug_steps.rb +11 -0
- data/lib/betagouv/cucumber/steps/version.rb +1 -1
- data/lib/betagouv/cucumber/steps.rb +2 -173
- data/lib/betagouv/cucumber/web_steps.rb +163 -0
- data/lib/rubocop/cop/cucumber/step_naming.rb +74 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ac48905d0b5c9b447895d58d165a7bd8b3f0a71bc6a92df2dcf91cd601f99711
|
|
4
|
+
data.tar.gz: 296aba285ee3e81a8895d18123c7d57d32f60b489aed9fbe128065dd18daad86
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f9980b077f998acf2bb3907e973044af516e9aba615daac45d23dab5ce36368b2fde867b913d5578a6aece172f9d9472c9883ab6b89f4e8601eb8a977fadfa30
|
|
7
|
+
data.tar.gz: 9a985477efe543f91d8add119559c8dd866e88c4809e112e77ae93426ecf61bb9c2a763cd58f9a07fec2311f1ce197f1fb83e720bdc6ed1aac6522bf487c8c01
|
data/.rubocop.yml
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
|
2
|
+
|
|
3
|
+
require:
|
|
4
|
+
- ./lib/rubocop/cop/cucumber/step_naming
|
|
5
|
+
|
|
6
|
+
plugins:
|
|
7
|
+
- rubocop-rake
|
|
8
|
+
- rubocop-rspec
|
|
9
|
+
- rubocop-capybara
|
|
10
|
+
|
|
1
11
|
AllCops:
|
|
2
12
|
TargetRubyVersion: 3.1
|
|
3
13
|
|
|
@@ -6,3 +16,6 @@ Style/StringLiterals:
|
|
|
6
16
|
|
|
7
17
|
Style/StringLiteralsInInterpolation:
|
|
8
18
|
EnforcedStyle: double_quotes
|
|
19
|
+
|
|
20
|
+
Cucumber/StepNaming:
|
|
21
|
+
Enabled: true
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2025-08-18 21:58:35 UTC using RuboCop version 1.78.0.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
11
|
+
Metrics/MethodLength:
|
|
12
|
+
Max: 14
|
|
13
|
+
|
|
14
|
+
# Offense count: 1
|
|
15
|
+
# Configuration parameters: AsciiConstants.
|
|
16
|
+
Naming/AsciiIdentifiers:
|
|
17
|
+
Exclude:
|
|
18
|
+
- 'test/support/env.rb'
|
data/README.md
CHANGED
|
@@ -5,7 +5,19 @@ Cucumber](https://cucumber.io/docs/gherkin/reference#steps)
|
|
|
5
5
|
génériques, surcouche française des matchers Capybara qui vous permet
|
|
6
6
|
de contruire votre propre librairie d'actions pour vos tests Cucumber.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Cette gem est fraîchement extraite de plusieurs projets Beta
|
|
9
|
+
([APLyPro](https://github.com/betagouv/aplypro/blob/main/features/step_definitions/web_steps.rb),
|
|
10
|
+
[Datapass](https://github.com/etalab/data_pass/blob/develop/features/step_definitions/web_steps.rb),
|
|
11
|
+
[Auto-audit](https://github.com/betagouv/auto-audit/blob/main/features/step_definitions/web_steps.rb))
|
|
12
|
+
et s'attend à une utilisation du DSFR.
|
|
13
|
+
|
|
14
|
+
## Aperçu
|
|
15
|
+
|
|
16
|
+
La librairie propose une [batterie
|
|
17
|
+
d'actions](./lib/betagouv/cucumber/steps.rb), qui vous permet de
|
|
18
|
+
composer vos tests.
|
|
19
|
+
|
|
20
|
+
### Exemple bête mais pas méchant
|
|
9
21
|
|
|
10
22
|
```ruby
|
|
11
23
|
Alors("la page contient {string}") do |content|
|
|
@@ -29,6 +41,26 @@ Scénario: la page d'accueil contient le nom du produit
|
|
|
29
41
|
Alors la page contient "foobar"
|
|
30
42
|
```
|
|
31
43
|
|
|
44
|
+
### Exemple avancé : composition d'une étape à vous (métier)
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
Quand("je rajoute un utilisateur {string}") do |nom|
|
|
48
|
+
steps %(
|
|
49
|
+
Quand je me rends sur la page d'accueil
|
|
50
|
+
Et que je clique sur "Rajoutez un utilisateur" dans le menu principal
|
|
51
|
+
Et que je remplis "Nom" avec "#{nom}"
|
|
52
|
+
Et que je clique sur "Enregistrer"
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```feature
|
|
58
|
+
Fonctionnalité: Gestion des utilisateurs
|
|
59
|
+
Scénario: Je peux rajouter un utilisateur
|
|
60
|
+
Quand je rajoute un utilisateur "Marie Curie" # et paf
|
|
61
|
+
Alors la page contient "Marie Curie a bien été rajouté(e)"
|
|
62
|
+
```
|
|
63
|
+
|
|
32
64
|
## Installation
|
|
33
65
|
|
|
34
66
|
```ruby
|
|
@@ -49,9 +81,6 @@ steps](./lib/betagouv/cucumber/steps.rb).
|
|
|
49
81
|
|
|
50
82
|
## Debug / Contribution
|
|
51
83
|
|
|
52
|
-
Cette gem est fraîchement extraite de plusieurs projets Beta et
|
|
53
|
-
nécessite probablement plus de travail.
|
|
54
|
-
|
|
55
84
|
Si un step ne fonctionne pas vous pouvez :
|
|
56
85
|
|
|
57
86
|
* utilisez le step `Alors debugger` pour debugger votre page en live
|
data/Rakefile
CHANGED
|
@@ -2,11 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
require "bundler/gem_tasks"
|
|
4
4
|
require "rspec/core/rake_task"
|
|
5
|
+
require "cucumber/rake/task"
|
|
5
6
|
|
|
6
7
|
RSpec::Core::RakeTask.new(:spec)
|
|
7
8
|
|
|
9
|
+
Cucumber::Rake::Task.new(:cucumber) do |task|
|
|
10
|
+
task.cucumber_opts = [
|
|
11
|
+
"--require",
|
|
12
|
+
"test/support",
|
|
13
|
+
"test/features/",
|
|
14
|
+
"--publish-quiet"
|
|
15
|
+
]
|
|
16
|
+
end
|
|
17
|
+
|
|
8
18
|
require "rubocop/rake_task"
|
|
9
19
|
|
|
10
20
|
RuboCop::RakeTask.new
|
|
11
21
|
|
|
22
|
+
desc "Run all tests"
|
|
23
|
+
task test: %i[spec cucumber]
|
|
24
|
+
|
|
12
25
|
task default: %i[spec rubocop]
|
|
@@ -2,176 +2,5 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "steps/version"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
Alors("la page contient {string}") do |content|
|
|
10
|
-
expect(page).to have_content(content)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
Alors("l'en-tête contient {string}") do |content|
|
|
14
|
-
within(".fr-header") do
|
|
15
|
-
step(%(la page contient "#{content}"))
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
Quand("print the page") do
|
|
20
|
-
log page.body
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
Quand("je clique sur {string}") do |label|
|
|
24
|
-
click_link_or_button label
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
Quand("je clique sur le premier lien ou bouton {string}") do |label|
|
|
28
|
-
click_link_or_button(label, match: :first)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
Alors("la page contient un bouton {string}") do |label|
|
|
32
|
-
expect(page).to have_button(label)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
Alors("la page ne contient pas de bouton {string}") do |title|
|
|
36
|
-
expect(page).not_to have_button(title)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
Alors("la page contient un bouton {string} désactivé") do |content|
|
|
40
|
-
expect(page).to have_button(content, disabled: true)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
Alors("la page ne contient pas {string}") do |content|
|
|
44
|
-
expect(page).to have_no_content(content)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
Alors("la page contient un lien {string}") do |text|
|
|
48
|
-
expect(page).to have_link(text)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
Alors("le titre de la page contient {string}") do |text|
|
|
52
|
-
expect(page.title.gsub(" ", " ")).to include text
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
Alors("il y a un titre de premier niveau contenant {string}") do |text|
|
|
56
|
-
# le titre est soit le premier h1 ou la légende du premier tableau
|
|
57
|
-
element = page.first("h1") || page.first("table caption")
|
|
58
|
-
|
|
59
|
-
expect(element.text).to include(text)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
Alors("la page est titrée {string}") do |text|
|
|
63
|
-
steps %(
|
|
64
|
-
Alors il y a un titre de premier niveau contenant "#{text}"
|
|
65
|
-
Et le titre de la page contient "#{text}"
|
|
66
|
-
)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
Quand("je remplis {string} avec {string}") do |label, value|
|
|
70
|
-
fill_in label, with: value
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
Quand("je remplis le champ {string} avec {string} dans les champs de {string}") do |label, value, fieldset_legend|
|
|
74
|
-
within_fieldset(fieldset_legend) do
|
|
75
|
-
fill_in label, with: value
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
Quand("je coche {string}") do |label|
|
|
80
|
-
check label
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
Quand("je décoche {string}") do |label|
|
|
84
|
-
uncheck label
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
Quand('je coche toutes les cases') do
|
|
88
|
-
page
|
|
89
|
-
.all('input[type="checkbox"]')
|
|
90
|
-
.map { |node| node.sibling("label").text }
|
|
91
|
-
.each { |label| step(%(je coche "#{label}")) }
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Quand("je clique sur {string} dans la rangée {string}") do |link, row|
|
|
96
|
-
within("tr", text: row) do
|
|
97
|
-
click_link_or_button(link)
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
Alors("la rangée {string} contient {string}") do |row, content|
|
|
102
|
-
within("tr", text: row) do
|
|
103
|
-
expect(page).to have_content(content)
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
Quand("je clique sur {string} dans la dernière rangée") do |link|
|
|
108
|
-
within(all("tr").last) do
|
|
109
|
-
click_link_or_button(link)
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
Quand("je clique sur {string} dans la classe {string}") do |link, title|
|
|
114
|
-
within("section", text: title) do
|
|
115
|
-
click_link_or_button(link)
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
Quand("je remplis le champ {string} dans la rangée {string} avec {string}") do |locator, row, value|
|
|
120
|
-
within("tr", text: row) do
|
|
121
|
-
fill_in locator, with: value
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
Quand("je sélectionne {string} pour {string}") do |option, name|
|
|
126
|
-
select option, from: name
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
Quand("je choisis {string}") do |option|
|
|
130
|
-
choose option
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
Quand("je choisis {string} pour {string}") do |option, fieldset|
|
|
134
|
-
within("fieldset", text: fieldset) do
|
|
135
|
-
choose option
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
Quand("j'attache le fichier {string} pour le champ {string}") do |path, field|
|
|
140
|
-
attach_file(field, path)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
Alors("je peux voir dans le tableau {string}") do |caption, table|
|
|
144
|
-
expect(page).to have_table(caption, with_rows: table.rows)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
Alors("je peux voir dans le tableau {string} dans cet ordre :") do |caption, table_data|
|
|
148
|
-
within_table(caption) do
|
|
149
|
-
table_data.rows.each_with_index do |row, row_number|
|
|
150
|
-
row.each_with_index do |cel, cel_number|
|
|
151
|
-
expect(find("tr[#{row_number + 1}]/td[#{cel_number + 1}]")).to have_text(cel)
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
Alors("debugger") do
|
|
158
|
-
debugger # rubocop:disable Lint/Debugger
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
Quand("je rafraîchis la page") do
|
|
162
|
-
visit current_path
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
Alors("le fil d'Ariane affiche {string}") do |path|
|
|
166
|
-
components = path.split(" > ")
|
|
167
|
-
|
|
168
|
-
breadcrumbs = page.all("nav.fr-breadcrumb li").map(&:text)
|
|
169
|
-
|
|
170
|
-
expect(breadcrumbs).to eq components
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
Quand("je clique sur {string} dans le menu principal") do |item|
|
|
174
|
-
within("nav#main-nav") do
|
|
175
|
-
click_link_or_button(item)
|
|
176
|
-
end
|
|
177
|
-
end
|
|
5
|
+
require_relative "debug_steps"
|
|
6
|
+
require_relative "web_steps"
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Quand("je me rends sur la page d'accueil") do
|
|
4
|
+
visit "/"
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
Alors("la page contient {string}") do |content|
|
|
8
|
+
expect(page).to have_content(content)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
Alors("l'en-tête contient {string}") do |content|
|
|
12
|
+
within(".fr-header") do
|
|
13
|
+
step(%(la page contient "#{content}"))
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
Quand("je clique sur {string}") do |label|
|
|
18
|
+
click_link_or_button label
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Quand("je clique sur le premier lien ou bouton {string}") do |label|
|
|
22
|
+
click_link_or_button(label, match: :first)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
Alors("la page contient un bouton {string}") do |label|
|
|
26
|
+
expect(page).to have_button(label)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Alors("la page ne contient pas de bouton {string}") do |title|
|
|
30
|
+
expect(page).not_to have_button(title)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Alors("la page contient un bouton {string} désactivé") do |content|
|
|
34
|
+
expect(page).to have_button(content, disabled: true)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
Alors("la page ne contient pas {string}") do |content|
|
|
38
|
+
expect(page).to have_no_content(content)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
Alors("la page contient un lien {string}") do |text|
|
|
42
|
+
expect(page).to have_link(text)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
Alors("le titre de la page contient {string}") do |text|
|
|
46
|
+
expect(page.title.gsub(" ", " ")).to include text
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Alors("il y a un titre de premier niveau contenant {string}") do |text|
|
|
50
|
+
# le titre est soit le premier h1 ou la légende du premier tableau
|
|
51
|
+
element = page.first("h1") || page.first("table caption")
|
|
52
|
+
|
|
53
|
+
expect(element.text).to include(text)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
Alors("la page est titrée {string}") do |text|
|
|
57
|
+
steps %(
|
|
58
|
+
Alors il y a un titre de premier niveau contenant "#{text}"
|
|
59
|
+
Et le titre de la page contient "#{text}"
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
Quand("je remplis {string} avec {string}") do |label, value|
|
|
64
|
+
fill_in label, with: value
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Quand("je remplis le champ {string} avec {string} dans les champs de {string}") do |label, value, fieldset_legend|
|
|
68
|
+
within_fieldset(fieldset_legend) do
|
|
69
|
+
fill_in label, with: value
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
Quand("je coche {string}") do |label|
|
|
74
|
+
check label
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
Quand("je décoche {string}") do |label|
|
|
78
|
+
uncheck label
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
Quand("je coche toutes les cases") do
|
|
82
|
+
page
|
|
83
|
+
.all('input[type="checkbox"]')
|
|
84
|
+
.map { |node| node.sibling("label").text }
|
|
85
|
+
.each { |label| step(%(je coche "#{label}")) }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
Quand("je clique sur {string} dans la rangée {string}") do |link, row|
|
|
89
|
+
within("tr", text: row) do
|
|
90
|
+
click_link_or_button(link)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
Alors("la rangée {string} contient {string}") do |row, content|
|
|
95
|
+
within("tr", text: row) do
|
|
96
|
+
expect(page).to have_content(content)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
Quand("je clique sur {string} dans la dernière rangée") do |link|
|
|
101
|
+
within(all("tr").last) do
|
|
102
|
+
click_link_or_button(link)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
Quand("je remplis le champ {string} dans la rangée {string} avec {string}") do |locator, row, value|
|
|
107
|
+
within("tr", text: row) do
|
|
108
|
+
fill_in locator, with: value
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
Quand("je sélectionne {string} pour {string}") do |option, name|
|
|
113
|
+
select option, from: name
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
Quand("je choisis {string}") do |option|
|
|
117
|
+
choose option
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
Quand("je choisis {string} pour {string}") do |option, fieldset|
|
|
121
|
+
within("fieldset", text: fieldset) do
|
|
122
|
+
choose option
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
Quand("j'attache le fichier {string} pour le champ {string}") do |path, field|
|
|
127
|
+
attach_file(field, path)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
Alors("le tableau {string} contient :") do |caption, table|
|
|
131
|
+
expect(page).to have_table(caption, with_rows: table.rows)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
Alors("la colonne {string} du tableau {string} contient dans l'ordre :") do |column_name, caption, table_data|
|
|
135
|
+
within_table(caption) do
|
|
136
|
+
headers = all("thead th").map(&:text)
|
|
137
|
+
column_index = headers.index(column_name)
|
|
138
|
+
|
|
139
|
+
column_texts = all("tbody tr").map do |row|
|
|
140
|
+
row.all("th, td")[column_index].text
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
expect(column_texts).to eq(table_data.raw.flatten)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
Quand("je rafraîchis la page") do
|
|
148
|
+
visit current_path
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
Alors("le fil d'Ariane affiche {string}") do |path|
|
|
152
|
+
components = path.split(" > ")
|
|
153
|
+
|
|
154
|
+
breadcrumbs = page.all("nav.fr-breadcrumb li").map(&:text)
|
|
155
|
+
|
|
156
|
+
expect(breadcrumbs).to eq components
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
Quand("je clique sur {string} dans le menu principal") do |item|
|
|
160
|
+
within("nav#main-nav") do
|
|
161
|
+
click_link_or_button(item)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Cucumber
|
|
6
|
+
# this cop ensures we write constitent steps: active voice for
|
|
7
|
+
# the actions, and passive voice for the expectations.
|
|
8
|
+
#
|
|
9
|
+
# ---
|
|
10
|
+
# Actions :
|
|
11
|
+
#
|
|
12
|
+
# bad :
|
|
13
|
+
# Quand le bouton Enregistrer est cliqué
|
|
14
|
+
|
|
15
|
+
# good :
|
|
16
|
+
# Quand je clique sur le bouton Enregistrer
|
|
17
|
+
#
|
|
18
|
+
# ---
|
|
19
|
+
# Exceptations :
|
|
20
|
+
#
|
|
21
|
+
# bad :
|
|
22
|
+
# Alors je peux voir dans le tableau X que la colonne Y contient dans cet ordre
|
|
23
|
+
#
|
|
24
|
+
# good :
|
|
25
|
+
# Alors la colonne X dans le tableau Y contient dans cet ordre :
|
|
26
|
+
#
|
|
27
|
+
class StepNaming < Base
|
|
28
|
+
MSG_QUAND_SHOULD_START_WITH_JE = '"Quand" steps should start with "je"'
|
|
29
|
+
MSG_ALORS_SHOULD_NOT_START_WITH_JE = '"Alors" steps should not start with "je"'
|
|
30
|
+
|
|
31
|
+
def on_send(node)
|
|
32
|
+
return unless step_definition?(node)
|
|
33
|
+
|
|
34
|
+
step_type = node.method_name.to_s
|
|
35
|
+
step_text = extract_step_text(node)
|
|
36
|
+
|
|
37
|
+
return unless step_text
|
|
38
|
+
|
|
39
|
+
case step_type
|
|
40
|
+
when "Quand"
|
|
41
|
+
check_quand_step(node, step_text)
|
|
42
|
+
when "Alors"
|
|
43
|
+
check_alors_step(node, step_text)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def step_definition?(node)
|
|
50
|
+
%w[Quand Alors].include?(node.method_name.to_s) && node.arguments.any?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def extract_step_text(node)
|
|
54
|
+
first_arg = node.arguments.first
|
|
55
|
+
return unless first_arg&.str_type?
|
|
56
|
+
|
|
57
|
+
first_arg.str_content
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def check_quand_step(node, step_text)
|
|
61
|
+
return if step_text.start_with?("je ") || step_text.start_with?("j'")
|
|
62
|
+
|
|
63
|
+
add_offense(node, message: MSG_QUAND_SHOULD_START_WITH_JE)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def check_alors_step(node, step_text)
|
|
67
|
+
return unless step_text.start_with?("je ") || step_text.start_with?("j'")
|
|
68
|
+
|
|
69
|
+
add_offense(node, message: MSG_ALORS_SHOULD_NOT_START_WITH_JE)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: betagouv-cucumber-steps
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stéphane Maniaci
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2025-
|
|
10
|
+
date: 2025-08-20 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: These helpers provide a (French) human syntax to drive a browser
|
|
13
13
|
email:
|
|
@@ -18,11 +18,15 @@ extra_rdoc_files: []
|
|
|
18
18
|
files:
|
|
19
19
|
- ".rspec"
|
|
20
20
|
- ".rubocop.yml"
|
|
21
|
+
- ".rubocop_todo.yml"
|
|
21
22
|
- LICENSE.txt
|
|
22
23
|
- README.md
|
|
23
24
|
- Rakefile
|
|
25
|
+
- lib/betagouv/cucumber/debug_steps.rb
|
|
24
26
|
- lib/betagouv/cucumber/steps.rb
|
|
25
27
|
- lib/betagouv/cucumber/steps/version.rb
|
|
28
|
+
- lib/betagouv/cucumber/web_steps.rb
|
|
29
|
+
- lib/rubocop/cop/cucumber/step_naming.rb
|
|
26
30
|
- sig/betagouv/cucumber/steps.rbs
|
|
27
31
|
homepage: https://github.com/betagouv/cucumber-steps
|
|
28
32
|
licenses:
|