Skip to content

Commit cc1877d

Browse files
authored
Add more unit tests (#51)
1 parent eae174f commit cc1877d

File tree

8 files changed

+292
-67
lines changed

8 files changed

+292
-67
lines changed

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"devDependencies": {
7171
"@parcel/config-webextension": "^2.8.2",
7272
"@sindresorhus/tsconfig": "^3.0.1",
73-
"@types/chrome": "^0.0.206",
73+
"@types/chrome": "^0.0.208",
7474
"@types/firefox-webext-browser": "^94.0.1",
7575
"@types/jest": "^29.2.5",
7676
"jest": "^29.3.1",
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Vitest Snapshot v1
2+
3+
exports[`init - registerContentScript > should register multiple manifest scripts on new permissions 1`] = `
4+
[MockFunction registerContentScript] {
5+
"calls": [
6+
[
7+
{
8+
"allFrames": undefined,
9+
"css": undefined,
10+
"excludeMatches": [
11+
"https://content-script.example.com/*",
12+
],
13+
"js": [
14+
"/script.js",
15+
],
16+
"matches": [
17+
"https://granted.example.com/*",
18+
],
19+
"runAt": undefined,
20+
},
21+
],
22+
[
23+
{
24+
"allFrames": undefined,
25+
"css": undefined,
26+
"excludeMatches": [
27+
"https://content-script-extra.example.com/*",
28+
],
29+
"js": [
30+
"/otherScript.js",
31+
],
32+
"matches": [
33+
"https://granted.example.com/*",
34+
],
35+
"runAt": undefined,
36+
},
37+
],
38+
],
39+
"results": [
40+
{
41+
"type": "return",
42+
"value": undefined,
43+
},
44+
{
45+
"type": "return",
46+
"value": undefined,
47+
},
48+
],
49+
}
50+
`;
51+
52+
exports[`init - registerContentScript > should register the manifest scripts on multiple new permissions 1`] = `
53+
[MockFunction registerContentScript] {
54+
"calls": [
55+
[
56+
{
57+
"allFrames": undefined,
58+
"css": undefined,
59+
"excludeMatches": [
60+
"https://content-script.example.com/*",
61+
],
62+
"js": [
63+
"/script.js",
64+
],
65+
"matches": [
66+
"https://granted.example.com/*",
67+
],
68+
"runAt": undefined,
69+
},
70+
],
71+
[
72+
{
73+
"allFrames": undefined,
74+
"css": undefined,
75+
"excludeMatches": [
76+
"https://content-script.example.com/*",
77+
],
78+
"js": [
79+
"/script.js",
80+
],
81+
"matches": [
82+
"https://granted-more.example.com/*",
83+
],
84+
"runAt": undefined,
85+
},
86+
],
87+
],
88+
"results": [
89+
{
90+
"type": "return",
91+
"value": undefined,
92+
},
93+
{
94+
"type": "return",
95+
"value": undefined,
96+
},
97+
],
98+
}
99+
`;
100+
101+
exports[`init - registerContentScript > should register the manifest scripts on new permissions 1`] = `
102+
[MockFunction registerContentScript] {
103+
"calls": [
104+
[
105+
{
106+
"allFrames": undefined,
107+
"css": undefined,
108+
"excludeMatches": [
109+
"https://content-script.example.com/*",
110+
],
111+
"js": [
112+
"/script.js",
113+
],
114+
"matches": [
115+
"https://granted.example.com/*",
116+
],
117+
"runAt": undefined,
118+
},
119+
],
120+
],
121+
"results": [
122+
{
123+
"type": "return",
124+
"value": undefined,
125+
},
126+
],
127+
}
128+
`;

source/inject-to-existing-tabs.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {injectContentScript} from 'webext-content-scripts';
2+
3+
export function injectToExistingTabs(
4+
origins: string[],
5+
scripts: ManifestContentScripts) {
6+
if (origins.length === 0) {
7+
return;
8+
}
9+
10+
chrome.tabs.query({
11+
url: origins,
12+
}, tabs => {
13+
for (const tab of tabs) {
14+
if (tab.id) {
15+
void injectContentScript(tab.id, scripts);
16+
}
17+
}
18+
});
19+
}

source/lib.test.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import {chrome} from 'jest-chrome';
2+
import {describe, it, vi, beforeEach, expect} from 'vitest';
3+
import {getAdditionalPermissions} from 'webext-additional-permissions';
4+
import {init} from './lib.js';
5+
import {injectToExistingTabs} from './inject-to-existing-tabs.js';
6+
import {registerContentScript} from './register-content-script-shim.js';
7+
8+
vi.mock('webext-additional-permissions');
9+
vi.mock('./register-content-script-shim.js');
10+
vi.mock('./inject-to-existing-tabs.js');
11+
12+
const baseManifest: chrome.runtime.Manifest = {
13+
name: 'required',
14+
manifest_version: 3,
15+
version: '0.0.0',
16+
content_scripts: [
17+
{
18+
js: ['script.js'],
19+
matches: ['https://content-script.example.com/*'],
20+
},
21+
],
22+
host_permissions: ['https://permission-only.example.com/*'],
23+
optional_host_permissions: ['*://*/*'],
24+
};
25+
26+
const additionalPermissions: Required<chrome.permissions.Permissions> = {
27+
origins: ['https://granted.example.com/*'],
28+
permissions: [],
29+
};
30+
31+
const getAdditionalPermissionsMock = vi.mocked(getAdditionalPermissions);
32+
const injectToExistingTabsMock = vi.mocked(injectToExistingTabs);
33+
const registerContentScriptMock = vi.mocked(registerContentScript);
34+
35+
beforeEach(() => {
36+
registerContentScriptMock.mockClear();
37+
injectToExistingTabsMock.mockClear();
38+
getAdditionalPermissionsMock.mockResolvedValue(additionalPermissions);
39+
chrome.runtime.getManifest.mockReturnValue(baseManifest);
40+
});
41+
42+
describe('init', () => {
43+
it('it should register the listeners and start checking permissions', async () => {
44+
await init();
45+
expect(getAdditionalPermissionsMock).toHaveBeenCalled();
46+
expect(injectToExistingTabsMock).toHaveBeenCalledWith(
47+
additionalPermissions.origins,
48+
baseManifest.content_scripts,
49+
);
50+
51+
// TODO: https://github.com/extend-chrome/jest-chrome/issues/20
52+
// expect(chrome.permissions.onAdded.addListener).toHaveBeenCalledOnce();
53+
// expect(chrome.permissions.onRemoved.addListener).toHaveBeenCalledOnce();
54+
});
55+
56+
it('it should throw if no content scripts exist at all', async () => {
57+
const manifest = structuredClone(baseManifest);
58+
delete manifest.content_scripts;
59+
chrome.runtime.getManifest.mockReturnValue(manifest);
60+
await expect(init()).rejects.toMatchInlineSnapshot('[Error: webext-dynamic-content-scripts tried to register scripts on the new host permissions, but no content scripts were found in the manifest.]');
61+
});
62+
});
63+
64+
describe('init - registerContentScript', () => {
65+
it('should register the manifest scripts on new permissions', async () => {
66+
await init();
67+
expect(registerContentScriptMock).toMatchSnapshot();
68+
});
69+
70+
it('should register the manifest scripts on multiple new permissions', async () => {
71+
getAdditionalPermissionsMock.mockResolvedValue({
72+
origins: [
73+
'https://granted.example.com/*',
74+
'https://granted-more.example.com/*',
75+
],
76+
permissions: [],
77+
});
78+
79+
await init();
80+
expect(registerContentScriptMock).toMatchSnapshot();
81+
});
82+
83+
it('should register multiple manifest scripts on new permissions', async () => {
84+
const manifest = structuredClone(baseManifest);
85+
manifest.content_scripts!.push({
86+
js: ['otherScript.js'],
87+
matches: ['https://content-script-extra.example.com/*'],
88+
});
89+
chrome.runtime.getManifest.mockReturnValue(manifest);
90+
91+
await init();
92+
expect(registerContentScriptMock).toMatchSnapshot();
93+
});
94+
});

source/lib.ts

Lines changed: 3 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,17 @@
1-
import registerContentScriptPonyfill from 'content-scripts-register-polyfill/ponyfill.js';
21
import {getAdditionalPermissions} from 'webext-additional-permissions';
3-
import {injectContentScript} from 'webext-content-scripts';
2+
import {injectToExistingTabs} from './inject-to-existing-tabs.js';
3+
import {registerContentScript} from './register-content-script-shim.js';
44

55
const registeredScripts = new Map<
66
string,
77
Promise<browser.contentScripts.RegisteredContentScript>
88
>();
99

10-
const chromeRegister = globalThis?.chrome?.scripting?.registerContentScripts;
11-
const firefoxRegister = globalThis?.browser?.contentScripts?.register;
12-
13-
async function registerContentScript(
14-
contentScript: ChromeContentScript,
15-
): Promise<browser.contentScripts.RegisteredContentScript> {
16-
if (chromeRegister) {
17-
const id = 'webext-dynamic-content-script-' + JSON.stringify(contentScript);
18-
try {
19-
await chromeRegister([{
20-
id,
21-
...contentScript,
22-
}]);
23-
} catch (error) {
24-
if (!(error as Error)?.message.startsWith('Duplicate script ID')) {
25-
throw error;
26-
}
27-
}
28-
29-
return {
30-
unregister: async () => chrome.scripting.unregisterContentScripts([id]),
31-
};
32-
}
33-
34-
const firefoxContentScript = {
35-
...contentScript,
36-
js: contentScript.js?.map(file => ({file})),
37-
css: contentScript.css?.map(file => ({file})),
38-
};
39-
40-
if (firefoxRegister) {
41-
return firefoxRegister(firefoxContentScript);
42-
}
43-
44-
return registerContentScriptPonyfill(firefoxContentScript);
45-
}
46-
4710
// In Firefox, paths in the manifest are converted to full URLs under `moz-extension://` but browser.contentScripts expects exclusively relative paths
4811
function makePathRelative(file: string): string {
4912
return new URL(file, location.origin).pathname;
5013
}
5114

52-
function injectToExistingTabs(
53-
origins: string[],
54-
scripts: ManifestContentScripts,
55-
) {
56-
if (origins.length === 0) {
57-
return;
58-
}
59-
60-
chrome.tabs.query({
61-
url: origins,
62-
}, tabs => {
63-
for (const tab of tabs) {
64-
if (tab.id) {
65-
void injectContentScript(tab.id, scripts);
66-
}
67-
}
68-
});
69-
}
70-
7115
// Automatically register the content scripts on the new origins
7216
async function registerOnOrigins({
7317
origins: newOrigins,
@@ -122,7 +66,7 @@ async function handledDroppedPermissions({origins}: chrome.permissions.Permissio
12266
export async function init() {
12367
chrome.permissions.onRemoved.addListener(handledDroppedPermissions);
12468
chrome.permissions.onAdded.addListener(handleNewPermissions);
125-
void registerOnOrigins(
69+
await registerOnOrigins(
12670
await getAdditionalPermissions({
12771
strictOrigins: false,
12872
}),

0 commit comments

Comments
 (0)