howitzer 2.4.0 → 2.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe051b3bfe068d7fe68f999882f1aac432ee24dd558438e3e0b6f195c7123885
4
- data.tar.gz: '09dca8df71b0ed83c4f0cf6f49679330628d92934f4e2e36bd861ddeb3ff2427'
3
+ metadata.gz: 3b59a8a3bed744aeb4c97b117d141bbec762d24d398b97fe6ddfa4f955838360
4
+ data.tar.gz: 20b21155002eb01cb5e680b610b57f1d64d6b68ede1a683e32b74165d5d3c00e
5
5
  SHA512:
6
- metadata.gz: 5265ec269dba8e334e2c1223ac788c2a65b331f2374d9007ae78a3c0b5fc1aa79a9ce65ccfff713efeec3a7e6531cf42fc413eeb722c908f916b7fd5efc8f34d
7
- data.tar.gz: 72948920c6c1cd9b437e766dc89bc205b12837c86e98a225ff05d853d17f16a4b833cbcc9febeeafd4b5ed3f60be915c0a67e779dd5d9967175c6b9e62cfc9f5
6
+ metadata.gz: 16a09f131e9b6f9ec714e654f1ee6796a8ffd4779f75fd3d8c13e7b42ad6267abbd9f1e258e5ae8552f6cf59d1a3aa4914345734bcd4738e305e5e62561da2b1
7
+ data.tar.gz: 4bad2e4917e4e19bb0eae5da2c699af26e70adbc558c52b21da9f12781d0c714f23e0d7ea02c8bbf6dc03df44402b488bd87ead92adbeb2d93a06be43e334d69
data/CHANGELOG.md CHANGED
@@ -4,6 +4,33 @@
4
4
 
5
5
  ### Bug-fixes
6
6
 
7
+ ## [2.6.0](https://github.com/strongqa/howitzer/compare/v2.5.0...v2.6.0) (2023-01-16)
8
+
9
+
10
+ ### Features
11
+
12
+ * Add Docker support ([#321](https://github.com/strongqa/howitzer/issues/321)) ([d0e7bc9](https://github.com/strongqa/howitzer/commit/d0e7bc953182b13e93b74ab4b609316ece6cf956))
13
+ * Ruby3.2 support ([#327](https://github.com/strongqa/howitzer/issues/327)) ([265acc3](https://github.com/strongqa/howitzer/commit/265acc34fb2eac9b879e097ae938e66c62a6e7f7))
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * Handle section options ([#324](https://github.com/strongqa/howitzer/issues/324)) ([b976e5b](https://github.com/strongqa/howitzer/commit/b976e5b83800fa1c0671857daba796dd8a1048f4))
19
+ * Section method typo ([#318](https://github.com/strongqa/howitzer/issues/318)) ([984deeb](https://github.com/strongqa/howitzer/commit/984deebe817d27278b93517b3f0e1338af25128a))
20
+
21
+ ## [2.5.0](https://github.com/strongqa/howitzer/compare/v2.4.0...v2.5.0) (2022-08-16)
22
+
23
+
24
+ ### Features
25
+
26
+ * 1secMail integration ([#316](https://github.com/strongqa/howitzer/issues/316)) ([6850758](https://github.com/strongqa/howitzer/commit/6850758370bd293d241f95c2a3cc0163c6fb3062))
27
+ * testmail.app integration ([#314](https://github.com/strongqa/howitzer/issues/314)) ([7f62bae](https://github.com/strongqa/howitzer/commit/7f62bae2e7e91200e02ed98acded9070726f3fc1))
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * mailtrap integration update ([#313](https://github.com/strongqa/howitzer/issues/313)) ([49e7390](https://github.com/strongqa/howitzer/commit/49e73909f7033d2986b0f5713bbbcbea7231ade0))
33
+
7
34
  ## [2.4.0](https://github.com/strongqa/howitzer/compare/v2.3.0...v2.4.0) (2022-07-22)
8
35
 
9
36
 
data/bin/howitzer CHANGED
@@ -31,21 +31,21 @@ module HowitzerCli
31
31
  Dir.mkdir(path_to_dir)
32
32
  puts " #{ColorizedString.new('Created').light_green} './#{args.first}' folder"
33
33
  Dir.chdir(path_to_dir)
34
- Howitzer::ConfigGenerator.new(options)
35
- Howitzer::WebGenerator.new(options)
36
- Howitzer::TasksGenerator.new(options)
37
- Howitzer::EmailsGenerator.new(options)
38
- Howitzer::RootGenerator.new(options)
39
- Howitzer::PrerequisitesGenerator.new(options)
34
+ Howitzer::ConfigGenerator.new(options, args)
35
+ Howitzer::WebGenerator.new(options, args)
36
+ Howitzer::TasksGenerator.new(options, args)
37
+ Howitzer::EmailsGenerator.new(options, args)
38
+ Howitzer::RootGenerator.new(options, args)
39
+ Howitzer::PrerequisitesGenerator.new(options, args)
40
40
  if options[:cucumber]
41
- Howitzer::CucumberGenerator.new(options)
41
+ Howitzer::CucumberGenerator.new(options, args)
42
42
  elsif options[:rspec]
43
- Howitzer::RspecGenerator.new(options)
43
+ Howitzer::RspecGenerator.new(options, args)
44
44
  elsif options['turnip']
45
- Howitzer::TurnipGenerator.new(options)
45
+ Howitzer::TurnipGenerator.new(options, args)
46
46
  end
47
47
  puts ColorizedString.new('[WARN] Extra parameters were skipped').yellow if args.size > 1
48
- elsif args.size.zero?
48
+ elsif args.empty?
49
49
  exit_now!(ColorizedString.new('Please specify <PROJECT NAME>').red, 64)
50
50
  end
51
51
  end
@@ -54,8 +54,8 @@ module Howitzer
54
54
  end
55
55
  end
56
56
 
57
- def initialize(_options)
58
- super()
57
+ def initialize
58
+ super
59
59
 
60
60
  manifest.each do |type, list|
61
61
  case type
@@ -72,6 +72,12 @@ module Howitzer
72
72
  []
73
73
  end
74
74
 
75
+ def template_context
76
+ data = options
77
+ data = options.merge(project_name: project_name) unless project_name.nil?
78
+ OpenStruct.new(data) # rubocop:disable Style/OpenStructUse
79
+ end
80
+
75
81
  protected
76
82
 
77
83
  def copy_files(list)
@@ -90,7 +96,7 @@ module Howitzer
90
96
  else
91
97
  write_template(destination_path, source_path)
92
98
  puts_info "#{ColorizedString.new('Added').light_green} template '#{data[:source]}' with " \
93
- "params '#{@options}' to destination '#{data[:destination]}'"
99
+ "params '#{template_context.to_h}' to destination '#{data[:destination]}'"
94
100
  end
95
101
  end
96
102
  end
@@ -118,8 +124,10 @@ module Howitzer
118
124
  end
119
125
 
120
126
  def write_template(dest_path, source_path)
121
- File.write(dest_path, ERB.new(File.read(source_path), trim_mode: '-')
122
- .result(OpenStruct.new(@options).instance_eval { binding })) # rubocop:disable Style/OpenStructUse
127
+ File.write(
128
+ dest_path,
129
+ ERB.new(File.read(source_path), trim_mode: '-').result(template_context.instance_eval { binding })
130
+ )
123
131
  end
124
132
 
125
133
  private
@@ -177,14 +185,16 @@ module Howitzer
177
185
 
178
186
  # Parent class for all generators
179
187
  class BaseGenerator
180
- attr_reader :options
188
+ attr_reader :options, :args, :project_name
181
189
 
182
190
  include Outputable
183
191
  include Copyable
184
192
 
185
- def initialize(options = {})
193
+ def initialize(options = {}, args = [])
186
194
  @options = options.symbolize_keys
187
- super
195
+ @args = args
196
+ @project_name = args.first
197
+ super()
188
198
  end
189
199
  end
190
200
  end
@@ -120,3 +120,10 @@
120
120
  # -Gmail-
121
121
  gmail_login: gmail_address
122
122
  gmail_password: gmail_password
123
+
124
+ # -testmail.app-
125
+ testmail_api_key: testmail_api_key
126
+ testmail_namespace: testmail_namespace
127
+
128
+ # 1secMail
129
+ onesecmail_domain: 1secmail.com
@@ -7,12 +7,16 @@ module Howitzer
7
7
  { files:
8
8
  [
9
9
  { source: '.gitignore', destination: '.gitignore' },
10
+ { source: '.dockerignore', destination: '.dockerignore' },
11
+ { source: 'Dockerfile', destination: 'Dockerfile' },
10
12
  { source: 'Rakefile', destination: 'Rakefile' }
11
13
  ],
12
14
  templates:
13
15
  [
14
16
  { source: '.rubocop.yml.erb', destination: '.rubocop.yml' },
15
- { source: 'Gemfile.erb', destination: 'Gemfile' }
17
+ { source: 'docker-compose.yml.erb', destination: 'docker-compose.yml' },
18
+ { source: 'Gemfile.erb', destination: 'Gemfile' },
19
+ { source: 'README.md.erb', destination: 'README.md' }
16
20
  ] }
17
21
  end
18
22
 
@@ -0,0 +1,34 @@
1
+ FROM ruby:alpine
2
+
3
+ ENV CHROME_BIN=/usr/bin/chromium-browser \
4
+ CHROME_PATH=/usr/lib/chromium/ \
5
+ SEXY_SETTINGS_DELIMITER=";" \
6
+ CHROME_ARGS="window-size=1920x1080, disable-gpu, no-sandbox, disable-dev-shm-usage, disable-software-rasterizer"
7
+
8
+ RUN apk update && apk upgrade --no-cache --available \
9
+ && apk add --no-cache \
10
+ chromium firefox \
11
+ chromium-chromedriver \
12
+ ttf-freefont \
13
+ font-noto-emoji \
14
+ build-base bash \
15
+ curl \
16
+ git \
17
+ less dbus \
18
+ && apk add --no-cache \
19
+ --repository=https://dl-cdn.alpinelinux.org/alpine/edge/testing font-wqy-zenhei \
20
+ && wget https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz \
21
+ && tar -zxf geckodriver-v0.31.0-linux64.tar.gz -C /usr/bin \
22
+ && dbus-daemon --system
23
+
24
+ RUN adduser -D howitzer
25
+ USER howitzer
26
+
27
+ WORKDIR /home/howitzer
28
+
29
+ COPY --chown=howitzer Gemfile Gemfile.lock /home/howitzer/
30
+ RUN bundle config --global && bundle install --jobs=3 --retry=3
31
+
32
+ COPY --chown=howitzer . ./
33
+
34
+ ENTRYPOINT ["sleep", "infinity"]
@@ -0,0 +1,33 @@
1
+ # <%= project_name %>
2
+
3
+ ## Run tests in Docker
4
+
5
+ ### Build an image
6
+
7
+ `docker build -t <%= project_name %> .`
8
+
9
+ ### Run a container
10
+
11
+ `docker run -d --name <%= project_name %>_container <%= project_name %>
12
+
13
+ ### Connect to the container
14
+
15
+ `docker exec -it <%= project_name %>_container /bin/bash`
16
+
17
+ ### Run tests in the container
18
+
19
+ `SEXY_SETTINGS="driver=headless_chrome; headless_chrome_flags=$CHROME_ARGS" bundle exec rake`
20
+
21
+ or
22
+
23
+ `SEXY_SETTINGS="driver=headless_firefox" bundle exec rake`
24
+
25
+ ## Run tests via docker compose
26
+
27
+ ### Initialize build, and run a container in detached mode
28
+
29
+ `docker-compose -f docker-compose.yml up -d`
30
+
31
+ ### Connect to the container
32
+
33
+ `docker compose exec -it <%= project_name %> /bin/bash`
@@ -0,0 +1,9 @@
1
+ version: '1.0'
2
+
3
+ services:
4
+ <%= project_name %>:
5
+ build:
6
+ context: "."
7
+ dockerfile: Dockerfile
8
+ volumes:
9
+ - '.:/home/howitzer/:cached'
@@ -24,19 +24,19 @@ module Howitzer
24
24
  # @return [String] plain text body of the email message
25
25
 
26
26
  def plain_text_body
27
- message['text_body']
27
+ Howitzer::MailtrapApi::Client.new.get_txt_body(message)
28
28
  end
29
29
 
30
30
  # @return [String] html body of the email message
31
31
 
32
32
  def html_body
33
- message['html_body']
33
+ Howitzer::MailtrapApi::Client.new.get_html_body(message)
34
34
  end
35
35
 
36
36
  # @return [String] stripped text
37
37
 
38
38
  def text
39
- message['text_body']
39
+ Howitzer::MailtrapApi::Client.new.get_raw_body(message)
40
40
  end
41
41
 
42
42
  # @return [String] an email address specified in `From` field
@@ -0,0 +1,80 @@
1
+ require 'howitzer/exceptions'
2
+ require 'howitzer/mail_adapters/abstract'
3
+ require 'howitzer/onesecmail_api/client'
4
+
5
+ module Howitzer
6
+ module MailAdapters
7
+ # This class represents 1secMail mail adapter
8
+ class Onesecmail < Abstract
9
+ # Finds an email in storage
10
+ # @param recipient [String] an email
11
+ # @param subject [String]
12
+ # @param wait [Integer] how much time is required to wait an email
13
+ # @raise [EmailNotFoundError] if blank message
14
+
15
+ def self.find(recipient, subject, wait:)
16
+ message = {}
17
+ retryable(find_retry_params(wait)) { message = retrieve_message(recipient, subject) }
18
+ return new(message) if message.present?
19
+
20
+ raise Howitzer::EmailNotFoundError,
21
+ "Message with subject '#{subject}' for recipient '#{recipient}' was not found."
22
+ end
23
+
24
+ # @return [String] plain text body of the email message
25
+
26
+ def plain_text_body
27
+ message['body']
28
+ end
29
+
30
+ # @return [String] html body of the email message
31
+
32
+ def html_body
33
+ message['htmlBody']
34
+ end
35
+
36
+ # @return [String] stripped text
37
+
38
+ def text
39
+ message['textBody']
40
+ end
41
+
42
+ # @return [String] an email address specified in `From` field
43
+
44
+ def mail_from
45
+ message['from']
46
+ end
47
+
48
+ # @return [String] when email was received
49
+
50
+ def received_time
51
+ Time.parse(message['date']).to_s
52
+ end
53
+
54
+ # @return [String] a real sender email address
55
+
56
+ def sender_email
57
+ message['from']
58
+ end
59
+
60
+ def self.find_retry_params(wait)
61
+ {
62
+ timeout: wait,
63
+ sleep: Howitzer.mail_sleep_time,
64
+ silent: true,
65
+ logger: Howitzer::Log,
66
+ on: Howitzer::EmailNotFoundError
67
+ }
68
+ end
69
+ private_class_method :find_retry_params
70
+
71
+ def self.retrieve_message(recipient, subject)
72
+ message = Howitzer::OnesecmailApi::Client.new.find_message(recipient, subject)
73
+ raise Howitzer::EmailNotFoundError, 'Message not received yet, retry...' unless message
74
+
75
+ message
76
+ end
77
+ private_class_method :retrieve_message
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,102 @@
1
+ require 'howitzer/exceptions'
2
+ require 'howitzer/mail_adapters/abstract'
3
+ require 'howitzer/testmail_api/client'
4
+
5
+ module Howitzer
6
+ module MailAdapters
7
+ # This class represents testmail.app mail adapter
8
+ class Testmail < Abstract
9
+ # Finds an email in storage
10
+ # @param recipient [String] an email
11
+ # @param subject [String]
12
+ # @param wait [Integer] how much time is required to wait an email
13
+ # @raise [EmailNotFoundError] if blank message
14
+
15
+ def self.find(recipient, subject, wait:)
16
+ message = {}
17
+ retryable(find_retry_params(wait)) { message = retrieve_message(recipient, subject) }
18
+ return new(message) if message.present?
19
+
20
+ raise Howitzer::EmailNotFoundError,
21
+ "Message with subject '#{subject}' for recipient '#{recipient}' was not found."
22
+ end
23
+
24
+ # @return [String] plain text body of the email message
25
+
26
+ def plain_text_body
27
+ message['text']
28
+ end
29
+
30
+ # @return [String] html body of the email message
31
+
32
+ def html_body
33
+ message['html']
34
+ end
35
+
36
+ # @return [String] stripped text
37
+
38
+ def text
39
+ message['text']
40
+ end
41
+
42
+ # @return [String] an email address specified in `From` field
43
+
44
+ def mail_from
45
+ message['from']
46
+ end
47
+
48
+ # @return [String] recipient emails separated with `, `
49
+
50
+ def recipients
51
+ message['to'].split ', '
52
+ end
53
+
54
+ # @return [String] when email was received
55
+
56
+ def received_time
57
+ Time.parse(message['timestamp']).to_s
58
+ end
59
+
60
+ # @return [String] a real sender email address
61
+
62
+ def sender_email
63
+ message['from']
64
+ end
65
+
66
+ # @return [Array] attachments
67
+
68
+ def mime_part
69
+ message['attachments']
70
+ end
71
+
72
+ # @raise [NoAttachmentsError] if no attachments present
73
+ # @return [Array] attachments
74
+
75
+ def mime_part!
76
+ files = mime_part
77
+ return files if files.present?
78
+
79
+ raise Howitzer::NoAttachmentsError, 'No attachments were found.'
80
+ end
81
+
82
+ def self.find_retry_params(wait)
83
+ {
84
+ timeout: wait,
85
+ sleep: Howitzer.mail_sleep_time,
86
+ silent: true,
87
+ logger: Howitzer::Log,
88
+ on: Howitzer::EmailNotFoundError
89
+ }
90
+ end
91
+ private_class_method :find_retry_params
92
+
93
+ def self.retrieve_message(recipient, subject)
94
+ message = Howitzer::TestmailApi::Client.new.find_message(recipient, subject)
95
+ raise Howitzer::EmailNotFoundError, 'Message not received yet, retry...' unless message
96
+
97
+ message
98
+ end
99
+ private_class_method :retrieve_message
100
+ end
101
+ end
102
+ end
@@ -32,6 +32,24 @@ module Howitzer
32
32
  JSON.parse(RestClient.get("#{BASE_URL}/messages/#{message['id']}/attachments", 'Api-Token' => @api_token))
33
33
  end
34
34
 
35
+ def get_html_body(message)
36
+ RestClient.get("#{BASE_URL}/messages/#{message['id']}/body.html", 'Api-Token' => @api_token).body
37
+ rescue => e
38
+ raise Howitzer::CommunicationError, e.message
39
+ end
40
+
41
+ def get_txt_body(message)
42
+ RestClient.get("#{BASE_URL}/messages/#{message['id']}/body.txt", 'Api-Token' => @api_token).body
43
+ rescue => e
44
+ raise Howitzer::CommunicationError, e.message
45
+ end
46
+
47
+ def get_raw_body(message)
48
+ RestClient.get("#{BASE_URL}/messages/#{message['id']}/body.raw", 'Api-Token' => @api_token).body
49
+ rescue => e
50
+ raise Howitzer::CommunicationError, e.message
51
+ end
52
+
35
53
  private
36
54
 
37
55
  def messages(recipient)
@@ -0,0 +1,44 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+
4
+ module Howitzer
5
+ module OnesecmailApi
6
+ # A Onesecmail::Client object is used to communicate with the 1secMail API.
7
+ class Client
8
+ BASE_URL = 'https://www.1secmail.com/api/v1/'.freeze # :nodoc:
9
+
10
+ # Finds message according to given parameters
11
+ #
12
+ # @param recipient [String] this is recipient mail address for message filtering
13
+ # @param subject [String] this is subject of the message to filter particular message
14
+ # @return [Hash] json message parsed to ruby hash
15
+
16
+ def find_message(recipient, subject)
17
+ messages = filter_by_subject(recipient[/[^@]+/], subject)
18
+ latest_message(messages)
19
+ end
20
+
21
+ private
22
+
23
+ def messages(recipient_name)
24
+ JSON.parse(RestClient.get("#{BASE_URL}?action=getMessages&login=#{recipient_name}" \
25
+ "&domain=#{Howitzer.onesecmail_domain}"))
26
+ end
27
+
28
+ def latest_message(messages)
29
+ messages[0]
30
+ end
31
+
32
+ def filter_by_subject(recipient_name, subject)
33
+ result_messages = []
34
+ messages(recipient_name).each do |msg|
35
+ if msg['subject'] == subject
36
+ result_messages << JSON.parse(RestClient.get("#{BASE_URL}?action=readMessage&login=#{recipient_name}" \
37
+ "&domain=#{Howitzer.onesecmail_domain}&id=#{msg['id']}"))
38
+ end
39
+ end
40
+ result_messages
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,7 @@
1
+ module Howitzer
2
+ # This module holds simple implementation of 1secMail api client
3
+ module OnesecmailApi
4
+ end
5
+ end
6
+
7
+ require 'howitzer/onesecmail_api/client'
@@ -0,0 +1,44 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+
4
+ module Howitzer
5
+ module TestmailApi
6
+ # A Testmail::Client object is used to communicate with the testmail.app API.
7
+ class Client
8
+ BASE_URL = "https://api.testmail.app/api/json?apikey=#{Howitzer.testmail_api_key}" \
9
+ "&namespace=#{Howitzer.testmail_namespace}".freeze # :nodoc:
10
+
11
+ def initialize
12
+ @api_token = Howitzer.testmail_api_key
13
+ end
14
+
15
+ # Finds message according to given parameters
16
+ #
17
+ # @param recipient [String] this is recipient mail address for message filtering
18
+ # @param subject [String] this is subject of the message to filter particular message
19
+ # @return [Hash] json message parsed to ruby hash
20
+
21
+ def find_message(recipient, subject)
22
+ recipient = recipient.gsub(/.*\.([^@]+)@.*/, '\1')
23
+ messages = filter_by_subject(messages(recipient), subject)
24
+ latest_message(messages)
25
+ end
26
+
27
+ private
28
+
29
+ def messages(recipient)
30
+ JSON.parse(RestClient.get("#{BASE_URL}&tag=#{recipient}"))
31
+ end
32
+
33
+ def latest_message(messages)
34
+ messages[0]
35
+ end
36
+
37
+ def filter_by_subject(messages, subject)
38
+ result_messages = []
39
+ messages['emails'].each { |msg| result_messages << msg if msg['subject'] == subject }
40
+ result_messages
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,7 @@
1
+ module Howitzer
2
+ # This module holds simple implementation of testmail.app api client
3
+ module TestmailApi
4
+ end
5
+ end
6
+
7
+ require 'howitzer/testmail_api/client'
@@ -0,0 +1,54 @@
1
+ module Howitzer
2
+ module Utils
3
+ # This module mixes in private utils methods for section and element dsl
4
+ module ArgumentConvertable
5
+ private
6
+
7
+ def convert_arguments(args, options, block_args, block_options)
8
+ conv_args = args.map { |el| el.is_a?(Proc) ? proc_to_selector(el, block_args, block_options) : el }
9
+ args_options = pop_options_from_array(conv_args)
10
+ block_args_options = pop_options_from_array(block_args)
11
+ conv_options = [args_options, options, block_args_options, block_options].map do |el|
12
+ el.transform_keys(&:to_sym)
13
+ end.reduce(&:merge).except(:lambda_args)
14
+ [conv_args, conv_options]
15
+ end
16
+
17
+ def proc_to_selector(proc, block_args, block_options)
18
+ lambda_args = extract_lambda_args(block_args, block_options)
19
+ if lambda_args
20
+ if lambda_args[:keyword_args].present?
21
+ proc.call(*lambda_args[:args], **lambda_args[:keyword_args])
22
+ else
23
+ proc.call(*lambda_args[:args])
24
+ end
25
+ else
26
+ puts "WARNING! Passing lambda arguments with element options is deprecated.\n" \
27
+ "Please use 'lambda_args' method, for example: foo_element(lambda_args(title: 'Example'), wait: 10)"
28
+ proc.call(*block_args.shift(proc.arity))
29
+ end
30
+ end
31
+
32
+ def extract_lambda_args(block_args, block_options)
33
+ (block_args.first.is_a?(Hash) && block_args.first[:lambda_args]) || block_options[:lambda_args]
34
+ end
35
+
36
+ def pop_options_from_array(value)
37
+ if value.last.is_a?(Hash) && !value.last.key?(:lambda_args)
38
+ value.pop
39
+ else
40
+ {}
41
+ end
42
+ end
43
+
44
+ def lambda_args(*args, **keyword_args)
45
+ {
46
+ lambda_args: {
47
+ args: args,
48
+ keyword_args: keyword_args
49
+ }
50
+ }
51
+ end
52
+ end
53
+ end
54
+ end
@@ -8,4 +8,5 @@ module Howitzer
8
8
  end
9
9
  end
10
10
 
11
+ require 'howitzer/utils/argument_convertable'
11
12
  require 'howitzer/utils/string_extensions'
@@ -1,4 +1,4 @@
1
1
  # This module holds howitzer version
2
2
  module Howitzer
3
- VERSION = '2.4.0'.freeze # :nodoc:
3
+ VERSION = '2.6.0'.freeze # :nodoc:
4
4
  end
@@ -3,67 +3,16 @@ module Howitzer
3
3
  module Web
4
4
  # This module combines element dsl methods
5
5
  module ElementDsl
6
- # This module holds element helper methods
7
- module Helpers
8
- private
9
-
10
- def lambda_args(*args, **keyword_args)
11
- {
12
- lambda_args: {
13
- args: args,
14
- keyword_args: keyword_args
15
- }
16
- }
17
- end
18
- end
19
-
20
6
  include CapybaraContextHolder
21
- include Helpers
7
+ include Howitzer::Utils::ArgumentConvertable
22
8
 
23
9
  def self.included(base) # :nodoc:
24
10
  base.extend(ClassMethods)
25
11
  end
26
12
 
27
- def convert_arguments(args, options, block_args, block_options)
28
- conv_args = args.map { |el| el.is_a?(Proc) ? proc_to_selector(el, block_args, block_options) : el }
29
- args_options = pop_options_from_array(conv_args)
30
- block_args_options = pop_options_from_array(block_args)
31
- conv_options = [args_options, options, block_args_options, block_options].map do |el|
32
- el.transform_keys(&:to_sym)
33
- end.reduce(&:merge).except(:lambda_args)
34
- [conv_args, conv_options]
35
- end
36
-
37
- def proc_to_selector(proc, block_args, block_options)
38
- lambda_args = extract_lambda_args(block_args, block_options)
39
- if lambda_args
40
- if lambda_args[:keyword_args].present?
41
- proc.call(*lambda_args[:args], **lambda_args[:keyword_args])
42
- else
43
- proc.call(*lambda_args[:args])
44
- end
45
- else
46
- puts "WARNING! Passing lambda arguments with element options is deprecated.\n" \
47
- "Please use 'lambda_args' method, for example: foo_element(lambda_args(title: 'Example'), wait: 10)"
48
- proc.call(*block_args.shift(proc.arity))
49
- end
50
- end
51
-
52
- def extract_lambda_args(block_args, block_options)
53
- (block_args.first.is_a?(Hash) && block_args.first[:lambda_args]) || block_options[:lambda_args]
54
- end
55
-
56
- def pop_options_from_array(value)
57
- if value.last.is_a?(Hash) && !value.last.key?(:lambda_args)
58
- value.pop
59
- else
60
- {}
61
- end
62
- end
63
-
64
13
  # This module holds element dsl methods
65
14
  module ClassMethods
66
- include Helpers
15
+ include Howitzer::Utils::ArgumentConvertable
67
16
 
68
17
  protected
69
18
 
@@ -172,7 +121,6 @@ module Howitzer
172
121
  else
173
122
  capybara_context.find(*conv_args)
174
123
  end
175
- return nil
176
124
  end
177
125
  private "wait_for_#{name}_element"
178
126
  end
@@ -50,7 +50,7 @@ module Howitzer
50
50
  private
51
51
 
52
52
  def eval_in_out_context(*args, **options, &block)
53
- return nil if args.size.zero?
53
+ return nil if args.empty?
54
54
 
55
55
  name = args.shift
56
56
  return get_outer_instance_variable(name) if name.to_s.start_with?('@')
@@ -4,6 +4,7 @@ module Howitzer
4
4
  # This module combines section dsl methods
5
5
  module SectionDsl
6
6
  include CapybaraContextHolder
7
+ include Howitzer::Utils::ArgumentConvertable
7
8
 
8
9
  def self.included(base) # :nodoc:
9
10
  base.extend(ClassMethods)
@@ -11,6 +12,7 @@ module Howitzer
11
12
 
12
13
  # This module holds section dsl class methods
13
14
  module ClassMethods
15
+ include Howitzer::Utils::ArgumentConvertable
14
16
  # This class is for private usage only
15
17
  class SectionScope
16
18
  attr_accessor :section_class
@@ -61,9 +63,7 @@ module Howitzer
61
63
  # @raise [ArgumentError] when finder arguments were not specified
62
64
 
63
65
  def finder_options
64
- @options if @args.present? # it is ok to have blank options, so we rely here on the argments
65
-
66
- @finder_options ||= (section_class.default_finder_options || {})
66
+ @options.presence || section_class.default_finder_options || {}
67
67
  end
68
68
  end
69
69
 
@@ -135,45 +135,45 @@ module Howitzer
135
135
  private
136
136
 
137
137
  def define_section_method(klass, name, *args, **options)
138
- define_method("#{name}_section") do |**block_options|
139
- kwdargs = options.transform_keys(&:to_sym).merge(block_options.transform_keys(&:to_sym))
140
- if kwdargs.present?
141
- klass.new(self, capybara_context.find(*args, **kwdargs))
138
+ define_method("#{name}_section") do |*block_args, **block_options|
139
+ conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
140
+ if conv_options.present?
141
+ klass.new(self, capybara_context.find(*conv_args, **conv_options))
142
142
  else
143
- klass.new(self, capybara_context.find(*args))
143
+ klass.new(self, capybara_context.find(*conv_args))
144
144
  end
145
145
  end
146
146
  end
147
147
 
148
148
  def define_sections_method(klass, name, *args, **options)
149
- define_method("#{name}_sections") do |**block_options|
150
- kwdargs = options.transform_keys(&:to_sym).merge(block_options.transform_keys(&:to_sym))
151
- if kwdargs.present?
152
- capybara_context.all(*args, **kwdargs).map { |el| klass.new(self, el) }
149
+ define_method("#{name}_sections") do |*block_args, **block_options|
150
+ conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
151
+ if conv_options.present?
152
+ capybara_context.all(*conv_args, **conv_options).map { |el| klass.new(self, el) }
153
153
  else
154
- capybara_context.all(*args).map { |el| klass.new(self, el) }
154
+ capybara_context.all(*conv_args).map { |el| klass.new(self, el) }
155
155
  end
156
156
  end
157
157
  end
158
158
 
159
159
  def define_has_section_method(name, *args, **options)
160
- define_method("has_#{name}_section?") do |**block_options|
161
- kwdargs = options.transform_keys(&:to_sym).merge(block_options.transform_keys(&:to_sym))
162
- if kwdargs.present?
163
- capybara_context.has_selector?(*args, **kwdargs)
160
+ define_method("has_#{name}_section?") do |*block_args, **block_options|
161
+ conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
162
+ if conv_options.present?
163
+ capybara_context.has_selector?(*conv_args, **conv_options)
164
164
  else
165
- capybara_context.has_selector?(*args)
165
+ capybara_context.has_selector?(*conv_args)
166
166
  end
167
167
  end
168
168
  end
169
169
 
170
170
  def define_has_no_section_method(name, *args, **options)
171
- define_method("has_no_#{name}_section?") do |**block_options|
172
- kwdargs = options.transform_keys(&:to_sym).merge(block_options.transform_keys(&:to_sym))
173
- if kwdargs.present?
174
- capybara_context.has_no_selector?(*args, **kwdarg)
171
+ define_method("has_no_#{name}_section?") do |*block_args, **block_options|
172
+ conv_args, conv_options = convert_arguments(args, options, block_args, block_options)
173
+ if conv_options.present?
174
+ capybara_context.has_no_selector?(*conv_args, **conv_options)
175
175
  else
176
- capybara_context.has_no_selector?(*args)
176
+ capybara_context.has_no_selector?(*conv_args)
177
177
  end
178
178
  end
179
179
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: howitzer
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Parashchenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-22 00:00:00.000000000 Z
11
+ date: 2023-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '5'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '7'
22
+ version: '8'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '5'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '7'
32
+ version: '8'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: capybara
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -272,8 +272,11 @@ files:
272
272
  - generators/prerequisites/templates/user.rb
273
273
  - generators/prerequisites/templates/users.rb
274
274
  - generators/root/root_generator.rb
275
+ - generators/root/templates/Dockerfile
275
276
  - generators/root/templates/Gemfile.erb
277
+ - generators/root/templates/README.md.erb
276
278
  - generators/root/templates/Rakefile
279
+ - generators/root/templates/docker-compose.yml.erb
277
280
  - generators/rspec/rspec_generator.rb
278
281
  - generators/rspec/templates/example_spec.rb
279
282
  - generators/rspec/templates/rspec.rake
@@ -302,6 +305,8 @@ files:
302
305
  - lib/howitzer/mail_adapters/gmail.rb
303
306
  - lib/howitzer/mail_adapters/mailgun.rb
304
307
  - lib/howitzer/mail_adapters/mailtrap.rb
308
+ - lib/howitzer/mail_adapters/onesecmail.rb
309
+ - lib/howitzer/mail_adapters/testmail.rb
305
310
  - lib/howitzer/mailgun_api.rb
306
311
  - lib/howitzer/mailgun_api/client.rb
307
312
  - lib/howitzer/mailgun_api/connector.rb
@@ -314,8 +319,13 @@ files:
314
319
  - lib/howitzer/meta/entry.rb
315
320
  - lib/howitzer/meta/iframe.rb
316
321
  - lib/howitzer/meta/section.rb
322
+ - lib/howitzer/onesecmail_api.rb
323
+ - lib/howitzer/onesecmail_api/client.rb
317
324
  - lib/howitzer/tasks/framework.rake
325
+ - lib/howitzer/testmail_api.rb
326
+ - lib/howitzer/testmail_api/client.rb
318
327
  - lib/howitzer/utils.rb
328
+ - lib/howitzer/utils/argument_convertable.rb
319
329
  - lib/howitzer/utils/string_extensions.rb
320
330
  - lib/howitzer/version.rb
321
331
  - lib/howitzer/web.rb
@@ -336,7 +346,7 @@ licenses:
336
346
  metadata:
337
347
  bug_tracker_uri: https://github.com/strongqa/howitzer/issues
338
348
  changelog_uri: https://github.com/strongqa/howitzer/blob/master/CHANGELOG.md
339
- documentation_uri: https://www.rubydoc.info/gems/howitzer/2.4.0
349
+ documentation_uri: https://www.rubydoc.info/gems/howitzer/2.6.0
340
350
  source_code_uri: https://github.com/strongqa/howitzer
341
351
  rubygems_mfa_required: 'false'
342
352
  post_install_message: