This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/tests/acceptance/search-test.js
Martin Brennan ac7bf98ad1
DEV: Load client site settings YML into JS tests (#18413)
Our method of loading a subset of client settings into tests via
tests/helpers/site-settings.js can be improved upon. Currently we have a
hardcoded subset of the client settings, which may get out of date and not have
the correct defaults. As well as this plugins do not get their settings into the
tests, so whenever you need a setting from a plugin, even if it has a default,
you have to do needs.setting({ ... }) which is inconvenient.

This commit introduces an ember CLI build step to take the site_settings.yml and
all the plugin settings.yml files, pull out the client settings, and dump them
into a variable in a single JS file we can load in our tests, so we have the
correct selection of settings and default values in our JS tests. It also fixes
many, many tests that were operating under incorrect assumptions or old
settings.

Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
2022-11-08 09:17:43 +10:00

852 lines
26 KiB
JavaScript

import {
acceptance,
count,
exists,
query,
} from "discourse/tests/helpers/qunit-helpers";
import {
click,
fillIn,
settled,
triggerKeyEvent,
visit,
} from "@ember/test-helpers";
import I18n from "I18n";
import searchFixtures from "discourse/tests/fixtures/search-fixtures";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import { skip, test } from "qunit";
import { DEFAULT_TYPE_FILTER } from "discourse/widgets/search-menu";
acceptance("Search - Anonymous", function (needs) {
needs.pretender((server, helper) => {
server.get("/search/query", (request) => {
if (request.queryParams.type_filter === DEFAULT_TYPE_FILTER) {
// posts/topics are not present in the payload by default
return helper.response({
users: searchFixtures["search/query"]["users"],
categories: searchFixtures["search/query"]["categories"],
tags: searchFixtures["search/query"]["tags"],
groups: searchFixtures["search/query"]["groups"],
grouped_search_result:
searchFixtures["search/query"]["grouped_search_result"],
});
}
return helper.response(searchFixtures["search/query"]);
});
server.get("/u/search/users", () => {
return helper.response({
users: [
{
username: "admin",
name: "admin",
avatar_template: "/images/avatar.png",
},
],
});
});
});
test("search", async function (assert) {
await visit("/");
await click("#search-button");
assert.ok(exists("#search-term"), "it shows the search input");
assert.ok(
exists(".show-advanced-search"),
"it shows full page search button"
);
assert.ok(
exists(".search-menu .results ul li.search-random-quick-tip"),
"shows random quick tip by default"
);
await fillIn("#search-term", "dev");
assert.ok(
!exists(".search-menu .results ul li.search-random-quick-tip"),
"quick tip no longer shown"
);
assert.strictEqual(
query(
".search-menu .results ul.search-menu-initial-options li:first-child .search-item-slug"
).innerText.trim(),
`dev ${I18n.t("search.in_topics_posts")}`,
"shows topic search as first dropdown item"
);
assert.ok(
exists(".search-menu .search-result-category ul li"),
"shows matching category results"
);
assert.ok(
exists(".search-menu .search-result-user ul li"),
"shows matching user results"
);
await triggerKeyEvent(".search-menu", "keydown", "ArrowDown");
await click(document.activeElement);
assert.ok(
exists(".search-menu .search-result-topic ul li"),
"shows topic results"
);
assert.ok(
exists(".search-menu .results ul li .topic-title[data-topic-id]"),
"topic has data-topic-id"
);
await click(".show-advanced-search");
assert.strictEqual(
query(".full-page-search").value,
"dev",
"it goes to full search page and preserves the search term"
);
assert.ok(
exists(".search-advanced-options"),
"advanced search is expanded"
);
});
// TODO: This feature doesn't work currently (/t/69760)
skip("search button toggles search menu", async function (assert) {
await visit("/");
await click("#search-button");
assert.ok(exists(".search-menu"));
await click(".d-header"); // click outside
assert.ok(!exists(".search-menu"));
await click("#search-button");
assert.ok(exists(".search-menu"));
await click("#search-button"); // toggle same button
assert.ok(!exists(".search-menu"));
});
test("search scope", async function (assert) {
const firstResult =
".search-menu .results .search-menu-assistant-item:first-child";
await visit("/tag/important");
await click("#search-button");
assert.strictEqual(
query(firstResult).textContent.trim(),
`${I18n.t("search.in")} test`,
"contextual tag search is first available option with no term"
);
await fillIn("#search-term", "smth");
assert.strictEqual(
query(firstResult).textContent.trim(),
`smth ${I18n.t("search.in")} test`,
"tag-scoped search is first available option"
);
await visit("/c/bug");
await click("#search-button");
assert.strictEqual(
query(firstResult).textContent.trim(),
`smth ${I18n.t("search.in")} bug`,
"category-scoped search is first available option"
);
assert.ok(
exists(`${firstResult} span.badge-wrapper`),
"category badge is a span (i.e. not a link)"
);
await visit("/t/internationalization-localization/280");
await click("#search-button");
assert.strictEqual(
query(firstResult).textContent.trim(),
`smth ${I18n.t("search.in_this_topic")}`,
"topic-scoped search is first available option"
);
await visit("/u/eviltrout");
await click("#search-button");
assert.strictEqual(
query(firstResult).textContent.trim(),
`smth ${I18n.t("search.in_posts_by", {
username: "eviltrout",
})}`,
"user-scoped search is first available option"
);
});
test("search scope for topics", async function (assert) {
await visit("/t/internationalization-localization/280/1");
await click("#search-button");
const firstResult =
".search-menu .results .search-menu-assistant-item:first-child";
assert.strictEqual(
query(firstResult).textContent.trim(),
I18n.t("search.in_this_topic"),
"contextual topic search is first available option"
);
await fillIn("#search-term", "a proper");
await query("input#search-term").focus();
await triggerKeyEvent(".search-menu", "keydown", "ArrowDown");
await click(document.activeElement);
assert.ok(
exists(".search-menu .search-result-post ul li"),
"clicking first option formats results as posts"
);
assert.strictEqual(
query("#post_7 span.highlighted").textContent.trim(),
"a proper",
"highlights the post correctly"
);
assert.ok(
exists(".search-menu .search-context"),
"search context indicator is visible"
);
await click(".clear-search");
assert.strictEqual(query("#search-term").value, "", "clear button works");
await click(".search-context");
assert.ok(
!exists(".search-menu .search-context"),
"search context indicator is no longer visible"
);
await fillIn("#search-term", "dev");
await query("input#search-term").focus();
await triggerKeyEvent(".search-menu", "keydown", "ArrowDown");
await click(document.activeElement);
assert.ok(
exists(".search-menu .search-context"),
"search context indicator is visible"
);
await fillIn("#search-term", "");
await query("input#search-term").focus();
await triggerKeyEvent("input#search-term", "keydown", "Backspace");
assert.ok(
!exists(".search-menu .search-context"),
"backspace resets search context"
);
});
test("topic search scope - keep 'in this topic' filter in full page search", async function (assert) {
await visit("/t/internationalization-localization/280/1");
await click("#search-button");
const firstResult =
".search-menu .results .search-menu-assistant-item:first-child";
assert.strictEqual(
query(firstResult).textContent.trim(),
I18n.t("search.in_this_topic"),
"contextual topic search is first available option"
);
await fillIn("#search-term", "proper");
await query("input#search-term").focus();
await triggerKeyEvent(".search-menu", "keydown", "ArrowDown");
await click(document.activeElement);
assert.ok(
exists(".search-menu .search-context"),
"search context indicator is visible"
);
await click(".show-advanced-search");
assert.strictEqual(
query(".full-page-search").value,
"proper topic:280",
"it goes to full search page and preserves search term + context"
);
assert.ok(
exists(".search-advanced-options"),
"advanced search is expanded"
);
});
test("topic search scope - special case when matching a single user", async function (assert) {
await visit("/t/internationalization-localization/280/1");
await click("#search-button");
await fillIn("#search-term", "@admin");
assert.strictEqual(count(".search-menu-assistant-item"), 2);
assert.strictEqual(
query(
".search-menu-assistant-item:first-child .search-item-user .label-suffix"
).textContent.trim(),
I18n.t("search.in_this_topic"),
"first result hints in this topic search"
);
assert.strictEqual(
query(
".search-menu-assistant-item:nth-child(2) .search-item-user .label-suffix"
).textContent.trim(),
I18n.t("search.in_topics_posts"),
"second result hints global search"
);
});
test("Right filters are shown in full page search", async function (assert) {
const inSelector = selectKit(".select-kit#in");
await visit("/search?expanded=true");
await inSelector.expand();
assert.ok(inSelector.rowByValue("first").exists());
assert.ok(inSelector.rowByValue("pinned").exists());
assert.ok(inSelector.rowByValue("wiki").exists());
assert.ok(inSelector.rowByValue("images").exists());
assert.notOk(inSelector.rowByValue("unseen").exists());
assert.notOk(inSelector.rowByValue("posted").exists());
assert.notOk(inSelector.rowByValue("watching").exists());
assert.notOk(inSelector.rowByValue("tracking").exists());
assert.notOk(inSelector.rowByValue("bookmarks").exists());
assert.notOk(exists(".search-advanced-options .in-likes"));
assert.notOk(exists(".search-advanced-options .in-private"));
assert.notOk(exists(".search-advanced-options .in-seen"));
});
});
acceptance("Search - Authenticated", function (needs) {
needs.user();
needs.settings({
log_search_queries: true,
allow_uncategorized_topics: true,
});
needs.pretender((server, helper) => {
server.get("/search/query", (request) => {
if (request.queryParams.term.includes("empty")) {
return helper.response({
posts: [],
users: [],
categories: [],
tags: [],
groups: [],
grouped_search_result: {
more_posts: null,
more_users: null,
more_categories: null,
term: "plans test",
search_log_id: 1,
more_full_page_results: null,
can_create_topic: true,
error: null,
type_filter: null,
post_ids: [],
user_ids: [],
category_ids: [],
tag_ids: [],
group_ids: [],
},
});
}
return helper.response(searchFixtures["search/query"]);
});
});
test("Right filters are shown in full page search", async function (assert) {
const inSelector = selectKit(".select-kit#in");
await visit("/search?expanded=true");
await inSelector.expand();
assert.ok(inSelector.rowByValue("first").exists());
assert.ok(inSelector.rowByValue("pinned").exists());
assert.ok(inSelector.rowByValue("wiki").exists());
assert.ok(inSelector.rowByValue("images").exists());
assert.ok(inSelector.rowByValue("unseen").exists());
assert.ok(inSelector.rowByValue("posted").exists());
assert.ok(inSelector.rowByValue("watching").exists());
assert.ok(inSelector.rowByValue("tracking").exists());
assert.ok(inSelector.rowByValue("bookmarks").exists());
assert.ok(exists(".search-advanced-options .in-likes"));
assert.ok(exists(".search-advanced-options .in-private"));
assert.ok(exists(".search-advanced-options .in-seen"));
});
test("Works with empty result sets", async function (assert) {
await visit("/t/internationalization-localization/280");
await click("#search-button");
await fillIn("#search-term", "plans");
await query("input#search-term").focus();
await triggerKeyEvent(".search-menu", "keydown", "ArrowDown");
await click(document.activeElement);
assert.notStrictEqual(count(".search-menu .results .item"), 0);
await fillIn("#search-term", "plans empty");
await triggerKeyEvent("#search-term", "keydown", 13);
assert.strictEqual(count(".search-menu .results .item"), 0);
assert.strictEqual(count(".search-menu .results .no-results"), 1);
});
test("search dropdown keyboard navigation", async function (assert) {
const container = ".search-menu .results";
await visit("/");
await click("#search-button");
await fillIn("#search-term", "dev");
assert.ok(exists(query(`${container} ul li`)), "has a list of items");
await triggerKeyEvent("#search-term", "keydown", "Enter");
assert.ok(
exists(query(`${container} .search-result-topic`)),
"has topic results"
);
await triggerKeyEvent("#search-term", "keydown", "ArrowDown");
assert.strictEqual(
document.activeElement.getAttribute("href"),
query(`${container} li:first-child a`).getAttribute("href"),
"arrow down selects first element"
);
await triggerKeyEvent("#search-term", "keydown", "ArrowDown");
assert.strictEqual(
document.activeElement.getAttribute("href"),
query(`${container} li:nth-child(2) a`).getAttribute("href"),
"arrow down selects next element"
);
await triggerKeyEvent("#search-term", "keydown", "ArrowDown");
await triggerKeyEvent("#search-term", "keydown", "ArrowDown");
await triggerKeyEvent("#search-term", "keydown", "ArrowDown");
await triggerKeyEvent("#search-term", "keydown", "ArrowDown");
assert.strictEqual(
document.activeElement.getAttribute("href"),
"/search?q=dev",
"arrow down sets focus to more results link"
);
await triggerKeyEvent(".search-menu", "keydown", "Escape");
assert.strictEqual(
document.activeElement,
query("#search-button"),
"Escaping search returns focus to search button"
);
assert.ok(!exists(".search-menu:visible"), "Esc removes search dropdown");
await click("#search-button");
await triggerKeyEvent(".search-menu", "keydown", "ArrowDown");
await triggerKeyEvent(".search-menu", "keydown", "ArrowUp");
assert.strictEqual(
document.activeElement.tagName.toLowerCase(),
"input",
"arrow up sets focus to search term input"
);
await triggerKeyEvent(".search-menu", "keydown", "Escape");
await click("#create-topic");
await click("#search-button");
await triggerKeyEvent(".search-menu", "keydown", "ArrowDown");
const firstLink = query(`${container} li:nth-child(1) a`).getAttribute(
"href"
);
await triggerKeyEvent(".search-menu", "keydown", "A");
await settled();
assert.strictEqual(
query("#reply-control textarea").value,
`${window.location.origin}${firstLink}`,
"hitting A when focused on a search result copies link to composer"
);
await click("#search-button");
await triggerKeyEvent("#search-term", "keydown", "Enter");
assert.ok(
exists(query(`${container} .search-result-topic`)),
"has topic results"
);
await triggerKeyEvent("#search-term", "keydown", "Enter");
assert.ok(
exists(query(`.search-container`)),
"second Enter hit goes to full page search"
);
assert.ok(
!exists(query(`.search-menu`)),
"search dropdown is collapsed after second Enter hit"
);
// new search launched, Enter key should be reset
await click("#search-button");
assert.ok(exists(query(`${container} ul li`)), "has a list of items");
await triggerKeyEvent("#search-term", "keydown", "Enter");
assert.ok(exists(query(`.search-menu`)), "search dropdown is visible");
});
test("Shows recent search results", async function (assert) {
await visit("/");
await click("#search-button");
assert.strictEqual(
query(
".search-menu .search-menu-recent li:nth-of-type(1) .search-link"
).textContent.trim(),
"yellow",
"shows first recent search"
);
assert.strictEqual(
query(
".search-menu .search-menu-recent li:nth-of-type(2) .search-link"
).textContent.trim(),
"blue",
"shows second recent search"
);
});
});
acceptance("Search - with tagging enabled", function (needs) {
needs.user();
needs.settings({ tagging_enabled: true });
test("displays tags", async function (assert) {
await visit("/");
await click("#search-button");
await fillIn("#search-term", "dev");
await triggerKeyEvent("#search-term", "keydown", 13);
assert.strictEqual(
query(
".search-menu .results ul li:nth-of-type(1) .discourse-tags"
).textContent.trim(),
"dev slow",
"tags displayed in search results"
);
});
test("displays tag shortcuts", async function (assert) {
await visit("/");
await click("#search-button");
await fillIn("#search-term", "dude #monk");
await triggerKeyEvent("#search-term", "keyup", 51);
const firstItem =
".search-menu .results ul.search-menu-assistant .search-link";
assert.ok(exists(query(firstItem)));
const firstTag = query(`${firstItem} .search-item-tag`).textContent.trim();
assert.strictEqual(firstTag, "monkey");
});
});
acceptance("Search - assistant", function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get("/search/query", (request) => {
if (request.queryParams["search_context[type]"] === "private_messages") {
// return only one result for PM search
return helper.response({
posts: [
{
id: 3833,
name: "Bill Dudney",
username: "bdudney",
avatar_template:
"/user_avatar/meta.discourse.org/bdudney/{size}/8343_1.png",
uploaded_avatar_id: 8343,
created_at: "2013-02-07T17:46:57.469Z",
cooked:
"<p>I've gotten vagrant up and running with a development environment but it's taking forever to load.</p>\n\n<p>For example <a href=\"http://192.168.10.200:3000/\" rel=\"nofollow\">http://192.168.10.200:3000/</a> takes tens of seconds to load.</p>\n\n<p>I'm running the whole stack on a new rMBP with OS X 10.8.2.</p>\n\n<p>Any ideas of what I've done wrong? Or is this just a function of being on the bleeding edge?</p>\n\n<p>Thanks,</p>\n\n<p>-bd</p>",
post_number: 1,
post_type: 1,
updated_at: "2013-02-07T17:46:57.469Z",
like_count: 0,
reply_count: 1,
reply_to_post_number: null,
quote_count: 0,
incoming_link_count: 4422,
reads: 327,
score: 21978.4,
yours: false,
topic_id: 2179,
topic_slug: "development-mode-super-slow",
display_username: "Bill Dudney",
primary_group_name: null,
version: 2,
can_edit: false,
can_delete: false,
can_recover: false,
user_title: null,
actions_summary: [
{
id: 2,
count: 0,
hidden: false,
can_act: false,
},
{
id: 3,
count: 0,
hidden: false,
can_act: false,
},
{
id: 4,
count: 0,
hidden: false,
can_act: false,
},
{
id: 5,
count: 0,
hidden: true,
can_act: false,
},
{
id: 6,
count: 0,
hidden: false,
can_act: false,
},
{
id: 7,
count: 0,
hidden: false,
can_act: false,
},
{
id: 8,
count: 0,
hidden: false,
can_act: false,
},
],
moderator: false,
admin: false,
staff: false,
user_id: 1828,
hidden: false,
hidden_reason_id: null,
trust_level: 1,
deleted_at: null,
user_deleted: false,
edit_reason: null,
can_view_edit_history: true,
wiki: false,
blurb:
"I've gotten vagrant up and running with a development environment but it's taking forever to load. For example http://192.168.10.200:3000/ takes...",
},
],
topics: [
{
id: 2179,
title: "Development mode super slow",
fancy_title: "Development mode super slow",
slug: "development-mode-super-slow",
posts_count: 72,
reply_count: 53,
highest_post_number: 73,
image_url: null,
created_at: "2013-02-07T17:46:57.262Z",
last_posted_at: "2015-04-17T08:08:26.671Z",
bumped: true,
bumped_at: "2015-04-17T08:08:26.671Z",
unseen: false,
pinned: false,
unpinned: null,
visible: true,
closed: false,
archived: false,
bookmarked: null,
liked: null,
views: 9538,
like_count: 45,
has_summary: true,
archetype: "regular",
last_poster_username: null,
category_id: 7,
pinned_globally: false,
posters: [],
tags: ["dev", "slow"],
tags_descriptions: {
dev: "dev description",
slow: "slow description",
},
},
],
grouped_search_result: {
term: "emoji",
post_ids: [3833],
},
});
}
return helper.response(searchFixtures["search/query"]);
});
server.get("/u/search/users", () => {
return helper.response({
users: [
{
username: "TeaMoe",
name: "TeaMoe",
avatar_template:
"https://avatars.discourse.org/v3/letter/t/41988e/{size}.png",
},
{
username: "TeamOneJ",
name: "J Cobb",
avatar_template:
"https://avatars.discourse.org/v3/letter/t/3d9bf3/{size}.png",
},
{
username: "kudos",
name: "Team Blogeto.com",
avatar_template:
"/user_avatar/meta.discourse.org/kudos/{size}/62185_1.png",
},
],
});
});
});
test("shows category shortcuts when typing #", async function (assert) {
await visit("/");
await click("#search-button");
await fillIn("#search-term", "#");
await triggerKeyEvent("#search-term", "keyup", 51);
const firstCategory =
".search-menu .results ul.search-menu-assistant .search-link";
assert.ok(exists(query(firstCategory)));
const firstResultSlug = query(
`${firstCategory} .category-name`
).textContent.trim();
await click(firstCategory);
assert.strictEqual(query("#search-term").value, `#${firstResultSlug}`);
await fillIn("#search-term", "sam #");
await triggerKeyEvent("#search-term", "keyup", 51);
assert.ok(exists(query(firstCategory)));
assert.strictEqual(
query(
".search-menu .results ul.search-menu-assistant .search-item-prefix"
).innerText,
"sam "
);
await click(firstCategory);
assert.strictEqual(query("#search-term").value, `sam #${firstResultSlug}`);
});
test("shows in: shortcuts", async function (assert) {
await visit("/");
await click("#search-button");
const firstTarget =
".search-menu .results ul.search-menu-assistant .search-link .search-item-slug";
await fillIn("#search-term", "in:");
await triggerKeyEvent("#search-term", "keyup", 51);
assert.strictEqual(query(firstTarget).innerText, "in:title");
await fillIn("#search-term", "sam in:");
await triggerKeyEvent("#search-term", "keyup", 51);
assert.strictEqual(query(firstTarget).innerText, "sam in:title");
await fillIn("#search-term", "in:mess");
await triggerKeyEvent("#search-term", "keyup", 51);
assert.strictEqual(query(firstTarget).innerText, "in:messages");
});
test("shows users when typing @", async function (assert) {
await visit("/");
await click("#search-button");
await fillIn("#search-term", "@");
await triggerKeyEvent("#search-term", "keyup", 51);
const firstUser =
".search-menu .results ul.search-menu-assistant .search-item-user";
const firstUsername = query(firstUser).innerText.trim();
assert.strictEqual(firstUsername, "TeaMoe");
await click(query(firstUser));
assert.strictEqual(query("#search-term").value, `@${firstUsername}`);
});
test("shows 'in messages' button when in an inbox", async function (assert) {
await visit("/u/charlie/messages");
await click("#search-button");
assert.ok(exists(".btn.search-context"), "it shows the button");
await fillIn("#search-term", "");
await query("input#search-term").focus();
await triggerKeyEvent("input#search-term", "keydown", "Backspace");
assert.notOk(exists(".btn.search-context"), "it removes the button");
await click(".d-header");
await click("#search-button");
assert.ok(
exists(".btn.search-context"),
"it shows the button when reinvoking search"
);
await fillIn("#search-term", "emoji");
await query("input#search-term").focus();
await triggerKeyEvent("#search-term", "keydown", "Enter");
assert.strictEqual(
count(".search-menu .search-result-topic"),
1,
"it passes the PM search context to the search query"
);
});
});