1 // Runs a slew of generic command tests
3 var utils = require("utils");
4 const { module } = utils;
5 var dactyllib = module("dactyl");
6 var jumlib = module("resource://mozmill/modules/jum.js");
8 var setupModule = function (module) {
9 controller = mozmill.getBrowserController();
10 dactyl = new dactyllib.Controller(controller);
12 dactyl.modules.options["autocomplete"] = [];
13 dactyl.modules.options["wildmode"] = ["list"];
15 dactyl.modules.prefs.set("browser.tabs.closeWindowWithLastTab", false);
16 dactyl.elements.multilineContainer.setAttribute("moz-collapsed", "true");
18 var teardownModule = function (module) {
19 dactyl.elements.multilineContainer.removeAttribute("moz-collapsed");
23 function $(selector) controller.window.document.querySelector(selector);
25 function hasNItems(nItems)
26 function hasNItems(context) {
27 utils.assertEqual("testCommand.hasNItems", nItems, context.allItems.items.length);
30 function hasItems(context) context.allItems.items.length;
32 function hasntNullItems(context) hasItems(context) &&
33 !context.allItems.items.some(function ({ text, description }) [text, description].some(function (text) /^\[object/.test(text)));
35 function sidebarState(state)
36 function sidebarState() {
37 utils.assertEqual("testCommand.sidebarState", state,
38 typeof state == "string" ? $("#sidebar-title").value
39 : !$("#sidebar-box").hidden);
41 function toolbarState(selector, state)
42 function toolbarState() {
43 utils.assertEqual("testCommand.toolbarState", state, !$(selector).collapsed)
48 multiOutput: ["echo foo"]
50 get Clistkeys() this.listcommands,
54 get Ilistkeys() this.listcommands,
60 someOutput: ["", "abc"],
61 noOutput: ["abc def", "-js abc def"],
62 completions: ["", "abc ", "-js abc "]
66 multiOutput: ["", "dactyl", "-type=extension", "-type=extension dactyl"],
73 multiOutput: ["", "DOMLoad", "DOMLoad foo"],
74 noOutput: ["DOMLoad foo bar", "-js DOMLoad foo bar"],
81 back: { noOutput: [""] },
83 init: ["tabopen about:pentadactyl", "tabopen about:pentadactyl"],
85 anyOutput: ["about:pentadactyl"],
86 completions: [["", hasItems]]
88 get blistkeys() this.listcommands,
91 singleOutput: ["", "-tags=foo -title=bar -keyword=baz -charset=UTF-8 -post=quux about:pentadactyl"],
92 error: ["-tags=foo -title=bar -keyword=baz -charset=nonExistentCharset -post=quux about:pentadactyl"],
95 "-max=1 -keyword=foo -tags=",
96 "-max=1 -keyword=foo -tags=bar -title=",
97 ["-max=1 -keyword=foo -tags=bar -title=baz -charset=", hasItems],
98 "-max=1 -keyword=foo -tags=bar -title=baz -charset= about:"
102 multiOutput: ["-max=1", "-max=1 -keyword=foo -tags=bar -title=baz about:pentadactyl"],
105 "-max=1 -keyword=foo -tags=",
106 "-max=1 -keyword=foo -tags=bar -title=",
107 "-max=1 -keyword=foo -tags=bar -title=baz about:"
112 anyOutput: ["", "1"],
113 noOutput: ["!", "! 1"],
121 multiOutput: ["", "1"],
122 completions: ["", "1"]
127 singleOutput: ["", "~/"],
128 completions: ["", "~/"]
130 get clistkeys() this.listcommands,
134 error: ["!", "", "some-nonexistent-scheme"]
138 singleOutput: ["", "foobar"],
139 noOutput: ["foo bar", "-js bar baz"],
144 "-group=builtin baz quux",
145 "! -group=builtin baz quux",
149 ["-group=", hasItems],
150 ["-group=user ", hasItems]
156 contexts: { // Not testable in this manner
160 anyOutput: ["5digits.org", "5digits.org list"],
164 ["5digits.org ", hasItems]
169 delbmarks: { anyOutput: ["", "about:pentadactyl"] },
172 init: ["delcommand!", "command foo bar"],
176 ["-group=", hasItems],
177 ["-group=user ", hasItems]
179 noOutput: ["foo", "! "]
182 init: ["delcommand!"],
187 error: ["", "! foo", "builtin"],
191 error: ["", "! foo"],
193 completions: ["", "x"]
195 get delmarks() this.delmacros,
196 get delqmarks() this.delmacros,
198 completions: ["", "-name=", "-name=foo ", "-index=", "-index="]
202 // Skip implementation for now
218 multiOutput: ["", "dactyl", "dactyl"]
227 ["window", /\[object\sChromeWindow\]/]
239 __proto__: this.echo,
241 get echomsg() this.echo,
249 noOutput: ["View.Zoom.Zoom In", "View.Zoom.Zoom Out"],
261 noOutput: ["", "'js " + "".quote() + "'"],
262 someOutput: ["'ls'"],
263 completions: [["", hasItems]]
269 completions: [["", hasItems]],
273 completions: [["", hasItems]],
276 get extdisable() this.extdelete,
285 get extrehash() this.extdelete,
286 get exttoggle() this.extdelete,
287 get extupdate() this.extdelete,
296 forward: { noOutput: [""] },
304 "foo -d='foo group' -nopersist -l 'bar.com','http://bar/*','http://bar','^http:'",
305 "! foo -d='foo group' -nopersist -l 'bar.com','http://bar/*','http://bar','^http:'",
314 cleanup: ["delmapgroup foo"]
316 hardcopy: {}, // Skip for now
319 noOutput: ["", "intro"],
320 cleanup: ["tabdelete", "tabdelete"],
326 get helpall() this.help,
329 multiOutput: ["", "Help"],
332 "Help -group=FontCode",
333 "Help -group=FontCode foo: bar;"
339 ["Help -group=", hasItems],
340 ["Help -group=FontCode ", hasItems],
341 ["Help foo: bar; -moz", hasItems]
345 init: ["open about:pentadactyl"],
346 anyOutput: ["-max=1", "-max=1 -sort=+date", "-max=1 dactyl"],
350 ["-sort=+", hasItems],
351 ["-sort=-", hasItems],
352 ["-sort=+date ", hasItems],
360 get ilistkeys() this.listcommands,
366 noOutput: ["''", "'\\n'", "<pre>foo bar</pre>", "window", "<<EOF\n''\nEOF"],
369 ["window", hasItems],
370 ["window.", hasItems],
371 ["window['", hasItems],
372 ["File('", hasItems],
373 ["File.expandPath('", hasItems],
374 "autocommands.user.get('",
375 ["commands.get('", hasItems],
376 ["commands.builtin.get('", hasItems],
377 ["highlight.get('", hasItems],
378 ["highlight.highlightNode(null, '", hasItems],
379 ["mappings.get(modes.NORMAL, '", hasItems],
380 // ["mappings.builtin.get(modes.NORMAL, '", hasItems],
381 ["options.get('", hasItems],
382 ["prefs.get('", hasItems],
383 ["prefs.defaults.get('", hasItems],
384 ["localPrefs.get('", hasItems],
385 ["localPrefs.defaults.get('", hasItems],
386 ["styles.system.get('", hasItems],
394 error: ["!", "", "some-nonexistent-command"],
396 anyOutput: ["echo 'foo'"],
397 completions: [["", hasItems]]
404 anyOutput: ["", "in"],
410 get listkeys() this.listcommands,
411 get listoptions() this.listcommands,
426 "-group=user -b i j",
430 "-mode=ex -b <C-a> <C-a>"
432 multiOutput: ["", "i"],
434 "-mode=some-nonexistent-mode <C-a> <C-a>",
435 "-group=some-nonexistent-group <C-a> <C-a>",
436 "-group=builtin <C-a> <C-a>"
441 ["-mode=ex ", hasItems],
442 ["-mode=", hasItems],
443 ["-group=", hasItems],
444 ["-builtin i ", hasItems],
445 ["-ex i ", hasItems],
446 ["-javascript i ", hasItems]
450 error: ["!", "", "#", "xy"],
455 init: ["delmarks q"],
456 multiOutput: ["", "y"],
457 error: ["!", "q", "#"],
462 anyOutput: ["messages"]
470 "some-nonexistent-rc.penta",
471 "! some-nonexistent-rc.penta"
473 error: ["some-nonexistent-rc.penta"],
475 cleanup: ["silent !rm some-nonexistent-rc.penta"]
479 "some-nonexistent-pentadactyl-dir/",
480 "! some-nonexistent-pentadactyl-dir/",
481 "some-nonexistent-pentadactyl-dir/foo.vim",
482 "! some-nonexistent-pentadactyl-dir/foo.vim",
485 "some-nonexistent-pentadactyl-dir/",
486 "some-nonexistent-pentadactyl-dir/foo.vim"
491 cleanup: ["silent !rm -r some-nonexistent-pentadactyl-dir/"]
493 get mlistkeys() this.listcommands,
497 get nlistkeys() this.listcommands,
507 singleOutput: ["<C-g>"],
508 multiOutput: ["g<C-g>"]
513 noOutput: ["about:blank | about:home"],
517 ["./ | ", hasItems], // FIXME: broken feature
518 ["chrome://", hasItems],
519 ["chrome://browser/", hasItems],
520 ["chrome://browser/content/", hasItems],
521 ["about:", hasItems],
522 ["resource://", hasItems],
523 ["resource://dactyl/", hasItems]
527 multiOutput: ["", "fgm"],
528 completions: [["", hasItems]],
529 error: ["!", "abcdefghijklmnopqrstuvwxyz", "f g m"]
548 error: ["!", "", "#"],
559 init: ["delqmarks a-zA-Z0-9"],
564 multiOutput: ["", "m", "x"],
565 completions: [["", hasItems]]
594 "js File('~/.pentadactyl/some-nonexistent/good.css').write('')",
595 "js File('~/.pentadactyl/some-nonexistent/good.js').write('')",
596 "js File('~/.pentadactyl/some-nonexistent/bad.js').write('dactyl.echoerr(\"error\")')",
597 "js File('~/.pentadactyl/some-nonexistent/good.penta').write('')",
598 "js File('~/.pentadactyl/some-nonexistent/bad.penta').write('echoerr \"error\"')",
600 cleanup: ["js File('~/.pentadactyl/some-nonexistent').remove(true)"],
602 "some-nonexistent/good.css",
603 "some-nonexistent/good.js",
604 "some-nonexistent/good.penta"
608 "some-nonexistent/bad.js",
609 "some-nonexistent/bad.penta"
611 singleOutput: ["some-nonexistent-file.js"],
614 ["some-nonexistent/", hasItems],
619 // Skip details for now.
621 ["", function (context) ["all",
637 ].every(function (item) context.allItems.items.some(function ({ text }) item == text))
654 "vb?", "cpt?", "messages?", "titlestring?", "au?", "eht?",
655 "cpt", "messages", "titlestring", "au", "eht", "! "
657 noOutput: ["vb", "novb"],
664 ["cpt+=f", hasItems],
665 ["activate=", hasItems],
666 ["activate=links,", hasItems],
667 ["activate+=", hasItems],
668 ["activate+=links,", hasItems],
669 ["activate^=", hasItems],
670 ["activate^=links,", hasItems],
671 ["activate-=", hasItems],
672 ["activate-=links,", hasItems],
673 ["activate!=", hasItems],
674 ["activate!=links,", hasItems]
677 get setglobal() this.set,
678 get setlocal() this.set,
681 test: function (name) [
682 ["! " + name, sidebarState(name)],
683 [name, sidebarState(name)],
684 ["! " + name, sidebarState(false)]
687 Array.concat.apply([],
688 ["Add-ons", // Final "! Add-ons" currently failing
696 ["Preferences", sidebarState("Preferences")],
697 ["!", sidebarState(false)]
700 ["", hasntNullItems],
708 "echo " + "foo\nbar".quote(),
710 "echoerr " + "foo\nbar".quote()
712 completions: [["", hasItems]]
715 init: this.runtime.init,
716 cleanup: this.runtime.cleanup,
718 "! .pentadactyl/some-nonexistent/really-nonexistent.js",
719 ".pentadactyl/some-nonexistent/good.css",
720 ".pentadactyl/some-nonexistent/good.js",
721 ".pentadactyl/some-nonexistent/good.penta"
725 ".pentadactyl/some-nonexistent/really-nonexistent.js",
726 "~/.pentadactyl/some-nonexistent/bad.js",
727 "~/.pentadactyl/some-nonexistent/bad.penta",
728 "./.pentadactyl/some-nonexistent/bad.js",
729 "./.pentadactyl/some-nonexistent/bad.penta",
730 ".pentadactyl/some-nonexistent/bad.js",
731 ".pentadactyl/some-nonexistent/bad.penta",
732 ".pentadactyl/some-nonexistent-file.js"
736 [".pentadactyl/some-nonexistent/", hasItems],
737 ["chrome://browser/content/", hasItems],
738 ["resource://dactyl/", hasItems]
751 cleanup: ["delstyle -n foo"],
753 "-name=foo http://does.not.exist/* div { display: inline; }",
754 "-name=foo -append http://does.not.exist/* span { display: block; }"
762 ["-name=", hasItems],
763 ["http:* div { -moz", hasItems],
764 ["http:* div { foo: bar; -moz", hasItems],
765 ["http:* div { foo: bar; } span { -moz", hasItems],
766 ["http:* div { foo: bar; } span { foo: bar; -moz", hasItems]
770 init: ["style -n foo http:* div {}", "style -n bar ftp:* div", "styledisable -n bar"],
771 cleanup: ["delstyle -n foo", "delstyle -n bar"],
774 ["-name=", hasNItems(1)],
775 ["-index=", hasNItems(1)]
777 noOutput: ["-name=foo", "-name=bar"]
779 get styleenable() this.styledisable,
781 init: ["style -n foo http:* div {}", "style -n bar ftp:* div", "styledisable -n bar"],
782 cleanup: ["delstyle -n foo", "delstyle -n bar"],
783 noOutput: ["-name=foo"],
786 ["-name=", hasNItems(2)],
787 ["-index=", hasNItems(2)]
791 error: ["!", "", "some-nonexistent-command"],
793 anyOutput: ["echo 'foo'"],
794 completions: [["", hasItems]]
803 error: ["!", "", "some-nonexistent-command"],
805 anyOutput: ["echo 'foo'"],
806 completions: [["", hasItems]]
816 noOutput: ["1", "$", "999", "-1", "+1", "! +1", "! -1", "-999", "+999", "! +999", "! -999"],
836 error: ["", ":some-nonexistent-command"/*, "some_nonexistent_reference"*/], // FIXME
837 singleOutput: [":js null", "null"]
840 get tlistkeys() this.listcommands,
845 ["tbs Navigation Toolbar", toolbarState("#nav-bar", true)],
846 ["tbs Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
848 completions: [["", hasItems]],
850 ["Navigation Toolbar", toolbarState("#nav-bar", false)],
851 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)]
853 error: ["!", "", "foo"]
856 completions: [["", hasItems]],
858 ["Navigation Toolbar", toolbarState("#nav-bar", true)],
859 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
861 error: ["!", "", "foo"]
864 completions: [["", hasItems]],
866 ["Navigation Toolbar", toolbarState("#nav-bar", false)],
867 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)],
868 ["Navigation Toolbar", toolbarState("#nav-bar", true)],
869 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)],
870 ["Navigation Toolbar", toolbarState("#nav-bar", false)],
871 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)]
873 error: ["!", "", "foo"]
877 noOutput: ["abc", "! "],
913 ["", function (msg) {
914 var res = /(\w+dactyl) (\S+) \(([\^)]+)\) running on:\nMozilla/;
915 return res && res[2] != "null" && res[3] != "null";
920 get vlistkeys() this.listcommands,
941 ["foo".quote(), /foo/],
942 [":echo " + "bar".quote(), /bar/],
943 [":addons", /Pentadactyl/]
947 ":echoerr " + "foo".quote()
958 function addTest(cmdName, testName, func) {
959 global["testCommand_" + cmdName + "_" + testName] = func;
962 function runCommands(cmdName, testName, commands, test, forbidErrors) {
963 addTest(cmdName, testName, function () {
964 commands.forEach(function (val) {
965 var [cmd, testVal] = Array.concat(val);
967 dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
968 dactyl.clearMessage();
969 dactyl.closeMessageWindow();
971 cmd = cmdName + cmd.replace(/^(!?) ?/, "$1 ");
973 dactyl.assertNoErrorMessages(function () { dactyl.runExCommand(cmd) },
976 dactyl.runExCommand(cmd);
977 controller.waitForPageLoad(controller.tabs.activeTab);
983 function _runCommands(cmdName, testName, commands) {
984 addTest(cmdName, testName, function () {
985 commands.forEach(function (value) {
986 var [cmd, test] = Array.concat(value);
988 dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
989 var res = dactyl.runExCommand(cmd);
990 controller.waitForPageLoad(controller.tabs.activeTab);
991 runTest("Initializing for " + cmdName + " tests failed: " + cmd.quote() + " " + test,
997 function runTest(message, test) {
999 var res = test.apply(null, Array.slice(arguments, runTest.length));
1000 if (res !== undefined)
1001 jumlib.assert(res, message);
1004 for (var val in Iterator(tests)) (function ([command, paramsList]) {
1005 Array.concat(paramsList).forEach(function (params, i) {
1007 _runCommands(command, "init" + (i || ""), params.init);
1009 // Goddamn stupid fucking MozMill and its stupid fucking sandboxes with their ancient fucking JS versions.
1010 for (var val in Iterator(params)) (function ([test, commands]) {
1011 var testName = test + (i || "");
1015 runCommands(command, testName, commands, function (cmd, test) {
1016 var res = dactyl.assertMessage(function (msg) !msg, "Unexpected command output: " + cmd);
1018 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1022 runCommands(command, testName, commands, function (cmd, test) {
1024 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1028 runCommands(command, testName, commands, function (cmd, test) {
1029 var res = dactyl.assertMessage(/./, "Expected command output: " + cmd);
1030 if (res && test != null)
1031 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1034 case "singleOutput":
1035 runCommands(command, testName, commands, function (cmd, test) {
1036 var res = dactyl.assertMessageLine(/./, "Expected command output: " + cmd);
1037 if (res && test != null)
1038 dactyl.assertMessageLine(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1039 }, !params.errorsOk);
1042 runCommands(command, testName, commands, function (cmd, test) {
1043 var res = dactyl.assertMessageWindowOpen(true, "Expected command output: " + cmd);
1044 if (res && test != null)
1045 dactyl.assertMessageWindow(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1046 }, !params.errorsOk);
1049 addTest(command, testName, function () {
1050 commands.forEach(function (val) {
1051 var [cmd, test] = Array.concat(val);
1052 cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
1054 var res = dactyl.assertMessageError(function () {
1055 dactyl.runExCommand(cmd);
1056 controller.waitForPageLoad(controller.tabs.activeTab);
1059 if (res && test != null)
1060 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1065 addTest(command, testName, function () {
1066 commands.forEach(function (val) {
1067 var [cmd, test] = Array.concat(val);
1068 cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
1070 dactyl.assertNoErrorMessages(function () {
1071 dump("COMPL: " + cmd + "\n");
1072 var context = dactyl.runExCompletion(cmd);
1074 runTest("Completion tests failed: " + cmd.quote() + " " + test,
1084 _runCommands(command, "cleanup" + (i || ""), params.cleanup);
1088 // vim: sw=4 ts=8 et: