nesta 0.11.1 → 0.13.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 +5 -5
- data/.github/workflows/tests.yml +21 -0
- data/.gitmodules +0 -0
- data/CHANGES +44 -2
- data/Gemfile +1 -1
- data/Gemfile.lock +73 -55
- data/LICENSE +1 -1
- data/README.md +7 -14
- data/RELEASING.md +10 -9
- data/Rakefile +20 -3
- data/bin/nesta +1 -1
- data/config/deploy.rb.sample +1 -1
- data/lib/nesta/app.rb +4 -8
- data/lib/nesta/commands/demo/content.rb +28 -12
- data/lib/nesta/commands/edit.rb +2 -6
- data/lib/nesta/commands/new.rb +9 -11
- data/lib/nesta/commands/plugin/create.rb +7 -9
- data/lib/nesta/commands/template.rb +20 -0
- data/lib/nesta/commands/theme/create.rb +8 -8
- data/lib/nesta/commands/theme/enable.rb +3 -5
- data/lib/nesta/commands/theme/install.rb +12 -14
- data/lib/nesta/commands.rb +8 -0
- data/lib/nesta/config_file.rb +25 -0
- data/lib/nesta/helpers.rb +14 -0
- data/lib/nesta/models.rb +26 -22
- data/lib/nesta/navigation.rb +1 -1
- data/lib/nesta/system_command.rb +15 -0
- data/lib/nesta/version.rb +1 -1
- data/lib/nesta.rb +6 -1
- data/nesta.gemspec +11 -12
- 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/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/lib/nesta-plugin-test.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 +33 -0
- data/test/integration/commands/edit_test.rb +21 -0
- data/test/integration/commands/new_test.rb +91 -0
- data/test/integration/commands/plugin/create_test.rb +131 -0
- data/test/integration/commands/theme/create_test.rb +41 -0
- data/test/integration/commands/theme/enable_test.rb +28 -0
- data/test/integration/commands/theme/install_test.rb +66 -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/temporary_files.rb +33 -0
- data/test/support/test_configuration.rb +19 -0
- data/test/test_helper.rb +26 -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/test/unit/system_command_test.rb +20 -0
- data/views/master.sass +1 -1
- metadata +90 -89
- data/.hound.yml +0 -2
- data/.rspec +0 -1
- data/.travis.yml +0 -6
- data/lib/nesta/commands/command.rb +0 -58
- 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,131 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require_relative '../../../../lib/nesta/commands'
|
3
|
+
|
4
|
+
describe 'nesta plugin:create' do
|
5
|
+
include TemporaryFiles
|
6
|
+
|
7
|
+
def working_directory
|
8
|
+
temp_path('plugins')
|
9
|
+
end
|
10
|
+
|
11
|
+
before do
|
12
|
+
FileUtils.mkdir_p(working_directory)
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
remove_temp_directory
|
17
|
+
end
|
18
|
+
|
19
|
+
def plugin_name
|
20
|
+
'my-feature'
|
21
|
+
end
|
22
|
+
|
23
|
+
def gem_name
|
24
|
+
"nesta-plugin-#{plugin_name}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def process_stub
|
28
|
+
Object.new.tap do |stub|
|
29
|
+
def stub.run(*args); end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_plugin(&block)
|
34
|
+
Dir.chdir(working_directory) do
|
35
|
+
command = Nesta::Commands::Plugin::Create.new(plugin_name)
|
36
|
+
command.execute(process_stub)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def assert_exists_in_plugin(path)
|
41
|
+
full_path = File.join(gem_name, path)
|
42
|
+
assert File.exist?(full_path), "#{path} not found in plugin"
|
43
|
+
end
|
44
|
+
|
45
|
+
def assert_file_contains(path, pattern)
|
46
|
+
assert_match pattern, File.read(File.join(gem_name, path))
|
47
|
+
end
|
48
|
+
|
49
|
+
it "creates the gem's directory" do
|
50
|
+
create_plugin { assert File.directory?(gem_name), 'gem directory not found' }
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'creates README.md file' do
|
54
|
+
create_plugin { assert_exists_in_plugin('README.md') }
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'includes installation instructions in README.md' do
|
58
|
+
create_plugin do
|
59
|
+
assert_file_contains('README.md', /echo 'gem "#{gem_name}"' >> Gemfile/)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'creates .gitignore file' do
|
64
|
+
create_plugin { assert_exists_in_plugin('.gitignore') }
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'creates the gemspec' do
|
68
|
+
create_plugin do
|
69
|
+
gemspec = "#{gem_name}.gemspec"
|
70
|
+
assert_exists_in_plugin(gemspec)
|
71
|
+
assert_file_contains(gemspec, %r{require "#{gem_name}/version"})
|
72
|
+
assert_file_contains(gemspec, %r{Nesta::Plugin::My::Feature::VERSION})
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'creates a Gemfile' do
|
77
|
+
create_plugin { assert_exists_in_plugin('Gemfile') }
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'creates Rakefile for packaging the gem' do
|
81
|
+
create_plugin { assert_exists_in_plugin('Rakefile') }
|
82
|
+
end
|
83
|
+
|
84
|
+
it "creates default folder for Ruby files" do
|
85
|
+
create_plugin do
|
86
|
+
code_directory = File.join(gem_name, 'lib', gem_name)
|
87
|
+
assert File.directory?(code_directory), 'directory for code not found'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'creates file required when gem loaded' do
|
92
|
+
create_plugin do
|
93
|
+
path = "#{File.join('lib', gem_name)}.rb"
|
94
|
+
assert_exists_in_plugin(path)
|
95
|
+
assert_file_contains(path, %r{require "#{gem_name}/version"})
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'creates version.rb' do
|
100
|
+
create_plugin do
|
101
|
+
version = File.join('lib', gem_name, 'version.rb')
|
102
|
+
assert_exists_in_plugin(version)
|
103
|
+
assert_file_contains version, <<-EOF
|
104
|
+
module Nesta
|
105
|
+
module Plugin
|
106
|
+
module My
|
107
|
+
module Feature
|
108
|
+
VERSION = '0.1.0'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
EOF
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'creates skeleton code for the plugin in init.rb' do
|
118
|
+
create_plugin do
|
119
|
+
init = File.join('lib', gem_name, 'init.rb')
|
120
|
+
assert_exists_in_plugin(init)
|
121
|
+
|
122
|
+
assert_file_contains init, <<-MODULE
|
123
|
+
module Nesta
|
124
|
+
module Plugin
|
125
|
+
module My::Feature
|
126
|
+
MODULE
|
127
|
+
|
128
|
+
assert_file_contains init, 'helpers Nesta::Plugin::My::Feature::Helpers'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require_relative '../../../../lib/nesta/commands'
|
3
|
+
|
4
|
+
describe 'nesta theme:create' do
|
5
|
+
include TemporaryFiles
|
6
|
+
|
7
|
+
def theme_path(path = '')
|
8
|
+
File.join('themes', 'theme-name', path)
|
9
|
+
end
|
10
|
+
|
11
|
+
before do
|
12
|
+
FileUtils.mkdir_p(project_root)
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
remove_temp_directory
|
17
|
+
end
|
18
|
+
|
19
|
+
def process_stub
|
20
|
+
Object.new.tap do |stub|
|
21
|
+
def stub.run(*args); end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'creates default files in the theme directory' do
|
26
|
+
Dir.chdir(project_root) do
|
27
|
+
Nesta::Commands::Theme::Create.new('theme-name').execute(process_stub)
|
28
|
+
end
|
29
|
+
assert_exists_in_project theme_path('README.md')
|
30
|
+
assert_exists_in_project theme_path('app.rb')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'copies default view templates into views directory' do
|
34
|
+
Dir.chdir(project_root) do
|
35
|
+
Nesta::Commands::Theme::Create.new('theme-name').execute(process_stub)
|
36
|
+
end
|
37
|
+
%w(layout.haml page.haml master.sass).each do |template|
|
38
|
+
assert_exists_in_project theme_path("views/#{template}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require_relative '../../../../lib/nesta/commands'
|
3
|
+
|
4
|
+
describe 'nesta theme:enable' do
|
5
|
+
include TemporaryFiles
|
6
|
+
|
7
|
+
before do
|
8
|
+
FileUtils.mkdir_p(File.join(project_root, 'config'))
|
9
|
+
File.open(File.join(project_root, 'config', 'config.yml'), 'w').close
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
remove_temp_directory
|
14
|
+
end
|
15
|
+
|
16
|
+
def process_stub
|
17
|
+
Object.new.tap do |stub|
|
18
|
+
def stub.run(*args); end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'enables the theme' do
|
23
|
+
Dir.chdir(project_root) do
|
24
|
+
Nesta::Commands::Theme::Enable.new('theme-name').execute(process_stub)
|
25
|
+
assert_match /^theme: theme-name/, File.read('config/config.yml')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require_relative '../../../../lib/nesta/commands'
|
3
|
+
|
4
|
+
describe 'nesta theme:install' do
|
5
|
+
include TemporaryFiles
|
6
|
+
|
7
|
+
def theme_name
|
8
|
+
'test'
|
9
|
+
end
|
10
|
+
|
11
|
+
def repo_url
|
12
|
+
"../../fixtures/nesta-theme-#{theme_name}.git"
|
13
|
+
end
|
14
|
+
|
15
|
+
def theme_dir
|
16
|
+
project_path("themes/#{theme_name}")
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
FileUtils.mkdir_p(project_root)
|
21
|
+
end
|
22
|
+
|
23
|
+
after do
|
24
|
+
remove_temp_directory
|
25
|
+
end
|
26
|
+
|
27
|
+
def process_stub
|
28
|
+
Object.new.tap do |stub|
|
29
|
+
def stub.run(*args); end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'clones the repository' do
|
34
|
+
process = Minitest::Mock.new
|
35
|
+
process.expect(:run, true, ['git', 'clone', repo_url, "themes/#{theme_name}"])
|
36
|
+
in_temporary_project do
|
37
|
+
Nesta::Commands::Theme::Install.new(repo_url).execute(process)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "removes the theme's .git directory" do
|
42
|
+
in_temporary_project do
|
43
|
+
Nesta::Commands::Theme::Install.new(repo_url).execute(process_stub)
|
44
|
+
refute File.exist?("#{theme_dir}/.git"), '.git folder found'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'enables the freshly installed theme' do
|
49
|
+
in_temporary_project do
|
50
|
+
Nesta::Commands::Theme::Install.new(repo_url).execute(process_stub)
|
51
|
+
assert_match /theme: #{theme_name}/, File.read('config/config.yml')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'determines name of theme from name of repository' do
|
56
|
+
url = 'https://foobar.com/path/to/nesta-theme-the-name.git'
|
57
|
+
command = Nesta::Commands::Theme::Install.new(url)
|
58
|
+
assert_equal 'the-name', command.theme_name
|
59
|
+
end
|
60
|
+
|
61
|
+
it "falls back to name of repo when theme name doesn't match correct format" do
|
62
|
+
url = 'https://foobar.com/path/to/mytheme.git'
|
63
|
+
command = Nesta::Commands::Theme::Install.new(url)
|
64
|
+
assert_equal 'mytheme', command.theme_name
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'integration_test_helper'
|
2
|
+
|
3
|
+
describe 'Default theme' do
|
4
|
+
include Nesta::IntegrationTest
|
5
|
+
|
6
|
+
def in_categories(*categories)
|
7
|
+
{ 'categories' => categories.map(&:path).join(', ') }
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'includes description meta tag' do
|
11
|
+
with_temp_content_directory do
|
12
|
+
model = create(:page, metadata: { 'Description' => 'A good page' })
|
13
|
+
visit model.path
|
14
|
+
xpath = "//meta[@name='description'][@content='A good page']"
|
15
|
+
assert_has_xpath xpath, visible: false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'includes keywords meta tag' do
|
20
|
+
with_temp_content_directory do
|
21
|
+
model = create(:page, metadata: { 'Keywords' => 'good, content' })
|
22
|
+
visit model.path
|
23
|
+
xpath = "//meta[@name='keywords'][@content='good, content']"
|
24
|
+
assert_has_xpath xpath, visible: false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "doesn't include Google Analytics JavaScript snippet by default" do
|
29
|
+
with_temp_content_directory do
|
30
|
+
visit '/'
|
31
|
+
assert_has_no_css 'script', text: 'google-analytics.com'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'includes Google Analytics JavaScript when configured' do
|
36
|
+
analytics_code = { 'google_analytics_code' => 'UA-1234' }
|
37
|
+
stub_config(temp_content.merge('test' => analytics_code)) do
|
38
|
+
visit '/'
|
39
|
+
assert_nil all('script').find { |s| s[:src].match /analytics\.js/ }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'displays site title' do
|
44
|
+
site_config = {
|
45
|
+
'title' => 'My blog',
|
46
|
+
'subtitle' => 'about stuff',
|
47
|
+
}
|
48
|
+
stub_config(temp_content.merge(site_config)) do
|
49
|
+
visit '/'
|
50
|
+
assert_has_css 'h1', text: 'My blog'
|
51
|
+
assert_has_css 'h2', text: 'about stuff'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'menus' do
|
56
|
+
def create_pages_in_menu
|
57
|
+
pages
|
58
|
+
end
|
59
|
+
|
60
|
+
it "doesn't include menu markup if menu not configured" do
|
61
|
+
with_temp_content_directory do
|
62
|
+
visit '/'
|
63
|
+
assert_has_no_css 'ul.menu'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'only displays first two levels of menu items' do
|
68
|
+
with_temp_content_directory do
|
69
|
+
level1, level2, level3 = (0..2).map { create(:page) }
|
70
|
+
text = "%s\n %s\n %s\n" % [level1, level2, level3].map(&:abspath)
|
71
|
+
create_menu(text)
|
72
|
+
visit '/'
|
73
|
+
assert_has_css "ul.menu li a:contains('#{level1.link_text}')"
|
74
|
+
assert_has_css "ul.menu li ul li a:contains('#{level2.link_text}')"
|
75
|
+
assert_has_no_css "ul.menu a:contains('#{level3.link_text}')"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_page_and_menu
|
80
|
+
model = create(:page)
|
81
|
+
create_menu(model.path)
|
82
|
+
model
|
83
|
+
end
|
84
|
+
|
85
|
+
it "highlights current page's menu item" do
|
86
|
+
with_temp_content_directory do
|
87
|
+
model = create_page_and_menu
|
88
|
+
visit model.path
|
89
|
+
assert_has_css "ul.menu li[class='current']:contains('#{model.link_text}')"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "highlights current page's menu item when app mounted at /prefix" do
|
94
|
+
Capybara.app = Rack::Builder.new do
|
95
|
+
map '/prefix' do
|
96
|
+
run Nesta::App.new
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
with_temp_content_directory do
|
101
|
+
model = create_page_and_menu
|
102
|
+
visit "/prefix/#{model.path}"
|
103
|
+
assert_has_css "ul.menu li[class='current']:contains('#{model.link_text}')"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'only displays read more link for summarised pages' do
|
109
|
+
with_temp_content_directory do
|
110
|
+
category = create(:category)
|
111
|
+
metadata = in_categories(category)
|
112
|
+
summarised = create(:page, metadata: metadata.merge('summary' => 'Summary'))
|
113
|
+
not_summarised = create(:page, metadata: metadata)
|
114
|
+
visit category.path
|
115
|
+
assert_has_css 'li:nth-child(1) p', text: summarised.read_more
|
116
|
+
assert_has_no_css 'li:nth-child(2) p', text: not_summarised.read_more
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'displays page summaries or full content of unsummarised pages' do
|
121
|
+
with_temp_content_directory do
|
122
|
+
category = create(:category)
|
123
|
+
metadata = in_categories(category)
|
124
|
+
summarised = create(:page,
|
125
|
+
content: 'Summarised content',
|
126
|
+
metadata: metadata.merge(summary: 'Summary'))
|
127
|
+
not_summarised = create(:page,
|
128
|
+
content: 'Unsummarised content',
|
129
|
+
metadata: metadata)
|
130
|
+
visit category.path
|
131
|
+
|
132
|
+
# Page with a summary
|
133
|
+
assert_has_css 'li:nth-child(1) p', text: 'Summary'
|
134
|
+
assert_has_no_css 'li:nth-child(1) p', text: 'content'
|
135
|
+
|
136
|
+
# Page without a summary
|
137
|
+
assert_has_css 'li:nth-child(2) p', text: 'Unsummarised content'
|
138
|
+
assert_has_no_css 'li:nth-child(2) p', text: 'Summary'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'displays contents of page' do
|
143
|
+
with_temp_content_directory do
|
144
|
+
model = create(:page, content: 'Body of page')
|
145
|
+
visit model.path
|
146
|
+
assert_has_css 'p', text: 'Body of page'
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe 'category' do
|
151
|
+
it 'displays its "articles heading" above the articles' do
|
152
|
+
with_temp_content_directory do
|
153
|
+
category = create(:category, metadata: {
|
154
|
+
'articles heading' => 'Articles on this topic'
|
155
|
+
})
|
156
|
+
create(:article, metadata: in_categories(category))
|
157
|
+
visit category.path
|
158
|
+
assert_has_css 'h1', text: 'Articles on this topic'
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'links to articles in category using article title' do
|
163
|
+
with_temp_content_directory do
|
164
|
+
category = create(:category)
|
165
|
+
article = create(:article, metadata: in_categories(category))
|
166
|
+
visit category.path
|
167
|
+
link_text, href = article.link_text, article.abspath
|
168
|
+
assert_has_css "ol h1 a[href$='#{href}']", text: link_text
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe 'article' do
|
174
|
+
it 'displays the date' do
|
175
|
+
with_temp_content_directory do
|
176
|
+
article = create(:article)
|
177
|
+
visit article.path
|
178
|
+
assert_has_css "time[datetime='#{article.date}']"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'links to parent page in breadcrumb' do
|
183
|
+
with_temp_content_directory do
|
184
|
+
parent = create(:category)
|
185
|
+
article = create(:article, path: "#{parent.path}/child")
|
186
|
+
visit article.path
|
187
|
+
href, link_text = parent.abspath, parent.link_text
|
188
|
+
assert_has_css "nav.breadcrumb a[href='#{href}']", text: link_text
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'links to its categories at end of article' do
|
193
|
+
with_temp_content_directory do
|
194
|
+
categories = [create(:category), create(:category)]
|
195
|
+
article = create(:article, metadata: in_categories(*categories))
|
196
|
+
visit article.path
|
197
|
+
categories.each do |category|
|
198
|
+
href, link_text = category.abspath, category.link_text
|
199
|
+
assert_has_css "p.meta a[href$='#{href}']", text: link_text
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'displays comments from Disqus' do
|
205
|
+
stub_config(temp_content.merge('disqus_short_name' => 'mysite')) do
|
206
|
+
article = create(:article)
|
207
|
+
visit article.path
|
208
|
+
assert_has_css '#disqus_thread'
|
209
|
+
assert_has_css 'script[src*="mysite.disqus.com"]', visible: false
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
it "doesn't use Disqus if it's not configured" do
|
214
|
+
with_temp_content_directory do
|
215
|
+
visit create(:article).path
|
216
|
+
assert_has_no_css '#disqus_thread'
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'integration_test_helper'
|
2
|
+
|
3
|
+
describe 'Overriding files in gem and themes' do
|
4
|
+
include Nesta::IntegrationTest
|
5
|
+
|
6
|
+
def in_nesta_project(config = {}, &block)
|
7
|
+
app_root = temp_path('root')
|
8
|
+
content_config = { 'content' => File.join(app_root, 'content') }
|
9
|
+
stub_config(content_config.merge(config)) do
|
10
|
+
with_app_root(app_root) do
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
end
|
14
|
+
ensure
|
15
|
+
remove_temp_directory
|
16
|
+
end
|
17
|
+
|
18
|
+
def theme_name
|
19
|
+
'my-theme'
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_fixture(type, name, content)
|
23
|
+
base_path = {
|
24
|
+
local: Nesta::Path.local,
|
25
|
+
theme: Nesta::Path.themes(theme_name)
|
26
|
+
}[type]
|
27
|
+
path = File.join(base_path, name)
|
28
|
+
FileUtils.mkdir_p(File.dirname(path))
|
29
|
+
open(path, 'w') { |file| file.write(content) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_app_file(type)
|
33
|
+
create_fixture(type, 'app.rb', "FROM_#{type.to_s.upcase} = true")
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'app.rb' do
|
37
|
+
it 'loads app.rb from configured theme' do
|
38
|
+
in_nesta_project('theme' => theme_name) do
|
39
|
+
create_app_file(:theme)
|
40
|
+
Nesta::Overrides.load_theme_app
|
41
|
+
assert Object.const_get(:FROM_THEME), 'should load app.rb in theme'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'loads both local and theme app.rb files' do
|
46
|
+
in_nesta_project('theme' => theme_name) do
|
47
|
+
create_app_file(:local)
|
48
|
+
Nesta::Overrides.load_local_app
|
49
|
+
create_app_file(:theme)
|
50
|
+
Nesta::Overrides.load_theme_app
|
51
|
+
assert Object.const_get(:FROM_THEME), 'should load app.rb in theme'
|
52
|
+
assert Object.const_get(:FROM_LOCAL), 'should load local app.rb'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_view(type, name, content)
|
58
|
+
create_fixture(type, File.join('views', name), content)
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'rendering stylesheets' do
|
62
|
+
it 'renders Sass stylesheets' do
|
63
|
+
in_nesta_project do
|
64
|
+
create_view(:local, 'master.sass', "body\n width: 10px * 2")
|
65
|
+
visit '/css/master.css'
|
66
|
+
assert_match /width: 20px;/, body, 'should match /width: 20px;/'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'renders SCSS stylesheets' do
|
71
|
+
in_nesta_project do
|
72
|
+
create_view(:local, 'master.scss', "body {\n width: 10px * 2;\n}")
|
73
|
+
visit '/css/master.css'
|
74
|
+
assert_match /width: 20px;/, body, 'should match /width: 20px;/'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'renders stylesheet in the the gem if no others found' do
|
79
|
+
in_nesta_project do
|
80
|
+
visit '/css/master.css'
|
81
|
+
assert_equal 200, page.status_code
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_haml(type, name, content)
|
87
|
+
create_view(type, 'layout.haml', '= yield')
|
88
|
+
create_view(type, name, content)
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'rendering Haml' do
|
92
|
+
it 'uses local template in place of default' do
|
93
|
+
in_nesta_project do
|
94
|
+
create_haml(:local, 'page.haml', '%p Local template')
|
95
|
+
visit create(:category).abspath
|
96
|
+
assert_has_xpath '//p', text: 'Local template'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'uses theme template in place of default' do
|
101
|
+
in_nesta_project('theme' => theme_name) do
|
102
|
+
create_haml(:theme, 'page.haml', '%p Theme template')
|
103
|
+
visit create(:category).abspath
|
104
|
+
assert_has_xpath '//p', text: 'Theme template'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'prioritise local templates over theme templates' do
|
109
|
+
in_nesta_project('theme' => theme_name) do
|
110
|
+
create_haml(:local, 'page.haml', '%p Local template')
|
111
|
+
create_haml(:theme, 'page.haml', '%p Theme template')
|
112
|
+
visit create(:category).abspath
|
113
|
+
assert_has_xpath '//p', text: 'Local template'
|
114
|
+
assert_has_no_xpath '//p', text: 'Theme template'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'integration_test_helper'
|
2
|
+
|
3
|
+
describe 'Routing' do
|
4
|
+
include Nesta::IntegrationTest
|
5
|
+
|
6
|
+
it 'redirects requests with trailing slash' do
|
7
|
+
with_temp_content_directory do
|
8
|
+
model = create(:page)
|
9
|
+
visit model.path + '/'
|
10
|
+
assert_equal model.abspath, page.current_path
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'not_found handler' do
|
15
|
+
it 'returns HTTP code 404' do
|
16
|
+
with_temp_content_directory do
|
17
|
+
visit '/no-such-page'
|
18
|
+
assert_equal 404, page.status_code
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'default route' do
|
24
|
+
it 'provides access to helper methods in Haml pages' do
|
25
|
+
with_temp_content_directory do
|
26
|
+
model = create(:category,
|
27
|
+
ext: 'haml',
|
28
|
+
content: '%div= format_date(Date.new(2010, 11, 23))')
|
29
|
+
visit model.path
|
30
|
+
assert_has_css 'div', text: '23 November 2010'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should access helpers when rendering articles on a category page" do
|
35
|
+
with_temp_content_directory do
|
36
|
+
category = create(:page)
|
37
|
+
markup = "%h1 Heading\n\n%div= format_date(Date.new(2010, 11, 23))"
|
38
|
+
article = create(:article,
|
39
|
+
ext: 'haml',
|
40
|
+
metadata: { 'categories' => category.path },
|
41
|
+
content: markup)
|
42
|
+
visit category.path
|
43
|
+
assert_has_css 'div', text: '23 November 2010'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_attachment_in(directory)
|
49
|
+
path = File.join(directory, 'test.txt')
|
50
|
+
FileUtils.mkdir_p(directory)
|
51
|
+
File.open(path, 'w') { |file| file.write("I'm a test attachment") }
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'attachments route' do
|
55
|
+
it 'returns HTTP code 200' do
|
56
|
+
with_temp_content_directory do
|
57
|
+
create_attachment_in(Nesta::Config.attachment_path)
|
58
|
+
visit '/attachments/test.txt'
|
59
|
+
assert_equal 200, page.status_code
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'serves attachment to the client' do
|
64
|
+
with_temp_content_directory do
|
65
|
+
create_attachment_in(Nesta::Config.attachment_path)
|
66
|
+
visit '/attachments/test.txt'
|
67
|
+
assert_equal "I'm a test attachment", page.body
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'sets the appropriate MIME type' do
|
72
|
+
with_temp_content_directory do
|
73
|
+
create_attachment_in(Nesta::Config.attachment_path)
|
74
|
+
visit '/attachments/test.txt'
|
75
|
+
assert_match %r{^text/plain}, page.response_headers['Content-Type']
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'refuses to serve files outside the attachments directory' do
|
80
|
+
# On earlier versions of Sinatra this test would have been handed
|
81
|
+
# to the attachments handler. On the current version (1.4.5) it
|
82
|
+
# appears as though the request is no longer matched by the
|
83
|
+
# attachments route handler, which means we're not in danger of
|
84
|
+
# serving serving files to attackers via `#send_file`.
|
85
|
+
#
|
86
|
+
# I've left the test in anyway, as without it we wouldn't become
|
87
|
+
# aware of a security hole if there was a regression in Sinatra.
|
88
|
+
#
|
89
|
+
with_temp_content_directory do
|
90
|
+
model = create(:page)
|
91
|
+
visit "/attachments/../pages/#{File.basename(model.filename)}"
|
92
|
+
assert_equal 404, page.status_code
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|