Skip to content

Instantly share code, notes, and snippets.

@CyJimmy264
Created October 27, 2024 11:14
Show Gist options
  • Save CyJimmy264/fdc6510d96b5a23ea8686ff88482c9a0 to your computer and use it in GitHub Desktop.
Save CyJimmy264/fdc6510d96b5a23ea8686ff88482c9a0 to your computer and use it in GitHub Desktop.
Combining RSpec Matchers with Negation

У меня есть такой пример:

    it 'does not change payment status, cancellation reason, or output cancellation message' do
      expect { job }
        .not_to change { payment.reload.payment_status }.from('transferring')
        .and change { payment.reload.cancellation_reason }.from(nil)
        .and output(/Платёж #{payment.uuid} отменён/).to_stdout
    end

Но я получаю ошибку

     NotImplementedError:
       `expect(...).not_to matcher.and matcher` is not supported, since it creates a bit of an ambiguity. Instead, define negated versions of whatever matchers you wish to negate with `RSpec::Matchers.define_negated_matcher` and use `expect(...).to matcher.and matcher`.

Придумай решение

====================================================

Понятно, проблема в том, что RSpec не поддерживает комбинацию not_to с and. Давайте решим это с помощью define_negated_matcher, как и предлагается в сообщении об ошибке.

Вот решение:

# В начале файла или в spec_helper.rb добавим определения негативных матчеров
RSpec::Matchers.define_negated_matcher :not_change, :change
RSpec::Matchers.define_negated_matcher :not_output, :output

# Теперь тест можно переписать так
it 'does not change payment status, cancellation reason, or output cancellation message' do
  expect { job }
    .to not_change { payment.reload.payment_status }.from('transferring')
    .and not_change { payment.reload.cancellation_reason }.from(nil)
    .and not_output(/Платёж #{payment.uuid} отменён/).to_stdout
end

Что я сделал:

  1. Создал негативный матчер not_change который является противоположностью change
  2. Создал негативный матчер not_output который является противоположностью output
  3. Заменил конструкцию expect().not_to change на expect().to not_change

Теперь тест должен работать корректно. Такой подход делает тест более читаемым и избегает проблемы с not_to и and.

Эти определения матчеров (define_negated_matcher) лучше вынести в общий файл конфигурации тестов (например, spec_helper.rb или rails_helper.rb), чтобы они были доступны во всех тестах.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment