132 lines
4.3 KiB
Python
132 lines
4.3 KiB
Python
from wagtail.search.backends import get_search_backend
|
|
|
|
from tests.conftest import EventPageFactory, GenericPageFactory
|
|
|
|
|
|
SEARCH_QUERY = """
|
|
query Search($query: String) {
|
|
results: search(query: $query) {
|
|
__typename
|
|
... on PageInterface {
|
|
title
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
|
|
|
|
def _index(page):
|
|
# Wagtail's post_save signal enqueues indexing via django-tasks, which isn't
|
|
# drained synchronously in tests. Call the backend directly so the page is
|
|
# findable through the live search code path.
|
|
get_search_backend().add(page)
|
|
|
|
|
|
def _titles_for(body, typename):
|
|
return [r["title"] for r in body["data"]["results"] if r["__typename"] == typename]
|
|
|
|
|
|
def test_search_returns_live_generic_page(home_page, graphql_post):
|
|
page = GenericPageFactory(
|
|
parent=home_page,
|
|
title="PublishedGenericSearchToken",
|
|
slug="published-generic-search",
|
|
)
|
|
_index(page)
|
|
|
|
response, body = graphql_post(SEARCH_QUERY, {"query": "PublishedGenericSearchToken"})
|
|
|
|
assert response.status_code == 200
|
|
assert "errors" not in body, body
|
|
assert "PublishedGenericSearchToken" in _titles_for(body, "GenericPage")
|
|
|
|
|
|
def test_search_excludes_draft_generic_page(home_page, graphql_post):
|
|
page = GenericPageFactory(
|
|
parent=home_page,
|
|
title="DraftGenericSearchToken",
|
|
slug="draft-generic-search",
|
|
live=False,
|
|
)
|
|
_index(page)
|
|
|
|
response, body = graphql_post(SEARCH_QUERY, {"query": "DraftGenericSearchToken"})
|
|
|
|
assert response.status_code == 200
|
|
assert "errors" not in body, body
|
|
assert "DraftGenericSearchToken" not in _titles_for(body, "GenericPage")
|
|
|
|
|
|
def test_search_returns_live_event_page(home_page, event_index, graphql_post):
|
|
page = EventPageFactory(
|
|
parent=event_index,
|
|
title="PublishedEventSearchToken",
|
|
slug="published-event-search",
|
|
)
|
|
_index(page)
|
|
|
|
response, body = graphql_post(SEARCH_QUERY, {"query": "PublishedEventSearchToken"})
|
|
|
|
assert response.status_code == 200
|
|
assert "errors" not in body, body
|
|
assert "PublishedEventSearchToken" in _titles_for(body, "EventPage")
|
|
|
|
|
|
def test_search_excludes_draft_event_page(home_page, event_index, graphql_post):
|
|
page = EventPageFactory(
|
|
parent=event_index,
|
|
title="DraftEventSearchToken",
|
|
slug="draft-event-search",
|
|
live=False,
|
|
)
|
|
_index(page)
|
|
|
|
response, body = graphql_post(SEARCH_QUERY, {"query": "DraftEventSearchToken"})
|
|
|
|
assert response.status_code == 200
|
|
assert "errors" not in body, body
|
|
assert "DraftEventSearchToken" not in _titles_for(body, "EventPage")
|
|
|
|
|
|
def test_search_results_not_grouped_by_type(home_page, event_index, graphql_post):
|
|
# Two pages of different types matching the query equally, plus a third
|
|
# page of one of those types that should rank highest. Under the
|
|
# per-model-iteration resolver, all Generic results come before all Event
|
|
# results (or vice versa) — type-grouped — so the highest-relevance Event
|
|
# ends up after a less-relevant Generic. Cross-type relevance ordering
|
|
# should put the strongest match first regardless of type.
|
|
weak_generic = GenericPageFactory(
|
|
parent=home_page,
|
|
title="Klatremus klatremus klatremus",
|
|
slug="weak-generic",
|
|
)
|
|
weak_event = EventPageFactory(
|
|
parent=event_index,
|
|
title="Klatremus klatremus klatremus",
|
|
slug="weak-event",
|
|
)
|
|
strong_event = EventPageFactory(
|
|
parent=event_index,
|
|
title="Klatremus klatremus klatremus klatremus klatremus klatremus",
|
|
slug="strong-event",
|
|
)
|
|
_index(weak_generic)
|
|
_index(weak_event)
|
|
_index(strong_event)
|
|
|
|
response, body = graphql_post(SEARCH_QUERY, {"query": "klatremus"})
|
|
|
|
assert response.status_code == 200
|
|
assert "errors" not in body, body
|
|
order = [
|
|
(r["__typename"], r["title"])
|
|
for r in body["data"]["results"]
|
|
if r["__typename"] in ("GenericPage", "EventPage")
|
|
]
|
|
assert len(order) == 3, order
|
|
# Per-type grouping would put all results of one type consecutively
|
|
# before the other type. Cross-type relevance ordering should interleave.
|
|
types_seen = [t for t, _ in order]
|
|
assert types_seen != ["GenericPage", "EventPage", "EventPage"], order
|
|
assert types_seen != ["EventPage", "EventPage", "GenericPage"], order
|