Skip to content

Declutter your test files from large hardcoded data and update them automatically when your code changes

License

Notifications You must be signed in to change notification settings

ddnexus/rematch

Repository files navigation

Rematch [DEPRECATED]

Caution

This gem has been deprecated in favor of minitest-holdify. Please migrate to the new gem for future updates and support.

Gem Version Build Status Coverage Rubocop Status MIT license

Overview

Declutter your test files and automatically update expected values when your code changes.

Don't copy-paste large outputs or structures into your tests. Rematch saves you hours of tedious maintenance by storing expected values in separate files and verifying them for you.

Instead of this mess...

it 'generates the pagination nav tag' do
  assert_equal "<nav id=" test - nav - id " class=" pagy - nav
  pagination " aria-label=" pager "><span class=" page prev "><a href=" / foo? page = 9 "  link-extra
  rel=" prev " aria-label=" previous ">&lsaquo;&nbsp;Prev</a></span> <span class=" page "><a
  href=" / foo? page = 1 "  link-extra >1</a></span> <span class=" page gap ">&hellip;</span>
  <span class=" page "><a href=" / foo? page = 6 "  link-extra >6</a></span> <span class=" page "><a
  href=" / foo? page = 7 "  link-extra >7</a></span> <span class=" page "><a href=" / foo? page = 8 "  link-extra
  >8</a></span> <span class=" page "><a href=" / foo? page = 9 "  link-extra rel=" prev " >9</a></span>
  <span class=" page active ">10</span> <span class=" page "><a href=" / foo? page = 11 "  link-extra
  rel=" next " >11</a></span> <span class=" page "><a href=" / foo? page = 12 "  link-extra
  >12</a></span> <span class=" page "><a href=" / foo? page = 13 "  link-extra >13</a></span>
  <span class=" page "><a href=" / foo? page = 14 "  link-extra >14</a></span> <span class=" page
  gap ">&hellip;</span> <span class=" page "><a href=" / foo? page = 50 "  link-extra >50</a></span>
  <span class=" page next "><a href=" / foo? page = 11 "  link-extra rel=" next " aria-label=" next ">Next&nbsp;&rsaquo;</a></span></nav>",
  view.pagy_nav(pagy)
end

it 'generates the metadata hash' do
  assert_equal(
  {
  :scaffold_url => "http://www.example.com/subdir?page=__pagy_page__",
  :first_url    => "http://www.example.com/subdir?page=1",
  :prev_url     => "http://www.example.com/subdir?page=",
  :page_url     => "http://www.example.com/subdir?page=1",
  :next_url     => "http://www.example.com/subdir?page=2",
  :last_url     => "http://www.example.com/subdir?page=50",
  :count        => 1000,
  :page         => 1,
  :items        => 20,
  :vars         =>
  { :page       => 1,
    :items      => 20,
    :outset     => 0,
    :size       => [1, 4, 4, 1],
    :page_param => :page,
    :params     => {},
    :fragment   => "",
    :link_extra => "",
    :i18n_key   => "pagy.item_name",
    :cycle      => false,
    :url        => "http://www.example.com/subdir",
    :headers    =>
    { :page  => "Current-Page",
      :items => "Page-Items",
      :count => "Total-Count",
      :pages => "Total-Pages" },
    :metadata   =>
    [:scaffold_url,
     :first_url,
     :prev_url,
     :page_url,
     :next_url,
     :last_url,
     :count,
     :page,
     :items,
     :vars,
     :pages,
     :last,
     :from,
     :to,
     :prev,
     :next,
     :series],
    :count      => 1000 },
  :pages        => 50,
  :last         => 50,
  :from         => 1,
  :to           => 20,
  :prev         => nil,
  :next         => 2,
  :series       => ["1", 2, 3, 4, 5, :gap, 50]
  },
  controller.pagy_metadata)
end

Do it the easy way!

it 'generates the pagination nav tag' do
  # Assertion
  assert_rematch view.pagy_nav(pagy)
  
  # Expectation (standard)
  _(view.pagy_nav(pagy)).must_rematch
  
  # Expectation (fluent / RSpec-style)
  value(view.pagy_nav(pagy)).must_rematch
  expect(view.pagy_nav(pagy)).to_rematch
end

Installation

Add rematch to your Gemfile (usually in the :test group). Minitest < 6.0 loads it automatically. For Minitest >= 6.0, add Minitest.load :rematch to your test_helper.rb.

Usage

How it works

The first time a test runs, Rematch records the returned value in a *.yaml file next to the test. The key is automatically generated from the line number and a test ID. Subsequent runs compare the fresh value against the recording, passing or failing as usual.

Updating stored values

When your code changes, you can update the store without editing test files:

  1. Rebuild all: Run tests with the --rematch-rebuild option.

    rake test TESTOPTS=--rematch-rebuild

    [!WARNING] Only use this when you are sure the new output is correct: it will be stored!

  2. Manual deletion: Delete the specific *.yaml store file and re-run the test.

  3. Selective update: Temporarily replace the check with its store_ counterpart:

    • assert_rematchstore_assert_rematch
    • must_rematchstore_must_rematch
    • to_rematchstore_to_rematch

    [!WARNING] This stores the new value and fails the test (to prevent committing the store_ call). Revert to the original method to pass the test.

Assertions and Expectations

By default, Rematch wraps assert_equal (or assert_nil, depending on the value). You can also specify a different equality assertion (e.g., assert_equal_unordered).

# Standard usage
assert_rematch actual
_(actual).must_rematch

# With custom assertion
assert_rematch actual, :assert_equal_unordered
_(actual).must_rematch :assert_equal_unordered
expect(actual).to_rematch :assert_equal_unordered

# With message
assert_rematch actual, 'message'
_(actual).must_rematch 'message'

Note: The custom assertion must be a symbol (e.g., :assert_something). The order of arguments (assertion symbol vs message) is flexible.

Store Format

Rematch stores values in a standard YAML file named after your test file (e.g., test_file.rb.yaml). The keys are designed to be human-readable, allowing you to easily correlate stored values with your source code:

  • Line Matching: Keys start with L<num> corresponding to the line number of the assertion in your test file (e.g., L10).
  • Multiple Hits: If a single assertion line is executed multiple times (e.g., inside a loop), Rematch automatically appends a counter to the key (e.g., L15, L15.2, L15.3).
  • Labels: You can make keys self-documenting by passing the label: option, which appears in brackets within the key.

Example:

---
# Simple assertion at line 10
L10 8a93...: "simple value"

# Loop executing line 15 twice
L15 2b4c...: "iteration 1"
L15.2 2b4c...: "iteration 2"

# Assertion at line 20 using `label: 'custom_id'`
L20 [custom_id] 9d1e...: "labeled value"

Suggestions

  • Check the stores: If you are unsure about the output, check the readable *.yaml files. Keys starting with L<num> make it easy to find the corresponding test case at the line indicated.
  • Update flow: Ensure tests pass before rebuilding. If there are expected failures, use the store_* methods to reconcile specific tests.
  • Test the whole: Don't pick apart complex structures. Test the whole output with a single line. Rematch handles the complexity for you.
  • Dos and Don'ts: Use Rematch for large, stable outputs (HTML, JSON, Hashes). Stick to standard assertions for simple values (integers, short strings).

Caveats

  • Equality: Stored values are compared using standard Minitest assertions. Custom objects must implement ==.
  • Ruby Versions: Complex objects with ivars might serialize differently across Ruby versions due to Psych. Store raw data (hashes/attributes) to avoid this.

Repository Info

Ruby version

Tested on 3.2+, but compatible with 2.1+.

Versioning

Follows Semantic Versioning 2.0.0. See the Changelog.

Contributions

Pull Requests are welcome! Ensure tests, Codecov, and Rubocop pass.

Branches

  • master: Latest published release. Never force-pushed.
  • dev: Development branch. May be force-pushed.

License

MIT License.

About

Declutter your test files from large hardcoded data and update them automatically when your code changes

Resources

License

Stars

Watchers

Forks

Contributors 2

  •  
  •