specimen 0.0.1.alpha.b

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '091d4e836ac67953118af5d330c4254d7e29716b7cb3e2756369b45a0ba74a88'
4
+ data.tar.gz: 69249e8db11054399bbc70c2fdee9163b9cbac769ae79ed55182c61f4083448a
5
+ SHA512:
6
+ metadata.gz: 83f173e5ecfe205b8581e18851aed9de5e0e19f52c995790f53af3316d7e16238d8ff02104339c360caf0db07916347c157664c955522bc89b6ad2a6c28dbcbe
7
+ data.tar.gz: 0ab049182afb589bfe054d0325114cd0d3536c4ec9990df0e222bfd5ef8713e93b2e901dbf2ae534794e9fda09d5bd4a42a87e778d8142346ea6f1bd50d817fc
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # specimen
2
+
3
+ Doing the same things over and over again in test automation was the initial inspiration of coming up with a gem which
4
+ will help me with:
5
+
6
+ - setting up a new test automation project, including README, Gemfile, rubocop.yml, etc...
7
+ - run Cucumber and RSpec tests with configs that make sense (e.g. parallel execution, reporting)
8
+ - provide a Rails like templating approach in terms of _convention over configuration_ to provide a maintainable base for
9
+ API or UI tests using RSpec and/or Cucumber.
10
+
11
+
12
+ **Beware**
13
+
14
+ At the point of writing the README and setting the repo to public, the gem does not do much yet so the current functionality
15
+ is minimal, not optimized and not tested :). Hopefully that will change in the future.
16
+
17
+ ```shell
18
+ # install Specimen gem
19
+ $> gem install specimen
20
+
21
+ # creates a new project relative to the current working directory. Will ask for a project name.
22
+ $> specimen init
23
+
24
+ # creates a new project 'foobar' relative to the current working directory.
25
+ # Inside /foobar you will find the default dir structures for Cucumber and RSpec tests and a few more files
26
+ $> specimen init -n foobar
27
+
28
+ # look at the command help
29
+ $> specimen help init
30
+ Usage:
31
+ specimen init
32
+
33
+ Options:
34
+ --name, -n, [--project-name=PROJECT_NAME]
35
+ [--api-only], [--no-api-only], [--skip-api-only] # Default: false
36
+ [--cucumber], [--no-cucumber], [--skip-cucumber] # Default: true
37
+ ```
38
+
39
+
40
+ ### Known issues
41
+
42
+ - tests are missing
43
+ - generated Gemfile contains Watir and Selenium webdriver, it should be only one of them.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1.alpha.b
data/bin/specimen ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_path = File.expand_path('..', __dir__) + '/lib'
4
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
5
+
6
+ require 'specimen/cli'
7
+ Specimen::CLI.start!(ARGV.dup)
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'specimen/generator'
4
+
5
+ module Specimen
6
+ module CLI
7
+ class DefaultCommand < Commands::BaseCommand
8
+ include Generator
9
+
10
+ namespace :default
11
+
12
+ def self.banner(task, namespace = true, subcommand = false)
13
+ "#{basename} #{task.name}"
14
+ end
15
+
16
+ def self.source_root
17
+ File.dirname(__FILE__)
18
+ end
19
+
20
+ desc 'init', 'Initialize a new Specimen project'
21
+
22
+ method_option :project_name, aliases: %w[--name -n], type: :string, default: ''
23
+ method_option :api_only, type: :boolean, default: false
24
+ method_option :cucumber, type: :boolean, default: true
25
+
26
+ def init
27
+ SpecimenProject.start([options.dup])
28
+ end
29
+
30
+ desc 'commands', 'print all commands'
31
+
32
+ def commands
33
+ [DefaultCommand].each { |cmd| cmd.new.help }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'specimen'
4
+ require 'specimen/cli/default_command'
5
+
6
+ module Specimen
7
+ module CLI
8
+ class << self
9
+ def start!(args = ARGV)
10
+ command = args.shift
11
+
12
+ case command
13
+ when '--version', '-v'
14
+ show_version
15
+ else
16
+ DefaultCommand.start(ARGV.dup)
17
+ end
18
+ end
19
+
20
+ def show_version
21
+ puts(Specimen::VERSION::STRING)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module Specimen
6
+ module Commands
7
+ class BaseCommand < Thor
8
+ include Thor::Actions
9
+
10
+ def self.banner(task, namespace = true, subcommand = false)
11
+ "#{basename} #{self.namespace} #{task.name}"
12
+ end
13
+ end
14
+
15
+ class BaseGroupCommand < Thor::Group
16
+ include Thor::Actions
17
+
18
+ def self.banner(task, namespace = true, subcommand = false)
19
+ "#{basename} #{self.namespace} #{task.name}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Returns a new hash with all keys converted to strings.
5
+ #
6
+ # hash = { name: 'Rob', age: '28' }
7
+ #
8
+ # hash.stringify_keys
9
+ # # => {"name"=>"Rob", "age"=>"28"}
10
+ def stringify_keys
11
+ transform_keys(&:to_s)
12
+ end
13
+
14
+ # Destructively converts all keys to strings. Same as
15
+ # +stringify_keys+, but modifies +self+.
16
+ def stringify_keys!
17
+ transform_keys!(&:to_s)
18
+ end
19
+
20
+ # Returns a new hash with all keys converted to symbols, as long as
21
+ # they respond to +to_sym+.
22
+ #
23
+ # hash = { 'name' => 'Rob', 'age' => '28' }
24
+ #
25
+ # hash.symbolize_keys
26
+ # # => {:name=>"Rob", :age=>"28"}
27
+ def symbolize_keys
28
+ transform_keys { |key| key.to_sym rescue key }
29
+ end
30
+ alias_method :to_options, :symbolize_keys
31
+
32
+ # Destructively converts all keys to symbols, as long as they respond
33
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
34
+ def symbolize_keys!
35
+ transform_keys! { |key| key.to_sym rescue key }
36
+ end
37
+ alias_method :to_options!, :symbolize_keys!
38
+
39
+ # Validates all keys in a hash match <tt>*valid_keys</tt>, raising
40
+ # +ArgumentError+ on a mismatch.
41
+ #
42
+ # Note that keys are treated differently than HashWithIndifferentAccess,
43
+ # meaning that string and symbol keys will not match.
44
+ #
45
+ # { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
46
+ # { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
47
+ # { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
48
+ def assert_valid_keys(*valid_keys)
49
+ valid_keys.flatten!
50
+ each_key do |k|
51
+ unless valid_keys.include?(k)
52
+ raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}")
53
+ end
54
+ end
55
+ end
56
+
57
+ # Returns a new hash with all keys converted by the block operation.
58
+ # This includes the keys from the root hash and from all
59
+ # nested hashes and arrays.
60
+ #
61
+ # hash = { person: { name: 'Rob', age: '28' } }
62
+ #
63
+ # hash.deep_transform_keys{ |key| key.to_s.upcase }
64
+ # # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
65
+ def deep_transform_keys(&block)
66
+ _deep_transform_keys_in_object(self, &block)
67
+ end
68
+
69
+ # Destructively converts all keys by using the block operation.
70
+ # This includes the keys from the root hash and from all
71
+ # nested hashes and arrays.
72
+ def deep_transform_keys!(&block)
73
+ _deep_transform_keys_in_object!(self, &block)
74
+ end
75
+
76
+ # Returns a new hash with all keys converted to strings.
77
+ # This includes the keys from the root hash and from all
78
+ # nested hashes and arrays.
79
+ #
80
+ # hash = { person: { name: 'Rob', age: '28' } }
81
+ #
82
+ # hash.deep_stringify_keys
83
+ # # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
84
+ def deep_stringify_keys
85
+ deep_transform_keys(&:to_s)
86
+ end
87
+
88
+ # Destructively converts all keys to strings.
89
+ # This includes the keys from the root hash and from all
90
+ # nested hashes and arrays.
91
+ def deep_stringify_keys!
92
+ deep_transform_keys!(&:to_s)
93
+ end
94
+
95
+ # Returns a new hash with all keys converted to symbols, as long as
96
+ # they respond to +to_sym+. This includes the keys from the root hash
97
+ # and from all nested hashes and arrays.
98
+ #
99
+ # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
100
+ #
101
+ # hash.deep_symbolize_keys
102
+ # # => {:person=>{:name=>"Rob", :age=>"28"}}
103
+ def deep_symbolize_keys
104
+ deep_transform_keys { |key| key.to_sym rescue key }
105
+ end
106
+
107
+ # Destructively converts all keys to symbols, as long as they respond
108
+ # to +to_sym+. This includes the keys from the root hash and from all
109
+ # nested hashes and arrays.
110
+ def deep_symbolize_keys!
111
+ deep_transform_keys! { |key| key.to_sym rescue key }
112
+ end
113
+
114
+ private
115
+ # Support methods for deep transforming nested hashes and arrays.
116
+ def _deep_transform_keys_in_object(object, &block)
117
+ case object
118
+ when Hash
119
+ object.each_with_object(self.class.new) do |(key, value), result|
120
+ result[yield(key)] = _deep_transform_keys_in_object(value, &block)
121
+ end
122
+ when Array
123
+ object.map { |e| _deep_transform_keys_in_object(e, &block) }
124
+ else
125
+ object
126
+ end
127
+ end
128
+
129
+ def _deep_transform_keys_in_object!(object, &block)
130
+ case object
131
+ when Hash
132
+ object.keys.each do |key|
133
+ value = object.delete(key)
134
+ object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
135
+ end
136
+ object
137
+ when Array
138
+ object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
139
+ else
140
+ object
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specimen
4
+ module Generator
5
+ class FileByTemplate < Commands::BaseGroupCommand
6
+ argument :template_file, type: :string
7
+ argument :destination, type: :string
8
+ argument :data, type: :hash, default: {}
9
+
10
+ def self.source_root
11
+ "#{File.dirname(__FILE__)}/templates"
12
+ end
13
+
14
+ def create
15
+ template(template_file, destination, data)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'specimen_project_config'
4
+
5
+ module Specimen
6
+ module Generator
7
+ class SpecimenProject < Commands::BaseGroupCommand
8
+ include Generator
9
+
10
+ argument :project_options
11
+
12
+ def self.source_root
13
+ "#{File.dirname(__FILE__)}/templates"
14
+ end
15
+
16
+ def initialize(_, _, _)
17
+ super
18
+ @opts = project_options.to_h.deep_symbolize_keys
19
+ end
20
+
21
+ def start
22
+ say('Initialize new Specimen project', Color::BOLD)
23
+
24
+ @opts[:project_name].empty? ? ask_for_name : @opts[:project_name]
25
+ @opts[:destination_root] = destination_root
26
+ @config = SpecimenProjectConfig.new(@opts)
27
+ end
28
+
29
+ def execute
30
+ empty_directory(@config.project_name)
31
+ create_root_files
32
+
33
+ inside @config.project_root do
34
+ if @config.cucumber?
35
+ empty_directory('features/step_definitions')
36
+ empty_directory('features/support')
37
+ end
38
+
39
+ empty_directory('spec/support')
40
+ end
41
+ end
42
+
43
+ def finish
44
+ say("created new Specimen project in #{@config.project_root}", Color::GREEN)
45
+ end
46
+
47
+ no_commands do
48
+ def ask_for_name
49
+ @opts[:project_name] = ask('What is the name of the project?')
50
+ end
51
+
52
+ def create_root_files
53
+ project_root_files.each do |file|
54
+ dest = dot_files.include?(file) ? ".#{file}" : file
55
+ create_file_by_template(file, "#{@config.project_root}/#{dest}", @config.data)
56
+ end
57
+ end
58
+
59
+ def dot_files
60
+ %w[gemrc rbenv-gemsets rubocop.yml]
61
+ end
62
+
63
+ def project_root_files
64
+ %w[gemrc
65
+ rbenv-gemsets
66
+ rubocop.yml
67
+ Gemfile
68
+ README.md]
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specimen
4
+ module Generator
5
+ class SpecimenProjectConfig
6
+ GEM_LIST = %w[
7
+ activesupport dotenv ffaker rest-client thor uuid
8
+ cucumber cuke_modeler parallel_tests rspec
9
+ selenium-webdriver watir
10
+ debug pry rubocop
11
+ ].freeze
12
+
13
+ def initialize(options)
14
+ @options = options
15
+ end
16
+
17
+ def data
18
+ @data ||= {
19
+ project_name: project_name,
20
+ gems: project_gems,
21
+ project_root: project_root,
22
+ api_only: api_only?,
23
+ cucumber: cucumber?
24
+ }
25
+ end
26
+
27
+ def project_gems
28
+ gems.reject! { |gem| gem.eql?('selenium-webdriver') || gem.eql?('watir') } if api_only?
29
+ gems.reject! { |gem| gem.eql?('cucumber') || gem.eql?('cuke_modeler') } unless cucumber?
30
+ gems.sort
31
+ end
32
+
33
+ def project_root
34
+ "#{@options[:destination_root]}/#{project_name}"
35
+ end
36
+
37
+ def project_name
38
+ @options[:project_name]
39
+ end
40
+
41
+ def gems
42
+ @gems ||= GEM_LIST.dup
43
+ end
44
+
45
+ def api_only?
46
+ @options[:api_only]
47
+ end
48
+
49
+ def cucumber?
50
+ @options[:cucumber]
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ <% data[:gems].sort.each do |gem| -%>
6
+ <% if gem == 'debug' || gem == 'pry' -%>
7
+ gem '<%= gem %>', require: false
8
+ <% else -%>
9
+ gem '<%= gem %>'
10
+ <% end -%>
11
+ <% end -%>
@@ -0,0 +1 @@
1
+ # <%= "#{data[:project_name]}" %>
@@ -0,0 +1 @@
1
+ gem: --no-rdoc --no-ri
@@ -0,0 +1 @@
1
+ <%= data[:project_name] %>-gems
@@ -0,0 +1,32 @@
1
+ Layout/LineLength:
2
+ Max: 120
3
+
4
+ Layout/SpaceInsideHashLiteralBraces:
5
+ EnforcedStyle: no_space
6
+
7
+ Metrics/AbcSize:
8
+ Enabled: false
9
+ CountRepeatedAttributes: true
10
+
11
+ Metrics/MethodLength:
12
+ Max: 25
13
+
14
+ Naming/AccessorMethodName:
15
+ Enabled: false
16
+
17
+ Style/Documentation:
18
+ Enabled: false
19
+
20
+ Style/EmptyCaseCondition:
21
+ Enabled: false
22
+
23
+ Style/HashSyntax:
24
+ EnforcedShorthandSyntax: either
25
+
26
+ Style/NumericLiterals:
27
+ Enabled: false
28
+
29
+ AllCops:
30
+ NewCops: enable
31
+ Exclude:
32
+ - '.irbrc'
@@ -0,0 +1 @@
1
+ project_name: 'Foo'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'generator/file_by_template'
4
+ require_relative 'generator/specimen_project'
5
+
6
+ module Specimen
7
+ module Generator
8
+ def create_file_by_template(template, destination, data = {})
9
+ FileByTemplate.start([template, destination, data])
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specimen
4
+ # Returns the currently loaded version of \Rails as a +Gem::Version+.
5
+ def self.gem_version
6
+ Gem::Version.new VERSION::STRING
7
+ end
8
+
9
+ module VERSION
10
+ MAJOR = 0
11
+ MINOR = 0
12
+ TINY = 1
13
+ PRE = "alpha.b"
14
+
15
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
+ end
17
+
18
+ end
data/lib/specimen.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ # require Ruby extensions
6
+ require 'specimen/extensions/ruby/hash'
7
+
8
+ require 'specimen/version'
9
+
10
+ module Specimen
11
+ extend ActiveSupport::Autoload
12
+
13
+ autoload :CLI
14
+ autoload :Commands
15
+ autoload :Generator
16
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: specimen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.alpha.b
5
+ platform: ruby
6
+ authors:
7
+ - Marek Witkowski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-06-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.14.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.14.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 13.2.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 13.2.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.64.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.64.1
83
+ description: Create maintainable automated tests using Rails-like COC approach
84
+ email: info@marekwitkowski.de
85
+ executables:
86
+ - specimen
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - README.md
91
+ - VERSION
92
+ - bin/specimen
93
+ - lib/specimen.rb
94
+ - lib/specimen/cli.rb
95
+ - lib/specimen/cli/default_command.rb
96
+ - lib/specimen/commands.rb
97
+ - lib/specimen/extensions/ruby/hash.rb
98
+ - lib/specimen/generator.rb
99
+ - lib/specimen/generator/file_by_template.rb
100
+ - lib/specimen/generator/specimen_project.rb
101
+ - lib/specimen/generator/specimen_project_config.rb
102
+ - lib/specimen/generator/templates/Gemfile.tt
103
+ - lib/specimen/generator/templates/README.md.tt
104
+ - lib/specimen/generator/templates/gemrc.tt
105
+ - lib/specimen/generator/templates/rbenv-gemsets.tt
106
+ - lib/specimen/generator/templates/rubocop.yml.tt
107
+ - lib/specimen/generator/templates/specimen/specimen.yml.tt
108
+ - lib/specimen/version.rb
109
+ homepage: https://github.com/dev-dots/specimen
110
+ licenses:
111
+ - MIT
112
+ metadata:
113
+ bug_tracker_uri: https://github.com/dev-dots/specimen/issues
114
+ rubygems_mfa_required: 'true'
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '3.0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: 3.0.1
129
+ requirements: []
130
+ rubygems_version: 3.5.11
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: Specimen
134
+ test_files: []