Back to Repositories

Testing Event-Based Version Control in Paper Trail

This test suite examines the core event handling functionality in PaperTrail’s base events module. It focuses on testing change detection and attribute tracking mechanisms for versioned records. The specs verify both new and persisted records, handling of ignored attributes, and timestamp-related behaviors.

Test Coverage Overview

The test suite provides comprehensive coverage of PaperTrail’s base event handling system, focusing on two key methods: changed_notably? and nonskipped_attributes_before_change.

  • Tests change detection for new records
  • Validates behavior with persisted records
  • Verifies handling of ignored attributes
  • Examines timestamp-related scenarios

Implementation Analysis

The testing approach utilizes RSpec’s context-based structure to organize related test scenarios. It employs factory-based test data generation and leverages RSpec’s described_class pattern for flexible test organization. The implementation includes versioning flags and custom model configurations.

  • Context-driven test organization
  • Focused unit tests for specific behaviors
  • Isolated test scenarios

Technical Details

Testing infrastructure includes:

  • RSpec as the testing framework
  • PaperTrail’s versioning configuration
  • Custom model (Gadget) with specific attribute tracking
  • Time-sensitive test scenarios
  • Attribute skipping mechanisms

Best Practices Demonstrated

The test suite exemplifies several testing best practices, including proper isolation of test cases and comprehensive coverage of edge cases. It demonstrates effective use of RSpec’s context blocks for organizing related tests and proper setup of test data.

  • Clear test case organization
  • Comprehensive edge case coverage
  • Proper test isolation
  • Descriptive test naming

paper-trail-gem/paper_trail

spec/paper_trail/events/base_spec.rb

            
# frozen_string_literal: true

require "spec_helper"

module PaperTrail
  module Events
    ::RSpec.describe Base do
      describe "#changed_notably?", versioning: true do
        context "with a new record" do
          it "returns true" do
            g = Gadget.new(created_at: Time.current)
            event = described_class.new(g, false)
            expect(event.changed_notably?).to eq(true)
          end
        end

        context "with a persisted record without update timestamps" do
          it "only acknowledges non-ignored attrs" do
            gadget = Gadget.create!(created_at: Time.current)
            gadget.name = "Wrench"
            event = described_class.new(gadget, false)
            expect(event.changed_notably?).to eq(true)
          end

          it "does not acknowledge ignored attr (brand)" do
            gadget = Gadget.create!(created_at: Time.current)
            gadget.brand = "Acme"
            event = described_class.new(gadget, false)
            expect(event.changed_notably?).to eq(false)
          end
        end

        context "with a persisted record with update timestamps" do
          it "only acknowledges non-ignored attrs" do
            gadget = Gadget.create!(created_at: Time.current)
            gadget.name = "Wrench"
            gadget.updated_at = Time.current
            event = described_class.new(gadget, false)
            expect(event.changed_notably?).to eq(true)
          end

          it "does not acknowledge ignored attrs and timestamps only" do
            gadget = Gadget.create!(created_at: Time.current)
            gadget.brand = "Acme"
            gadget.updated_at = Time.current
            event = described_class.new(gadget, false)
            expect(event.changed_notably?).to eq(false)
          end
        end
      end

      describe "#nonskipped_attributes_before_change", versioning: true do
        it "returns a hash lacking the skipped attribute" do
          # Skipper has_paper_trail(..., skip: [:another_timestamp])
          skipper = Skipper.create!(another_timestamp: Time.current)
          event = described_class.new(skipper, false)
          attributes = event.send(:nonskipped_attributes_before_change, false)
          expect(attributes).not_to have_key("another_timestamp")
        end
      end
    end
  end
end