summaryrefslogtreecommitdiffstats
path: root/browser/components/extensions/test/browser/browser_ext_search_favicon.js
blob: b46796a4276123e0c877225cdb2ed3fe7d3c0b95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";

const { AddonTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/AddonTestUtils.sys.mjs"
);
const { XPCShellContentUtils } = ChromeUtils.importESModule(
  "resource://testing-common/XPCShellContentUtils.sys.mjs"
);

AddonTestUtils.initMochitest(this);
XPCShellContentUtils.initMochitest(this);

// Base64-encoded "Fake icon data".
const FAKE_ICON_DATA = "RmFrZSBpY29uIGRhdGE=";

// Base64-encoded "HTTP icon data".
const HTTP_ICON_DATA = "SFRUUCBpY29uIGRhdGE=";
const HTTP_ICON_URL = "http://example.org/ico.png";
const server = XPCShellContentUtils.createHttpServer({
  hosts: ["example.org"],
});
server.registerPathHandler("/ico.png", (request, response) => {
  response.write(atob(HTTP_ICON_DATA));
});

function promiseEngineIconLoaded(engineName) {
  return TestUtils.topicObserved(
    "browser-search-engine-modified",
    (engine, verb) => {
      engine.QueryInterface(Ci.nsISearchEngine);
      return (
        verb == "engine-changed" && engine.name == engineName && engine.iconURI
      );
    }
  );
}

add_task(async function test_search_favicon() {
  let searchExt = ExtensionTestUtils.loadExtension({
    manifest: {
      chrome_settings_overrides: {
        search_provider: {
          name: "Engine Only",
          search_url: "https://example.com/",
          favicon_url: "someFavicon.png",
        },
      },
    },
    files: {
      "someFavicon.png": atob(FAKE_ICON_DATA),
    },
    useAddonManager: "temporary",
  });

  let searchExtWithBadIcon = ExtensionTestUtils.loadExtension({
    manifest: {
      chrome_settings_overrides: {
        search_provider: {
          name: "Bad Icon",
          search_url: "https://example.net/",
          favicon_url: "iDoNotExist.png",
        },
      },
    },
    useAddonManager: "temporary",
  });

  let searchExtWithHttpIcon = ExtensionTestUtils.loadExtension({
    manifest: {
      chrome_settings_overrides: {
        search_provider: {
          name: "HTTP Icon",
          search_url: "https://example.org/",
          favicon_url: HTTP_ICON_URL,
        },
      },
    },
    useAddonManager: "temporary",
  });

  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      permissions: ["search"],
      chrome_settings_overrides: {
        search_provider: {
          name: "My Engine",
          search_url: "https://example.org/",
          favicon_url: "myFavicon.png",
        },
      },
    },
    files: {
      "myFavicon.png": imageBuffer,
    },
    useAddonManager: "temporary",
    async background() {
      let engines = await browser.search.get();
      browser.test.sendMessage("engines", {
        badEngine: engines.find(engine => engine.name === "Bad Icon"),
        httpEngine: engines.find(engine => engine.name === "HTTP Icon"),
        myEngine: engines.find(engine => engine.name === "My Engine"),
        otherEngine: engines.find(engine => engine.name === "Engine Only"),
      });
    },
  });

  await searchExt.startup();
  await AddonTestUtils.waitForSearchProviderStartup(searchExt);

  await searchExtWithBadIcon.startup();
  await AddonTestUtils.waitForSearchProviderStartup(searchExtWithBadIcon);

  // TODO bug 1571718: browser.search.get should behave correctly (i.e return
  // the icon) even if the icon did not finish loading when the API was called.
  // Currently calling it too early returns undefined, so just wait until the
  // icon has loaded before calling browser.search.get.
  let httpIconLoaded = promiseEngineIconLoaded("HTTP Icon");
  await searchExtWithHttpIcon.startup();
  await AddonTestUtils.waitForSearchProviderStartup(searchExtWithHttpIcon);
  await httpIconLoaded;

  await extension.startup();
  await AddonTestUtils.waitForSearchProviderStartup(extension);

  let engines = await extension.awaitMessage("engines");

  // An extension's own icon can surely be accessed by the extension, so its
  // favIconUrl can be the moz-extension:-URL itself.
  Assert.deepEqual(
    engines.myEngine,
    {
      name: "My Engine",
      isDefault: false,
      alias: undefined,
      favIconUrl: `moz-extension://${extension.uuid}/myFavicon.png`,
    },
    "browser.search.get result for own extension"
  );

  // favIconUrl of other engines need to be in base64-encoded form.
  Assert.deepEqual(
    engines.otherEngine,
    {
      name: "Engine Only",
      isDefault: false,
      alias: undefined,
      favIconUrl: `data:image/png;base64,${FAKE_ICON_DATA}`,
    },
    "browser.search.get result for other extension"
  );

  // HTTP URLs should be provided as-is.
  Assert.deepEqual(
    engines.httpEngine,
    {
      name: "HTTP Icon",
      isDefault: false,
      alias: undefined,
      favIconUrl: `data:image/png;base64,${HTTP_ICON_DATA}`,
    },
    "browser.search.get result for extension with HTTP icon URL"
  );

  // When the favicon does not exists, the favIconUrl must be unset.
  Assert.deepEqual(
    engines.badEngine,
    {
      name: "Bad Icon",
      isDefault: false,
      alias: undefined,
      favIconUrl: undefined,
    },
    "browser.search.get result for other extension with non-existing icon"
  );

  await extension.unload();
  await searchExt.unload();
  await searchExtWithBadIcon.unload();
  await searchExtWithHttpIcon.unload();
});