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 +4 -4
- data/CHANGELOG.md +27 -0
- data/bin/howitzer +10 -10
- data/generators/base_generator.rb +18 -8
- data/generators/config/templates/default.yml +7 -0
- data/generators/root/root_generator.rb +5 -1
- data/generators/root/templates/Dockerfile +34 -0
- data/generators/root/templates/README.md.erb +33 -0
- data/generators/root/templates/docker-compose.yml.erb +9 -0
- data/lib/howitzer/mail_adapters/mailtrap.rb +3 -3
- data/lib/howitzer/mail_adapters/onesecmail.rb +80 -0
- data/lib/howitzer/mail_adapters/testmail.rb +102 -0
- data/lib/howitzer/mailtrap_api/client.rb +18 -0
- data/lib/howitzer/onesecmail_api/client.rb +44 -0
- data/lib/howitzer/onesecmail_api.rb +7 -0
- data/lib/howitzer/testmail_api/client.rb +44 -0
- data/lib/howitzer/testmail_api.rb +7 -0
- data/lib/howitzer/utils/argument_convertable.rb +54 -0
- data/lib/howitzer/utils.rb +1 -0
- data/lib/howitzer/version.rb +1 -1
- data/lib/howitzer/web/element_dsl.rb +2 -54
- data/lib/howitzer/web/page_dsl.rb +1 -1
- data/lib/howitzer/web/section_dsl.rb +23 -23
- metadata +15 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b59a8a3bed744aeb4c97b117d141bbec762d24d398b97fe6ddfa4f955838360
|
4
|
+
data.tar.gz: 20b21155002eb01cb5e680b610b57f1d64d6b68ede1a683e32b74165d5d3c00e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
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 '#{
|
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(
|
122
|
-
|
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
|
-
|
195
|
+
@args = args
|
196
|
+
@project_name = args.first
|
197
|
+
super()
|
188
198
|
end
|
189
199
|
end
|
190
200
|
end
|
@@ -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: '
|
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`
|
@@ -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
|
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
|
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
|
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,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,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
|
data/lib/howitzer/utils.rb
CHANGED
data/lib/howitzer/version.rb
CHANGED
@@ -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
|
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
|
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
|
@@ -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
|
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
|
139
|
-
|
140
|
-
if
|
141
|
-
klass.new(self, capybara_context.find(*
|
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(*
|
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
|
150
|
-
|
151
|
-
if
|
152
|
-
capybara_context.all(*
|
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(*
|
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
|
161
|
-
|
162
|
-
if
|
163
|
-
capybara_context.has_selector?(*
|
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?(*
|
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
|
172
|
-
|
173
|
-
if
|
174
|
-
capybara_context.has_no_selector?(*
|
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?(*
|
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
|
+
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:
|
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: '
|
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: '
|
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.
|
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:
|