ruby_raider 0.7.9 → 0.8.0

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: d7c0a06c991fd4bbbf94bdf2ed6081b2177fa40d9ee7df174ff2d9bf5698c794
4
- data.tar.gz: 3ea6fb9b0d3b7aa19b77b8f8815b709b75ec14aee59dafd6a8dbfc98659abe38
3
+ metadata.gz: 5dd7827d45155a3d24655334c4c43a818812cc541fd76955c57d7588bfe3cbdc
4
+ data.tar.gz: 99da1055ac90cf2787ddffe02cba3afe2a653fbc41adca96f376d00de21b3f05
5
5
  SHA512:
6
- metadata.gz: 9194bd0c1e51230f6458e4aa038729e68301511227c4034130310894b278f57704a3fe9dc13e206b9df8ff419c9697370a1930a02a803e660bfa9409bfb11b01
7
- data.tar.gz: b8c71e244cc25bb7c2b95d82abf37c1fbf1a0af32460ef4e514daf974bb7d1071deba7636df89279e80c9bb3d95eab5778fbd561a15947be2eba6719d972e475
6
+ metadata.gz: f37c2a6ef6760ef66cf2cbb1f4e936205ba042cff82ab7a213cb3334a64b27624f41dfcb40dd8fc0095ebc29a50e61f127277ae8f90b533dfd3c4cc53f442ab4
7
+ data.tar.gz: 76504d52c72488dd6f4cd305424b3796e4a8108b5a516e1c90652a568ad481d443dca30325d7600b0e41b3f367b736368f5782ca5e985502e6dfcaa2427c6035
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../generator'
4
+
5
+ class ActionsGenerator < Generator
6
+ def generate_actions_file
7
+ return unless web?
8
+
9
+ template('actions.tt', "#{name}/.github/workflows/test_pipeline.yml")
10
+ end
11
+ end
@@ -0,0 +1,64 @@
1
+ name: <%- if framework == 'cucumber' -%>Cucumber Tests<%- else -%>Rspec Tests<%- end -%>
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ browser:
7
+ type: choice
8
+ description: Which browser to test
9
+ required: true
10
+ options:
11
+ - chrome
12
+
13
+ jobs:
14
+ build:
15
+ name: CI
16
+ runs-on: ubuntu-latest
17
+
18
+ steps:
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: 3.1.0
23
+ bundler-cache: true
24
+
25
+ - name: Checkout repository
26
+ uses: actions/checkout@v3
27
+
28
+ - name: Install gems
29
+ run: bundle install
30
+
31
+ - name: Create allure-results folder
32
+ run: mkdir -p allure-results
33
+
34
+ - name: Create screenshots folder
35
+ run: mkdir -p allure-results/screenshots
36
+
37
+ - name: Build and test with rspec
38
+ run: <%- if framework == 'cucumber' -%>cucumber features --format pretty <%- else -%>bundle exec rspec spec --format documentation<%- end -%>
39
+
40
+ - name: Get Allure history
41
+ uses: actions/checkout@v2
42
+ if: always()
43
+ continue-on-error: true
44
+ with:
45
+ ref: gh-pages
46
+ path: gh-pages
47
+
48
+ - name: Allure Report
49
+ uses: simple-elf/allure-report-action@master
50
+ if: always()
51
+ id: allure-report
52
+ with:
53
+ allure_results: allure-results
54
+ gh_pages: gh-pages
55
+ allure_report: allure-report
56
+ allure_history: allure-history
57
+
58
+ - name: Deploy report to Github Pages
59
+ if: always()
60
+ uses: peaceiris/actions-gh-pages@v2
61
+ env:
62
+ PERSONAL_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63
+ PUBLISH_BRANCH: gh-pages
64
+ PUBLISH_DIR: allure-history
@@ -70,7 +70,7 @@ class AutomationGenerator < Generator
70
70
  end
71
71
 
72
72
  def generate_header_component
73
- template('component.tt', "#{name}/page_objects/components/header_component.rb")
73
+ template('component.tt', "#{name}/page_objects/components/header.rb")
74
74
  end
75
75
 
76
76
  def generate_model_factory
@@ -14,14 +14,32 @@ class AbstractPage
14
14
  end
15
15
  end
16
16
  <%- else -%>
17
+ <% if web? -%>
18
+ require_relative '../components/header'
19
+ <% end -%>
20
+
17
21
  class AbstractPage
18
- <% if automation == 'cross_platform' -%>
22
+
23
+ <%- if automation == 'cross_platform' -%>
19
24
  include AppiumHelper
20
- <% end -%>
25
+ <%- end -%>
21
26
  <%= ERB.new(File.read(File.expand_path('./partials/initialize_selector.tt', __dir__))).result(binding) -%>
22
27
  <%= ERB.new(File.read(File.expand_path('./partials/visit_method.tt', __dir__))).result(binding) -%>
23
28
  <%= ERB.new(File.read(File.expand_path('./partials/url_methods.tt', __dir__))).result(binding) -%>
24
29
 
30
+ <%- if automation == 'selenium' -%>
31
+ # Components
32
+
33
+ def header
34
+ Header.new(driver.find_element(id: 'customernav'))
35
+ end
36
+ <%- elsif automation == 'watir' -%>
37
+ # Components
38
+
39
+ def header
40
+ Header.new(browser.element(id: 'customernav'))
41
+ end
42
+ <%- end -%>
25
43
  def to_s
26
44
  self.class.to_s.sub('Page', ' Page')
27
45
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_relative '../abstract/abstract_component'
4
4
 
5
- class HeaderComponent < AbstractComponent
5
+ class Header < AbstractComponent
6
6
  def customer_name
7
7
  component.text
8
8
  end
@@ -1,17 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../abstract/abstract_page'
4
- require_relative '../components/header_component'
5
4
 
6
5
  class AccountPage < AbstractPage
7
-
8
6
  def url(_page)
9
7
  'index.php?rt=account/account'
10
8
  end
11
-
12
- # Components
13
-
14
- def header
15
- HeaderComponent.new(driver.find_element(class: 'menu_text'))
16
- end
17
9
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../abstract/abstract_page'
4
- require_relative '../components/header_component'
5
4
 
6
5
  class LoginPage < AbstractPage
7
6
  def url(_page)
@@ -16,12 +15,6 @@ class LoginPage < AbstractPage
16
15
  login_button.click
17
16
  end
18
17
 
19
- # Components
20
-
21
- def header
22
- HeaderComponent.new(driver.find_element(class: 'menu_text'))
23
- end
24
-
25
18
  private
26
19
 
27
20
  # Elements
@@ -1,15 +1,7 @@
1
1
  require_relative '../abstract/abstract_page'
2
- require_relative '../components/header_component'
3
2
 
4
3
  class AccountPage < AbstractPage
5
-
6
4
  def url(_page)
7
5
  'index.php?rt=account/account'
8
6
  end
9
-
10
- # Components
11
-
12
- def header
13
- HeaderComponent.new(browser.element(class: 'menu_text'))
14
- end
15
7
  end
@@ -1,8 +1,6 @@
1
1
  require_relative '../abstract/abstract_page'
2
- require_relative '../components/header_component'
3
2
 
4
3
  class LoginPage < AbstractPage
5
-
6
4
  def url(_page)
7
5
  'index.php?rt=account/login'
8
6
  end
@@ -15,12 +13,6 @@ class LoginPage < AbstractPage
15
13
  login_button.click
16
14
  end
17
15
 
18
- # Components
19
-
20
- def header
21
- HeaderComponent.new(browser.element(class: 'menu_text'))
22
- end
23
-
24
16
  private
25
17
 
26
18
  # Elements
@@ -29,6 +29,10 @@ class CommonGenerator < Generator
29
29
  template('common/rubocop.tt', "#{name}/.rubocop.yml")
30
30
  end
31
31
 
32
+ def generate_gitignore_file
33
+ template('common/git_ignore.tt', "#{name}/.gitignore")
34
+ end
35
+
32
36
  def create_allure_folder
33
37
  empty_directory "#{name}/allure-results"
34
38
  end
@@ -35,7 +35,7 @@ require_relative '../../helpers/allure_helper'
35
35
  include DriverHelper
36
36
 
37
37
  Before do
38
- driver
38
+ driver.manage.window.maximize
39
39
  end
40
40
 
41
41
  After do |scenario|
@@ -6,7 +6,7 @@ require_relative '../../helpers/browser_helper'
6
6
  include BrowserHelper
7
7
 
8
8
  Before do
9
- browser
9
+ browser.window.maximize
10
10
  end
11
11
 
12
12
  After do |scenario|
@@ -12,7 +12,8 @@ class Generator < Thor::Group
12
12
 
13
13
  def self.source_paths
14
14
  base_path = File.dirname(__FILE__)
15
- %W[#{base_path}/automation/templates #{base_path}/cucumber/templates #{base_path}/rspec/templates #{base_path}/templates]
15
+ %W[#{base_path}/automation/templates #{base_path}/cucumber/templates
16
+ #{base_path}/rspec/templates #{base_path}/templates #{base_path}/actions/templates ]
16
17
  end
17
18
 
18
19
  def args
@@ -53,7 +54,7 @@ class Generator < Thor::Group
53
54
  end
54
55
 
55
56
  def web?
56
- args.include?(%w[selenium watir])
57
+ (args & (%w[selenium watir])).count.positive?
57
58
  end
58
59
 
59
60
  private
@@ -61,5 +62,6 @@ class Generator < Thor::Group
61
62
  def _initializer
62
63
  @_initializer ||= super
63
64
  end
65
+
64
66
  alias initializer _initializer
65
67
  end
@@ -1,3 +1,4 @@
1
+ require_relative 'actions/actions_generator'
1
2
  require_relative 'automation/automation_generator'
2
3
  require_relative 'common_generator'
3
4
  require_relative 'cucumber/cucumber_generator'
@@ -8,7 +9,7 @@ require_relative 'rspec/rspec_generator'
8
9
  # :reek:UtilityFunction { enabled: false }
9
10
  module InvokeGenerators
10
11
  def generate_framework(structure = {})
11
- generators = %w[Automation Common Helpers]
12
+ generators = %w[Automation Actions Common Helpers]
12
13
  framework = structure[:framework]
13
14
  add_generator(generators, framework.capitalize)
14
15
  generators.each do |generator|
@@ -4,7 +4,7 @@ require_relative '../generator'
4
4
 
5
5
  class RspecGenerator < Generator
6
6
  def generate_login_spec
7
- return if mobile?
7
+ return unless web?
8
8
 
9
9
  template('spec.tt', "#{name}/spec/login_page_spec.rb")
10
10
  end
@@ -37,7 +37,7 @@ describe 'Login' do
37
37
  <%- if visual_automation == true -%>
38
38
  check_page login_page
39
39
  <%- else -%>
40
- expect(header).to be_empty
40
+ expect(header).to eql 'Login or register'
41
41
  <%- end -%>
42
42
  end
43
43
  end
@@ -25,7 +25,7 @@ gem 'rubocop'
25
25
  <% if framework == 'rspec' -%>
26
26
  gem 'rubocop-rspec'
27
27
  <% end -%>
28
- gem 'ruby_raider', '~> 0.7.0'
28
+ gem 'ruby_raider', '~> 0.8.0'
29
29
  <%= ERB.new(File.read(File.expand_path('./partials/automation_gems.tt', __dir__))).result(binding).strip! %>
30
30
  <% if automation == 'sparkling_ios' -%>
31
31
  gem 'sparkling_watir'
@@ -0,0 +1 @@
1
+ allure-results
@@ -45,12 +45,20 @@ module SpecHelper
45
45
  config.before(:each) do
46
46
  driver.start_driver
47
47
  end
48
+ <%- elsif automation == 'selenium' -%>
49
+ config.before(:each) do
50
+ driver.manage.window.maximize
51
+ end
52
+ <%- elsif automation == 'watir' -%>
53
+ config.before(:each) do
54
+ browser.window.maximize
55
+ end
48
56
  <%- end -%>
49
57
 
50
58
  config.after(:each) do
51
59
  example_name = self.class.descendant_filtered_examples.first.description
52
60
  <%= ERB.new(File.read(File.expand_path('./partials/screenshot.tt', __dir__)), trim_mode: '-').result(binding).strip! %>
53
- AllureHelper.add_screenshot example_name
61
+ AllureHelper.add_screenshot example_name
54
62
  <%= ERB.new(File.read(File.expand_path('./partials/quit_driver.tt', __dir__)), trim_mode: '-').result(binding).strip! %>
55
63
  end
56
64
  end
data/lib/ruby_raider.rb CHANGED
@@ -19,7 +19,7 @@ module RubyRaider
19
19
  desc 'version', 'It shows the version of Ruby Raider you are currently using'
20
20
 
21
21
  def version
22
- puts 'The Ruby Raider version is 0.7.9, Happy testing!'
22
+ puts 'The Ruby Raider version is 0.8.0, Happy testing!'
23
23
  end
24
24
 
25
25
  map 'v' => 'version'
data/ruby_raider.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'ruby_raider'
5
- s.version = '0.7.9'
5
+ s.version = '0.8.0'
6
6
  s.summary = 'A gem to make setup and start of UI automation projects easier'
7
7
  s.description = 'This gem has everything you need to start working with test automation'
8
8
  s.authors = ['Agustin Pequeno']
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/generators/actions/actions_generator'
4
+ require_relative 'spec_helper'
5
+
6
+ describe ActionsGenerator do
7
+ shared_examples 'creates web automation framework' do |name|
8
+ it 'creates a github actions file' do
9
+ expect(File).to exist("#{name}/.github/workflows/test_pipeline.yml")
10
+ end
11
+ end
12
+
13
+ context 'with rspec and selenium' do
14
+ include_examples 'creates web automation framework', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[2]}"
15
+ end
16
+
17
+ context 'with rspec and watir' do
18
+ include_examples 'creates web automation framework', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[3]}"
19
+ end
20
+
21
+ context 'with cucumber and selenium' do
22
+ include_examples 'creates web automation framework', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[2]}"
23
+ end
24
+
25
+ context 'with cucumber and watir' do
26
+ include_examples 'creates web automation framework', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[3]}"
27
+ end
28
+ end
@@ -18,7 +18,7 @@ describe AutomationGenerator do
18
18
  end
19
19
 
20
20
  it 'creates a component file' do
21
- expect(File).to exist("#{name}/page_objects/components/header_component.rb")
21
+ expect(File).to exist("#{name}/page_objects/components/header.rb")
22
22
  end
23
23
  end
24
24
 
@@ -42,71 +42,89 @@ describe CommonGenerator do
42
42
  end
43
43
  end
44
44
 
45
+ shared_examples 'creates a gitignore file' do |name|
46
+ it 'creates a gitignore file' do
47
+ expect(File).to exist("#{name}/.gitignore")
48
+ end
49
+ end
50
+
45
51
  context 'with rspec and selenium' do
46
52
  include_examples 'creates common files', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[2]}"
47
53
  include_examples 'creates a config file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[2]}"
54
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[2]}"
48
55
  end
49
56
 
50
57
  context 'with rspec and watir' do
51
58
  include_examples 'creates common files', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[3]}"
52
59
  include_examples 'creates a config file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[3]}"
60
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[3]}"
53
61
  end
54
62
 
55
63
  context 'with rspec, selenium and applitools' do
56
64
  include_examples 'creates common files', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[2]}_visual"
57
65
  include_examples 'creates a config file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[2]}_visual"
58
66
  include_examples 'creates an options file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[2]}_visual"
67
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[2]}_visual"
59
68
  end
60
69
 
61
70
  context 'with rspec, watir and applitools' do
62
71
  include_examples 'creates common files', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[3]}_visual"
63
72
  include_examples 'creates a config file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[3]}_visual"
64
73
  include_examples 'creates an options file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[3]}_visual"
74
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[3]}_visual"
65
75
  end
66
76
 
67
77
  context 'with cucumber and selenium' do
68
78
  include_examples 'creates common files', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[2]}"
69
79
  include_examples 'creates a config file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[2]}"
80
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[2]}"
70
81
  end
71
82
 
72
83
  context 'with cucumber and watir' do
73
84
  include_examples 'creates common files', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[3]}"
74
85
  include_examples 'creates a config file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[3]}"
86
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[3]}"
75
87
  end
76
88
 
77
89
  context 'with rspec and appium android' do
78
90
  include_examples 'creates common files', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES.first}"
79
91
  include_examples 'creates a capabilities file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES.first}"
80
92
  include_examples "doesn't create a config file", "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES.first}"
93
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES.first}"
81
94
  end
82
95
 
83
96
  context 'with rspec and appium ios' do
84
97
  include_examples 'creates common files', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[1]}"
85
98
  include_examples 'creates a capabilities file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[1]}"
86
99
  include_examples "doesn't create a config file", "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[1]}"
100
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES[1]}"
87
101
  end
88
102
 
89
103
  context 'with cucumber and appium android' do
90
104
  include_examples 'creates common files', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES.first}"
91
105
  include_examples 'creates a capabilities file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES.first}"
92
106
  include_examples "doesn't create a config file", "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES.first}"
107
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES.first}"
93
108
  end
94
109
 
95
110
  context 'with cucumber and appium ios' do
96
111
  include_examples 'creates common files', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[1]}"
97
112
  include_examples 'creates a capabilities file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[1]}"
98
113
  include_examples "doesn't create a config file", "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES[1]}"
114
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES.first}"
99
115
  end
100
116
 
101
117
  context 'with cucumber and appium cross platform' do
102
118
  include_examples 'creates common files', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES.last}"
103
119
  include_examples 'creates a capabilities file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES.last}"
104
120
  include_examples 'creates a config file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES.last}"
121
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.first}_#{AUTOMATION_TYPES.last}"
105
122
  end
106
123
 
107
124
  context 'with rspec and appium cross platform' do
108
125
  include_examples 'creates common files', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES.last}"
109
126
  include_examples 'creates a capabilities file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES.last}"
110
127
  include_examples 'creates a config file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES.last}"
128
+ include_examples 'creates a gitignore file', "#{FRAMEWORKS.last}_#{AUTOMATION_TYPES.last}"
111
129
  end
112
130
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_raider
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.9
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Agustin Pequeno
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-27 00:00:00.000000000 Z
11
+ date: 2023-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -197,6 +197,8 @@ files:
197
197
  - lib/commands/open_ai_commands.rb
198
198
  - lib/commands/scaffolding_commands.rb
199
199
  - lib/commands/utility_commands.rb
200
+ - lib/generators/actions/actions_generator.rb
201
+ - lib/generators/actions/templates/actions.tt
200
202
  - lib/generators/automation/automation_generator.rb
201
203
  - lib/generators/automation/templates/abstract_component.tt
202
204
  - lib/generators/automation/templates/abstract_page.tt
@@ -245,6 +247,7 @@ files:
245
247
  - lib/generators/rspec/templates/spec.tt
246
248
  - lib/generators/templates/common/config.tt
247
249
  - lib/generators/templates/common/gemfile.tt
250
+ - lib/generators/templates/common/git_ignore.tt
248
251
  - lib/generators/templates/common/partials/automation_gems.tt
249
252
  - lib/generators/templates/common/partials/mobile_config.tt
250
253
  - lib/generators/templates/common/partials/web_config.tt
@@ -274,6 +277,7 @@ files:
274
277
  - lib/utilities/logger.rb
275
278
  - lib/utilities/utilities.rb
276
279
  - ruby_raider.gemspec
280
+ - spec/actions_generator_spec.rb
277
281
  - spec/automation_generator_spec.rb
278
282
  - spec/common_generator_spec.rb
279
283
  - spec/cucumber_generator_spec.rb