summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-18 02:15:29 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-18 02:15:29 +0200
commitd41ee504caedbe858e24ab2a23c7a804454c64c8 (patch)
treeeb3ec7c8f44d15fea40292d0a9e7358e41640edc /test
parent5dced8b4b624aabf4215ba21b13957080345c326 (diff)
Add Trash affordances: cockpit, listing, dashboard entry
nodes#show gains a Trash section on trashed nodes: provenance from the trash entry, a restore form whose parent picker pre-fills the old parent while it still lives, and permanent deletion. A Move-to-Trash button joins the status actions on living nodes. nodes#trashed lists trashed subtree roots with weight, provenance, and deletion; the dashboard housekeeping row links to it, and trash/destroy redirect there. Deletion from Trash now removes the whole subtree, deepest first, each node through a real destroy! so every per-node cascade runs -- amending the never-recursive rule for this one sanctioned path (both confirms state the count; the root entry carries destroyed_descendants). Bare Node#destroy still refuses children.
Diffstat (limited to 'test')
-rw-r--r--test/controllers/nodes_controller_test.rb31
-rw-r--r--test/models/node_trash_test.rb41
2 files changed, 62 insertions, 10 deletions
diff --git a/test/controllers/nodes_controller_test.rb b/test/controllers/nodes_controller_test.rb
index 7e5a990..6e2ddb3 100644
--- a/test/controllers/nodes_controller_test.rb
+++ b/test/controllers/nodes_controller_test.rb
@@ -427,11 +427,11 @@ class NodesControllerTest < ActionController::TestCase
427 test "show never renders a destroy link for events" do 427 test "show never renders a destroy link for events" do
428 login_as :quentin 428 login_as :quentin
429 node = create_node_with_published_page 429 node = create_node_with_published_page
430 Event.create!(node_id: node.id, start_time: Time.now, end_time: Time.now + 1.hour) 430 event = Event.create!(node_id: node.id, start_time: Time.now, end_time: Time.now + 1.hour)
431 431
432 get :show, params: { id: node.id } 432 get :show, params: { id: node.id }
433 assert_response :success 433 assert_response :success
434 assert_select "form.button_to.destructive", count: 0 434 assert_select "form[action=?]", event_path(event), count: 0
435 end 435 end
436 436
437 test "reverting from nodes#show returns to the show page, not the editor, even if a draft remains" do 437 test "reverting from nodes#show returns to the show page, not the editor, even if a draft remains" do
@@ -479,7 +479,8 @@ class NodesControllerTest < ActionController::TestCase
479 login_as :quentin 479 login_as :quentin
480 get :show, params: { :id => node.id } 480 get :show, params: { :id => node.id }
481 assert_response :success 481 assert_response :success
482 assert_select "form.destructive", :count => 0 482 assert_select "form[action=?]", revert_node_path(node), count: 0
483 assert_select "form[action=?]", trash_node_path(node), count: 1
483 end 484 end
484 485
485 test "drafts includes a never-published node with only a draft" do 486 test "drafts includes a never-published node with only a draft" do
@@ -679,7 +680,7 @@ class NodesControllerTest < ActionController::TestCase
679 680
680 put :trash, params: { :id => node.id } 681 put :trash, params: { :id => node.id }
681 682
682 assert_redirected_to node_path(Node.trash) 683 assert_redirected_to trashed_nodes_path
683 assert node.reload.in_trash? 684 assert node.reload.in_trash?
684 end 685 end
685 686
@@ -722,6 +723,26 @@ class NodesControllerTest < ActionController::TestCase
722 delete :destroy, params: { :id => node.id } 723 delete :destroy, params: { :id => node.id }
723 724
724 assert_not Node.exists?(node.id) 725 assert_not Node.exists?(node.id)
725 assert_redirected_to node_path(Node.trash) 726 assert_redirected_to trashed_nodes_path
727 end
728
729 test "trash lists trashed subtree roots" do
730 login_as :quentin
731 node = Node.root.children.create!(:slug => "listed_in_trash")
732 node.trash!(users(:quentin))
733
734 get :trashed
735 assert_response :success
736 assert_select "a[href=?]", node_path(node)
737 end
738
739 test "trashed rows carry provenance and a delete for childless roots" do
740 login_as :quentin
741 node = Node.root.children.create!(:slug => "provenance_test")
742 node.trash!(users(:quentin))
743
744 get :trashed
745 assert_select "td", /quentin/
746 assert_select "form[action=?]", node_path(node), count: 1
726 end 747 end
727end 748end
diff --git a/test/models/node_trash_test.rb b/test/models/node_trash_test.rb
index b72770b..07e5bc6 100644
--- a/test/models/node_trash_test.rb
+++ b/test/models/node_trash_test.rb
@@ -102,12 +102,25 @@ class NodeTrashTest < ActiveSupport::TestCase
102 assert Node.exists?(node.id) 102 assert Node.exists?(node.id)
103 end 103 end
104 104
105 test "destroy_from_trash! refuses nodes with children" do 105 test "destroy_from_trash! removes the whole subtree bottom-up with one entry" do
106 node = create_node_with_published_page 106 parent = create_node_with_published_page
107 node.children.create!(:slug => "still_here") 107 child = parent.children.create!(:slug => "doomed_child")
108 node.trash!(@user1) 108 grandchild = child.children.create!(:slug => "doomed_grandchild")
109 page_ids = [parent, child, grandchild].flat_map { |n| n.pages.pluck(:id) }
110 parent.trash!(@user1)
111
112 assert_difference "NodeAction.count", 1 do
113 parent.reload.destroy_from_trash!(@user1)
114 end
115
116 assert_not Node.exists?(parent.id)
117 assert_not Node.exists?(child.id)
118 assert_not Node.exists?(grandchild.id)
119 assert_equal 0, Page.where(:id => page_ids).count
109 120
110 assert_raises(ActiveRecord::RecordNotDestroyed) { node.reload.destroy_from_trash!(@user1) } 121 action = NodeAction.where(:action => "destroy").last
122 assert_equal 2, action.metadata["destroyed_descendants"]
123 assert_nil action.node_id
111 end 124 end
112 125
113 test "destroy_from_trash! logs an entry that survives the node" do 126 test "destroy_from_trash! logs an entry that survives the node" do
@@ -124,4 +137,22 @@ class NodeTrashTest < ActiveSupport::TestCase
124 assert_equal "Doomed", action.subject_name 137 assert_equal "Doomed", action.subject_name
125 assert_equal @user1, action.user 138 assert_equal @user1, action.user
126 end 139 end
140
141 test "suggested_restore_parent finds the old parent while it lives" do
142 parent = Node.root.children.create!(:slug => "old_home")
143 node = parent.children.create!(:slug => "comes_back")
144 node.trash!(@user1)
145
146 assert_equal parent, node.reload.suggested_restore_parent
147
148 parent.trash!(@user1)
149 assert_nil node.reload.suggested_restore_parent
150 end
151
152 test "suggested_restore_parent is root for trashed top-level nodes" do
153 node = Node.root.children.create!(:slug => "was_top_level")
154 node.trash!(@user1)
155
156 assert_equal Node.root, node.reload.suggested_restore_parent
157 end
127end 158end