ASRouterTriggerListeners.test.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import {ASRouterTriggerListeners} from "lib/ASRouterTriggerListeners.jsm";
  2. import {GlobalOverrider} from "test/unit/utils";
  3. describe("ASRouterTriggerListeners", () => {
  4. let sandbox;
  5. let registerWindowNotificationStub;
  6. let unregisterWindoNotificationStub;
  7. let windowEnumeratorStub;
  8. let existingWindow;
  9. const triggerHandler = () => {};
  10. const openURLListener = ASRouterTriggerListeners.get("openURL");
  11. const frequentVisitsListener = ASRouterTriggerListeners.get("frequentVisits");
  12. const hosts = ["www.mozilla.com", "www.mozilla.org"];
  13. function resetEnumeratorStub(windows) {
  14. windowEnumeratorStub
  15. .withArgs("navigator:browser")
  16. .returns(windows);
  17. }
  18. beforeEach(async () => {
  19. sandbox = sinon.createSandbox();
  20. registerWindowNotificationStub = sandbox.stub(global.Services.ww, "registerNotification");
  21. unregisterWindoNotificationStub = sandbox.stub(global.Services.ww, "unregisterNotification");
  22. existingWindow = {gBrowser: {addTabsProgressListener: sandbox.stub(), removeTabsProgressListener: sandbox.stub(), currentURI: {host: ""}}, gBrowserInit: {delayedStartupFinished: true}, addEventListener: sinon.stub(), removeEventListener: sinon.stub()};
  23. windowEnumeratorStub = sandbox.stub(global.Services.wm, "getEnumerator");
  24. resetEnumeratorStub([existingWindow]);
  25. sandbox.spy(openURLListener, "init");
  26. sandbox.spy(openURLListener, "uninit");
  27. });
  28. afterEach(() => {
  29. sandbox.restore();
  30. });
  31. describe("frequentVisits", () => {
  32. let _triggerHandler;
  33. beforeEach(async () => {
  34. _triggerHandler = sandbox.stub();
  35. sandbox.useFakeTimers();
  36. await frequentVisitsListener.init(_triggerHandler, hosts);
  37. });
  38. afterEach(() => {
  39. sandbox.clock.restore();
  40. frequentVisitsListener.uninit();
  41. });
  42. it("should be initialized", () => {
  43. assert.isTrue(frequentVisitsListener._initialized);
  44. });
  45. it("should listen for TabSelect events", () => {
  46. assert.calledOnce(existingWindow.addEventListener);
  47. assert.calledWith(existingWindow.addEventListener, "TabSelect", frequentVisitsListener.onTabSwitch);
  48. });
  49. it("should call _triggerHandler if the visit is valid (is recoreded)", () => {
  50. frequentVisitsListener.triggerHandler({}, "www.mozilla.com");
  51. assert.calledOnce(_triggerHandler);
  52. });
  53. it("should call _triggerHandler only once", () => {
  54. frequentVisitsListener.triggerHandler({}, "www.mozilla.com");
  55. frequentVisitsListener.triggerHandler({}, "www.mozilla.com");
  56. assert.calledOnce(_triggerHandler);
  57. });
  58. it("should call _triggerHandler again after 15 minutes", () => {
  59. frequentVisitsListener.triggerHandler({}, "www.mozilla.com");
  60. sandbox.clock.tick(15 * 60 * 1000 + 1);
  61. frequentVisitsListener.triggerHandler({}, "www.mozilla.com");
  62. assert.calledTwice(_triggerHandler);
  63. });
  64. it("should call triggerHandler on valid hosts", () => {
  65. const stub = sandbox.stub(frequentVisitsListener, "triggerHandler");
  66. existingWindow.gBrowser.currentURI.host = hosts[0]; // eslint-disable-line prefer-destructuring
  67. frequentVisitsListener.onTabSwitch({target: {ownerGlobal: existingWindow}});
  68. assert.calledOnce(stub);
  69. });
  70. it("should not call triggerHandler on invalid hosts", () => {
  71. const stub = sandbox.stub(frequentVisitsListener, "triggerHandler");
  72. existingWindow.gBrowser.currentURI.host = "foo.com";
  73. frequentVisitsListener.onTabSwitch({target: {ownerGlobal: existingWindow}});
  74. assert.notCalled(stub);
  75. });
  76. describe("MatchPattern", () => {
  77. let globals;
  78. beforeEach(() => {
  79. globals = new GlobalOverrider();
  80. globals.set("MatchPatternSet", sandbox.stub().callsFake(patterns => ({patterns})));
  81. });
  82. afterEach(() => {
  83. globals.restore();
  84. frequentVisitsListener.uninit();
  85. });
  86. it("should create a matchPatternSet", async () => {
  87. await frequentVisitsListener.init(_triggerHandler, hosts, ["pattern"]);
  88. assert.calledOnce(window.MatchPatternSet);
  89. assert.calledWithExactly(window.MatchPatternSet, ["pattern"], {ignorePath: true});
  90. });
  91. it("should allow to add multiple patterns and dedupe", async () => {
  92. await frequentVisitsListener.init(_triggerHandler, hosts, ["pattern"]);
  93. await frequentVisitsListener.init(_triggerHandler, hosts, ["foo"]);
  94. assert.calledTwice(window.MatchPatternSet);
  95. assert.calledWithExactly(window.MatchPatternSet, new Set(["pattern", "foo"]), {ignorePath: true});
  96. });
  97. });
  98. });
  99. describe("openURL listener", () => {
  100. it("should exist and initially be uninitialised", () => {
  101. assert.ok(openURLListener);
  102. assert.notOk(openURLListener._initialized);
  103. });
  104. describe("#init", () => {
  105. beforeEach(async () => {
  106. await openURLListener.init(triggerHandler, hosts);
  107. });
  108. afterEach(() => {
  109. openURLListener.uninit();
  110. });
  111. it("should set ._initialized to true and save the triggerHandler and hosts", () => {
  112. assert.ok(openURLListener._initialized);
  113. assert.deepEqual(openURLListener._hosts, new Set(hosts));
  114. assert.equal(openURLListener._triggerHandler, triggerHandler);
  115. });
  116. it("should register an open-window notification", () => {
  117. assert.calledOnce(registerWindowNotificationStub);
  118. assert.calledWith(registerWindowNotificationStub, openURLListener);
  119. });
  120. it("should add tab progress listeners to all existing browser windows", () => {
  121. assert.calledOnce(existingWindow.gBrowser.addTabsProgressListener);
  122. assert.calledWithExactly(existingWindow.gBrowser.addTabsProgressListener, openURLListener);
  123. });
  124. it("if already initialised, should only update the trigger handler and add the new hosts", () => {
  125. const newHosts = ["www.example.com"];
  126. const newTriggerHandler = () => {};
  127. resetEnumeratorStub([existingWindow]);
  128. registerWindowNotificationStub.reset();
  129. existingWindow.gBrowser.addTabsProgressListener.reset();
  130. openURLListener.init(newTriggerHandler, newHosts);
  131. assert.ok(openURLListener._initialized);
  132. assert.deepEqual(openURLListener._hosts, new Set([...hosts, ...newHosts]));
  133. assert.equal(openURLListener._triggerHandler, newTriggerHandler);
  134. assert.notCalled(registerWindowNotificationStub);
  135. assert.notCalled(existingWindow.gBrowser.addTabsProgressListener);
  136. });
  137. });
  138. describe("#uninit", () => {
  139. beforeEach(async () => {
  140. await openURLListener.init(triggerHandler, hosts);
  141. // Ensure that the window enumerator will return the existing window for uninit as well
  142. resetEnumeratorStub([existingWindow]);
  143. openURLListener.uninit();
  144. });
  145. it("should set ._initialized to false and clear the triggerHandler and hosts", () => {
  146. assert.notOk(openURLListener._initialized);
  147. assert.equal(openURLListener._hosts, null);
  148. assert.equal(openURLListener._triggerHandler, null);
  149. });
  150. it("should remove an open-window notification", () => {
  151. assert.calledOnce(unregisterWindoNotificationStub);
  152. assert.calledWith(unregisterWindoNotificationStub, openURLListener);
  153. });
  154. it("should remove tab progress listeners from all existing browser windows", () => {
  155. assert.calledOnce(existingWindow.gBrowser.removeTabsProgressListener);
  156. assert.calledWithExactly(existingWindow.gBrowser.removeTabsProgressListener, openURLListener);
  157. });
  158. it("should do nothing if already uninitialised", () => {
  159. unregisterWindoNotificationStub.reset();
  160. existingWindow.gBrowser.removeTabsProgressListener.reset();
  161. resetEnumeratorStub([existingWindow]);
  162. openURLListener.uninit();
  163. assert.notOk(openURLListener._initialized);
  164. assert.notCalled(unregisterWindoNotificationStub);
  165. assert.notCalled(existingWindow.gBrowser.removeTabsProgressListener);
  166. });
  167. });
  168. describe("#onLocationChange", () => {
  169. afterEach(() => {
  170. openURLListener.uninit();
  171. frequentVisitsListener.uninit();
  172. });
  173. it("should call the ._triggerHandler with the right arguments", async () => {
  174. const newTriggerHandler = sinon.stub();
  175. await openURLListener.init(newTriggerHandler, hosts);
  176. const browser = {};
  177. const webProgress = {isTopLevel: true};
  178. const location = "www.mozilla.org";
  179. openURLListener.onLocationChange(browser, webProgress, undefined, {host: location, spec: location});
  180. assert.calledOnce(newTriggerHandler);
  181. assert.calledWithExactly(newTriggerHandler, browser, {id: "openURL", param: {host: "www.mozilla.org", url: "www.mozilla.org"}});
  182. });
  183. it("should call triggerHandler for a redirect (openURL + frequentVisits)", async () => {
  184. for (let trigger of [openURLListener, frequentVisitsListener]) {
  185. const newTriggerHandler = sinon.stub();
  186. await trigger.init(newTriggerHandler, hosts);
  187. const browser = {};
  188. const webProgress = {isTopLevel: true};
  189. const aLocationURI = {host: "subdomain.mozilla.org", spec: "subdomain.mozilla.org"};
  190. const aRequest = {
  191. QueryInterface: sandbox.stub().returns({
  192. originalURI: {spec: "www.mozilla.org", host: "www.mozilla.org"},
  193. }),
  194. };
  195. trigger.onLocationChange(browser, webProgress, aRequest, aLocationURI);
  196. assert.calledOnce(aRequest.QueryInterface);
  197. assert.calledOnce(newTriggerHandler);
  198. }
  199. });
  200. it("should call triggerHandler with the right arguments (redirect)", async () => {
  201. const newTriggerHandler = sinon.stub();
  202. await openURLListener.init(newTriggerHandler, hosts);
  203. const browser = {};
  204. const webProgress = {isTopLevel: true};
  205. const aLocationURI = {host: "subdomain.mozilla.org", spec: "subdomain.mozilla.org"};
  206. const aRequest = {
  207. QueryInterface: sandbox.stub().returns({
  208. originalURI: {spec: "www.mozilla.org", host: "www.mozilla.org"},
  209. }),
  210. };
  211. openURLListener.onLocationChange(browser, webProgress, aRequest, aLocationURI);
  212. assert.calledWithExactly(newTriggerHandler, browser, {id: "openURL", param: {host: "www.mozilla.org", url: "www.mozilla.org"}});
  213. });
  214. it("should call triggerHandler for a redirect (openURL + frequentVisits)", async () => {
  215. for (let trigger of [openURLListener, frequentVisitsListener]) {
  216. const newTriggerHandler = sinon.stub();
  217. await trigger.init(newTriggerHandler, hosts);
  218. const browser = {};
  219. const webProgress = {isTopLevel: true};
  220. const aLocationURI = {host: "subdomain.mozilla.org", spec: "subdomain.mozilla.org"};
  221. const aRequest = {
  222. QueryInterface: sandbox.stub().returns({
  223. originalURI: {spec: "www.mozilla.org", host: "www.mozilla.org"},
  224. }),
  225. };
  226. trigger.onLocationChange(browser, webProgress, aRequest, aLocationURI);
  227. assert.calledOnce(aRequest.QueryInterface);
  228. assert.calledOnce(newTriggerHandler);
  229. }
  230. });
  231. it("should call triggerHandler with the right arguments (redirect)", async () => {
  232. const newTriggerHandler = sinon.stub();
  233. await openURLListener.init(newTriggerHandler, hosts);
  234. const browser = {};
  235. const webProgress = {isTopLevel: true};
  236. const aLocationURI = {host: "subdomain.mozilla.org", spec: "subdomain.mozilla.org"};
  237. const aRequest = {
  238. QueryInterface: sandbox.stub().returns({
  239. originalURI: {spec: "www.mozilla.org", host: "www.mozilla.org"},
  240. }),
  241. };
  242. openURLListener.onLocationChange(browser, webProgress, aRequest, aLocationURI);
  243. assert.calledWithExactly(newTriggerHandler, browser, {id: "openURL", param: {host: "www.mozilla.org", url: "www.mozilla.org"}});
  244. });
  245. it("should fail for subdomains (not redirect)", async () => {
  246. const newTriggerHandler = sinon.stub();
  247. await openURLListener.init(newTriggerHandler, hosts);
  248. const browser = {};
  249. const webProgress = {isTopLevel: true};
  250. const aLocationURI = {host: "subdomain.mozilla.org", spec: "subdomain.mozilla.org"};
  251. const aRequest = {
  252. QueryInterface: sandbox.stub().returns({
  253. originalURI: {spec: "subdomain.mozilla.org", host: "subdomain.mozilla.org"},
  254. }),
  255. };
  256. openURLListener.onLocationChange(browser, webProgress, aRequest, aLocationURI);
  257. assert.calledOnce(aRequest.QueryInterface);
  258. assert.notCalled(newTriggerHandler);
  259. });
  260. });
  261. describe("delayed startup finished", () => {
  262. beforeEach(() => {
  263. existingWindow.gBrowserInit.delayedStartupFinished = false;
  264. sandbox.stub(global.Services.obs, "addObserver").callsFake(fn => fn(existingWindow, "browser-delayed-startup-finished"));
  265. });
  266. afterEach(() => {
  267. openURLListener.uninit();
  268. });
  269. it("should wait for startup and then add the tabs listener", async () => {
  270. await openURLListener.init(triggerHandler, hosts);
  271. assert.calledOnce(existingWindow.gBrowser.addTabsProgressListener);
  272. });
  273. });
  274. });
  275. });