searchkick_test.rb 8.17 KB
require "test_helper"

class Product < ActiveRecord::Base
  searchkick \
    synonyms: [
      ["clorox", "bleach"],
      ["scallion", "greenonion"],
      ["saranwrap", "plasticwrap"],
      ["qtip", "cotton swab"],
      ["burger", "hamburger"],
      ["bandaid", "bandag"]
    ],
    settings: {
      number_of_shards: 1
    },
    conversions: true

  serialize :conversions, JSON

  def search_data
    as_json(except: [:updated_at])
  end
end

Product.reindex

class TestSearchkick < Minitest::Unit::TestCase

  def setup
    Product.destroy_all
  end

  # exact

  def test_match
    store_names ["Whole Milk", "Fat Free Milk", "Milk"]
    assert_search "milk", ["Milk", "Whole Milk", "Fat Free Milk"]
  end

  def test_case
    store_names ["Whole Milk", "Fat Free Milk", "Milk"]
    assert_search "MILK", ["Milk", "Whole Milk", "Fat Free Milk"]
  end

  def test_cheese_space_in_index
    store_names ["Pepper Jack Cheese Skewers"]
    assert_search "pepperjack cheese skewers", ["Pepper Jack Cheese Skewers"]
  end

  def test_cheese_space_in_query
    store_names ["Pepperjack Cheese Skewers"]
    assert_search "pepper jack cheese skewers", ["Pepperjack Cheese Skewers"]
  end

  def test_middle_token
    store_names ["Dish Washer Amazing Organic Soap"]
    assert_search "dish soap", ["Dish Washer Amazing Organic Soap"]
  end

  def test_percent
    store_names ["1% Milk", "2% Milk", "Whole Milk"]
    assert_search "1%", ["1% Milk"]
  end

  # ascii

  def test_jalapenos
    store_names ["Jalapeño"]
    assert_search "jalapeno", ["Jalapeño"]
  end

  # stemming

  def test_stemming
    store_names ["Whole Milk", "Fat Free Milk", "Milk"]
    assert_search "milks", ["Milk", "Whole Milk", "Fat Free Milk"]
  end

  # fuzzy

  def test_misspelling_sriracha
    store_names ["Sriracha"]
    assert_search "siracha", ["Sriracha"]
  end

  def test_misspelling_tabasco
    store_names ["Tabasco"]
    assert_search "tobasco", ["Tabasco"]
  end

  def test_misspelling_zucchini
    store_names ["Zucchini"]
    assert_search "zuchini", ["Zucchini"]
  end

  def test_misspelling_ziploc
    store_names ["Ziploc"]
    assert_search "zip lock", ["Ziploc"]
  end

  # conversions

  def test_conversions
    store [
      {name: "Tomato Sauce", conversions: [{query: "tomato sauce", count: 5}, {query: "tomato", count: 200}]},
      {name: "Tomato Paste", conversions: []},
      {name: "Tomatoes", conversions: [{query: "tomato", count: 100}, {query: "tomato sauce", count: 2}]}
    ]
    assert_search "tomato", ["Tomato Sauce", "Tomatoes", "Tomato Paste"]
  end

  def test_conversions_stemmed
    store [
      {name: "Tomato A", conversions: [{query: "tomato", count: 2}, {query: "tomatos", count: 2}, {query: "Tomatoes", count: 2}]},
      {name: "Tomato B", conversions: [{query: "tomato", count: 4}]}
    ]
    assert_search "tomato", ["Tomato A", "Tomato B"]
  end

  # spaces

  def test_spaces_in_field
    store_names ["Red Bull"]
    assert_search "redbull", ["Red Bull"]
  end

  def test_spaces_in_query
    store_names ["Dishwasher Soap"]
    assert_search "dish washer", ["Dishwasher Soap"]
  end

  def test_spaces_three_words
    store_names ["Dish Washer Soap", "Dish Washer"]
    assert_search "dish washer soap", ["Dish Washer Soap"]
  end

  def test_spaces_stemming
    store_names ["Almond Milk"]
    assert_search "almondmilks", ["Almond Milk"]
  end

  # keywords

  def test_keywords
    store_names ["Clorox Bleach", "Kroger Bleach", "Saran Wrap", "Kroger Plastic Wrap", "Hamburger Buns", "Band-Aid", "Kroger 12-Pack Bandages"]
    assert_search "clorox", ["Clorox Bleach", "Kroger Bleach"]
    assert_search "saran wrap", ["Saran Wrap", "Kroger Plastic Wrap"]
    assert_search "burger buns", ["Hamburger Buns"]
    assert_search "bandaids", ["Band-Aid", "Kroger 12-Pack Bandages"]
  end

  def test_keywords_qtips
    store_names ["Q Tips", "Kroger Cotton Swabs"]
    assert_search "q tips", ["Q Tips", "Kroger Cotton Swabs"]
  end

  def test_keywords_reverse
    store_names ["Scallions"]
    assert_search "green onions", ["Scallions"]
  end

  def test_keywords_exact
    store_names ["Green Onions", "Yellow Onions"]
    assert_search "scallion", ["Green Onions"]
  end

  def test_keywords_stemmed
    store_names ["Green Onions", "Yellow Onions"]
    assert_search "scallions", ["Green Onions"]
  end

  # global boost

  def test_boost
    store [
      {name: "Organic Tomato A", _boost: 10},
      {name: "Tomato B"}
    ]
    assert_search "tomato", ["Organic Tomato A", "Tomato B"]
  end

  def test_boost_zero
    store [
      {name: "Zero Boost", _boost: 0}
    ]
    assert_search "zero", ["Zero Boost"]
  end

  # default to 1
  def test_boost_null
    store [
      {name: "Zero Boost A", _boost: 1.1},
      {name: "Zero Boost B"},
      {name: "Zero Boost C", _boost: 0.9},
    ]
    assert_search "zero", ["Zero Boost A", "Zero Boost B", "Zero Boost C"]
  end

  # search method

  def test_limit
    store_names ["Product A", "Product B"]
    assert_equal 1, Product.search("Product", limit: 1).size
  end

  def test_offset
    store_names ["Product A", "Product B"]
    assert_equal 1, Product.search("Product", offset: 1).size
  end

  def test_where
    now = Time.now
    store [
      {name: "Product A", store_id: 1, in_stock: true, backordered: true, created_at: now, _boost: 4},
      {name: "Product B", store_id: 2, in_stock: true, backordered: false, created_at: now - 1, _boost: 3},
      {name: "Product C", store_id: 3, in_stock: false, backordered: true, created_at: now - 2, _boost: 2},
      {name: "Product D", store_id: 4, in_stock: false, backordered: false, created_at: now - 3, _boost: 1},
    ]
    assert_search "product", ["Product A", "Product B"], where: {in_stock: true}
    # date
    assert_search "product", ["Product A"], where: {created_at: {gt: now - 1}}
    assert_search "product", ["Product A", "Product B"], where: {created_at: {gte: now - 1}}
    assert_search "product", ["Product D"], where: {created_at: {lt: now - 2}}
    assert_search "product", ["Product C", "Product D"], where: {created_at: {lte: now - 2}}
    # integer
    assert_search "product", ["Product A"], where: {store_id: {lt: 2}}
    assert_search "product", ["Product A", "Product B"], where: {store_id: {lte: 2}}
    assert_search "product", ["Product D"], where: {store_id: {gt: 3}}
    assert_search "product", ["Product C", "Product D"], where: {store_id: {gte: 3}}
    # range
    assert_search "product", ["Product A", "Product B"], where: {store_id: 1..2}
    assert_search "product", ["Product A"], where: {store_id: 1...2}
    assert_search "product", ["Product A", "Product B"], where: {store_id: [1, 2]}
    assert_search "product", ["Product B", "Product C", "Product D"], where: {store_id: {not: 1}}
    assert_search "product", ["Product C", "Product D"], where: {store_id: {not: [1, 2]}}
    assert_search "product", ["Product A", "Product B", "Product C"], where: {or: [[{in_stock: true}, {store_id: 3}]]}
  end

  def test_order
    store_names ["Product A", "Product B", "Product C", "Product D"]
    assert_search "product", ["Product D", "Product C", "Product B", "Product A"], order: {name: :desc}
  end

  def test_facets
    store [
      {name: "Product Show", store_id: 1, in_stock: true, color: "blue"},
      {name: "Product Hide", store_id: 2, in_stock: false, color: "green"},
      {name: "Product B", store_id: 2, in_stock: false, color: "red"}
    ]
    assert_equal 2, Product.search("Product", facets: [:store_id]).facets["store_id"]["terms"].size
    assert_equal 1, Product.search("Product", facets: {store_id: {where: {in_stock: true}}}).facets["store_id"]["terms"].size
    assert_equal 1, Product.search("Product", facets: {store_id: {where: {in_stock: true, color: "blue"}}}).facets["store_id"]["terms"].size
  end

  def test_partial
    store_names ["Honey"]
    assert_search "fresh honey", []
    assert_search "fresh honey", ["Honey"], partial: true
  end

  protected

  def store(documents)
    documents.each do |document|
      Product.create!(document)
    end
    Product.index.refresh
  end

  def store_names(names)
    store names.map{|name| {name: name} }
  end

  def assert_search(term, expected, options = {})
    assert_equal expected, Product.search(term, options.merge(fields: [:name], conversions: true)).map(&:name)
  end

end