hanami 2.1.0.beta1 → 2.1.0.beta2.1
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 -4
- data/README.md +1 -1
- data/lib/hanami/app.rb +5 -0
- data/lib/hanami/config/actions.rb +4 -7
- data/lib/hanami/config/assets.rb +84 -0
- data/lib/hanami/config/null_config.rb +3 -0
- data/lib/hanami/config.rb +17 -5
- data/lib/hanami/extensions/action.rb +4 -2
- data/lib/hanami/extensions/view/standard_helpers.rb +4 -0
- data/lib/hanami/helpers/assets_helper.rb +772 -0
- data/lib/hanami/middleware/assets.rb +21 -0
- data/lib/hanami/middleware/render_errors.rb +4 -7
- data/lib/hanami/providers/assets.rb +44 -0
- data/lib/hanami/rake_tasks.rb +19 -18
- data/lib/hanami/settings.rb +1 -1
- data/lib/hanami/slice.rb +25 -4
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami.rb +2 -2
- data/spec/integration/assets/assets_spec.rb +101 -0
- data/spec/integration/assets/serve_static_assets_spec.rb +152 -0
- data/spec/integration/logging/exception_logging_spec.rb +115 -0
- data/spec/integration/logging/notifications_spec.rb +68 -0
- data/spec/integration/logging/request_logging_spec.rb +128 -0
- data/spec/integration/rack_app/middleware_spec.rb +4 -4
- data/spec/integration/rack_app/rack_app_spec.rb +0 -221
- data/spec/integration/rake_tasks_spec.rb +107 -0
- data/spec/integration/view/context/assets_spec.rb +3 -9
- data/spec/integration/web/render_detailed_errors_spec.rb +17 -0
- data/spec/integration/web/render_errors_spec.rb +6 -4
- data/spec/support/app_integration.rb +46 -2
- data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +24 -36
- data/spec/unit/hanami/config/actions/csrf_protection_spec.rb +4 -3
- data/spec/unit/hanami/config/actions/default_values_spec.rb +3 -2
- data/spec/unit/hanami/env_spec.rb +11 -25
- data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +109 -0
- data/spec/unit/hanami/helpers/assets_helper/audio_spec.rb +136 -0
- data/spec/unit/hanami/helpers/assets_helper/favicon_spec.rb +91 -0
- data/spec/unit/hanami/helpers/assets_helper/image_spec.rb +96 -0
- data/spec/unit/hanami/helpers/assets_helper/javascript_spec.rb +147 -0
- data/spec/unit/hanami/helpers/assets_helper/stylesheet_spec.rb +130 -0
- data/spec/unit/hanami/helpers/assets_helper/video_spec.rb +136 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- metadata +32 -4
- data/lib/hanami/assets/app_config.rb +0 -61
- data/lib/hanami/assets/config.rb +0 -53
@@ -3,43 +3,31 @@
|
|
3
3
|
require "hanami/config/actions"
|
4
4
|
|
5
5
|
RSpec.describe Hanami::Config::Actions, "#content_security_policy" do
|
6
|
-
let(:
|
6
|
+
let(:app_config) { Hanami::Config.new(app_name: "MyApp::App", env: :development) }
|
7
|
+
let(:config) { app_config.actions }
|
7
8
|
subject(:content_security_policy) { config.content_security_policy }
|
8
9
|
|
9
10
|
context "no CSP config specified" do
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
expect(content_security_policy.to_s).to eq(expected)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context "with assets_server_url" do
|
36
|
-
let(:config) { described_class.new(assets_server_url: assets_server_url) }
|
37
|
-
let(:assets_server_url) { "http://localhost:8080" }
|
38
|
-
|
39
|
-
it "includes server url" do
|
40
|
-
expect(content_security_policy[:script_src]).to eq("'self' #{assets_server_url}")
|
41
|
-
expect(content_security_policy[:style_src]).to eq("'self' 'unsafe-inline' https: #{assets_server_url}")
|
42
|
-
end
|
11
|
+
it "has defaults" do
|
12
|
+
expect(content_security_policy[:base_uri]).to eq("'self'")
|
13
|
+
|
14
|
+
expected = [
|
15
|
+
%(base-uri 'self'),
|
16
|
+
%(child-src 'self'),
|
17
|
+
%(connect-src 'self'),
|
18
|
+
%(default-src 'none'),
|
19
|
+
%(font-src 'self'),
|
20
|
+
%(form-action 'self'),
|
21
|
+
%(frame-ancestors 'self'),
|
22
|
+
%(frame-src 'self'),
|
23
|
+
%(img-src 'self' https: data:),
|
24
|
+
%(media-src 'self'),
|
25
|
+
%(object-src 'none'),
|
26
|
+
%(script-src 'self'),
|
27
|
+
%(style-src 'self' 'unsafe-inline' https:)
|
28
|
+
].join(";")
|
29
|
+
|
30
|
+
expect(content_security_policy.to_s).to eq(expected)
|
43
31
|
end
|
44
32
|
end
|
45
33
|
|
@@ -84,7 +72,7 @@ RSpec.describe Hanami::Config::Actions, "#content_security_policy" do
|
|
84
72
|
|
85
73
|
context "with CSP enabled" do
|
86
74
|
it "sets default header" do
|
87
|
-
|
75
|
+
app_config.finalize!
|
88
76
|
|
89
77
|
expect(config.default_headers.fetch("Content-Security-Policy")).to eq(content_security_policy.to_s)
|
90
78
|
end
|
@@ -93,7 +81,7 @@ RSpec.describe Hanami::Config::Actions, "#content_security_policy" do
|
|
93
81
|
context "with CSP disabled" do
|
94
82
|
it "doesn't set default header" do
|
95
83
|
config.content_security_policy = false
|
96
|
-
|
84
|
+
app_config.finalize!
|
97
85
|
|
98
86
|
expect(config.default_headers.key?("Content-Security-Policy")).to be(false)
|
99
87
|
end
|
@@ -3,7 +3,8 @@
|
|
3
3
|
require "hanami/config/actions"
|
4
4
|
|
5
5
|
RSpec.describe Hanami::Config::Actions, "#csrf_protection" do
|
6
|
-
let(:
|
6
|
+
let(:app_config) { Hanami::Config.new(app_name: "MyApp::App", env: :development) }
|
7
|
+
let(:config) { app_config.actions }
|
7
8
|
subject(:value) { config.csrf_protection }
|
8
9
|
|
9
10
|
context "non-finalized config" do
|
@@ -26,7 +27,7 @@ RSpec.describe Hanami::Config::Actions, "#csrf_protection" do
|
|
26
27
|
context "sessions enabled" do
|
27
28
|
before do
|
28
29
|
config.sessions = :cookie, {secret: "abc"}
|
29
|
-
|
30
|
+
app_config.finalize!
|
30
31
|
end
|
31
32
|
|
32
33
|
it "is true" do
|
@@ -46,7 +47,7 @@ RSpec.describe Hanami::Config::Actions, "#csrf_protection" do
|
|
46
47
|
|
47
48
|
context "sessions not enabled" do
|
48
49
|
before do
|
49
|
-
|
50
|
+
app_config.finalize!
|
50
51
|
end
|
51
52
|
|
52
53
|
it "is true" do
|
@@ -3,7 +3,8 @@
|
|
3
3
|
require "hanami/config/actions"
|
4
4
|
|
5
5
|
RSpec.describe Hanami::Config::Actions, "default values" do
|
6
|
-
|
6
|
+
let(:app_config) { Hanami::Config.new(app_name: "MyApp::App", env: :development) }
|
7
|
+
subject(:config) { app_config.actions }
|
7
8
|
|
8
9
|
describe "sessions" do
|
9
10
|
specify { expect(config.sessions).not_to be_enabled }
|
@@ -28,7 +29,7 @@ RSpec.describe Hanami::Config::Actions, "default values" do
|
|
28
29
|
|
29
30
|
describe "default_headers" do
|
30
31
|
specify {
|
31
|
-
|
32
|
+
app_config.finalize!
|
32
33
|
|
33
34
|
expect(config.default_headers).to eq(
|
34
35
|
"X-Frame-Options" => "DENY",
|
@@ -1,54 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Hanami, ".env" do
|
4
|
-
subject
|
5
|
-
|
6
|
-
before do
|
7
|
-
@orig_env = ENV.to_h
|
8
|
-
end
|
9
|
-
|
10
|
-
after do
|
11
|
-
ENV.replace(@orig_env)
|
12
|
-
end
|
4
|
+
subject { described_class.env(e: env) }
|
13
5
|
|
14
6
|
context "HANAMI_ENV in ENV" do
|
15
|
-
|
16
|
-
ENV["HANAMI_ENV"] = "test"
|
17
|
-
end
|
7
|
+
let(:env) { {"HANAMI_ENV" => "test"} }
|
18
8
|
|
19
9
|
it "is the value of HANAMI_ENV" do
|
20
|
-
is_expected.to eq
|
10
|
+
is_expected.to eq(:test)
|
21
11
|
end
|
22
12
|
end
|
23
13
|
|
24
14
|
context "RACK_ENV in ENV" do
|
25
|
-
|
26
|
-
ENV["RACK_ENV"] = "test"
|
27
|
-
end
|
15
|
+
let(:env) { {"HANAMI_ENV" => "test"} }
|
28
16
|
|
29
17
|
it "is the value of RACK_ENV" do
|
30
|
-
is_expected.to eq
|
18
|
+
is_expected.to eq(:test)
|
31
19
|
end
|
32
20
|
end
|
33
21
|
|
34
22
|
context "both HANAMI_ENV and RACK_ENV in ENV" do
|
35
|
-
|
36
|
-
|
37
|
-
|
23
|
+
let(:env) do
|
24
|
+
{"HANAMI_ENV" => "test",
|
25
|
+
"RACK_ENV" => "production"}
|
38
26
|
end
|
39
27
|
|
40
28
|
it "is the value of HANAMI_ENV" do
|
41
|
-
is_expected.to eq
|
29
|
+
is_expected.to eq(:test)
|
42
30
|
end
|
43
31
|
end
|
44
32
|
|
45
33
|
context "no ENV vars set" do
|
46
|
-
|
47
|
-
ENV.delete("HANAMI_ENV")
|
48
|
-
end
|
34
|
+
let(:env) { {} }
|
49
35
|
|
50
36
|
it "defaults to \"development\"" do
|
51
|
-
is_expected.to eq
|
37
|
+
is_expected.to eq(:development)
|
52
38
|
end
|
53
39
|
end
|
54
40
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Hanami::Helpers::AssetsHelper, "#asset_url", :app_integration do
|
4
|
+
subject(:obj) {
|
5
|
+
helpers = described_class
|
6
|
+
Class.new {
|
7
|
+
include helpers
|
8
|
+
|
9
|
+
attr_reader :_context
|
10
|
+
|
11
|
+
def initialize(context)
|
12
|
+
@_context = context
|
13
|
+
end
|
14
|
+
}.new(context)
|
15
|
+
}
|
16
|
+
|
17
|
+
def asset_url(...)
|
18
|
+
subject.asset_url(...)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:context) { TestApp::Views::Context.new }
|
22
|
+
let(:root) { make_tmp_directory }
|
23
|
+
|
24
|
+
before do
|
25
|
+
with_directory(root) do
|
26
|
+
write "config/app.rb", <<~RUBY
|
27
|
+
module TestApp
|
28
|
+
class App < Hanami::App
|
29
|
+
config.logger.stream = StringIO.new
|
30
|
+
end
|
31
|
+
end
|
32
|
+
RUBY
|
33
|
+
|
34
|
+
write "app/views/context.rb", <<~RUBY
|
35
|
+
# auto_register: false
|
36
|
+
|
37
|
+
require "hanami/view/context"
|
38
|
+
|
39
|
+
module TestApp
|
40
|
+
module Views
|
41
|
+
class Context < Hanami::View::Context
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
RUBY
|
46
|
+
|
47
|
+
write "app/assets/js/app.ts", <<~JS
|
48
|
+
import "../css/app.css";
|
49
|
+
|
50
|
+
console.log("Hello from index.ts");
|
51
|
+
JS
|
52
|
+
|
53
|
+
write "app/assets/css/app.css", <<~CSS
|
54
|
+
.btn {
|
55
|
+
background: #f00;
|
56
|
+
}
|
57
|
+
CSS
|
58
|
+
|
59
|
+
stub_assets("app.js")
|
60
|
+
|
61
|
+
require "hanami/setup"
|
62
|
+
before_prepare if respond_to?(:before_prepare)
|
63
|
+
require "hanami/prepare"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when configurated relative path only" do
|
68
|
+
context "without manifest" do
|
69
|
+
it "returns the relative URL to the asset" do
|
70
|
+
expect(asset_url("app.js")).to eq("/assets/app.js")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns absolute URL if the argument is an absolute URL" do
|
74
|
+
result = asset_url("http://assets.hanamirb.org/assets/application.css")
|
75
|
+
expect(result).to eq("http://assets.hanamirb.org/assets/application.css")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "with manifest" do
|
80
|
+
before { compile_assets! }
|
81
|
+
|
82
|
+
it "returns the relative URL to the asset" do
|
83
|
+
expect(asset_url("app.js")).to match(%r{/assets/app-[A-Z0-9]{8}\.js})
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when configured with base url" do
|
89
|
+
let(:base_url) { "https://hanami.test" }
|
90
|
+
|
91
|
+
def before_prepare
|
92
|
+
Hanami.app.config.assets.base_url = base_url
|
93
|
+
end
|
94
|
+
|
95
|
+
context "without manifest" do
|
96
|
+
it "returns the absolute URL to the asset" do
|
97
|
+
expect(asset_url("app.js")).to eq("#{base_url}/assets/app.js")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "with manifest" do
|
102
|
+
before { compile_assets! }
|
103
|
+
|
104
|
+
it "returns the relative path to the asset" do
|
105
|
+
expect(asset_url("app.js")).to match(%r{#{base_url}/assets/app-[A-Z0-9]{8}.js})
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Hanami::Helpers::AssetsHelper, "#audio", :app_integration do
|
4
|
+
subject(:obj) {
|
5
|
+
helpers = described_class
|
6
|
+
Class.new {
|
7
|
+
include helpers
|
8
|
+
|
9
|
+
attr_reader :_context
|
10
|
+
|
11
|
+
def initialize(context)
|
12
|
+
@_context = context
|
13
|
+
end
|
14
|
+
}.new(context)
|
15
|
+
}
|
16
|
+
|
17
|
+
def audio(...)
|
18
|
+
subject.audio(...)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:context) { TestApp::Views::Context.new }
|
22
|
+
let(:root) { make_tmp_directory }
|
23
|
+
|
24
|
+
before do
|
25
|
+
with_directory(root) do
|
26
|
+
write "config/app.rb", <<~RUBY
|
27
|
+
module TestApp
|
28
|
+
class App < Hanami::App
|
29
|
+
config.logger.stream = StringIO.new
|
30
|
+
end
|
31
|
+
end
|
32
|
+
RUBY
|
33
|
+
|
34
|
+
write "app/views/context.rb", <<~RUBY
|
35
|
+
# auto_register: false
|
36
|
+
|
37
|
+
require "hanami/view/context"
|
38
|
+
|
39
|
+
module TestApp
|
40
|
+
module Views
|
41
|
+
class Context < Hanami::View::Context
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
RUBY
|
46
|
+
|
47
|
+
stub_assets("song.ogg", "song.pt-BR.vtt")
|
48
|
+
|
49
|
+
require "hanami/setup"
|
50
|
+
before_prepare if respond_to?(:before_prepare)
|
51
|
+
require "hanami/prepare"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns an instance of HtmlBuilder" do
|
56
|
+
actual = audio("song.ogg")
|
57
|
+
expect(actual).to be_instance_of(::Hanami::View::HTML::SafeString)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "renders <audio> tag" do
|
61
|
+
actual = audio("song.ogg").to_s
|
62
|
+
expect(actual).to eq(%(<audio src="/assets/song.ogg"></audio>))
|
63
|
+
end
|
64
|
+
|
65
|
+
it "is aliased as #audio_tag" do
|
66
|
+
expect(subject.audio_tag("song.ogg")).to eq(audio("song.ogg"))
|
67
|
+
end
|
68
|
+
|
69
|
+
it "renders with html attributes" do
|
70
|
+
actual = audio("song.ogg", autoplay: true, controls: true).to_s
|
71
|
+
expect(actual).to eq(%(<audio autoplay="autoplay" controls="controls" src="/assets/song.ogg"></audio>))
|
72
|
+
end
|
73
|
+
|
74
|
+
it "renders with fallback content" do
|
75
|
+
actual = audio("song.ogg") do
|
76
|
+
"Your browser does not support the audio tag"
|
77
|
+
end.to_s
|
78
|
+
|
79
|
+
expect(actual).to eq(%(<audio src="/assets/song.ogg">Your browser does not support the audio tag</audio>))
|
80
|
+
end
|
81
|
+
|
82
|
+
it "renders with tracks" do
|
83
|
+
actual = audio("song.ogg") do
|
84
|
+
tag.track kind: "captions", src: subject.asset_url("song.pt-BR.vtt"), srclang: "pt-BR", label: "Portuguese"
|
85
|
+
end.to_s
|
86
|
+
|
87
|
+
expect(actual).to eq(%(<audio src="/assets/song.ogg"><track kind="captions" src="/assets/song.pt-BR.vtt" srclang="pt-BR" label="Portuguese"></audio>))
|
88
|
+
end
|
89
|
+
|
90
|
+
xit "renders with sources" do
|
91
|
+
actual = audio do
|
92
|
+
tag.text "Your browser does not support the audio tag"
|
93
|
+
tag.source src: subject.asset_url("song.ogg"), type: "audio/ogg"
|
94
|
+
tag.source src: subject.asset_url("song.wav"), type: "audio/wav"
|
95
|
+
end.to_s
|
96
|
+
|
97
|
+
expect(actual).to eq(%(<audio>Your browser does not support the audio tag<source src="/assets/song.ogg" type="audio/ogg"><source src="/assets/song.wav" type="audio/wav"></audio>))
|
98
|
+
end
|
99
|
+
|
100
|
+
it "raises an exception when no arguments" do
|
101
|
+
expect do
|
102
|
+
audio
|
103
|
+
end.to raise_error(
|
104
|
+
ArgumentError,
|
105
|
+
"You should provide a source via `src` option or with a `source` HTML tag"
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "raises an exception when no src and no block" do
|
110
|
+
expect do
|
111
|
+
audio(controls: true)
|
112
|
+
end.to raise_error(
|
113
|
+
ArgumentError,
|
114
|
+
"You should provide a source via `src` option or with a `source` HTML tag"
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "cdn mode" do
|
119
|
+
let(:base_url) { "https://hanami.test" }
|
120
|
+
|
121
|
+
def before_prepare
|
122
|
+
Hanami.app.config.assets.base_url = base_url
|
123
|
+
end
|
124
|
+
|
125
|
+
it "returns absolute url for src attribute" do
|
126
|
+
actual = audio("song.ogg").to_s
|
127
|
+
expect(actual).to eq(%(<audio src="#{base_url}/assets/song.ogg"></audio>))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def tag(...)
|
134
|
+
subject.__send__(:tag, ...)
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Hanami::Helpers::AssetsHelper, "#favicon", :app_integration do
|
4
|
+
subject(:obj) {
|
5
|
+
helpers = described_class
|
6
|
+
Class.new {
|
7
|
+
include helpers
|
8
|
+
|
9
|
+
attr_reader :_context
|
10
|
+
|
11
|
+
def initialize(context)
|
12
|
+
@_context = context
|
13
|
+
end
|
14
|
+
}.new(context)
|
15
|
+
}
|
16
|
+
|
17
|
+
def favicon(...)
|
18
|
+
obj.instance_eval { favicon(...) }
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:root) { make_tmp_directory }
|
22
|
+
let(:context) { TestApp::Views::Context.new }
|
23
|
+
|
24
|
+
before do
|
25
|
+
with_directory(root) do
|
26
|
+
write "config/app.rb", <<~RUBY
|
27
|
+
module TestApp
|
28
|
+
class App < Hanami::App
|
29
|
+
config.logger.stream = StringIO.new
|
30
|
+
end
|
31
|
+
end
|
32
|
+
RUBY
|
33
|
+
|
34
|
+
write "app/views/context.rb", <<~RUBY
|
35
|
+
# auto_register: false
|
36
|
+
|
37
|
+
require "hanami/view/context"
|
38
|
+
|
39
|
+
module TestApp
|
40
|
+
module Views
|
41
|
+
class Context < Hanami::View::Context
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
RUBY
|
46
|
+
|
47
|
+
stub_assets("favicon.ico", "favicon.png")
|
48
|
+
|
49
|
+
require "hanami/setup"
|
50
|
+
before_prepare if respond_to?(:before_prepare)
|
51
|
+
require "hanami/prepare"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns an instance of SafeString" do
|
56
|
+
actual = favicon
|
57
|
+
expect(actual).to be_instance_of(::Hanami::View::HTML::SafeString)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "is aliased as #favicon_link_tag" do
|
61
|
+
expect(subject.favicon_link_tag).to eq(favicon)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "renders <link> tag" do
|
65
|
+
actual = favicon.to_s
|
66
|
+
expect(actual).to eq(%(<link href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon">))
|
67
|
+
end
|
68
|
+
|
69
|
+
it "renders with HTML attributes" do
|
70
|
+
actual = favicon("favicon.png", rel: "icon", type: "image/png").to_s
|
71
|
+
expect(actual).to eq(%(<link href="/assets/favicon.png" rel="icon" type="image/png">))
|
72
|
+
end
|
73
|
+
|
74
|
+
it "ignores href passed as an option" do
|
75
|
+
actual = favicon("favicon.png", href: "wrong").to_s
|
76
|
+
expect(actual).to eq(%(<link href="/assets/favicon.png" rel="shortcut icon" type="image/x-icon">))
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "cdn mode" do
|
80
|
+
let(:base_url) { "https://hanami.test" }
|
81
|
+
|
82
|
+
def before_prepare
|
83
|
+
Hanami.app.config.assets.base_url = "https://hanami.test"
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns absolute url for href attribute" do
|
87
|
+
actual = favicon.to_s
|
88
|
+
expect(actual).to eq(%(<link href="#{base_url}/assets/favicon.ico" rel="shortcut icon" type="image/x-icon">))
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Hanami::Helpers::AssetsHelper, "#image", :app_integration do
|
4
|
+
subject(:obj) {
|
5
|
+
helpers = described_class
|
6
|
+
Class.new {
|
7
|
+
include helpers
|
8
|
+
|
9
|
+
attr_reader :_context
|
10
|
+
|
11
|
+
def initialize(context)
|
12
|
+
@_context = context
|
13
|
+
end
|
14
|
+
}.new(context)
|
15
|
+
}
|
16
|
+
|
17
|
+
def image(...)
|
18
|
+
subject.image(...)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:root) { make_tmp_directory }
|
22
|
+
let(:context) { TestApp::Views::Context.new }
|
23
|
+
|
24
|
+
before do
|
25
|
+
with_directory(root) do
|
26
|
+
write "config/app.rb", <<~RUBY
|
27
|
+
module TestApp
|
28
|
+
class App < Hanami::App
|
29
|
+
config.logger.stream = StringIO.new
|
30
|
+
end
|
31
|
+
end
|
32
|
+
RUBY
|
33
|
+
|
34
|
+
write "app/views/context.rb", <<~RUBY
|
35
|
+
# auto_register: false
|
36
|
+
|
37
|
+
require "hanami/view/context"
|
38
|
+
|
39
|
+
module TestApp
|
40
|
+
module Views
|
41
|
+
class Context < Hanami::View::Context
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
RUBY
|
46
|
+
|
47
|
+
stub_assets("application.jpg")
|
48
|
+
|
49
|
+
require "hanami/setup"
|
50
|
+
before_prepare if respond_to?(:before_prepare)
|
51
|
+
require "hanami/prepare"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns an instance of HtmlBuilder" do
|
56
|
+
actual = image("application.jpg")
|
57
|
+
expect(actual).to be_instance_of(::Hanami::View::HTML::SafeString)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "renders an <img> tag" do
|
61
|
+
actual = image("application.jpg").to_s
|
62
|
+
expect(actual).to eq(%(<img src="/assets/application.jpg" alt="Application">))
|
63
|
+
end
|
64
|
+
|
65
|
+
it "is aliased as #image_tag" do
|
66
|
+
expect(subject.image_tag("application.jpg")).to eq image("application.jpg")
|
67
|
+
end
|
68
|
+
|
69
|
+
it "custom alt" do
|
70
|
+
actual = image("application.jpg", alt: "My Alt").to_s
|
71
|
+
expect(actual).to eq(%(<img src="/assets/application.jpg" alt="My Alt">))
|
72
|
+
end
|
73
|
+
|
74
|
+
it "custom data attribute" do
|
75
|
+
actual = image("application.jpg", "data-user-id" => 5).to_s
|
76
|
+
expect(actual).to eq(%(<img src="/assets/application.jpg" alt="Application" data-user-id="5">))
|
77
|
+
end
|
78
|
+
|
79
|
+
it "ignores src passed as an option" do
|
80
|
+
actual = image("application.jpg", src: "wrong").to_s
|
81
|
+
expect(actual).to eq(%(<img src="/assets/application.jpg" alt="Application">))
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "cdn mode" do
|
85
|
+
let(:base_url) { "https://hanami.test" }
|
86
|
+
|
87
|
+
def before_prepare
|
88
|
+
Hanami.app.config.assets.base_url = "https://hanami.test"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns absolute url for src attribute" do
|
92
|
+
actual = image("application.jpg").to_s
|
93
|
+
expect(actual).to eq(%(<img src="#{base_url}/assets/application.jpg" alt="Application">))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|