spec_views 0.1.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 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: []