nesta 0.11.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitmodules +6 -0
- data/.travis.yml +9 -4
- data/CHANGES +18 -2
- data/Gemfile +1 -1
- data/Gemfile.lock +70 -54
- data/LICENSE +1 -1
- data/RELEASING.md +5 -6
- data/Rakefile +20 -3
- data/lib/nesta/app.rb +4 -8
- data/lib/nesta/commands/command.rb +1 -2
- data/lib/nesta/commands/demo/content.rb +23 -5
- data/lib/nesta/commands/theme/install.rb +9 -7
- data/lib/nesta/helpers.rb +14 -0
- data/lib/nesta/models.rb +26 -22
- data/lib/nesta/navigation.rb +1 -1
- data/lib/nesta/version.rb +1 -1
- data/nesta.gemspec +10 -11
- data/templates/config/config.yml +1 -1
- data/{spec → test}/fixtures/nesta-plugin-test/Gemfile +0 -0
- data/{spec → test}/fixtures/nesta-plugin-test/Rakefile +0 -0
- data/{spec → test}/fixtures/nesta-plugin-test/lib/nesta-plugin-test.rb +0 -0
- data/{spec → test}/fixtures/nesta-plugin-test/lib/nesta-plugin-test/init.rb +0 -0
- data/{spec → test}/fixtures/nesta-plugin-test/lib/nesta-plugin-test/version.rb +0 -0
- data/{spec → test}/fixtures/nesta-plugin-test/nesta-plugin-test.gemspec +0 -0
- data/test/integration/atom_feed_test.rb +178 -0
- data/test/integration/commands/demo/content_test.rb +31 -0
- data/test/integration/commands/edit_test.rb +21 -0
- data/test/integration/commands/new_test.rb +120 -0
- data/test/integration/commands/plugin/create_test.rb +128 -0
- data/test/integration/commands/theme/create_test.rb +35 -0
- data/test/integration/commands/theme/enable_test.rb +22 -0
- data/test/integration/commands/theme/install_test.rb +62 -0
- data/test/integration/default_theme_test.rb +220 -0
- data/test/integration/overrides_test.rb +118 -0
- data/test/integration/route_handlers_test.rb +96 -0
- data/test/integration/sitemap_test.rb +85 -0
- data/test/integration_test_helper.rb +61 -0
- data/test/support/model_factory.rb +169 -0
- data/test/support/silence_commands_during_tests.rb +5 -0
- data/test/support/temporary_files.rb +33 -0
- data/test/support/test_configuration.rb +19 -0
- data/test/test_helper.rb +26 -0
- data/test/unit/commands_test.rb +23 -0
- data/test/unit/config_test.rb +138 -0
- data/test/unit/file_model_test.rb +71 -0
- data/test/unit/menu_test.rb +82 -0
- data/test/unit/page_test.rb +571 -0
- data/test/unit/path_test.rb +41 -0
- data/test/unit/plugin_test.rb +47 -0
- data/views/master.sass +1 -1
- metadata +81 -85
- data/smoke-test.sh +0 -107
- data/spec/atom_spec.rb +0 -141
- data/spec/commands/demo/content_spec.rb +0 -65
- data/spec/commands/edit_spec.rb +0 -27
- data/spec/commands/new_spec.rb +0 -88
- data/spec/commands/plugin/create_spec.rb +0 -97
- data/spec/commands/system_spec.rb +0 -25
- data/spec/commands/theme/create_spec.rb +0 -41
- data/spec/commands/theme/enable_spec.rb +0 -44
- data/spec/commands/theme/install_spec.rb +0 -56
- data/spec/config_spec.rb +0 -127
- data/spec/model_factory.rb +0 -92
- data/spec/models_spec.rb +0 -700
- data/spec/overrides_spec.rb +0 -132
- data/spec/page_spec.rb +0 -560
- data/spec/path_spec.rb +0 -28
- data/spec/plugin_spec.rb +0 -51
- data/spec/sitemap_spec.rb +0 -105
- data/spec/spec_helper.rb +0 -114
@@ -0,0 +1,19 @@
|
|
1
|
+
module TestConfiguration
|
2
|
+
include TemporaryFiles
|
3
|
+
|
4
|
+
def stub_config(config, &block)
|
5
|
+
Nesta::Config.stub(:yaml_exists?, true) do
|
6
|
+
Nesta::Config.stub(:yaml_conf, config) do
|
7
|
+
yield
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def temp_content
|
13
|
+
{ 'content' => temp_path('content') }
|
14
|
+
end
|
15
|
+
|
16
|
+
def with_temp_content_directory(&block)
|
17
|
+
stub_config(temp_content) { yield }
|
18
|
+
end
|
19
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
require 'minitest/reporters'
|
5
|
+
|
6
|
+
reporter_setting = ENV.fetch('REPORTER', 'progress')
|
7
|
+
camel_case = reporter_setting.split(/_/).map { |word| word.capitalize }.join('')
|
8
|
+
Minitest::Reporters.use! Minitest::Reporters.const_get("#{camel_case}Reporter").new
|
9
|
+
|
10
|
+
require File.expand_path('../lib/nesta/env', File.dirname(__FILE__))
|
11
|
+
require File.expand_path('../lib/nesta/app', File.dirname(__FILE__))
|
12
|
+
|
13
|
+
require_relative 'support/model_factory'
|
14
|
+
require_relative 'support/temporary_files'
|
15
|
+
require_relative 'support/test_configuration'
|
16
|
+
|
17
|
+
Nesta::App.environment = 'test'
|
18
|
+
|
19
|
+
class Minitest::Test
|
20
|
+
def with_app_root(path, &block)
|
21
|
+
original, Nesta::App.root = Nesta::App.root, path
|
22
|
+
yield
|
23
|
+
ensure
|
24
|
+
Nesta::App.root = original
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require_relative '../../lib/nesta/commands'
|
3
|
+
|
4
|
+
class TestCommand
|
5
|
+
include Nesta::Commands::Command
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'Nesta::Commands::Command' do
|
9
|
+
describe '#run_process' do
|
10
|
+
it 'catches errors when running external processes' do
|
11
|
+
TestCommand.new.run_process('ls / >/dev/null')
|
12
|
+
begin
|
13
|
+
stderr, $stderr = $stderr, File.open('/dev/null', 'w')
|
14
|
+
assert_raises(SystemExit) do
|
15
|
+
TestCommand.new.run_process('ls no-such-file 2>/dev/null')
|
16
|
+
end
|
17
|
+
ensure
|
18
|
+
$stderr.close
|
19
|
+
$stderr = stderr
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Nesta::Config do
|
4
|
+
include TestConfiguration
|
5
|
+
|
6
|
+
after do
|
7
|
+
ENV.keys.each { |variable| ENV.delete(variable) if variable =~ /NESTA_/ }
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'returns default value for "Read more"' do
|
11
|
+
assert_equal 'Continue reading', Nesta::Config.read_more
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns nil for author when not defined' do
|
15
|
+
assert_nil Nesta::Config.author
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'when settings defined in ENV' do
|
19
|
+
before do
|
20
|
+
@title = 'Title from ENV'
|
21
|
+
ENV['NESTA_TITLE'] = @title
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'falls back to config.yml' do
|
25
|
+
stub_config('subtitle' => 'Subtitle in YAML file') do
|
26
|
+
assert_equal 'Subtitle in YAML file', Nesta::Config.subtitle
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'overrides config.yml' do
|
31
|
+
stub_config('title' => 'Title in YAML file') do
|
32
|
+
assert_equal @title, Nesta::Config.title
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'knows how to cope with boolean values' do
|
37
|
+
Nesta::Config.settings << 'a_boolean'
|
38
|
+
begin
|
39
|
+
ENV['NESTA_A_BOOLEAN'] = 'true'
|
40
|
+
assert_equal true, Nesta::Config.a_boolean, 'should be true'
|
41
|
+
ENV['NESTA_A_BOOLEAN'] = 'false'
|
42
|
+
assert_equal false, Nesta::Config.a_boolean, 'should be false'
|
43
|
+
ensure
|
44
|
+
Nesta::Config.settings.pop
|
45
|
+
ENV.delete('NESTA_A_BOOLEAN')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should return configured value for "Read more"' do
|
50
|
+
ENV['NESTA_READ_MORE'] = 'Read on'
|
51
|
+
begin
|
52
|
+
assert_equal 'Read on', Nesta::Config.read_more
|
53
|
+
ensure
|
54
|
+
ENV.delete('NESTA_READ_MORE')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'sets author hash from ENV' do
|
59
|
+
name = 'Name from ENV'
|
60
|
+
uri = 'URI from ENV'
|
61
|
+
ENV['NESTA_AUTHOR__NAME'] = name
|
62
|
+
ENV['NESTA_AUTHOR__URI'] = uri
|
63
|
+
assert_equal name, Nesta::Config.author['name']
|
64
|
+
assert_equal uri, Nesta::Config.author['uri']
|
65
|
+
assert Nesta::Config.author['email'].nil?, 'should be nil'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'when settings only defined in config.yml' do
|
70
|
+
before do
|
71
|
+
@title = 'Title in YAML file'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'reads configuration from YAML' do
|
75
|
+
stub_config('subtitle' => @title) do
|
76
|
+
assert_equal @title, Nesta::Config.subtitle
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'sets author hash from YAML' do
|
81
|
+
name = 'Name from YAML'
|
82
|
+
uri = 'URI from YAML'
|
83
|
+
stub_config('author' => { 'name' => name, 'uri' => uri }) do
|
84
|
+
assert_equal name, Nesta::Config.author['name']
|
85
|
+
assert_equal uri, Nesta::Config.author['uri']
|
86
|
+
assert Nesta::Config.author['email'].nil?, 'should be nil'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'overrides top level settings with environment specific settings' do
|
91
|
+
config = {
|
92
|
+
'content' => 'general/path',
|
93
|
+
'test' => { 'content' => 'rack_env_specific/path' }
|
94
|
+
}
|
95
|
+
stub_config(config) do
|
96
|
+
assert_equal 'rack_env_specific/path', Nesta::Config.content
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'Nesta::Config.fetch' do
|
102
|
+
it 'retrieves settings from environment' do
|
103
|
+
ENV['NESTA_MY_SETTING'] = 'value in ENV'
|
104
|
+
begin
|
105
|
+
assert_equal 'value in ENV', Nesta::Config.fetch('my_setting')
|
106
|
+
assert_equal 'value in ENV', Nesta::Config.fetch(:my_setting)
|
107
|
+
ensure
|
108
|
+
ENV.delete('NESTA_MY_SETTING')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'retrieves settings from YAML' do
|
113
|
+
stub_config('my_setting' => 'value in YAML') do
|
114
|
+
assert_equal 'value in YAML', Nesta::Config.fetch('my_setting')
|
115
|
+
assert_equal 'value in YAML', Nesta::Config.fetch(:my_setting)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it "throws NotDefined if a setting isn't defined" do
|
120
|
+
assert_raises(Nesta::Config::NotDefined) do
|
121
|
+
Nesta::Config.fetch('no such setting')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'allows default values to be set' do
|
126
|
+
assert_equal 'default', Nesta::Config.fetch('no such setting', 'default')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'copes with non-truthy boolean values' do
|
130
|
+
ENV['NESTA_SETTING'] = 'false'
|
131
|
+
begin
|
132
|
+
assert_equal false, Nesta::Config.fetch('setting')
|
133
|
+
ensure
|
134
|
+
ENV.delete('NESTA_SETTING')
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Nesta::FileModel do
|
4
|
+
include ModelFactory
|
5
|
+
include TestConfiguration
|
6
|
+
|
7
|
+
after do
|
8
|
+
Nesta::FileModel.purge_cache
|
9
|
+
remove_temp_directory
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'can find all files of this type' do
|
13
|
+
with_temp_content_directory do
|
14
|
+
model = create(:file_model)
|
15
|
+
assert_equal [model], Nesta::FileModel.find_all
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '.find_file_for_path' do
|
20
|
+
it 'returns filename for path' do
|
21
|
+
with_temp_content_directory do
|
22
|
+
model = create(:file_model)
|
23
|
+
filename = Nesta::FileModel.find_file_for_path(model.path)
|
24
|
+
assert_equal filename, model.filename
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns nil if file not found' do
|
29
|
+
with_temp_content_directory do
|
30
|
+
assert_nil Nesta::FileModel.find_file_for_path('foobar')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'can parse metadata at top of a file' do
|
36
|
+
with_temp_content_directory do
|
37
|
+
model = create(:file_model)
|
38
|
+
metadata = model.parse_metadata('My key: some value')
|
39
|
+
assert_equal 'some value', metadata['my key']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "doesn't break loading pages with badly formatted metadata" do
|
44
|
+
with_temp_content_directory do
|
45
|
+
dodgy_metadata = "Key: value\nKey without value\nAnother key: value"
|
46
|
+
page = create(:page) do |path|
|
47
|
+
text = File.read(path)
|
48
|
+
File.open(path, 'w') do |file|
|
49
|
+
file.puts(dodgy_metadata)
|
50
|
+
file.write(text)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
Nesta::Page.find_by_path(page.path)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'invalidates cached models when files are modified' do
|
58
|
+
with_temp_content_directory do
|
59
|
+
create(:file_model, path: 'a-page', metadata: { 'Version' => '1' })
|
60
|
+
now = Time.now
|
61
|
+
File.stub(:mtime, now - 1) do
|
62
|
+
Nesta::FileModel.load('a-page')
|
63
|
+
end
|
64
|
+
create(:file_model, path: 'a-page', metadata: { 'Version' => '2' })
|
65
|
+
model = File.stub(:mtime, now) do
|
66
|
+
Nesta::FileModel.load('a-page')
|
67
|
+
end
|
68
|
+
assert_equal '2', model.metadata('version')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Nesta::Menu do
|
4
|
+
include ModelFactory
|
5
|
+
include TestConfiguration
|
6
|
+
|
7
|
+
def with_page(&block)
|
8
|
+
with_temp_content_directory do
|
9
|
+
page = create(:page)
|
10
|
+
create_menu(page.path)
|
11
|
+
yield(page)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_hierarchy_of_pages(&block)
|
16
|
+
with_temp_content_directory do
|
17
|
+
pages = (1..6).map { |i| create(:page) }
|
18
|
+
text = <<-EOF
|
19
|
+
#{pages[0].path}
|
20
|
+
#{pages[1].path}
|
21
|
+
#{pages[2].path}
|
22
|
+
#{pages[3].path}
|
23
|
+
"no-such-page"
|
24
|
+
"another-missing-page"
|
25
|
+
#{pages[4].path}
|
26
|
+
#{pages[5].path}
|
27
|
+
EOF
|
28
|
+
create_menu(text)
|
29
|
+
yield(pages)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
after do
|
34
|
+
remove_temp_directory
|
35
|
+
Nesta::FileModel.purge_cache
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'retrieves Page objects for the menu' do
|
39
|
+
with_page do |page|
|
40
|
+
assert_equal [page], Nesta::Menu.full_menu
|
41
|
+
assert_equal [page], Nesta::Menu.for_path('/')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "filters pages that don't exist out of the menu" do
|
46
|
+
with_temp_content_directory do
|
47
|
+
page = create(:page)
|
48
|
+
text = ['no-such-page', page.path].join("\n")
|
49
|
+
create_menu(text)
|
50
|
+
assert_equal [page], Nesta::Menu.top_level
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'nested sub menus' do
|
55
|
+
it 'returns top level menu items' do
|
56
|
+
with_hierarchy_of_pages do |pages|
|
57
|
+
assert_equal [pages[0], pages[4]], Nesta::Menu.top_level
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns full tree of menu items' do
|
62
|
+
with_hierarchy_of_pages do |pages|
|
63
|
+
page1, page2, page3, page4, page5, page6 = pages
|
64
|
+
expected = [page1, [page2, [page3, page4]], page5, [page6]]
|
65
|
+
assert_equal expected, Nesta::Menu.full_menu
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'returns part of the tree of menu items' do
|
70
|
+
with_hierarchy_of_pages do |pages|
|
71
|
+
page1, page2, page3, page4, page5, page6 = pages
|
72
|
+
assert_equal [page2, [page3, page4]], Nesta::Menu.for_path(page2.path)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'deems menu for path not in menu to be nil' do
|
77
|
+
with_hierarchy_of_pages do
|
78
|
+
assert_nil Nesta::Menu.for_path('wibble')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,571 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Nesta::Page do
|
4
|
+
include ModelFactory
|
5
|
+
include TestConfiguration
|
6
|
+
|
7
|
+
after do
|
8
|
+
Nesta::FileModel.purge_cache
|
9
|
+
remove_temp_directory
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'raises error if instantiated for non existant file' do
|
13
|
+
with_temp_content_directory do
|
14
|
+
assert_raises(Sinatra::NotFound) do
|
15
|
+
Nesta::Page.new('no-such-file')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.find_by_path' do
|
21
|
+
it 'finds model instances by path' do
|
22
|
+
with_temp_content_directory do
|
23
|
+
page = create(:page)
|
24
|
+
assert_equal page.heading, Nesta::Page.find_by_path(page.path).heading
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'finds model for index page by path' do
|
29
|
+
with_temp_content_directory do
|
30
|
+
page = create(:page, path: 'path/index')
|
31
|
+
assert_equal page.heading, Nesta::Page.find_by_path('path').heading
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'finds model for home page when path is /' do
|
36
|
+
with_temp_content_directory do
|
37
|
+
create(:page, heading: 'Home', path: 'index')
|
38
|
+
assert_equal 'Home', Nesta::Page.find_by_path('/').title
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns nil if page not found' do
|
43
|
+
with_temp_content_directory do
|
44
|
+
assert_nil Nesta::Page.find_by_path('no-such-page')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns nil for draft pages when running in production'do
|
49
|
+
with_temp_content_directory do
|
50
|
+
draft = create(:page, metadata: { 'flags' => 'draft' })
|
51
|
+
assert Nesta::Page.find_by_path(draft.path), 'should find draft'
|
52
|
+
Nesta::App.stub(:production?, true) do
|
53
|
+
assert_nil Nesta::Page.find_by_path(draft.path)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '.find_articles 'do
|
60
|
+
it "doesn't return articles with a published date in the future" do
|
61
|
+
with_temp_content_directory do
|
62
|
+
future_date = (Time.now + 172800).strftime('%d %B %Y')
|
63
|
+
article = create(:article, metadata: { 'date' => future_date })
|
64
|
+
assert_nil Nesta::Page.find_articles.detect { |a| a == article }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "doesn't return pages without a date" do
|
69
|
+
with_temp_content_directory do
|
70
|
+
create(:category)
|
71
|
+
create(:article)
|
72
|
+
articles = Nesta::Page.find_articles
|
73
|
+
assert_equal 1, articles.size
|
74
|
+
articles.each { |page| fail 'not an article' if page.date.nil? }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns articles in reverse chronological order' do
|
79
|
+
with_temp_content_directory do
|
80
|
+
create(:article, metadata: { 'date' => '30 December 2008' })
|
81
|
+
create(:article, metadata: { 'date' => '31 December 2008' })
|
82
|
+
article1, article2 = Nesta::Page.find_articles[0..1]
|
83
|
+
assert article1.date > article2.date, 'not reverse chronological order'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#title' do
|
89
|
+
it 'returns page heading by default' do
|
90
|
+
with_temp_content_directory do
|
91
|
+
page = create(:page, heading: 'Heading')
|
92
|
+
assert_equal page.heading, Nesta::Page.find_by_path(page.path).title
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'overrides heading with title set in metadata' do
|
97
|
+
with_temp_content_directory do
|
98
|
+
page = create(:page, metadata: { 'title' => 'Specific title' })
|
99
|
+
assert_equal 'Specific title', Nesta::Page.find_by_path(page.path).title
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'defaults to site title for home page' do
|
104
|
+
stub_config(temp_content.merge('title' => 'Site title')) do
|
105
|
+
create(:page, heading: nil, path: 'index')
|
106
|
+
assert_equal 'Site title', Nesta::Page.find_by_path('/').title
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#heading' do
|
112
|
+
it 'raises error if heading not set' do
|
113
|
+
with_temp_content_directory do
|
114
|
+
assert_raises Nesta::HeadingNotSet do
|
115
|
+
create(:page, heading: nil).heading
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'parses Markdown pages returning contents of first # heading' do
|
121
|
+
with_temp_content_directory do
|
122
|
+
page = create(:page) do |path|
|
123
|
+
file = File.open(path, 'w')
|
124
|
+
file.write('# Hello Markdown')
|
125
|
+
file.close
|
126
|
+
end
|
127
|
+
assert_equal 'Hello Markdown', page.heading
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'parses Textile pages returning contents of first h1. heading' do
|
132
|
+
with_temp_content_directory do
|
133
|
+
page = create(:page, ext: 'textile') do |path|
|
134
|
+
file = File.open(path, 'w')
|
135
|
+
file.write('h1. Hello Textile')
|
136
|
+
file.close
|
137
|
+
end
|
138
|
+
assert_equal 'Hello Textile', page.heading
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'parases Haml pages returning contents of first %h1 tag' do
|
143
|
+
with_temp_content_directory do
|
144
|
+
page = create(:page, ext: 'haml') do |path|
|
145
|
+
file = File.open(path, 'w')
|
146
|
+
file.write('%h1 Hello Haml')
|
147
|
+
file.close
|
148
|
+
end
|
149
|
+
assert_equal 'Hello Haml', page.heading
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'ignores subsequent h1 tags' do
|
154
|
+
with_temp_content_directory do
|
155
|
+
page = create(:page, content: '# Second heading')
|
156
|
+
fail 'wrong h1 tag' if page.heading == 'Second heading'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'ignores trailing # characters in Markdown headings' do
|
161
|
+
with_temp_content_directory do
|
162
|
+
page = create(:page, heading: 'With trailing #')
|
163
|
+
assert_equal 'With trailing', page.heading
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#abspath' do
|
169
|
+
it 'returns / for home page' do
|
170
|
+
with_temp_content_directory do
|
171
|
+
create(:page, path: 'index')
|
172
|
+
assert_equal '/', Nesta::Page.find_by_path('index').abspath
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe '#permalink' do
|
178
|
+
it 'returns basename of filename' do
|
179
|
+
with_temp_content_directory do
|
180
|
+
assert_equal 'page', create(:page, path: 'path/to/page').permalink
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'returns empty string for home page' do
|
185
|
+
with_temp_content_directory do
|
186
|
+
home = create(:page, path: 'index')
|
187
|
+
assert_equal '', Nesta::Page.find_by_path(home.path).permalink
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'removes /index from permalink of index pages' do
|
192
|
+
with_temp_content_directory do
|
193
|
+
index = create(:page, path: 'parent/child/index')
|
194
|
+
assert_equal 'child', index.permalink
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe '#parent' do
|
200
|
+
it 'finds the parent by inspecting the path' do
|
201
|
+
with_temp_content_directory do
|
202
|
+
parent = create(:page, path: 'parent')
|
203
|
+
child = create(:page, path: 'parent/child')
|
204
|
+
assert_equal parent, child.parent
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'returns nil for pages at top level' do
|
209
|
+
with_temp_content_directory do
|
210
|
+
assert_nil create(:page, path: 'top-level').parent
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'finds parents that are index pages' do
|
215
|
+
with_temp_content_directory do
|
216
|
+
home = create(:page, path: 'index')
|
217
|
+
child = create(:page, path: 'parent')
|
218
|
+
assert_equal home, child.parent
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
it "returns grandparent if parent doesn't exist" do
|
223
|
+
with_temp_content_directory do
|
224
|
+
grandparent = create(:page, path: 'grandparent')
|
225
|
+
child = create(:page, path: 'grandparent/parent/child')
|
226
|
+
assert_equal grandparent, child.parent
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'recognises that home page can be returned as a grandparent' do
|
231
|
+
with_temp_content_directory do
|
232
|
+
grandparent = create(:page, path: 'index')
|
233
|
+
child = create(:page, path: 'parent/child')
|
234
|
+
assert_equal grandparent, child.parent
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'returns nil if page has no parent' do
|
239
|
+
with_temp_content_directory do
|
240
|
+
assert_nil create(:page, path: 'index').parent
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'finds parent of an index page' do
|
245
|
+
with_temp_content_directory do
|
246
|
+
parent = create(:page, path: 'parent')
|
247
|
+
index = create(:page, path: 'parent/child/index')
|
248
|
+
assert_equal parent, index.parent
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe '#priority' do
|
254
|
+
it 'defaults to 0 for pages in category' do
|
255
|
+
with_temp_content_directory do
|
256
|
+
page = create(:page, metadata: { 'categories' => 'the-category' })
|
257
|
+
assert_equal 0, page.priority('the-category')
|
258
|
+
assert_nil page.priority('another-category')
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'parses metadata to determine priority in each category' do
|
263
|
+
with_temp_content_directory do
|
264
|
+
page = create(:page, metadata: {
|
265
|
+
'categories' => ' category-page:1, another-page , and-another :-1 '
|
266
|
+
})
|
267
|
+
assert_equal 1, page.priority('category-page')
|
268
|
+
assert_equal 0, page.priority('another-page')
|
269
|
+
assert_equal -1, page.priority('and-another')
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe '#pages' do
|
275
|
+
it 'returns pages but not articles within this category' do
|
276
|
+
with_temp_content_directory do
|
277
|
+
category = create(:category)
|
278
|
+
metadata = { 'categories' => category.path }
|
279
|
+
page1 = create(:category, metadata: metadata)
|
280
|
+
page2 = create(:category, metadata: metadata)
|
281
|
+
create(:article, metadata: metadata)
|
282
|
+
assert_equal [page1, page2], category.pages
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'sorts pages within a category by priority' do
|
287
|
+
with_temp_content_directory do
|
288
|
+
category = create(:category)
|
289
|
+
create(:category, metadata: { 'categories' => category.path })
|
290
|
+
page = create(:category, metadata: {
|
291
|
+
'categories' => "#{category.path}:1"
|
292
|
+
})
|
293
|
+
assert_equal 0, category.pages.index(page)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'orders pages within a category by heading if priority not set' do
|
298
|
+
with_temp_content_directory do
|
299
|
+
category = create(:category)
|
300
|
+
metadata = { 'categories' => category.path }
|
301
|
+
last = create(:category, heading: 'B', metadata: metadata)
|
302
|
+
first = create(:category, heading: 'A', metadata: metadata)
|
303
|
+
assert_equal [first, last], category.pages
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
it 'filters out draft pages when running in production' do
|
308
|
+
with_temp_content_directory do
|
309
|
+
category = create(:category)
|
310
|
+
create(:page, metadata: {
|
311
|
+
'categories' => category.path,
|
312
|
+
'flags' => 'draft'
|
313
|
+
})
|
314
|
+
fail 'should include draft pages' if category.pages.empty?
|
315
|
+
Nesta::App.stub(:production?, true) do
|
316
|
+
assert category.pages.empty?, 'should filter out draft pages'
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe '#articles' do
|
323
|
+
it "returns just the articles that are in this page's category" do
|
324
|
+
with_temp_content_directory do
|
325
|
+
category1 = create(:category)
|
326
|
+
in_category1 = { 'categories' => category1.path }
|
327
|
+
category2 = create(:category, metadata: in_category1)
|
328
|
+
in_category2 = { 'categories' => category2.path }
|
329
|
+
|
330
|
+
article1 = create(:article, metadata: in_category1)
|
331
|
+
create(:article, metadata: in_category2)
|
332
|
+
|
333
|
+
assert_equal [article1], category1.articles
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'returns articles in reverse chronological order' do
|
338
|
+
with_temp_content_directory do
|
339
|
+
category = create(:category)
|
340
|
+
create(:article, metadata: {
|
341
|
+
'date' => '30 December 2008',
|
342
|
+
'categories' => category.path
|
343
|
+
})
|
344
|
+
latest = create(:article, metadata: {
|
345
|
+
'date' => '31 December 2008',
|
346
|
+
'categories' => category.path
|
347
|
+
})
|
348
|
+
assert_equal latest, category.articles.first
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
describe '#categories' do
|
354
|
+
it "returns a page's categories" do
|
355
|
+
with_temp_content_directory do
|
356
|
+
category1 = create(:category, path: 'path/to/cat1')
|
357
|
+
category2 = create(:category, path: 'path/to/cat2')
|
358
|
+
article = create(:article, metadata: {
|
359
|
+
'categories' => 'path/to/cat1, path/to/cat2'
|
360
|
+
})
|
361
|
+
assert_equal [category1, category2], article.categories
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'only returns categories that exist' do
|
366
|
+
with_temp_content_directory do
|
367
|
+
article = create(:article, metadata: { 'categories' => 'no-such-page' })
|
368
|
+
assert_empty article.categories
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
describe '#to_html' do
|
374
|
+
it 'produces no output if page has no content' do
|
375
|
+
with_temp_content_directory do
|
376
|
+
page = create(:page) do |path|
|
377
|
+
file = File.open(path, 'w')
|
378
|
+
file.close
|
379
|
+
end
|
380
|
+
assert_match /^\s*$/, Nesta::Page.find_by_path(page.path).to_html
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'converts page content to HTML' do
|
385
|
+
with_temp_content_directory do
|
386
|
+
assert_match %r{<h1>Hello</h1>}, create(:page, heading: 'Hello').to_html
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
it "doesn't include leading metadata in HTML" do
|
391
|
+
with_temp_content_directory do
|
392
|
+
page = create(:page, metadata: { 'key' => 'value' })
|
393
|
+
fail 'HTML contains metadata' if page.to_html =~ /(key|value)/
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
describe '#summary' do
|
399
|
+
it 'returns value set in metadata wrapped in p tags' do
|
400
|
+
with_temp_content_directory do
|
401
|
+
page = create(:page, metadata: { 'Summary' => 'Summary paragraph' })
|
402
|
+
assert_equal "<p>Summary paragraph</p>\n", page.summary
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
it 'treats double newline characters as paragraph breaks' do
|
407
|
+
with_temp_content_directory do
|
408
|
+
page = create(:page, metadata: { 'Summary' => 'Line 1\n\nLine 2' })
|
409
|
+
assert_includes page.summary, '<p>Line 1</p>'
|
410
|
+
assert_includes page.summary, '<p>Line 2</p>'
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
describe '#body' do
|
416
|
+
it "doesn't include page heading" do
|
417
|
+
with_temp_content_directory do
|
418
|
+
page = create(:page, heading: 'Heading')
|
419
|
+
fail 'body contains heading' if page.body_markup =~ /#{page.heading}/
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe '#metadata' do
|
425
|
+
it 'return value of any key set in metadata at top of page' do
|
426
|
+
with_temp_content_directory do
|
427
|
+
page = create(:page, metadata: { 'Any key' => 'Any string' })
|
428
|
+
assert_equal 'Any string', page.metadata('Any key')
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
describe '#layout' do
|
434
|
+
it 'defaults to :layout' do
|
435
|
+
with_temp_content_directory do
|
436
|
+
assert_equal :layout, create(:page).layout
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
it 'returns value set in metadata' do
|
441
|
+
with_temp_content_directory do
|
442
|
+
page = create(:page, metadata: { 'Layout' => 'my_layout' })
|
443
|
+
assert_equal :my_layout, page.layout
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
describe '#template' do
|
449
|
+
it 'defaults to :page' do
|
450
|
+
with_temp_content_directory do
|
451
|
+
assert_equal :page, create(:page).template
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
it 'returns value set in metadata' do
|
456
|
+
with_temp_content_directory do
|
457
|
+
page = create(:page, metadata: { 'Template' => 'my_template' })
|
458
|
+
assert_equal :my_template, page.template
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
describe '#link_text' do
|
464
|
+
it 'raises error if neither heading nor link text set' do
|
465
|
+
with_temp_content_directory do
|
466
|
+
assert_raises Nesta::LinkTextNotSet do
|
467
|
+
create(:page, heading: nil).link_text
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
it 'defaults to page heading' do
|
473
|
+
with_temp_content_directory do
|
474
|
+
page = create(:page)
|
475
|
+
assert_equal page.heading, page.link_text
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
it 'returns value set in metadata' do
|
480
|
+
with_temp_content_directory do
|
481
|
+
page = create(:page, metadata: { 'link text' => 'Hello' })
|
482
|
+
assert_equal 'Hello', page.link_text
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
describe '#read_more' do
|
488
|
+
it 'has sensible default' do
|
489
|
+
with_temp_content_directory do
|
490
|
+
assert_equal 'Continue reading', create(:page).read_more
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
it 'returns value set in metadata' do
|
495
|
+
with_temp_content_directory do
|
496
|
+
page = create(:page, metadata: { 'Read more' => 'Click here' })
|
497
|
+
assert_equal 'Click here', page.read_more
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
describe '#description' do
|
503
|
+
it 'returns nil by default' do
|
504
|
+
with_temp_content_directory { assert_nil create(:page).description }
|
505
|
+
end
|
506
|
+
|
507
|
+
it 'returns value set in metadata' do
|
508
|
+
with_temp_content_directory do
|
509
|
+
page = create(:page, metadata: { 'description' => 'A page' })
|
510
|
+
assert_equal 'A page', page.description
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
describe '#keywords' do
|
516
|
+
it 'returns nil by default' do
|
517
|
+
with_temp_content_directory { assert_nil create(:page).keywords }
|
518
|
+
end
|
519
|
+
|
520
|
+
it 'returns value set in metadata' do
|
521
|
+
with_temp_content_directory do
|
522
|
+
page = create(:page, metadata: { 'keywords' => 'good, content' })
|
523
|
+
assert_equal 'good, content', page.keywords
|
524
|
+
end
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
describe '#date' do
|
529
|
+
it 'returns date article was published' do
|
530
|
+
with_temp_content_directory do
|
531
|
+
article = create(:article, metadata: { 'date' => 'November 18 2015' })
|
532
|
+
assert_equal '18 November 2015', article.date.strftime('%d %B %Y')
|
533
|
+
end
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
describe '#flagged_as?' do
|
538
|
+
it 'returns true if flags metadata contains the string' do
|
539
|
+
with_temp_content_directory do
|
540
|
+
page = create(:page, metadata: { 'flags' => 'A flag, popular' })
|
541
|
+
assert page.flagged_as?('popular'), 'should be flagged popular'
|
542
|
+
assert page.flagged_as?('A flag'), 'should be flagged with "A flag"'
|
543
|
+
fail 'not flagged as green' if page.flagged_as?('green')
|
544
|
+
end
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
describe '#draft?' do
|
549
|
+
it 'returns true if page flagged as draft' do
|
550
|
+
with_temp_content_directory do
|
551
|
+
page = create(:page, metadata: { 'flags' => 'draft' })
|
552
|
+
assert page.draft?
|
553
|
+
fail 'not a draft' if create(:page).draft?
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
describe '#last_modified' do
|
559
|
+
it 'reads last modified timestamp from disk' do
|
560
|
+
with_temp_content_directory do
|
561
|
+
page = create(:page)
|
562
|
+
file_stat = Minitest::Mock.new
|
563
|
+
file_stat.expect(:mtime, Time.parse('3 January 2009'))
|
564
|
+
File.stub(:stat, file_stat) do
|
565
|
+
assert_equal '03 Jan 2009', page.last_modified.strftime('%d %b %Y')
|
566
|
+
end
|
567
|
+
file_stat.verify
|
568
|
+
end
|
569
|
+
end
|
570
|
+
end
|
571
|
+
end
|