bddgenx 2.4.3 → 2.4.5
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/README.md +79 -162
- data/VERSION +1 -1
- data/bin/bddgenx +11 -2
- data/lib/bddgenx/ia/chatgtp_cliente.rb +6 -6
- data/lib/bddgenx/ia/gemini_cliente.rb +3 -3
- data/lib/bddgenx/locales/en.yml +27 -2
- data/lib/bddgenx/locales/pt.yml +27 -0
- data/lib/bddgenx/reports/backup.rb +4 -4
- data/lib/bddgenx/reports/pdf_exporter.rb +2 -2
- data/lib/bddgenx/setup.rb +168 -15
- data/lib/bddgenx/support/font_loader.rb +1 -1
- data/lib/bddgenx/support/validator.rb +5 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35e8e21b724442b0cb35cda26d862a4aa3a1eccbfd1bdb050dba306c1606600e
|
4
|
+
data.tar.gz: 540d3c814c5621fb7184261c4f070b4f30fa7c0ea351028b6205739556864bc9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6942cf6d50f8f4f4a1ddd69f05a294f066907798f3b3dcfaac0cbc4bb04844267488bad866c65eef47c1bc9596efca105b366102d6eff3305025afbb70b8565e
|
7
|
+
data.tar.gz: ed96a04fa5b37f17f768f3f015eaed93e5a944ae9d041425743610b97b3dc1bbf58caef555c692d6cf732b1229d373a3f3b0fae6ebe02c719514eaa6f253b839
|
data/README.md
CHANGED
@@ -1,81 +1,40 @@
|
|
1
1
|
# Gerador Automático de BDD em Ruby
|
2
|
+
|
2
3
|
[](https://badge.fury.io/rb/bddgenx)
|
3
4
|
|
4
5
|
## Visão Geral
|
5
6
|
|
6
|
-
Ferramenta Ruby para gerar automaticamente arquivos Gherkin (`.feature`) e definições de passos (`steps.rb`) a partir de histórias em texto. Atende aos padrões ISTQB, suporta parametrização com blocos de exemplos e fornece relatórios de QA (rastreabilidade, backups e PDF).
|
7
|
-
|
8
|
-
---
|
7
|
+
Ferramenta Ruby para gerar automaticamente arquivos Gherkin (`.feature`) e definições de passos (`steps.rb`) a partir de histórias em texto. Atende aos padrões ISTQB, suporta parametrização com blocos de exemplos e fornece relatórios de QA (rastreabilidade, backups e PDF).
|
9
8
|
|
10
9
|
## Estrutura do Projeto
|
11
10
|
|
12
11
|
```
|
13
12
|
bdd-generation/
|
14
|
-
├──
|
15
|
-
|
16
|
-
│
|
17
|
-
├──
|
18
|
-
│ ├── bddgenx # Executável CLI para gerar BDD (static/chatgpt/gemini)
|
19
|
-
│ └── setup.rb # Script para preparar o ambiente local (gera .env, input/)
|
20
|
-
├── features/ # Gherkin gerados automaticamente
|
21
|
-
│ └── steps/ # Steps correspondentes aos cenários
|
22
|
-
├── input/ # Arquivos de entrada (.txt com histórias)
|
23
|
-
│ ├── historia.txt
|
24
|
-
│ ├── historia_en.txt
|
25
|
-
│ └── ...
|
13
|
+
├── bin/
|
14
|
+
├── features/ # Gherkin gerados automaticamente
|
15
|
+
│ └── steps/ # Steps correspondentes
|
16
|
+
├── input/ # Histórias de entrada
|
26
17
|
├── lib/
|
27
18
|
│ ├── bddgenx/
|
28
|
-
│ │ ├── generators/
|
29
|
-
│ │
|
30
|
-
│ │
|
31
|
-
│ │
|
32
|
-
│ │
|
33
|
-
│ │ ├──
|
34
|
-
│ │
|
35
|
-
│
|
36
|
-
│
|
37
|
-
|
38
|
-
│
|
39
|
-
│
|
40
|
-
│
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
│ │ │ ├── remover_steps_duplicados.rb
|
46
|
-
│ │ │ └── validator.rb
|
47
|
-
│ │ │
|
48
|
-
│ │ ├── configuration.rb # Configuração global da gem (modo, ENV keys)
|
49
|
-
│ │ └── version.rb # Leitura da versão a partir do arquivo VERSION
|
50
|
-
│ │
|
51
|
-
│ ├── bddgenx.rb # Entrada principal da gem (require env)
|
52
|
-
│ └── parser.rb # Parser de arquivos de entrada
|
53
|
-
├── reports/ # Artefatos gerados
|
54
|
-
│ ├── pdf/ # Features exportadas em PDF
|
55
|
-
│ ├── backup/ # Versões antigas de features
|
56
|
-
│ └── rastreabilidade/ # Arquivos de rastreabilidade (se implementado)
|
57
|
-
├── spec/ # Testes unitários RSpec
|
58
|
-
│ ├── support/
|
59
|
-
│ ├── utils/
|
60
|
-
│ ├── ia/
|
61
|
-
│ ├── spec_helper.rb
|
62
|
-
│ └── version_spec.rb
|
63
|
-
├── .env # Arquivo com chaves reais (não versionado)
|
64
|
-
├── .env.example # Modelo para configurar variáveis de ambiente
|
65
|
-
├── .gitignore # Arquivos/pastas ignoradas pelo Git
|
66
|
-
├── bddgenx.gemspec # Especificação da gem
|
67
|
-
├── bump_version.sh # Script de versionamento automático (semântico)
|
68
|
-
├── Gemfile
|
69
|
-
├── Gemfile.lock
|
70
|
-
├── LICENSE
|
71
|
-
├── Rakefile # Tarefas automatizadas (static, chatgpt, gemini)
|
72
|
-
├── README.md # Documentação principal do projeto
|
73
|
-
└── VERSION # Arquivo contendo a versão atual da gem
|
74
|
-
|
19
|
+
│ │ ├── generators/ # Geração de features e steps
|
20
|
+
│ │ ├── ia/ # Integração com APIs de IA
|
21
|
+
│ │ ├── reports/ # Exportação PDF, backup, rastreio
|
22
|
+
│ │ ├── support/ # Validação e utilitários
|
23
|
+
│ │ ├── configuration.rb # Configuração global
|
24
|
+
│ │ ├── setup.rb # Cria estrutura inicial do projeto
|
25
|
+
│ │ └── version.rb # Versão da gem
|
26
|
+
│ ├── bddgenx.rb
|
27
|
+
│ └── parser.rb
|
28
|
+
├── reports/
|
29
|
+
│ ├── backup/
|
30
|
+
│ ├── pdf/
|
31
|
+
│ └── rastreabilidade/
|
32
|
+
├── .env # Variáveis de ambiente
|
33
|
+
├── bddgenx.gemspec
|
34
|
+
├── Rakefile
|
35
|
+
└── README.md
|
75
36
|
```
|
76
37
|
|
77
|
-
---
|
78
|
-
|
79
38
|
## Instalação
|
80
39
|
|
81
40
|
Adicione ao seu `Gemfile`:
|
@@ -84,71 +43,76 @@ Adicione ao seu `Gemfile`:
|
|
84
43
|
gem 'bddgenx'
|
85
44
|
```
|
86
45
|
|
87
|
-
|
46
|
+
Instale com:
|
88
47
|
|
89
48
|
```bash
|
90
|
-
|
49
|
+
bundle install
|
91
50
|
```
|
92
51
|
|
93
|
-
|
94
|
-
|
95
|
-
## 🔧 Configuração
|
96
|
-
|
97
|
-
### 1. Instale dependências
|
52
|
+
Ou diretamente:
|
98
53
|
|
99
54
|
```bash
|
100
|
-
|
55
|
+
gem install bddgenx
|
101
56
|
```
|
102
57
|
|
103
|
-
|
58
|
+
## Inicialização do Projeto (`Setup.run`)
|
104
59
|
|
105
|
-
|
106
|
-
cp .env.example .env
|
107
|
-
```
|
60
|
+
Antes de usar a gem, é recomendado executar o setup para criar:
|
108
61
|
|
109
|
-
|
62
|
+
* Pastas obrigatórias (`input/`, `features/steps/`, `reports/`...)
|
63
|
+
* Arquivo `historia.txt` com conteúdo exemplo
|
64
|
+
* Feature `.feature` e steps `_steps.rb`
|
65
|
+
* Arquivo `.env` com variáveis de ambiente
|
110
66
|
|
111
|
-
|
112
|
-
OPENAI_API_KEY=sk-...
|
113
|
-
GEMINI_API_KEY=ya29-...
|
114
|
-
BDDGENX_MODE=chatgpt # static | chatgpt | gemini
|
115
|
-
```
|
67
|
+
### Via Ruby
|
116
68
|
|
117
|
-
|
69
|
+
```bash
|
70
|
+
bundle exec ruby -e "require 'bddgenx'; Bddgenx::Setup.run"
|
71
|
+
```
|
118
72
|
|
119
|
-
|
73
|
+
### Via Rakefile
|
120
74
|
|
121
|
-
|
75
|
+
```ruby
|
76
|
+
require 'bddgenx'
|
122
77
|
|
123
|
-
|
78
|
+
namespace :bddgenx do
|
79
|
+
desc 'Inicializa estrutura do projeto'
|
80
|
+
task :setup do
|
81
|
+
Bddgenx::Setup.run
|
82
|
+
end
|
83
|
+
end
|
84
|
+
```
|
124
85
|
|
125
86
|
```bash
|
126
|
-
rake bddgenx:
|
127
|
-
rake bddgenx:chatgpt # usando ChatGPT
|
128
|
-
rake bddgenx:gemini # usando Gemini
|
87
|
+
rake bddgenx:setup
|
129
88
|
```
|
130
89
|
|
131
|
-
|
90
|
+
## Configuração do `.env`
|
132
91
|
|
133
|
-
|
92
|
+
```dotenv
|
93
|
+
# OPENAI e GEMINI só são usados se modo for IA\OPENAI_API_KEY=xxx
|
94
|
+
GEMINI_API_KEY=xxx
|
134
95
|
|
135
|
-
|
96
|
+
BDDGENX_MODE=static # static, chatgpt, gemini, deepseek
|
97
|
+
BDDGENX_LANG=pt # pt ou en
|
98
|
+
```
|
99
|
+
|
100
|
+
## Uso via Código Ruby
|
136
101
|
|
137
102
|
```ruby
|
138
103
|
require 'bddgenx'
|
139
104
|
|
140
105
|
Bddgenx.configure do |config|
|
141
|
-
config.mode = :
|
142
|
-
config.
|
106
|
+
config.mode = :gemini
|
107
|
+
config.gemini_api_key_env = 'GEMINI_API_KEY'
|
143
108
|
end
|
144
109
|
|
145
110
|
Bddgenx::Runner.execute
|
146
111
|
```
|
147
112
|
|
148
|
-
|
113
|
+
## Uso via Rake
|
149
114
|
|
150
|
-
|
151
|
-
```Ruby
|
115
|
+
```ruby
|
152
116
|
require 'rake'
|
153
117
|
require 'bddgenx'
|
154
118
|
|
@@ -187,86 +151,39 @@ namespace :bddgenx do
|
|
187
151
|
end
|
188
152
|
```
|
189
153
|
|
190
|
-
|
154
|
+
Execute com:
|
155
|
+
|
156
|
+
```bash
|
157
|
+
rake bddgenx:generate[static] # ou chatgpt, gemini, deepseek
|
158
|
+
```
|
159
|
+
|
160
|
+
## Formato do Arquivo de Entrada
|
191
161
|
|
192
162
|
```txt
|
193
163
|
# language: pt
|
194
164
|
Como um usuário do sistema
|
195
|
-
Quero
|
196
|
-
Para
|
165
|
+
Quero acessar minha conta
|
166
|
+
Para realizar tarefas
|
197
167
|
|
198
168
|
[CONTEXT]
|
199
169
|
Dado que estou na tela de login
|
200
170
|
|
201
171
|
[SUCCESS]
|
202
|
-
Quando preencho email e senha
|
172
|
+
Quando preencho email e senha
|
203
173
|
Então vejo a tela inicial
|
204
174
|
|
205
|
-
[SUCCESS]
|
206
|
-
Quando tento logar com "<email>" e "<senha>"
|
207
|
-
Então recebo "<mensagem>"
|
208
|
-
|
209
175
|
[EXAMPLES]
|
210
|
-
| email
|
211
|
-
| user@site.com
|
212
|
-
| errado@site
|
213
|
-
| | senha | email é obrigatório |
|
214
|
-
| user@site.com | | senha é obrigatória |
|
215
|
-
|
216
|
-
[SUCCESS]
|
217
|
-
Quando deixo o campo "<campo>" vazio
|
218
|
-
Então recebo a mensagem "<mensagem>"
|
219
|
-
|
220
|
-
[EXAMPLES]
|
221
|
-
| campo | mensagem |
|
222
|
-
| | login realizado |
|
223
|
-
| | credenciais inválidas |
|
224
|
-
| email | email é obrigatório |
|
225
|
-
| senha | senha é obrigatória |
|
176
|
+
| email | senha | resultado |
|
177
|
+
| user@site.com | 123456 | login realizado |
|
178
|
+
| errado@site | 000000 | credenciais inválidas |
|
226
179
|
```
|
227
180
|
|
228
|
-
|
229
|
-
|
230
|
-
## 🧪 Setup Rápido para Novos Usuários
|
231
|
-
|
232
|
-
```bash
|
233
|
-
ruby bin/setup.rb
|
234
|
-
```
|
235
|
-
|
236
|
-
Esse comando:
|
237
|
-
|
238
|
-
- Cria `.env` a partir de `.env.example`
|
239
|
-
- Garante que `input/` existe
|
240
|
-
|
241
|
-
---
|
242
|
-
|
243
|
-
## 🧾 Artefatos Gerados
|
244
|
-
|
245
|
-
- ✅ `.feature` → dentro de `features/`
|
246
|
-
- ✅ `steps.rb` → dentro de `features/steps/`
|
247
|
-
- 🗂️ Backup automático → `reports/backup/`
|
248
|
-
- 📄 PDF das features → `reports/pdf/`
|
249
|
-
|
250
|
-
---
|
251
|
-
|
252
|
-
## ⚙️ CI/CD Exemplo com GitHub Actions
|
253
|
-
|
254
|
-
```yaml
|
255
|
-
jobs:
|
256
|
-
gerar_bdd:
|
257
|
-
runs-on: ubuntu-latest
|
258
|
-
steps:
|
259
|
-
- uses: actions/checkout@v3
|
260
|
-
- uses: ruby/setup-ruby@v1
|
261
|
-
with:
|
262
|
-
ruby-version: '3.1'
|
263
|
-
- run: bundle install
|
264
|
-
- run: bundle exec rake bddgenx:chatgpt
|
265
|
-
env:
|
266
|
-
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
267
|
-
```
|
181
|
+
## Geração de Artefatos
|
268
182
|
|
269
|
-
|
183
|
+
* Arquivos `.feature` na pasta `features/`
|
184
|
+
* Arquivos `*_steps.rb` na pasta `features/steps/`
|
185
|
+
* Arquivos PDF em `reports/pdf/`
|
186
|
+
* Backups de features anteriores em `reports/backup/`
|
270
187
|
|
271
188
|
## Licença
|
272
189
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.4.
|
1
|
+
2.4.5
|
data/bin/bddgenx
CHANGED
@@ -1,4 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
# bin/bddgenx
|
3
|
+
|
4
|
+
require_relative '../lib/bddgenx'
|
5
|
+
|
6
|
+
# Permite usar: `bddgenx --init`
|
7
|
+
if ARGV.include?('--init')
|
8
|
+
Bddgenx::Setup.run
|
9
|
+
exit 0
|
10
|
+
end
|
11
|
+
|
12
|
+
puts I18n.t('cli.init_hint')
|
3
13
|
|
4
|
-
Bddgenx::Runner.execute
|
@@ -7,7 +7,7 @@ module Bddgenx
|
|
7
7
|
# cenários BDD no formato Gherkin, com suporte a fallback para Gemini.
|
8
8
|
#
|
9
9
|
class ChatGptCliente
|
10
|
-
CHATGPT_API_URL = '
|
10
|
+
CHATGPT_API_URL = ENV['CHATGPT_API_URL']
|
11
11
|
MODEL = 'gpt-4o'
|
12
12
|
|
13
13
|
##
|
@@ -24,7 +24,7 @@ module Bddgenx
|
|
24
24
|
api_key = Bddgenx.configuration.openai_api_key # para ChatGPT
|
25
25
|
|
26
26
|
unless api_key
|
27
|
-
warn
|
27
|
+
warn I18n.t('errors.chatgpt_key_missing')
|
28
28
|
return fallback_com_gemini(historia, idioma)
|
29
29
|
end
|
30
30
|
|
@@ -112,14 +112,14 @@ module Bddgenx
|
|
112
112
|
texto_limpo.prepend("# language: #{idioma}\n") unless texto_limpo.start_with?("# language:")
|
113
113
|
return texto_limpo
|
114
114
|
else
|
115
|
-
warn
|
115
|
+
warn I18n.t('errors.ia_no_content')
|
116
116
|
warn JSON.pretty_generate(json)
|
117
117
|
return fallback_com_gemini(historia, idioma)
|
118
118
|
end
|
119
119
|
else
|
120
120
|
if response.code.to_i == 429
|
121
|
-
warn
|
122
|
-
warn
|
121
|
+
warn I18n.t('errors.openai_quota')
|
122
|
+
warn I18n.t('errors.openai_check_usage')
|
123
123
|
end
|
124
124
|
return fallback_com_gemini(historia, idioma)
|
125
125
|
end
|
@@ -134,7 +134,7 @@ module Bddgenx
|
|
134
134
|
# @return [String] Cenários gerados pelo GeminiCliente.
|
135
135
|
#
|
136
136
|
def self.fallback_com_gemini(historia, idioma)
|
137
|
-
warn
|
137
|
+
warn I18n.t('messages.fallback_gemini')
|
138
138
|
GeminiCliente.gerar_cenarios(historia, idioma)
|
139
139
|
end
|
140
140
|
|
@@ -7,7 +7,7 @@ module Bddgenx
|
|
7
7
|
# de conteúdo, aqui usado para criar cenários BDD no formato Gherkin.
|
8
8
|
#
|
9
9
|
class GeminiCliente
|
10
|
-
GEMINI_API_URL = '
|
10
|
+
GEMINI_API_URL = ENV['GEMINI_API_URL']
|
11
11
|
|
12
12
|
##
|
13
13
|
# Gera cenários BDD baseados em uma história, solicitando à API Gemini
|
@@ -120,12 +120,12 @@ module Bddgenx
|
|
120
120
|
|
121
121
|
return texto_limpo
|
122
122
|
else
|
123
|
-
warn
|
123
|
+
warn I18n.t('errors.ia_no_content')
|
124
124
|
warn JSON.pretty_generate(json)
|
125
125
|
return nil
|
126
126
|
end
|
127
127
|
else
|
128
|
-
warn
|
128
|
+
warn I18n.t('errors.gemini_error', code: response.code, body: response.body)
|
129
129
|
return nil
|
130
130
|
end
|
131
131
|
end
|
data/lib/bddgenx/locales/en.yml
CHANGED
@@ -11,6 +11,7 @@ en:
|
|
11
11
|
features_generated: "Generated features"
|
12
12
|
steps_generated: "Generated steps"
|
13
13
|
feature_created: "✅ .feature file generated: %{caminho}"
|
14
|
+
fallback_gemini: "🔁 Trying to generate with Gemini as fallback..."
|
14
15
|
gherkin:
|
15
16
|
feature: "Feature"
|
16
17
|
context: "Background"
|
@@ -24,5 +25,29 @@ en:
|
|
24
25
|
generated: "✅ Steps generated: %{path}"
|
25
26
|
errors:
|
26
27
|
invalid_path: "Expected path as String, got %{path}"
|
27
|
-
|
28
|
-
|
28
|
+
ia_no_content: "❌ No content returned from AI"
|
29
|
+
gemini_error: "❌ Error calling Gemini: %{code} - %{body}"
|
30
|
+
chatgpt_key_missing: "❌ ChatGPT API key not found in .env (OPENAI_API_KEY)"
|
31
|
+
openai_quota: "❌ OpenAI API quota exceeded."
|
32
|
+
openai_check_usage: "🔗 Check your usage: https://platform.openai.com/account/usage"
|
33
|
+
feature_not_found: "⚠️ Feature not found: %{feature}"
|
34
|
+
pdf_generation_failed: "❌ Failed to generate PDF for %{file}: %{error}"
|
35
|
+
font_fallback: "⚠️ DejaVuSansMono fonts missing or corrupted in %{font}. Falling back to Courier."
|
36
|
+
backup:
|
37
|
+
created: "📦 Backup created: %{path}"
|
38
|
+
validator:
|
39
|
+
missing_header: "❌ Missing header (Como, Quero, Para are required)"
|
40
|
+
no_blocks: "❌ No step groups detected"
|
41
|
+
empty_group: "❌ Group %{index} of type [%{type}] is empty"
|
42
|
+
invalid_examples: "❌ EXAMPLES group in block %{index} does not contain a valid table"
|
43
|
+
found_errors: "⚠️ Errors found in the file:"
|
44
|
+
setup:
|
45
|
+
init: "🔧 Initializing structure with Bddgenx::Setup.run"
|
46
|
+
spinner_checking: "Checking structure..."
|
47
|
+
dir_created: "📁 Directory created: %{path} ✔️"
|
48
|
+
dir_exists: "📁 Directory already exists: %{path} ✔️"
|
49
|
+
file_created: "📄 File created: %{path} ✔️"
|
50
|
+
file_exists: "📄 File already exists: %{path} ✔️"
|
51
|
+
success: "✅ Structure successfully completed!"
|
52
|
+
cli:
|
53
|
+
init_hint: "ℹ️ Use 'bddgenx --init' to initialize the project."
|
data/lib/bddgenx/locales/pt.yml
CHANGED
@@ -11,6 +11,7 @@ pt:
|
|
11
11
|
features_generated: "Features geradas"
|
12
12
|
steps_generated: "Steps gerados"
|
13
13
|
feature_created: "✅ Arquivo .feature gerado: %{caminho}"
|
14
|
+
fallback_gemini: "🔁 Tentando gerar com Gemini como fallback..."
|
14
15
|
gherkin:
|
15
16
|
feature: "Funcionalidade"
|
16
17
|
context: "Contexto"
|
@@ -24,4 +25,30 @@ pt:
|
|
24
25
|
generated: "✅ Steps gerados: %{path}"
|
25
26
|
errors:
|
26
27
|
invalid_path: "Caminho esperado como String, recebeu %{path}"
|
28
|
+
ia_no_content: "❌ Resposta da IA sem conteúdo de texto"
|
29
|
+
gemini_error: "❌ Erro ao chamar Gemini: %{code} - %{body}"
|
30
|
+
chatgpt_key_missing: "❌ API Key do ChatGPT não encontrada no .env (OPENAI_API_KEY)"
|
31
|
+
openai_quota: "❌ Limite de uso da API OpenAI excedido."
|
32
|
+
openai_check_usage: "🔗 Verifique sua conta: https://platform.openai.com/account/usage"
|
33
|
+
feature_not_found: "⚠️ Feature não encontrada: %{feature}"
|
34
|
+
pdf_generation_failed: "❌ Erro ao gerar PDF de %{file}: %{error}"
|
35
|
+
font_fallback: "⚠️ Fontes DejaVuSansMono ausentes ou corrompidas em %{font}. Usando fallback Courier."
|
36
|
+
backup:
|
37
|
+
created: "📦 Backup criado: %{path}"
|
38
|
+
validator:
|
39
|
+
missing_header: "❌ Cabeçalho incompleto (Como, Quero, Para obrigatórios)"
|
40
|
+
no_blocks: "❌ Nenhum grupo de blocos detectado"
|
41
|
+
empty_group: "❌ Grupo %{index} do tipo [%{type}] está vazio"
|
42
|
+
invalid_examples: "❌ Grupo de EXAMPLES no bloco %{index} não contém tabela válida"
|
43
|
+
found_errors: "⚠️ Erros encontrados no arquivo:"
|
44
|
+
setup:
|
45
|
+
init: "🔧 Iniciando estrutura com Bddgenx::Setup.run"
|
46
|
+
spinner_checking: "Verificando estrutura..."
|
47
|
+
dir_created: "📁 Diretório criado: %{path} ✔️"
|
48
|
+
dir_exists: "📁 Diretório já existe: %{path} ✔️"
|
49
|
+
file_created: "📄 Arquivo criado: %{path} ✔️"
|
50
|
+
file_exists: "📄 Arquivo já existe: %{path} ✔️"
|
51
|
+
success: "✅ Estrutura finalizada com sucesso!"
|
52
|
+
cli:
|
53
|
+
init_hint: "ℹ️ Use 'bddgenx --init' para iniciar o projeto."
|
27
54
|
|
@@ -16,15 +16,15 @@ module Bddgenx
|
|
16
16
|
def self.salvar_versao_antiga(caminho)
|
17
17
|
return unless File.exist?(caminho)
|
18
18
|
|
19
|
-
pasta
|
19
|
+
pasta = 'reports/backup'
|
20
20
|
FileUtils.mkdir_p(pasta)
|
21
21
|
|
22
|
-
base
|
22
|
+
base = File.basename(caminho, '.feature')
|
23
23
|
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
24
|
-
destino
|
24
|
+
destino = File.join(pasta, "#{base}_#{timestamp}.feature")
|
25
25
|
|
26
26
|
FileUtils.cp(caminho, destino)
|
27
|
-
puts
|
27
|
+
puts I18n.t('backup.created', path: destino)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -37,7 +37,7 @@ module Bddgenx
|
|
37
37
|
|
38
38
|
features_list.each do |feature|
|
39
39
|
unless File.file?(feature)
|
40
|
-
warn
|
40
|
+
warn I18n.t('errors.feature_not_found', feature: feature)
|
41
41
|
next
|
42
42
|
end
|
43
43
|
|
@@ -151,7 +151,7 @@ module Bddgenx
|
|
151
151
|
pdf.number_pages 'Página <page> de <total>', align: :right, size: 8
|
152
152
|
end
|
153
153
|
rescue => e
|
154
|
-
warn
|
154
|
+
warn I18n.t('errors.pdf_generation_failed', file: origem, error: e.message)
|
155
155
|
end
|
156
156
|
end
|
157
157
|
end
|
data/lib/bddgenx/setup.rb
CHANGED
@@ -1,26 +1,179 @@
|
|
1
|
-
|
1
|
+
# lib/bddgenx/setup.rb
|
2
|
+
|
2
3
|
module Bddgenx
|
3
4
|
class Setup
|
4
|
-
|
5
|
-
|
5
|
+
SPINNER_FRAMES = %w[⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏].freeze
|
6
|
+
SPINNER_DELAY = 0.1
|
7
|
+
def self.run
|
8
|
+
thread, stop = start_spinner(I18n.t('setup.spinner_checking'))
|
9
|
+
|
10
|
+
resultados = []
|
11
|
+
resultados << verificar("input") do
|
12
|
+
File.write('input/historia.txt', exemplo_txt) unless File.exist?('input/historia.txt')
|
13
|
+
end
|
14
|
+
|
15
|
+
resultados << verificar("features/steps") do
|
16
|
+
File.write('features/exemplo_login.feature', exemplo_feature) unless File.exist?('features/exemplo_login.feature')
|
17
|
+
File.write('features/steps/exemplo_login_steps.rb', exemplo_step) unless File.exist?('features/steps/exemplo_login_steps.rb')
|
18
|
+
end
|
19
|
+
|
20
|
+
resultados << verificar("reports/pdf")
|
21
|
+
resultados << verificar("reports/backup")
|
22
|
+
|
23
|
+
resultados << verificar(".env", is_file: true) do
|
24
|
+
File.write('.env', exemplo_env)
|
25
|
+
end
|
26
|
+
|
27
|
+
stop_spinner(thread, stop)
|
6
28
|
|
7
|
-
|
8
|
-
|
9
|
-
|
29
|
+
resultados.each { |mensagem| puts mensagem }
|
30
|
+
puts "\n#{I18n.t('setup.success')}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.verificar(path, is_file: false)
|
34
|
+
if is_file
|
35
|
+
if File.exist?(path)
|
36
|
+
I18n.t('setup.file_exists', path: path)
|
37
|
+
else
|
38
|
+
yield if block_given?
|
39
|
+
I18n.t('setup.file_created', path: path)
|
40
|
+
end
|
10
41
|
else
|
11
|
-
if
|
12
|
-
|
13
|
-
puts "✅ .env criado a partir de .env.example"
|
42
|
+
if Dir.exist?(path)
|
43
|
+
I18n.t('setup.dir_exists', path: path)
|
14
44
|
else
|
15
|
-
|
45
|
+
FileUtils.mkdir_p(path)
|
46
|
+
yield if block_given?
|
47
|
+
I18n.t('setup.dir_created', path: path)
|
16
48
|
end
|
17
49
|
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.start_spinner(mensagem)
|
53
|
+
done_flag = false
|
18
54
|
|
19
|
-
|
20
|
-
|
21
|
-
|
55
|
+
thread = Thread.new do
|
56
|
+
i = 0
|
57
|
+
until done_flag
|
58
|
+
print "\r#{SPINNER_FRAMES[i % SPINNER_FRAMES.size]} #{mensagem}"
|
59
|
+
sleep(SPINNER_DELAY)
|
60
|
+
i += 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
[thread, -> { done_flag = true }]
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.stop_spinner(thread, stop_proc)
|
68
|
+
stop_proc.call
|
69
|
+
thread.join
|
70
|
+
print "\r"
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.exemplo_txt
|
74
|
+
<<~TXT
|
75
|
+
# language: pt
|
76
|
+
Como um gerente
|
77
|
+
Quero que meus clientes efetue login
|
78
|
+
Para acompanhar o progresso da equipe
|
79
|
+
|
80
|
+
[SUCCESS]
|
81
|
+
Quando preencho email e senha válidos
|
82
|
+
Então sou redirecionado para o dashboard
|
83
|
+
|
84
|
+
[FAILURE]
|
85
|
+
Quando informo uma senha incorreta
|
86
|
+
Então recebo a mensagem "Credenciais inválidas"
|
87
|
+
|
88
|
+
[SUCCESS]
|
89
|
+
Quando tento logar com "<email>" e "<senha>"
|
90
|
+
Então recebo "<resultado>"
|
91
|
+
|
92
|
+
[EXAMPLES]
|
93
|
+
| email | senha | resultado |
|
94
|
+
| teste@site.com | 123456 | acesso permitido |
|
95
|
+
| errado@site.com | senhaincorreta | acesso negado |
|
96
|
+
TXT
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.exemplo_feature
|
100
|
+
<<~FEATURE
|
101
|
+
# language: pt
|
102
|
+
Funcionalidade: que meus clientes efetue login
|
103
|
+
# Como um gerente
|
104
|
+
# Quero que meus clientes efetue login
|
105
|
+
# Para acompanhar o progresso da equipe
|
106
|
+
@success
|
107
|
+
Cenário: Success
|
108
|
+
Quando preencho email e senha válidos
|
109
|
+
Então sou redirecionado para o dashboard
|
110
|
+
|
111
|
+
|
112
|
+
@failure
|
113
|
+
Cenário: Failure
|
114
|
+
Quando informo uma senha incorreta
|
115
|
+
Então recebo a mensagem "Credenciais inválidas"
|
116
|
+
|
117
|
+
@success
|
118
|
+
Esquema do Cenário: Exemplo 1
|
119
|
+
Quando tento logar com "<email>" e "<senha>"
|
120
|
+
Então recebo "<resultado>"
|
121
|
+
|
122
|
+
Exemplos:
|
123
|
+
| email | senha | resultado |
|
124
|
+
| teste@site.com | 123456 | acesso permitido |
|
125
|
+
| errado@site.com | senhaincorreta | acesso negado |
|
126
|
+
FEATURE
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.exemplo_step
|
130
|
+
<<~STEP
|
131
|
+
Quando("preencho email e senha válidos") do
|
132
|
+
pending 'Implementar passo: preencho email e senha válidos'
|
133
|
+
end
|
134
|
+
|
135
|
+
Então("sou redirecionado para o dashboard") do
|
136
|
+
pending 'Implementar passo: sou redirecionado para o dashboard'
|
137
|
+
end
|
138
|
+
|
139
|
+
Quando("informo uma senha incorreta") do
|
140
|
+
pending 'Implementar passo: informo uma senha incorreta'
|
141
|
+
end
|
142
|
+
|
143
|
+
Então("recebo a mensagem {string}") do |arg1|
|
144
|
+
pending 'Implementar passo: recebo a mensagem "Credenciais inválidas"'
|
145
|
+
end
|
146
|
+
|
147
|
+
Quando("tento logar com {string} e {string}") do |arg1, arg2|
|
148
|
+
pending 'Implementar passo: tento logar com "<email>" e "<senha>"'
|
149
|
+
end
|
150
|
+
|
151
|
+
Então("recebo {string}") do |arg1|
|
152
|
+
pending 'Implementar passo: recebo "<resultado>"'
|
153
|
+
end
|
154
|
+
STEP
|
155
|
+
end
|
22
156
|
|
23
|
-
|
157
|
+
def self.exemplo_env
|
158
|
+
<<~ENV
|
159
|
+
############################################
|
160
|
+
# CONFIGURAÇÃO DE CHAVES DE ACESSO À IA #
|
161
|
+
############################################
|
162
|
+
OPENAI_API_KEY={{SUA_CHAVE_OPENAI}}
|
163
|
+
CHATGPT_API_URL={{CHATGPT_API_URL}}
|
164
|
+
|
165
|
+
############################################
|
166
|
+
# CONFIGURAÇÃO DE CHAVES DE URI À IA #
|
167
|
+
############################################
|
168
|
+
OPENAI_API_KEY={{SUA_CHAVE_OPENAI}}
|
169
|
+
GEMINI_API_URL={{GEMINI_API_URL}}
|
170
|
+
|
171
|
+
############################################
|
172
|
+
# MODO DE GERAÇÃO DE CENÁRIOS BDD #
|
173
|
+
############################################
|
174
|
+
BDDGENX_MODE=static
|
175
|
+
BDDGENX_LANG=pt
|
176
|
+
ENV
|
24
177
|
end
|
25
178
|
end
|
26
|
-
end
|
179
|
+
end
|
@@ -38,7 +38,7 @@ module Bddgenx
|
|
38
38
|
if arquivos.values.all? { |path| File.file?(path) && File.size(path) > 12 }
|
39
39
|
{ 'DejaVuSansMono' => arquivos }
|
40
40
|
else
|
41
|
-
warn
|
41
|
+
warn I18n.t('errors.font_fallback', font: base)
|
42
42
|
{}
|
43
43
|
end
|
44
44
|
end
|
@@ -22,31 +22,31 @@ module Bddgenx
|
|
22
22
|
|
23
23
|
# Verificação do cabeçalho obrigatório
|
24
24
|
unless historia[:como] && historia[:quero] && historia[:para]
|
25
|
-
erros <<
|
25
|
+
erros << I18n.t('validator.missing_header')
|
26
26
|
end
|
27
27
|
|
28
28
|
# Verificação de grupos de passos
|
29
29
|
if historia[:grupos].nil? || historia[:grupos].empty?
|
30
|
-
erros <<
|
30
|
+
erros << I18n.t('validator.no_blocks')
|
31
31
|
else
|
32
32
|
historia[:grupos].each_with_index do |grupo, idx|
|
33
33
|
# Cada grupo deve conter passos ou exemplos
|
34
34
|
if (grupo[:passos].nil? || grupo[:passos].empty?) &&
|
35
35
|
(grupo[:exemplos].nil? || grupo[:exemplos].empty?)
|
36
|
-
erros <<
|
36
|
+
erros << I18n.t('validator.empty_group', index: idx + 1, type: grupo[:tipo])
|
37
37
|
end
|
38
38
|
|
39
39
|
# Validação específica para blocos de exemplos
|
40
40
|
if grupo[:tipo].casecmp('EXAMPLES').zero? &&
|
41
41
|
grupo[:exemplos].none? { |l| l.strip.start_with?('|') }
|
42
|
-
erros <<
|
42
|
+
erros << I18n.t('validator.invalid_examples', index: idx + 1)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
# Exibe erros e retorna false se houver falhas
|
48
48
|
if erros.any?
|
49
|
-
puts
|
49
|
+
puts I18n.t('validator.found_errors')
|
50
50
|
erros.each { |e| puts " - #{e}" }
|
51
51
|
return false
|
52
52
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bddgenx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Nascimento
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prawn
|