summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-23 19:45:47 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-23 19:45:47 +0200
commitaedf5778aba87c4e8d036dde2a0b6ec79cf8b342 (patch)
tree059a8954c332d0a7c3e48e44906a4104d4338007 /test
parentf993853db3e233f05a55de5ba2a87b77acf041aa (diff)
Keep in-editor asset curation off the head, layering it like every edit
ensure_autosave! gives body keystrokes and asset curation one shared layer, so head is never mutated in place and every curation change surfaces in the publish delta. Stale rendered join ids are mapped across the clone via asset_id. Curation now requires holding the lock; a missing lock answers 423, matching the autosave endpoint.
Diffstat (limited to 'test')
-rw-r--r--test/controllers/related_assets_controller_test.rb44
1 files changed, 36 insertions, 8 deletions
diff --git a/test/controllers/related_assets_controller_test.rb b/test/controllers/related_assets_controller_test.rb
index ced4b74d..fd30dddd 100644
--- a/test/controllers/related_assets_controller_test.rb
+++ b/test/controllers/related_assets_controller_test.rb
@@ -38,19 +38,24 @@ class RelatedAssetsControllerTest < ActionController::TestCase
38 test "create attaches an asset to the node's editable page" do 38 test "create attaches an asset to the node's editable page" do
39 login_as :quentin 39 login_as :quentin
40 node = Node.root.children.create!(:slug => "related_assets_create_test") 40 node = Node.root.children.create!(:slug => "related_assets_create_test")
41 node.lock_for_editing!(users(:quentin))
41 asset = Asset.create!(:name => "erfa-photo", :upload_content_type => "image/png") 42 asset = Asset.create!(:name => "erfa-photo", :upload_content_type => "image/png")
42 43
43 post :create, params: { :node_id => node.id, :asset_id => asset.id } 44 post :create, params: { :node_id => node.id, :asset_id => asset.id }
44 45
45 assert_response :success 46 assert_response :success
46 assert_includes node.draft.reload.related_assets.map(&:asset_id), asset.id 47 current = node.reload.editable_page
48 assert_equal node.autosave, current, "mutation should have created an autosave layer"
49 assert_includes current.related_assets.map(&:asset_id), asset.id
47 json = JSON.parse(response.body) 50 json = JSON.parse(response.body)
48 assert json["url"].present? 51 assert json["url"].present?
52 assert_empty node.draft.reload.related_assets, "the draft must stay untouched"
49 end 53 end
50 54
51 test "create does not duplicate an already-attached asset" do 55 test "create does not duplicate an already-attached asset" do
52 login_as :quentin 56 login_as :quentin
53 node = Node.root.children.create!(:slug => "related_assets_dup_test") 57 node = Node.root.children.create!(:slug => "related_assets_dup_test")
58 node.lock_for_editing!(users(:quentin))
54 asset = Asset.create!(:name => "erfa-photo-2", :upload_content_type => "image/png") 59 asset = Asset.create!(:name => "erfa-photo-2", :upload_content_type => "image/png")
55 node.draft.assets << asset 60 node.draft.assets << asset
56 61
@@ -63,19 +68,22 @@ class RelatedAssetsControllerTest < ActionController::TestCase
63 test "destroy removes the attached asset" do 68 test "destroy removes the attached asset" do
64 login_as :quentin 69 login_as :quentin
65 node = Node.root.children.create!(:slug => "related_assets_destroy_test") 70 node = Node.root.children.create!(:slug => "related_assets_destroy_test")
71 node.lock_for_editing!(users(:quentin))
66 asset = Asset.create!(:name => "old-photo", :upload_content_type => "image/png") 72 asset = Asset.create!(:name => "old-photo", :upload_content_type => "image/png")
67 node.draft.assets << asset 73 node.draft.assets << asset
68 related = node.draft.related_assets.first
69 74
75 related = node.draft.related_assets.first
70 delete :destroy, params: { :node_id => node.id, :id => related.id } 76 delete :destroy, params: { :node_id => node.id, :id => related.id }
71 77
72 assert_response :success 78 assert_response :success
73 assert_equal 0, node.draft.reload.related_assets.count 79 assert_equal 0, node.reload.editable_page.related_assets.count
80 assert_equal 1, node.draft.reload.related_assets.count, "the draft must stay untouched"
74 end 81 end
75 82
76 test "update reorders the attached assets" do 83 test "update reorders the attached assets" do
77 login_as :quentin 84 login_as :quentin
78 node = Node.root.children.create!(:slug => "related_assets_reorder_test") 85 node = Node.root.children.create!(:slug => "related_assets_reorder_test")
86 node.lock_for_editing!(users(:quentin))
79 first = Asset.create!(:name => "first-photo", :upload_content_type => "image/png") 87 first = Asset.create!(:name => "first-photo", :upload_content_type => "image/png")
80 second = Asset.create!(:name => "second-photo", :upload_content_type => "image/png") 88 second = Asset.create!(:name => "second-photo", :upload_content_type => "image/png")
81 node.draft.assets << first 89 node.draft.assets << first
@@ -85,13 +93,15 @@ class RelatedAssetsControllerTest < ActionController::TestCase
85 patch :update, params: { :node_id => node.id, :id => second_related.id, :position => 1 } 93 patch :update, params: { :node_id => node.id, :id => second_related.id, :position => 1 }
86 94
87 assert_response :success 95 assert_response :success
88 ordered_asset_ids = node.draft.reload.related_assets.map(&:asset_id) 96 ordered_asset_ids = node.reload.editable_page.related_assets.order(:position).map(&:asset_id)
97 # XXXX ordered_asset_ids = node.draft.reload.related_assets.map(&:asset_id)
89 assert_equal [second.id, first.id], ordered_asset_ids 98 assert_equal [second.id, first.id], ordered_asset_ids
90 end 99 end
91 100
92 test "update sets the headline flag" do 101 test "update sets the headline flag" do
93 login_as :quentin 102 login_as :quentin
94 node = Node.root.children.create!(:slug => "related_assets_headline_test") 103 node = Node.root.children.create!(:slug => "related_assets_headline_test")
104 node.lock_for_editing!(users(:quentin))
95 asset = Asset.create!(:name => "headline-photo", :upload_content_type => "image/png") 105 asset = Asset.create!(:name => "headline-photo", :upload_content_type => "image/png")
96 node.draft.assets << asset 106 node.draft.assets << asset
97 related = node.draft.related_assets.find_by(:asset_id => asset.id) 107 related = node.draft.related_assets.find_by(:asset_id => asset.id)
@@ -99,12 +109,14 @@ class RelatedAssetsControllerTest < ActionController::TestCase
99 patch :update, params: { :node_id => node.id, :id => related.id, :headline => "true" } 109 patch :update, params: { :node_id => node.id, :id => related.id, :headline => "true" }
100 110
101 assert_response :success 111 assert_response :success
102 assert related.reload.headline? 112 assert node.reload.editable_page.related_assets.find_by!(:asset_id => asset.id).headline?
113 assert_not related.reload.headline?, "the draft must stay untouched"
103 end 114 end
104 115
105 test "update with headline=true clears any previous headline on the same page" do 116 test "update with headline=true clears any previous headline on the same page" do
106 login_as :quentin 117 login_as :quentin
107 node = Node.root.children.create!(:slug => "related_assets_headline_swap_test") 118 node = Node.root.children.create!(:slug => "related_assets_headline_swap_test")
119 node.lock_for_editing!(users(:quentin))
108 first = Asset.create!(:name => "first-headline", :upload_content_type => "image/png") 120 first = Asset.create!(:name => "first-headline", :upload_content_type => "image/png")
109 second = Asset.create!(:name => "second-headline", :upload_content_type => "image/png") 121 second = Asset.create!(:name => "second-headline", :upload_content_type => "image/png")
110 node.draft.assets << first 122 node.draft.assets << first
@@ -117,13 +129,16 @@ class RelatedAssetsControllerTest < ActionController::TestCase
117 patch :update, params: { :node_id => node.id, :id => second_related.id, :headline => "true" } 129 patch :update, params: { :node_id => node.id, :id => second_related.id, :headline => "true" }
118 130
119 assert_response :success 131 assert_response :success
120 assert_not first_related.reload.headline? 132 current = node.reload.editable_page
121 assert second_related.reload.headline? 133 assert_not current.related_assets.find_by!(:asset_id => first.id).headline?
134 assert current.related_assets.find_by!(:asset_id => second.id).headline?
135 assert first_related.reload.headline?, "the draft must stay untouched"
122 end 136 end
123 137
124 test "update with headline=false clears the headline" do 138 test "update with headline=false clears the headline" do
125 login_as :quentin 139 login_as :quentin
126 node = Node.root.children.create!(:slug => "related_assets_headline_unset_test") 140 node = Node.root.children.create!(:slug => "related_assets_headline_unset_test")
141 node.lock_for_editing!(users(:quentin))
127 asset = Asset.create!(:name => "unset-headline", :upload_content_type => "image/png") 142 asset = Asset.create!(:name => "unset-headline", :upload_content_type => "image/png")
128 node.draft.assets << asset 143 node.draft.assets << asset
129 related = node.draft.related_assets.find_by(:asset_id => asset.id) 144 related = node.draft.related_assets.find_by(:asset_id => asset.id)
@@ -132,7 +147,8 @@ class RelatedAssetsControllerTest < ActionController::TestCase
132 patch :update, params: { :node_id => node.id, :id => related.id, :headline => "false" } 147 patch :update, params: { :node_id => node.id, :id => related.id, :headline => "false" }
133 148
134 assert_response :success 149 assert_response :success
135 assert_not related.reload.headline? 150 assert_not node.reload.editable_page.related_assets.find_by!(:asset_id => asset.id).headline?
151 assert related.reload.headline?, "the draft must stay untouched"
136 end 152 end
137 153
138 test "search includes PDF assets as headline-eligible candidates" do 154 test "search includes PDF assets as headline-eligible candidates" do
@@ -159,4 +175,16 @@ class RelatedAssetsControllerTest < ActionController::TestCase
159 ids = JSON.parse(response.body).map { |r| r["id"] } 175 ids = JSON.parse(response.body).map { |r| r["id"] }
160 assert_includes ids, asset.id 176 assert_includes ids, asset.id
161 end 177 end
178
179 test "curation without holding the lock is refused with 423" do
180 login_as :quentin
181 node = Node.root.children.create!(:slug => "curation_lock_test")
182 asset = Asset.create!(:name => "Untouchable", :upload_content_type => "image/png")
183 node.lock_for_editing!(users(:aaron))
184
185 post :create, params: { :node_id => node.id, :asset_id => asset.id }
186
187 assert_response :locked
188 assert_empty node.draft.assets.reload
189 end
162end 190end