Bug 1733104 - Implement runtime.getFrameId available from content scripts r=robwu
[gecko.git] / toolkit / components / extensions / test / mochitest / test_ext_all_apis.js
blob758274bac519a44b1bda76f7bbb5c309769983dd
1 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
2 /* vim: set sts=2 sw=2 et tw=80: */
3 "use strict";
5 // Tests whether not too many APIs are visible by default.
6 // This file is used by test_ext_all_apis.html in browser/ and mobile/android/,
7 // which may modify the following variables to add or remove expected APIs.
8 /* globals expectedContentApisTargetSpecific */
9 /* globals expectedBackgroundApisTargetSpecific */
11 // Generates a list of expectations.
12 function generateExpectations(list) {
13   return list
14     .reduce((allApis, path) => {
15       return allApis.concat(`browser.${path}`, `chrome.${path}`);
16     }, [])
17     .sort();
20 let expectedCommonApis = [
21   "extension.getURL",
22   "extension.inIncognitoContext",
23   "extension.lastError",
24   "i18n.detectLanguage",
25   "i18n.getAcceptLanguages",
26   "i18n.getMessage",
27   "i18n.getUILanguage",
28   "runtime.OnInstalledReason",
29   "runtime.OnRestartRequiredReason",
30   "runtime.PlatformArch",
31   "runtime.PlatformOs",
32   "runtime.RequestUpdateCheckStatus",
33   "runtime.getManifest",
34   "runtime.connect",
35   "runtime.getFrameId",
36   "runtime.getURL",
37   "runtime.id",
38   "runtime.lastError",
39   "runtime.onConnect",
40   "runtime.onMessage",
41   "runtime.sendMessage",
42   // browser.test is only available in xpcshell or when
43   // Cu.isInAutomation is true.
44   "test.assertEq",
45   "test.assertFalse",
46   "test.assertRejects",
47   "test.assertThrows",
48   "test.assertTrue",
49   "test.fail",
50   "test.log",
51   "test.notifyFail",
52   "test.notifyPass",
53   "test.onMessage",
54   "test.sendMessage",
55   "test.succeed",
56   "test.withHandlingUserInput",
59 let expectedContentApis = [
60   ...expectedCommonApis,
61   ...expectedContentApisTargetSpecific,
64 let expectedBackgroundApis = [
65   ...expectedCommonApis,
66   ...expectedBackgroundApisTargetSpecific,
67   "contentScripts.register",
68   "experiments.APIChildScope",
69   "experiments.APIEvent",
70   "experiments.APIParentScope",
71   "extension.ViewType",
72   "extension.getBackgroundPage",
73   "extension.getViews",
74   "extension.isAllowedFileSchemeAccess",
75   "extension.isAllowedIncognitoAccess",
76   // Note: extensionTypes is not visible in Chrome.
77   "extensionTypes.CSSOrigin",
78   "extensionTypes.ImageFormat",
79   "extensionTypes.RunAt",
80   "management.ExtensionDisabledReason",
81   "management.ExtensionInstallType",
82   "management.ExtensionType",
83   "management.getSelf",
84   "management.uninstallSelf",
85   "permissions.getAll",
86   "permissions.contains",
87   "permissions.request",
88   "permissions.remove",
89   "permissions.onAdded",
90   "permissions.onRemoved",
91   "runtime.getBackgroundPage",
92   "runtime.getBrowserInfo",
93   "runtime.getPlatformInfo",
94   "runtime.onConnectExternal",
95   "runtime.onInstalled",
96   "runtime.onMessageExternal",
97   "runtime.onStartup",
98   "runtime.onUpdateAvailable",
99   "runtime.openOptionsPage",
100   "runtime.reload",
101   "runtime.setUninstallURL",
102   "theme.getCurrent",
103   "theme.onUpdated",
104   "types.LevelOfControl",
105   "types.SettingScope",
108 function sendAllApis() {
109   function isEvent(key, val) {
110     if (!/^on[A-Z]/.test(key)) {
111       return false;
112     }
113     let eventKeys = [];
114     for (let prop in val) {
115       eventKeys.push(prop);
116     }
117     eventKeys = eventKeys.sort().join();
118     return eventKeys === "addListener,hasListener,removeListener";
119   }
120   function mayRecurse(key, val) {
121     if (Object.keys(val).filter(k => !/^[A-Z\-0-9_]+$/.test(k)).length === 0) {
122       // Don't recurse on constants and empty objects.
123       return false;
124     }
125     return !isEvent(key, val);
126   }
128   let results = [];
129   function diveDeeper(path, obj) {
130     for (let key in obj) {
131       let val = obj[key];
132       if (typeof val == "object" && val !== null && mayRecurse(key, val)) {
133         diveDeeper(`${path}.${key}`, val);
134       } else if (val !== undefined) {
135         results.push(`${path}.${key}`);
136       }
137     }
138   }
139   diveDeeper("browser", browser);
140   diveDeeper("chrome", chrome);
141   browser.test.sendMessage("allApis", results.sort());
144 add_task(async function test_enumerate_content_script_apis() {
145   let extensionData = {
146     manifest: {
147       content_scripts: [
148         {
149           matches: ["http://mochi.test/*/file_sample.html"],
150           js: ["contentscript.js"],
151           run_at: "document_start",
152         },
153       ],
154     },
155     files: {
156       "contentscript.js": sendAllApis,
157     },
158   };
159   // Turn off warning as errors to pass for deprecated APIs
160   ExtensionTestUtils.failOnSchemaWarnings(false);
161   let extension = ExtensionTestUtils.loadExtension(extensionData);
162   await extension.startup();
164   let win = window.open("file_sample.html");
165   let actualApis = await extension.awaitMessage("allApis");
166   win.close();
167   let expectedApis = generateExpectations(expectedContentApis);
168   isDeeply(actualApis, expectedApis, "content script APIs");
170   await extension.unload();
171   ExtensionTestUtils.failOnSchemaWarnings(true);
174 add_task(async function test_enumerate_background_script_apis() {
175   let extensionData = {
176     background: sendAllApis,
177   };
178   // Turn off warning as errors to pass for deprecated APIs
179   ExtensionTestUtils.failOnSchemaWarnings(false);
180   let extension = ExtensionTestUtils.loadExtension(extensionData);
181   await extension.startup();
183   let actualApis = await extension.awaitMessage("allApis");
184   let expectedApis = generateExpectations(expectedBackgroundApis);
185   isDeeply(actualApis, expectedApis, "background script APIs");
187   await extension.unload();
188   ExtensionTestUtils.failOnSchemaWarnings(true);