RSpec: You can super into parent "let" definitions

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 About 2 years ago