bddgenx 0.1.43 → 0.1.44

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27d5aae37397f6f4cbebc64d87ea9046812aa8ca9754f15963f7a943e04c870f
4
- data.tar.gz: cad3d2ef7e11724824d2cd3c3a31ffd09725d189f6f20813488fd5164db1ea01
3
+ metadata.gz: bd3102863b9bbf30f979673c0a24d0b0f256f434af382a3efcaed7f2dc766930
4
+ data.tar.gz: 8c36dc262f88c01373968fbc251fe543359cb95f716bc28b8e75a755557b4288
5
5
  SHA512:
6
- metadata.gz: 8f9d4ff065c91d9b4c20e77fa2ef267c13c43d574d5f825afa0eb07f90518ba1994666a95464058152a8f8346a1283a9419311ad4ee3a55ed42ce75ae492a222
7
- data.tar.gz: b7f6fc413a78140a23812ab38db086b49c5cb5db1fdd0f51251e5607df6a6c57481c07acee2c95303b9e99ffa1120ae8f165dde5a698dca4c915ab9c7ad0c1cb
6
+ metadata.gz: 0fe963d729bb3d0d467d37a3cdfdf229e9ac0ee58df5451f72a6a93206f09e830fe1695b06b18682a7ac1bf73143a1b703e91ff7714efc3428d192c378ffd893
7
+ data.tar.gz: a7cf35c73fa936673078da5a2c47ea9208e913d5f9e86b23bf882a16b6c87b27814a5b617b6a28984f810fa8d66fce8854f89b4b86b2442e80bb362877142240
data/README.md CHANGED
@@ -1,142 +1,89 @@
1
- # 🧪 Gerador de BDD Automático em Ruby
2
- [![Gem Version](https://badge.fury.io/rb/bddgenx.svg)](https://badge.fury.io/rb/bddgenx)
1
+ # Gerador Automático de BDD em Ruby
3
2
 
4
- Este projeto gera arquivos `.feature` (Gherkin) e `steps.rb` automaticamente a partir de arquivos `.txt` com histórias de usuário, seguindo padrões ISTQB, parametrização com `Examples` e integração com pipelines.
3
+ ## Visão Geral
5
4
 
6
- ---
5
+ 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
6
 
8
- ## 📂 Estrutura do Projeto
9
- ```txt
10
- bddgenx/
11
- ├── bin/bddgenx # CLI executável
12
- ├── input/ # .txt de histórias de usuário
13
- ├── features/ # .feature geradas
14
- ├── features/<nome>/steps/ # step definitions por feature (se existir)
15
- ├── reports/ # todos os artefatos de saída
16
- │ ├── backup/ # versões antigas de .feature
17
- │ ├── output/ # rastreabilidade.csv
18
- │ └── pdf/ # relatórios camelCase
19
- ├── lib/
20
- │ ├── bddgenx/
21
- │ │ ├── parser.rb
22
- │ │ ├── validator.rb
23
- │ │ ├── generator.rb
24
- │ │ ├── steps_generator.rb
25
- │ │ ├── tracer.rb
26
- │ │ ├── backup.rb
27
- │ │ └── pdf_exporter.rb
28
- │ └── bddgenx.rb # Runner que orquestra tudo
29
- ├── Gemfile
30
- ├── bddgenx.gemspec
31
- ├── Rakefile
32
- ├── VERSION
33
- ├── bump_version.sh
34
- └── README.md
35
- ```
36
- ## ▶️ Como Executar
7
+ ## Instalação
37
8
 
38
- ### 🔧 Requisitos
39
- - Ruby 3.x
40
- - `bundle install` (caso use gems como `prawn` ou `jira-ruby`)
9
+ Adicione ao seu `Gemfile`:
41
10
 
42
- ### 🏁 Comando direto:
11
+ ```ruby
12
+ gem 'bddgenx'
13
+ ```
14
+
15
+ Execute:
43
16
 
44
17
  ```bash
45
- ruby main.rb
18
+ bundle install
46
19
  ```
47
20
 
48
- 🧱 Com Rake:
21
+ Ou instale diretamente:
22
+
49
23
  ```bash
50
- rake bddgen:gerar
24
+ gem install bddgenx
51
25
  ```
52
26
 
53
- 📥 Como Escrever um .txt de Entrada
54
- ```txt
55
- # language: pt
56
- Como um usuario do sistema
57
- Quero fazer login com sucesso
58
- Para acessar minha conta
27
+ ## Uso no Código
59
28
 
60
- [FAILURE]
61
- Quando preencho email e senha válidos
62
- Então vejo a tela inicial
29
+ ```ruby
30
+ require 'bddgenx'
63
31
 
64
- [SUCCESS]
65
- Quando tento logar com "<email>" e "<senha>"
66
- Então recebo "<resultado>"
32
+ # Gera todas as features e steps a partir dos .txt em input/
33
+ Bddgenx::Runner.execute
67
34
 
68
- [EXAMPLES]
69
- | email | senha | resultado |
70
- | user@site.com | 123456 | login realizado |
71
- | errado@site.com | senha | credenciais inválidas |
35
+ # Opcional: gerar apenas novos artefatos
36
+ Bddgenx::Runner.execute(only_new: true)
37
+
38
+ # Opcional: gerar apenas uma feature específica
39
+ Bddgenx::Runner.execute(feature: 'input/minha_historia.txt')
72
40
  ```
73
- ✅ Blocos Suportados
74
- [CONTEXT] – contexto comum
75
41
 
76
- [SUCCESS] cenário positivo
42
+ ## Tarefa Rake (opcional)
77
43
 
78
- [FAILURE] cenário negativo
44
+ Em um projeto Rails ou Ruby com Rake, adicione ao `Rakefile`:
79
45
 
80
- [ERROR], [EXCEPTION], [PERFORMANCE], etc.
46
+ ```ruby
47
+ require 'bddgenx'
48
+ require 'rake'
81
49
 
82
- [REGRA] ou [RULE] – regras de negócio
50
+ namespace :bddgenx do
51
+ desc 'Gera .feature e steps a partir de histórias em input/'
52
+ task :gerar do
53
+ Bddgenx::Runner.execute
54
+ end
55
+ end
56
+ ```
83
57
 
84
- [EXAMPLES] tabela de dados para Scenario Outline
58
+ ## Formato do Arquivo de Entrada (`.txt`)
85
59
 
86
- 🧠 Saída esperada (feature)
87
- ```gherkin
60
+ ```txt
88
61
  # language: pt
89
- Funcionalidade: adicionar produtos ao carrinho
90
-
91
- Como um cliente do e-commerce
92
- Quero adicionar produtos ao carrinho
93
- Para finalizar minha compra com praticidade
62
+ Como um usuário do sistema
63
+ Quero fazer login
64
+ Para acessar minha conta
94
65
 
95
- Regra: O carrinho não deve permitir produtos fora de estoque
96
- E o valor total deve refletir o desconto promocional
66
+ [SUCCESS]
67
+ Quando preencho <email> e <senha>
68
+ Então vejo a tela inicial
97
69
 
98
- Contexto:
99
- Dado que estou logado na plataforma
100
- E tenho produtos disponíveis
70
+ [EXAMPLES]
71
+ | email | senha | resultado |
72
+ | user@site.com | 123456 | login realizado |
73
+ | errado@site.com | senha | credenciais inválidas |
74
+ ```
101
75
 
102
- @success
103
- Cenário: Teste Positivo - adiciono um produto ao carrinho - ele aparece na listagem do carrinho
104
- Quando adiciono um produto ao carrinho
105
- Então ele aparece na listagem do carrinho
76
+ ## Artefatos de QA
106
77
 
107
- Esquema do Cenário: Gerado a partir de dados de exemplo
108
- Quando adiciono "<produto>" com quantidade <quantidade>
109
- Então vejo o total <total esperado>
78
+ * **Rastreabilidade**: `reports/output/rastreabilidade.csv` com colunas:
79
+ `Funcionalidade, Tipo, Tag, Cenário, Passo, Origem`
80
+ * **Backup**: versões antigas de `.feature` em `reports/backup` com timestamp
81
+ * **PDF**: exporta features em P/B para `reports/pdf` via `PDFExporter`
110
82
 
111
- Exemplos:
112
- | produto | quantidade | total esperado |
113
- | Camiseta Azul | 2 | 100 |
114
- | Tênis Branco | 1 | 250 |
115
- ```
83
+ ## Integração CI/CD
116
84
 
117
- 🧩 Step Definitions geradas
118
- ```ruby
119
- Quando('adiciono "<produto>" com quantidade <quantidade>') do |produto, quantidade|
120
- pending 'Implementar passo: adiciono "<produto>" com quantidade <quantidade>'
121
- end
85
+ Exemplo de GitHub Actions:
122
86
 
123
- Então('vejo o total <total esperado>') do |total_esperado|
124
- pending 'Implementar passo: vejo o total <total esperado>'
125
- end
126
- ```
127
- 🧾 Rastreabilidade
128
- - Gera automaticamente um CSV em output/rastreabilidade.csv com:
129
- - Nome do cenário
130
- - Tipo (SUCCESS, FAILURE, etc.)
131
- - Caminho do .feature
132
- - Origem do .txt
133
-
134
- 🔄 Backup
135
- Toda vez que um .feature existente for sobrescrito, a versão anterior é salva em:
136
- ```
137
- backup/
138
- ```
139
- ✅ Execução em CI/CD (GitHub Actions)
140
87
  ```yaml
141
88
  jobs:
142
89
  gerar_bdd:
@@ -145,26 +92,11 @@ jobs:
145
92
  - uses: actions/checkout@v3
146
93
  - uses: ruby/setup-ruby@v1
147
94
  with:
148
- ruby-version: '3.2'
149
- - run: ruby main.rb
95
+ ruby-version: '3.x'
96
+ - run: bundle install
97
+ - run: bundle exec ruby -e "require 'bddgenx'; Bddgenx::Runner.execute(only_new: true)"
150
98
  ```
151
- ⚙️ Alternativa: Usar via Rake
152
-
153
- Você também pode executar a gem bddgenx com Rake, como em projetos Rails:
154
-
155
- Crie um arquivo Rakefile:
156
- ```ruby
157
- require "bddgenx"
158
- require "rake"
159
99
 
160
- namespace :bddgenx do
161
- desc "Gera arquivos .feature e steps a partir de arquivos .txt"
162
- task :gerar do
163
- Bddgenx::Runner.execute
164
- end
165
- end
166
- ```
100
+ ## Licença
167
101
 
168
- 👨‍💻 Autor
169
- David Nascimento – Projeto de automação BDD com Ruby – 2025
170
- ---
102
+ MIT © 2025 David Nascimento
data/Rakefile CHANGED
@@ -1,54 +1,55 @@
1
+ # Rakefile
2
+ # Tarefas para geração automática de BDD e relatórios com bddgenx
3
+
1
4
  require 'rake'
2
- require_relative 'lib/bddgenx.rb'
3
- require_relative 'lib/bddgenx/utils/porter'
4
- require_relative 'lib/bddgenx/integrations/jira'
5
- require_relative 'lib/bddgenx/integrations/testlink'
5
+ require 'fileutils'
6
+ require 'bddgenx'
6
7
 
7
8
  namespace :bddgenx do
9
+ desc 'Gerar arquivos .feature, steps, rastreabilidade e backups'
10
+ task :gerar, [:only_new, :input_dir] do |t, args|
11
+ # Parâmetros: only_new (true/false), input_dir (pasta com .txt)
12
+ args.with_defaults(only_new: 'false', input_dir: 'input')
13
+ only_new = args.only_new == 'true'
14
+ input_dir = args.input_dir
15
+
16
+ files = FileList["#{input_dir}/*.txt"]
17
+ if files.empty?
18
+ puts "❌ Nenhum arquivo encontrado em \#{input_dir}"
19
+ next
20
+ end
21
+
22
+ files.each do |file|
23
+ puts "🔄 Processando história: \#{file}"
24
+ historia = Bddgenx::Parser.ler_historia(file)
25
+ next unless Bddgenx::Validator.validar(historia)
26
+
27
+ feature_path, conteudo = Bddgenx::Generator.gerar_feature(historia)
28
+
29
+ Bddgenx::Backup.salvar_versao_antiga(feature_path)
30
+ Bddgenx::Generator.salvar_feature(feature_path, conteudo)
8
31
 
9
- desc "Gerar arquivos .feature, steps, rastreabilidade e backups"
10
- task :gerar do
11
- arquivos = Bddgenx::CLI.todos_arquivos('input')
12
- arquivos.each do |arquivo|
13
- puts "🔁 Executando: ruby bddgen.rb"
14
- system("ruby lib/bddgen.rb")
32
+ Bddgenx::StepsGenerator.gerar_passos(feature_path)
33
+ Bddgenx::Tracer.adicionar_entrada(historia, feature_path)
15
34
  end
16
35
 
36
+ puts "✅ Geração concluída#{' (apenas novos)' if only_new}!"
17
37
  end
18
38
 
19
- desc "Exportar todos os arquivos .feature para PDF"
39
+ desc 'Exportar todos os arquivos .feature para PDF'
20
40
  task :pdf do
21
- puts "📦 Exportando para PDF..."
22
- Bddgenx::PDFExporter.exportar_todos
41
+ puts '📦 Exportando features para PDF...'
42
+ result = Bddgenx::PDFExporter.exportar_todos
43
+ puts " Gerados: \#{result[:generated].size}, Pulados: \#{result[:skipped].size}"
23
44
  end
24
45
 
25
- desc "Enviar todos os cenários para o Jira"
26
- task :jira do
27
- jira = Bddgenx::Integrations::Jira.new(
28
- username: ENV['JIRA_USER'],
29
- api_token: ENV['JIRA_TOKEN'],
30
- site: ENV['JIRA_SITE'],
31
- project_key: ENV['JIRA_PROJECT']
32
- )
33
-
34
- Dir.glob("features/*.feature") do |arquivo|
35
- conteudo = File.read(arquivo)
36
- titulo = File.basename(arquivo, ".feature").gsub('_', ' ').capitalize
37
- jira.enviar_cenario(titulo, conteudo)
38
- end
39
- end
40
-
41
- desc "Enviar todos os cenários para o TestLink"
42
- task :testlink do
43
- testlink = Bddgen::Integrations::TestLink.new(
44
- ENV['TESTLINK_TOKEN'],
45
- ENV['TESTLINK_URL']
46
- )
47
-
48
- Dir.glob("features/*.feature") do |arquivo|
49
- conteudo = File.readlines(arquivo).reject { |l| l.strip.start_with?("#") || l.strip.empty? }
50
- titulo = File.basename(arquivo, ".feature").gsub('_', ' ').capitalize
51
- testlink.criar_caso_teste(ENV['TESTLINK_PLAN_ID'].to_i, titulo, conteudo)
46
+ desc 'Remover diretórios gerados (reports/ e features/)'
47
+ task :clean do
48
+ %w[reports features].each do |dir|
49
+ FileUtils.rm_rf(dir)
50
+ puts "🗑️ Diretório removido: \#{dir}"
52
51
  end
53
52
  end
54
53
  end
54
+
55
+ task default: 'bddgenx:gerar'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.43
1
+ 0.1.44
@@ -1,37 +1,82 @@
1
+ # lib/bddgenx/generator.rb
2
+ # encoding: utf-8
3
+ #
4
+ # Este arquivo define a classe Generator, responsável por gerar arquivos
5
+ # .feature a partir de um hash de história ou de um arquivo de história em texto.
6
+ # Suporta Gherkin em Português e Inglês, inclusão de tags, cenários simples
7
+ # e esquemas de cenário com exemplos.
8
+
1
9
  require 'fileutils'
2
- require_relative 'utils/tipo_param'
3
10
 
4
11
  module Bddgenx
12
+ # Gera cenários e arquivos .feature baseados em histórias e grupos de passos.
5
13
  class Generator
14
+ # Palavras-chave Gherkin em Português
15
+ # @return [Array<String>]
6
16
  GHERKIN_KEYS_PT = %w[Dado Quando Então E Mas].freeze
17
+
18
+ # Palavras-chave Gherkin em Inglês
19
+ # @return [Array<String>]
7
20
  GHERKIN_KEYS_EN = %w[Given When Then And But].freeze
21
+
22
+ # Mapeamento PT -> EN
23
+ # @return [Hash{String=>String}]
8
24
  GHERKIN_MAP_PT_EN = GHERKIN_KEYS_PT.zip(GHERKIN_KEYS_EN).to_h
25
+
26
+ # Mapeamento EN -> PT
27
+ # @return [Hash{String=>String}]
9
28
  GHERKIN_MAP_EN_PT = GHERKIN_KEYS_EN.zip(GHERKIN_KEYS_PT).to_h
29
+
30
+ # Conjunto de todas as palavras-chave suportadas (PT + EN)
31
+ # @return [Array<String>]
10
32
  ALL_KEYS = GHERKIN_KEYS_PT + GHERKIN_KEYS_EN
11
33
 
12
- # Divide raw example blocks into a single table
34
+ # Seleciona apenas as linhas que representam exemplos do cenário
35
+ #
36
+ # @param raw [Array<String>] Lista de linhas brutas do bloco de exemplos
37
+ # @return [Array<String>] Linhas que começam com '|' representando a tabela de exemplos
13
38
  def self.dividir_examples(raw)
14
39
  raw.select { |l| l.strip.start_with?('|') }
15
40
  end
16
41
 
17
- # Gera .feature a partir de hash ou arquivo de história
18
- # Respeita idioma em historia[:idioma]
42
+ # Gera conteúdo de um arquivo .feature a partir de um hash de história ou caminho para arquivo
43
+ #
44
+ # @param input [Hash, String]
45
+ # Objeto de história com chaves :idioma, :quero, :como, :para, :grupos
46
+ # Ou caminho para um arquivo de história que será lido via Parser.ler_historia
47
+ # @param override_path [String, nil]
48
+ # Caminho de saída alternativo para o arquivo .feature
49
+ # @raise [ArgumentError] Se Parser.ler_historia lançar erro ao ler arquivo
50
+ # @return [Array(String, String)] Array com caminho e conteúdo gerado
19
51
  def self.gerar_feature(input, override_path = nil)
20
52
  historia = input.is_a?(String) ? Parser.ler_historia(input) : input
21
- idioma = historia[:idioma] || 'pt'
22
- nome_base = historia[:quero].gsub(/[^a-z0-9]/i, '_')
23
- .downcase.split('_',3)[0,3].join('_')
24
- caminho = override_path.is_a?(String) ? override_path : "features/#{nome_base}.feature"
53
+ idioma = historia[:idioma] || 'pt'
54
+
55
+ # Geração do nome base do arquivo
56
+ nome_base = historia[:quero]
57
+ .gsub(/[^a-z0-9]/i, '_')
58
+ .downcase
59
+ .split('_', 3)
60
+ .first(3)
61
+ .join('_')
62
+
63
+ caminho = if override_path.is_a?(String)
64
+ override_path
65
+ else
66
+ "features/#{nome_base}.feature"
67
+ end
25
68
 
69
+ # Definição das palavras-chave Gherkin conforme idioma
26
70
  palavras = {
27
- feature: idioma=='en' ? 'Feature' : 'Funcionalidade',
28
- contexto: idioma=='en' ? 'Background' : 'Contexto',
29
- cenario: idioma=='en' ? 'Scenario' : 'Cenário',
30
- esquema: idioma=='en' ? 'Scenario Outline' : 'Esquema do Cenário',
31
- exemplos: idioma=='en' ? 'Examples' : 'Exemplos',
32
- regra: idioma=='en' ? 'Rule' : 'Regra'
71
+ feature: idioma == 'en' ? 'Feature' : 'Funcionalidade',
72
+ contexto: idioma == 'en' ? 'Background' : 'Contexto',
73
+ cenario: idioma == 'en' ? 'Scenario' : 'Cenário',
74
+ esquema: idioma == 'en' ? 'Scenario Outline' : 'Esquema do Cenário',
75
+ exemplos: idioma == 'en' ? 'Examples' : 'Exemplos',
76
+ regra: idioma == 'en' ? 'Rule' : 'Regra'
33
77
  }
34
78
 
79
+ # Cabeçalho do arquivo .feature
35
80
  conteudo = <<~GHK
36
81
  # language: #{idioma}
37
82
  #{palavras[:feature]}: #{historia[:quero].sub(/^Quero\s*/i,'')}
@@ -41,56 +86,51 @@ module Bddgenx
41
86
 
42
87
  GHK
43
88
 
44
- pt_map = GHERKIN_MAP_PT_EN
45
- en_map = GHERKIN_MAP_EN_PT
46
- detect = ALL_KEYS
89
+ pt_map = GHERKIN_MAP_PT_EN
90
+ en_map = GHERKIN_MAP_EN_PT
91
+ detect = ALL_KEYS
47
92
 
48
- historia[:grupos].each_with_index do |grupo, idx|
49
- passos = grupo[:passos] || []
93
+ historia[:grupos].each do |grupo|
94
+ passos = grupo[:passos] || []
50
95
  exemplos = grupo[:exemplos] || []
51
96
  next if passos.empty?
52
97
 
53
- tag_line = ["@#{grupo[:tipo].downcase}", ("@#{grupo[:tag]}" if grupo[:tag])].compact.join(' ')
98
+ # Linha de tags para o grupo
99
+ tag_line = ["@#{grupo[:tipo].downcase}",
100
+ ("@#{grupo[:tag]}" if grupo[:tag])]
101
+ .compact.join(' ')
54
102
 
55
103
  if exemplos.any?
56
- # Scenario Outline
104
+ # Cenário com Esquema
57
105
  conteudo << " #{tag_line}\n"
58
106
  conteudo << " #{palavras[:esquema]}: #{historia[:quero]}\n"
59
107
 
60
- # Renderiza cada passo, mapeando connector mesmo se não for Gherkin padrão
108
+ # Passos do cenário
61
109
  passos.each do |p|
62
- line = p.strip
63
- parts = line.split(' ', 2)
64
- # match connector case-insensitive
110
+ parts = p.strip.split(' ', 2)
65
111
  con_in = detect.find { |k| k.casecmp(parts[0]) == 0 } || parts[0]
66
- text = parts[1] || ''
67
- out_conn = idioma=='en' ? pt_map[con_in] || con_in : en_map[con_in] || con_in
68
- conteudo << " #{out_conn} #{text}
69
- "
112
+ text = parts[1] || ''
113
+ out_conn = idioma == 'en' ? pt_map[con_in] || con_in : en_map[con_in] || con_in
114
+ conteudo << " #{out_conn} #{text}\n"
70
115
  end
71
116
 
72
- # Monta tabela de exemplos completa
73
- # Renderiza o bloco de Examples exatamente como veio no TXT
117
+ # Bloco de exemplos original
74
118
  conteudo << "\n #{palavras[:exemplos]}:\n"
75
119
  exemplos.select { |l| l.strip.start_with?('|') }.each do |line|
76
- # Remove aspas apenas das células, mantendo todas as colunas e valores originais
77
120
  cleaned = line.strip.gsub(/^"|"$/, '')
78
121
  conteudo << " #{cleaned}\n"
79
122
  end
80
123
  conteudo << "\n"
81
124
  else
82
- # Scenario simples
125
+ # Cenário simples
83
126
  conteudo << " #{tag_line}\n"
84
127
  conteudo << " #{palavras[:cenario]}: #{grupo[:tipo].capitalize}\n"
85
128
  passos.each do |p|
86
- line = p.strip
87
- parts = line.split(' ', 2)
88
- # match connector case-insensitive
129
+ parts = p.strip.split(' ', 2)
89
130
  con_in = detect.find { |k| k.casecmp(parts[0]) == 0 } || parts[0]
90
- text = parts[1] || ''
91
- out_conn = idioma=='en' ? pt_map[con_in] || con_in : en_map[con_in] || con_in
92
- conteudo << " #{out_conn} #{text}
93
- "
131
+ text = parts[1] || ''
132
+ out_conn = idioma == 'en' ? pt_map[con_in] || con_in : en_map[con_in] || con_in
133
+ conteudo << " #{out_conn} #{text}\n"
94
134
  end
95
135
  conteudo << "\n"
96
136
  end
@@ -99,10 +139,15 @@ module Bddgenx
99
139
  [caminho, conteudo]
100
140
  end
101
141
 
142
+ # Salva o conteúdo gerado em arquivo .feature no disco
143
+ #
144
+ # @param caminho [String] Caminho completo para salvar o arquivo
145
+ # @param conteudo [String] Conteúdo do arquivo .feature
146
+ # @return [nil]
102
147
  def self.salvar_feature(caminho, conteudo)
103
148
  FileUtils.mkdir_p(File.dirname(caminho))
104
149
  File.write(caminho, conteudo)
105
150
  puts "✅ Arquivo .feature gerado: #{caminho}"
106
151
  end
107
152
  end
108
- end
153
+ end