Back to Repositories

Testing Enum Version Tracking Functionality in PaperTrail

This test suite validates the PaperTrail gem’s handling of enum values in model versioning, focusing on the PostWithStatus model. It ensures proper version tracking for enum state changes and compatibility with different PaperTrail versions.

Test Coverage Overview

The test suite comprehensively covers enum versioning functionality in PaperTrail.

Key areas tested include:
  • Enum value preservation in version records
  • Backwards compatibility with PaperTrail 4 enum storage
  • Object changes tracking for enum transitions
  • Version creation with save_with_version method

Implementation Analysis

The testing approach uses RSpec’s describe/context/it blocks to organize related test scenarios. It leverages PaperTrail’s with_versioning helper and implements factory-style test data creation using let blocks. The tests verify both direct enum state transitions and version record integrity.

Framework features utilized include:
  • RSpec expectations and matchers
  • Nested context blocks for scenario organization
  • Change detection for version count verification

Technical Details

Testing tools and configuration:
  • RSpec as the testing framework
  • PaperTrail’s versioning helpers
  • Model-level enum definitions
  • Custom version record manipulation
  • Object changes serialization validation

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through clear scenario isolation and comprehensive state verification. Notable practices include:
  • Explicit state transition testing
  • Backwards compatibility verification
  • Isolated context blocks for different scenarios
  • Proper setup and teardown management
  • Clear test case naming and organization

paper-trail-gem/paper_trail

spec/models/post_with_status_spec.rb

            
# frozen_string_literal: true

require "spec_helper"

RSpec.describe PostWithStatus, type: :model do
  with_versioning do
    let(:post) { described_class.create!(status: "draft") }

    it "saves the enum value in versions" do
      post.published!
      post.archived!
      expect(post.paper_trail.previous_version.published?).to be true
    end

    it "can read enums in version records written by PT 4" do
      post = described_class.create(status: "draft")
      post.published!
      version = post.versions.last
      # Simulate behavior PT 4, which used to save the string version of
      # enums to `object_changes`
      version.update(object_changes: "---\nid:\n- \n- 1\nstatus:\n- draft\n- published\n")
      assert_equal %w[draft published], version.changeset["status"]
    end

    context "when storing enum object_changes" do
      it "saves the enum value properly in versions object_changes" do
        post.published!
        post.archived!
        post_version = post.versions.last
        expect(post_version.changeset["status"]).to eql(%w[published archived])
      end
    end

    describe "#save_with_version" do
      context "when passing *args" do
        it "passes *args down correctly" do
          post = described_class.create(status: :draft)
          expect do
            post.paper_trail.save_with_version(validate: false)
          end.to change(post.versions, :count).by(1)
        end
      end

      it "preserves the enum value (and all other attributes)" do
        post = described_class.create(status: :draft)
        expect(post.versions.count).to eq(1)
        expect(post.status).to eq("draft")
        post.paper_trail.save_with_version
        expect(post.versions.count).to eq(2)
        expect(post.versions.last[:object]).to include("status: 0")
        expect(post.paper_trail.previous_version.status).to eq("draft")
      end
    end
  end
end