scarpe-components 0.1.0 → 0.3.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/Gemfile +22 -0
- data/Gemfile.lock +86 -0
- data/lib/scarpe/components/base64.rb +25 -0
- data/lib/scarpe/components/calzini/alert.rb +49 -0
- data/lib/scarpe/components/calzini/art_widgets.rb +203 -0
- data/lib/scarpe/components/calzini/button.rb +39 -0
- data/lib/scarpe/components/calzini/misc.rb +146 -0
- data/lib/scarpe/components/calzini/para.rb +35 -0
- data/lib/scarpe/components/calzini/slots.rb +155 -0
- data/lib/scarpe/components/calzini/text_widgets.rb +65 -0
- data/lib/scarpe/components/calzini.rb +149 -0
- data/lib/scarpe/components/errors.rb +20 -0
- data/lib/scarpe/components/file_helpers.rb +66 -0
- data/lib/scarpe/components/html.rb +131 -0
- data/lib/scarpe/components/minitest_export_reporter.rb +75 -0
- data/lib/scarpe/components/minitest_import_runnable.rb +98 -0
- data/lib/scarpe/components/minitest_result.rb +86 -0
- data/lib/scarpe/{logger.rb → components/modular_logger.rb} +11 -6
- data/lib/scarpe/components/print_logger.rb +47 -0
- data/lib/scarpe/components/promises.rb +454 -0
- data/lib/scarpe/components/segmented_file_loader.rb +189 -0
- data/lib/scarpe/components/string_helpers.rb +10 -0
- data/lib/scarpe/components/tiranti.rb +225 -0
- data/lib/scarpe/components/unit_test_helpers.rb +257 -0
- data/lib/scarpe/components/version.rb +7 -0
- metadata +28 -4
@@ -0,0 +1,225 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# In Italian, tiranti are bootstraps -- the literal pull-on-a-boot kind, not a step to something better.
|
4
|
+
# Tiranti.rb builds on calzini.rb, but renders a Bootstrap-decorated version of the HTML output.
|
5
|
+
# You would ordinarily set either Calzini or Tiranti as the top-level HTML renderer, not both.
|
6
|
+
# You'll include both if you use Tiranti, because it falls back to Calzini for a lot of its rendering.
|
7
|
+
|
8
|
+
require "scarpe/components/calzini"
|
9
|
+
|
10
|
+
# The Tiranti module expects to be included by a class defining
|
11
|
+
# the following methods:
|
12
|
+
#
|
13
|
+
# * html_id - the HTML ID for the specific rendered DOM object
|
14
|
+
# * handler_js_code(event_name) - the JS handler code for this DOM object and event name
|
15
|
+
# * (optional) display_properties - the display properties for this object, unless overridden in render()
|
16
|
+
module Scarpe::Components::Tiranti
|
17
|
+
include Scarpe::Components::Calzini
|
18
|
+
extend self
|
19
|
+
|
20
|
+
# Currently we're using Bootswatch 5
|
21
|
+
BOOTSWATCH_THEMES = [
|
22
|
+
"cerulean",
|
23
|
+
"cosmo",
|
24
|
+
"cyborg",
|
25
|
+
"darkly",
|
26
|
+
"flatly",
|
27
|
+
"journal",
|
28
|
+
"litera",
|
29
|
+
"lumen",
|
30
|
+
"lux",
|
31
|
+
"materia",
|
32
|
+
"minty",
|
33
|
+
"morph",
|
34
|
+
"pulse",
|
35
|
+
"quartz",
|
36
|
+
"sandstone",
|
37
|
+
"simplex",
|
38
|
+
"sketchy",
|
39
|
+
"slate",
|
40
|
+
"solar",
|
41
|
+
"spacelab",
|
42
|
+
"superhero",
|
43
|
+
"united",
|
44
|
+
"vapor",
|
45
|
+
"yeti",
|
46
|
+
"zephyr",
|
47
|
+
]
|
48
|
+
|
49
|
+
BOOTSWATCH_THEME = ENV["SCARPE_BOOTSTRAP_THEME"] || "sketchy"
|
50
|
+
|
51
|
+
def empty_page_element
|
52
|
+
<<~HTML
|
53
|
+
<html>
|
54
|
+
<head id='head-wvroot'>
|
55
|
+
<meta charset="utf-8">
|
56
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
57
|
+
<link rel="stylesheet" href="https://bootswatch.com/5/#{BOOTSWATCH_THEME}/bootstrap.css">
|
58
|
+
<link rel="stylesheet" href="https://bootswatch.com/_vendor/bootstrap-icons/font/bootstrap-icons.min.css">
|
59
|
+
<style id='style-wvroot'>
|
60
|
+
/** Style resets **/
|
61
|
+
body {
|
62
|
+
height: 100%;
|
63
|
+
overflow: hidden;
|
64
|
+
}
|
65
|
+
</style>
|
66
|
+
</head>
|
67
|
+
<body id='body-wvroot'>
|
68
|
+
<div id='wrapper-wvroot'></div>
|
69
|
+
|
70
|
+
<script src="https://bootswatch.com/_vendor/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
71
|
+
</body>
|
72
|
+
</html>
|
73
|
+
HTML
|
74
|
+
end
|
75
|
+
|
76
|
+
# def render_stack
|
77
|
+
# end
|
78
|
+
# def render_flow
|
79
|
+
# end
|
80
|
+
|
81
|
+
# How do we want to handle theme-specific colours and primary/secondary buttons in Bootstrap?
|
82
|
+
# "Disabled" could be checked in properties. Is there any way we can/should use "outline" buttons?
|
83
|
+
def button_element(props)
|
84
|
+
HTML.render do |h|
|
85
|
+
h.button(id: html_id, type: "button", class: "btn btn-primary", onclick: handler_js_code("click"), style: button_style(props)) do
|
86
|
+
props["text"]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def button_style(props)
|
94
|
+
styles = drawable_style(props)
|
95
|
+
|
96
|
+
styles[:"background-color"] = props["color"] if props["color"]
|
97
|
+
styles[:"padding-top"] = props["padding_top"] if props["padding_top"]
|
98
|
+
styles[:"padding-bottom"] = props["padding_bottom"] if props["padding_bottom"]
|
99
|
+
styles[:color] = props["text_color"] if props["text_color"]
|
100
|
+
styles[:width] = dimensions_length(props["width"]) if props["width"]
|
101
|
+
styles[:height] = dimensions_length(props["height"]) if props["height"]
|
102
|
+
styles[:"font-size"] = props["font_size"] if props["font_size"]
|
103
|
+
|
104
|
+
styles[:top] = dimensions_length(props["top"]) if props["top"]
|
105
|
+
styles[:left] = dimensions_length(props["left"]) if props["left"]
|
106
|
+
styles[:position] = "absolute" if props["top"] || props["left"]
|
107
|
+
styles[:"font-size"] = dimensions_length(text_size(props["size"])) if props["size"]
|
108
|
+
styles[:"font-family"] = props["font"] if props["font"]
|
109
|
+
|
110
|
+
styles
|
111
|
+
end
|
112
|
+
|
113
|
+
public
|
114
|
+
|
115
|
+
def alert_element(props)
|
116
|
+
onclick = handler_js_code(props["event_name"] || "click")
|
117
|
+
|
118
|
+
HTML.render do |h|
|
119
|
+
h.div(id: html_id, class: "modal", tabindex: -1, role: "dialog", style: alert_overlay_style(props)) do
|
120
|
+
h.div(class: "modal-dialog", role: "document") do
|
121
|
+
h.div(class: "modal-content", style: alert_modal_style) do
|
122
|
+
h.div(class: "modal-header") do
|
123
|
+
h.h5(class: "modal-title") { "Alert" }
|
124
|
+
h.button(type: "button", class: "close", data_dismiss: "modal", aria_label: "Close") do
|
125
|
+
h.span(aria_hidden: "true") { "×" }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
h.div(class: "modal-body") do
|
129
|
+
h.p { props["text"] }
|
130
|
+
end
|
131
|
+
h.div(class: "modal-footer") do
|
132
|
+
h.button(type: "button", onclick:, class: "btn btn-primary") { "OK" }
|
133
|
+
#h.button(type: "button", class: "btn btn-secondary") { "Close" }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def check_element(props)
|
142
|
+
HTML.render do |h|
|
143
|
+
h.div class: "form-check" do
|
144
|
+
h.input type: :checkbox,
|
145
|
+
id: html_id,
|
146
|
+
class: "form-check-input",
|
147
|
+
onclick: handler_js_code("click"),
|
148
|
+
value: props["text"],
|
149
|
+
checked: props["checked"],
|
150
|
+
style: drawable_style(props)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def progress_element(props)
|
156
|
+
HTML.render do |h|
|
157
|
+
h.div(class: "progress", style: "width: 90%") do
|
158
|
+
pct = "%.1f" % ((props["fraction"] || 0.0) * 100.0)
|
159
|
+
h.div(
|
160
|
+
class: "progress-bar progress-bar-striped progress-bar-animated",
|
161
|
+
role: "progressbar",
|
162
|
+
"aria-valuenow": pct,
|
163
|
+
"aria-valuemin": 0,
|
164
|
+
"aria-valuemax": 100,
|
165
|
+
style: "width: #{pct}%",
|
166
|
+
)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# para_element is a bit of a hard one, since it does not-entirely-trivial
|
172
|
+
# mapping between display objects and IDs. But we don't want Calzini
|
173
|
+
# messing with the display service or display objects.
|
174
|
+
def para_element(props, &block)
|
175
|
+
tag, opts = para_elt_and_opts(props)
|
176
|
+
|
177
|
+
HTML.render do |h|
|
178
|
+
h.send(tag, **opts, &block)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
ELT_AND_SIZE = {
|
185
|
+
inscription: [:p, 10],
|
186
|
+
ins: [:p, 10],
|
187
|
+
para: [:p, 12],
|
188
|
+
caption: [:p, 14],
|
189
|
+
tagline: [:p, 18],
|
190
|
+
subtitle: [:h3, 26],
|
191
|
+
title: [:h2, 34],
|
192
|
+
banner: [:h1, 48],
|
193
|
+
}.freeze
|
194
|
+
|
195
|
+
def para_elt_and_opts(props)
|
196
|
+
elt, size = para_elt_and_size(props)
|
197
|
+
size = dimensions_length(size)
|
198
|
+
|
199
|
+
para_style = drawable_style(props).merge({
|
200
|
+
color: rgb_to_hex(props["stroke"]),
|
201
|
+
"font-size": para_font_size(props),
|
202
|
+
"font-family": props["font"],
|
203
|
+
}.compact)
|
204
|
+
|
205
|
+
opts = (props["html_attributes"] || {}).merge(id: html_id, style: para_style)
|
206
|
+
|
207
|
+
[elt, opts]
|
208
|
+
end
|
209
|
+
|
210
|
+
def para_elt_and_size(props)
|
211
|
+
return [:p, nil] unless props["size"]
|
212
|
+
|
213
|
+
ps = props["size"].to_s.to_sym
|
214
|
+
if ELT_AND_SIZE.key?(ps)
|
215
|
+
ELT_AND_SIZE[ps]
|
216
|
+
else
|
217
|
+
sz = props["size"].to_i
|
218
|
+
if sz > 18
|
219
|
+
[:h2, sz]
|
220
|
+
else
|
221
|
+
[:p, sz]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,257 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tempfile"
|
4
|
+
require "json"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
require "scarpe/components/file_helpers"
|
8
|
+
|
9
|
+
module Scarpe::Test; end
|
10
|
+
|
11
|
+
# We want test failures set up once *total*, not per Minitest::Test. So an instance var
|
12
|
+
# doesn't do it.
|
13
|
+
ALREADY_SET_UP_LOGGED_TEST_FAILURES = { setup: false }
|
14
|
+
|
15
|
+
# General helpers for general usage.
|
16
|
+
# Helpers here should *not* use Webview-specific functionality.
|
17
|
+
# The intention is that these are helpers for various Scarpe display
|
18
|
+
# services that do *not* necessarily use Webview.
|
19
|
+
|
20
|
+
module Scarpe::Test::Helpers
|
21
|
+
# Very useful for tests
|
22
|
+
include Scarpe::Components::FileHelpers
|
23
|
+
|
24
|
+
# Temporarily set env vars for the block of code inside. The old environment
|
25
|
+
# variable values will be restored after the block finishes.
|
26
|
+
#
|
27
|
+
# @param envs [Hash<String,String>] A hash of environment variable names and values
|
28
|
+
def with_env_vars(envs)
|
29
|
+
old_env = {}
|
30
|
+
envs.each do |k, v|
|
31
|
+
old_env[k] = ENV[k]
|
32
|
+
ENV[k] = v
|
33
|
+
end
|
34
|
+
yield
|
35
|
+
ensure
|
36
|
+
old_env.each { |k, v| ENV[k] = v }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# This test will save extensive logs in case of test failure.
|
41
|
+
# Note that it defines setup/teardown methods. If you want
|
42
|
+
# multiple setup/teardowns from multiple places to happen you
|
43
|
+
# may need to explictly call (e.g. with logged_test_setup/teardown)
|
44
|
+
# to ensure everything you want happens.
|
45
|
+
module Scarpe::Test::LoggedTest
|
46
|
+
def self.included(includer)
|
47
|
+
class << includer
|
48
|
+
attr_accessor :logger_dir
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def file_id
|
53
|
+
"#{self.class.name}_#{self.name}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# This should be called by the test during setup to make sure that
|
57
|
+
# failure logs will be saved if this test fails. It makes sure the
|
58
|
+
# log config will save all logs from all sources, but keeps a copy
|
59
|
+
# of the old log config to restore after the test is finished.
|
60
|
+
#
|
61
|
+
# @return [void]
|
62
|
+
def logged_test_setup
|
63
|
+
# Make sure test failures will be saved at the end of the run.
|
64
|
+
# Delete stale test failures and logging only the *first* time this is called.
|
65
|
+
set_up_test_failures
|
66
|
+
|
67
|
+
@normal_log_config = Shoes::Log.current_log_config
|
68
|
+
Shoes::Log.configure_logger(log_config_for_test)
|
69
|
+
|
70
|
+
Shoes::Log.logger("LoggedScarpeTest").info("Test: #{self.class.name}##{self.name}")
|
71
|
+
end
|
72
|
+
|
73
|
+
# If you include this module and don't override setup/teardown, everything will
|
74
|
+
# work fine. But if you need more setup/teardown steps, you can do that too.
|
75
|
+
#
|
76
|
+
# The setup method guarantees that just including this module will do setup
|
77
|
+
# automatically. If you override it, be sure to call `super` or `logged_test_setup`.
|
78
|
+
#
|
79
|
+
# @return [void]
|
80
|
+
def setup
|
81
|
+
logged_test_setup
|
82
|
+
end
|
83
|
+
|
84
|
+
# After the test has finished, this will restore the old log configuration.
|
85
|
+
# It will also save the logfiles, but only if the test failed, not if it
|
86
|
+
# succeeded or was skipped.
|
87
|
+
#
|
88
|
+
# @return [void]
|
89
|
+
def logged_test_teardown
|
90
|
+
# Restore previous log config
|
91
|
+
Shoes::Log.configure_logger(@normal_log_config)
|
92
|
+
|
93
|
+
if self.failure
|
94
|
+
save_failure_logs
|
95
|
+
else
|
96
|
+
remove_unsaved_logs
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Make sure that, by default, #logged_test_teardown will be called for teardown.
|
101
|
+
# If a class overrides teardown, it should also call `super` or `logged_test_teardown`
|
102
|
+
# to make sure this still happens.
|
103
|
+
#
|
104
|
+
# @return [void]
|
105
|
+
def teardown
|
106
|
+
logged_test_teardown
|
107
|
+
end
|
108
|
+
|
109
|
+
# Set additional LoggedTest configuration for specific logs to separate or save.
|
110
|
+
# This is normally going to be display-service-specific log components.
|
111
|
+
# Note that this only really works with the modular logger or another logger
|
112
|
+
# that does something useful with the log config. The simple print logger
|
113
|
+
# doesn't do a lot with it.
|
114
|
+
def extra_log_config=(additional_log_config)
|
115
|
+
@additional_log_config = additional_log_config
|
116
|
+
end
|
117
|
+
|
118
|
+
# This is the log config that LoggedTests use. It makes sure all components keep all
|
119
|
+
# logs, but also splits the logs into several different files for later ease of scanning.
|
120
|
+
#
|
121
|
+
# TODO: this shouldn't directly include any Webview entries like WebviewAPI or
|
122
|
+
# CatsCradle. Those should be overridden in Webview.
|
123
|
+
#
|
124
|
+
# @return [Hash] the log config
|
125
|
+
def log_config_for_test
|
126
|
+
{
|
127
|
+
"default" => ["debug", "logger/test_failure_#{file_id}.log"],
|
128
|
+
"DisplayService" => ["debug", "logger/test_failure_display_service_#{file_id}.log"],
|
129
|
+
}.merge(@additional_log_config || {})
|
130
|
+
end
|
131
|
+
|
132
|
+
# The list of logfiles that should be saved. Normally this is called internally by the
|
133
|
+
# class, not externally from elsewhere.
|
134
|
+
#
|
135
|
+
# This could be a lot simpler except I want to only update the file list in one place,
|
136
|
+
# log_config_for_test(). Having a single spot should (I hope) make it a lot friendlier to
|
137
|
+
# add more logfiles for different components, logged API objects, etc.
|
138
|
+
def saved_log_files
|
139
|
+
lc = log_config_for_test
|
140
|
+
log_outfiles = lc.values.map { |_level, loc| loc }
|
141
|
+
log_outfiles.select { |s| s.start_with?("logger/") }.map { |s| s.delete_prefix("logger/") }
|
142
|
+
end
|
143
|
+
|
144
|
+
# Make sure that test failure logs will be noticed, and a message will be printed,
|
145
|
+
# if any logged tests fail. This needs to be called at least once in any Minitest-enabled
|
146
|
+
# process using logged tests.
|
147
|
+
#
|
148
|
+
# @return [void]
|
149
|
+
def set_up_test_failures
|
150
|
+
return if ALREADY_SET_UP_LOGGED_TEST_FAILURES[:setup]
|
151
|
+
|
152
|
+
log_dir = self.class.logger_dir
|
153
|
+
raise(Scarpe::MustOverrideMethod, "Must set logger directory!") unless log_dir
|
154
|
+
raise(Scarpe::NoSuchFile, "Can't find logger directory!") unless File.directory?(log_dir)
|
155
|
+
|
156
|
+
ALREADY_SET_UP_LOGGED_TEST_FAILURES[:setup] = true
|
157
|
+
# Delete stale test failures, if any, before starting the first failure-logged test
|
158
|
+
Dir["#{log_dir}/test_failure*.log"].each { |fn| File.unlink(fn) }
|
159
|
+
|
160
|
+
Minitest.after_run do
|
161
|
+
# Print test failure notice to console
|
162
|
+
unless Dir["#{log_dir}/test_failure*.out.log"].empty?
|
163
|
+
puts "Some tests have failed! See #{log_dir}/test_failure*.out.log for test logs!"
|
164
|
+
end
|
165
|
+
|
166
|
+
# Remove un-saved test logs
|
167
|
+
Dir["#{log_dir}/test_failure*.log"].each do |f|
|
168
|
+
next if f.include?(".out.log")
|
169
|
+
|
170
|
+
File.unlink(f) if File.exist?(f)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Failure log output location for a given file path. This is normally used internally to this
|
176
|
+
# class, not externally.
|
177
|
+
#
|
178
|
+
# @return [String] the output path
|
179
|
+
def logfail_out_loc(filepath)
|
180
|
+
# Add a .out prefix before final .log
|
181
|
+
out_loc = filepath.gsub(%r{.log\Z}, ".out.log")
|
182
|
+
|
183
|
+
if out_loc == filepath
|
184
|
+
raise Shoes::Errors::InvalidAttributeValueError, "Something is wrong! Could not figure out failure-log output path for #{filepath.inspect}!"
|
185
|
+
end
|
186
|
+
|
187
|
+
if File.exist?(out_loc)
|
188
|
+
raise Scarpe::DuplicateFileError, "Duplicate test file #{out_loc.inspect}? This file should *not* already exist!"
|
189
|
+
end
|
190
|
+
|
191
|
+
out_loc
|
192
|
+
end
|
193
|
+
|
194
|
+
# Save the failure logs in the appropriate place(s). This is normally used internally, not externally.
|
195
|
+
#
|
196
|
+
# @return [void]
|
197
|
+
def save_failure_logs
|
198
|
+
saved_log_files.each do |log_file|
|
199
|
+
full_loc = File.expand_path("#{self.class.logger_dir}/#{log_file}")
|
200
|
+
# TODO: we'd like to skip 0-length logfiles. But also Logging doesn't flush. For now, ignore.
|
201
|
+
next unless File.exist?(full_loc)
|
202
|
+
|
203
|
+
FileUtils.mv full_loc, logfail_out_loc(full_loc)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Remove unsaved failure logs. This is normally used internally, not externally.
|
208
|
+
#
|
209
|
+
# @return [void]
|
210
|
+
def remove_unsaved_logs
|
211
|
+
Dir["#{self.class.logger_dir}/test_failure*.log"].each do |f|
|
212
|
+
next if f.include?(".out.log") # Don't delete saved logs
|
213
|
+
|
214
|
+
File.unlink(f)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
module Scarpe::Test::HTMLAssertions
|
220
|
+
# Assert that `actual_html` is the same as `expected_tag` with `opts`.
|
221
|
+
# This uses Scarpe's HTML tag-based renderer to render the tag and options
|
222
|
+
# into text, and valides that the text is the same.
|
223
|
+
#
|
224
|
+
# @see Scarpe::Components::HTML.render
|
225
|
+
#
|
226
|
+
# @param actual_html [String] the html to compare to
|
227
|
+
# @param expected_tag [String,Symbol] the HTML tag, used to send a method call
|
228
|
+
# @param opts keyword options passed to the tag method call
|
229
|
+
# @yield block passed to the tag method call.
|
230
|
+
# @return [void]
|
231
|
+
def assert_html(actual_html, expected_tag, **opts, &block)
|
232
|
+
expected_html = Scarpe::Components::HTML.render do |h|
|
233
|
+
h.public_send(expected_tag, opts, &block)
|
234
|
+
end
|
235
|
+
|
236
|
+
assert_equal expected_html, actual_html
|
237
|
+
end
|
238
|
+
|
239
|
+
# Assert that `actual_html` includes `expected_tag` with `opts`.
|
240
|
+
# This uses Scarpe's HTML tag-based renderer to render the tag and options
|
241
|
+
# into text, and valides that the full HTML contains that tag.
|
242
|
+
#
|
243
|
+
# @see Scarpe::Components::HTML.render
|
244
|
+
#
|
245
|
+
# @param actual_html [String] the html to compare to
|
246
|
+
# @param expected_tag [String,Symbol] the HTML tag, used to send a method call
|
247
|
+
# @param opts keyword options passed to the tag method call
|
248
|
+
# @yield block passed to the tag method call.
|
249
|
+
# @return [void]
|
250
|
+
def assert_contains_html(actual_html, expected_tag, **opts, &block)
|
251
|
+
expected_html = Scarpe::Components::HTML.render do |h|
|
252
|
+
h.public_send(expected_tag, opts, &block)
|
253
|
+
end
|
254
|
+
|
255
|
+
assert actual_html.include?(expected_html), "Expected #{actual_html.inspect} to include #{expected_html.inspect}!"
|
256
|
+
end
|
257
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scarpe-components
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marco Concetto Rudilosso
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-11-24 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email:
|
@@ -19,9 +19,33 @@ executables: []
|
|
19
19
|
extensions: []
|
20
20
|
extra_rdoc_files: []
|
21
21
|
files:
|
22
|
+
- Gemfile
|
23
|
+
- Gemfile.lock
|
22
24
|
- README.md
|
23
25
|
- Rakefile
|
24
|
-
- lib/scarpe/
|
26
|
+
- lib/scarpe/components/base64.rb
|
27
|
+
- lib/scarpe/components/calzini.rb
|
28
|
+
- lib/scarpe/components/calzini/alert.rb
|
29
|
+
- lib/scarpe/components/calzini/art_widgets.rb
|
30
|
+
- lib/scarpe/components/calzini/button.rb
|
31
|
+
- lib/scarpe/components/calzini/misc.rb
|
32
|
+
- lib/scarpe/components/calzini/para.rb
|
33
|
+
- lib/scarpe/components/calzini/slots.rb
|
34
|
+
- lib/scarpe/components/calzini/text_widgets.rb
|
35
|
+
- lib/scarpe/components/errors.rb
|
36
|
+
- lib/scarpe/components/file_helpers.rb
|
37
|
+
- lib/scarpe/components/html.rb
|
38
|
+
- lib/scarpe/components/minitest_export_reporter.rb
|
39
|
+
- lib/scarpe/components/minitest_import_runnable.rb
|
40
|
+
- lib/scarpe/components/minitest_result.rb
|
41
|
+
- lib/scarpe/components/modular_logger.rb
|
42
|
+
- lib/scarpe/components/print_logger.rb
|
43
|
+
- lib/scarpe/components/promises.rb
|
44
|
+
- lib/scarpe/components/segmented_file_loader.rb
|
45
|
+
- lib/scarpe/components/string_helpers.rb
|
46
|
+
- lib/scarpe/components/tiranti.rb
|
47
|
+
- lib/scarpe/components/unit_test_helpers.rb
|
48
|
+
- lib/scarpe/components/version.rb
|
25
49
|
homepage: https://github.com/scarpe-team/scarpe
|
26
50
|
licenses:
|
27
51
|
- MIT
|
@@ -44,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
68
|
- !ruby/object:Gem::Version
|
45
69
|
version: '0'
|
46
70
|
requirements: []
|
47
|
-
rubygems_version: 3.4.
|
71
|
+
rubygems_version: 3.4.10
|
48
72
|
signing_key:
|
49
73
|
specification_version: 4
|
50
74
|
summary: Reusable components for Scarpe display libraries
|