spec_views 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 82f7ca371b973c3523a11dd3cacb3b76001d3fe2f2d8b78b93992bdabdafafea
4
+ data.tar.gz: 5285d6511b852478642cb6402f6b58a62271642822a18acd25113cd2b39bc068
5
+ SHA512:
6
+ metadata.gz: 3cc275120f3d2f06ca86158ac2a950edacce9a829dbacd7205edd556b4f52aaaa4b9b4ed24366918449fb1a239af7da86786ed43c2cb1b27c3371066ce23f40b
7
+ data.tar.gz: 1513f33981acb6b65b397c3faa2760eba807a5fd4f0a7a033599684471fd5e17a73c927d97361072fb548f142cdd31605b4ef4fb4d789428a20bbc9b541b8d02
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Sebastian Gaul
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # SpecViews
2
+ Render views from controller specs for comparision
3
+
4
+ ## Usage
5
+ Replace selected RSpec `it` methods with `render`:
6
+
7
+ ```ruby
8
+ RSpec.describe HomeController, type: :controller do
9
+ describe 'GET #show' do
10
+ render 'homepage' do
11
+ get :show
12
+ end
13
+ end
14
+ end
15
+ ```
16
+
17
+ ## Installation
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'spec_views'
22
+ ```
23
+
24
+ And then execute:
25
+ ```bash
26
+ $ bundle
27
+ ```
28
+
29
+ Or install it yourself as:
30
+ ```bash
31
+ $ gem install spec_views
32
+ ```
33
+
34
+ ## License
35
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'SpecViews'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
File without changes
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpecViews
4
+ class ViewsController < ApplicationController
5
+ skip_authorization_check
6
+ layout 'spec_views'
7
+
8
+ def index
9
+ @directories = directories
10
+ @latest_run = directories.map(&:last_run).max
11
+ return unless params[:challenger] == 'next'
12
+
13
+ first = @directories.detect(&:challenger?)
14
+ if first
15
+ redirect_to(action: :compare, id: first)
16
+ else
17
+ redirect_to(action: :index, challenger: nil)
18
+ end
19
+ end
20
+
21
+ def show
22
+ view = filename('view')
23
+ view = filename('challenger') if params[:view] == 'challenger'
24
+ if pdf?
25
+ send_data(
26
+ get_view(view),
27
+ filename: 'a.pdf',
28
+ type: 'application/pdf', disposition: 'inline'
29
+ )
30
+ else
31
+ render html: get_view(view)
32
+ end
33
+ end
34
+
35
+ def compare
36
+ @directory = directory
37
+ end
38
+
39
+ def preview
40
+ @directory = directory
41
+ @next = directories[directories.index(@directory) + 1]
42
+ index = directories.index(@directory)
43
+ @previous = directories[index - 1] if index > 0
44
+ end
45
+
46
+ def accept
47
+ accept_directory(params[:id])
48
+ redirect_to action: :index, challenger: :next
49
+ end
50
+
51
+ def accept_all
52
+ directories.each do |dir|
53
+ accept_directory(dir) if dir.challenger?
54
+ end
55
+ redirect_to action: :index
56
+ end
57
+
58
+ def reject
59
+ challenger = file_path(filename('challenger'))
60
+ FileUtils.remove_file(challenger)
61
+ redirect_to action: :index, challenger: :next
62
+ end
63
+
64
+ def destroy_outdated
65
+ @directories = directories
66
+ @latest_run = directories.map(&:last_run).max
67
+ @directories.each do |dir|
68
+ dir.delete! if dir.last_run < @latest_run
69
+ end
70
+ redirect_to action: :index
71
+ end
72
+
73
+ private
74
+
75
+ class Directory
76
+ attr_reader :path
77
+
78
+ def initialize(path)
79
+ @path = path
80
+ end
81
+
82
+ def basename
83
+ path.basename
84
+ end
85
+
86
+ def to_param
87
+ basename.to_s
88
+ end
89
+
90
+ def name
91
+ basename
92
+ end
93
+
94
+ def challenger?
95
+ File.file?(path.join('challenger.html')) || File.file?(path.join('challenger.pdf'))
96
+ end
97
+
98
+ def controller_name
99
+ splitted_name.first.gsub(/Controller(_.*)$/, 'Controller').gsub('_', '::')
100
+ end
101
+
102
+ def method
103
+ splitted_name.second
104
+ end
105
+
106
+ def description
107
+ splitted_name.third.humanize
108
+ end
109
+
110
+ def last_run
111
+ @last_run ||= begin
112
+ Time.zone.parse(File.read(path.join('last_run.txt')))
113
+ rescue Errno::ENOENT
114
+ Time.zone.at(0)
115
+ end
116
+ end
117
+
118
+ def delete!
119
+ FileUtils.remove_dir(path)
120
+ end
121
+
122
+ private
123
+
124
+ def splitted_name
125
+ @splitted_name ||= name.to_s.split(/_(DELETE|GET|PATCH|POST|PUT)_/)
126
+ end
127
+ end
128
+
129
+ def directories
130
+ @directories ||= Pathname.new(directory_path).children.select(&:directory?).map do |path|
131
+ Directory.new(path)
132
+ end.sort_by(&:basename)
133
+ end
134
+
135
+ def directory_path
136
+ Rails.root.join(Rails.configuration.spec_views.directory)
137
+ end
138
+
139
+ def directory
140
+ directories.detect { |dir| dir.to_param == params[:id] }
141
+ end
142
+
143
+ def get_view(filename = nil)
144
+ filename ||= pdf? ? 'view.pdf' : 'view.html'
145
+ File.read(file_path(filename)).html_safe # rubocop:disable Rails/OutputSafety
146
+ rescue Errno::ENOENT
147
+ ''
148
+ end
149
+
150
+ def file_path(filename, id: nil)
151
+ id ||= params[:id]
152
+ id = id.to_param if id.respond_to?(:to_param)
153
+ directory_path.join(id, filename)
154
+ end
155
+
156
+ def filename(base = 'view')
157
+ pdf? ? "#{base}.pdf" : "#{base}.html"
158
+ end
159
+
160
+ def pdf?
161
+ params[:id] && params[:id].end_with?('__pdf')
162
+ end
163
+
164
+ def accept_directory(id)
165
+ champion = file_path(filename('view'), id: id)
166
+ challenger = file_path(filename('challenger'), id: id)
167
+ FileUtils.copy_file(challenger, champion)
168
+ FileUtils.remove_file(challenger)
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,198 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %meta{content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
5
+ %title Spec Views
6
+ %meta{charset: "utf-8"}/
7
+ %meta{content: "width=device-width, initial-scale=1, shrink-to-fit=no", name: "viewport"}/
8
+ %meta{name: "turbolinks-cache-control", content: "no-cache"}/
9
+ = csrf_meta_tags
10
+ = csp_meta_tag
11
+ :sass
12
+ $dark-bg: #252526
13
+ $dark-bg-light: #2A2D2E
14
+ $dark-bg-lighter: #37373D
15
+ $dark-text: #DADADA
16
+
17
+ $accept-bg: #5fa285
18
+ $accept-text: $dark-text
19
+
20
+ $reject-bg: #d27575
21
+ $reject-text: $dark-text
22
+
23
+ $highlight: #0E639C
24
+ $challenger: $highlight
25
+ $outdated: $reject-bg
26
+
27
+ *
28
+ box-sizing: border-box
29
+ margin: 0
30
+ padding: 0
31
+
32
+ body
33
+ font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"
34
+ background: #252526
35
+ color: #FFF
36
+ margin: 0
37
+ padding: 0
38
+
39
+ .iframes
40
+ position: relative
41
+ z-index: 5
42
+ display: flex
43
+ justify-content: space-between
44
+ align-items: stretch
45
+ height: calc(100vh - 50px)
46
+ overflow: auto
47
+
48
+ > *
49
+ width: calc(50% - 5px)
50
+ height: 100%
51
+ display: flex
52
+ flex-direction: column
53
+ justify-content: stretch
54
+
55
+ &.w-100
56
+ width: calc(100% - 5px)
57
+
58
+ iframe
59
+ border: 0
60
+ margin: 0
61
+ padding: 0
62
+ width: 100%
63
+ flex-grow: 1
64
+
65
+ h2
66
+ margin: 0
67
+ padding: 4px 0
68
+ text-align: center
69
+ font-weight: 300
70
+ text-transform: uppercase
71
+ font-size: 12px
72
+ line-height: 1
73
+
74
+ .footer
75
+ position: relative
76
+ z-index: 10
77
+ display: flex
78
+ justify-content: space-between
79
+ height: 50px
80
+ box-shadow: 0px -1px 4px rgba(0, 0, 0, 0.65)
81
+
82
+ .info
83
+ padding: 0 0 0 10px
84
+ font-size: 14px
85
+ display: flex
86
+ align-items: center
87
+
88
+ > div
89
+ padding: .5rem .2rem
90
+
91
+ .actions
92
+ display: flex
93
+ justify-content: flex-end
94
+ padding: 2px 2rem 0 0
95
+
96
+ > *
97
+ margin-left: 2rem
98
+
99
+ form.button_to
100
+ display: flex
101
+
102
+ input[type=submit], .btn
103
+ display: block
104
+ padding: .5rem .5rem .4rem
105
+ border: 0 solid $dark-bg-lighter
106
+ border-width: 0 0 8px 0
107
+ color: $dark-text
108
+ border-radius: 0
109
+ background: $dark-bg-light
110
+ cursor: pointer
111
+ font-size: .9rem
112
+ line-height: 1.75
113
+ min-width: 5rem
114
+ text-align: center
115
+
116
+ &:hover
117
+ background: $dark-bg-lighter
118
+
119
+ &.accept
120
+ border-color: $accept-bg
121
+ color: $accept-text
122
+ &.reject
123
+ border-color: $reject-bg
124
+ color: $reject-text
125
+ &.btn
126
+ border-color: $highlight
127
+ &.disabled
128
+ opacity: 0.5
129
+ cursor: default
130
+ &:hover
131
+ background: $dark-bg-light
132
+
133
+ a
134
+ color: $dark-text
135
+ text-decoration: none
136
+
137
+ .directories
138
+ display: flex
139
+ flex-direction: column
140
+ align-items: center
141
+ margin: 5rem auto 0
142
+ list-style-type: none
143
+ padding: 0
144
+
145
+ > div
146
+ margin-top: 1rem
147
+ width: 58rem
148
+ > a
149
+ display: flex
150
+ flex: 1 0 auto
151
+ align-items: stretch
152
+
153
+ &:hover, &:focus
154
+ background-color: $dark-bg-light
155
+ &:active
156
+ background-color: $dark-bg-lighter
157
+
158
+ &.challenger
159
+ > div:first-child
160
+ border-color: $challenger
161
+ text-align: center
162
+ &.outdated
163
+ > div:first-child
164
+ border-color: $outdated
165
+ text-align: center
166
+
167
+ > div
168
+ padding: .5rem
169
+
170
+ > :first-child
171
+ width: 8rem
172
+ border: 0 solid transparent
173
+ border-left-width: 1rem
174
+ font-size: 0.75rem
175
+ display: flex
176
+ align-items: center
177
+
178
+ > :last-child
179
+ display: flex
180
+ flex: 1 0 auto
181
+ width: 50rem
182
+ align-items: center
183
+
184
+ > :nth-child(1)
185
+ flex-shrink: 0
186
+ overflow: hidden
187
+ text-overflow: ellipsis
188
+ width: 15rem
189
+ text-align: right
190
+ > :nth-child(2)
191
+ flex-shrink: 0
192
+ padding: 0 1rem
193
+ text-align: center
194
+ width: 4rem
195
+ > :nth-child(3)
196
+
197
+ %body
198
+ = yield
@@ -0,0 +1,16 @@
1
+ .iframes
2
+ %div
3
+ %h2 Champion
4
+ %iframe{ src: url_for(action: :show) }
5
+ %div
6
+ %h2 Challenger
7
+ %iframe{ src: url_for(action: :show, view: :challenger) }
8
+ .footer
9
+ .info
10
+ %div= @directory.controller_name
11
+ %div= @directory.method
12
+ %div= @directory.description
13
+ .actions
14
+ = link_to 'Index', url_for(action: :index), class: 'index btn'
15
+ = button_to 'Reject', url_for(action: :reject), class: 'reject'
16
+ = button_to 'Accept', url_for(action: :accept), class: 'accept'
@@ -0,0 +1,28 @@
1
+ .iframes
2
+ .directories.w-100
3
+ - @directories.each do |dir|
4
+ - body = capture do
5
+ %div
6
+ %div= dir.controller_name
7
+ %div= dir.method
8
+ %div= dir.description
9
+ - if dir.challenger?
10
+ = link_to({ action: :compare, id: dir }, class: 'challenger') do
11
+ %div CHALLENGER
12
+ = body
13
+ - elsif dir.last_run < @latest_run
14
+ = link_to({ action: :preview, id: dir }, class: 'outdated') do
15
+ %div OUTDATED
16
+ = body
17
+ - else
18
+ = link_to(action: :preview, id: dir) do
19
+ %div
20
+ = body
21
+
22
+ .footer
23
+ .info
24
+ .actions
25
+ - if @directories.any?{ |dir| dir.last_run < @latest_run }
26
+ = button_to 'Remove Outdated', url_for(action: :destroy_outdated), method: :delete, class: 'reject'
27
+ - if @directories.any?(&:challenger?)
28
+ = button_to 'Accept All', url_for(action: :accept_all), method: :post, class: 'accept'
@@ -0,0 +1,19 @@
1
+ .iframes
2
+ %div.w-100
3
+ %h2 Champion
4
+ %iframe{ src: url_for(action: :show) }
5
+ .footer
6
+ .info
7
+ %div= @directory.controller_name
8
+ %div= @directory.method
9
+ %div= @directory.description
10
+ .actions
11
+ = link_to 'Index', url_for(action: :index), class: 'index btn'
12
+ - if @previous
13
+ = link_to 'Previous', url_for(action: :preview, id: @previous), class: 'previous btn', disabled: true
14
+ - else
15
+ %span.previous.btn.disabled Previous
16
+ - if @next
17
+ = link_to 'Next', url_for(action: :preview, id: @next), class: 'next btn'
18
+ - else
19
+ %span.previous.btn.disabled Next
data/config/routes.rb ADDED
@@ -0,0 +1,18 @@
1
+ Rails.application.routes.draw do
2
+ namespace :spec_views do
3
+ root to: redirect('spec_views/views')
4
+
5
+ resources :views, only: %i[index show] do
6
+ collection do
7
+ delete :destroy_outdated
8
+ post :accept_all
9
+ end
10
+ member do
11
+ get :compare
12
+ get :preview
13
+ post :accept
14
+ post :reject
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpecViews
4
+ class Configuration < ActiveSupport::InheritableOptions
5
+ def self.default
6
+ new(
7
+ directory: 'spec/fixtures/views'
8
+ )
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_views/configuration'
2
+
3
+ module SpecViews
4
+ class Engine < ::Rails::Engine
5
+ config.spec_views = Configuration.default
6
+
7
+ initializer 'configure.rspec' do |app|
8
+ if Rails.env.test? && Object.const_defined?('RSpec')
9
+ require 'spec_views/support'
10
+
11
+ RSpec.configure do |config|
12
+ config.include Support
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpecViews
4
+ module Support
5
+ class SpecView
6
+ attr_reader :body, :context, :example, :spec_name, :directory_path, :last_run_path,
7
+ :time, :response
8
+
9
+ class ReadError < StandardError
10
+ def initialize(msg = 'My default message')
11
+ super
12
+ end
13
+ end
14
+
15
+ def initialize(context, example, response, time)
16
+ @context = context
17
+ @response = response
18
+ @example = example
19
+ @spec_name = example.full_description.strip
20
+ .gsub(/[^0-9A-Za-z.\-]/, '_').gsub('__', '_')
21
+ @spec_name = "#{@spec_name}__pdf" if pdf?
22
+ @directory_path = Rails.root.join(Rails.configuration.spec_views.directory, spec_name)
23
+ @last_run_path = directory_path.join('last_run.txt')
24
+ @body = response.body
25
+ @time = time
26
+ end
27
+
28
+ def write
29
+ FileUtils.mkdir_p(directory_path)
30
+ write_to_path(champion_path, sanitized_body)
31
+ put_write_instructions
32
+ end
33
+
34
+ def write_challenger
35
+ return unless changed?
36
+
37
+ FileUtils.mkdir_p(directory_path)
38
+ write_to_path(challenger_path, sanitized_body)
39
+ end
40
+
41
+ def delete_challenger
42
+ FileUtils.rm_f(challenger_path) unless changed?
43
+ end
44
+
45
+ def write_last_run
46
+ FileUtils.mkdir_p(directory_path)
47
+ write_to_path(last_run_path, time)
48
+ end
49
+
50
+ def expect_eq
51
+ pdf? ? expect_eq_pdf : expect_eq_text
52
+ delete_challenger
53
+ end
54
+
55
+ def expect_eq_text
56
+ context.expect(sanitized_body).to context.eq(read)
57
+ end
58
+
59
+ def expect_eq_pdf
60
+ champion_md5 = nil
61
+ begin
62
+ champion_md5 = Digest::MD5.file(champion_path).hexdigest
63
+ rescue Errno::ENOENT # rubocop:disable Lint/SuppressedException
64
+ end
65
+ current_md5 = Digest::MD5.hexdigest(sanitized_body)
66
+ context.expect(current_md5).to context.eq(champion_md5), 'MD5s of PDF do not match'
67
+ end
68
+
69
+ def read
70
+ File.read(champion_path)
71
+ rescue Errno::ENOENT
72
+ raise ReadError, "Cannot find view fixture #{champion_path.to_s.gsub(Rails.root.to_s, '')}\n" \
73
+ "Create the file by adding the follwing to your spec:\n" \
74
+ 'spec_view.write'
75
+ end
76
+
77
+ def changed?
78
+ return pdf_changed? if pdf?
79
+
80
+ begin
81
+ champion = read
82
+ rescue ReadError
83
+ champion = nil
84
+ end
85
+ sanitized_body != champion
86
+ end
87
+
88
+ def pdf_changed?
89
+ champion_md5 = Digest::MD5.file(champion_path).hexdigest
90
+ current_md5 = Digest::MD5.hexdigest(sanitized_body)
91
+ champion_md5 != current_md5
92
+ rescue Errno::ENOENT
93
+ true
94
+ end
95
+
96
+ private
97
+
98
+ def champion_path
99
+ pdf? ? directory_path.join('view.pdf') : directory_path.join('view.html')
100
+ end
101
+
102
+ def challenger_path
103
+ pdf? ? directory_path.join('challenger.pdf') : directory_path.join('challenger.html')
104
+ end
105
+
106
+ def sanitized_body
107
+ return body if pdf?
108
+
109
+ remove_pack_digests_from_body(
110
+ remove_digests_from_body(body),
111
+ )
112
+ end
113
+
114
+ def remove_digests_from_body(body)
115
+ body.gsub(/(-[a-z0-9]{64})(\.css|\.js|\.png|\.jpg|\.jpeg|\.svg|\.gif)/, '\2')
116
+ end
117
+
118
+ def remove_pack_digests_from_body(body)
119
+ body.gsub(%r{(packs.*/js/[a-z0-9_]+)(-[a-z0-9]{20})(\.js)}, '\1\3')
120
+ end
121
+
122
+ def put_write_instructions
123
+ puts
124
+ puts "\e[33mWarning:\e[0m Writing view fixture to #{champion_path.to_s.gsub(Rails.root.to_s, '')}"
125
+ puts 'xdg-open "http://localhost:3100/spec_views/"'
126
+ end
127
+
128
+ def write_to_path(path, content)
129
+ File.open(path.to_s, pdf? ? 'wb' : 'w') do |file|
130
+ file.write(content)
131
+ end
132
+ end
133
+
134
+ def pdf?
135
+ response.content_type == 'application/pdf'
136
+ end
137
+ end
138
+
139
+ def spec_view
140
+ SpecView.new(self, @_spec_view_example, response, $_spec_view_time)
141
+ end
142
+
143
+ module SpecViewExample
144
+ def render(description = nil, focus: nil, pending: nil, status: :ok, &block)
145
+ context do # rubocop:disable RSpec/MissingExampleGroupArgument
146
+ render_views
147
+ options = {}
148
+ options[:focus] = focus unless focus.nil?
149
+ options[:pending] = pending unless pending.nil?
150
+ it(description, options) do
151
+ instance_eval(&block)
152
+ spec_view.write_last_run
153
+ write = status.in?(
154
+ [
155
+ response.message.parameterize.underscore.to_sym,
156
+ response.status,
157
+ ],
158
+ )
159
+ spec_view.write_challenger if write
160
+ spec_view.expect_eq
161
+ end
162
+ end
163
+ end
164
+ end
165
+
166
+ RSpec.configure do |c|
167
+ c.extend SpecViewExample, type: :controller
168
+ c.before(:suite) do |_example|
169
+ $_spec_view_time = Time.zone.now
170
+ end
171
+ c.before(type: :controller) do |example|
172
+ @_spec_view_example = example
173
+ end
174
+ c.before(:each, type: :controller) do
175
+ Timecop.freeze(Time.zone.local(2024, 2, 29, 0o0, 17, 42))
176
+ end
177
+ c.after(:each, type: :controller) do
178
+ Timecop.return
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,3 @@
1
+ module SpecViews
2
+ VERSION = '0.1.0'
3
+ end
data/lib/spec_views.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "spec_views/engine"
2
+
3
+ module SpecViews
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :spec_views do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spec_views
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Gaul
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-01-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: haml-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Render views from controller specs for comparision
56
+ email:
57
+ - sebastian.gaul@lichtbit.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - app/assets/config/spec_views_manifest.js
66
+ - app/controllers/spec_views/views_controller.rb
67
+ - app/views/layouts/spec_views.html.haml
68
+ - app/views/spec_views/views/compare.html.haml
69
+ - app/views/spec_views/views/index.html.haml
70
+ - app/views/spec_views/views/preview.html.haml
71
+ - config/routes.rb
72
+ - lib/spec_views.rb
73
+ - lib/spec_views/configuration.rb
74
+ - lib/spec_views/engine.rb
75
+ - lib/spec_views/support.rb
76
+ - lib/spec_views/version.rb
77
+ - lib/tasks/spec_views_tasks.rake
78
+ homepage: https://lichtbit.com
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubygems_version: 3.1.6
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Render views from controller specs for comparision
101
+ test_files: []