js_rails_routes 0.7.0 → 0.7.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.
@@ -1,199 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe JSRailsRoutes::Generator do
4
- let(:generator) do
5
- described_class.clone.instance
6
- end
4
+ include_context 'run in a sandbox'
5
+
6
+ subject(:generator) { described_class.new(builder, writable: writable) }
7
7
 
8
- it { expect(described_class).to include(Singleton) }
8
+ let(:writable) { spy('writable') }
9
+ let(:builder) { double('builder', build: result) }
10
+ let(:result) { Hash['Rails' => 'rails body', 'Admin::Engine' => 'admin body'] }
9
11
 
10
12
  describe '#generate' do
11
- let(:output_dir) { File.expand_path('spec/tmp') }
12
- subject do
13
- generator.output_dir = output_dir
14
- generator.generate(task)
15
- end
13
+ subject { generator.generate(task) }
16
14
 
17
- let(:task) do
18
- 'js:routes'
19
- end
15
+ let(:task) { 'js:routes' }
20
16
 
21
- it 'writes JS files' do
22
- expect(generator).to receive(:write)
23
- .with(be_in(['Rails', 'Admin::Engine']), a_string_including("rake #{task}"))
24
- .twice
17
+ it 'writes with path to file and its contents' do
18
+ allow(writable).to receive(:write)
25
19
  subject
26
- end
27
-
28
- context 'when actually creating files' do
29
- let(:js_files) { Dir.glob(File.join(output_dir, '{admin,rails}-routes.js')).map { |file| Pathname.new(file) } }
30
-
31
- after { FileUtils.rm_f(js_files) }
32
-
33
- it 'creates JS files' do
34
- subject
35
- expect(js_files).to all be_file
36
- end
37
- end
38
-
39
- context 'when include_paths is given' do
40
- before do
41
- generator.include_paths = include_paths
42
- end
43
-
44
- let(:include_paths) do
45
- %r{/new}
46
- end
47
-
48
- it 'writes paths matching with the parameter' do
49
- expect(generator).to receive(:write)
50
- .with(be_in(['Rails', 'Admin::Engine']), a_kind_of(String))
51
- .twice do |_, arg|
52
- paths = arg.split("\n")[(2 + described_class::PROCESS_FUNC.split("\n").size)..-1]
53
- expect(paths).not_to be_empty
54
- expect(paths).to all(match(include_paths))
55
- end
56
- subject
57
- end
58
- end
59
-
60
- context 'when exclude_paths is given' do
61
- before do
62
- generator.exclude_paths = exclude_paths
63
- end
64
-
65
- let(:exclude_paths) do
66
- %r{/new}
67
- end
68
-
69
- it 'writes paths not matching with the parameter' do
70
- expect(generator).to receive(:write)
71
- .with(be_in(['Rails', 'Admin::Engine']), a_kind_of(String))
72
- .twice do |_, arg|
73
- paths = arg.split("\n")[(2 + described_class::PROCESS_FUNC.split("\n").size)..-1]
74
- expect(paths).not_to be_empty
75
- paths.each do |path|
76
- expect(path).to_not match(exclude_paths)
77
- end
78
- end
79
- subject
80
- end
81
- end
82
-
83
- context 'when include_names is given' do
84
- before do
85
- generator.include_names = include_names
86
- end
87
-
88
- let(:include_names) do
89
- /user|note/
90
- end
91
-
92
- it 'writes paths matching with the parameter' do
93
- expect(generator).to receive(:write)
94
- .with(be_in(['Rails', 'Admin::Engine']), a_kind_of(String))
95
- .twice do |_, arg|
96
- paths = arg.split("\n")[(2 + described_class::PROCESS_FUNC.split("\n").size)..-1]
97
- expect(paths).not_to be_empty
98
- expect(paths).to all(match(include_names))
99
- end
100
- subject
101
- end
102
- end
103
-
104
- context 'when exclude_names is given' do
105
- before do
106
- generator.exclude_names = exclude_names
107
- end
108
-
109
- let(:exclude_names) do
110
- /user|note/
111
- end
112
-
113
- it 'writes paths not matching with the parameter' do
114
- expect(generator).to receive(:write)
115
- .with(be_in(['Rails', 'Admin::Engine']), a_kind_of(String))
116
- .twice do |_, arg|
117
- paths = arg.split("\n")[(2 + described_class::PROCESS_FUNC.split("\n").size)..-1]
118
- expect(paths).not_to be_empty
119
- paths.each do |path|
120
- expect(path).to_not match(exclude_names)
121
- end
122
- end
123
- subject
124
- end
125
- end
126
-
127
- context 'when exclude_engines is given' do
128
- before do
129
- generator.exclude_engines = exclude_engines
130
- end
131
-
132
- let(:exclude_engines) do
133
- /^admin/
134
- end
135
-
136
- let(:excluded_routes) do
137
- /note|photo/
138
- end
139
-
140
- it 'writes paths not matching with the parameter' do
141
- expect(generator).to receive(:write)
142
- .with(be_in(['Rails', 'Admin::Engine']), a_kind_of(String))
143
- .once do |_, arg|
144
- paths = arg.split("\n")[(2 + described_class::PROCESS_FUNC.split("\n").size)..-1]
145
- expect(paths).not_to be_empty
146
- paths.each do |path|
147
- expect(path).to_not match(excluded_routes)
148
- end
149
- end
150
- subject
151
- end
152
- end
153
-
154
- shared_examples_for 'writes paths that matches expected routes' do
155
- it do
156
- expect(generator).to receive(:write)
157
- .with(be_in(['Rails', 'Admin::Engine']), a_kind_of(String))
158
- .twice do |_, arg|
159
- paths = arg.split("\n")[(2 + described_class::PROCESS_FUNC.split("\n").size)..-1]
160
- expect(paths).not_to be_empty
161
- expect(paths).to include(match(expected_routes))
162
- end
163
- subject
164
- end
165
- end
166
-
167
- context 'when camelize is nil' do
168
- let(:expected_routes) do
169
- /blog_path|note_path/
170
- end
171
-
172
- it_behaves_like 'writes paths that matches expected routes'
173
- end
174
-
175
- context 'when camelize is :lower' do
176
- before do
177
- generator.camelize = :lower
178
- end
179
-
180
- let(:expected_routes) do
181
- /blogPath|notePath/
182
- end
183
-
184
- it_behaves_like 'writes paths that matches expected routes'
185
- end
186
-
187
- context 'when camelize is :upper' do
188
- before do
189
- generator.camelize = :upper
190
- end
191
-
192
- let(:expected_routes) do
193
- /BlogPath|NotePath/
194
- end
195
-
196
- it_behaves_like 'writes paths that matches expected routes'
20
+ expect(writable).to have_received(:write).with(
21
+ a_string_ending_with('app/assets/javascripts/rails-routes.js'),
22
+ a_string_including('rails body')
23
+ ).ordered
24
+ expect(writable).to have_received(:write).with(
25
+ a_string_ending_with('app/assets/javascripts/admin-routes.js'),
26
+ a_string_including('admin body')
27
+ ).ordered
197
28
  end
198
29
  end
199
30
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe JSRailsRoutes::Language::Base do
4
+ subject(:language) { described_class.new }
5
+
6
+ describe '#handle_route_set' do
7
+ subject { language.handle_route_set(double('route set')) }
8
+
9
+ it { expect { subject }.to raise_error(NotImplementedError) }
10
+ end
11
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe JSRailsRoutes::Language::JavaScript do
4
+ subject(:language) { described_class.new }
5
+
6
+ include_context 'run in a sandbox'
7
+
8
+ describe '::PROCESS_FUNC' do
9
+ subject { described_class::PROCESS_FUNC }
10
+
11
+ it 'returns a javascript function' do
12
+ is_expected.to eq <<~JAVASCRIPT
13
+ function process(route, params, keys) {
14
+ var query = [];
15
+ for (var param in params) if (params.hasOwnProperty(param)) {
16
+ if (keys.indexOf(param) === -1) {
17
+ query.push(param + "=" + encodeURIComponent(params[param]));
18
+ }
19
+ }
20
+ return query.length ? route + "?" + query.join("&") : route;
21
+ }
22
+ JAVASCRIPT
23
+ end
24
+ end
25
+
26
+ describe '#handle_route_set' do
27
+ subject { language.handle_route_set(route_set) }
28
+
29
+ let(:route_set) do
30
+ rails_route_set = ActionDispatch::Routing::RouteSet.new.tap do |routes|
31
+ routes.draw do
32
+ resources :articles
33
+ end
34
+ end
35
+ JSRailsRoutes::RouteSet.new('Rails', rails_route_set)
36
+ end
37
+
38
+ context 'without camelize option' do
39
+ it 'returns a javascript with snake_case functions' do
40
+ is_expected.to eq <<~JAVASCRIPT
41
+ #{described_class::PROCESS_FUNC}
42
+ export function articles_path(params) { return process('/articles', params, []); }
43
+ export function new_article_path(params) { return process('/articles/new', params, []); }
44
+ export function edit_article_path(params) { return process('/articles/' + params.id + '/edit', params, ['id']); }
45
+ export function article_path(params) { return process('/articles/' + params.id + '', params, ['id']); }
46
+ JAVASCRIPT
47
+ end
48
+ end
49
+
50
+ context 'with camelize = :lower option' do
51
+ before do
52
+ JSRailsRoutes.configure do |c|
53
+ c.camelize = :lower
54
+ end
55
+ end
56
+
57
+ it 'returns a javascript with lowerCamelCase functions' do
58
+ is_expected.to eq <<~JAVASCRIPT
59
+ #{described_class::PROCESS_FUNC}
60
+ export function articlesPath(params) { return process('/articles', params, []); }
61
+ export function newArticlePath(params) { return process('/articles/new', params, []); }
62
+ export function editArticlePath(params) { return process('/articles/' + params.id + '/edit', params, ['id']); }
63
+ export function articlePath(params) { return process('/articles/' + params.id + '', params, ['id']); }
64
+ JAVASCRIPT
65
+ end
66
+ end
67
+
68
+ context 'with camelize = :upper option' do
69
+ before do
70
+ JSRailsRoutes.configure do |c|
71
+ c.camelize = :upper
72
+ end
73
+ end
74
+
75
+ it 'returns a javascript with UpperCamelCase functions' do
76
+ is_expected.to eq <<~JAVASCRIPT
77
+ #{described_class::PROCESS_FUNC}
78
+ export function ArticlesPath(params) { return process('/articles', params, []); }
79
+ export function NewArticlePath(params) { return process('/articles/new', params, []); }
80
+ export function EditArticlePath(params) { return process('/articles/' + params.id + '/edit', params, ['id']); }
81
+ export function ArticlePath(params) { return process('/articles/' + params.id + '', params, ['id']); }
82
+ JAVASCRIPT
83
+ end
84
+ end
85
+
86
+ context 'with include_paths option' do
87
+ before do
88
+ JSRailsRoutes.configure do |c|
89
+ c.include_paths = /new/
90
+ end
91
+ end
92
+
93
+ it 'returns a javascript matching to the regexp' do
94
+ is_expected.to eq <<~JAVASCRIPT
95
+ #{described_class::PROCESS_FUNC}
96
+ export function new_article_path(params) { return process('/articles/new', params, []); }
97
+ JAVASCRIPT
98
+ end
99
+ end
100
+
101
+ context 'with exclude_paths option' do
102
+ before do
103
+ JSRailsRoutes.configure do |c|
104
+ c.exclude_paths = /new/
105
+ end
106
+ end
107
+
108
+ it 'returns a javascript not matching to the regexp' do
109
+ is_expected.to eq <<~JAVASCRIPT
110
+ #{described_class::PROCESS_FUNC}
111
+ export function articles_path(params) { return process('/articles', params, []); }
112
+ export function edit_article_path(params) { return process('/articles/' + params.id + '/edit', params, ['id']); }
113
+ export function article_path(params) { return process('/articles/' + params.id + '', params, ['id']); }
114
+ JAVASCRIPT
115
+ end
116
+ end
117
+
118
+ context 'with include_names option' do
119
+ before do
120
+ JSRailsRoutes.configure do |c|
121
+ c.include_names = /new/
122
+ end
123
+ end
124
+
125
+ it 'returns a javascript matching to the regexp' do
126
+ is_expected.to eq <<~JAVASCRIPT
127
+ #{described_class::PROCESS_FUNC}
128
+ export function new_article_path(params) { return process('/articles/new', params, []); }
129
+ JAVASCRIPT
130
+ end
131
+ end
132
+
133
+ context 'with exclude_names option' do
134
+ before do
135
+ JSRailsRoutes.configure do |c|
136
+ c.exclude_names = /new/
137
+ end
138
+ end
139
+
140
+ it 'returns a javascript not matching to the regexp' do
141
+ is_expected.to eq <<~JAVASCRIPT
142
+ #{described_class::PROCESS_FUNC}
143
+ export function articles_path(params) { return process('/articles', params, []); }
144
+ export function edit_article_path(params) { return process('/articles/' + params.id + '/edit', params, ['id']); }
145
+ export function article_path(params) { return process('/articles/' + params.id + '', params, ['id']); }
146
+ JAVASCRIPT
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe JSRailsRoutes::RouteSet do
4
+ subject(:route_set) { described_class.new(name, routes) }
5
+
6
+ include_context 'run in a sandbox'
7
+
8
+ let(:name) { 'Foo::Engine' }
9
+ let(:routes) do
10
+ ActionDispatch::Routing::RouteSet.new.tap do |routes|
11
+ routes.draw do
12
+ get '/articles' => 'articles#index'
13
+ get '/users' => 'users#index'
14
+ end
15
+ end
16
+ end
17
+
18
+ describe '.correct_matching_route_set_list' do
19
+ subject { described_class.correct_matching_route_set_list }
20
+
21
+ it 'returns an array of matching route sets' do
22
+ # See spec/support/test_app.rb
23
+ is_expected.to match [
24
+ be_a(described_class).and(have_attributes(name: 'Rails')).and(be_match),
25
+ be_a(described_class).and(have_attributes(name: 'Admin::Engine')).and(be_match)
26
+ ]
27
+ end
28
+ end
29
+
30
+ describe '#name' do
31
+ subject { route_set.name }
32
+
33
+ it { is_expected.to eq name }
34
+ end
35
+
36
+ describe '#routes' do
37
+ subject { route_set.routes }
38
+
39
+ it { is_expected.to all be_a(JSRailsRoutes::Route).and(be_match) }
40
+
41
+ context 'when some routes are excluded' do
42
+ before do
43
+ JSRailsRoutes.configure do |c|
44
+ c.exclude_names = /users/
45
+ end
46
+ end
47
+
48
+ it "doesn't include the excluded route" do
49
+ is_expected.to include be_a(JSRailsRoutes::Route).and(have_attributes(name: /articles/))
50
+ is_expected.not_to include be_a(JSRailsRoutes::Route).and(have_attributes(name: /users/))
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#match?' do
56
+ subject { route_set.match? }
57
+
58
+ it { is_expected.to be true }
59
+
60
+ context 'when exclude_engines option is specified' do
61
+ before do
62
+ JSRailsRoutes.configure do |c|
63
+ c.exclude_engines = exclude_engines
64
+ end
65
+ end
66
+
67
+ context 'and it matches to the name' do
68
+ let(:exclude_engines) { /Foo/ }
69
+
70
+ it { is_expected.to be false }
71
+ end
72
+
73
+ context 'and it does not match to the name' do
74
+ let(:exclude_engines) { /Bar/ }
75
+
76
+ it { is_expected.to be true }
77
+ end
78
+ end
79
+
80
+ context 'when routes are empty' do
81
+ before { allow(route_set).to receive(:routes).and_return([]) }
82
+
83
+ it { is_expected.to be false }
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe JSRailsRoutes::Route do
4
+ subject(:route) { described_class.new(raw_route) }
5
+
6
+ include_context 'run in a sandbox'
7
+
8
+ let(:raw_route) do
9
+ ActionDispatch::Routing::RouteSet.new.tap do |routes|
10
+ routes.draw do
11
+ get '/articles' => 'articles#index'
12
+ end
13
+ end.routes.first
14
+ end
15
+
16
+ describe '#name' do
17
+ subject { route.name }
18
+
19
+ it { is_expected.to eq 'articles' }
20
+ end
21
+
22
+ describe '#path' do
23
+ subject { route.path }
24
+
25
+ it { is_expected.to eq '/articles' }
26
+ end
27
+
28
+ describe '#match?' do
29
+ subject { route.match? }
30
+
31
+ it { is_expected.to be true }
32
+
33
+ context 'when include_paths option is specified' do
34
+ before do
35
+ JSRailsRoutes.configure do |c|
36
+ c.include_paths = include_paths
37
+ end
38
+ end
39
+
40
+ context 'and it matches to the path' do
41
+ let(:include_paths) { /articles/ }
42
+
43
+ it { is_expected.to be true }
44
+ end
45
+
46
+ context 'and it does not matche to the path' do
47
+ let(:include_paths) { /users/ }
48
+
49
+ it { is_expected.to be false }
50
+ end
51
+ end
52
+
53
+ context 'when exclude_paths option is specified' do
54
+ before do
55
+ JSRailsRoutes.configure do |c|
56
+ c.exclude_paths = exclude_paths
57
+ end
58
+ end
59
+
60
+ context 'and it matches to the path' do
61
+ let(:exclude_paths) { /articles/ }
62
+
63
+ it { is_expected.to be false }
64
+ end
65
+
66
+ context 'and it does not matche to the path' do
67
+ let(:exclude_paths) { /users/ }
68
+
69
+ it { is_expected.to be true }
70
+ end
71
+ end
72
+
73
+ context 'when include_names option is specified' do
74
+ before do
75
+ JSRailsRoutes.configure do |c|
76
+ c.include_names = include_names
77
+ end
78
+ end
79
+
80
+ context 'and it matches to the name' do
81
+ let(:include_names) { /articles/ }
82
+
83
+ it { is_expected.to be true }
84
+ end
85
+
86
+ context 'and it does not matche to the name' do
87
+ let(:include_names) { /users/ }
88
+
89
+ it { is_expected.to be false }
90
+ end
91
+ end
92
+
93
+ context 'when exclude_names option is specified' do
94
+ before do
95
+ JSRailsRoutes.configure do |c|
96
+ c.exclude_names = exclude_names
97
+ end
98
+ end
99
+
100
+ context 'and it matches to the name' do
101
+ let(:exclude_names) { /articles/ }
102
+
103
+ it { is_expected.to be false }
104
+ end
105
+
106
+ context 'and it does not matche to the name' do
107
+ let(:exclude_names) { /users/ }
108
+
109
+ it { is_expected.to be true }
110
+ end
111
+ end
112
+ end
113
+ end
@@ -2,8 +2,67 @@
2
2
 
3
3
  RSpec.describe JSRailsRoutes do
4
4
  describe '.configure' do
5
- it 'yields with Generator instance' do
6
- expect { |b| described_class.configure(&b) }.to yield_with_args(JSRailsRoutes::Generator.instance)
5
+ it 'yields with .config' do
6
+ expect { |b| described_class.configure(&b) }.to yield_with_args(described_class.config)
7
+ end
8
+ end
9
+
10
+ describe '.config' do
11
+ subject { described_class.config }
12
+
13
+ it { is_expected.to be_a JSRailsRoutes::Configuration }
14
+ end
15
+
16
+ describe '.sandbox' do
17
+ it 'yields within a new sandbox' do
18
+ original = described_class.config
19
+ described_class.sandbox do
20
+ expect(described_class.config).not_to be original
21
+ expect(described_class.config).to be_a JSRailsRoutes::Configuration
22
+ end
23
+ expect(described_class.config).to be original
24
+ end
25
+ end
26
+
27
+ describe '.generate_javascript' do
28
+ subject { described_class.generate_javascript(task) }
29
+
30
+ let(:task) { 'js:routes' }
31
+ let(:app_root) { JSRailsRoutes::SpecHelper::TestApp.root }
32
+
33
+ before do
34
+ FileUtils.rm_rf(app_root)
35
+ FileUtils.mkdir_p(app_root.join('app/assets/javascripts'))
36
+ end
37
+
38
+ it 'generates javascript files' do
39
+ subject
40
+
41
+ expect(File.read(app_root.join('app/assets/javascripts/rails-routes.js'))).to eq <<~JAVASCRIPT
42
+ // Don't edit manually. `rake #{task}` generates this file.
43
+ #{JSRailsRoutes::Language::JavaScript::PROCESS_FUNC}
44
+ export function blogs_path(params) { return process('/blogs', params, []); }
45
+ export function new_blog_path(params) { return process('/blogs/new', params, []); }
46
+ export function edit_blog_path(params) { return process('/blogs/' + params.id + '/edit', params, ['id']); }
47
+ export function blog_path(params) { return process('/blogs/' + params.id + '', params, ['id']); }
48
+ export function users_path(params) { return process('/users', params, []); }
49
+ export function new_user_path(params) { return process('/users/new', params, []); }
50
+ export function edit_user_path(params) { return process('/users/' + params.id + '/edit', params, ['id']); }
51
+ export function user_path(params) { return process('/users/' + params.id + '', params, ['id']); }
52
+ JAVASCRIPT
53
+
54
+ expect(File.read(app_root.join('app/assets/javascripts/admin-routes.js'))).to eq <<~JAVASCRIPT
55
+ // Don't edit manually. `rake #{task}` generates this file.
56
+ #{JSRailsRoutes::Language::JavaScript::PROCESS_FUNC}
57
+ export function notes_path(params) { return process('/notes', params, []); }
58
+ export function new_note_path(params) { return process('/notes/new', params, []); }
59
+ export function edit_note_path(params) { return process('/notes/' + params.id + '/edit', params, ['id']); }
60
+ export function note_path(params) { return process('/notes/' + params.id + '', params, ['id']); }
61
+ export function photos_path(params) { return process('/photos', params, []); }
62
+ export function new_photo_path(params) { return process('/photos/new', params, []); }
63
+ export function edit_photo_path(params) { return process('/photos/' + params.id + '/edit', params, ['id']); }
64
+ export function photo_path(params) { return process('/photos/' + params.id + '', params, ['id']); }
65
+ JAVASCRIPT
7
66
  end
8
67
  end
9
68
  end
data/spec/spec_helper.rb CHANGED
@@ -8,23 +8,7 @@ SimpleCov.start
8
8
  require 'rails/all'
9
9
  require 'js_rails_routes'
10
10
 
11
- class TestApp < Rails::Application
12
- config.root = File.expand_path('test_app', __dir__)
13
-
14
- routes.draw do
15
- resources :blogs
16
- resources :users
17
- end
18
- end
19
-
20
- module Admin
21
- class Engine < ::Rails::Engine
22
- routes.draw do
23
- resources :notes
24
- resources :photos
25
- end
26
- end
27
- end
11
+ Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require f }
28
12
 
29
13
  RSpec.configure do |config|
30
14
  config.expect_with :rspec do |expectations|
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec::Matchers.define_negated_matcher(:not_change, :change)
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_context 'run in a sandbox' do # rubocop:disable RSpec/ContextWording
4
+ around do |example|
5
+ JSRailsRoutes.sandbox { example.run }
6
+ end
7
+ end