From 3bab3248e5175fa70e359613f15333d1684f0569 Mon Sep 17 00:00:00 2001 From: James Addison <55152140+jayaddison@users.noreply.github.com> Date: Sun, 11 Aug 2024 15:13:14 +0100 Subject: [PATCH] HTML search: Add test coverage & introduce test module file suffix (#12759) --- tests/js/fixtures/partial/searchindex.js | 2 +- tests/js/fixtures/titles/searchindex.js | 2 +- tests/js/jasmine-browser.mjs | 3 +- tests/js/roots/partial/index.rst | 2 +- tests/js/roots/titles/index.rst | 14 ++++++ .../{searchtools.js => searchtools.spec.js} | 46 +++++++++++++++++++ ..._highlight.js => sphinx_highlight.spec.js} | 0 7 files changed, 64 insertions(+), 5 deletions(-) rename tests/js/{searchtools.js => searchtools.spec.js} (82%) rename tests/js/{sphinx_highlight.js => sphinx_highlight.spec.js} (100%) diff --git a/tests/js/fixtures/partial/searchindex.js b/tests/js/fixtures/partial/searchindex.js index dc6bc1cddbb..b650c366e94 100644 --- a/tests/js/fixtures/partial/searchindex.js +++ b/tests/js/fixtures/partial/searchindex.js @@ -1 +1 @@ -Search.setIndex({"alltitles": {"sphinx_utils module": [[0, null]]}, "docnames": ["index"], "envversion": {"sphinx": 63, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2}, "filenames": ["index.rst"], "indexentries": {}, "objects": {}, "objnames": {}, "objtypes": {}, "terms": {"also": 0, "ar": 0, "built": 0, "confirm": 0, "document": 0, "function": 0, "html": 0, "i": 0, "includ": 0, "input": 0, "javascript": 0, "known": 0, "match": 0, "partial": 0, "possibl": 0, "prefix": 0, "project": 0, "provid": 0, "restructuredtext": 0, "sampl": 0, "search": 0, "should": 0, "thi": 0, "titl": 0, "us": 0, "when": 0}, "titles": ["sphinx_utils module"], "titleterms": {"modul": 0, "sphinx_util": 0}}) \ No newline at end of file +Search.setIndex({"alltitles": {"sphinx_utils module": [[0, null]]}, "docnames": ["index"], "envversion": {"sphinx": 63, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2}, "filenames": ["index.rst"], "indexentries": {}, "objects": {}, "objnames": {}, "objtypes": {}, "terms": {"ar": 0, "both": 0, "built": 0, "confirm": 0, "document": 0, "function": 0, "html": 0, "i": 0, "includ": 0, "input": 0, "javascript": 0, "match": 0, "partial": 0, "possibl": 0, "project": 0, "provid": 0, "restructuredtext": 0, "sampl": 0, "search": 0, "should": 0, "term": 0, "thi": 0, "titl": 0, "us": 0, "when": 0}, "titles": ["sphinx_utils module"], "titleterms": {"modul": 0, "sphinx_util": 0}}) \ No newline at end of file diff --git a/tests/js/fixtures/titles/searchindex.js b/tests/js/fixtures/titles/searchindex.js index f503bf35df9..a084952248a 100644 --- a/tests/js/fixtures/titles/searchindex.js +++ b/tests/js/fixtures/titles/searchindex.js @@ -1 +1 @@ -Search.setIndex({"alltitles": {"Main Page": [[0, null]], "Relevance": [[0, "relevance"], [1, null]]}, "docnames": ["index", "relevance"], "envversion": {"sphinx": 63, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2}, "filenames": ["index.rst", "relevance.rst"], "indexentries": {"example (class in relevance)": [[0, "relevance.Example", false]], "module": [[0, "module-relevance", false]], "relevance": [[0, "module-relevance", false]], "relevance (relevance.example attribute)": [[0, "relevance.Example.relevance", false]]}, "objects": {"": [[0, 0, 0, "-", "relevance"]], "relevance": [[0, 1, 1, "", "Example"]], "relevance.Example": [[0, 2, 1, "", "relevance"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "attribute", "Python attribute"]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:attribute"}, "terms": {"": [0, 1], "A": 1, "For": 1, "In": [0, 1], "against": 0, "also": 1, "an": 0, "answer": 0, "appear": 1, "ar": 1, "area": 0, "ask": 0, "attribut": 0, "built": 1, "can": [0, 1], "class": 0, "code": [0, 1], "consid": 1, "contain": 0, "context": 0, "corpu": 1, "could": 1, "demonstr": 0, "describ": 1, "detail": 1, "determin": 1, "docstr": 0, "document": [0, 1], "domain": 1, "engin": 0, "exampl": [0, 1], "extract": 0, "find": 0, "found": 0, "from": 0, "function": 1, "ha": 1, "handl": 0, "happen": 1, "head": 0, "help": 0, "highli": 1, "how": 0, "i": [0, 1], "improv": 0, "inform": 0, "intend": 0, "issu": 1, "itself": 1, "knowledg": 0, "languag": 1, "less": 1, "like": [0, 1], "match": 0, "mention": 1, "name": [0, 1], "object": 0, "one": 1, "onli": 1, "other": 0, "page": 1, "part": 1, "particular": 0, "printf": 1, "program": 1, "project": 0, "queri": [0, 1], "question": 0, "re": 0, "rel": 0, "research": 0, "result": 1, "sai": 0, "same": 1, "score": 0, "search": [0, 1], "seem": 0, "softwar": 1, "some": 1, "sphinx": 0, "straightforward": 1, "subject": 0, "subsect": 0, "term": [0, 1], "test": 0, "text": 0, "than": 1, "thei": 0, "them": 0, "thi": 0, "titl": 0, "user": [0, 1], "we": [0, 1], "when": 0, "whether": 1, "within": 0, "would": 1}, "titles": ["Main Page", "Relevance"], "titleterms": {"main": 0, "page": 0, "relev": [0, 1]}}) \ No newline at end of file +Search.setIndex({"alltitles": {"Main Page": [[0, null]], "Relevance": [[0, "relevance"], [1, null]], "Result Scoring": [[0, "result-scoring"]]}, "docnames": ["index", "relevance"], "envversion": {"sphinx": 63, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2}, "filenames": ["index.rst", "relevance.rst"], "indexentries": {"example (class in relevance)": [[0, "relevance.Example", false]], "module": [[0, "module-relevance", false]], "relevance": [[0, "index-1", false], [0, "module-relevance", false]], "relevance (relevance.example attribute)": [[0, "relevance.Example.relevance", false]], "scoring": [[0, "index-0", true]]}, "objects": {"": [[0, 0, 0, "-", "relevance"]], "relevance": [[0, 1, 1, "", "Example"]], "relevance.Example": [[0, 2, 1, "", "relevance"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "attribute", "Python attribute"]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:attribute"}, "terms": {"": [0, 1], "A": 1, "By": 0, "For": [0, 1], "In": [0, 1], "against": 0, "align": 0, "also": 1, "an": 0, "answer": 0, "appear": 1, "ar": 1, "area": 0, "ask": 0, "assign": 0, "attempt": 0, "attribut": 0, "both": 0, "built": 1, "can": [0, 1], "class": 0, "code": [0, 1], "collect": 0, "consid": 1, "contain": 0, "context": 0, "corpu": 1, "could": 1, "demonstr": 0, "describ": 1, "detail": 1, "determin": [0, 1], "docstr": 0, "document": [0, 1], "domain": 1, "dure": 0, "engin": 0, "evalu": 0, "exampl": [0, 1], "extract": 0, "feedback": 0, "find": 0, "found": 0, "from": 0, "function": 1, "ha": 1, "handl": 0, "happen": 1, "head": 0, "help": 0, "highli": [0, 1], "how": 0, "i": [0, 1], "improv": 0, "inform": 0, "intend": 0, "issu": [0, 1], "itself": 1, "knowledg": 0, "languag": 1, "less": 1, "like": [0, 1], "mani": 0, "match": 0, "mention": 1, "more": 0, "name": [0, 1], "numer": 0, "object": 0, "often": 0, "one": [0, 1], "onli": [0, 1], "order": 0, "other": 0, "over": 0, "page": 1, "part": 1, "particular": 0, "present": 0, "printf": 1, "program": 1, "project": 0, "queri": [0, 1], "question": 0, "re": 0, "rel": 0, "research": 0, "result": 1, "retriev": 0, "sai": 0, "same": 1, "search": [0, 1], "seem": 0, "softwar": 1, "some": 1, "sphinx": 0, "straightforward": 1, "subject": 0, "subsect": 0, "term": [0, 1], "test": 0, "text": 0, "than": [0, 1], "thei": 0, "them": 0, "thi": 0, "time": 0, "titl": 0, "two": 0, "typic": 0, "us": 0, "user": [0, 1], "we": [0, 1], "when": 0, "whether": 1, "which": 0, "within": 0, "word": 0, "would": [0, 1]}, "titles": ["Main Page", "Relevance"], "titleterms": {"main": 0, "page": 0, "relev": [0, 1], "result": 0, "score": 0}}) \ No newline at end of file diff --git a/tests/js/jasmine-browser.mjs b/tests/js/jasmine-browser.mjs index fd45a1e3b59..7cc8610dd76 100644 --- a/tests/js/jasmine-browser.mjs +++ b/tests/js/jasmine-browser.mjs @@ -10,8 +10,7 @@ export default { ], specDir: "tests/js", specFiles: [ - 'searchtools.js', - 'sphinx_highlight.js' + '**/*.spec.js', ], helpers: [], env: { diff --git a/tests/js/roots/partial/index.rst b/tests/js/roots/partial/index.rst index 6a9561b3994..23fba6dd3eb 100644 --- a/tests/js/roots/partial/index.rst +++ b/tests/js/roots/partial/index.rst @@ -1,7 +1,7 @@ sphinx_utils module =================== -Partial (also known as "prefix") matches on document titles should be possible +Partial matches on document titles and document terms should both be possible using the JavaScript search functionality included when HTML documentation projects are built. diff --git a/tests/js/roots/titles/index.rst b/tests/js/roots/titles/index.rst index 464cd954b5c..c401c0b95f5 100644 --- a/tests/js/roots/titles/index.rst +++ b/tests/js/roots/titles/index.rst @@ -18,3 +18,17 @@ the subject area they're researching. .. automodule:: relevance :members: + +Result Scoring +-------------- + +Many search engines assign a numeric score to documents during retrieval of +results - and this score is often used to determine the order in which they +will be presented to the user. + +For example, if a user issues a query for a two words, then documents that +contain both of the words would typically be scored more highly than documents +which only contain one of them. + +By evaluating search results and collecting user feedback over time, we can +attempt to align document :index:`!scoring` with :index:`relevance`. diff --git a/tests/js/searchtools.js b/tests/js/searchtools.spec.js similarity index 82% rename from tests/js/searchtools.js rename to tests/js/searchtools.spec.js index 407fcd2bfe9..1ff789a4a56 100644 --- a/tests/js/searchtools.js +++ b/tests/js/searchtools.spec.js @@ -73,6 +73,24 @@ describe('Basic html theme search', function() { expect(Search.performTermsSearch(searchterms, excluded)).toEqual(hits); }); + it('should partially-match within "possible" when in term index', function() { + eval(loadFixture("partial/searchindex.js")); + + [_searchQuery, searchterms, excluded, ..._remainingItems] = Search._parseQuery('ossibl'); + terms = Search._index.terms; + titleterms = Search._index.titleterms; + + hits = [[ + "index", + "sphinx_utils module", + "", + null, + 2, + "index.rst" + ]]; + expect(Search.performTermsSearch(searchterms, excluded, terms, titleterms)).toEqual(hits); + }); + }); describe('aggregation of search results', function() { @@ -141,6 +159,34 @@ describe('Basic html theme search', function() { checkRanking(expectedRanking, results); }); + it('should score a title match above a standard index entry match', function() { + eval(loadFixture("titles/searchindex.js")); + + expectedRanking = [ + ['relevance', 'Relevance', ''], /* title */ + ['index', 'Main Page', '#index-1'], /* index entry */ + ]; + + searchParameters = Search._parseQuery('relevance'); + results = Search._performSearch(...searchParameters); + + checkRanking(expectedRanking, results); + }); + + it('should score a priority index entry match above a title match', function() { + eval(loadFixture("titles/searchindex.js")); + + expectedRanking = [ + ['index', 'Main Page', '#index-0'], /* index entry */ + ['index', 'Main Page > Result Scoring', '#result-scoring'], /* title */ + ]; + + searchParameters = Search._parseQuery('scoring'); + results = Search._performSearch(...searchParameters); + + checkRanking(expectedRanking, results); + }); + it('should score a main-title match above a subheading-title match', function() { eval(loadFixture("titles/searchindex.js")); diff --git a/tests/js/sphinx_highlight.js b/tests/js/sphinx_highlight.spec.js similarity index 100% rename from tests/js/sphinx_highlight.js rename to tests/js/sphinx_highlight.spec.js