2020-08-01 03:43:15 +02:00
|
|
|
"use strict";
|
|
|
|
|
2020-11-30 23:46:45 +01:00
|
|
|
const {strict: assert} = require("assert");
|
|
|
|
|
zjsunit: Remove rewiremock dependency.
We now just use a module._load hook to inject
stubs into our code.
For conversion purposes I temporarily maintain
the API of rewiremock, apart from the enable/disable
pieces, but I will make a better wrapper in an
upcoming commit.
We can detect when rewiremock is called after
zrequire now, and I fix all the violations in
this commit, mostly by using override.
We can also detect when a mock is needlessly
created, and I fix all the violations in this
commit.
The one minor nuisance that this commit introduces
is that you can only stub out modules in the Zulip
source tree, which is now static/js. This should
not really be a problem--there are usually better
techniques to deal with third party depenencies.
In the prior commit I show a typical workaround,
which is to create a one-line wrapper in your
test code. It's often the case that you can simply
use override(), as well.
In passing I kill off `reset_modules`, and I
eliminated the second argument to zrequire,
which dates back to pre-es6 days.
2021-03-06 12:47:54 +01:00
|
|
|
const {
|
2021-03-10 06:10:32 +01:00
|
|
|
mock_esm,
|
zjsunit: Remove rewiremock dependency.
We now just use a module._load hook to inject
stubs into our code.
For conversion purposes I temporarily maintain
the API of rewiremock, apart from the enable/disable
pieces, but I will make a better wrapper in an
upcoming commit.
We can detect when rewiremock is called after
zrequire now, and I fix all the violations in
this commit, mostly by using override.
We can also detect when a mock is needlessly
created, and I fix all the violations in this
commit.
The one minor nuisance that this commit introduces
is that you can only stub out modules in the Zulip
source tree, which is now static/js. This should
not really be a problem--there are usually better
techniques to deal with third party depenencies.
In the prior commit I show a typical workaround,
which is to create a one-line wrapper in your
test code. It's often the case that you can simply
use override(), as well.
In passing I kill off `reset_modules`, and I
eliminated the second argument to zrequire,
which dates back to pre-es6 days.
2021-03-06 12:47:54 +01:00
|
|
|
set_global,
|
|
|
|
with_field,
|
|
|
|
with_overrides,
|
|
|
|
zrequire,
|
|
|
|
} = require("../zjsunit/namespace");
|
2021-02-13 03:46:14 +01:00
|
|
|
const {make_stub} = require("../zjsunit/stub");
|
2020-12-01 00:39:47 +01:00
|
|
|
const {run_test} = require("../zjsunit/test");
|
2020-12-01 00:02:16 +01:00
|
|
|
|
2017-03-20 06:05:54 +01:00
|
|
|
// Important note on these tests:
|
2021-03-06 17:37:51 +01:00
|
|
|
|
2017-03-20 06:05:54 +01:00
|
|
|
//
|
|
|
|
// The way the Zulip hotkey tests work is as follows. First, we set
|
|
|
|
// up various contexts by monkey-patching the various hotkeys exports
|
2017-05-27 15:40:54 +02:00
|
|
|
// functions (like overlays.settings_open). Within that context, to
|
2017-03-20 06:05:54 +01:00
|
|
|
// test whether a given key (e.g. `x`) results in a specific function
|
|
|
|
// (e.g. `ui.foo()`), we fail to import any modules other than
|
|
|
|
// hotkey.js so that accessing them will result in a ReferenceError.
|
|
|
|
//
|
|
|
|
// Then we create a stub `ui.foo`, and call the hotkey function. If
|
|
|
|
// it calls any external module other than `ui.foo`, it'll crash.
|
|
|
|
// Future work includes making sure it actually does call `ui.foo()`.
|
|
|
|
|
2020-09-20 10:14:24 +02:00
|
|
|
// Since all the tests here are based on narrow starting with all_messages.
|
|
|
|
// We set our default narrow to all messages here.
|
|
|
|
window.location.hash = "#all_messages";
|
|
|
|
|
2020-07-15 01:29:15 +02:00
|
|
|
set_global("navigator", {
|
|
|
|
platform: "",
|
2018-03-29 22:29:10 +02:00
|
|
|
});
|
|
|
|
|
2018-04-12 22:38:31 +02:00
|
|
|
// jQuery stuff should go away if we make an initialize() method.
|
2020-07-15 01:29:15 +02:00
|
|
|
set_global("document", "document-stub");
|
2017-03-14 18:29:38 +01:00
|
|
|
|
2021-03-22 16:09:12 +01:00
|
|
|
const browser_history = mock_esm("../../static/js/browser_history");
|
2021-03-10 06:10:32 +01:00
|
|
|
const compose_actions = mock_esm("../../static/js/compose_actions");
|
|
|
|
const condense = mock_esm("../../static/js/condense");
|
|
|
|
const drafts = mock_esm("../../static/js/drafts");
|
|
|
|
const emoji_picker = mock_esm("../../static/js/emoji_picker", {
|
2021-03-07 13:57:14 +01:00
|
|
|
reactions_popped: () => false,
|
|
|
|
});
|
2021-03-10 06:10:32 +01:00
|
|
|
const gear_menu = mock_esm("../../static/js/gear_menu", {
|
2021-03-07 13:57:14 +01:00
|
|
|
is_open: () => false,
|
|
|
|
});
|
2021-03-10 06:10:32 +01:00
|
|
|
const lightbox = mock_esm("../../static/js/lightbox");
|
|
|
|
const list_util = mock_esm("../../static/js/list_util");
|
|
|
|
const message_edit = mock_esm("../../static/js/message_edit");
|
2021-03-30 02:21:21 +02:00
|
|
|
const message_lists = mock_esm("../../static/js/message_lists");
|
2021-07-08 20:36:52 +02:00
|
|
|
const muted_topics_ui = mock_esm("../../static/js/muted_topics_ui");
|
2021-03-10 06:10:32 +01:00
|
|
|
const narrow = mock_esm("../../static/js/narrow");
|
|
|
|
const navigate = mock_esm("../../static/js/navigate");
|
|
|
|
const overlays = mock_esm("../../static/js/overlays", {
|
2021-03-07 13:57:14 +01:00
|
|
|
is_active: () => false,
|
|
|
|
settings_open: () => false,
|
|
|
|
streams_open: () => false,
|
|
|
|
lightbox_open: () => false,
|
|
|
|
drafts_open: () => false,
|
|
|
|
info_overlay_open: () => false,
|
2021-07-08 08:37:44 +02:00
|
|
|
is_modal_open: () => false,
|
2021-03-07 13:57:14 +01:00
|
|
|
});
|
2021-03-10 06:10:32 +01:00
|
|
|
const popovers = mock_esm("../../static/js/popovers", {
|
2021-03-07 13:57:14 +01:00
|
|
|
actions_popped: () => false,
|
|
|
|
message_info_popped: () => false,
|
|
|
|
user_sidebar_popped: () => false,
|
|
|
|
user_info_popped: () => false,
|
|
|
|
});
|
2021-03-10 06:10:32 +01:00
|
|
|
const reactions = mock_esm("../../static/js/reactions");
|
|
|
|
const search = mock_esm("../../static/js/search");
|
2021-04-28 21:58:33 +02:00
|
|
|
const settings_data = mock_esm("../../static/js/settings_data");
|
2021-03-10 06:10:32 +01:00
|
|
|
const stream_list = mock_esm("../../static/js/stream_list");
|
2021-07-09 15:51:31 +02:00
|
|
|
const stream_settings_ui = mock_esm("../../static/js/stream_settings_ui");
|
2021-02-28 21:32:47 +01:00
|
|
|
|
2021-03-10 06:10:32 +01:00
|
|
|
mock_esm("../../static/js/hotspots", {
|
2021-03-07 13:57:14 +01:00
|
|
|
is_open: () => false,
|
|
|
|
});
|
2017-04-04 18:14:27 +02:00
|
|
|
|
2021-06-10 14:18:46 +02:00
|
|
|
mock_esm("../../static/js/recent_topics_util", {
|
2021-03-06 17:37:51 +01:00
|
|
|
is_visible: () => false,
|
2021-03-30 10:38:06 +02:00
|
|
|
is_in_focus: () => false,
|
2021-03-06 17:37:51 +01:00
|
|
|
});
|
2021-03-07 13:57:14 +01:00
|
|
|
|
2021-04-03 21:08:07 +02:00
|
|
|
mock_esm("../../static/js/stream_popover", {
|
|
|
|
stream_popped: () => false,
|
|
|
|
topic_popped: () => false,
|
|
|
|
all_messages_popped: () => false,
|
|
|
|
starred_messages_popped: () => false,
|
|
|
|
});
|
|
|
|
|
2021-03-30 02:21:21 +02:00
|
|
|
message_lists.current = {
|
2021-02-26 14:04:11 +01:00
|
|
|
empty() {
|
|
|
|
return false;
|
|
|
|
},
|
2020-07-20 22:18:43 +02:00
|
|
|
selected_id() {
|
2017-03-19 05:19:36 +01:00
|
|
|
return 42;
|
|
|
|
},
|
2020-07-20 22:18:43 +02:00
|
|
|
selected_message() {
|
2017-03-19 05:19:36 +01:00
|
|
|
return {
|
|
|
|
sent_by_me: true,
|
|
|
|
flags: ["read", "starred"],
|
|
|
|
};
|
|
|
|
},
|
2020-07-20 22:18:43 +02:00
|
|
|
selected_row() {},
|
|
|
|
get_row() {
|
2019-04-06 15:57:48 +02:00
|
|
|
return 101;
|
|
|
|
},
|
2021-03-30 02:21:21 +02:00
|
|
|
};
|
2017-03-10 22:24:54 +01:00
|
|
|
|
zjsunit: Remove rewiremock dependency.
We now just use a module._load hook to inject
stubs into our code.
For conversion purposes I temporarily maintain
the API of rewiremock, apart from the enable/disable
pieces, but I will make a better wrapper in an
upcoming commit.
We can detect when rewiremock is called after
zrequire now, and I fix all the violations in
this commit, mostly by using override.
We can also detect when a mock is needlessly
created, and I fix all the violations in this
commit.
The one minor nuisance that this commit introduces
is that you can only stub out modules in the Zulip
source tree, which is now static/js. This should
not really be a problem--there are usually better
techniques to deal with third party depenencies.
In the prior commit I show a typical workaround,
which is to create a one-line wrapper in your
test code. It's often the case that you can simply
use override(), as well.
In passing I kill off `reset_modules`, and I
eliminated the second argument to zrequire,
which dates back to pre-es6 days.
2021-03-06 12:47:54 +01:00
|
|
|
const emoji_codes = zrequire("../generated/emoji/emoji_codes.json");
|
|
|
|
const emoji = zrequire("../shared/js/emoji");
|
2020-12-01 23:21:38 +01:00
|
|
|
const activity = zrequire("activity");
|
|
|
|
const hotkey = zrequire("hotkey");
|
|
|
|
|
|
|
|
emoji.initialize({
|
|
|
|
realm_emoji: {},
|
|
|
|
emoji_codes,
|
|
|
|
});
|
|
|
|
|
2021-02-11 01:23:23 +01:00
|
|
|
function stubbing(module, func_name_to_stub, test_function) {
|
2020-12-01 00:02:16 +01:00
|
|
|
with_overrides((override) => {
|
2021-02-13 03:46:14 +01:00
|
|
|
const stub = make_stub();
|
|
|
|
override(module, func_name_to_stub, stub.f);
|
|
|
|
test_function(stub);
|
2017-03-10 22:24:54 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-02-26 14:04:11 +01:00
|
|
|
// Set up defaults for most tests.
|
2021-02-28 01:06:02 +01:00
|
|
|
hotkey.__Rewire__("in_content_editable_widget", () => false);
|
|
|
|
hotkey.__Rewire__("processing_text", () => false);
|
2021-02-26 14:04:11 +01:00
|
|
|
|
2020-07-15 01:29:15 +02:00
|
|
|
run_test("mappings", () => {
|
2017-03-13 21:41:28 +01:00
|
|
|
function map_press(which, shiftKey) {
|
|
|
|
return hotkey.get_keypress_hotkey({
|
2020-07-20 22:18:43 +02:00
|
|
|
which,
|
|
|
|
shiftKey,
|
2017-03-13 21:41:28 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-08-14 00:05:36 +02:00
|
|
|
function map_down(which, shiftKey, ctrlKey, metaKey) {
|
2017-03-13 21:41:28 +01:00
|
|
|
return hotkey.get_keydown_hotkey({
|
2020-07-20 22:18:43 +02:00
|
|
|
which,
|
|
|
|
shiftKey,
|
|
|
|
ctrlKey,
|
|
|
|
metaKey,
|
2017-03-13 21:41:28 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// The next assertion protects against an iOS bug where we
|
|
|
|
// treat "!" as a hotkey, because iOS sends the wrong code.
|
|
|
|
assert.equal(map_press(33), undefined);
|
|
|
|
|
|
|
|
// Test page-up does work.
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(map_down(33).name, "page_up");
|
2017-03-13 21:41:28 +01:00
|
|
|
|
|
|
|
// Test other mappings.
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(map_down(9).name, "tab");
|
|
|
|
assert.equal(map_down(9, true).name, "shift_tab");
|
|
|
|
assert.equal(map_down(27).name, "escape");
|
|
|
|
assert.equal(map_down(37).name, "left_arrow");
|
|
|
|
assert.equal(map_down(13).name, "enter");
|
|
|
|
assert.equal(map_down(46).name, "delete");
|
|
|
|
assert.equal(map_down(13, true).name, "enter");
|
|
|
|
|
|
|
|
assert.equal(map_press(47).name, "search"); // slash
|
|
|
|
assert.equal(map_press(106).name, "vim_down"); // j
|
|
|
|
|
2020-08-11 02:09:14 +02:00
|
|
|
assert.equal(map_down(219, false, true).name, "escape"); // Ctrl + [
|
|
|
|
assert.equal(map_down(67, false, true).name, "copy_with_c"); // Ctrl + C
|
|
|
|
assert.equal(map_down(75, false, true).name, "search_with_k"); // Ctrl + K
|
|
|
|
assert.equal(map_down(83, false, true).name, "star_message"); // Ctrl + S
|
|
|
|
assert.equal(map_down(190, false, true).name, "narrow_to_compose_target"); // Ctrl + .
|
2017-03-19 19:26:13 +01:00
|
|
|
|
2017-03-13 21:41:28 +01:00
|
|
|
// More negative tests.
|
|
|
|
assert.equal(map_down(47), undefined);
|
|
|
|
assert.equal(map_press(27), undefined);
|
|
|
|
assert.equal(map_down(27, true), undefined);
|
2020-08-11 02:09:14 +02:00
|
|
|
assert.equal(map_down(86, false, true), undefined); // Ctrl + V
|
|
|
|
assert.equal(map_down(90, false, true), undefined); // Ctrl + Z
|
|
|
|
assert.equal(map_down(84, false, true), undefined); // Ctrl + T
|
|
|
|
assert.equal(map_down(82, false, true), undefined); // Ctrl + R
|
|
|
|
assert.equal(map_down(79, false, true), undefined); // Ctrl + O
|
|
|
|
assert.equal(map_down(80, false, true), undefined); // Ctrl + P
|
|
|
|
assert.equal(map_down(65, false, true), undefined); // Ctrl + A
|
|
|
|
assert.equal(map_down(70, false, true), undefined); // Ctrl + F
|
|
|
|
assert.equal(map_down(72, false, true), undefined); // Ctrl + H
|
|
|
|
assert.equal(map_down(88, false, true), undefined); // Ctrl + X
|
|
|
|
assert.equal(map_down(78, false, true), undefined); // Ctrl + N
|
|
|
|
assert.equal(map_down(77, false, true), undefined); // Ctrl + M
|
|
|
|
assert.equal(map_down(67, false, false, true), undefined); // Cmd + C
|
|
|
|
assert.equal(map_down(75, false, false, true), undefined); // Cmd + K
|
|
|
|
assert.equal(map_down(83, false, false, true), undefined); // Cmd + S
|
|
|
|
assert.equal(map_down(75, true, true), undefined); // Shift + Ctrl + K
|
|
|
|
assert.equal(map_down(83, true, true), undefined); // Shift + Ctrl + S
|
|
|
|
assert.equal(map_down(219, true, true, false), undefined); // Shift + Ctrl + [
|
|
|
|
|
|
|
|
// Cmd tests for MacOS
|
2020-12-01 00:57:57 +01:00
|
|
|
navigator.platform = "MacIntel";
|
2020-08-11 02:09:14 +02:00
|
|
|
assert.equal(map_down(219, false, true, false).name, "escape"); // Ctrl + [
|
|
|
|
assert.equal(map_down(219, false, false, true), undefined); // Cmd + [
|
|
|
|
assert.equal(map_down(67, false, true, true).name, "copy_with_c"); // Ctrl + C
|
|
|
|
assert.equal(map_down(67, false, true, false), undefined); // Cmd + C
|
|
|
|
assert.equal(map_down(75, false, false, true).name, "search_with_k"); // Cmd + K
|
|
|
|
assert.equal(map_down(75, false, true, false), undefined); // Ctrl + K
|
|
|
|
assert.equal(map_down(83, false, false, true).name, "star_message"); // Cmd + S
|
|
|
|
assert.equal(map_down(83, false, true, false), undefined); // Ctrl + S
|
|
|
|
assert.equal(map_down(190, false, false, true).name, "narrow_to_compose_target"); // Cmd + .
|
|
|
|
assert.equal(map_down(190, false, true, false), undefined); // Ctrl + .
|
2019-06-24 14:11:21 +02:00
|
|
|
// Reset platform
|
2020-12-01 00:57:57 +01:00
|
|
|
navigator.platform = "";
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|
2017-03-13 21:41:28 +01:00
|
|
|
|
2021-02-26 13:30:58 +01:00
|
|
|
function process(s) {
|
|
|
|
const e = {
|
|
|
|
which: s.charCodeAt(0),
|
|
|
|
};
|
|
|
|
try {
|
|
|
|
return hotkey.process_keypress(e);
|
|
|
|
} catch (error) {
|
|
|
|
// An exception will be thrown here if a different
|
|
|
|
// function is called than the one declared. Try to
|
|
|
|
// provide a useful error message.
|
|
|
|
// add a newline to separate from other console output.
|
|
|
|
console.log('\nERROR: Mapping for character "' + e.which + '" does not match tests.');
|
|
|
|
throw error;
|
2017-03-10 22:24:54 +01:00
|
|
|
}
|
2021-02-26 13:30:58 +01:00
|
|
|
}
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2021-02-26 13:30:58 +01:00
|
|
|
function assert_mapping(c, module, func_name, shiftKey) {
|
|
|
|
stubbing(module, func_name, (stub) => {
|
2021-06-10 08:32:54 +02:00
|
|
|
assert.ok(process(c, shiftKey));
|
2021-02-26 13:30:58 +01:00
|
|
|
assert.equal(stub.num_calls, 1);
|
|
|
|
});
|
|
|
|
}
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2021-02-26 13:30:58 +01:00
|
|
|
function assert_unmapped(s) {
|
|
|
|
for (const c of s) {
|
|
|
|
assert.equal(process(c), false);
|
2017-03-10 22:24:54 +01:00
|
|
|
}
|
2021-02-26 13:30:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function test_normal_typing() {
|
|
|
|
assert_unmapped("abcdefghijklmnopqrsuvwxyz");
|
|
|
|
assert_unmapped(" ");
|
|
|
|
assert_unmapped("[]\\.,;");
|
|
|
|
assert_unmapped("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
|
|
|
assert_unmapped('~!@#$%^*()_+{}:"<>');
|
|
|
|
}
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
run_test("allow normal typing when processing text", ({override}) => {
|
2017-03-10 22:24:54 +01:00
|
|
|
// Unmapped keys should immediately return false, without
|
|
|
|
// calling any functions outside of hotkey.js.
|
2020-09-20 10:14:24 +02:00
|
|
|
assert_unmapped("bfmoyz");
|
2020-07-15 01:29:15 +02:00
|
|
|
assert_unmapped("BEFHILNOQTUWXYZ");
|
2017-03-10 22:24:54 +01:00
|
|
|
|
|
|
|
// All letters should return false if we are composing text.
|
2021-02-26 14:04:11 +01:00
|
|
|
override(hotkey, "processing_text", () => true);
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2021-02-26 12:49:16 +01:00
|
|
|
for (const settings_open of [() => true, () => false]) {
|
|
|
|
for (const is_active of [() => true, () => false]) {
|
|
|
|
for (const info_overlay_open of [() => true, () => false]) {
|
2021-02-26 14:40:35 +01:00
|
|
|
with_field(overlays, "is_active", is_active, () => {
|
|
|
|
with_field(overlays, "settings_open", settings_open, () => {
|
|
|
|
with_field(overlays, "info_overlay_open", info_overlay_open, () => {
|
|
|
|
test_normal_typing();
|
|
|
|
});
|
|
|
|
});
|
2017-10-21 19:21:44 +02:00
|
|
|
});
|
js: Automatically convert _.each to for…of.
This commit was automatically generated by the following script,
followed by lint --fix and a few small manual lint-related cleanups.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import { Context } from "ast-types/lib/path-visitor";
import K from "ast-types/gen/kinds";
import { NodePath } from "ast-types/lib/node-path";
import assert from "assert";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
const checkStatement = (node: n.Node): node is K.StatementKind =>
n.Statement.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
let inLoop = false;
let replaceReturn = false;
const visitLoop = (...args: string[]) =>
function(this: Context, path: NodePath) {
for (const arg of args) {
this.visit(path.get(arg));
}
const old = { inLoop };
inLoop = true;
this.visit(path.get("body"));
inLoop = old.inLoop;
return false;
};
recast.visit(ast, {
visitDoWhileStatement: visitLoop("test"),
visitExpressionStatement(path) {
const { expression, comments } = path.node;
let valueOnly;
if (
n.CallExpression.check(expression) &&
n.MemberExpression.check(expression.callee) &&
!expression.callee.computed &&
n.Identifier.check(expression.callee.object) &&
expression.callee.object.name === "_" &&
n.Identifier.check(expression.callee.property) &&
["each", "forEach"].includes(expression.callee.property.name) &&
[2, 3].includes(expression.arguments.length) &&
checkExpression(expression.arguments[0]) &&
(n.FunctionExpression.check(expression.arguments[1]) ||
n.ArrowFunctionExpression.check(expression.arguments[1])) &&
[1, 2].includes(expression.arguments[1].params.length) &&
n.Identifier.check(expression.arguments[1].params[0]) &&
((valueOnly = expression.arguments[1].params[1] === undefined) ||
n.Identifier.check(expression.arguments[1].params[1])) &&
(expression.arguments[2] === undefined ||
n.ThisExpression.check(expression.arguments[2]))
) {
const old = { inLoop, replaceReturn };
inLoop = false;
replaceReturn = true;
this.visit(
path
.get("expression")
.get("arguments")
.get(1)
.get("body")
);
inLoop = old.inLoop;
replaceReturn = old.replaceReturn;
const [right, { body, params }] = expression.arguments;
const loop = b.forOfStatement(
b.variableDeclaration("let", [
b.variableDeclarator(
valueOnly ? params[0] : b.arrayPattern([params[1], params[0]])
),
]),
valueOnly
? right
: b.callExpression(
b.memberExpression(right, b.identifier("entries")),
[]
),
checkStatement(body) ? body : b.expressionStatement(body)
);
loop.comments = comments;
path.replace(loop);
changed = true;
}
this.traverse(path);
},
visitForStatement: visitLoop("init", "test", "update"),
visitForInStatement: visitLoop("left", "right"),
visitForOfStatement: visitLoop("left", "right"),
visitFunction(path) {
this.visit(path.get("params"));
const old = { replaceReturn };
replaceReturn = false;
this.visit(path.get("body"));
replaceReturn = old.replaceReturn;
return false;
},
visitReturnStatement(path) {
if (replaceReturn) {
assert(!inLoop); // could use labeled continue if this ever fires
const { argument, comments } = path.node;
if (argument === null) {
const s = b.continueStatement();
s.comments = comments;
path.replace(s);
} else {
const s = b.expressionStatement(argument);
s.comments = comments;
path.replace(s, b.continueStatement());
}
return false;
}
this.traverse(path);
},
visitWhileStatement: visitLoop("test"),
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-06 06:19:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-26 13:49:13 +01:00
|
|
|
});
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
run_test("streams", ({override}) => {
|
2021-03-27 05:48:37 +01:00
|
|
|
settings_data.user_can_create_private_streams = () => true;
|
|
|
|
settings_data.user_can_create_public_streams = () => true;
|
2021-02-26 14:04:11 +01:00
|
|
|
override(overlays, "streams_open", () => true);
|
|
|
|
override(overlays, "is_active", () => true);
|
2021-07-09 15:51:31 +02:00
|
|
|
assert_mapping("S", stream_settings_ui, "keyboard_sub");
|
|
|
|
assert_mapping("V", stream_settings_ui, "view_stream");
|
|
|
|
assert_mapping("n", stream_settings_ui, "open_create_stream");
|
2021-03-27 05:48:37 +01:00
|
|
|
settings_data.user_can_create_private_streams = () => false;
|
|
|
|
settings_data.user_can_create_public_streams = () => false;
|
2020-07-15 01:29:15 +02:00
|
|
|
assert_unmapped("n");
|
2021-02-26 13:49:13 +01:00
|
|
|
});
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2021-02-26 13:49:13 +01:00
|
|
|
run_test("basic mappings", () => {
|
2021-03-22 16:09:12 +01:00
|
|
|
assert_mapping("?", browser_history, "go_to_location");
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("/", search, "initiate_search");
|
|
|
|
assert_mapping("w", activity, "initiate_search");
|
|
|
|
assert_mapping("q", stream_list, "initiate_search");
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("A", narrow, "stream_cycle_backward");
|
|
|
|
assert_mapping("D", narrow, "stream_cycle_forward");
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("c", compose_actions, "start");
|
|
|
|
assert_mapping("x", compose_actions, "start");
|
|
|
|
assert_mapping("P", narrow, "by");
|
|
|
|
assert_mapping("g", gear_menu, "open");
|
2021-02-26 13:49:13 +01:00
|
|
|
});
|
2017-10-03 00:41:43 +02:00
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
run_test("drafts open", ({override}) => {
|
2021-02-26 14:04:11 +01:00
|
|
|
override(overlays, "is_active", () => true);
|
|
|
|
override(overlays, "drafts_open", () => true);
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("d", overlays, "close_overlay");
|
2021-02-26 13:49:13 +01:00
|
|
|
});
|
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
run_test("drafts closed w/other overlay", ({override}) => {
|
2021-02-26 14:04:11 +01:00
|
|
|
override(overlays, "is_active", () => true);
|
|
|
|
override(overlays, "drafts_open", () => false);
|
2017-10-21 19:21:44 +02:00
|
|
|
test_normal_typing();
|
2021-02-26 14:04:11 +01:00
|
|
|
});
|
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
run_test("drafts closed launch", ({override}) => {
|
2021-02-26 14:04:11 +01:00
|
|
|
override(overlays, "is_active", () => false);
|
2021-05-18 03:48:34 +02:00
|
|
|
assert_mapping("d", browser_history, "go_to_location");
|
2021-02-26 13:49:13 +01:00
|
|
|
});
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2021-07-08 08:37:44 +02:00
|
|
|
run_test("modal open", ({override}) => {
|
|
|
|
override(overlays, "is_modal_open", () => true);
|
|
|
|
test_normal_typing();
|
|
|
|
});
|
|
|
|
|
2021-02-26 13:49:13 +01:00
|
|
|
run_test("misc", () => {
|
2017-03-10 22:24:54 +01:00
|
|
|
// Next, test keys that only work on a selected message.
|
2020-07-15 01:29:15 +02:00
|
|
|
const message_view_only_keys = "@+>RjJkKsSuvi:GM";
|
2017-03-23 19:38:08 +01:00
|
|
|
|
|
|
|
// Check that they do nothing without a selected message
|
2021-02-26 14:04:11 +01:00
|
|
|
with_overrides((override) => {
|
2021-03-30 02:21:21 +02:00
|
|
|
override(message_lists.current, "empty", () => true);
|
2021-02-26 14:04:11 +01:00
|
|
|
assert_unmapped(message_view_only_keys);
|
|
|
|
});
|
2017-03-10 22:24:54 +01:00
|
|
|
|
2017-03-23 19:38:08 +01:00
|
|
|
// Check that they do nothing while in the settings overlay
|
2021-02-26 14:04:11 +01:00
|
|
|
with_overrides((override) => {
|
|
|
|
override(overlays, "settings_open", () => true);
|
|
|
|
assert_unmapped("@*+->rRjJkKsSuvi:GM");
|
|
|
|
});
|
2017-03-23 19:38:08 +01:00
|
|
|
|
|
|
|
// TODO: Similar check for being in the subs page
|
|
|
|
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("@", compose_actions, "reply_with_mention");
|
|
|
|
assert_mapping("+", reactions, "toggle_emoji_reaction");
|
|
|
|
assert_mapping("-", condense, "toggle_collapse");
|
|
|
|
assert_mapping("r", compose_actions, "respond_to_message");
|
|
|
|
assert_mapping("R", compose_actions, "respond_to_message", true);
|
|
|
|
assert_mapping("j", navigate, "down");
|
|
|
|
assert_mapping("J", navigate, "page_down");
|
|
|
|
assert_mapping("k", navigate, "up");
|
|
|
|
assert_mapping("K", navigate, "page_up");
|
|
|
|
assert_mapping("s", narrow, "by_recipient");
|
|
|
|
assert_mapping("S", narrow, "by_topic");
|
|
|
|
assert_mapping("u", popovers, "show_sender_info");
|
|
|
|
assert_mapping("i", popovers, "open_message_menu");
|
|
|
|
assert_mapping(":", reactions, "open_reactions_popover", true);
|
|
|
|
assert_mapping(">", compose_actions, "quote_and_reply");
|
|
|
|
assert_mapping("e", message_edit, "start");
|
2021-02-26 13:49:13 +01:00
|
|
|
});
|
2017-10-02 23:10:55 +02:00
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
run_test("lightbox overlay open", ({override}) => {
|
2021-02-26 14:04:11 +01:00
|
|
|
override(overlays, "is_active", () => true);
|
|
|
|
override(overlays, "lightbox_open", () => true);
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("v", overlays, "close_overlay");
|
2021-02-26 14:04:11 +01:00
|
|
|
});
|
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
run_test("lightbox closed w/other overlay open", ({override}) => {
|
2021-02-26 14:04:11 +01:00
|
|
|
override(overlays, "is_active", () => true);
|
|
|
|
override(overlays, "lightbox_open", () => false);
|
2017-10-21 19:21:44 +02:00
|
|
|
test_normal_typing();
|
2021-02-26 14:04:11 +01:00
|
|
|
});
|
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
run_test("v w/no overlays", ({override}) => {
|
2021-02-26 14:04:11 +01:00
|
|
|
override(overlays, "is_active", () => false);
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("v", lightbox, "show_from_selected_message");
|
2021-02-26 13:49:13 +01:00
|
|
|
});
|
2017-10-21 19:21:44 +02:00
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
run_test("emoji picker", ({override}) => {
|
2021-02-26 14:04:11 +01:00
|
|
|
override(emoji_picker, "reactions_popped", () => true);
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping(":", emoji_picker, "navigate", true);
|
2021-02-26 13:49:13 +01:00
|
|
|
});
|
2017-10-02 23:10:55 +02:00
|
|
|
|
2021-02-26 13:49:13 +01:00
|
|
|
run_test("G/M keys", () => {
|
|
|
|
// TODO: move
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("G", navigate, "to_end");
|
2021-07-08 20:36:52 +02:00
|
|
|
assert_mapping("M", muted_topics_ui, "toggle_topic_mute");
|
2021-02-26 13:49:13 +01:00
|
|
|
});
|
2017-03-23 13:23:49 +01:00
|
|
|
|
2021-02-26 13:49:13 +01:00
|
|
|
run_test("n/p keys", () => {
|
2017-03-23 13:23:49 +01:00
|
|
|
// Test keys that work when a message is selected and
|
|
|
|
// also when the message list is empty.
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("n", narrow, "narrow_to_next_topic");
|
|
|
|
assert_mapping("p", narrow, "narrow_to_next_pm_string");
|
|
|
|
assert_mapping("n", narrow, "narrow_to_next_topic");
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|
2017-03-14 18:29:38 +01:00
|
|
|
|
2020-07-15 01:29:15 +02:00
|
|
|
run_test("motion_keys", () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
const codes = {
|
2017-03-14 18:29:38 +01:00
|
|
|
down_arrow: 40,
|
|
|
|
end: 35,
|
|
|
|
home: 36,
|
|
|
|
left_arrow: 37,
|
2017-03-19 01:51:20 +01:00
|
|
|
right_arrow: 39,
|
2017-03-14 18:29:38 +01:00
|
|
|
page_up: 33,
|
|
|
|
page_down: 34,
|
|
|
|
spacebar: 32,
|
|
|
|
up_arrow: 38,
|
2020-07-15 01:29:15 +02:00
|
|
|
"+": 187,
|
2017-03-14 18:29:38 +01:00
|
|
|
};
|
|
|
|
|
2021-02-26 15:15:38 +01:00
|
|
|
function process(name) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const e = {
|
2017-03-14 18:29:38 +01:00
|
|
|
which: codes[name],
|
|
|
|
};
|
2017-03-18 22:05:07 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
return hotkey.process_keydown(e);
|
2020-10-07 10:20:41 +02:00
|
|
|
} catch (error) {
|
2017-03-18 22:05:07 +01:00
|
|
|
// An exception will be thrown here if a different
|
|
|
|
// function is called than the one declared. Try to
|
|
|
|
// provide a useful error message.
|
2017-11-09 16:26:38 +01:00
|
|
|
// add a newline to separate from other console output.
|
2017-03-18 22:05:07 +01:00
|
|
|
console.log('\nERROR: Mapping for character "' + e.which + '" does not match tests.');
|
2020-10-07 10:20:41 +02:00
|
|
|
throw error;
|
2017-03-18 22:05:07 +01:00
|
|
|
}
|
2017-03-14 18:29:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function assert_unmapped(name) {
|
|
|
|
assert.equal(process(name), false);
|
|
|
|
}
|
|
|
|
|
2021-02-26 15:15:38 +01:00
|
|
|
function assert_mapping(key_name, module, func_name) {
|
2021-02-13 03:46:14 +01:00
|
|
|
stubbing(module, func_name, (stub) => {
|
2021-06-10 08:32:54 +02:00
|
|
|
assert.ok(process(key_name));
|
2021-02-13 03:46:14 +01:00
|
|
|
assert.equal(stub.num_calls, 1);
|
2017-03-14 18:29:38 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-02-26 12:49:16 +01:00
|
|
|
list_util.inside_list = () => false;
|
2021-03-30 02:21:21 +02:00
|
|
|
message_lists.current.empty = () => true;
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.settings_open = () => false;
|
|
|
|
overlays.streams_open = () => false;
|
|
|
|
overlays.lightbox_open = () => false;
|
2017-03-14 18:29:38 +01:00
|
|
|
|
2020-07-15 01:29:15 +02:00
|
|
|
assert_unmapped("down_arrow");
|
|
|
|
assert_unmapped("end");
|
|
|
|
assert_unmapped("home");
|
|
|
|
assert_unmapped("page_up");
|
|
|
|
assert_unmapped("page_down");
|
|
|
|
assert_unmapped("spacebar");
|
|
|
|
assert_unmapped("up_arrow");
|
2017-03-14 18:29:38 +01:00
|
|
|
|
2021-02-26 12:49:16 +01:00
|
|
|
list_util.inside_list = () => true;
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("up_arrow", list_util, "go_up");
|
|
|
|
assert_mapping("down_arrow", list_util, "go_down");
|
2021-02-26 12:49:16 +01:00
|
|
|
list_util.inside_list = () => false;
|
2017-04-04 18:14:27 +02:00
|
|
|
|
2021-03-30 02:21:21 +02:00
|
|
|
message_lists.current.empty = () => false;
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("down_arrow", navigate, "down");
|
|
|
|
assert_mapping("end", navigate, "to_end");
|
|
|
|
assert_mapping("home", navigate, "to_home");
|
|
|
|
assert_mapping("left_arrow", message_edit, "edit_last_sent_message");
|
|
|
|
assert_mapping("page_up", navigate, "page_up");
|
|
|
|
assert_mapping("page_down", navigate, "page_down");
|
|
|
|
assert_mapping("spacebar", navigate, "page_down");
|
|
|
|
assert_mapping("up_arrow", navigate, "up");
|
2017-03-14 18:29:38 +01:00
|
|
|
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.info_overlay_open = () => true;
|
2020-07-15 01:29:15 +02:00
|
|
|
assert_unmapped("down_arrow");
|
|
|
|
assert_unmapped("up_arrow");
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.info_overlay_open = () => false;
|
2017-04-12 20:58:31 +02:00
|
|
|
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.streams_open = () => true;
|
2021-07-09 15:51:31 +02:00
|
|
|
assert_mapping("up_arrow", stream_settings_ui, "switch_rows");
|
|
|
|
assert_mapping("down_arrow", stream_settings_ui, "switch_rows");
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.streams_open = () => false;
|
2017-03-23 06:02:01 +01:00
|
|
|
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.lightbox_open = () => true;
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("left_arrow", lightbox, "prev");
|
|
|
|
assert_mapping("right_arrow", lightbox, "next");
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.lightbox_open = () => false;
|
2017-03-22 02:49:52 +01:00
|
|
|
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.settings_open = () => true;
|
2020-07-15 01:29:15 +02:00
|
|
|
assert_unmapped("end");
|
|
|
|
assert_unmapped("home");
|
|
|
|
assert_unmapped("left_arrow");
|
|
|
|
assert_unmapped("page_up");
|
|
|
|
assert_unmapped("page_down");
|
|
|
|
assert_unmapped("spacebar");
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.settings_open = () => false;
|
2017-04-04 20:48:08 +02:00
|
|
|
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.is_active = () => true;
|
|
|
|
overlays.drafts_open = () => true;
|
2021-02-11 01:23:23 +01:00
|
|
|
assert_mapping("up_arrow", drafts, "drafts_handle_events");
|
|
|
|
assert_mapping("down_arrow", drafts, "drafts_handle_events");
|
2021-02-26 12:49:16 +01:00
|
|
|
overlays.is_active = () => false;
|
|
|
|
overlays.drafts_open = () => false;
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|