RSpec: You can super into parent "let" definitions

Posted . Visible to the public.

RSpec's let allows you to super into "outside" definitions, in parent contexts.

Example:

describe '#save' do
  subject { described_class.new(attributes) }
  let(:attributes) { title: 'Example', user: create(:user) }

  it 'saves' do
    expect(subject.save).to eq(true)
  end

  context 'when trying to set a disallowed title' do
    let(:attributes) { super().merge(title: 'Hello') } # <==

    it 'will not save' do
      expect(subject.save).to eq(false)
    end
  end
end

I suggest you don't make a habit of using this regularly, as it has high potential to make your tests hard to read and understand.
You're often better of by using factories, generally different implementation patterns, or just duplicating some of your tests' code.

In some situations this has benefits, like making complex setups simpler if you want to modify only one aspect.
My use case for this was testing data migration logic where some edge cases caused different behavior for otherwise fine data. YMMV.

Note that you must use super() with explicitly no arguments instead of super. This is because let defines methods via define_method (which does not support super with implicit arguments).

Arne Hartherz
Last edit
Arne Hartherz
License
Source code in this card is licensed under the MIT License.
Posted by Arne Hartherz to makandra dev (2022-02-02 08:26)