mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-03-25 09:05:47 +00:00
Expand test coverage across generator and plugins
This commit is contained in:
parent
674fe01e04
commit
08bc3e4d99
17 changed files with 1275 additions and 0 deletions
|
|
@ -40,6 +40,215 @@ class Pressa::Config::LoaderTest < Minitest::Test
|
|||
end
|
||||
end
|
||||
|
||||
def test_build_site_raises_for_missing_projects_array
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
TOML
|
||||
File.write(File.join(dir, "projects.toml"), "title = \"no projects\"\n")
|
||||
|
||||
loader = Pressa::Config::Loader.new(source_path: dir)
|
||||
error = assert_raises(Pressa::Config::ValidationError) { loader.build_site }
|
||||
assert_match(/Missing required top-level array 'projects'/, error.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_build_site_raises_for_invalid_project_entries
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
TOML
|
||||
File.write(File.join(dir, "projects.toml"), <<~TOML)
|
||||
projects = [1]
|
||||
TOML
|
||||
|
||||
loader = Pressa::Config::Loader.new(source_path: dir)
|
||||
error = assert_raises(Pressa::Config::ValidationError) { loader.build_site }
|
||||
assert_match(/Project entry 1 must be a table/, error.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_build_site_raises_for_invalid_projects_plugin_type
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
projects_plugin = []
|
||||
TOML
|
||||
File.write(File.join(dir, "projects.toml"), <<~TOML)
|
||||
[[projects]]
|
||||
name = "demo"
|
||||
title = "demo"
|
||||
description = "demo project"
|
||||
url = "https://github.com/samsonjs/demo"
|
||||
TOML
|
||||
|
||||
loader = Pressa::Config::Loader.new(source_path: dir)
|
||||
error = assert_raises(Pressa::Config::ValidationError) { loader.build_site }
|
||||
assert_match(/Expected site\.toml projects_plugin to be a table/, error.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_build_site_raises_for_invalid_script_and_style_entries
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
scripts = [{}]
|
||||
styles = [123]
|
||||
TOML
|
||||
File.write(File.join(dir, "projects.toml"), <<~TOML)
|
||||
[[projects]]
|
||||
name = "demo"
|
||||
title = "demo"
|
||||
description = "demo project"
|
||||
url = "https://github.com/samsonjs/demo"
|
||||
TOML
|
||||
|
||||
loader = Pressa::Config::Loader.new(source_path: dir)
|
||||
script_error = assert_raises(Pressa::Config::ValidationError) { loader.build_site }
|
||||
assert_match(/Expected site\.toml scripts\[0\]\.src to be a String/, script_error.message)
|
||||
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
scripts = []
|
||||
styles = [123]
|
||||
TOML
|
||||
style_error = assert_raises(Pressa::Config::ValidationError) { loader.build_site }
|
||||
assert_match(/Expected site\.toml styles\[0\] to be a String or table/, style_error.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_build_site_accepts_script_hashes_and_absolute_image_url
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
image_url = "https://images.example.net/me.jpg"
|
||||
scripts = [{"src": "/js/site.js", "defer": false}]
|
||||
styles = [{"href": "/css/site.css"}]
|
||||
|
||||
[projects_plugin]
|
||||
scripts = [{"src": "/js/projects.js", "defer": true}]
|
||||
styles = [{"href": "/css/projects.css"}]
|
||||
TOML
|
||||
File.write(File.join(dir, "projects.toml"), <<~TOML)
|
||||
[[projects]]
|
||||
name = "demo"
|
||||
title = "demo"
|
||||
description = "demo project"
|
||||
url = "https://github.com/samsonjs/demo"
|
||||
TOML
|
||||
|
||||
loader = Pressa::Config::Loader.new(source_path: dir)
|
||||
site = loader.build_site
|
||||
|
||||
assert_equal("https://images.example.net/me.jpg", site.image_url)
|
||||
assert_equal(["/js/site.js"], site.scripts.map(&:src))
|
||||
assert_equal([false], site.scripts.map(&:defer))
|
||||
assert_equal(["/css/site.css"], site.styles.map(&:href))
|
||||
end
|
||||
end
|
||||
|
||||
def test_build_site_rewraps_toml_parse_errors_as_validation_errors
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), "author = \"unterminated\n")
|
||||
File.write(File.join(dir, "projects.toml"), <<~TOML)
|
||||
[[projects]]
|
||||
name = "demo"
|
||||
title = "demo"
|
||||
description = "demo project"
|
||||
url = "https://github.com/samsonjs/demo"
|
||||
TOML
|
||||
|
||||
loader = Pressa::Config::Loader.new(source_path: dir)
|
||||
error = assert_raises(Pressa::Config::ValidationError) { loader.build_site }
|
||||
assert_match(/Unterminated value for key 'author'/, error.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_build_site_rejects_non_boolean_defer_values
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
scripts = [{"src": "/js/site.js", "defer": "yes"}]
|
||||
TOML
|
||||
File.write(File.join(dir, "projects.toml"), <<~TOML)
|
||||
[[projects]]
|
||||
name = "demo"
|
||||
title = "demo"
|
||||
description = "demo project"
|
||||
url = "https://github.com/samsonjs/demo"
|
||||
TOML
|
||||
|
||||
loader = Pressa::Config::Loader.new(source_path: dir)
|
||||
error = assert_raises(Pressa::Config::ValidationError) { loader.build_site }
|
||||
assert_match(/Expected site\.toml scripts\[0\]\.defer to be a Boolean/, error.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_build_site_rejects_non_string_or_table_scripts_and_non_array_script_lists
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
scripts = [123]
|
||||
TOML
|
||||
File.write(File.join(dir, "projects.toml"), <<~TOML)
|
||||
[[projects]]
|
||||
name = "demo"
|
||||
title = "demo"
|
||||
description = "demo project"
|
||||
url = "https://github.com/samsonjs/demo"
|
||||
TOML
|
||||
|
||||
loader = Pressa::Config::Loader.new(source_path: dir)
|
||||
invalid_item = assert_raises(Pressa::Config::ValidationError) { loader.build_site }
|
||||
assert_match(/Expected site\.toml scripts\[0\] to be a String or table/, invalid_item.message)
|
||||
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
|
||||
[projects_plugin]
|
||||
scripts = "js/projects.js"
|
||||
TOML
|
||||
non_array = assert_raises(Pressa::Config::ValidationError) { loader.build_site }
|
||||
assert_match(/Expected site\.toml projects_plugin\.scripts to be an array/, non_array.message)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def with_temp_config
|
||||
|
|
|
|||
147
spec/config/simple_toml_test.rb
Normal file
147
spec/config/simple_toml_test.rb
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
require "test_helper"
|
||||
require "tmpdir"
|
||||
|
||||
class Pressa::Config::SimpleTomlTest < Minitest::Test
|
||||
def parser
|
||||
@parser ||= Pressa::Config::SimpleToml.new
|
||||
end
|
||||
|
||||
def test_load_file_raises_parse_error_for_missing_file
|
||||
Dir.mktmpdir do |dir|
|
||||
missing = File.join(dir, "missing.toml")
|
||||
|
||||
error = assert_raises(Pressa::Config::ParseError) do
|
||||
Pressa::Config::SimpleToml.load_file(missing)
|
||||
end
|
||||
|
||||
assert_match(/Config file not found/, error.message)
|
||||
end
|
||||
end
|
||||
|
||||
def test_parse_supports_tables_array_tables_comments_and_multiline_arrays
|
||||
content = <<~TOML
|
||||
title = "samhuri # not a comment"
|
||||
[projects_plugin]
|
||||
scripts = ["js/a.js", "js/b.js"]
|
||||
styles = [
|
||||
"css/a.css",
|
||||
"css/b.css"
|
||||
]
|
||||
|
||||
[[projects]]
|
||||
name = "alpha"
|
||||
title = "Alpha"
|
||||
description = "Project Alpha"
|
||||
url = "https://github.com/samsonjs/alpha"
|
||||
|
||||
[[projects]]
|
||||
name = "beta"
|
||||
title = "Beta"
|
||||
description = "Project Beta"
|
||||
url = "https://github.com/samsonjs/beta"
|
||||
TOML
|
||||
|
||||
parsed = parser.parse(content)
|
||||
|
||||
assert_equal("samhuri # not a comment", parsed["title"])
|
||||
assert_equal(["js/a.js", "js/b.js"], parsed.dig("projects_plugin", "scripts"))
|
||||
assert_equal(["css/a.css", "css/b.css"], parsed.dig("projects_plugin", "styles"))
|
||||
assert_equal(2, parsed["projects"].length)
|
||||
assert_equal("alpha", parsed["projects"][0]["name"])
|
||||
assert_equal("beta", parsed["projects"][1]["name"])
|
||||
end
|
||||
|
||||
def test_parse_rejects_duplicate_keys
|
||||
content = <<~TOML
|
||||
author = "Sami"
|
||||
author = "Sam"
|
||||
TOML
|
||||
|
||||
error = assert_raises(Pressa::Config::ParseError) { parser.parse(content) }
|
||||
assert_match(/Duplicate key 'author'/, error.message)
|
||||
end
|
||||
|
||||
def test_parse_rejects_invalid_assignment
|
||||
error = assert_raises(Pressa::Config::ParseError) { parser.parse("invalid") }
|
||||
assert_match(/Invalid assignment/, error.message)
|
||||
end
|
||||
|
||||
def test_parse_rejects_invalid_key_names
|
||||
error = assert_raises(Pressa::Config::ParseError) { parser.parse("bad-key = 1") }
|
||||
assert_match(/Invalid key/, error.message)
|
||||
end
|
||||
|
||||
def test_parse_rejects_missing_value
|
||||
error = assert_raises(Pressa::Config::ParseError) { parser.parse("author = ") }
|
||||
assert_match(/Missing value for key 'author'/, error.message)
|
||||
end
|
||||
|
||||
def test_parse_rejects_invalid_table_paths
|
||||
error = assert_raises(Pressa::Config::ParseError) { parser.parse("[projects..plugin]") }
|
||||
assert_match(/Invalid table path/, error.message)
|
||||
end
|
||||
|
||||
def test_parse_rejects_array_table_when_table_already_exists
|
||||
content = <<~TOML
|
||||
[projects]
|
||||
title = "single"
|
||||
[[projects]]
|
||||
title = "array item"
|
||||
TOML
|
||||
|
||||
error = assert_raises(Pressa::Config::ParseError) { parser.parse(content) }
|
||||
assert_match(/Expected array for '\[\[projects\]\]'/, error.message)
|
||||
end
|
||||
|
||||
def test_parse_rejects_nested_table_on_non_table_path
|
||||
content = <<~TOML
|
||||
projects = 1
|
||||
[projects.plugin]
|
||||
enabled = true
|
||||
TOML
|
||||
|
||||
error = assert_raises(Pressa::Config::ParseError) { parser.parse(content) }
|
||||
assert_match(/Expected table path 'projects.plugin'/, error.message)
|
||||
end
|
||||
|
||||
def test_parse_rejects_unsupported_value_types
|
||||
error = assert_raises(Pressa::Config::ParseError) do
|
||||
parser.parse("published_at = 2025-01-01")
|
||||
end
|
||||
|
||||
assert_match(/Unsupported TOML value/, error.message)
|
||||
end
|
||||
|
||||
def test_parse_rejects_unterminated_multiline_value
|
||||
content = <<~TOML
|
||||
scripts = [
|
||||
"a.js",
|
||||
"b.js"
|
||||
TOML
|
||||
|
||||
error = assert_raises(Pressa::Config::ParseError) { parser.parse(content) }
|
||||
assert_match(/Unterminated value for key 'scripts'/, error.message)
|
||||
end
|
||||
|
||||
def test_parse_ignores_comments_but_not_hashes_inside_strings
|
||||
content = <<~TOML
|
||||
url = "https://example.com/#anchor" # remove me
|
||||
TOML
|
||||
|
||||
parsed = parser.parse(content)
|
||||
assert_equal("https://example.com/#anchor", parsed["url"])
|
||||
end
|
||||
|
||||
def test_private_parsing_helpers_handle_escaped_quotes_inside_strings
|
||||
refute(parser.send(:needs_continuation?, "\"a\\\\\\\"b\""))
|
||||
|
||||
stripped = parser.send(:strip_comments, "title = \"a\\\\\\\"b # keep\" # drop\n")
|
||||
assert_equal("title = \"a\\\\\\\"b # keep\" ", stripped)
|
||||
|
||||
source = "\"a\\\\\\\"=b\" = 1"
|
||||
index = parser.send(:index_of_unquoted, source, "=")
|
||||
refute_nil(index)
|
||||
assert_equal("=", source[index])
|
||||
assert(index > source.rindex('"'))
|
||||
end
|
||||
end
|
||||
23
spec/plugin_test.rb
Normal file
23
spec/plugin_test.rb
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
require "test_helper"
|
||||
|
||||
class Pressa::PluginTest < Minitest::Test
|
||||
def test_setup_requires_subclass_implementation
|
||||
plugin = Pressa::Plugin.new
|
||||
|
||||
error = assert_raises(NotImplementedError) do
|
||||
plugin.setup(site: Object.new, source_path: "/tmp/source")
|
||||
end
|
||||
|
||||
assert_match(/Pressa::Plugin#setup must be implemented/, error.message)
|
||||
end
|
||||
|
||||
def test_render_requires_subclass_implementation
|
||||
plugin = Pressa::Plugin.new
|
||||
|
||||
error = assert_raises(NotImplementedError) do
|
||||
plugin.render(site: Object.new, target_path: "/tmp/target")
|
||||
end
|
||||
|
||||
assert_match(/Pressa::Plugin#render must be implemented/, error.message)
|
||||
end
|
||||
end
|
||||
|
|
@ -57,4 +57,12 @@ class Pressa::Posts::PostMetadataTest < Minitest::Test
|
|||
assert_equal([], metadata.tags)
|
||||
assert_nil(metadata.link)
|
||||
end
|
||||
|
||||
def test_parse_raises_error_when_front_matter_is_missing
|
||||
error = assert_raises(StandardError) do
|
||||
Pressa::Posts::PostMetadata.parse("just plain markdown")
|
||||
end
|
||||
|
||||
assert_match(/No YAML front-matter found in post/, error.message)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
76
spec/posts/models_test.rb
Normal file
76
spec/posts/models_test.rb
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
require "test_helper"
|
||||
|
||||
class Pressa::Posts::ModelsTest < Minitest::Test
|
||||
def regular_post
|
||||
@regular_post ||= Pressa::Posts::Post.new(
|
||||
slug: "regular",
|
||||
title: "Regular",
|
||||
author: "Sami Samhuri",
|
||||
date: DateTime.parse("2025-11-05T10:00:00-08:00"),
|
||||
formatted_date: "5th November, 2025",
|
||||
body: "<p>regular</p>",
|
||||
excerpt: "regular...",
|
||||
path: "/posts/2025/11/regular"
|
||||
)
|
||||
end
|
||||
|
||||
def link_post
|
||||
@link_post ||= Pressa::Posts::Post.new(
|
||||
slug: "linked",
|
||||
title: "Linked",
|
||||
author: "Sami Samhuri",
|
||||
date: DateTime.parse("2024-10-01T10:00:00-07:00"),
|
||||
formatted_date: "1st October, 2024",
|
||||
link: "https://example.net/post",
|
||||
body: "<p>linked</p>",
|
||||
excerpt: "linked...",
|
||||
path: "/posts/2024/10/linked"
|
||||
)
|
||||
end
|
||||
|
||||
def test_post_helpers_report_date_parts_and_link_state
|
||||
assert_equal(2025, regular_post.year)
|
||||
assert_equal(11, regular_post.month)
|
||||
assert_equal("November", regular_post.formatted_month)
|
||||
assert_equal("11", regular_post.padded_month)
|
||||
refute(regular_post.link_post?)
|
||||
assert(link_post.link_post?)
|
||||
end
|
||||
|
||||
def test_month_from_date_creates_expected_values
|
||||
month = Pressa::Posts::Month.from_date(DateTime.parse("2025-02-14T08:00:00-08:00"))
|
||||
assert_equal("February", month.name)
|
||||
assert_equal(2, month.number)
|
||||
assert_equal("02", month.padded)
|
||||
end
|
||||
|
||||
def test_month_posts_sorted_posts_returns_descending_by_date
|
||||
month_posts = Pressa::Posts::MonthPosts.new(
|
||||
month: Pressa::Posts::Month.new(name: "November", number: 11, padded: "11"),
|
||||
posts: [link_post, regular_post]
|
||||
)
|
||||
|
||||
assert_equal([regular_post, link_post], month_posts.sorted_posts)
|
||||
end
|
||||
|
||||
def test_year_posts_and_posts_by_year_sorting_helpers
|
||||
oct_posts = Pressa::Posts::MonthPosts.new(
|
||||
month: Pressa::Posts::Month.new(name: "October", number: 10, padded: "10"),
|
||||
posts: [link_post]
|
||||
)
|
||||
nov_posts = Pressa::Posts::MonthPosts.new(
|
||||
month: Pressa::Posts::Month.new(name: "November", number: 11, padded: "11"),
|
||||
posts: [regular_post]
|
||||
)
|
||||
|
||||
year_2025 = Pressa::Posts::YearPosts.new(year: 2025, by_month: {11 => nov_posts, 10 => oct_posts})
|
||||
year_2024 = Pressa::Posts::YearPosts.new(year: 2024, by_month: {10 => oct_posts})
|
||||
posts_by_year = Pressa::Posts::PostsByYear.new(by_year: {2024 => year_2024, 2025 => year_2025})
|
||||
|
||||
assert_equal([11, 10], year_2025.sorted_months.map { |mp| mp.month.number })
|
||||
assert_equal([regular_post, link_post], year_2025.all_posts)
|
||||
assert_equal([2025, 2024], posts_by_year.sorted_years)
|
||||
assert_equal(3, posts_by_year.all_posts.length)
|
||||
assert_equal([regular_post], posts_by_year.recent_posts(1))
|
||||
end
|
||||
end
|
||||
67
spec/posts/plugin_test.rb
Normal file
67
spec/posts/plugin_test.rb
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
require "test_helper"
|
||||
require "fileutils"
|
||||
require "tmpdir"
|
||||
|
||||
class Pressa::Posts::PluginTest < Minitest::Test
|
||||
def site
|
||||
@site ||= Pressa::Site.new(
|
||||
author: "Sami Samhuri",
|
||||
email: "sami@samhuri.net",
|
||||
title: "samhuri.net",
|
||||
description: "blog",
|
||||
url: "https://samhuri.net"
|
||||
)
|
||||
end
|
||||
|
||||
def test_setup_skips_when_posts_directory_does_not_exist
|
||||
Dir.mktmpdir do |source_path|
|
||||
plugin = Pressa::Posts::Plugin.new
|
||||
plugin.setup(site:, source_path:)
|
||||
|
||||
assert_nil(plugin.posts_by_year)
|
||||
end
|
||||
end
|
||||
|
||||
def test_render_skips_when_setup_did_not_load_posts
|
||||
Dir.mktmpdir do |target_path|
|
||||
plugin = Pressa::Posts::Plugin.new
|
||||
plugin.render(site:, target_path:)
|
||||
|
||||
refute(File.exist?(File.join(target_path, "index.html")))
|
||||
refute(File.exist?(File.join(target_path, "feed.json")))
|
||||
refute(File.exist?(File.join(target_path, "feed.xml")))
|
||||
end
|
||||
end
|
||||
|
||||
def test_setup_and_render_write_post_indexes_and_feeds
|
||||
Dir.mktmpdir do |root|
|
||||
source_path = File.join(root, "source")
|
||||
target_path = File.join(root, "target")
|
||||
posts_dir = File.join(source_path, "posts", "2025", "11")
|
||||
FileUtils.mkdir_p(posts_dir)
|
||||
|
||||
File.write(File.join(posts_dir, "shredding.md"), <<~MARKDOWN)
|
||||
---
|
||||
Title: Shredding in November
|
||||
Author: Shaun White
|
||||
Date: 5th November, 2025
|
||||
Timestamp: 2025-11-05T10:00:00-08:00
|
||||
---
|
||||
|
||||
Had an epic day at Whistler. The powder was deep and the lines were short.
|
||||
MARKDOWN
|
||||
|
||||
plugin = Pressa::Posts::Plugin.new
|
||||
plugin.setup(site:, source_path:)
|
||||
plugin.render(site:, target_path:)
|
||||
|
||||
assert(File.exist?(File.join(target_path, "index.html")))
|
||||
assert(File.exist?(File.join(target_path, "posts/index.html")))
|
||||
assert(File.exist?(File.join(target_path, "posts/2025/index.html")))
|
||||
assert(File.exist?(File.join(target_path, "posts/2025/11/index.html")))
|
||||
assert(File.exist?(File.join(target_path, "posts/2025/11/shredding/index.html")))
|
||||
assert(File.exist?(File.join(target_path, "feed.json")))
|
||||
assert(File.exist?(File.join(target_path, "feed.xml")))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -70,4 +70,39 @@ class Pressa::Posts::PostRepoTest < Minitest::Test
|
|||
refute_includes(post.excerpt, "[link]")
|
||||
end
|
||||
end
|
||||
|
||||
def test_read_posts_merges_multiple_posts_in_same_month
|
||||
Dir.mktmpdir do |tmpdir|
|
||||
posts_dir = File.join(tmpdir, "posts", "2025", "11")
|
||||
FileUtils.mkdir_p(posts_dir)
|
||||
|
||||
File.write(File.join(posts_dir, "first.md"), <<~MARKDOWN)
|
||||
---
|
||||
Title: First Post
|
||||
Author: Sami Samhuri
|
||||
Date: 5th November, 2025
|
||||
Timestamp: 2025-11-05T10:00:00-08:00
|
||||
---
|
||||
|
||||
First
|
||||
MARKDOWN
|
||||
|
||||
File.write(File.join(posts_dir, "second.md"), <<~MARKDOWN)
|
||||
---
|
||||
Title: Second Post
|
||||
Author: Sami Samhuri
|
||||
Date: 6th November, 2025
|
||||
Timestamp: 2025-11-06T10:00:00-08:00
|
||||
---
|
||||
|
||||
Second
|
||||
MARKDOWN
|
||||
|
||||
posts_by_year = repo.read_posts(File.join(tmpdir, "posts"))
|
||||
month_posts = posts_by_year.by_year.fetch(2025).by_month.fetch(11)
|
||||
|
||||
assert_equal(2, month_posts.posts.length)
|
||||
assert_equal(["Second Post", "First Post"], month_posts.sorted_posts.map(&:title))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
94
spec/posts/rss_feed_test.rb
Normal file
94
spec/posts/rss_feed_test.rb
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
require "test_helper"
|
||||
require "tmpdir"
|
||||
|
||||
class Pressa::Posts::RSSFeedWriterTest < Minitest::Test
|
||||
class PostsByYearStub
|
||||
attr_accessor :posts
|
||||
|
||||
def initialize(posts)
|
||||
@posts = posts
|
||||
end
|
||||
|
||||
def recent_posts(_limit = 30)
|
||||
@posts
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@site = Pressa::Site.new(
|
||||
author: "Sami Samhuri",
|
||||
email: "sami@samhuri.net",
|
||||
title: "samhuri.net",
|
||||
description: "blog",
|
||||
url: "https://samhuri.net"
|
||||
)
|
||||
@posts_by_year = PostsByYearStub.new([link_post])
|
||||
@writer = Pressa::Posts::RSSFeedWriter.new(site: @site, posts_by_year: @posts_by_year)
|
||||
end
|
||||
|
||||
def test_write_feed_for_link_post_uses_arrow_title_permalink_and_content
|
||||
Dir.mktmpdir do |dir|
|
||||
@writer.write_feed(target_path: dir, limit: 30)
|
||||
xml = File.read(File.join(dir, "feed.xml"))
|
||||
|
||||
assert_includes(xml, "<title>→ GitHub Flow Like a Pro</title>")
|
||||
assert_includes(xml, "<guid isPermaLink=\"true\">https://samhuri.net/posts/2015/05/github-flow-like-a-pro</guid>")
|
||||
assert_includes(xml, "https://samhuri.net/feed.xml")
|
||||
assert_includes(xml, "<author>Sami Samhuri</author>")
|
||||
assert_match(%r{<content:encoded>\s*<!\[CDATA\[}m, xml)
|
||||
end
|
||||
end
|
||||
|
||||
def test_write_feed_for_regular_post_uses_plain_title
|
||||
@posts_by_year.posts = [regular_post]
|
||||
|
||||
Dir.mktmpdir do |dir|
|
||||
@writer.write_feed(target_path: dir, limit: 30)
|
||||
xml = File.read(File.join(dir, "feed.xml"))
|
||||
|
||||
assert_includes(xml, "<title>Swift Optional OR</title>")
|
||||
refute_includes(xml, "→ Swift Optional OR")
|
||||
end
|
||||
end
|
||||
|
||||
def test_write_feed_without_posts_skips_channel_pub_date
|
||||
@posts_by_year.posts = []
|
||||
|
||||
Dir.mktmpdir do |dir|
|
||||
@writer.write_feed(target_path: dir, limit: 30)
|
||||
xml = File.read(File.join(dir, "feed.xml"))
|
||||
|
||||
assert_includes(xml, "<channel>")
|
||||
refute_match(%r{<channel>.*?<pubDate>.*?</pubDate>}m, xml)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def link_post
|
||||
Pressa::Posts::Post.new(
|
||||
slug: "github-flow-like-a-pro",
|
||||
title: "GitHub Flow Like a Pro",
|
||||
author: "Sami Samhuri",
|
||||
date: DateTime.parse("2015-05-28T07:42:27-07:00"),
|
||||
formatted_date: "28th May, 2015",
|
||||
link: "http://haacked.com/archive/2014/07/28/github-flow-aliases/",
|
||||
body: "<p>hello</p>",
|
||||
excerpt: "hello...",
|
||||
path: "/posts/2015/05/github-flow-like-a-pro"
|
||||
)
|
||||
end
|
||||
|
||||
def regular_post
|
||||
Pressa::Posts::Post.new(
|
||||
slug: "swift-optional-or",
|
||||
title: "Swift Optional OR",
|
||||
author: "Sami Samhuri",
|
||||
date: DateTime.parse("2017-10-01T10:00:00-07:00"),
|
||||
formatted_date: "1st October, 2017",
|
||||
body: "<p>hello</p>",
|
||||
excerpt: "hello...",
|
||||
path: "/posts/2017/10/swift-optional-or"
|
||||
)
|
||||
end
|
||||
end
|
||||
123
spec/posts/writer_test.rb
Normal file
123
spec/posts/writer_test.rb
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
require "test_helper"
|
||||
require "tmpdir"
|
||||
|
||||
class Pressa::Posts::PostWriterTest < Minitest::Test
|
||||
def site
|
||||
@site ||= Pressa::Site.new(
|
||||
author: "Sami Samhuri",
|
||||
email: "sami@samhuri.net",
|
||||
title: "samhuri.net",
|
||||
description: "blog",
|
||||
url: "https://samhuri.net"
|
||||
)
|
||||
end
|
||||
|
||||
def posts_by_year
|
||||
@posts_by_year ||= begin
|
||||
link_post = Pressa::Posts::Post.new(
|
||||
slug: "link-post",
|
||||
title: "Linked",
|
||||
author: "Sami Samhuri",
|
||||
date: DateTime.parse("2025-11-05T10:00:00-08:00"),
|
||||
formatted_date: "5th November, 2025",
|
||||
link: "https://example.net/linked",
|
||||
body: "<p>linked body</p>",
|
||||
excerpt: "linked body...",
|
||||
path: "/posts/2025/11/link-post"
|
||||
)
|
||||
regular_post = Pressa::Posts::Post.new(
|
||||
slug: "regular-post",
|
||||
title: "Regular",
|
||||
author: "Sami Samhuri",
|
||||
date: DateTime.parse("2024-10-01T10:00:00-07:00"),
|
||||
formatted_date: "1st October, 2024",
|
||||
body: "<p>regular body</p>",
|
||||
excerpt: "regular body...",
|
||||
path: "/posts/2024/10/regular-post"
|
||||
)
|
||||
|
||||
nov_posts = Pressa::Posts::MonthPosts.new(
|
||||
month: Pressa::Posts::Month.new(name: "November", number: 11, padded: "11"),
|
||||
posts: [link_post]
|
||||
)
|
||||
oct_posts = Pressa::Posts::MonthPosts.new(
|
||||
month: Pressa::Posts::Month.new(name: "October", number: 10, padded: "10"),
|
||||
posts: [regular_post]
|
||||
)
|
||||
|
||||
Pressa::Posts::PostsByYear.new(
|
||||
by_year: {
|
||||
2025 => Pressa::Posts::YearPosts.new(year: 2025, by_month: {11 => nov_posts}),
|
||||
2024 => Pressa::Posts::YearPosts.new(year: 2024, by_month: {10 => oct_posts})
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def writer
|
||||
@writer ||= Pressa::Posts::PostWriter.new(site:, posts_by_year:)
|
||||
end
|
||||
|
||||
def test_write_posts_writes_each_post_page
|
||||
Dir.mktmpdir do |dir|
|
||||
writer.write_posts(target_path: dir)
|
||||
|
||||
regular = File.join(dir, "posts/2024/10/regular-post/index.html")
|
||||
linked = File.join(dir, "posts/2025/11/link-post/index.html")
|
||||
|
||||
assert(File.exist?(regular))
|
||||
assert(File.exist?(linked))
|
||||
assert_includes(File.read(regular), "Regular")
|
||||
assert_includes(File.read(linked), "→ Linked")
|
||||
end
|
||||
end
|
||||
|
||||
def test_write_recent_posts_writes_index_page
|
||||
Dir.mktmpdir do |dir|
|
||||
writer.write_recent_posts(target_path: dir, limit: 1)
|
||||
|
||||
index_path = File.join(dir, "index.html")
|
||||
assert(File.exist?(index_path))
|
||||
html = File.read(index_path)
|
||||
assert_includes(html, "Linked")
|
||||
refute_includes(html, "Regular")
|
||||
end
|
||||
end
|
||||
|
||||
def test_write_archive_writes_archive_index
|
||||
Dir.mktmpdir do |dir|
|
||||
writer.write_archive(target_path: dir)
|
||||
|
||||
archive_path = File.join(dir, "posts/index.html")
|
||||
assert(File.exist?(archive_path))
|
||||
html = File.read(archive_path)
|
||||
assert_includes(html, "Archive")
|
||||
assert_includes(html, "https://samhuri.net/posts/2025/")
|
||||
end
|
||||
end
|
||||
|
||||
def test_write_year_indexes_writes_each_year_index
|
||||
Dir.mktmpdir do |dir|
|
||||
writer.write_year_indexes(target_path: dir)
|
||||
|
||||
path_2025 = File.join(dir, "posts/2025/index.html")
|
||||
path_2024 = File.join(dir, "posts/2024/index.html")
|
||||
assert(File.exist?(path_2025))
|
||||
assert(File.exist?(path_2024))
|
||||
assert_includes(File.read(path_2025), "November")
|
||||
end
|
||||
end
|
||||
|
||||
def test_write_month_rollups_writes_each_month_index
|
||||
Dir.mktmpdir do |dir|
|
||||
writer.write_month_rollups(target_path: dir)
|
||||
|
||||
nov = File.join(dir, "posts/2025/11/index.html")
|
||||
oct = File.join(dir, "posts/2024/10/index.html")
|
||||
assert(File.exist?(nov))
|
||||
assert(File.exist?(oct))
|
||||
assert_includes(File.read(nov), "November 2025")
|
||||
assert_includes(File.read(oct), "October 2024")
|
||||
end
|
||||
end
|
||||
end
|
||||
15
spec/projects/models_test.rb
Normal file
15
spec/projects/models_test.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
require "test_helper"
|
||||
|
||||
class Pressa::Projects::ModelsTest < Minitest::Test
|
||||
def test_project_helpers_compute_paths
|
||||
project = Pressa::Projects::Project.new(
|
||||
name: "demo",
|
||||
title: "Demo",
|
||||
description: "Demo project",
|
||||
url: "https://github.com/samsonjs/demo"
|
||||
)
|
||||
|
||||
assert_equal("samsonjs/demo", project.github_path)
|
||||
assert_equal("/projects/demo", project.path)
|
||||
end
|
||||
end
|
||||
55
spec/projects/plugin_test.rb
Normal file
55
spec/projects/plugin_test.rb
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
require "test_helper"
|
||||
require "tmpdir"
|
||||
|
||||
class Pressa::Projects::PluginTest < Minitest::Test
|
||||
def site
|
||||
@site ||= Pressa::Site.new(
|
||||
author: "Sami Samhuri",
|
||||
email: "sami@samhuri.net",
|
||||
title: "samhuri.net",
|
||||
description: "blog",
|
||||
url: "https://samhuri.net"
|
||||
)
|
||||
end
|
||||
|
||||
def project
|
||||
@project ||= Pressa::Projects::Project.new(
|
||||
name: "demo",
|
||||
title: "Demo",
|
||||
description: "Demo project",
|
||||
url: "https://github.com/samsonjs/demo"
|
||||
)
|
||||
end
|
||||
|
||||
def test_setup_is_a_no_op
|
||||
plugin = Pressa::Projects::Plugin.new(projects: [project])
|
||||
assert_nil(plugin.setup(site:, source_path: "/tmp/unused"))
|
||||
end
|
||||
|
||||
def test_render_writes_projects_index_and_project_page
|
||||
plugin = Pressa::Projects::Plugin.new(
|
||||
projects: [project],
|
||||
scripts: [Pressa::Script.new(src: "js/projects.js", defer: false)],
|
||||
styles: [Pressa::Stylesheet.new(href: "css/projects.css")]
|
||||
)
|
||||
|
||||
Dir.mktmpdir do |dir|
|
||||
plugin.render(site:, target_path: dir)
|
||||
|
||||
index_path = File.join(dir, "projects/index.html")
|
||||
project_path = File.join(dir, "projects/demo/index.html")
|
||||
|
||||
assert(File.exist?(index_path))
|
||||
assert(File.exist?(project_path))
|
||||
|
||||
index_html = File.read(index_path)
|
||||
details_html = File.read(project_path)
|
||||
|
||||
assert_includes(index_html, "Projects")
|
||||
assert_includes(index_html, "Demo")
|
||||
assert_includes(details_html, "Demo project")
|
||||
assert_includes(details_html, "js/projects.js")
|
||||
assert_includes(details_html, "css/projects.css")
|
||||
end
|
||||
end
|
||||
end
|
||||
113
spec/site_generator_rendering_test.rb
Normal file
113
spec/site_generator_rendering_test.rb
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
require "test_helper"
|
||||
require "fileutils"
|
||||
require "tmpdir"
|
||||
|
||||
class Pressa::SiteGeneratorRenderingTest < Minitest::Test
|
||||
class PluginSpy
|
||||
attr_reader :calls
|
||||
|
||||
def initialize
|
||||
@calls = []
|
||||
end
|
||||
|
||||
def setup(site:, source_path:)
|
||||
@calls << [:setup, site.title, source_path]
|
||||
end
|
||||
|
||||
def render(site:, target_path:)
|
||||
@calls << [:render, site.title, target_path]
|
||||
File.write(File.join(target_path, "plugin-output.txt"), "plugin rendered")
|
||||
end
|
||||
end
|
||||
|
||||
class MarkdownRendererSpy
|
||||
attr_reader :calls
|
||||
|
||||
def initialize
|
||||
@calls = []
|
||||
end
|
||||
|
||||
def can_render_file?(filename:, extension:)
|
||||
extension == "md" && !filename.start_with?("_")
|
||||
end
|
||||
|
||||
def render(site:, file_path:, target_dir:)
|
||||
@calls << [site.title, file_path, target_dir]
|
||||
FileUtils.mkdir_p(target_dir)
|
||||
slug = File.basename(file_path, ".md")
|
||||
File.write(File.join(target_dir, "#{slug}.html"), "rendered #{slug}")
|
||||
end
|
||||
end
|
||||
|
||||
def build_site(plugin:, renderer:)
|
||||
Pressa::Site.new(
|
||||
author: "Sami Samhuri",
|
||||
email: "sami@samhuri.net",
|
||||
title: "samhuri.net",
|
||||
description: "blog",
|
||||
url: "https://samhuri.net",
|
||||
plugins: [plugin],
|
||||
renderers: [renderer]
|
||||
)
|
||||
end
|
||||
|
||||
def test_generate_runs_plugins_copies_static_files_and_renders_supported_files
|
||||
Dir.mktmpdir do |root|
|
||||
source_path = File.join(root, "source")
|
||||
target_path = File.join(root, "target")
|
||||
public_dir = File.join(source_path, "public", "nested")
|
||||
FileUtils.mkdir_p(public_dir)
|
||||
|
||||
File.write(File.join(source_path, "public", "plain.txt"), "copy me")
|
||||
File.write(File.join(source_path, "public", "home.md"), "# home")
|
||||
File.write(File.join(source_path, "public", ".hidden"), "skip me")
|
||||
File.write(File.join(public_dir, "page.md"), "# title")
|
||||
File.write(File.join(public_dir, "_ignore.md"), "# ignored")
|
||||
|
||||
plugin = PluginSpy.new
|
||||
renderer = MarkdownRendererSpy.new
|
||||
site = build_site(plugin:, renderer:)
|
||||
|
||||
Pressa::SiteGenerator.new(site:).generate(source_path:, target_path:)
|
||||
|
||||
assert_equal(2, plugin.calls.length)
|
||||
assert_equal(:setup, plugin.calls[0][0])
|
||||
assert_equal(:render, plugin.calls[1][0])
|
||||
assert_equal("samhuri.net", renderer.calls.first[0])
|
||||
assert(renderer.calls.any? do |call|
|
||||
call[1].end_with?("/public/nested/page.md") &&
|
||||
File.expand_path(call[2]) == File.expand_path(File.join(target_path, "nested"))
|
||||
end)
|
||||
assert(renderer.calls.any? do |call|
|
||||
call[1].end_with?("/public/home.md") &&
|
||||
File.expand_path(call[2]) == File.expand_path(target_path)
|
||||
end)
|
||||
|
||||
assert(File.exist?(File.join(target_path, "plain.txt")))
|
||||
assert_equal("copy me", File.read(File.join(target_path, "plain.txt")))
|
||||
refute(File.exist?(File.join(target_path, ".hidden")))
|
||||
refute(File.exist?(File.join(target_path, "nested", "page.md")))
|
||||
assert(File.exist?(File.join(target_path, "home.html")))
|
||||
assert(File.exist?(File.join(target_path, "nested", "page.html")))
|
||||
refute(File.exist?(File.join(target_path, "nested", "_ignore.html")))
|
||||
assert(File.exist?(File.join(target_path, "plugin-output.txt")))
|
||||
end
|
||||
end
|
||||
|
||||
def test_generate_handles_missing_public_directory
|
||||
Dir.mktmpdir do |root|
|
||||
source_path = File.join(root, "source")
|
||||
target_path = File.join(root, "target")
|
||||
FileUtils.mkdir_p(source_path)
|
||||
|
||||
plugin = PluginSpy.new
|
||||
renderer = MarkdownRendererSpy.new
|
||||
site = build_site(plugin:, renderer:)
|
||||
|
||||
Pressa::SiteGenerator.new(site:).generate(source_path:, target_path:)
|
||||
|
||||
assert(File.exist?(File.join(target_path, "plugin-output.txt")))
|
||||
assert_empty(renderer.calls)
|
||||
end
|
||||
end
|
||||
end
|
||||
52
spec/site_test.rb
Normal file
52
spec/site_test.rb
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
require "test_helper"
|
||||
require "tmpdir"
|
||||
|
||||
class Pressa::SiteTest < Minitest::Test
|
||||
def test_url_helpers
|
||||
site = Pressa::Site.new(
|
||||
author: "Sami Samhuri",
|
||||
email: "sami@samhuri.net",
|
||||
title: "samhuri.net",
|
||||
description: "blog",
|
||||
url: "https://samhuri.net",
|
||||
image_url: "https://images.example.net"
|
||||
)
|
||||
|
||||
assert_equal("https://samhuri.net/posts", site.url_for("/posts"))
|
||||
assert_equal("https://images.example.net/avatar.png", site.image_url_for("/avatar.png"))
|
||||
end
|
||||
|
||||
def test_image_url_for_returns_nil_when_image_url_not_configured
|
||||
site = Pressa::Site.new(
|
||||
author: "Sami Samhuri",
|
||||
email: "sami@samhuri.net",
|
||||
title: "samhuri.net",
|
||||
description: "blog",
|
||||
url: "https://samhuri.net"
|
||||
)
|
||||
|
||||
assert_nil(site.image_url_for("/avatar.png"))
|
||||
end
|
||||
|
||||
def test_create_site_builds_site_using_loader
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
TOML
|
||||
File.write(File.join(dir, "projects.toml"), <<~TOML)
|
||||
[[projects]]
|
||||
name = "demo"
|
||||
title = "demo"
|
||||
description = "demo project"
|
||||
url = "https://github.com/samsonjs/demo"
|
||||
TOML
|
||||
|
||||
site = Pressa.create_site(source_path: dir, url_override: "https://beta.samhuri.net")
|
||||
assert_equal("https://beta.samhuri.net", site.url)
|
||||
end
|
||||
end
|
||||
end
|
||||
25
spec/utils/file_writer_test.rb
Normal file
25
spec/utils/file_writer_test.rb
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
require "test_helper"
|
||||
require "tmpdir"
|
||||
|
||||
class Pressa::Utils::FileWriterTest < Minitest::Test
|
||||
def test_write_creates_directories_writes_content_and_sets_permissions
|
||||
Dir.mktmpdir do |dir|
|
||||
path = File.join(dir, "nested", "file.txt")
|
||||
Pressa::Utils::FileWriter.write(path:, content: "hello", permissions: 0o600)
|
||||
|
||||
assert_equal("hello", File.read(path))
|
||||
assert_equal("600", format("%o", File.stat(path).mode & 0o777))
|
||||
end
|
||||
end
|
||||
|
||||
def test_write_data_writes_binary_content_and_sets_permissions
|
||||
Dir.mktmpdir do |dir|
|
||||
path = File.join(dir, "nested", "data.bin")
|
||||
data = "\x00\xFFabc".b
|
||||
Pressa::Utils::FileWriter.write_data(path:, data:, permissions: 0o640)
|
||||
|
||||
assert_equal(data, File.binread(path))
|
||||
assert_equal("640", format("%o", File.stat(path).mode & 0o777))
|
||||
end
|
||||
end
|
||||
end
|
||||
94
spec/utils/markdown_renderer_test.rb
Normal file
94
spec/utils/markdown_renderer_test.rb
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
require "test_helper"
|
||||
require "fileutils"
|
||||
require "tmpdir"
|
||||
|
||||
class Pressa::Utils::MarkdownRendererTest < Minitest::Test
|
||||
def renderer
|
||||
@renderer ||= Pressa::Utils::MarkdownRenderer.new
|
||||
end
|
||||
|
||||
def site
|
||||
@site ||= Pressa::Site.new(
|
||||
author: "Sami Samhuri",
|
||||
email: "sami@samhuri.net",
|
||||
title: "samhuri.net",
|
||||
description: "blog",
|
||||
url: "https://samhuri.net"
|
||||
)
|
||||
end
|
||||
|
||||
def test_can_render_file_checks_md_extension
|
||||
assert(renderer.can_render_file?(filename: "about.md", extension: "md"))
|
||||
refute(renderer.can_render_file?(filename: "about.txt", extension: "txt"))
|
||||
end
|
||||
|
||||
def test_render_writes_pretty_url_output_by_default
|
||||
Dir.mktmpdir do |dir|
|
||||
source_file = File.join(dir, "public", "about.md")
|
||||
target_dir = File.join(dir, "www")
|
||||
FileUtils.mkdir_p(File.dirname(source_file))
|
||||
|
||||
File.write(source_file, <<~MARKDOWN)
|
||||
---
|
||||
Title: About
|
||||
Description: About page
|
||||
---
|
||||
|
||||
This is [my bio](https://example.net).
|
||||
MARKDOWN
|
||||
|
||||
renderer.render(site:, file_path: source_file, target_dir:)
|
||||
|
||||
output_file = File.join(target_dir, "about", "index.html")
|
||||
assert(File.exist?(output_file))
|
||||
|
||||
html = File.read(output_file)
|
||||
assert_includes(html, "<title>samhuri.net: About</title>")
|
||||
assert_includes(html, "<meta name=\"description\" content=\"About page\">")
|
||||
assert_includes(html, "<meta property=\"og:type\" content=\"website\">")
|
||||
end
|
||||
end
|
||||
|
||||
def test_render_writes_html_extension_when_enabled_and_uses_fallbacks
|
||||
Dir.mktmpdir do |dir|
|
||||
source_file = File.join(dir, "public", "docs", "readme.md")
|
||||
target_dir = File.join(dir, "www", "docs")
|
||||
FileUtils.mkdir_p(File.dirname(source_file))
|
||||
|
||||
File.write(source_file, <<~MARKDOWN)
|
||||
---
|
||||
Show extension: yes
|
||||
Page type: article
|
||||
---
|
||||
|
||||
Hello <strong>world</strong>. This is an  excerpt with [a link](https://example.net).
|
||||
MARKDOWN
|
||||
|
||||
renderer.render(site:, file_path: source_file, target_dir:)
|
||||
|
||||
output_file = File.join(target_dir, "readme.html")
|
||||
assert(File.exist?(output_file))
|
||||
|
||||
html = File.read(output_file)
|
||||
assert_includes(html, "<title>samhuri.net: Readme</title>")
|
||||
assert_includes(html, "<meta property=\"og:type\" content=\"article\">")
|
||||
assert_includes(html, "<meta name=\"description\" content=\"Hello world. This is an excerpt with a link....\">")
|
||||
assert_includes(html, "<link rel=\"canonical\" href=\"https://samhuri.net/docs/readme.html\">")
|
||||
end
|
||||
end
|
||||
|
||||
def test_render_without_front_matter_uses_filename_title
|
||||
Dir.mktmpdir do |dir|
|
||||
source_file = File.join(dir, "public", "notes.md")
|
||||
target_dir = File.join(dir, "www")
|
||||
FileUtils.mkdir_p(File.dirname(source_file))
|
||||
|
||||
File.write(source_file, "hello from markdown")
|
||||
renderer.render(site:, file_path: source_file, target_dir:)
|
||||
|
||||
html = File.read(File.join(target_dir, "notes", "index.html"))
|
||||
assert_includes(html, "<title>samhuri.net: Notes</title>")
|
||||
assert_includes(html, "<h1>Notes</h1>")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -63,4 +63,14 @@ class Pressa::Views::LayoutTest < Minitest::Test
|
|||
|
||||
assert_includes(html, %(<link rel="stylesheet" type="text/css" href="https://cdn.example.com/site.css">))
|
||||
end
|
||||
|
||||
def test_format_output_is_enabled
|
||||
layout = Pressa::Views::Layout.new(
|
||||
site:,
|
||||
canonical_url: "https://samhuri.net/posts/",
|
||||
content: content_view
|
||||
)
|
||||
|
||||
assert(layout.format_output?)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
129
spec/views/rendering_test.rb
Normal file
129
spec/views/rendering_test.rb
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
require "test_helper"
|
||||
|
||||
class Pressa::Views::RenderingTest < Minitest::Test
|
||||
def site
|
||||
@site ||= Pressa::Site.new(
|
||||
author: "Sami Samhuri",
|
||||
email: "sami@samhuri.net",
|
||||
title: "samhuri.net",
|
||||
description: "blog",
|
||||
url: "https://samhuri.net"
|
||||
)
|
||||
end
|
||||
|
||||
def regular_post
|
||||
@regular_post ||= Pressa::Posts::Post.new(
|
||||
slug: "swift-optional-or",
|
||||
title: "Swift Optional OR",
|
||||
author: "Sami Samhuri",
|
||||
date: DateTime.parse("2017-10-01T10:00:00-07:00"),
|
||||
formatted_date: "1st October, 2017",
|
||||
body: "<p>hello</p>",
|
||||
excerpt: "hello...",
|
||||
path: "/posts/2017/10/swift-optional-or"
|
||||
)
|
||||
end
|
||||
|
||||
def link_post
|
||||
@link_post ||= Pressa::Posts::Post.new(
|
||||
slug: "github-flow-like-a-pro",
|
||||
title: "GitHub Flow Like a Pro",
|
||||
author: "Sami Samhuri",
|
||||
date: DateTime.parse("2015-05-28T07:42:27-07:00"),
|
||||
formatted_date: "28th May, 2015",
|
||||
link: "http://haacked.com/archive/2014/07/28/github-flow-aliases/",
|
||||
body: "<p>hello</p>",
|
||||
excerpt: "hello...",
|
||||
path: "/posts/2015/05/github-flow-like-a-pro"
|
||||
)
|
||||
end
|
||||
|
||||
def test_post_view_renders_regular_post_and_article_class
|
||||
html = Pressa::Views::PostView.new(
|
||||
post: regular_post,
|
||||
site:,
|
||||
article_class: "container"
|
||||
).call
|
||||
|
||||
assert_includes(html, "<article class=\"container\">")
|
||||
assert_includes(html, "<a href=\"/posts/2017/10/swift-optional-or\">Swift Optional OR</a>")
|
||||
assert_includes(html, "<a href=\"/posts/2017/10/swift-optional-or\" class=\"permalink\">∞</a>")
|
||||
end
|
||||
|
||||
def test_post_view_renders_link_post_title_with_arrow
|
||||
html = Pressa::Views::PostView.new(post: link_post, site:).call
|
||||
|
||||
assert_includes(html, "→ GitHub Flow Like a Pro")
|
||||
assert_includes(html, "http://haacked.com/archive/2014/07/28/github-flow-aliases/")
|
||||
end
|
||||
|
||||
def test_feed_post_view_expands_root_relative_urls_only
|
||||
post = Pressa::Posts::Post.new(
|
||||
slug: "with-assets",
|
||||
title: "With Assets",
|
||||
author: "Sami Samhuri",
|
||||
date: DateTime.parse("2017-10-01T10:00:00-07:00"),
|
||||
formatted_date: "1st October, 2017",
|
||||
body: '<p><a href="/posts/2010/01/basics-of-the-mach-o-file-format">read</a></p>' \
|
||||
'<p><img src="/images/me.jpg" alt="me"></p>' \
|
||||
'<p><a href="//cdn.example.net/app.js">cdn</a></p>',
|
||||
excerpt: "hello...",
|
||||
path: "/posts/2017/10/with-assets"
|
||||
)
|
||||
|
||||
html = Pressa::Views::FeedPostView.new(post:, site:).call
|
||||
|
||||
assert_includes(html, 'href="https://samhuri.net/posts/2010/01/basics-of-the-mach-o-file-format"')
|
||||
assert_includes(html, 'src="https://samhuri.net/images/me.jpg"')
|
||||
assert_includes(html, 'href="//cdn.example.net/app.js"')
|
||||
end
|
||||
|
||||
def test_project_and_projects_views_render_project_links_and_stats
|
||||
project = Pressa::Projects::Project.new(
|
||||
name: "demo",
|
||||
title: "Demo Project",
|
||||
description: "Demo project description",
|
||||
url: "https://github.com/samsonjs/demo"
|
||||
)
|
||||
|
||||
listing = Pressa::Views::ProjectsView.new(projects: [project], site:).call
|
||||
details = Pressa::Views::ProjectView.new(project:, site:).call
|
||||
|
||||
assert_includes(listing, "Demo Project")
|
||||
assert_includes(listing, "https://samhuri.net/projects/demo")
|
||||
assert_includes(details, "https://github.com/samsonjs/demo/stargazers")
|
||||
assert_includes(details, "https://github.com/samsonjs/demo/network/members")
|
||||
end
|
||||
|
||||
def test_archive_views_render_year_month_and_both_post_types
|
||||
may_posts = Pressa::Posts::MonthPosts.new(
|
||||
month: Pressa::Posts::Month.new(name: "May", number: 5, padded: "05"),
|
||||
posts: [link_post]
|
||||
)
|
||||
oct_posts = Pressa::Posts::MonthPosts.new(
|
||||
month: Pressa::Posts::Month.new(name: "October", number: 10, padded: "10"),
|
||||
posts: [regular_post]
|
||||
)
|
||||
|
||||
by_year = {
|
||||
2017 => Pressa::Posts::YearPosts.new(year: 2017, by_month: {10 => oct_posts}),
|
||||
2015 => Pressa::Posts::YearPosts.new(year: 2015, by_month: {5 => may_posts})
|
||||
}
|
||||
posts_by_year = Pressa::Posts::PostsByYear.new(by_year:)
|
||||
|
||||
year_html = Pressa::Views::YearPostsView.new(year: 2015, year_posts: by_year[2015], site:).call
|
||||
month_html = Pressa::Views::MonthPostsView.new(year: 2017, month_posts: oct_posts, site:).call
|
||||
recent_html = Pressa::Views::RecentPostsView.new(posts: [regular_post], site:).call
|
||||
archive_html = Pressa::Views::ArchiveView.new(posts_by_year:, site:).call
|
||||
|
||||
assert_includes(year_html, "https://samhuri.net/posts/2015/05/")
|
||||
assert_includes(year_html, "→ GitHub Flow Like a Pro")
|
||||
assert_match(%r{<a (?=[^>]*class="permalink")(?=[^>]*href="/posts/2015/05/github-flow-like-a-pro")[^>]*>∞</a>}, year_html)
|
||||
|
||||
assert_includes(month_html, "October 2017")
|
||||
assert_includes(recent_html, "Swift Optional OR")
|
||||
assert_includes(archive_html, "Archive")
|
||||
assert_includes(archive_html, "https://samhuri.net/posts/2017/")
|
||||
assert_includes(archive_html, "https://samhuri.net/posts/2015/")
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue