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 +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:
|