summaryrefslogtreecommitdiff
path: root/test/models
diff options
context:
space:
mode:
Diffstat (limited to 'test/models')
-rw-r--r--test/models/asset_license_test.rb31
-rw-r--r--test/models/asset_test.rb35
-rw-r--r--test/models/helpers/content_helper_test.rb124
-rw-r--r--test/models/node_attach_asset_test.rb107
-rw-r--r--test/models/node_test.rb35
-rw-r--r--test/models/page_test.rb8
-rw-r--r--test/models/related_asset_test.rb54
7 files changed, 360 insertions, 34 deletions
diff --git a/test/models/asset_license_test.rb b/test/models/asset_license_test.rb
new file mode 100644
index 0000000..9f2d04f
--- /dev/null
+++ b/test/models/asset_license_test.rb
@@ -0,0 +1,31 @@
1require 'test_helper'
2
3class AssetLicenseTest < ActiveSupport::TestCase
4 test "find returns a populated entry for a known key" do
5 entry = AssetLicense.find("cc_by_4")
6
7 assert_equal "cc_by_4", entry.key
8 assert_equal "https://creativecommons.org/licenses/by/4.0/", entry.url
9 assert entry.requires_attribution
10 assert_equal "license", entry.style
11 end
12
13 test "find returns nil for an unknown or blank key" do
14 assert_nil AssetLicense.find("not_a_real_license")
15 assert_nil AssetLicense.find(nil)
16 assert_nil AssetLicense.find("")
17 end
18
19 test "keys includes every dictionary entry" do
20 assert_includes AssetLicense.keys, "cc0"
21 assert_includes AssetLicense.keys, "own_work"
22 end
23
24 test "a note-style entry has no attribution requirement and no url" do
25 entry = AssetLicense.find("own_work")
26
27 assert_not entry.requires_attribution
28 assert_nil entry.url
29 assert_equal "note", entry.style
30 end
31end
diff --git a/test/models/asset_test.rb b/test/models/asset_test.rb
index a1041e4..ab1cc5d 100644
--- a/test/models/asset_test.rb
+++ b/test/models/asset_test.rb
@@ -19,5 +19,38 @@ class AssetTest < ActiveSupport::TestCase
19 assert_equal 0, draft.assets.length 19 assert_equal 0, draft.assets.length
20 assert_equal 0, RelatedAsset.count 20 assert_equal 0, RelatedAsset.count
21 end 21 end
22 22
23 test "image? is true for supported image content types" do
24 assert Asset.new(:upload_content_type => "image/png").image?
25 assert Asset.new(:upload_content_type => "image/jpeg").image?
26 end
27
28 test "image? is false for non-image content types" do
29 assert_not Asset.new(:upload_content_type => "application/pdf").image?
30 assert_not Asset.new(:upload_content_type => nil).image?
31 end
32
33 test "license_key must be a known dictionary key" do
34 asset = Asset.new(:license_key => "not_a_real_license")
35 I18n.with_locale(:en) do
36 assert_not asset.valid?
37 assert_includes asset.errors[:license_key], "is not included in the list"
38 end
39 end
40
41 test "license_key may be blank" do
42 assert Asset.new(:license_key => nil).valid?
43 end
44
45 test "pdf? is true only for application/pdf" do
46 assert Asset.new(:upload_content_type => "application/pdf").pdf?
47 assert_not Asset.new(:upload_content_type => "image/png").pdf?
48 end
49
50 test "show_credit? is false for a PDF even with every credit field present" do
51 asset = Asset.new(:name => "demo", :upload_content_type => "application/pdf",
52 :creator => "Jane Doe", :source_url => "https://example.org", :license_key => "cc_by_4")
53 assert asset.has_credit?
54 assert_not asset.show_credit?
55 end
23end 56end
diff --git a/test/models/helpers/content_helper_test.rb b/test/models/helpers/content_helper_test.rb
index a7ed478..c69ef4e 100644
--- a/test/models/helpers/content_helper_test.rb
+++ b/test/models/helpers/content_helper_test.rb
@@ -2,7 +2,127 @@ require 'test_helper'
2 2
3class ContentHelperTest < ActionView::TestCase 3class ContentHelperTest < ActionView::TestCase
4 test "weekday_abbr delegates through the current I18n locale" do 4 test "weekday_abbr delegates through the current I18n locale" do
5 I18n.locale = :de 5 I18n.with_locale(:de) do
6 assert_equal "Mo", weekday_abbr(Time.parse("2026-07-06")) 6 assert_equal "Mo", weekday_abbr(Time.parse("2026-07-06"))
7 end
8 end
9
10 test "asset_credit returns nil for a nil asset" do
11 assert_nil asset_credit(nil)
12 end
13
14 test "asset_credit returns nil when creator, source, and license are all blank" do
15 assert_nil asset_credit(Asset.new(:name => "blank"))
16 end
17
18 test "asset_credit renders creator, source link, and license link when all are present" do
19 asset = Asset.new(:name => "demo", :creator => "Jane Doe",
20 :source_url => "https://example.org/photo", :license_key => "cc_by_4")
21
22 result = I18n.with_locale(:en) { asset_credit(asset) }
23
24 assert_match %r{<a href="https://example.org/photo">Photo demo</a>}, result
25 assert_match "by Jane Doe", result
26 assert_match %r{<a href="https://creativecommons.org/licenses/by/4.0/">Licensed under CC BY 4.0</a>}, result
27 end
28
29 test "asset_credit falls back to plain text when source_url is blank" do
30 asset = Asset.new(:name => "demo", :creator => "Jane Doe", :license_key => "cc_by_4")
31 assert_no_match %r{<a href="[^"]*">Photo demo</a>}, I18n.with_locale(:en) { asset_credit(asset) }
32 end
33
34 test "asset_credit omits the 'by' clause when creator is blank" do
35 asset = Asset.new(:name => "demo", :source_url => "https://example.org/photo", :license_key => "cc_by_4")
36 assert_no_match "by ", I18n.with_locale(:en) { asset_credit(asset) }
37 end
38
39 test "a note-style license renders with no 'Licensed under' prefix and no link" do
40 asset = Asset.new(:name => "demo", :creator => "CCC", :license_key => "own_work")
41 result = I18n.with_locale(:en) { asset_credit(asset) }
42
43 assert_match "Own work", result
44 assert_no_match "Licensed under", result
45 assert_no_match "<a", result
46 end
47
48 test "asset_credit degrades gracefully when the license_key is no longer in the dictionary" do
49 asset = Asset.new(:name => "demo", :creator => "Jane Doe")
50 asset.license_key = "a_retired_key"
51
52 result = I18n.with_locale(:en) { asset_credit(asset) }
53
54 assert_match "Photo demo by Jane Doe", result
55 assert_no_match "Licensed under", result
56 end
57
58 test "headline_image renders nothing when no images are attached" do
59 node = Node.root.children.create!(:slug => "headline_image_empty_test")
60 @page = node.draft
61 assert_nil headline_image
62 end
63
64 test "headline_image renders the flagged headline asset" do
65 node = Node.root.children.create!(:slug => "headline_image_flagged_test")
66 asset = Asset.create!(:name => "flagged", :upload_content_type => "image/png")
67 node.draft.assets << asset
68 node.draft.related_assets.find_by(:asset_id => asset.id).update!(:headline => true)
69 @page = node.draft
70
71 assert_match "glightbox", headline_image
72 end
73
74 test "headline_image falls back to a gallery-open caption when no headline is flagged" do
75 node = Node.root.children.create!(:slug => "headline_image_no_flag_test")
76 asset = Asset.create!(:name => "unflagged", :upload_content_type => "image/png")
77 node.draft.assets << asset
78 @page = node.draft
79
80 I18n.with_locale(:en) { assert_match t(:open_gallery), headline_image }
81 end
82
83 test "headline_image renders a document card for a PDF headline, not a lightbox image" do
84 node = Node.root.children.create!(:slug => "headline_image_pdf_test")
85 asset = Asset.create!(:name => "Expert Opinion", :upload_content_type => "application/pdf")
86 node.draft.assets << asset
87 node.draft.related_assets.find_by(:asset_id => asset.id).update!(:headline => true)
88 @page = node.draft
89
90 result = headline_image
91
92 assert_match "headline_document_card", result
93 assert_match "Expert Opinion", result
94 assert_no_match "data-gallery", result
95 end
96
97 test "headline_image lists other attached PDFs below the headline" do
98 node = Node.root.children.create!(:slug => "headline_image_multi_pdf_test")
99 headline_pdf = Asset.create!(:name => "Main Filing", :upload_content_type => "application/pdf")
100 other_pdf = Asset.create!(:name => "Supplementary Exhibit", :upload_content_type => "application/pdf")
101 node.draft.assets << headline_pdf
102 node.draft.assets << other_pdf
103 node.draft.related_assets.find_by(:asset_id => headline_pdf.id).update!(:headline => true)
104 @page = node.draft
105
106 result = headline_image
107
108 assert_match "Main Filing", result
109 assert_match "Supplementary Exhibit", result
110 assert_match "headline_document_card", result
111 assert_match "related_documents_list", result
112 end
113
114 test "headline_image lists attached PDFs even with no headline chosen" do
115 node = Node.root.children.create!(:slug => "headline_image_pdf_no_headline_test")
116 pdf_a = Asset.create!(:name => "Document A", :upload_content_type => "application/pdf")
117 pdf_b = Asset.create!(:name => "Document B", :upload_content_type => "application/pdf")
118 node.draft.assets << pdf_a
119 node.draft.assets << pdf_b
120 @page = node.draft
121
122 result = headline_image
123
124 assert_no_match "headline_document_card", result
125 assert_match "Document A", result
126 assert_match "Document B", result
7 end 127 end
8end 128end
diff --git a/test/models/node_attach_asset_test.rb b/test/models/node_attach_asset_test.rb
new file mode 100644
index 0000000..cb5b60f
--- /dev/null
+++ b/test/models/node_attach_asset_test.rb
@@ -0,0 +1,107 @@
1require "test_helper"
2
3class NodeAttachAssetTest < ActiveSupport::TestCase
4
5 def setup
6 @user = users(:quentin)
7 @other = users(:aaron)
8 @node = Node.root.children.create!(:slug => "attach_asset_test")
9 @image = create_image_asset
10 end
11
12 test "attaches to a draft-only node" do
13 result = @node.attach_asset!(@image, :user => @user)
14 assert_equal 1, result[:attached]
15 assert_includes @node.draft.assets, @image
16 end
17
18 test "attaches to head when no draft is pending" do
19 @node.publish_draft!(@user)
20 result = @node.attach_asset!(@image, :user => @user)
21 assert_equal 1, result[:attached]
22 assert_includes @node.head.assets, @image
23 end
24
25 test "attaches to head and pending draft alike" do
26 @node.publish_draft!(@user)
27 @node.lock_for_editing!(@user)
28 @node.create_new_draft(@user)
29 result = @node.attach_asset!(@image, :user => @user)
30 assert_equal 2, result[:attached]
31 assert_includes @node.head.assets, @image
32 assert_includes @node.draft.assets, @image
33 end
34
35 test "attaches to all three lifecycle rows" do
36 @node.publish_draft!(@user)
37 @node.lock_for_editing!(@user)
38 @node.create_new_draft(@user)
39 @node.autosave!({ :title => "wip" }, @user)
40 result = @node.attach_asset!(@image, :user => @user)
41 assert_equal 3, result[:attached]
42 [@node.head, @node.draft, @node.autosave].each do |row|
43 assert_includes row.assets, @image
44 end
45 end
46
47 test "skips rows that already carry the asset" do
48 @node.draft.related_assets.create!(:asset => @image)
49 @node.publish_draft!(@user)
50 @node.lock_for_editing!(@user)
51 @node.create_new_draft(@user)
52 result = @node.attach_asset!(@image, :user => @user)
53 assert_equal 0, result[:attached]
54 assert_equal 2, result[:already]
55 assert_equal 1, @node.draft.related_assets.where(:asset_id => @image.id).count
56 end
57
58 test "refuses when another user holds the lock and writes nothing" do
59 @node.lock_for_editing!(@other)
60 assert_raises(LockedByAnotherUser) { @node.attach_asset!(@image, :user => @user) }
61 assert_empty @node.draft.assets.reload
62 end
63
64 test "proceeds when the attaching user holds the lock" do
65 @node.lock_for_editing!(@user)
66 result = @node.attach_asset!(@image, :user => @user)
67 assert_equal 1, result[:attached]
68 end
69
70 test "sets the headline when none exists" do
71 result = @node.attach_asset!(@image, :user => @user, :headline => true)
72 assert_equal :set, result[:headline]
73 assert_equal @image, @node.draft.headline_asset
74 end
75
76 test "keeps an existing headline and reports it" do
77 incumbent = create_image_asset
78 @node.draft.related_assets.create!(:asset => incumbent, :headline => true)
79 result = @node.attach_asset!(@image, :user => @user, :headline => true)
80 assert_equal :kept_existing, result[:headline]
81 assert_equal incumbent, @node.draft.reload.headline_asset
82 assert_includes @node.draft.assets, @image
83 end
84
85 test "declines the headline flag for ineligible asset types" do
86 plain = create_plain_asset
87 result = @node.attach_asset!(plain, :user => @user, :headline => true)
88 assert_equal :not_eligible, result[:headline]
89 assert_includes @node.draft.assets.reload, plain
90 assert_nil @node.draft.headline_asset
91 end
92
93 test "refuses nodes in the Trash" do
94 @node.trash!(@user)
95 assert_raises(ActiveRecord::RecordInvalid) { @node.attach_asset!(@image, :user => @user) }
96 end
97
98 private
99
100 def create_image_asset
101 Asset.create!(:name => "attach test image", :upload_content_type => "image/png")
102 end
103
104 def create_plain_asset
105 Asset.create!(:name => "attach test note", :upload_content_type => "text/plain")
106 end
107end
diff --git a/test/models/node_test.rb b/test/models/node_test.rb
index ab66f81..ba38340 100644
--- a/test/models/node_test.rb
+++ b/test/models/node_test.rb
@@ -268,7 +268,6 @@ class NodeTest < ActiveSupport::TestCase
268 assert_equal "quentin", node.head.user.login 268 assert_equal "quentin", node.head.user.login
269 end 269 end
270 270
271
272 test "update?" do 271 test "update?" do
273 Node.root.descendants.delete_all 272 Node.root.descendants.delete_all
274 updates = Node.root.children.create!( :slug => "updates" ) 273 updates = Node.root.children.create!( :slug => "updates" )
@@ -359,6 +358,16 @@ class NodeTest < ActiveSupport::TestCase
359 assert_equal @user1, node.reload.lock_owner 358 assert_equal @user1, node.reload.lock_owner
360 end 359 end
361 360
361 test "title reads from autosave when neither draft nor head exists yet" do
362 node = Node.root.children.create!(:slug => "title_autosave_only_test")
363 node.draft.destroy
364 node.update_column(:draft_id, nil)
365 node.lock_for_editing!(users(:quentin))
366 node.autosave!({ :title => "autosave-only title" }, users(:quentin))
367
368 assert_equal "autosave-only title", node.reload.title
369 end
370
362 test "revert! is a safe no-op on a fresh node with only a draft" do 371 test "revert! is a safe no-op on a fresh node with only a draft" do
363 node = create_node_with_draft 372 node = create_node_with_draft
364 node.lock_for_editing!(@user1) 373 node.lock_for_editing!(@user1)
@@ -537,30 +546,6 @@ class NodeTest < ActiveSupport::TestCase
537 assert result.index(mine) < result.index(someone_elses_newer) 546 assert result.index(mine) < result.index(someone_elses_newer)
538 end 547 end
539 548
540 test "recently_changed includes a node whose head was recently published" do
541 node = Node.root.children.create!(:slug => "recent_changed_published")
542 find_or_create_draft(node, @user1)
543 node.autosave!({:title => "v1"}, @user1)
544 node.save_draft!(@user1)
545 node.publish_draft!
546
547 assert_includes Node.recently_changed, node
548 end
549
550 test "recently_changed excludes a node only touched by locking or unlocking after an old publish" do
551 node = Node.root.children.create!(:slug => "recent_changed_lock_only")
552 find_or_create_draft(node, @user1)
553 node.autosave!({:title => "v1"}, @user1)
554 node.save_draft!(@user1)
555 node.publish_draft!
556 node.head.update_column(:updated_at, 20.days.ago)
557
558 node.lock_for_editing!(@user1)
559 node.unlock!
560
561 assert_not_includes Node.recently_changed, node
562 end
563
564 test "autosave! carries over the current related assets to the newly created autosave row" do 549 test "autosave! carries over the current related assets to the newly created autosave row" do
565 node = Node.root.children.create!(:slug => "autosave_asset_carryover_test") 550 node = Node.root.children.create!(:slug => "autosave_asset_carryover_test")
566 user = User.find_by_login("quentin") 551 user = User.find_by_login("quentin")
diff --git a/test/models/page_test.rb b/test/models/page_test.rb
index 1f924f9..98a00d2 100644
--- a/test/models/page_test.rb
+++ b/test/models/page_test.rb
@@ -309,11 +309,15 @@ class PageTest < ActiveSupport::TestCase
309 309
310 kept_asset = Asset.create!(:upload_file_name => "kept.png", :upload_content_type => "image/png", :upload_file_size => 1) 310 kept_asset = Asset.create!(:upload_file_name => "kept.png", :upload_content_type => "image/png", :upload_file_size => 1)
311 removed_asset = Asset.create!(:upload_file_name => "removed.pdf", :upload_content_type => "application/pdf", :upload_file_size => 1) 311 removed_asset = Asset.create!(:upload_file_name => "removed.pdf", :upload_content_type => "application/pdf", :upload_file_size => 1)
312 n.head.update_assets([kept_asset.id, removed_asset.id]) 312 n.head.related_assets.delete_all
313 n.head.related_assets.create!(:asset_id => kept_asset.id, :position => 1)
314 n.head.related_assets.create!(:asset_id => removed_asset.id, :position => 2)
313 315
314 d2 = find_or_create_draft(n, @user1) 316 d2 = find_or_create_draft(n, @user1)
315 added_asset = Asset.create!(:upload_file_name => "added.png", :upload_content_type => "image/png", :upload_file_size => 1) 317 added_asset = Asset.create!(:upload_file_name => "added.png", :upload_content_type => "image/png", :upload_file_size => 1)
316 d2.update_assets([kept_asset.id, added_asset.id]) 318 d2.related_assets.delete_all
319 d2.related_assets.create!(:asset_id => kept_asset.id, :position => 1)
320 d2.related_assets.create!(:asset_id => added_asset.id, :position => 2)
317 d2.save! 321 d2.save!
318 322
319 diff = d2.diff_against(n.head) 323 diff = d2.diff_against(n.head)
diff --git a/test/models/related_asset_test.rb b/test/models/related_asset_test.rb
index a739e6b..bb86ddb 100644
--- a/test/models/related_asset_test.rb
+++ b/test/models/related_asset_test.rb
@@ -1,8 +1,54 @@
1require 'test_helper' 1require 'test_helper'
2 2
3class RelatedImageTest < ActiveSupport::TestCase 3class RelatedAssetTest < ActiveSupport::TestCase
4 # Replace this with your real tests. 4 test "headline can be set on an image asset" do
5 test "the truth" do 5 node = Node.root.children.create!(:slug => "related_asset_headline_image_test")
6 assert true 6 asset = Asset.create!(:name => "photo", :upload_content_type => "image/png")
7 node.draft.assets << asset
8 related = node.draft.related_assets.find_by(:asset_id => asset.id)
9
10 related.headline = true
11 assert related.valid?
12 end
13
14 test "headline can be set on a PDF asset" do
15 node = Node.root.children.create!(:slug => "related_asset_headline_pdf_test")
16 asset = Asset.create!(:name => "expert opinion", :upload_content_type => "application/pdf")
17 node.draft.assets << asset
18 related = node.draft.related_assets.find_by(:asset_id => asset.id)
19
20 related.headline = true
21 assert related.valid?
22 end
23
24 test "headline cannot be set on a non-image, non-PDF asset" do
25 node = Node.root.children.create!(:slug => "related_asset_headline_text_test")
26 asset = Asset.create!(:name => "programme", :upload_content_type => "text/plain")
27 node.draft.assets << asset
28 related = node.draft.related_assets.find_by(:asset_id => asset.id)
29
30 related.headline = true
31 assert_not related.valid?
32 assert_includes related.errors[:headline], "can only be set on image or PDF assets"
33 end
34
35 test "the headline validation does not raise when asset is missing" do
36 related = RelatedAsset.new(:headline => true)
37 assert_not related.valid?
38 end
39
40 test "at most one headline per page is enforced at the database level" do
41 node = Node.root.children.create!(:slug => "related_asset_headline_uniqueness_test")
42 first = Asset.create!(:name => "first", :upload_content_type => "image/png")
43 second = Asset.create!(:name => "second", :upload_content_type => "image/png")
44 node.draft.assets << first
45 node.draft.assets << second
46
47 node.draft.related_assets.find_by(:asset_id => first.id).update!(:headline => true)
48 second_related = node.draft.related_assets.find_by(:asset_id => second.id)
49
50 assert_raises(ActiveRecord::RecordNotUnique) do
51 RelatedAsset.where(:id => second_related.id).update_all(:headline => true)
52 end
7 end 53 end
8end 54end