Back to Repositories

Testing Search Suggestion Functionality in Searchkick

This test suite validates the suggestion functionality in Searchkick, focusing on search term corrections and autocomplete features. It covers various scenarios for text suggestions including basic matching, phrase matching, and multi-field suggestions.

Test Coverage Overview

The test suite provides comprehensive coverage of Searchkick’s suggestion capabilities.

Key areas tested include:
  • Basic text suggestions and corrections
  • Perfect match scenarios
  • Phrase-based suggestions
  • Multi-field suggestion handling
  • Field-specific suggestion configurations
  • Partial word matching

Implementation Analysis

The testing approach uses Minitest framework with a structured setup for product indexing. Tests implement pattern matching and assertion methods specifically designed for suggestion validation.

Notable patterns include:
  • Custom assertion helpers for suggestion testing
  • Product name storage helpers
  • Multiple field testing scenarios
  • Boost configuration testing

Technical Details

Testing infrastructure includes:
  • Minitest as the testing framework
  • Custom assertion methods (assert_suggest, assert_suggest_all)
  • Elasticsearch backend integration
  • Product model with searchkick configuration
  • Field-specific suggestion configurations

Best Practices Demonstrated

The test suite exhibits strong testing practices through organized test methods and comprehensive edge case coverage.

Notable practices include:
  • Isolated test cases
  • Clear test naming conventions
  • Edge case handling
  • Proper setup and teardown
  • Custom assertion helpers for cleaner test code

ankane/searchkick

test/suggest_test.rb

            
require_relative "test_helper"

class SuggestTest < Minitest::Test
  def setup
    super
    Product.reindex
  end

  def test_basic
    store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
    assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark", fields: [:name]
  end

  def test_perfect
    store_names ["Tiger Shark", "Great White Shark"]
    assert_suggest "Tiger Shark", nil, fields: [:name] # no correction
  end

  def test_phrase
    store_names ["Big Tiger Shark", "Tiger Sharp Teeth", "Tiger Sharp Mind"]
    assert_suggest "How to catch a big tiger shar", "how to catch a big tiger shark", fields: [:name]
  end

  def test_empty
    assert_suggest "hi", nil
  end

  def test_without_option
    store_names ["hi"] # needed to prevent ElasticsearchException - seed 668
    assert_raises(RuntimeError) { Product.search("hi").suggestions }
  end

  def test_multiple_fields
    store [
      {name: "Shark", color: "Sharp"},
      {name: "Shark", color: "Sharp"}
    ]
    assert_suggest_all "shar", ["shark", "sharp"]
  end

  def test_multiple_fields_highest_score_first
    store [
      {name: "Tiger Shark", color: "Sharp"}
    ]
    assert_suggest "tiger shar", "tiger shark"
  end

  def test_multiple_fields_same_value
    store [
      {name: "Shark", color: "Shark"}
    ]
    assert_suggest_all "shar", ["shark"]
  end

  def test_fields_option
    store [
      {name: "Shark", color: "Sharp"}
    ]
    assert_suggest_all "shar", ["shark"], fields: [:name]
  end

  def test_fields_option_multiple
    store [
      {name: "Shark"}
    ]
    assert_suggest "shar", "shark", fields: [:name, :unknown]
  end

  def test_fields_partial_match
    store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
    assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark", fields: [{name: :word_start}]
  end

  def test_fields_partial_match_boost
    store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
    assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark", fields: [{"name^2" => :word_start}]
  end

  def test_multiple_models
    skip # flaky test
    store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
    assert_equal "how big is a tiger shark", Searchkick.search("How Big is a Tigre Shar", suggest: [:name], fields: [:name]).suggestions.first
  end

  def test_multiple_models_no_fields
    store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
    assert_raises(ArgumentError) { Searchkick.search("How Big is a Tigre Shar", suggest: true) }
  end

  def test_star
    assert_equal [], Product.search("*", suggest: true).suggestions
  end

  protected

  def assert_suggest(term, expected, options = {})
    result = Product.search(term, suggest: true, **options).suggestions.first
    if expected.nil?
      assert_nil result
    else
      assert_equal expected, result
    end
  end

  # any order
  def assert_suggest_all(term, expected, options = {})
    assert_equal expected.sort, Product.search(term, suggest: true, **options).suggestions.sort
  end
end