diff options
Diffstat (limited to 'test/models/node_trash_test.rb')
| -rw-r--r-- | test/models/node_trash_test.rb | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/test/models/node_trash_test.rb b/test/models/node_trash_test.rb new file mode 100644 index 0000000..52069d7 --- /dev/null +++ b/test/models/node_trash_test.rb | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | require "test_helper" | ||
| 2 | |||
| 3 | class NodeTrashTest < ActiveSupport::TestCase | ||
| 4 | |||
| 5 | def setup | ||
| 6 | @user1 = User.create!(:login => "trasher", :email => "t@example.com", | ||
| 7 | :password => "foobar", :password_confirmation => "foobar") | ||
| 8 | end | ||
| 9 | |||
| 10 | test "trash! demotes the head into the draft slot when no draft exists" do | ||
| 11 | node = create_node_with_published_page | ||
| 12 | former_head = node.head | ||
| 13 | |||
| 14 | node.trash!(@user1) | ||
| 15 | node.reload | ||
| 16 | |||
| 17 | assert_nil node.head_id | ||
| 18 | assert_equal former_head, node.draft | ||
| 19 | assert node.in_trash? | ||
| 20 | end | ||
| 21 | |||
| 22 | test "trash! keeps an existing draft; the former head stays a plain revision" do | ||
| 23 | node = create_node_with_published_page | ||
| 24 | draft = find_or_create_draft(node, @user1) | ||
| 25 | former_head = node.head | ||
| 26 | |||
| 27 | node.trash!(@user1) | ||
| 28 | node.reload | ||
| 29 | |||
| 30 | assert_nil node.head_id | ||
| 31 | assert_equal draft, node.draft | ||
| 32 | assert_includes node.pages, former_head | ||
| 33 | end | ||
| 34 | |||
| 35 | test "trash! demotes descendant heads and counts them in the log entry" do | ||
| 36 | parent = create_node_with_published_page | ||
| 37 | child = parent.children.create!(:slug => "trashed_child") | ||
| 38 | child.draft.update!(:title => "Child") | ||
| 39 | child.publish_draft!(@user1) | ||
| 40 | |||
| 41 | parent.trash!(@user1) | ||
| 42 | |||
| 43 | action = NodeAction.where(:action => "trash").last | ||
| 44 | assert_equal parent, action.node | ||
| 45 | assert_equal 2, action.metadata["demoted_heads"] | ||
| 46 | assert action.metadata["was_published"] | ||
| 47 | assert_nil child.reload.head_id | ||
| 48 | assert child.in_trash? | ||
| 49 | end | ||
| 50 | |||
| 51 | test "trash! logs one entry with the path pair and updates unique names" do | ||
| 52 | node = create_node_with_published_page | ||
| 53 | path_before = node.unique_name | ||
| 54 | |||
| 55 | assert_difference "NodeAction.count", 1 do | ||
| 56 | node.trash!(@user1) | ||
| 57 | end | ||
| 58 | |||
| 59 | action = NodeAction.last | ||
| 60 | assert_equal path_before, action.metadata.dig("path", "from") | ||
| 61 | assert_equal node.reload.unique_name, action.metadata.dig("path", "to") | ||
| 62 | assert action.metadata.dig("path", "to").start_with?(CccConventions::TRASH_SLUG) | ||
| 63 | end | ||
| 64 | |||
| 65 | test "trash! on an already trashed node is a logged-nothing no-op" do | ||
| 66 | node = create_node_with_published_page | ||
| 67 | node.trash!(@user1) | ||
| 68 | |||
| 69 | assert_no_difference "NodeAction.count" do | ||
| 70 | assert_nil node.reload.trash!(@user1) | ||
| 71 | end | ||
| 72 | end | ||
| 73 | |||
| 74 | test "restore_from_trash! reparents as drafts without republishing" do | ||
| 75 | node = create_node_with_published_page | ||
| 76 | node.trash!(@user1) | ||
| 77 | target = Node.root.children.create!(:slug => "restore_target") | ||
| 78 | |||
| 79 | node.reload.restore_from_trash!(target, @user1) | ||
| 80 | node.reload | ||
| 81 | |||
| 82 | assert_equal target, node.parent | ||
| 83 | assert_not node.in_trash? | ||
| 84 | assert_nil node.head_id | ||
| 85 | assert_not_nil node.draft_id | ||
| 86 | assert_equal "restore_from_trash", NodeAction.last.action | ||
| 87 | end | ||
| 88 | |||
| 89 | test "restore_from_trash! refuses targets inside the Trash and the Trash itself" do | ||
| 90 | node = create_node_with_published_page | ||
| 91 | node.trash!(@user1) | ||
| 92 | other_trashed = Node.trash.children.create!(:slug => "also_trashed") | ||
| 93 | |||
| 94 | assert_raises(ActiveRecord::RecordInvalid) { node.reload.restore_from_trash!(Node.trash, @user1) } | ||
| 95 | assert_raises(ActiveRecord::RecordInvalid) { node.reload.restore_from_trash!(other_trashed, @user1) } | ||
| 96 | end | ||
| 97 | |||
| 98 | test "destroy_from_trash! refuses nodes outside the Trash" do | ||
| 99 | node = create_node_with_published_page | ||
| 100 | |||
| 101 | assert_raises(ActiveRecord::RecordInvalid) { node.destroy_from_trash!(@user1) } | ||
| 102 | assert Node.exists?(node.id) | ||
| 103 | end | ||
| 104 | |||
| 105 | test "destroy_from_trash! removes the whole subtree bottom-up with one entry" do | ||
| 106 | parent = create_node_with_published_page | ||
| 107 | child = parent.children.create!(:slug => "doomed_child") | ||
| 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 | ||
| 120 | |||
| 121 | action = NodeAction.where(:action => "destroy").last | ||
| 122 | assert_equal 2, action.metadata["destroyed_descendants"] | ||
| 123 | assert_nil action.node_id | ||
| 124 | end | ||
| 125 | |||
| 126 | test "destroy_from_trash! logs an entry that survives the node" do | ||
| 127 | node = create_node_with_published_page | ||
| 128 | Globalize.with_locale(I18n.default_locale) { node.head.update!(:title => "Doomed") } | ||
| 129 | node.trash!(@user1) | ||
| 130 | final_path = node.reload.unique_name | ||
| 131 | |||
| 132 | node.destroy_from_trash!(@user1) | ||
| 133 | |||
| 134 | action = NodeAction.where(:action => "destroy").last | ||
| 135 | assert_nil action.node_id | ||
| 136 | assert_equal final_path, action.metadata["path"] | ||
| 137 | assert_equal "Doomed", action.subject_name | ||
| 138 | assert_equal @user1, action.user | ||
| 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 | ||
| 158 | |||
| 159 | test "trashed nodes and the Trash itself stay out of the drafts surfaces" do | ||
| 160 | Node.trash | ||
| 161 | node = create_node_with_published_page | ||
| 162 | node.trash!(@user1) | ||
| 163 | |||
| 164 | ids = Node.drafts_and_autosaves.pluck(:id) | ||
| 165 | assert_not_includes ids, Node.trash.id | ||
| 166 | assert_not_includes ids, node.id | ||
| 167 | end | ||
| 168 | end | ||
