Fuse/test/fuzzy-search.test.js
2020-10-05 19:45:05 +02:00

1205 lines
30 KiB
JavaScript

const Fuse = require('../dist/fuse')
import * as ErrorMsg from '../src/core/errorMessages'
const defaultList = ['Apple', 'Orange', 'Banana']
const defaultOptions = {}
const setup = (itemList, overwriteOptions) => {
const list = itemList || defaultList
const options = { ...defaultOptions, ...overwriteOptions }
return new Fuse(list, options)
}
describe('Flat list of strings: ["Apple", "Orange", "Banana"]', () => {
let fuse
beforeEach(() => (fuse = setup()))
describe('When searching for the term "Apple"', () => {
let result
beforeEach(() => (result = fuse.search('Apple')))
test('we get a list of exactly 1 item', () => {
expect(result).toHaveLength(1)
})
test('whose value is the index 0, representing ["Apple"]', () => {
expect(result[0].refIndex).toBe(0)
})
})
describe('When performing a fuzzy search for the term "ran"', () => {
let result
beforeEach(() => (result = fuse.search('ran')))
test('we get a list of containing 2 items', () => {
expect(result).toHaveLength(2)
})
test('whose values represent the indices of ["Orange", "Banana"]', () => {
expect(result[0].refIndex).toBe(1)
expect(result[1].refIndex).toBe(2)
})
})
describe('When performing a fuzzy search for the term "nan"', () => {
let result
beforeEach(() => (result = fuse.search('nan')))
test('we get a list of containing 2 items', () => {
expect(result).toHaveLength(2)
})
test('whose values represent the indices of ["Banana", "Orange"]', () => {
expect(result[0].refIndex).toBe(2)
expect(result[1].refIndex).toBe(1)
})
})
describe('When performing a fuzzy search for the term "nan" with a limit of 1 result', () => {
let result
beforeEach(() => (result = fuse.search('nan', { limit: 1 })))
test('we get a list of containing 1 item: [2]', () => {
expect(result).toHaveLength(1)
})
test('whose values represent the indices of ["Banana", "Orange"]', () => {
expect(result[0].refIndex).toBe(2)
})
})
})
describe('Deep key search, with ["title", "author.firstName"]', () => {
const customBookList = [
{
title: "Old Man's War",
author: { firstName: 'John', lastName: 'Scalzi' }
},
{
title: 'The Lock Artist',
author: { firstName: 'Steve', lastName: 'Hamilton' }
},
{ title: 'HTML5' },
{
title: 'A History of England',
author: { firstName: 1066, lastName: 'Hastings' }
}
]
let fuse
beforeEach(
() =>
(fuse = setup(customBookList, { keys: ['title', 'author.firstName'] }))
)
describe('When searching for the term "Stve"', () => {
let result
beforeEach(() => (result = fuse.search('Stve')))
test('we get a list containing at least 1 item', () => {
expect(result.length).toBeGreaterThanOrEqual(1)
})
test('and the first item has the matching key/value pairs', () => {
expect(result[0].item).toMatchObject({
title: 'The Lock Artist',
author: { firstName: 'Steve', lastName: 'Hamilton' }
})
})
})
describe('When searching for the term "106"', () => {
let result
beforeEach(() => (result = fuse.search('106')))
test('we get a list of exactly 1 item', () => {
expect(result).toHaveLength(1)
})
test('whose value matches', () => {
expect(result[0].item).toMatchObject({
title: 'A History of England',
author: { firstName: 1066, lastName: 'Hastings' }
})
})
})
})
describe('Custom search function, with ["title", "author.firstName"]', () => {
const customBookList = [
{
title: "Old Man's War",
author: {
firstName: 'John',
lastName: 'Scalzi'
}
},
{
title: 'The Lock Artist',
author: {
firstName: 'Steve',
lastName: 'Hamilton'
}
}
]
const customOptions = {
keys: ['title', 'author.firstName'],
getFn: (obj) => {
if (!obj) return null
obj = obj.author.lastName
return obj
}
}
let fuse
beforeEach(() => (fuse = setup(customBookList, customOptions)))
describe('When searching for the term "Hmlt"', () => {
let result
beforeEach(() => (result = fuse.search('Hmlt')))
test('we get a list containing at least 1 item', () => {
expect(result.length).toBeGreaterThanOrEqual(1)
})
test('and the first item has the matching key/value pairs', () => {
expect(result[0].item).toMatchObject({
title: 'The Lock Artist',
author: { firstName: 'Steve', lastName: 'Hamilton' }
})
})
})
describe('When searching for the term "Stve"', () => {
let result
beforeEach(() => (result = fuse.search('Stve')))
test('we get a list of exactly 0 items', () => {
expect(result).toHaveLength(0)
})
})
})
describe('Include score in result list: ["Apple", "Orange", "Banana"]', () => {
let fuse
beforeEach(() => (fuse = setup(defaultList, { includeScore: true })))
describe('When searching for the term "Apple"', () => {
let result
beforeEach(() => (result = fuse.search('Apple')))
test('we get a list of exactly 1 item', () => {
expect(result).toHaveLength(1)
})
test('whose value is the index 0, representing ["Apple"]', () => {
expect(result[0].refIndex).toBe(0)
expect(result[0].score).toBe(0)
})
})
describe('When performing a fuzzy search for the term "ran"', () => {
let result
beforeEach(() => (result = fuse.search('ran')))
test('we get a list of containing 2 items', () => {
expect(result).toHaveLength(2)
})
test('whose values represent the indices, and have non-zero scores', () => {
expect(result[0].refIndex).toBe(1)
expect(result[0].score).not.toBe(0)
expect(result[1].refIndex).toBe(2)
expect(result[1].score).not.toBe(0)
})
})
})
describe('Include both ID and score in results list', () => {
const customBookList = [
{
ISBN: '0765348276',
title: "Old Man's War",
author: 'John Scalzi'
},
{
ISBN: '0312696957',
title: 'The Lock Artist',
author: 'Steve Hamilton'
}
]
const customOptions = {
keys: ['title', 'author'],
includeScore: true
}
let fuse
beforeEach(() => (fuse = setup(customBookList, customOptions)))
describe('When searching for the term "Stve"', () => {
let result
beforeEach(() => (result = fuse.search('Stve')))
test('we get a list containing exactly 1 item', () => {
expect(result).toHaveLength(1)
})
test('whose value is the ISBN of the book', () => {
expect(result[0].item.ISBN).toBe('0312696957')
})
test('and has a score that is not zero', () => {
expect(result[0].score).not.toBe(0)
})
})
})
describe('Search when IDs are numbers', () => {
const customBookList = [
{
ISBN: 1111,
title: "Old Man's War",
author: 'John Scalzi'
},
{
ISBN: 2222,
title: 'The Lock Artist',
author: 'Steve Hamilton'
}
]
const customOptions = {
keys: ['title', 'author'],
id: 'ISBN',
includeScore: true
}
let fuse
beforeEach(() => (fuse = setup(customBookList, customOptions)))
describe('When searching for the term "Stve"', () => {
let result
beforeEach(() => (result = fuse.search('Stve')))
test('we get a list containing exactly 1 item', () => {
expect(result).toHaveLength(1)
})
test('whose value is the ISBN of the book', () => {
expect(result[0].item.ISBN).toBe(2222)
})
test('and has a score that is not zero', () => {
expect(result[0].score).not.toBe(0)
})
})
})
describe('Recurse into arrays', () => {
const customBookList = [
{
ISBN: '0765348276',
title: "Old Man's War",
author: 'John Scalzi',
tags: ['fiction']
},
{
ISBN: '0312696957',
title: 'The Lock Artist',
author: 'Steve Hamilton',
tags: ['fiction']
},
{
ISBN: '0321784421',
title: 'HTML5',
author: 'Remy Sharp',
tags: ['web development', 'nonfiction']
}
]
const customOptions = {
keys: ['tags'],
threshold: 0,
includeMatches: true
}
let fuse
beforeEach(() => (fuse = setup(customBookList, customOptions)))
describe('When searching for the tag "nonfiction"', () => {
let result
beforeEach(() => (result = fuse.search('nonfiction')))
test('we get a list containing exactly 1 item', () => {
expect(result).toHaveLength(1)
})
test('whose value is the ISBN of the book', () => {
expect(result[0].item.ISBN).toBe('0321784421')
})
test('with matched tag provided', () => {
const { matches } = result[0]
expect(matches[0]).toMatchObject({
indices: [[0, 9]],
value: 'nonfiction',
key: 'tags',
refIndex: 1
})
})
})
})
describe('Recurse into objects in arrays with null object in array', () => {
const customBookList = [
{
ISBN: '0765348276',
title: "Old Man's War",
author: {
name: 'John Scalzi',
tags: [
{
value: 'American'
},
null
]
}
},
{
ISBN: '0312696957',
title: 'The Lock Artist',
author: {
name: 'Steve Hamilton',
tags: [
{
value: 'American'
}
]
}
},
{
ISBN: '0321784421',
title: 'HTML5',
author: {
name: 'Remy Sharp',
tags: [
{
value: 'British'
},
null,
]
}
}
]
const customOptions = {
keys: ['author.tags.value'],
threshold: 0
}
let fuse
beforeEach(() => (fuse = setup(customBookList, customOptions)))
describe('When searching for the author tag "British"', () => {
let result
beforeEach(() => (result = fuse.search('British')))
test('we get a list containing exactly 1 item', () => {
expect(result).toHaveLength(1)
})
test('whose value is the ISBN of the book', () => {
expect(result[0].item.ISBN).toBe('0321784421')
})
})
})
describe('Recurse into objects in arrays', () => {
const customBookList = [
{
ISBN: '0765348276',
title: "Old Man's War",
author: {
name: 'John Scalzi',
tags: [
{
value: 'American'
}
]
}
},
{
ISBN: '0312696957',
title: 'The Lock Artist',
author: {
name: 'Steve Hamilton',
tags: [
{
value: 'American'
}
]
}
},
{
ISBN: '0321784421',
title: 'HTML5',
author: {
name: 'Remy Sharp',
tags: [
{
value: 'British'
}
]
}
}
]
const customOptions = {
keys: ['author.tags.value'],
threshold: 0
}
let fuse
beforeEach(() => (fuse = setup(customBookList, customOptions)))
describe('When searching for the author tag "British"', () => {
let result
beforeEach(() => (result = fuse.search('British')))
test('we get a list containing exactly 1 item', () => {
expect(result).toHaveLength(1)
})
test('whose value is the ISBN of the book', () => {
expect(result[0].item.ISBN).toBe('0321784421')
})
})
})
describe('Set new list on Fuse', () => {
const vegetables = ['Onion', 'Lettuce', 'Broccoli']
let fuse
beforeEach(() => {
fuse = setup()
fuse.setCollection(vegetables)
return fuse
})
describe('When searching for the term "Lettuce"', () => {
let result
beforeEach(() => (result = fuse.search('Lettuce')))
test('we get a list of exactly 1 item', () => {
expect(result).toHaveLength(1)
})
test('whose value is the index 0, representing ["Apple"]', () => {
expect(result[0].refIndex).toBe(1)
})
})
})
describe('Weighted search', () => {
const customBookList = [
{
title: "Old Man's War fiction",
author: 'John X',
tags: ['war']
},
{
title: 'Right Ho Jeeves',
author: 'P.D. Mans',
tags: ['fiction', 'war']
},
{
title: 'The life of Jane',
author: 'John Smith',
tags: ['john', 'smith']
},
{
title: 'John Smith',
author: 'Steve Pearson',
tags: ['steve', 'pearson']
}
]
test('Invalid key entries throw errors', () => {
expect(() => {
setup(customBookList, {
keys: [
{ name: 'title', weight: -10 },
{ name: 'author', weight: 0.7 }
]
})
}).toThrowError(ErrorMsg.INVALID_KEY_WEIGHT_VALUE('title'))
expect(() => {
setup(customBookList, {
keys: [{ weight: 10 }, { name: 'author', weight: 0.7 }]
})
}).toThrowError(ErrorMsg.MISSING_KEY_PROPERTY('name'))
})
describe('When searching for the term "John Smith" with author weighted higher', () => {
const customOptions = {
keys: [
{ name: 'title', weight: 0.3 },
{ name: 'author', weight: 0.7 }
]
}
let fuse
let result
beforeEach(() => {
fuse = setup(customBookList, customOptions)
return (result = fuse.search('John Smith'))
})
test('We get the the exactly matching object', () => {
expect(result[0]).toMatchObject({
item: {
title: 'The life of Jane',
author: 'John Smith',
tags: ['john', 'smith']
},
refIndex: 2
})
})
})
describe('When searching for the term "John Smith" with author weighted higher, with mixed key types', () => {
const customOptions = {
keys: ['title', { name: 'author', weight: 2 }]
}
let fuse
let result
beforeEach(() => {
fuse = setup(customBookList, customOptions)
return (result = fuse.search('John Smith'))
})
test('We get the the exactly matching object', () => {
expect(result[0]).toMatchObject({
item: {
title: 'The life of Jane',
author: 'John Smith',
tags: ['john', 'smith']
},
refIndex: 2
})
})
test('Throws when key does not have a name property', () => {
expect(() => {
new Fuse(customBookList, {
keys: ['title', { weight: 2 }]
})
}).toThrow()
})
})
describe('When searching for the term "John Smith" with title weighted higher', () => {
const customOptions = {
keys: [
{ name: 'title', weight: 0.7 },
{ name: 'author', weight: 0.3 }
]
}
let fuse
let result
beforeEach(() => {
fuse = setup(customBookList, customOptions)
return (result = fuse.search('John Smith'))
})
test('We get the the exactly matching object', () => {
expect(result[0]).toMatchObject({
item: {
title: 'John Smith',
author: 'Steve Pearson',
tags: ['steve', 'pearson']
},
refIndex: 3
})
})
})
describe('When searching for the term "Man", where the author is weighted higher than title', () => {
const customOptions = {
keys: [
{ name: 'title', weight: 0.3 },
{ name: 'author', weight: 0.7 }
]
}
let fuse
let result
beforeEach(() => {
fuse = setup(customBookList, customOptions)
return (result = fuse.search('Man'))
})
test('We get the the exactly matching object', () => {
expect(result[0]).toMatchObject({
item: {
title: 'Right Ho Jeeves',
author: 'P.D. Mans',
tags: ['fiction', 'war']
},
refIndex: 1
})
})
})
describe('When searching for the term "Man", where the title is weighted higher than author', () => {
const customOptions = {
keys: [
{ name: 'title', weight: 0.7 },
{ name: 'author', weight: 0.3 }
]
}
let fuse
let result
beforeEach(() => {
fuse = setup(customBookList, customOptions)
return (result = fuse.search('Man'))
})
test('We get the the exactly matching object', () => {
expect(result[0]).toMatchObject({
item: {
title: "Old Man's War fiction",
author: 'John X',
tags: ['war']
},
refIndex: 0
})
})
})
describe('When searching for the term "War", where tags are weighted higher than all other keys', () => {
const customOptions = {
keys: [
{ name: 'title', weight: 0.4 },
{ name: 'author', weight: 0.1 },
{ name: 'tags', weight: 0.5 }
]
}
let fuse
let result
beforeEach(() => {
fuse = setup(customBookList, customOptions)
return (result = fuse.search('War'))
})
test('We get the exactly matching object', () => {
expect(result[0]).toMatchObject({
item: {
title: "Old Man's War fiction",
author: 'John X',
tags: ['war']
},
refIndex: 0
})
})
})
})
describe('Search location', () => {
const customList = [{ name: 'Hello World' }]
const customOptions = {
keys: ['name'],
includeScore: true,
includeMatches: true
}
let fuse
beforeEach(() => (fuse = setup(customList, customOptions)))
describe('When searching for the term "wor"', () => {
let result
let matches
beforeEach(() => {
result = fuse.search('wor')
return (matches = result[0].matches)
})
test('We get a list whose indices are found', () => {
expect(matches[0].indices[0]).toEqual([4, 4])
expect(matches[0].indices[1]).toEqual([6, 8])
})
test('with original text values', () => {
expect(matches[0].value).toBe('Hello World')
})
})
})
describe('Searching with default options', () => {
const customList = ['t te tes test tes te t']
let fuse
beforeEach(() => (fuse = new Fuse(customList, { includeMatches: true })))
describe('When searching for the term "test"', () => {
let result
beforeEach(() => (result = fuse.search('test')))
test('We get a match containing 4 indices', () => {
expect(result[0].matches[0].indices).toHaveLength(4)
})
test('and the first index is a single character', () => {
expect(result[0].matches[0].indices[0][0]).toBe(0)
expect(result[0].matches[0].indices[0][1]).toBe(0)
})
})
})
describe('Searching with findAllMatches', () => {
const customList = ['t te tes test tes te t']
let fuse
beforeEach(
() =>
(fuse = new Fuse(customList, {
includeMatches: true,
findAllMatches: true
}))
)
describe('When searching for the term "test"', () => {
let result
beforeEach(() => (result = fuse.search('test')))
test('We get a match containing 7 indices', () => {
expect(result[0].matches[0].indices).toHaveLength(7)
})
test('and the first index is a single character', () => {
expect(result[0].matches[0].indices[0][0]).toBe(0)
expect(result[0].matches[0].indices[0][1]).toBe(0)
})
})
})
describe('Searching with minCharLength', () => {
const customList = ['t te tes test tes te t']
let fuse
beforeEach(
() =>
(fuse = new Fuse(customList, {
includeMatches: true,
minMatchCharLength: 2
}))
)
describe('When searching for the term "test"', () => {
let result
beforeEach(() => (result = fuse.search('test')))
test('We get a match containing 3 indices', () => {
expect(result[0].matches[0].indices).toHaveLength(3)
})
test('and the first index is a single character', () => {
expect(result[0].matches[0].indices[0][0]).toBe(2)
expect(result[0].matches[0].indices[0][1]).toBe(3)
})
})
describe('When searching for a string shorter than minMatchCharLength', () => {
let result
beforeEach(() => (result = fuse.search('t')))
test('We get no results', () => {
expect(result).toHaveLength(0)
})
})
describe('Main functionality', () => {
const list = [
{
title: 'HTML5',
author: {
firstName: 'Remy',
lastName: 'Sharp'
}
},
{
title: 'Angels & Demons',
author: {
firstName: 'Dan',
lastName: 'Brown'
}
}
]
const fuse = new Fuse(list, {
keys: ['title', 'author.firstName'],
includeMatches: true,
includeScore: true,
minMatchCharLength: 3
})
test('We get a result with no matches', () => {
const result = fuse.search('remy')
expect(result).toHaveLength(1)
expect(result[0].matches).toHaveLength(1)
})
})
})
describe('Searching with minCharLength and pattern larger than machine word size', () => {
const customList = [
'Apple pie is a tasty treat that is always best made by mom! But we love store bought too.',
'Banana splits are what you want from DQ on a hot day. But a parfait is even better.',
'Orange sorbet is just a strange yet satisfying snack. Chocolate seems to be more of a favourite though.'
]
let fuse
beforeEach(
() =>
(fuse = new Fuse(customList, {
includeMatches: true,
findAllMatches: true,
includeScore: true,
minMatchCharLength: 20,
threshold: 0.6,
distance: 30
}))
)
describe('When searching for the term "American as apple pie is odd treatment of something made by mom"', () => {
let result
beforeEach(() => {
result = fuse.search(
'American as apple pie is odd treatment of something made by mom'
)
})
test('We get exactly 1 result', () => {
expect(result).toHaveLength(1)
})
test('Which corresponds to the first item in the list, with no matches', () => {
expect(result[0].refIndex).toBe(0)
expect(result[0].matches).toHaveLength(1)
})
})
})
describe('Sorted search results', () => {
const customList = [
{
title: 'Right Ho Jeeves',
author: { firstName: 'P.D', lastName: 'Woodhouse' }
},
{
title: 'The Code of the Wooster',
author: { firstName: 'P.D', lastName: 'Woodhouse' }
},
{
title: 'Thank You Jeeves',
author: { firstName: 'P.D', lastName: 'Woodhouse' }
}
]
const customOptions = {
keys: ['title', 'author.firstName', 'author.lastName']
}
let fuse
beforeEach(() => (fuse = new Fuse(customList, customOptions)))
describe('When searching for the term "wood"', () => {
let result
beforeEach(() => (result = fuse.search('wood')))
test('We get the properly ordered results', () => {
expect(result[0].item.title).toBe('The Code of the Wooster')
expect(result[1].item.title).toBe('Right Ho Jeeves')
expect(result[2].item.title).toBe('Thank You Jeeves')
})
})
})
describe('Searching using string large strings', () => {
const list = [
{
text: 'pizza'
},
{
text: 'feast'
},
{
text: 'where in the world is carmen san diego'
}
]
const options = {
shouldSort: true,
includeScore: true,
threshold: 0.6,
keys: ['text']
}
test('finds no matches when string is larger than 32 characters', () => {
const fuse = new Fuse(list, options)
let pattern = 'where exctly is carmen in the world san diego'
let result = fuse.search(pattern)
expect(result.length).toBe(1)
expect(result[0].item.text).toBe(list[2].text)
})
test('Test matches with very long patterns', () => {
let fuse = new Fuse(list, options)
let patterns = []
for (let i = 0; i < 66; ++i) {
patterns.push('w'.repeat(i))
}
const search = (pattern) => {
return fuse.search(pattern).length === 0
}
expect(search(patterns[32])).toBeTruthy()
expect(search(patterns[33])).toBeTruthy()
expect(search(patterns[34])).toBeTruthy()
expect(search(patterns[64])).toBeTruthy()
expect(search(patterns[65])).toBeTruthy()
})
it('With hyphens', () => {
const searchText = 'leverage-streams-to'
const fuseOptions = {
distance: 1000,
includeScore: true,
includeMatches: true,
keys: ['name', 'tag', 'description'],
minMatchCharLength: Math.floor(searchText.length * 0.6),
shouldSort: false
}
const fuse = new Fuse(
[
{
name: 'Streaming Service',
description: 'Leverage-streams-to-ingest, analyze, monitor.',
tag: 'Free'
}
],
fuseOptions
)
const results = fuse.search(searchText)
expect(results[0].matches).toEqual([
{
indices: [[0, 18]],
key: 'description',
value: 'Leverage-streams-to-ingest, analyze, monitor.'
}
])
})
it('With spaces', () => {
const searchText = 'leverage streams to'
const fuseOptions = {
distance: 1000,
includeScore: true,
includeMatches: true,
keys: ['name', 'tag', 'description'],
minMatchCharLength: Math.floor(searchText.length * 0.6),
shouldSort: false
}
const fuse = new Fuse(
[
{
name: 'Streaming Service',
description: 'Leverage streams to ingest, analyze, monitor.',
tag: 'Free'
}
],
fuseOptions
)
const results = fuse.search(searchText)
expect(results[0].matches).toEqual([
{
indices: [[0, 18]],
key: 'description',
value: 'Leverage streams to ingest, analyze, monitor.'
}
])
})
})
describe('Searching taking into account field length', () => {
const list = [
{
ISBN: '0312696957',
title: 'The Lock war Artist nonficon',
author: 'Steve Hamilton',
tags: ['fiction war hello no way']
},
{
ISBN: '0765348276',
title: "Old Man's War",
author: 'John Scalzi',
tags: ['fiction no']
}
]
test('The entry with the shorter field length appears first', () => {
const fuse = new Fuse(list, {
keys: ['title']
})
let result = fuse.search('war')
expect(result.length).toBe(2)
expect(result[0].item.ISBN).toBe('0765348276')
expect(result[1].item.ISBN).toBe('0312696957')
})
test('Weighted entries still are given high precedence', () => {
const fuse = new Fuse(list, {
keys: [
{ name: 'tags', weight: 0.8 },
{ name: 'title', weight: 0.2 }
]
})
let result = fuse.search('war')
expect(result.length).toBe(2)
expect(result[0].item.ISBN).toBe('0312696957')
expect(result[1].item.ISBN).toBe('0765348276')
})
})
describe('Ignore location and field length norm', () => {
const list = [
'beforeEach',
'async beforeEach test',
'assert.async in beforeEach',
'Module with Promise-aware beforeEach',
'Promise-aware return values without beforeEach/afterEach',
'Module with Promise-aware afterEach',
'before',
'before (skip)'
]
test('Check order of entries when location and field-length norm are ignored', () => {
const options = {
includeScore: true,
ignoreLocation: true,
ignoreFieldNorm: true
}
const fuse = new Fuse(list, options)
let result = fuse.search('promiseawarebeforeEach')
expect(result).toMatchSnapshot()
})
test('Check order of entries when location and field-length norm are not ignored', () => {
const options = {
includeScore: true
}
const fuse = new Fuse(list, options)
let result = fuse.search('beforeEach')
expect(result).toMatchSnapshot()
})
})
describe('Standard dotted keys', () => {
test('We get mathes', () => {
const list = [
{
title: 'HTML5',
author: {
firstName: 'Remy',
lastName: 'Sharp'
}
},
{
title: 'Angels & Demons',
author: {
firstName: 'rmy',
lastName: 'Brown'
}
}
]
const fuse = new Fuse(list, {
keys: ['title', ['author', 'firstName']],
includeMatches: true,
includeScore: true
})
const result = fuse.search('remy')
expect(result).toHaveLength(2)
})
test('We get a result with no matches', () => {
const list = [
{
title: 'HTML5',
author: {
'first.name': 'Remy',
'last.name': 'Sharp'
}
},
{
title: 'Angels & Demons',
author: {
'first.name': 'rmy',
'last.name': 'Brown'
}
}
]
const fuse = new Fuse(list, {
keys: ['title', ['author', 'first.name']],
includeMatches: true,
includeScore: true
})
const result = fuse.search('remy')
expect(result).toHaveLength(2)
})
test('Keys with weights', () => {
const list = [
{
title: 'HTML5',
author: {
firstName: 'Remy',
lastName: 'Sharp'
}
},
{
title: 'Angels & Demons',
author: {
firstName: 'rmy',
lastName: 'Brown'
}
}
]
const fuse = new Fuse(list, {
keys: [{ name: 'title' }, { name: ['author', 'firstName'] }],
includeMatches: true,
includeScore: true
})
const result = fuse.search('remy')
expect(result).toHaveLength(2)
})
})
describe('Breaking values', () => {
test('Non-strings are still processed', () => {
const data = [{ first: false }]
const options = { keys: [{ name: 'first' }] }
const fuse = new Fuse(data, options)
const result = fuse.search('fa')
expect(result).toHaveLength(1)
})
})