algoliasearch-jekyll 0.2.2 → 0.2.3
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 +4 -4
- data/.rspec +2 -0
- data/.rubocop.yml +25 -0
- data/Gemfile +15 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +20 -0
- data/README.md +148 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/lib/push.rb +17 -10
- data/lib/record_extractor.rb +40 -46
- data/scripts/git_hooks/pre-commit +10 -0
- data/scripts/git_hooks/pre-push +3 -0
- data/scripts/run_tests +2 -0
- data/scripts/update_gem +10 -0
- data/spec/fixtures/_config.yml +7 -0
- data/spec/fixtures/_my-collection/collection-item.html +6 -0
- data/spec/fixtures/_my-collection/collection-item.md +7 -0
- data/spec/fixtures/_posts/2015-07-02-test-post.md +32 -0
- data/spec/fixtures/about.md +34 -0
- data/spec/fixtures/api_key_dir/_algolia_api_key +1 -0
- data/spec/fixtures/assets/ring.png +0 -0
- data/spec/fixtures/authors.html +5 -0
- data/spec/fixtures/excluded.html +5 -0
- data/spec/fixtures/hierarchy.md +35 -0
- data/spec/fixtures/weight.md +19 -0
- data/spec/push_spec.rb +220 -0
- data/spec/record_extractor_spec.rb +451 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/spec_helper_jekyll.rb +4 -0
- data/spec/spec_helper_simplecov.rb +9 -0
- metadata +99 -27
data/spec/push_spec.rb
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe(AlgoliaSearchJekyllPush) do
|
4
|
+
let(:push) { AlgoliaSearchJekyllPush }
|
5
|
+
let(:site) { get_site }
|
6
|
+
let(:page_file) { site.file_by_name('about.md') }
|
7
|
+
let(:html_page_file) { site.file_by_name('authors.html') }
|
8
|
+
let(:excluded_page_file) { site.file_by_name('excluded.html') }
|
9
|
+
let(:post_file) { site.file_by_name('2015-07-02-test-post.md') }
|
10
|
+
let(:static_file) { site.file_by_name('ring.png') }
|
11
|
+
let(:document_file) { site.file_by_name('collection-item.md') }
|
12
|
+
let(:html_document_file) { site.file_by_name('collection-item.html') }
|
13
|
+
let(:options) do
|
14
|
+
{
|
15
|
+
'drafts' => true
|
16
|
+
}
|
17
|
+
end
|
18
|
+
let(:config) do
|
19
|
+
{
|
20
|
+
'source' => File.expand_path('./spec/fixtures'),
|
21
|
+
'markdown_ext' => 'md,mkd',
|
22
|
+
'algolia' => {
|
23
|
+
'application_id' => 'APPID',
|
24
|
+
'index_name' => 'INDEXNAME'
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'init_options' do
|
30
|
+
it 'sets options and config' do
|
31
|
+
# Given
|
32
|
+
args = nil
|
33
|
+
|
34
|
+
# When
|
35
|
+
push.init_options(args, options, config)
|
36
|
+
|
37
|
+
# Then
|
38
|
+
expect(push.options).to include(options)
|
39
|
+
expect(push.config).to include(config)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'sets indexname from the commandline' do
|
43
|
+
# Given
|
44
|
+
args = ['newindex']
|
45
|
+
|
46
|
+
# When
|
47
|
+
push.init_options(args, options, config)
|
48
|
+
|
49
|
+
# Then
|
50
|
+
expect(push.config['algolia']['index_name']).to eq 'newindex'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'indexable?' do
|
55
|
+
before(:each) do
|
56
|
+
push.init_options(nil, options, config)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'exclude StaticFiles' do
|
60
|
+
expect(push.indexable?(static_file)).to eq false
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'keeps markdown files' do
|
64
|
+
expect(push.indexable?(page_file)).to eq true
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'keeps html files' do
|
68
|
+
expect(push.indexable?(html_page_file)).to eq true
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'keeps markdown documents' do
|
72
|
+
expect(push.indexable?(document_file)).to eq true
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'keeps html documents' do
|
76
|
+
expect(push.indexable?(html_document_file)).to eq true
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'exclude file specified in config' do
|
80
|
+
# Given
|
81
|
+
config['algolia']['excluded_files'] = [
|
82
|
+
'excluded.html'
|
83
|
+
]
|
84
|
+
push.init_options(nil, options, config)
|
85
|
+
|
86
|
+
# Then
|
87
|
+
expect(push.indexable?(excluded_page_file)).to eq false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'api_key' do
|
92
|
+
it 'returns nil if no key found' do
|
93
|
+
# Given
|
94
|
+
push.init_options(nil, options, config)
|
95
|
+
|
96
|
+
# When
|
97
|
+
expect(push.api_key).to be_nil
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'reads from ENV var if set' do
|
101
|
+
# Given
|
102
|
+
push.init_options(nil, options, config)
|
103
|
+
stub_const('ENV', 'ALGOLIA_API_KEY' => 'APIKEY_FROM_ENV')
|
104
|
+
|
105
|
+
# When
|
106
|
+
actual = push.api_key
|
107
|
+
|
108
|
+
# Then
|
109
|
+
expect(actual).to eq 'APIKEY_FROM_ENV'
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'reads from _algolia_api_key in source if set' do
|
113
|
+
# Given
|
114
|
+
config['source'] = File.join(config['source'], 'api_key_dir')
|
115
|
+
push.init_options(nil, options, config)
|
116
|
+
|
117
|
+
# When
|
118
|
+
actual = push.api_key
|
119
|
+
|
120
|
+
# Then
|
121
|
+
expect(actual).to eq 'APIKEY_FROM_FILE'
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'reads from ENV before from file' do
|
125
|
+
# Given
|
126
|
+
config['source'] = File.join(config['source'], 'api_key_dir')
|
127
|
+
stub_const('ENV', 'ALGOLIA_API_KEY' => 'APIKEY_FROM_ENV')
|
128
|
+
push.init_options(nil, options, config)
|
129
|
+
|
130
|
+
# When
|
131
|
+
actual = push.api_key
|
132
|
+
|
133
|
+
# Then
|
134
|
+
expect(actual).to eq 'APIKEY_FROM_ENV'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe 'check_credentials' do
|
139
|
+
it 'should display error if no api key' do
|
140
|
+
# Given
|
141
|
+
config['algolia'] = {
|
142
|
+
'application_id' => 'APP_ID',
|
143
|
+
'index_name' => 'INDEX_NAME'
|
144
|
+
}
|
145
|
+
push.init_options(nil, options, config)
|
146
|
+
|
147
|
+
# Then
|
148
|
+
expect(Jekyll.logger).to receive(:error).with(/api key/i)
|
149
|
+
expect(Jekyll.logger).to receive(:warn).at_least(:once)
|
150
|
+
expect(-> { push.check_credentials }).to raise_error SystemExit
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should display error if no application id' do
|
154
|
+
# Given
|
155
|
+
config['algolia'] = {
|
156
|
+
'application_id' => nil,
|
157
|
+
'index_name' => 'INDEX_NAME'
|
158
|
+
}
|
159
|
+
stub_const('ENV', 'ALGOLIA_API_KEY' => 'APIKEY_FROM_ENV')
|
160
|
+
push.init_options(nil, options, config)
|
161
|
+
|
162
|
+
# Then
|
163
|
+
expect(Jekyll.logger).to receive(:error).with(/application id/i)
|
164
|
+
expect(Jekyll.logger).to receive(:warn).at_least(:once)
|
165
|
+
expect(-> { push.check_credentials }).to raise_error SystemExit
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'should display error if no index name' do
|
169
|
+
# Given
|
170
|
+
config['algolia'] = {
|
171
|
+
'application_id' => 'APPLICATION_ID',
|
172
|
+
'index_name' => nil
|
173
|
+
}
|
174
|
+
stub_const('ENV', 'ALGOLIA_API_KEY' => 'APIKEY_FROM_ENV')
|
175
|
+
push.init_options(nil, options, config)
|
176
|
+
|
177
|
+
# Then
|
178
|
+
expect(Jekyll.logger).to receive(:error).with(/index name/i)
|
179
|
+
expect(Jekyll.logger).to receive(:warn).at_least(:once)
|
180
|
+
expect(-> { push.check_credentials }).to raise_error SystemExit
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe 'configure_index' do
|
185
|
+
it 'sets some sane defaults' do
|
186
|
+
# Given
|
187
|
+
push.init_options(nil, options, config)
|
188
|
+
index = double
|
189
|
+
|
190
|
+
# Then
|
191
|
+
expected = {
|
192
|
+
attributeForDistinct: 'title',
|
193
|
+
distinct: true,
|
194
|
+
customRanking: ['desc(posted_at)', 'desc(weight)']
|
195
|
+
}
|
196
|
+
expect(index).to receive(:set_settings).with(hash_including(expected))
|
197
|
+
|
198
|
+
# When
|
199
|
+
push.configure_index(index)
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'allow user to override all settings' do
|
203
|
+
# Given
|
204
|
+
settings = {
|
205
|
+
distinct: false,
|
206
|
+
customSetting: 'foo',
|
207
|
+
customRanking: ['asc(foo)', 'desc(bar)']
|
208
|
+
}
|
209
|
+
config['algolia']['settings'] = settings
|
210
|
+
push.init_options(nil, options, config)
|
211
|
+
index = double
|
212
|
+
|
213
|
+
# Then
|
214
|
+
expect(index).to receive(:set_settings).with(hash_including(settings))
|
215
|
+
|
216
|
+
# When
|
217
|
+
push.configure_index(index)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,451 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe(AlgoliaSearchRecordExtractor) do
|
4
|
+
let(:extractor) { AlgoliaSearchRecordExtractor }
|
5
|
+
let(:site) { get_site }
|
6
|
+
let(:page_file) { extractor.new(site.file_by_name('about.md')) }
|
7
|
+
let(:html_page_file) { extractor.new(site.file_by_name('authors.html')) }
|
8
|
+
let(:post_file) { extractor.new(site.file_by_name('test-post.md')) }
|
9
|
+
let(:hierarchy_page_file) { extractor.new(site.file_by_name('hierarchy.md')) }
|
10
|
+
let(:weight_page_file) { extractor.new(site.file_by_name('weight.md')) }
|
11
|
+
let(:document_file) { extractor.new(site.file_by_name('collection-item.md')) }
|
12
|
+
|
13
|
+
describe 'metadata' do
|
14
|
+
it 'gets metadata from page' do
|
15
|
+
# Given
|
16
|
+
actual = page_file.metadata
|
17
|
+
|
18
|
+
# Then
|
19
|
+
expect(actual[:type]).to eq 'page'
|
20
|
+
expect(actual[:slug]).to eq 'about'
|
21
|
+
expect(actual[:title]).to eq 'About page'
|
22
|
+
expect(actual[:url]).to eq '/about.html'
|
23
|
+
expect(actual[:custom]).to eq 'Foo'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'gets metadata from post' do
|
27
|
+
# Given
|
28
|
+
actual = post_file.metadata
|
29
|
+
|
30
|
+
# Then
|
31
|
+
expect(actual[:type]).to eq 'post'
|
32
|
+
expect(actual[:slug]).to eq 'test-post'
|
33
|
+
expect(actual[:title]).to eq 'Test post'
|
34
|
+
expect(actual[:url]).to eq '/2015/07/02/test-post.html'
|
35
|
+
expect(actual[:posted_at]).to eq 1_435_788_000
|
36
|
+
expect(actual[:custom]).to eq 'Foo'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'gets metadata from document' do
|
40
|
+
# Given
|
41
|
+
actual = document_file.metadata
|
42
|
+
|
43
|
+
# Then
|
44
|
+
expect(actual[:type]).to eq 'document'
|
45
|
+
expect(actual[:slug]).to eq 'collection-item'
|
46
|
+
expect(actual[:title]).to eq 'Collection Item'
|
47
|
+
expect(actual[:url]).to eq '/my-collection/collection-item.html'
|
48
|
+
expect(actual[:custom]).to eq 'Foo'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'tags' do
|
53
|
+
it 'returns nil if no tag found' do
|
54
|
+
expect(page_file.tags).to eq nil
|
55
|
+
end
|
56
|
+
it 'extract tags from front matter' do
|
57
|
+
# Given
|
58
|
+
actual = post_file.tags
|
59
|
+
|
60
|
+
# Then
|
61
|
+
expect(actual).to include('tag', 'another tag')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'html_nodes' do
|
66
|
+
it 'returns the list of all <p> by default' do
|
67
|
+
expect(page_file.html_nodes.size).to eq 6
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'allow _config.yml to override the selector' do
|
71
|
+
# Given
|
72
|
+
site = get_site(algolia: { 'record_css_selector' => 'p,ul' })
|
73
|
+
page_file = extractor.new(site.file_by_name('about.md'))
|
74
|
+
|
75
|
+
expect(page_file.html_nodes.size).to eq 7
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'node_heading_parent' do
|
80
|
+
it 'returns the direct heading right above' do
|
81
|
+
# Given
|
82
|
+
nodes = hierarchy_page_file.html_nodes
|
83
|
+
p = nodes[0]
|
84
|
+
|
85
|
+
# When
|
86
|
+
actual = hierarchy_page_file.node_heading_parent(p)
|
87
|
+
|
88
|
+
# Then
|
89
|
+
expect(actual.name).to eq 'h1'
|
90
|
+
expect(actual.text).to eq 'H1'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns the closest heading even if in a sub tag' do
|
94
|
+
# Given
|
95
|
+
nodes = hierarchy_page_file.html_nodes
|
96
|
+
p = nodes[2]
|
97
|
+
|
98
|
+
# When
|
99
|
+
actual = hierarchy_page_file.node_heading_parent(p)
|
100
|
+
|
101
|
+
# Then
|
102
|
+
expect(actual.name).to eq 'h2'
|
103
|
+
expect(actual.text).to eq 'H2A'
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should automatically go up one level when indexing headings' do
|
107
|
+
# Given
|
108
|
+
site = get_site(algolia: { 'record_css_selector' => 'p,h2' })
|
109
|
+
hierarchy_page_file = extractor.new(site.file_by_name('hierarchy.md'))
|
110
|
+
nodes = hierarchy_page_file.html_nodes
|
111
|
+
h2 = nodes[4]
|
112
|
+
|
113
|
+
# When
|
114
|
+
actual = hierarchy_page_file.node_heading_parent(h2)
|
115
|
+
|
116
|
+
# Then
|
117
|
+
expect(actual.name).to eq 'h1'
|
118
|
+
expect(actual.text).to eq 'H1'
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should find the correct parent when indexing deep headings' do
|
122
|
+
# Given
|
123
|
+
site = get_site(algolia: { 'record_css_selector' => 'h2' })
|
124
|
+
hierarchy_page_file = extractor.new(site.file_by_name('hierarchy.md'))
|
125
|
+
nodes = hierarchy_page_file.html_nodes
|
126
|
+
h2 = nodes[2]
|
127
|
+
|
128
|
+
# When
|
129
|
+
actual = hierarchy_page_file.node_heading_parent(h2)
|
130
|
+
|
131
|
+
# Then
|
132
|
+
expect(actual.name).to eq 'h1'
|
133
|
+
expect(actual.text).to eq 'H1'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe 'node_hierarchy' do
|
138
|
+
it 'returns the unique parent of a simple element' do
|
139
|
+
# Note: First <p> should only have a h1 as hierarchy
|
140
|
+
# Given
|
141
|
+
nodes = hierarchy_page_file.html_nodes
|
142
|
+
p = nodes[0]
|
143
|
+
|
144
|
+
# When
|
145
|
+
actual = hierarchy_page_file.node_hierarchy(p)
|
146
|
+
|
147
|
+
# Then
|
148
|
+
expect(actual).to include(h1: 'H1')
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'returns the heading hierarchy of multiple headings' do
|
152
|
+
# Note: 5th <p> is inside h3, second h2 and main h1
|
153
|
+
# Given
|
154
|
+
nodes = hierarchy_page_file.html_nodes
|
155
|
+
p = nodes[4]
|
156
|
+
|
157
|
+
# When
|
158
|
+
actual = hierarchy_page_file.node_hierarchy(p)
|
159
|
+
|
160
|
+
# Then
|
161
|
+
expect(actual).to include(h1: 'H1', h2: 'H2B', h3: 'H3A')
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'works even if heading not on the same level' do
|
165
|
+
# Note: The 6th <p> is inside a div
|
166
|
+
# Given
|
167
|
+
nodes = hierarchy_page_file.html_nodes
|
168
|
+
p = nodes[5]
|
169
|
+
|
170
|
+
# When
|
171
|
+
actual = hierarchy_page_file.node_hierarchy(p)
|
172
|
+
|
173
|
+
# Then
|
174
|
+
expect(actual).to include(h1: 'H1', h2: 'H2B', h3: 'H3A', h4: 'H4')
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'includes node in the output if headings are indexed' do
|
178
|
+
# Given
|
179
|
+
site = get_site(algolia: { 'record_css_selector' => 'h1' })
|
180
|
+
hierarchy_page_file = extractor.new(site.file_by_name('hierarchy.md'))
|
181
|
+
nodes = hierarchy_page_file.html_nodes
|
182
|
+
h1 = nodes[0]
|
183
|
+
|
184
|
+
# When
|
185
|
+
actual = hierarchy_page_file.node_hierarchy(h1)
|
186
|
+
|
187
|
+
# Then
|
188
|
+
expect(actual).to include(h1: 'H1')
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'escape html in headings' do
|
192
|
+
# Given
|
193
|
+
nodes = hierarchy_page_file.html_nodes
|
194
|
+
p = nodes[7]
|
195
|
+
|
196
|
+
# When
|
197
|
+
actual = hierarchy_page_file.node_hierarchy(p)
|
198
|
+
|
199
|
+
# Then
|
200
|
+
expect(actual).to include(h3: 'H3B <code>')
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe 'node_raw_html' do
|
205
|
+
it 'returns html including surrounding tags' do
|
206
|
+
# Note: 3rd <p> is a real HTML with a custom class
|
207
|
+
# Given
|
208
|
+
nodes = page_file.html_nodes
|
209
|
+
p = nodes[3]
|
210
|
+
|
211
|
+
# When
|
212
|
+
actual = page_file.node_raw_html(p)
|
213
|
+
|
214
|
+
# Then
|
215
|
+
expect(actual).to eq '<p id="text4">Another text 4</p>'
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe 'node_text' do
|
220
|
+
it 'returns inner text with <> escaped' do
|
221
|
+
# Note: 4th <p> contains a <code> tag with <>
|
222
|
+
# Given
|
223
|
+
nodes = page_file.html_nodes
|
224
|
+
p = nodes[4]
|
225
|
+
|
226
|
+
# When
|
227
|
+
actual = page_file.node_text(p)
|
228
|
+
|
229
|
+
# Then
|
230
|
+
expect(actual).to eq 'Another <text> 5'
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
describe 'unique_hierarchy' do
|
235
|
+
it 'combines title and headings' do
|
236
|
+
# Given
|
237
|
+
hierarchy = {
|
238
|
+
title: 'title',
|
239
|
+
h1: 'h1',
|
240
|
+
h2: 'h2',
|
241
|
+
h3: 'h3',
|
242
|
+
h4: 'h4',
|
243
|
+
h5: 'h5',
|
244
|
+
h6: 'h6'
|
245
|
+
}
|
246
|
+
|
247
|
+
# When
|
248
|
+
actual = page_file.unique_hierarchy(hierarchy)
|
249
|
+
|
250
|
+
# Then
|
251
|
+
expect(actual).to eq 'title > h1 > h2 > h3 > h4 > h5 > h6'
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'combines title and headings even with missing elements' do
|
255
|
+
# Given
|
256
|
+
hierarchy = {
|
257
|
+
title: 'title',
|
258
|
+
h2: 'h2',
|
259
|
+
h4: 'h4',
|
260
|
+
h6: 'h6'
|
261
|
+
}
|
262
|
+
|
263
|
+
# When
|
264
|
+
actual = page_file.unique_hierarchy(hierarchy)
|
265
|
+
|
266
|
+
# Then
|
267
|
+
expect(actual).to eq 'title > h2 > h4 > h6'
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe 'node_css_selector' do
|
272
|
+
it 'uses the #id to make the selector more precise if one is found' do
|
273
|
+
# Given
|
274
|
+
nodes = page_file.html_nodes
|
275
|
+
p = nodes[3]
|
276
|
+
|
277
|
+
# When
|
278
|
+
actual = page_file.node_css_selector(p)
|
279
|
+
|
280
|
+
# Then
|
281
|
+
expect(actual).to eq '#text4'
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'uses p:nth-of-type if no #id found' do
|
285
|
+
# Given
|
286
|
+
nodes = page_file.html_nodes
|
287
|
+
p = nodes[2]
|
288
|
+
|
289
|
+
# When
|
290
|
+
actual = page_file.node_css_selector(p)
|
291
|
+
|
292
|
+
# Then
|
293
|
+
expect(actual).to eq 'p:nth-of-type(3)'
|
294
|
+
end
|
295
|
+
|
296
|
+
it 'handles custom <div> markup' do
|
297
|
+
# Given
|
298
|
+
nodes = page_file.html_nodes
|
299
|
+
p = nodes[5]
|
300
|
+
|
301
|
+
# When
|
302
|
+
actual = page_file.node_css_selector(p)
|
303
|
+
|
304
|
+
# Then
|
305
|
+
expect(actual).to eq 'div:nth-of-type(2) > p'
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
describe 'weight' do
|
310
|
+
it 'gets the number of words in text also in the title' do
|
311
|
+
# Given
|
312
|
+
data = {
|
313
|
+
title: 'foo bar',
|
314
|
+
text: 'Lorem ipsum dolor foo bar, consectetur adipiscing elit'
|
315
|
+
}
|
316
|
+
|
317
|
+
# When
|
318
|
+
actual = page_file.weight(data)
|
319
|
+
|
320
|
+
# Then
|
321
|
+
expect(actual).to eq 2
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'gets the number of words in text also in the headings' do
|
325
|
+
# Given
|
326
|
+
data = {
|
327
|
+
title: 'foo',
|
328
|
+
h1: 'bar',
|
329
|
+
h2: 'baz',
|
330
|
+
text: 'Lorem baz dolor foo bar, consectetur adipiscing elit'
|
331
|
+
}
|
332
|
+
|
333
|
+
# When
|
334
|
+
actual = page_file.weight(data)
|
335
|
+
|
336
|
+
# Then
|
337
|
+
expect(actual).to eq 3
|
338
|
+
end
|
339
|
+
|
340
|
+
it 'count each word only once' do
|
341
|
+
# Given
|
342
|
+
data = {
|
343
|
+
title: 'foo',
|
344
|
+
h1: 'foo foo foo',
|
345
|
+
h2: 'bar bar foo bar',
|
346
|
+
text: 'foo bar bar bar bar baz foo bar baz'
|
347
|
+
}
|
348
|
+
|
349
|
+
# When
|
350
|
+
actual = page_file.weight(data)
|
351
|
+
|
352
|
+
# Then
|
353
|
+
expect(actual).to eq 2
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'is case-insensitive' do
|
357
|
+
# Given
|
358
|
+
data = {
|
359
|
+
title: 'FOO',
|
360
|
+
h1: 'bar Bar BAR',
|
361
|
+
text: 'foo BAR'
|
362
|
+
}
|
363
|
+
|
364
|
+
# When
|
365
|
+
actual = page_file.weight(data)
|
366
|
+
|
367
|
+
# Then
|
368
|
+
expect(actual).to eq 2
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'should only use words, no partial matches' do
|
372
|
+
# Given
|
373
|
+
data = {
|
374
|
+
title: 'foo bar',
|
375
|
+
text: 'xxxfooxxx bar'
|
376
|
+
}
|
377
|
+
|
378
|
+
# When
|
379
|
+
actual = page_file.weight(data)
|
380
|
+
|
381
|
+
# Then
|
382
|
+
expect(actual).to eq 1
|
383
|
+
|
384
|
+
# I don't seem fit for that
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'should still work with non-string keys' do
|
388
|
+
# Given
|
389
|
+
data = {
|
390
|
+
title: nil,
|
391
|
+
h1: [],
|
392
|
+
h2: {},
|
393
|
+
h3: true,
|
394
|
+
h4: false,
|
395
|
+
h5: 'foo bar',
|
396
|
+
text: 'foo bar'
|
397
|
+
}
|
398
|
+
|
399
|
+
# When
|
400
|
+
actual = page_file.weight(data)
|
401
|
+
|
402
|
+
# Then
|
403
|
+
expect(actual).to eq 2
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
describe 'custom_hook_each' do
|
408
|
+
it 'let the user call a custom hook to modify a record' do
|
409
|
+
# Given
|
410
|
+
def page_file.custom_hook_each(item, _)
|
411
|
+
item[:custom_attribute] = 'foo'
|
412
|
+
item
|
413
|
+
end
|
414
|
+
|
415
|
+
# When
|
416
|
+
actual = page_file.extract
|
417
|
+
|
418
|
+
# Then
|
419
|
+
expect(actual[0]).to include(custom_attribute: 'foo')
|
420
|
+
end
|
421
|
+
|
422
|
+
it 'let the user discard a record by returning nil' do
|
423
|
+
# Given
|
424
|
+
def page_file.custom_hook_each(_, _)
|
425
|
+
nil
|
426
|
+
end
|
427
|
+
|
428
|
+
# When
|
429
|
+
actual = page_file.extract
|
430
|
+
|
431
|
+
# Then
|
432
|
+
expect(actual.size).to eq 0
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
describe 'custom_hook_all' do
|
437
|
+
it 'let the user call a custom hook to modify the list of records' do
|
438
|
+
# Given
|
439
|
+
def page_file.custom_hook_all(items)
|
440
|
+
[items[0], { foo: 'bar' }]
|
441
|
+
end
|
442
|
+
|
443
|
+
# When
|
444
|
+
actual = page_file.extract
|
445
|
+
|
446
|
+
# Then
|
447
|
+
expect(actual.size).to eq 2
|
448
|
+
expect(actual[1]).to include(foo: 'bar')
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'awesome_print'
|
2
|
+
require_relative './spec_helper_jekyll.rb'
|
3
|
+
require_relative './spec_helper_simplecov.rb'
|
4
|
+
require './lib/push.rb'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.filter_run(focus: true)
|
8
|
+
config.run_all_when_everything_filtered = true
|
9
|
+
|
10
|
+
# Build a jekyll site, creating access to @__files used internally
|
11
|
+
def get_site(config = {})
|
12
|
+
config = config.merge(
|
13
|
+
source: File.expand_path('./spec/fixtures')
|
14
|
+
)
|
15
|
+
config = Jekyll.configuration(config)
|
16
|
+
site = Jekyll::Site.new(config)
|
17
|
+
|
18
|
+
# Keep a list of all files
|
19
|
+
def site.write
|
20
|
+
@__files = {}
|
21
|
+
each_site_file do |file|
|
22
|
+
@__files[file.path] = file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def site.file_by_name(file_name)
|
27
|
+
@__files.find { |path, _| path =~ /#{file_name}$/ }[1]
|
28
|
+
end
|
29
|
+
|
30
|
+
site.process
|
31
|
+
site
|
32
|
+
end
|
33
|
+
end
|