diff options
Diffstat (limited to 'test/models/node_test.rb')
| -rw-r--r-- | test/models/node_test.rb | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/test/models/node_test.rb b/test/models/node_test.rb index 959387d..ab66f81 100644 --- a/test/models/node_test.rb +++ b/test/models/node_test.rb | |||
| @@ -621,4 +621,245 @@ class NodeTest < ActiveSupport::TestCase | |||
| 621 | assert_equal "Edited directly on autosave", Globalize.with_locale(:en) { autosave.title } | 621 | assert_equal "Edited directly on autosave", Globalize.with_locale(:en) { autosave.title } |
| 622 | assert_equal "v2", Globalize.with_locale(:de) { autosave.title } | 622 | assert_equal "v2", Globalize.with_locale(:de) { autosave.title } |
| 623 | end | 623 | end |
| 624 | |||
| 625 | test "publish_draft! logs a NodeAction crediting the actual publisher" do | ||
| 626 | node = Node.root.children.create!(:slug => "publish_log_test") | ||
| 627 | node.draft.update!(:title => "Version one") | ||
| 628 | |||
| 629 | node.publish_draft!(@user1) | ||
| 630 | |||
| 631 | action = NodeAction.last | ||
| 632 | assert_equal node, action.node | ||
| 633 | assert_equal node.head, action.page | ||
| 634 | assert_equal @user1, action.user | ||
| 635 | assert_equal "publish", action.action | ||
| 636 | assert_equal "draft", action.metadata["via"] | ||
| 637 | end | ||
| 638 | |||
| 639 | test "publish_draft! called with no user logs no actor, not a guessed one" do | ||
| 640 | node = Node.root.children.create!(:slug => "publish_log_no_user_test") | ||
| 641 | node.draft.update!(:title => "Version one") | ||
| 642 | |||
| 643 | node.publish_draft! | ||
| 644 | |||
| 645 | action = NodeAction.last | ||
| 646 | assert_nil action.user | ||
| 647 | assert_nil action.metadata["username"] | ||
| 648 | end | ||
| 649 | |||
| 650 | test "publish_draft! with nothing pending creates no NodeAction" do | ||
| 651 | node = Node.root.children.create!(:slug => "publish_log_noop_test") | ||
| 652 | node.publish_draft! | ||
| 653 | count_before = NodeAction.count | ||
| 654 | |||
| 655 | result = node.publish_draft! | ||
| 656 | |||
| 657 | assert_nil result | ||
| 658 | assert_equal count_before, NodeAction.count | ||
| 659 | end | ||
| 660 | |||
| 661 | test "revert! logs discard_autosave for an in-progress autosave" do | ||
| 662 | node = create_node_with_published_page | ||
| 663 | node.lock_for_editing!(@user1) | ||
| 664 | node.autosave!({:title => "in progress"}, @user1) | ||
| 665 | |||
| 666 | node.revert!(@user1) | ||
| 667 | |||
| 668 | action = NodeAction.last | ||
| 669 | assert_equal node, action.node | ||
| 670 | assert_equal @user1, action.user | ||
| 671 | assert_equal "discard_autosave", action.action | ||
| 672 | end | ||
| 673 | |||
| 674 | test "revert! logs destroy_draft for a draft with a head behind it" do | ||
| 675 | node = create_node_with_published_page | ||
| 676 | find_or_create_draft(node, @user1) | ||
| 677 | |||
| 678 | node.revert!(@user1) | ||
| 679 | |||
| 680 | action = NodeAction.last | ||
| 681 | assert_equal node, action.node | ||
| 682 | assert_equal @user1, action.user | ||
| 683 | assert_equal "destroy_draft", action.action | ||
| 684 | end | ||
| 685 | |||
| 686 | test "revert! with nothing to revert logs nothing" do | ||
| 687 | node = create_node_with_published_page | ||
| 688 | node.lock_for_editing!(@user1) | ||
| 689 | count_before = NodeAction.count | ||
| 690 | |||
| 691 | node.revert!(@user1) | ||
| 692 | |||
| 693 | assert_equal count_before, NodeAction.count | ||
| 694 | end | ||
| 695 | |||
| 696 | test "publish_draft! records the title diff in metadata" do | ||
| 697 | node = create_node_with_published_page | ||
| 698 | Globalize.with_locale(:de) { node.head.update!(:title => "Original Title") } | ||
| 699 | find_or_create_draft(node, @user1) | ||
| 700 | Globalize.with_locale(:de) { node.draft.update!(:title => "New Title") } | ||
| 701 | |||
| 702 | node.publish_draft!(@user1) | ||
| 703 | |||
| 704 | action = NodeAction.last | ||
| 705 | assert_equal "draft", action.metadata["via"] | ||
| 706 | assert_equal "Original Title", action.metadata.dig("title", "from") | ||
| 707 | assert_equal "New Title", action.metadata.dig("title", "to") | ||
| 708 | end | ||
| 709 | |||
| 710 | test "publishing a staged slug change logs a move with the path pair" do | ||
| 711 | node = create_node_with_published_page | ||
| 712 | path_before = node.unique_name | ||
| 713 | node.staged_slug = "moved-#{node.slug}" | ||
| 714 | node.save! | ||
| 715 | publish_count_before = NodeAction.where(:action => "publish").count | ||
| 716 | |||
| 717 | node.publish_draft!(@user1) | ||
| 718 | |||
| 719 | node.reload | ||
| 720 | assert_not_equal path_before, node.unique_name | ||
| 721 | |||
| 722 | action = NodeAction.where(:action => "move").last | ||
| 723 | assert_equal node, action.node | ||
| 724 | assert_equal @user1, action.user | ||
| 725 | assert_equal path_before, action.metadata.dig("path", "from") | ||
| 726 | assert_equal node.unique_name, action.metadata.dig("path", "to") | ||
| 727 | |||
| 728 | # No draft was pending: path change alone must not fabricate a publish. | ||
| 729 | assert_equal publish_count_before, NodeAction.where(:action => "publish").count | ||
| 730 | end | ||
| 731 | |||
| 732 | test "publishing a draft together with a staged move logs two entries" do | ||
| 733 | node = create_node_with_published_page | ||
| 734 | find_or_create_draft(node, @user1) | ||
| 735 | node.staged_slug = "relocated-#{node.slug}" | ||
| 736 | node.save! | ||
| 737 | |||
| 738 | assert_difference "NodeAction.count", 2 do | ||
| 739 | node.publish_draft!(@user1) | ||
| 740 | end | ||
| 741 | |||
| 742 | assert_equal %w[move publish], | ||
| 743 | NodeAction.order(:id).last(2).map(&:action).sort | ||
| 744 | end | ||
| 745 | |||
| 746 | test "restore_revision! logs a publish via revision" do | ||
| 747 | node = create_node_with_published_page | ||
| 748 | Globalize.with_locale(:de) { node.head.update!(:title => "First") } | ||
| 749 | first_head = node.head | ||
| 750 | find_or_create_draft(node, @user1) | ||
| 751 | Globalize.with_locale(:de) { node.draft.update!(:title => "Second") } | ||
| 752 | node.publish_draft!(@user1) | ||
| 753 | |||
| 754 | node.restore_revision!(first_head.revision, @user1) | ||
| 755 | |||
| 756 | action = NodeAction.last | ||
| 757 | assert_equal "publish", action.action | ||
| 758 | assert_equal "revision", action.metadata["via"] | ||
| 759 | assert_equal first_head, action.page | ||
| 760 | assert_equal @user1, action.user | ||
| 761 | assert_equal "Second", action.metadata.dig("title", "from") | ||
| 762 | assert_equal "First", action.metadata.dig("title", "to") | ||
| 763 | end | ||
| 764 | |||
| 765 | test "default_template_name rejects values not present in the template directory" do | ||
| 766 | node = Node.root.children.build(:slug => "template_guard_test", | ||
| 767 | :default_template_name => "../../layouts/admin") | ||
| 768 | assert_not node.valid? | ||
| 769 | |||
| 770 | node.default_template_name = "standard_template" | ||
| 771 | assert node.valid? | ||
| 772 | end | ||
| 773 | |||
| 774 | test "destroying a node with children is refused" do | ||
| 775 | parent = Node.root.children.create!(:slug => "destroy_guard_parent") | ||
| 776 | parent.children.create!(:slug => "destroy_guard_child") | ||
| 777 | |||
| 778 | assert_no_difference "Node.count" do | ||
| 779 | assert_not parent.destroy | ||
| 780 | end | ||
| 781 | assert parent.errors[:base].any? | ||
| 782 | end | ||
| 783 | |||
| 784 | test "destroying a childless node leaves no orphaned pages or asset links" do | ||
| 785 | node = create_node_with_published_page | ||
| 786 | page_ids = node.pages.pluck(:id) | ||
| 787 | asset = Asset.create!(:name => "destroy cascade probe", | ||
| 788 | :upload_file_name => "test_image.png", | ||
| 789 | :upload_content_type => "image/png", | ||
| 790 | :upload_file_size => 49854, | ||
| 791 | :upload_updated_at => Time.current) | ||
| 792 | node.head.related_assets.create!(:asset_id => asset.id, :position => 1) | ||
| 793 | |||
| 794 | node.destroy | ||
| 795 | |||
| 796 | assert_equal 0, Page.where(:id => page_ids).count | ||
| 797 | assert_equal 0, RelatedAsset.where(:page_id => page_ids).count | ||
| 798 | end | ||
| 799 | |||
| 800 | test "destroying a node also removes its autosave page" do | ||
| 801 | node = create_node_with_published_page | ||
| 802 | node.lock_for_editing!(@user1) | ||
| 803 | node.autosave!({:title => "in flight"}, @user1) | ||
| 804 | autosave_id = node.autosave_id | ||
| 805 | |||
| 806 | node.destroy | ||
| 807 | |||
| 808 | assert_equal 0, Page.where(:id => autosave_id).count | ||
| 809 | end | ||
| 810 | |||
| 811 | test "Node.trash lazily creates the container exactly once" do | ||
| 812 | assert_difference "Node.count", 1 do | ||
| 813 | Node.trash | ||
| 814 | end | ||
| 815 | assert_no_difference "Node.count" do | ||
| 816 | assert_equal Node.trash, Node.trash | ||
| 817 | end | ||
| 818 | assert Node.trash.trash_node? | ||
| 819 | assert_not Node.trash.in_trash? | ||
| 820 | assert_equal "Trash", Globalize.with_locale(I18n.default_locale) { Node.trash.draft.title } | ||
| 821 | end | ||
| 822 | |||
| 823 | test "in_trash? walks the whole parent chain" do | ||
| 824 | child = Node.trash.children.create!(:slug => "trashed_thing") | ||
| 825 | grandchild = child.children.create!(:slug => "trashed_deeper") | ||
| 826 | |||
| 827 | assert child.in_trash? | ||
| 828 | assert grandchild.in_trash? | ||
| 829 | assert_not Node.root.children.create!(:slug => "living_thing").in_trash? | ||
| 830 | end | ||
| 831 | |||
| 832 | test "the reserved slug is refused for other root children, live and staged" do | ||
| 833 | Node.trash | ||
| 834 | |||
| 835 | assert_not Node.root.children.build(:slug => CccConventions::TRASH_SLUG).valid? | ||
| 836 | assert_not Node.root.children.build(:slug => "fine", :staged_slug => CccConventions::TRASH_SLUG).valid? | ||
| 837 | assert Node.trash.children.create!(:slug => "sub").children.build(:slug => CccConventions::TRASH_SLUG).valid? | ||
| 838 | end | ||
| 839 | |||
| 840 | test "the Trash node refuses rename, move, and destroy" do | ||
| 841 | trash = Node.trash | ||
| 842 | other = Node.root.children.create!(:slug => "not_the_trash") | ||
| 843 | |||
| 844 | trash.slug = "recycling" | ||
| 845 | assert_not trash.valid? | ||
| 846 | |||
| 847 | trash.reload.parent_id = other.id | ||
| 848 | assert_not trash.valid? | ||
| 849 | |||
| 850 | assert_no_difference "Node.count" do | ||
| 851 | assert_not trash.reload.destroy | ||
| 852 | end | ||
| 853 | end | ||
| 854 | |||
| 855 | test "a head cannot exist inside the Trash, and publishing there is refused" do | ||
| 856 | node = Node.trash.children.create!(:slug => "no_publish_here") | ||
| 857 | page = node.pages.create! | ||
| 858 | |||
| 859 | node.head = page | ||
| 860 | assert_not node.valid? | ||
| 861 | |||
| 862 | node.reload | ||
| 863 | assert_raises(ActiveRecord::RecordInvalid) { node.publish_draft! } | ||
| 864 | end | ||
| 624 | end | 865 | end |
