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"]);
    });

    server.get("/inline-onebox", () =>
      helper.response({
        "inline-oneboxes": [
          {
            url: "http://www.something.com",
            title: searchFixtures["search/query"].topics[0].title,
          },
        ],
      })
    );
  });

  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("search while composer is open", async function (assert) {
    await visit("/t/internationalization-localization/280");
    await click(".reply");
    await fillIn(".d-editor-input", "a link");
    await click("#search-button");
    await fillIn("#search-term", "dev");

    await triggerKeyEvent("#search-term", "keydown", "Enter");
    await triggerKeyEvent(".search-menu", "keydown", "ArrowDown");
    await triggerKeyEvent("#search-term", "keydown", 65); // maps to lowercase a

    assert.ok(
      query(".d-editor-input").value.includes("a link"),
      "still has the original composer content"
    );

    assert.ok(
      query(".d-editor-input").value.includes(
        searchFixtures["search/query"].topics[0].slug
      ),
      "adds link from search to composer"
    );
  });

  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("/tag/dev/notifications", () => {
      return helper.response({
        tag_notification: { id: "dev", notification_level: 2 },
      });
    });

    server.get("/tags/c/bug/1/dev/l/latest.json", () => {
      return helper.response({
        users: [],
        primary_groups: [],
        topic_list: {
          can_create_topic: true,
          draft: null,
          draft_key: "new_topic",
          draft_sequence: 1,
          per_page: 30,
          tags: [
            {
              id: 1,
              name: "dev",
              topic_count: 1,
            },
          ],
          topics: [],
        },
      });
    });

    server.get("/tags/intersection/dev/foo.json", () => {
      return helper.response({
        topic_list: {
          can_create_topic: true,
          draft: null,
          draft_key: "new_topic",
          draft_sequence: 1,
          per_page: 30,
          topics: [],
        },
      });
    });

    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 category / tag combination shortcut when both are present", async function (assert) {
    await visit("/tags/c/bug/dev");
    await click("#search-button");

    assert.strictEqual(
      query(".search-menu .results ul.search-menu-assistant .category-name")
        .innerText,
      "bug",
      "Category is displayed"
    );

    assert.strictEqual(
      query(".search-menu .results ul.search-menu-assistant .search-item-tag")
        .innerText,
      "dev",
      "Tag is displayed"
    );
  });

  test("Updates tag / category combination search suggestion when typing", async function (assert) {
    await visit("/tags/c/bug/dev");
    await click("#search-button");
    await fillIn("#search-term", "foo bar");

    assert.strictEqual(
      query(
        ".search-menu .results ul.search-menu-assistant .search-item-prefix"
      ).innerText,
      "foo bar",
      "Input is applied to search query"
    );

    assert.strictEqual(
      query(".search-menu .results ul.search-menu-assistant .category-name")
        .innerText,
      "bug"
    );

    assert.strictEqual(
      query(".search-menu .results ul.search-menu-assistant .search-item-tag")
        .innerText,
      "dev",
      "Tag is displayed"
    );
  });

  test("Shows tag combination shortcut when visiting tag intersection", async function (assert) {
    await visit("/tags/intersection/dev/foo");
    await click("#search-button");

    assert.strictEqual(
      query(".search-menu .results ul.search-menu-assistant .search-item-tag")
        .innerText,
      "tags:dev+foo",
      "Tags are displayed"
    );
  });

  test("Updates tag intersection search suggestion when typing", async function (assert) {
    await visit("/tags/intersection/dev/foo");
    await click("#search-button");
    await fillIn("#search-term", "foo bar");

    assert.strictEqual(
      query(
        ".search-menu .results ul.search-menu-assistant .search-item-prefix"
      ).innerText,
      "foo bar",
      "Input is applied to search query"
    );

    assert.strictEqual(
      query(".search-menu .results ul.search-menu-assistant .search-item-tag")
        .innerText,
      "tags:dev+foo",
      "Tags are displayed"
    );
  });

  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"
    );
  });
});
