diff options
Diffstat (limited to 'spec/support/matchers')
-rw-r--r-- | spec/support/matchers/be_n_plus_1_query.rb | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/spec/support/matchers/be_n_plus_1_query.rb b/spec/support/matchers/be_n_plus_1_query.rb new file mode 100644 index 00000000000..bbfd1897f04 --- /dev/null +++ b/spec/support/matchers/be_n_plus_1_query.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module Nplus1QueryHelpers + DEFAULT_THRESHOLD = 3 + + def with_threshold(threshold) + @threshold = threshold + self + end + + def for_query(query) + @query = query + self + end + + def threshold + @threshold || DEFAULT_THRESHOLD + end + + def occurrences + @occurrences ||= + if @query + recorder.occurrences.select { |recorded, count| recorded =~ @query } + else + recorder.occurrences + end + end + + def over_threshold + occurrences.select do |recorded, count| + count > threshold + end + end + + def recorder + @recorder ||= ActiveRecord::QueryRecorder.new(&@subject_block) + end + + def verify_count(&block) + @subject_block = block + over_threshold.present? + end + + def failure_message + log_message = over_threshold.to_yaml + "The following queries are executed more than #{threshold} time(s):\n#{log_message}" + end +end + +RSpec::Matchers.define :be_n_plus_1_query do + supports_block_expectations + + include Nplus1QueryHelpers + + match do |block| + verify_count(&block) + end + + failure_message_when_negated do |actual| + failure_message + end +end |