howitzer 2.4.0 → 2.6.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: 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: