Back to Repositories

Testing Serializer Implementation Workflows in PaperTrail

This test suite validates PaperTrail’s serialization functionality across YAML, JSON, and custom serializer implementations. It ensures proper version tracking and attribute serialization for model changes.

Test Coverage Overview

The test suite provides comprehensive coverage of PaperTrail’s serialization capabilities:

  • YAML serializer functionality and version object storage
  • JSON serializer configuration and reification
  • Custom serializer implementation and changeset tracking
  • Version history length validation
  • Attribute reification accuracy checks

Implementation Analysis

The testing approach uses RSpec to systematically verify serializer behavior:

Tests are organized into distinct contexts for each serializer type, with proper setup and teardown using before/after blocks. The implementation leverages RSpec’s expectation syntax for precise assertions on serialized data formats and changeset contents.

Technical Details

  • RSpec as the testing framework
  • ActiveSupport::JSON for JSON encoding/decoding
  • Custom JSON serializer implementation
  • PaperTrail configuration management
  • Version model assertions
  • Changeset validation

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Proper test isolation with configuration reset
  • Comprehensive edge case coverage
  • Clear context separation
  • Consistent assertion patterns
  • Proper setup and teardown management

paper-trail-gem/paper_trail

spec/paper_trail/serializer_spec.rb

            
# frozen_string_literal: true

require "spec_helper"
require "support/custom_json_serializer"

RSpec.describe("PaperTrail serializers", versioning: true) do
  context "with YAML serializer" do
    it "saves the expected YAML in the object column" do
      customer = Customer.create(name: "Some text.")
      original_attributes = PaperTrail::Events::Base.
        new(customer, false).
        send(:nonskipped_attributes_before_change, false)
      customer.update(name: "Some more text.")
      expect(customer.versions.length).to(eq(2))
      expect(customer.versions[0].reify).to(be_nil)
      expect(customer.versions[1].reify.name).to(eq("Some text."))
      expect(YAML.load(customer.versions[1].object)).to(eq(original_attributes))
      expect(customer.versions[1].object).to(eq(YAML.dump(original_attributes)))
    end
  end

  context "with JSON Serializer" do
    before do
      PaperTrail.configure do |config|
        config.serializer = PaperTrail::Serializers::JSON
      end
    end

    after do
      PaperTrail.config.serializer = PaperTrail::Serializers::YAML
    end

    it "reify with JSON serializer" do
      customer = Customer.create(name: "Some text.")
      original_attributes = PaperTrail::Events::Base.
        new(customer, false).
        send(:nonskipped_attributes_before_change, false)
      customer.update(name: "Some more text.")
      expect(customer.versions.length).to(eq(2))
      expect(customer.versions[0].reify).to(be_nil)
      expect(customer.versions[1].reify.name).to(eq("Some text."))
      expect(ActiveSupport::JSON.decode(customer.versions[1].object)).to(eq(original_attributes))
      expect(customer.versions[1].object).to(eq(ActiveSupport::JSON.encode(original_attributes)))
    end

    describe "#changeset" do
      it "returns the expected hash" do
        customer = Customer.create(name: "Some text.")
        customer.update(name: "Some more text.")
        initial_changeset = { "name" => [nil, "Some text."], "id" => [nil, customer.id] }
        second_changeset = { "name" => ["Some text.", "Some more text."] }
        expect(customer.versions[0].changeset).to(eq(initial_changeset))
        expect(customer.versions[1].changeset).to(eq(second_changeset))
      end
    end
  end

  context "with Custom Serializer" do
    before do
      PaperTrail.configure { |config| config.serializer = CustomJsonSerializer }
    end

    after do
      PaperTrail.config.serializer = PaperTrail::Serializers::YAML
    end

    it "reify with custom serializer" do
      customer = Customer.create
      original_attributes = PaperTrail::Events::Base.
        new(customer, false).
        send(:nonskipped_attributes_before_change, false).
        compact
      customer.update(name: "Some more text.")
      expect(customer.versions.length).to(eq(2))
      expect(customer.versions[0].reify).to(be_nil)
      expect(customer.versions[1].reify.name).to(be_nil)
      expect(
        ActiveSupport::JSON.decode(customer.versions[1].object)
      ).to eq(original_attributes)
      expect(
        customer.versions[1].object
      ).to eq(ActiveSupport::JSON.encode(original_attributes))
    end

    describe "#changeset" do
      it "store object_changes" do
        customer = Customer.create
        customer.update(name: "banana")
        expect(customer.versions[0].changeset).to eq("id" => [nil, customer.id])
        expect(customer.versions[1].changeset).to eq("name" => [nil, "banana"])
      end
    end
  end
end