hanami 2.1.0.beta1 → 2.1.0.beta2

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -4
  3. data/README.md +1 -1
  4. data/lib/hanami/app.rb +5 -0
  5. data/lib/hanami/config/actions.rb +4 -7
  6. data/lib/hanami/config/assets.rb +84 -0
  7. data/lib/hanami/config/null_config.rb +3 -0
  8. data/lib/hanami/config.rb +17 -5
  9. data/lib/hanami/extensions/action.rb +4 -2
  10. data/lib/hanami/extensions/view/standard_helpers.rb +4 -0
  11. data/lib/hanami/helpers/assets_helper.rb +752 -0
  12. data/lib/hanami/middleware/assets.rb +21 -0
  13. data/lib/hanami/middleware/render_errors.rb +4 -7
  14. data/lib/hanami/providers/assets.rb +44 -0
  15. data/lib/hanami/rake_tasks.rb +19 -18
  16. data/lib/hanami/settings.rb +1 -1
  17. data/lib/hanami/slice.rb +25 -4
  18. data/lib/hanami/version.rb +1 -1
  19. data/lib/hanami.rb +2 -2
  20. data/spec/integration/assets/assets_spec.rb +101 -0
  21. data/spec/integration/assets/serve_static_assets_spec.rb +152 -0
  22. data/spec/integration/logging/exception_logging_spec.rb +115 -0
  23. data/spec/integration/logging/notifications_spec.rb +68 -0
  24. data/spec/integration/logging/request_logging_spec.rb +128 -0
  25. data/spec/integration/rack_app/middleware_spec.rb +4 -4
  26. data/spec/integration/rack_app/rack_app_spec.rb +0 -221
  27. data/spec/integration/rake_tasks_spec.rb +107 -0
  28. data/spec/integration/view/context/assets_spec.rb +3 -9
  29. data/spec/integration/web/render_detailed_errors_spec.rb +17 -0
  30. data/spec/integration/web/render_errors_spec.rb +6 -4
  31. data/spec/support/app_integration.rb +46 -2
  32. data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +24 -36
  33. data/spec/unit/hanami/config/actions/csrf_protection_spec.rb +4 -3
  34. data/spec/unit/hanami/config/actions/default_values_spec.rb +3 -2
  35. data/spec/unit/hanami/env_spec.rb +11 -25
  36. data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +109 -0
  37. data/spec/unit/hanami/helpers/assets_helper/audio_tag_spec.rb +132 -0
  38. data/spec/unit/hanami/helpers/assets_helper/favicon_link_tag_spec.rb +91 -0
  39. data/spec/unit/hanami/helpers/assets_helper/image_tag_spec.rb +92 -0
  40. data/spec/unit/hanami/helpers/assets_helper/javascript_tag_spec.rb +143 -0
  41. data/spec/unit/hanami/helpers/assets_helper/stylesheet_link_tag_spec.rb +126 -0
  42. data/spec/unit/hanami/helpers/assets_helper/video_tag_spec.rb +132 -0
  43. data/spec/unit/hanami/version_spec.rb +1 -1
  44. metadata +32 -4
  45. data/lib/hanami/assets/app_config.rb +0 -61
  46. 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(:config) { described_class.new }
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
- context "without assets_server_url" do
11
-
12
- it "has defaults" do
13
- expect(content_security_policy[:base_uri]).to eq("'self'")
14
-
15
- expected = [
16
- %(base-uri 'self'),
17
- %(child-src 'self'),
18
- %(connect-src 'self'),
19
- %(default-src 'none'),
20
- %(font-src 'self'),
21
- %(form-action 'self'),
22
- %(frame-ancestors 'self'),
23
- %(frame-src 'self'),
24
- %(img-src 'self' https: data:),
25
- %(media-src 'self'),
26
- %(object-src 'none'),
27
- %(script-src 'self'),
28
- %(style-src 'self' 'unsafe-inline' https:)
29
- ].join(";")
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
- config.finalize!
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
- config.finalize!
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(:config) { described_class.new }
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
- config.finalize!
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
- config.finalize!
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
- subject(:config) { described_class.new }
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
- config.finalize!
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(:env) { described_class.env }
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
- before do
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 :test
10
+ is_expected.to eq(:test)
21
11
  end
22
12
  end
23
13
 
24
14
  context "RACK_ENV in ENV" do
25
- before do
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 :test
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
- before do
36
- ENV["HANAMI_ENV"] = "test"
37
- ENV["RACK_ENV"] = "production"
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 :test
29
+ is_expected.to eq(:test)
42
30
  end
43
31
  end
44
32
 
45
33
  context "no ENV vars set" do
46
- before do
47
- ENV.delete("HANAMI_ENV")
48
- end
34
+ let(:env) { {} }
49
35
 
50
36
  it "defaults to \"development\"" do
51
- is_expected.to eq :development
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,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Hanami::Helpers::AssetsHelper, "#audio_tag", :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_tag(...)
18
+ subject.audio_tag(...)
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_tag("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_tag("song.ogg").to_s
62
+ expect(actual).to eq(%(<audio src="/assets/song.ogg"></audio>))
63
+ end
64
+
65
+ it "renders with html attributes" do
66
+ actual = audio_tag("song.ogg", autoplay: true, controls: true).to_s
67
+ expect(actual).to eq(%(<audio autoplay="autoplay" controls="controls" src="/assets/song.ogg"></audio>))
68
+ end
69
+
70
+ it "renders with fallback content" do
71
+ actual = audio_tag("song.ogg") do
72
+ "Your browser does not support the audio tag"
73
+ end.to_s
74
+
75
+ expect(actual).to eq(%(<audio src="/assets/song.ogg">Your browser does not support the audio tag</audio>))
76
+ end
77
+
78
+ it "renders with tracks" do
79
+ actual = audio_tag("song.ogg") do
80
+ tag.track kind: "captions", src: subject.asset_url("song.pt-BR.vtt"), srclang: "pt-BR", label: "Portuguese"
81
+ end.to_s
82
+
83
+ expect(actual).to eq(%(<audio src="/assets/song.ogg"><track kind="captions" src="/assets/song.pt-BR.vtt" srclang="pt-BR" label="Portuguese"></audio>))
84
+ end
85
+
86
+ xit "renders with sources" do
87
+ actual = audio_tag do
88
+ tag.text "Your browser does not support the audio tag"
89
+ tag.source src: subject.asset_url("song.ogg"), type: "audio/ogg"
90
+ tag.source src: subject.asset_url("song.wav"), type: "audio/wav"
91
+ end.to_s
92
+
93
+ 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>))
94
+ end
95
+
96
+ it "raises an exception when no arguments" do
97
+ expect do
98
+ audio_tag
99
+ end.to raise_error(
100
+ ArgumentError,
101
+ "You should provide a source via `src` option or with a `source` HTML tag"
102
+ )
103
+ end
104
+
105
+ it "raises an exception when no src and no block" do
106
+ expect do
107
+ audio_tag(controls: true)
108
+ end.to raise_error(
109
+ ArgumentError,
110
+ "You should provide a source via `src` option or with a `source` HTML tag"
111
+ )
112
+ end
113
+
114
+ describe "cdn mode" do
115
+ let(:base_url) { "https://hanami.test" }
116
+
117
+ def before_prepare
118
+ Hanami.app.config.assets.base_url = base_url
119
+ end
120
+
121
+ it "returns absolute url for src attribute" do
122
+ actual = audio_tag("song.ogg").to_s
123
+ expect(actual).to eq(%(<audio src="#{base_url}/assets/song.ogg"></audio>))
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ def tag(...)
130
+ subject.__send__(:tag, ...)
131
+ end
132
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Hanami::Helpers::AssetsHelper, "#favicon_link_tag", :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_link_tag(...)
18
+ obj.instance_eval { favicon_link_tag(...) }
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_link_tag
57
+ expect(actual).to be_instance_of(::Hanami::View::HTML::SafeString)
58
+ end
59
+
60
+ it "is aliased as `favicon`" do
61
+ expect(subject.favicon).to eq favicon_link_tag
62
+ end
63
+
64
+ it "renders <link> tag" do
65
+ actual = favicon_link_tag.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_link_tag("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_link_tag("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_link_tag.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,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Hanami::Helpers::AssetsHelper, "#image_tag", :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_tag(...)
18
+ subject.image_tag(...)
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_tag("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_tag("application.jpg").to_s
62
+ expect(actual).to eq(%(<img src="/assets/application.jpg" alt="Application">))
63
+ end
64
+
65
+ it "custom alt" do
66
+ actual = image_tag("application.jpg", alt: "My Alt").to_s
67
+ expect(actual).to eq(%(<img src="/assets/application.jpg" alt="My Alt">))
68
+ end
69
+
70
+ it "custom data attribute" do
71
+ actual = image_tag("application.jpg", "data-user-id" => 5).to_s
72
+ expect(actual).to eq(%(<img src="/assets/application.jpg" alt="Application" data-user-id="5">))
73
+ end
74
+
75
+ it "ignores src passed as an option" do
76
+ actual = image_tag("application.jpg", src: "wrong").to_s
77
+ expect(actual).to eq(%(<img src="/assets/application.jpg" alt="Application">))
78
+ end
79
+
80
+ describe "cdn mode" do
81
+ let(:base_url) { "https://hanami.test" }
82
+
83
+ def before_prepare
84
+ Hanami.app.config.assets.base_url = "https://hanami.test"
85
+ end
86
+
87
+ it "returns absolute url for src attribute" do
88
+ actual = image_tag("application.jpg").to_s
89
+ expect(actual).to eq(%(<img src="#{base_url}/assets/application.jpg" alt="Application">))
90
+ end
91
+ end
92
+ end