hanami 2.1.0.beta1 → 2.1.0.beta2.1
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 -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
|