This commit merges the mentions and "watching" tabs into the replies tab of the user menu. This change is kind of experimental, so we may change it back either fully or partially. Internal topic: t/76474.
963 lines
30 KiB
JavaScript
963 lines
30 KiB
JavaScript
import { click, currentURL, visit } from "@ember/test-helpers";
|
|
import {
|
|
acceptance,
|
|
exists,
|
|
loggedInUser,
|
|
publishToMessageBus,
|
|
query,
|
|
queryAll,
|
|
updateCurrentUser,
|
|
} from "discourse/tests/helpers/qunit-helpers";
|
|
import { test } from "qunit";
|
|
import { cloneJSON } from "discourse-common/lib/object";
|
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
|
import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types";
|
|
import UserMenuFixtures from "discourse/tests/fixtures/user-menu";
|
|
import TopicFixtures from "discourse/tests/fixtures/topic";
|
|
import { Promise } from "rsvp";
|
|
import { later } from "@ember/runloop";
|
|
import I18n from "I18n";
|
|
|
|
acceptance("User menu", function (needs) {
|
|
needs.user({
|
|
redesigned_user_menu_enabled: true,
|
|
unread_high_priority_notifications: 73,
|
|
trust_level: 3,
|
|
grouped_unread_notifications: {
|
|
[NOTIFICATION_TYPES.replied]: 2,
|
|
},
|
|
});
|
|
|
|
needs.settings({
|
|
allow_anonymous_posting: true,
|
|
anonymous_posting_min_trust_level: 3,
|
|
});
|
|
|
|
let requestHeaders = {};
|
|
|
|
needs.pretender((server, helper) => {
|
|
server.get("/t/1234.json", (request) => {
|
|
const json = cloneJSON(TopicFixtures["/t/130.json"]);
|
|
json.id = 1234;
|
|
json.post_stream.posts.forEach((post) => {
|
|
post.topic_id = 1234;
|
|
});
|
|
requestHeaders = request.requestHeaders;
|
|
return helper.response(json);
|
|
});
|
|
});
|
|
|
|
needs.hooks.afterEach(() => {
|
|
requestHeaders = {};
|
|
});
|
|
|
|
test("notifications panel has a11y attributes", async function (assert) {
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
const panel = query("#quick-access-all-notifications");
|
|
assert.strictEqual(panel.getAttribute("tabindex"), "-1");
|
|
assert.strictEqual(
|
|
panel.querySelector("ul").getAttribute("aria-labelledby"),
|
|
"user-menu-button-all-notifications"
|
|
);
|
|
});
|
|
|
|
test("replies notifications panel has a11y attributes", async function (assert) {
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-replies");
|
|
const panel = query("#quick-access-replies");
|
|
assert.strictEqual(panel.getAttribute("tabindex"), "-1");
|
|
assert.strictEqual(
|
|
panel.querySelector("ul").getAttribute("aria-labelledby"),
|
|
"user-menu-button-replies"
|
|
);
|
|
});
|
|
|
|
test("profile panel has a11y attributes", async function (assert) {
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-profile");
|
|
const panel = query("#quick-access-profile");
|
|
assert.strictEqual(panel.getAttribute("tabindex"), "-1");
|
|
assert.strictEqual(
|
|
panel.querySelector("ul").getAttribute("aria-labelledby"),
|
|
"user-menu-button-profile"
|
|
);
|
|
});
|
|
|
|
test("clicking on an unread notification", async function (assert) {
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
|
|
let repliesBadgeNotification = query(
|
|
"#user-menu-button-replies .badge-notification"
|
|
);
|
|
assert.strictEqual(
|
|
repliesBadgeNotification.textContent.trim(),
|
|
"2",
|
|
"badge shows the right count"
|
|
);
|
|
|
|
await click(".user-menu ul li.replied a");
|
|
|
|
assert.strictEqual(
|
|
requestHeaders["Discourse-Clear-Notifications"],
|
|
123, // id is from the fixtures in fixtures/notification-fixtures.js
|
|
"the Discourse-Clear-Notifications request header is set to the notification id in the next ajax request"
|
|
);
|
|
|
|
await click(".d-header-icons .current-user");
|
|
repliesBadgeNotification = query(
|
|
"#user-menu-button-replies .badge-notification"
|
|
);
|
|
assert.strictEqual(
|
|
repliesBadgeNotification.textContent.trim(),
|
|
"1",
|
|
"badge shows count reduced by one"
|
|
);
|
|
});
|
|
|
|
test("clicking on user menu items", async function (assert) {
|
|
updateCurrentUser({ reviewable_count: 1 });
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-review-queue");
|
|
await click("#quick-access-review-queue li.reviewable.pending a");
|
|
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
"/review/17",
|
|
"clicking on an item results in navigation to the item's page"
|
|
);
|
|
assert.notOk(
|
|
exists(".user-menu"),
|
|
"clicking on an item closes the menu after navigating"
|
|
);
|
|
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-review-queue");
|
|
await click("#quick-access-review-queue li.reviewable.pending a");
|
|
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
"/review/17",
|
|
"clicking on the same item again keeps on the same page"
|
|
);
|
|
assert.notOk(
|
|
exists(".user-menu"),
|
|
"clicking on the same item again closes the menu"
|
|
);
|
|
});
|
|
|
|
test("tabs have title attributes", async function (assert) {
|
|
updateCurrentUser({ reviewable_count: 1 });
|
|
withPluginApi("0.1", (api) => {
|
|
api.registerUserMenuTab((UserMenuTab) => {
|
|
return class extends UserMenuTab {
|
|
get id() {
|
|
return "tiny-tab-1";
|
|
}
|
|
|
|
get count() {
|
|
return this.currentUser.get("unread_high_priority_notifications");
|
|
}
|
|
|
|
get icon() {
|
|
return "wrench";
|
|
}
|
|
|
|
get panelComponent() {
|
|
return "d-button";
|
|
}
|
|
|
|
get title() {
|
|
return `Custom title: ${this.count}`;
|
|
}
|
|
};
|
|
});
|
|
});
|
|
|
|
const expectedTitles = {
|
|
"user-menu-button-all-notifications": I18n.t(
|
|
"user_menu.tabs.all_notifications"
|
|
),
|
|
"user-menu-button-replies": I18n.t("user_menu.tabs.replies_with_unread", {
|
|
count: 2,
|
|
}),
|
|
"user-menu-button-likes": I18n.t("user_menu.tabs.likes"),
|
|
"user-menu-button-messages": I18n.t("user_menu.tabs.messages"),
|
|
"user-menu-button-bookmarks": I18n.t("user_menu.tabs.bookmarks"),
|
|
"user-menu-button-tiny-tab-1": "Custom title: 73",
|
|
"user-menu-button-review-queue": I18n.t(
|
|
"user_menu.tabs.review_queue_with_unread",
|
|
{ count: 1 }
|
|
),
|
|
"user-menu-button-other-notifications": I18n.t(
|
|
"user_menu.tabs.other_notifications"
|
|
),
|
|
"user-menu-button-profile": I18n.t("user_menu.tabs.profile"),
|
|
};
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
for (const [key, title] of Object.entries(expectedTitles)) {
|
|
assert.strictEqual(
|
|
query(`#${key}`).title,
|
|
title,
|
|
`${key} tab has the right title`
|
|
);
|
|
}
|
|
|
|
await publishToMessageBus(`/notification/${loggedInUser().id}`, {
|
|
unread_high_priority_notifications: 22,
|
|
});
|
|
assert.strictEqual(
|
|
query("#user-menu-button-tiny-tab-1").title,
|
|
"Custom title: 22",
|
|
"tabs titles can update dynamically"
|
|
);
|
|
});
|
|
|
|
test("tabs added via the plugin API", async function (assert) {
|
|
updateCurrentUser({ reviewable_count: 1 });
|
|
withPluginApi("0.1", (api) => {
|
|
api.registerUserMenuTab((UserMenuTab) => {
|
|
return class extends UserMenuTab {
|
|
get id() {
|
|
return "custom-tab-1";
|
|
}
|
|
|
|
get count() {
|
|
return this.currentUser.get("unread_high_priority_notifications");
|
|
}
|
|
|
|
get icon() {
|
|
return "wrench";
|
|
}
|
|
|
|
get panelComponent() {
|
|
return "d-button";
|
|
}
|
|
};
|
|
});
|
|
|
|
api.registerUserMenuTab((UserMenuTab) => {
|
|
return class extends UserMenuTab {
|
|
get id() {
|
|
return "custom-tab-2";
|
|
}
|
|
|
|
get count() {
|
|
return 29;
|
|
}
|
|
|
|
get icon() {
|
|
return "plus";
|
|
}
|
|
|
|
get panelComponent() {
|
|
return "d-button";
|
|
}
|
|
};
|
|
});
|
|
});
|
|
const expectedTabOrder = {
|
|
"user-menu-button-all-notifications": "0",
|
|
"user-menu-button-replies": "1",
|
|
"user-menu-button-likes": "2",
|
|
"user-menu-button-messages": "3",
|
|
"user-menu-button-bookmarks": "4",
|
|
"user-menu-button-custom-tab-1": "5",
|
|
"user-menu-button-custom-tab-2": "6",
|
|
"user-menu-button-review-queue": "7",
|
|
"user-menu-button-other-notifications": "8",
|
|
};
|
|
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
|
|
assert.ok(
|
|
exists("#user-menu-button-custom-tab-1"),
|
|
"first custom tab is rendered"
|
|
);
|
|
assert.ok(
|
|
exists("#user-menu-button-custom-tab-2"),
|
|
"second custom tab is rendered"
|
|
);
|
|
|
|
const tabs = [...queryAll(".tabs-list.top-tabs .btn")];
|
|
|
|
assert.deepEqual(
|
|
tabs.reduce((acc, tab) => {
|
|
acc[tab.id] = tab.dataset.tabNumber;
|
|
return acc;
|
|
}, {}),
|
|
expectedTabOrder,
|
|
"data-tab-number of the tabs has no gaps when custom tabs are added and the tabs are in the right order"
|
|
);
|
|
assert.strictEqual(
|
|
query(".tabs-list.bottom-tabs .btn").dataset.tabNumber,
|
|
"9",
|
|
"bottom tab has the correct data-tab-number"
|
|
);
|
|
|
|
let customTab1Bubble = query(
|
|
"#user-menu-button-custom-tab-1 .badge-notification"
|
|
);
|
|
|
|
assert.strictEqual(
|
|
customTab1Bubble.textContent.trim(),
|
|
"73",
|
|
"bubble shows the right count"
|
|
);
|
|
|
|
const customTab2Bubble = query(
|
|
"#user-menu-button-custom-tab-2 .badge-notification"
|
|
);
|
|
|
|
assert.strictEqual(
|
|
customTab2Bubble.textContent.trim(),
|
|
"29",
|
|
"bubble shows the right count"
|
|
);
|
|
|
|
await publishToMessageBus(`/notification/${loggedInUser().id}`, {
|
|
unread_high_priority_notifications: 18,
|
|
});
|
|
|
|
customTab1Bubble = query(
|
|
"#user-menu-button-custom-tab-1 .badge-notification"
|
|
);
|
|
|
|
assert.strictEqual(
|
|
customTab1Bubble.textContent.trim(),
|
|
"18",
|
|
"displayed bubble count updates when the value is changed"
|
|
);
|
|
|
|
await click("#user-menu-button-custom-tab-1");
|
|
|
|
assert.ok(
|
|
exists("#user-menu-button-custom-tab-1.active"),
|
|
"custom tabs can be clicked on and become active"
|
|
);
|
|
|
|
assert.ok(
|
|
exists("#quick-access-custom-tab-1 button.btn"),
|
|
"the tab's content is now displayed in the panel"
|
|
);
|
|
});
|
|
|
|
test("notifications tab applies model transformations registered by plugins", async function (assert) {
|
|
withPluginApi("0.1", (api) => {
|
|
api.registerModelTransformer("notification", (notifications) => {
|
|
notifications.forEach((notification, index) => {
|
|
if (notification.fancy_title) {
|
|
notification.fancy_title = `pluginNotificationTransformer ${index} ${notification.fancy_title}`;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
|
|
const notifications = queryAll(
|
|
"#quick-access-all-notifications ul li.notification"
|
|
);
|
|
assert.strictEqual(
|
|
notifications[0].textContent.replace(/\s+/g, " ").trim(),
|
|
"velesin pluginNotificationTransformer 0 edited topic 443"
|
|
);
|
|
assert.strictEqual(
|
|
notifications[1].textContent.replace(/\s+/g, " ").trim(),
|
|
"velesin pluginNotificationTransformer 1 some title"
|
|
);
|
|
});
|
|
|
|
test("bookmarks tab applies model transformations registered by plugins", async function (assert) {
|
|
withPluginApi("0.1", (api) => {
|
|
api.registerModelTransformer("bookmark", (bookmarks) => {
|
|
bookmarks.forEach((bookmark) => {
|
|
if (bookmark.title) {
|
|
bookmark.title = `pluginBookmarkTransformer ${bookmark.title}`;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-bookmarks");
|
|
|
|
const bookmarks = queryAll("#quick-access-bookmarks ul li.bookmark");
|
|
assert.strictEqual(
|
|
bookmarks[0].textContent.replace(/\s+/g, " ").trim(),
|
|
"osama pluginBookmarkTransformer Test poll topic hello world"
|
|
);
|
|
});
|
|
|
|
test("messages tab applies model transformations registered by plugins", async function (assert) {
|
|
withPluginApi("0.1", (api) => {
|
|
api.registerModelTransformer("topic", (topics) => {
|
|
topics.forEach((topic) => {
|
|
topic.fancy_title = `pluginTransformer#1 ${topic.fancy_title}`;
|
|
});
|
|
});
|
|
api.registerModelTransformer("topic", async (topics) => {
|
|
// sleep 1 ms
|
|
await new Promise((resolve) => later(resolve, 1));
|
|
topics.forEach((topic) => {
|
|
topic.fancy_title = `pluginTransformer#2 ${topic.fancy_title}`;
|
|
});
|
|
});
|
|
});
|
|
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-messages");
|
|
|
|
const messages = queryAll("#quick-access-messages ul li.message");
|
|
assert.strictEqual(
|
|
messages[0].textContent.replace(/\s+/g, " ").trim(),
|
|
"mixtape pluginTransformer#2 pluginTransformer#1 BUG: Can not render emoji properly"
|
|
);
|
|
});
|
|
|
|
test("the profile tab", async function (assert) {
|
|
updateCurrentUser({ draft_count: 13 });
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-profile");
|
|
|
|
const summaryLink = query("#quick-access-profile ul li.summary a");
|
|
assert.ok(
|
|
summaryLink.href.endsWith("/u/eviltrout/summary"),
|
|
"has a link to the summary page of the user"
|
|
);
|
|
assert.strictEqual(
|
|
summaryLink.textContent.trim(),
|
|
I18n.t("user.summary.title"),
|
|
"summary link has the right label"
|
|
);
|
|
assert.ok(
|
|
summaryLink.querySelector(".d-icon-user"),
|
|
"summary link has the right icon"
|
|
);
|
|
|
|
const activityLink = query("#quick-access-profile ul li.activity a");
|
|
assert.ok(
|
|
activityLink.href.endsWith("/u/eviltrout/activity"),
|
|
"has a link to the activity page of the user"
|
|
);
|
|
assert.strictEqual(
|
|
activityLink.textContent.trim(),
|
|
I18n.t("user.activity_stream"),
|
|
"activity link has the right label"
|
|
);
|
|
assert.ok(
|
|
activityLink.querySelector(".d-icon-stream"),
|
|
"activity link has the right icon"
|
|
);
|
|
|
|
const invitesLink = query("#quick-access-profile ul li.invites a");
|
|
assert.ok(
|
|
invitesLink.href.endsWith("/u/eviltrout/invited"),
|
|
"has a link to the invites page of the user"
|
|
);
|
|
assert.strictEqual(
|
|
invitesLink.textContent.trim(),
|
|
I18n.t("user.invited.title"),
|
|
"invites link has the right label"
|
|
);
|
|
assert.ok(
|
|
invitesLink.querySelector(".d-icon-user-plus"),
|
|
"invites link has the right icon"
|
|
);
|
|
|
|
await click("header.d-header"); // close the menu
|
|
updateCurrentUser({ can_invite_to_forum: false });
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-profile");
|
|
|
|
assert.notOk(
|
|
exists("#quick-access-profile ul li.invites"),
|
|
"invites link not shown when the user can't invite"
|
|
);
|
|
|
|
const dratsLink = query("#quick-access-profile ul li.drafts a");
|
|
assert.ok(
|
|
dratsLink.href.endsWith("/u/eviltrout/activity/drafts"),
|
|
"has a link to the drafts page of the user"
|
|
);
|
|
assert.strictEqual(
|
|
dratsLink.textContent.trim(),
|
|
I18n.t("drafts.label_with_count", { count: 13 }),
|
|
"drafts link has the right label with count of the user's drafts"
|
|
);
|
|
assert.ok(
|
|
dratsLink.querySelector(".d-icon-pencil-alt"),
|
|
"drafts link has the right icon"
|
|
);
|
|
|
|
const preferencesLink = query("#quick-access-profile ul li.preferences a");
|
|
assert.ok(
|
|
preferencesLink.href.endsWith("/u/eviltrout/preferences"),
|
|
"has a link to the preferences page of the user"
|
|
);
|
|
assert.strictEqual(
|
|
preferencesLink.textContent.trim(),
|
|
I18n.t("user.preferences"),
|
|
"preferences link has the right label"
|
|
);
|
|
assert.ok(
|
|
preferencesLink.querySelector(".d-icon-cog"),
|
|
"preferences link has the right icon"
|
|
);
|
|
|
|
let doNotDisturbButton = query(
|
|
"#quick-access-profile ul li.do-not-disturb .btn"
|
|
);
|
|
assert.strictEqual(
|
|
doNotDisturbButton.textContent
|
|
.replaceAll(/\s+/g, " ")
|
|
.replaceAll(/\u200B/g, "")
|
|
.trim(),
|
|
I18n.t("do_not_disturb.label"),
|
|
"Do Not Disturb button has the right label"
|
|
);
|
|
assert.ok(
|
|
doNotDisturbButton.querySelector(".d-icon-toggle-off"),
|
|
"Do Not Disturb button has the right icon"
|
|
);
|
|
|
|
await click("header.d-header"); // close the menu
|
|
const date = new Date();
|
|
date.setHours(date.getHours() + 2);
|
|
updateCurrentUser({ do_not_disturb_until: date.toISOString() });
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-profile");
|
|
|
|
doNotDisturbButton = query(
|
|
"#quick-access-profile ul li.do-not-disturb .btn"
|
|
);
|
|
assert.strictEqual(
|
|
doNotDisturbButton.textContent
|
|
.replaceAll(/\s+/g, " ")
|
|
.replaceAll(/\u200B/g, "")
|
|
.trim(),
|
|
`${I18n.t("do_not_disturb.label")} 2h`,
|
|
"Do Not Disturb button has the right label when Do Not Disturb is enabled"
|
|
);
|
|
assert.ok(
|
|
doNotDisturbButton.querySelector(".d-icon-toggle-on"),
|
|
"Do Not Disturb button has the right icon when Do Not Disturb is enabled"
|
|
);
|
|
|
|
let toggleAnonButton = query(
|
|
"#quick-access-profile ul li.enable-anonymous .btn"
|
|
);
|
|
assert.strictEqual(
|
|
toggleAnonButton.textContent
|
|
.replaceAll(/\s+/g, " ")
|
|
.replaceAll(/\u200B/g, "")
|
|
.trim(),
|
|
I18n.t("switch_to_anon"),
|
|
"toggle anonymous button has the right label when the user isn't anonymous"
|
|
);
|
|
assert.ok(
|
|
toggleAnonButton.querySelector(".d-icon-user-secret"),
|
|
"toggle anonymous button has the right icon when the user isn't anonymous"
|
|
);
|
|
|
|
await click("header.d-header"); // close the menu
|
|
updateCurrentUser({ is_anonymous: true });
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-profile");
|
|
|
|
toggleAnonButton = query(
|
|
"#quick-access-profile ul li.disable-anonymous .btn"
|
|
);
|
|
assert.strictEqual(
|
|
toggleAnonButton.textContent
|
|
.replaceAll(/\s+/g, " ")
|
|
.replaceAll(/\u200B/g, "")
|
|
.trim(),
|
|
I18n.t("switch_from_anon"),
|
|
"toggle anonymous button has the right label when the user is anonymous"
|
|
);
|
|
assert.ok(
|
|
toggleAnonButton.querySelector(".d-icon-ban"),
|
|
"toggle anonymous button has the right icon when the user is anonymous"
|
|
);
|
|
|
|
await click("header.d-header"); // close the menu
|
|
updateCurrentUser({ is_anonymous: false, trust_level: 2 });
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-profile");
|
|
|
|
assert.notOk(
|
|
exists("#quick-access-profile ul li.enable-anonymous"),
|
|
"toggle anon button isn't shown when the user can't use it"
|
|
);
|
|
assert.notOk(
|
|
exists("#quick-access-profile ul li.disable-anonymous"),
|
|
"toggle anon button isn't shown when the user can't use it"
|
|
);
|
|
|
|
await click("header.d-header"); // close the menu
|
|
updateCurrentUser({ is_anonymous: true, trust_level: 2 });
|
|
this.siteSettings.allow_anonymous_posting = false;
|
|
this.siteSettings.anonymous_posting_min_trust_level = 3;
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-profile");
|
|
|
|
assert.ok(
|
|
exists("#quick-access-profile ul li.disable-anonymous"),
|
|
"toggle anon button is always shown if the user is anonymous"
|
|
);
|
|
|
|
await click("header.d-header"); // close the menu
|
|
updateCurrentUser({ is_anonymous: false, trust_level: 4 });
|
|
this.siteSettings.allow_anonymous_posting = false;
|
|
this.siteSettings.anonymous_posting_min_trust_level = 3;
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-profile");
|
|
|
|
assert.notOk(
|
|
exists("#quick-access-profile ul li.enable-anonymous"),
|
|
"toggle anon button is not shown if the allow_anonymous_posting setting is false"
|
|
);
|
|
|
|
await click("header.d-header"); // close the menu
|
|
updateCurrentUser({ is_anonymous: false, trust_level: 2 });
|
|
this.siteSettings.allow_anonymous_posting = true;
|
|
this.siteSettings.anonymous_posting_min_trust_level = 3;
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-profile");
|
|
|
|
assert.notOk(
|
|
exists("#quick-access-profile ul li.enable-anonymous"),
|
|
"toggle anon button is not shown if the user doesn't have a high enough trust level"
|
|
);
|
|
|
|
const logoutButton = query("#quick-access-profile ul li.logout .btn");
|
|
assert.strictEqual(
|
|
logoutButton.textContent
|
|
.replaceAll(/\s+/g, " ")
|
|
.replaceAll(/\u200B/g, "")
|
|
.trim(),
|
|
I18n.t("user.log_out"),
|
|
"logout button has the right label"
|
|
);
|
|
assert.ok(
|
|
logoutButton.querySelector(".d-icon-sign-out-alt"),
|
|
"logout button has the right icon"
|
|
);
|
|
});
|
|
|
|
test("the active tab can be clicked again to navigate to a page", async function (assert) {
|
|
updateCurrentUser({ reviewable_count: 1 });
|
|
withPluginApi("0.1", (api) => {
|
|
api.registerUserMenuTab((UserMenuTab) => {
|
|
return class extends UserMenuTab {
|
|
get id() {
|
|
return "custom-tab-1";
|
|
}
|
|
|
|
get icon() {
|
|
return "wrench";
|
|
}
|
|
|
|
get panelComponent() {
|
|
return "d-button";
|
|
}
|
|
|
|
get linkWhenActive() {
|
|
return "/u/eviltrout/preferences";
|
|
}
|
|
};
|
|
});
|
|
|
|
api.registerUserMenuTab((UserMenuTab) => {
|
|
return class extends UserMenuTab {
|
|
get id() {
|
|
return "custom-tab-2";
|
|
}
|
|
|
|
get icon() {
|
|
return "plus";
|
|
}
|
|
|
|
get panelComponent() {
|
|
return "d-button";
|
|
}
|
|
};
|
|
});
|
|
});
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
await click("#user-menu-button-all-notifications");
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
"/u/eviltrout/notifications",
|
|
"clicking on active tab navigates to the page it links to"
|
|
);
|
|
assert.notOk(exists(".user-menu"), "user menu is closed after navigating");
|
|
|
|
const tabs = [
|
|
["#user-menu-button-custom-tab-1", "/u/eviltrout/preferences/account"],
|
|
["#user-menu-button-replies", "/u/eviltrout/notifications/responses"],
|
|
["#user-menu-button-messages", "/u/eviltrout/messages"],
|
|
["#user-menu-button-bookmarks", "/u/eviltrout/activity/bookmarks"],
|
|
["#user-menu-button-likes", "/u/eviltrout/notifications/likes-received"],
|
|
["#user-menu-button-custom-tab-2", null],
|
|
["#user-menu-button-review-queue", "/review"],
|
|
["#user-menu-button-profile", "/u/eviltrout/summary"],
|
|
];
|
|
for (const [id, expectedLink] of tabs) {
|
|
await click(".d-header-icons .current-user");
|
|
await click(id);
|
|
await click(id);
|
|
if (expectedLink) {
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
expectedLink,
|
|
`clicking on the ${id} tab navigates to ${expectedLink}`
|
|
);
|
|
assert.notOk(
|
|
exists(".user-menu"),
|
|
"user menu is closed after navigating"
|
|
);
|
|
} else {
|
|
assert.ok(
|
|
exists(".user-menu"),
|
|
"user menu remains open if tab doesn't link to anywhere"
|
|
);
|
|
}
|
|
await click("#site-logo");
|
|
}
|
|
});
|
|
});
|
|
|
|
acceptance("User menu - Dismiss button", function (needs) {
|
|
needs.user({
|
|
redesigned_user_menu_enabled: true,
|
|
unread_high_priority_notifications: 10,
|
|
grouped_unread_notifications: {
|
|
[NOTIFICATION_TYPES.bookmark_reminder]: 103,
|
|
[NOTIFICATION_TYPES.private_message]: 89,
|
|
[NOTIFICATION_TYPES.votes_released]: 1,
|
|
[NOTIFICATION_TYPES.code_review_commit_approved]: 3,
|
|
},
|
|
});
|
|
|
|
let markRead = false;
|
|
let markReadRequestBody;
|
|
|
|
needs.pretender((server, helper) => {
|
|
server.put("/notifications/mark-read", (request) => {
|
|
markReadRequestBody = request.requestBody;
|
|
markRead = true;
|
|
return helper.response({ success: true });
|
|
});
|
|
|
|
server.get("/u/eviltrout/user-menu-bookmarks", () => {
|
|
if (markRead) {
|
|
const copy = cloneJSON(
|
|
UserMenuFixtures["/u/:username/user-menu-bookmarks"]
|
|
);
|
|
copy.notifications = [];
|
|
return helper.response(copy);
|
|
} else {
|
|
return helper.response(
|
|
UserMenuFixtures["/u/:username/user-menu-bookmarks"]
|
|
);
|
|
}
|
|
});
|
|
|
|
server.get("/u/eviltrout/user-menu-private-messages", () => {
|
|
if (markRead) {
|
|
const copy = cloneJSON(
|
|
UserMenuFixtures["/u/:username/user-menu-private-messages"]
|
|
);
|
|
copy.unread_notifications = [];
|
|
return helper.response(copy);
|
|
} else {
|
|
return helper.response(
|
|
UserMenuFixtures["/u/:username/user-menu-private-messages"]
|
|
);
|
|
}
|
|
});
|
|
});
|
|
|
|
needs.hooks.afterEach(() => {
|
|
markRead = false;
|
|
markReadRequestBody = null;
|
|
});
|
|
|
|
test("shows confirmation modal for the all-notifications list", async function (assert) {
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
|
|
await click(".user-menu .notifications-dismiss");
|
|
assert.strictEqual(
|
|
query(".dismiss-notification-confirmation").textContent.trim(),
|
|
I18n.t("notifications.dismiss_confirmation.body.default", { count: 10 }),
|
|
"confirmation modal is shown when there are unread high pri notifications"
|
|
);
|
|
|
|
await click(".modal-footer .btn-default"); // click cancel on the dismiss modal
|
|
assert.notOk(markRead, "mark-read request isn't sent");
|
|
|
|
await click(".user-menu .notifications-dismiss");
|
|
await click(".modal-footer .btn-primary"); // click confirm on the dismiss modal
|
|
assert.ok(markRead, "mark-read request is sent");
|
|
});
|
|
|
|
test("shows confirmation modal for the bookmarks list", async function (assert) {
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
|
|
assert.strictEqual(
|
|
query("#user-menu-button-bookmarks .badge-notification").textContent,
|
|
"103",
|
|
"bookmarks tab has bubble with count"
|
|
);
|
|
|
|
await click("#user-menu-button-bookmarks");
|
|
assert.ok(
|
|
exists("#quick-access-bookmarks ul li.notification"),
|
|
"bookmark reminder notifications are visible"
|
|
);
|
|
assert.ok(
|
|
exists("#quick-access-bookmarks ul li.bookmark"),
|
|
"bookmarks are visible"
|
|
);
|
|
|
|
await click(".user-menu .notifications-dismiss");
|
|
|
|
assert.strictEqual(
|
|
query(".dismiss-notification-confirmation").textContent.trim(),
|
|
I18n.t("notifications.dismiss_confirmation.body.bookmarks", {
|
|
count: 103,
|
|
}),
|
|
"confirmation modal is shown when there are unread bookmark reminder notifications"
|
|
);
|
|
assert.notOk(markRead, "mark-read request isn't sent");
|
|
|
|
await click(".modal-footer .btn-primary"); // confirm dismiss on the dismiss modal
|
|
|
|
assert.notOk(
|
|
exists("#quick-access-bookmarks ul li.notification"),
|
|
"bookmark reminder notifications are gone"
|
|
);
|
|
assert.ok(
|
|
exists("#quick-access-bookmarks ul li.bookmark"),
|
|
"bookmarks are still visible"
|
|
);
|
|
assert.notOk(
|
|
exists("#user-menu-button-bookmarks .badge-notification"),
|
|
"bookmarks tab no longer has bubble"
|
|
);
|
|
assert.ok(markRead, "mark-read request is sent");
|
|
assert.strictEqual(
|
|
markReadRequestBody,
|
|
"dismiss_types=bookmark_reminder",
|
|
"mark-read request specifies bookmark_reminder types"
|
|
);
|
|
assert.notOk(exists(".user-menu .notifications-dismiss"));
|
|
});
|
|
|
|
test("shows confirmation modal for the messages list", async function (assert) {
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
|
|
assert.strictEqual(
|
|
query("#user-menu-button-messages .badge-notification").textContent,
|
|
"89",
|
|
"messages tab has bubble with count"
|
|
);
|
|
|
|
await click("#user-menu-button-messages");
|
|
assert.ok(
|
|
exists("#quick-access-messages ul li.notification"),
|
|
"messages notifications are visible"
|
|
);
|
|
assert.ok(
|
|
exists("#quick-access-messages ul li.message"),
|
|
"messages are visible"
|
|
);
|
|
|
|
await click(".user-menu .notifications-dismiss");
|
|
|
|
assert.strictEqual(
|
|
query(".dismiss-notification-confirmation").textContent.trim(),
|
|
I18n.t("notifications.dismiss_confirmation.body.messages", {
|
|
count: 89,
|
|
}),
|
|
"confirmation modal is shown when there are unread messages notifications"
|
|
);
|
|
assert.notOk(markRead, "mark-read request isn't sent");
|
|
|
|
await click(".modal-footer .btn-primary"); // confirm dismiss on the dismiss modal
|
|
|
|
assert.notOk(
|
|
exists("#quick-access-messages ul li.notification"),
|
|
"messages notifications are gone"
|
|
);
|
|
assert.ok(
|
|
exists("#quick-access-messages ul li.message"),
|
|
"messages are still visible"
|
|
);
|
|
assert.notOk(
|
|
exists("#user-menu-button-messages .badge-notification"),
|
|
"messages tab no longer has bubble"
|
|
);
|
|
assert.ok(markRead, "mark-read request is sent");
|
|
assert.strictEqual(
|
|
markReadRequestBody,
|
|
"dismiss_types=private_message%2Cgroup_message_summary",
|
|
"mark-read request specifies private_message types"
|
|
);
|
|
assert.notOk(exists(".user-menu .notifications-dismiss"));
|
|
});
|
|
|
|
test("doesn't show confirmation modal for the likes notifications list", async function (assert) {
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
|
|
await click("#user-menu-button-likes");
|
|
await click(".user-menu .notifications-dismiss");
|
|
assert.ok(
|
|
markRead,
|
|
"mark-read request is sent without a confirmation modal"
|
|
);
|
|
});
|
|
|
|
test("doesn't show confirmation modal for the other notifications list", async function (assert) {
|
|
await visit("/");
|
|
await click(".d-header-icons .current-user");
|
|
|
|
await click("#user-menu-button-other-notifications");
|
|
let othersBadgeNotification = query(
|
|
"#user-menu-button-other-notifications .badge-notification"
|
|
);
|
|
assert.strictEqual(
|
|
othersBadgeNotification.textContent.trim(),
|
|
"4",
|
|
"badge shows the right count"
|
|
);
|
|
|
|
await click(".user-menu .notifications-dismiss");
|
|
|
|
assert.ok(
|
|
!exists("#user-menu-button-other-notifications .badge-notification")
|
|
);
|
|
assert.ok(
|
|
markRead,
|
|
"mark-read request is sent without a confirmation modal"
|
|
);
|
|
});
|
|
});
|