nesta 0.11.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/tests.yml +21 -0
  3. data/.gitmodules +0 -0
  4. data/CHANGES +44 -2
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +73 -55
  7. data/LICENSE +1 -1
  8. data/README.md +7 -14
  9. data/RELEASING.md +10 -9
  10. data/Rakefile +20 -3
  11. data/bin/nesta +1 -1
  12. data/config/deploy.rb.sample +1 -1
  13. data/lib/nesta/app.rb +4 -8
  14. data/lib/nesta/commands/demo/content.rb +28 -12
  15. data/lib/nesta/commands/edit.rb +2 -6
  16. data/lib/nesta/commands/new.rb +9 -11
  17. data/lib/nesta/commands/plugin/create.rb +7 -9
  18. data/lib/nesta/commands/template.rb +20 -0
  19. data/lib/nesta/commands/theme/create.rb +8 -8
  20. data/lib/nesta/commands/theme/enable.rb +3 -5
  21. data/lib/nesta/commands/theme/install.rb +12 -14
  22. data/lib/nesta/commands.rb +8 -0
  23. data/lib/nesta/config_file.rb +25 -0
  24. data/lib/nesta/helpers.rb +14 -0
  25. data/lib/nesta/models.rb +26 -22
  26. data/lib/nesta/navigation.rb +1 -1
  27. data/lib/nesta/system_command.rb +15 -0
  28. data/lib/nesta/version.rb +1 -1
  29. data/lib/nesta.rb +6 -1
  30. data/nesta.gemspec +11 -12
  31. data/templates/config/config.yml +1 -1
  32. data/{spec → test}/fixtures/nesta-plugin-test/Gemfile +0 -0
  33. data/{spec → test}/fixtures/nesta-plugin-test/Rakefile +0 -0
  34. data/{spec → test}/fixtures/nesta-plugin-test/lib/nesta-plugin-test/init.rb +0 -0
  35. data/{spec → test}/fixtures/nesta-plugin-test/lib/nesta-plugin-test/version.rb +0 -0
  36. data/{spec → test}/fixtures/nesta-plugin-test/lib/nesta-plugin-test.rb +0 -0
  37. data/{spec → test}/fixtures/nesta-plugin-test/nesta-plugin-test.gemspec +0 -0
  38. data/test/integration/atom_feed_test.rb +178 -0
  39. data/test/integration/commands/demo/content_test.rb +33 -0
  40. data/test/integration/commands/edit_test.rb +21 -0
  41. data/test/integration/commands/new_test.rb +91 -0
  42. data/test/integration/commands/plugin/create_test.rb +131 -0
  43. data/test/integration/commands/theme/create_test.rb +41 -0
  44. data/test/integration/commands/theme/enable_test.rb +28 -0
  45. data/test/integration/commands/theme/install_test.rb +66 -0
  46. data/test/integration/default_theme_test.rb +220 -0
  47. data/test/integration/overrides_test.rb +118 -0
  48. data/test/integration/route_handlers_test.rb +96 -0
  49. data/test/integration/sitemap_test.rb +85 -0
  50. data/test/integration_test_helper.rb +61 -0
  51. data/test/support/model_factory.rb +169 -0
  52. data/test/support/temporary_files.rb +33 -0
  53. data/test/support/test_configuration.rb +19 -0
  54. data/test/test_helper.rb +26 -0
  55. data/test/unit/config_test.rb +138 -0
  56. data/test/unit/file_model_test.rb +71 -0
  57. data/test/unit/menu_test.rb +82 -0
  58. data/test/unit/page_test.rb +571 -0
  59. data/test/unit/path_test.rb +41 -0
  60. data/test/unit/plugin_test.rb +47 -0
  61. data/test/unit/system_command_test.rb +20 -0
  62. data/views/master.sass +1 -1
  63. metadata +90 -89
  64. data/.hound.yml +0 -2
  65. data/.rspec +0 -1
  66. data/.travis.yml +0 -6
  67. data/lib/nesta/commands/command.rb +0 -58
  68. data/smoke-test.sh +0 -107
  69. data/spec/atom_spec.rb +0 -141
  70. data/spec/commands/demo/content_spec.rb +0 -65
  71. data/spec/commands/edit_spec.rb +0 -27
  72. data/spec/commands/new_spec.rb +0 -88
  73. data/spec/commands/plugin/create_spec.rb +0 -97
  74. data/spec/commands/system_spec.rb +0 -25
  75. data/spec/commands/theme/create_spec.rb +0 -41
  76. data/spec/commands/theme/enable_spec.rb +0 -44
  77. data/spec/commands/theme/install_spec.rb +0 -56
  78. data/spec/config_spec.rb +0 -127
  79. data/spec/model_factory.rb +0 -92
  80. data/spec/models_spec.rb +0 -700
  81. data/spec/overrides_spec.rb +0 -132
  82. data/spec/page_spec.rb +0 -560
  83. data/spec/path_spec.rb +0 -28
  84. data/spec/plugin_spec.rb +0 -51
  85. data/spec/sitemap_spec.rb +0 -105
  86. 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