DEV: Add more keyboard shortcut acceptance tests (#13280)

This adds acceptance tests for keyboard shortcuts to
dismiss new and unread topics.

Also, I cleaned out a few old specs for the unit test for
keyboard-shortcuts. Some were introduced way back in
5100c2bbd2
but then supplanted by
9548876c2d
and never cleaned up, so they were doing nothing.

Follow up to https://review.discourse.org/t/fix-dismiss-topics-keyboard-shortcut-not-working-pr-13260/22157/4?u=martin
This commit is contained in:
Martin Brennan 2021-06-04 14:04:20 +10:00 committed by GitHub
parent 27763da412
commit b01e4738ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 110 deletions

View File

@ -9,5 +9,6 @@
class="btn-primary"
action=(route-action "dismissReadTopics" dismissTopics)
icon="check"
id="dismiss-read-confirm"
label="topics.bulk.dismiss"}}
</div>

View File

@ -1,8 +1,11 @@
import { currentURL, triggerKeyEvent, visit } from "@ember/test-helpers";
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
import { cloneJSON } from "discourse-common/lib/object";
import I18n from "I18n";
import { acceptance, queryAll } from "discourse/tests/helpers/qunit-helpers";
import DiscoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
import { test } from "qunit";
acceptance("Keyboard Shortcuts", function (needs) {
acceptance("Keyboard Shortcuts - Anonymous Users", function (needs) {
needs.pretender((server, helper) => {
server.get("/t/27331/4.json", () => helper.response({}));
server.get("/t/27331.json", () => helper.response({}));
@ -41,3 +44,93 @@ acceptance("Keyboard Shortcuts", function (needs) {
assert.equal(currentURL(), "/t/keyboard-shortcuts-are-awesome/27331");
});
});
acceptance("Keyboard Shortcuts - Authenticated Users", function (needs) {
let resetNewCalled;
let markReadCalled;
let topicList;
needs.user();
needs.hooks.beforeEach(() => {
resetNewCalled = 0;
markReadCalled = 0;
});
needs.pretender((server, helper) => {
topicList = cloneJSON(DiscoveryFixtures["/latest.json"]);
// get rid of some of the topics and the more_topics_url
// so we consider them allLoaded and show the footer with
// the bottom dismiss button
topicList.topic_list.topics.splice(20, 30);
topicList.topic_list.more_topics_url = null;
server.get("/unread.json", () => {
return helper.response(topicList);
});
server.get("/new.json", () => {
return helper.response(topicList);
});
server.put("/topics/reset-new", () => {
resetNewCalled += 1;
return helper.response({});
});
server.put("/topics/bulk", () => {
markReadCalled += 1;
return helper.response({});
});
});
test("dismiss unread from top and bottom button", async function (assert) {
await visit("/unread");
await triggerKeyEvent(document, "keypress", "x".charCodeAt(0));
await triggerKeyEvent(document, "keypress", "t".charCodeAt(0));
assert.ok(exists("#dismiss-read-confirm"));
assert.equal(
queryAll(".modal-body").text().trim(),
I18n.t("topics.bulk.also_dismiss_topics")
);
await click("#dismiss-read-confirm");
assert.equal(markReadCalled, 1);
// we get rid of all but one topic so the top dismiss button doesn't
// show up, as it only appears if there are too many topics pushing
// the bottom button out of the viewport
let originalTopics = [...topicList.topic_list.topics];
topicList.topic_list.topics = [topicList.topic_list.topics[0]];
await visit("/unread");
await triggerKeyEvent(document, "keypress", "x".charCodeAt(0));
await triggerKeyEvent(document, "keypress", "t".charCodeAt(0));
assert.ok(exists("#dismiss-read-confirm"));
assert.equal(
queryAll(".modal-body").text().trim(),
"Stop tracking these topics so they never show up as unread for me again"
);
await click("#dismiss-read-confirm");
assert.equal(markReadCalled, 2);
// restore the original topic list
topicList.topic_list.topics = originalTopics;
});
test("dismiss new from top and bottom button", async function (assert) {
await visit("/new");
await triggerKeyEvent(document, "keypress", "x".charCodeAt(0));
await triggerKeyEvent(document, "keypress", "r".charCodeAt(0));
assert.equal(resetNewCalled, 1);
// we get rid of all but one topic so the top dismiss button doesn't
// show up, as it only appears if there are too many topics pushing
// the bottom button out of the viewport
let originalTopics = [...topicList.topic_list.topics];
topicList.topic_list.topics = [topicList.topic_list.topics[0]];
await visit("/new");
await triggerKeyEvent(document, "keypress", "x".charCodeAt(0));
await triggerKeyEvent(document, "keypress", "r".charCodeAt(0));
assert.equal(resetNewCalled, 2);
// restore the original topic list
topicList.topic_list.topics = originalTopics;
});
});

View File

@ -3,117 +3,9 @@ import DiscourseURL from "discourse/lib/url";
import KeyboardShortcuts from "discourse/lib/keyboard-shortcuts";
import sinon from "sinon";
let testMouseTrap;
module("Unit | Utility | keyboard-shortcuts", function (hooks) {
hooks.beforeEach(function () {
let _bindings = {};
testMouseTrap = {
bind: function (bindings, callback) {
let registerBinding = function (binding) {
_bindings[binding] = callback;
}.bind(this);
if (Array.isArray(bindings)) {
bindings.forEach(registerBinding, this);
} else {
registerBinding(bindings);
}
},
trigger: function (binding) {
_bindings[binding].call();
},
};
sinon.stub(DiscourseURL, "routeTo");
$("#qunit-fixture").html(
[
"<article class='topic-post selected'>",
"<a class='post-date'></a>" + "</article>",
"<div class='notification-options'>",
" <ul>",
" <li data-id='0'><a></a></li>",
" <li data-id='1'><a></a></li>",
" <li data-id='2'><a></a></li>",
" <li data-id='3'><a></a></li>",
" </ul>",
"</div>",
"<table class='topic-list'>",
" <tr class='topic-list-item selected'><td>",
" <a class='title'></a>",
" </td></tr>",
"</table>",
"<div id='topic-footer-buttons'>",
" <button class='star'></button>",
" <button class='create'></button>",
" <button class='share'></button>",
" <button id='dismiss-new-top'></button>",
" <button id='dismiss-topics-top'></button>",
"</div>",
"<div class='alert alert-info clickable'></div>",
"<button id='create-topic'></button>",
"<div id='user-notifications'></div>",
"<div id='toggle-hamburger-menu'></div>",
"<div id='search-button'></div>",
"<div id='current-user'></div>",
"<div id='keyboard-help'></div>",
].join("\n")
);
});
hooks.afterEach(function () {
$("#qunit-scratch").html("");
testMouseTrap = undefined;
});
let pathBindings = KeyboardShortcuts.PATH_BINDINGS || {};
Object.keys(pathBindings).forEach((path) => {
const binding = pathBindings[path];
let testName = binding + " goes to " + path;
test(testName, function (assert) {
KeyboardShortcuts.bindEvents();
testMouseTrap.trigger(binding);
assert.ok(DiscourseURL.routeTo.calledWith(path));
});
});
let clickBindings = KeyboardShortcuts.CLICK_BINDINGS || {};
Object.keys(clickBindings).forEach((selector) => {
const binding = clickBindings[selector];
let bindings = binding.split(",");
let testName = binding + " clicks on " + selector;
test(testName, function (assert) {
KeyboardShortcuts.bindEvents();
$(selector).on("click", function () {
assert.ok(true, selector + " was clicked");
});
bindings.forEach(function (b) {
testMouseTrap.trigger(b);
}, this);
});
});
let functionBindings = KeyboardShortcuts.FUNCTION_BINDINGS || {};
Object.keys(functionBindings).forEach((func) => {
const binding = functionBindings[func];
let testName = binding + " calls " + func;
test(testName, function (assert) {
sinon.stub(KeyboardShortcuts, func, function () {
assert.ok(true, func + " is called when " + binding + " is triggered");
});
KeyboardShortcuts.bindEvents();
testMouseTrap.trigger(binding);
});
});
test("selectDown calls _moveSelection with 1", function (assert) {