From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/browser/browser_ext_tabs_executeScript.js | 453 +++++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js (limited to 'browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js') diff --git a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js new file mode 100644 index 0000000000..c02aef3da9 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js @@ -0,0 +1,453 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +add_task(async function testExecuteScript() { + let { MessageChannel } = ChromeUtils.importESModule( + "resource://testing-common/MessageChannel.sys.mjs" + ); + + function countMM(messageManagerMap) { + let count = 0; + // List of permanent message managers in the main process. We should not + // count them in the test because MessageChannel unsubscribes when the + // message manager closes, which never happens to these, of course. + let globalMMs = [Services.mm, Services.ppmm, Services.ppmm.getChildAt(0)]; + for (let mm of messageManagerMap.keys()) { + if (!globalMMs.includes(mm)) { + ++count; + } + } + return count; + } + + let messageManagersSize = countMM(MessageChannel.messageManagers); + + const BASE = + "http://mochi.test:8888/browser/browser/components/extensions/test/browser/"; + const URL = BASE + "file_iframe_document.html"; + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL, true); + + async function background() { + try { + // This promise is meant to be resolved when browser.tabs.executeScript({file: "script.js"}) + // is called and the content script does message back, registering the runtime.onMessage + // listener here is meant to prevent intermittent failures due to a race on executing the + // array of promises passed to the `await Promise.all(...)` below. + const promiseRuntimeOnMessage = new Promise(resolve => { + browser.runtime.onMessage.addListener(message => { + browser.test.assertEq( + "script ran", + message, + "Expected runtime message" + ); + resolve(); + }); + }); + + let [tab] = await browser.tabs.query({ + active: true, + currentWindow: true, + }); + let frames = await browser.webNavigation.getAllFrames({ tabId: tab.id }); + browser.test.assertEq(3, frames.length, "Expect exactly three frames"); + browser.test.assertEq(0, frames[0].frameId, "Main frame has frameId:0"); + browser.test.assertTrue(frames[1].frameId > 0, "Subframe has a valid id"); + + browser.test.log( + `FRAMES: ${frames[1].frameId} ${JSON.stringify(frames)}\n` + ); + await Promise.all([ + browser.tabs + .executeScript({ + code: "42", + }) + .then(result => { + browser.test.assertEq( + 1, + result.length, + "Expected one callback result" + ); + browser.test.assertEq(42, result[0], "Expected callback result"); + }), + + browser.tabs + .executeScript({ + file: "script.js", + code: "42", + }) + .then( + result => { + browser.test.fail( + "Expected not to be able to execute a script with both file and code" + ); + }, + error => { + browser.test.assertTrue( + /a 'code' or a 'file' property, but not both/.test( + error.message + ), + "Got expected error" + ); + } + ), + + browser.tabs + .executeScript({ + file: "script.js", + }) + .then(result => { + browser.test.assertEq( + 1, + result.length, + "Expected one callback result" + ); + browser.test.assertEq( + undefined, + result[0], + "Expected callback result" + ); + }), + + browser.tabs + .executeScript({ + file: "script2.js", + }) + .then(result => { + browser.test.assertEq( + 1, + result.length, + "Expected one callback result" + ); + browser.test.assertEq(27, result[0], "Expected callback result"); + }), + + browser.tabs + .executeScript({ + code: "location.href;", + allFrames: true, + }) + .then(result => { + browser.test.assertTrue( + Array.isArray(result), + "Result is an array" + ); + + browser.test.assertEq( + 2, + result.length, + "Result has correct length" + ); + + browser.test.assertTrue( + /\/file_iframe_document\.html$/.test(result[0]), + "First result is correct" + ); + browser.test.assertEq( + "http://mochi.test:8888/", + result[1], + "Second result is correct" + ); + }), + + browser.tabs + .executeScript({ + code: "location.href;", + allFrames: true, + matchAboutBlank: true, + }) + .then(result => { + browser.test.assertTrue( + Array.isArray(result), + "Result is an array" + ); + + browser.test.assertEq( + 3, + result.length, + "Result has correct length" + ); + + browser.test.assertTrue( + /\/file_iframe_document\.html$/.test(result[0]), + "First result is correct" + ); + browser.test.assertEq( + "http://mochi.test:8888/", + result[1], + "Second result is correct" + ); + browser.test.assertEq( + "about:blank", + result[2], + "Thirds result is correct" + ); + }), + + browser.tabs + .executeScript({ + code: "location.href;", + runAt: "document_end", + }) + .then(result => { + browser.test.assertEq(1, result.length, "Expected callback result"); + browser.test.assertEq( + "string", + typeof result[0], + "Result is a string" + ); + + browser.test.assertTrue( + /\/file_iframe_document\.html$/.test(result[0]), + "Result is correct" + ); + }), + + browser.tabs + .executeScript({ + code: "window", + }) + .then( + result => { + browser.test.fail( + "Expected error when returning non-structured-clonable object" + ); + }, + error => { + browser.test.assertEq( + "", + error.fileName, + "Got expected fileName" + ); + browser.test.assertEq( + "Script '' result is non-structured-clonable data", + error.message, + "Got expected error" + ); + } + ), + + browser.tabs + .executeScript({ + code: "Promise.resolve(window)", + }) + .then( + result => { + browser.test.fail( + "Expected error when returning non-structured-clonable object" + ); + }, + error => { + browser.test.assertEq( + "", + error.fileName, + "Got expected fileName" + ); + browser.test.assertEq( + "Script '' result is non-structured-clonable data", + error.message, + "Got expected error" + ); + } + ), + + browser.tabs + .executeScript({ + file: "script3.js", + }) + .then( + result => { + browser.test.fail( + "Expected error when returning non-structured-clonable object" + ); + }, + error => { + const expected = + /Script '.*script3.js' result is non-structured-clonable data/; + browser.test.assertTrue( + expected.test(error.message), + "Got expected error" + ); + browser.test.assertTrue( + error.fileName.endsWith("script3.js"), + "Got expected fileName" + ); + } + ), + + browser.tabs + .executeScript({ + frameId: Number.MAX_SAFE_INTEGER, + code: "42", + }) + .then( + result => { + browser.test.fail( + "Expected error when specifying invalid frame ID" + ); + }, + error => { + browser.test.assertEq( + `Invalid frame IDs: [${Number.MAX_SAFE_INTEGER}].`, + error.message, + "Got expected error" + ); + } + ), + + browser.tabs + .create({ url: "http://example.net/", active: false }) + .then(async tab => { + await browser.tabs + .executeScript(tab.id, { + code: "42", + }) + .then( + result => { + browser.test.fail( + "Expected error when trying to execute on invalid domain" + ); + }, + error => { + browser.test.assertEq( + "Missing host permission for the tab", + error.message, + "Got expected error" + ); + } + ); + + await browser.tabs.remove(tab.id); + }), + + browser.tabs + .executeScript({ + code: "Promise.resolve(42)", + }) + .then(result => { + browser.test.assertEq( + 42, + result[0], + "Got expected promise resolution value as result" + ); + }), + + browser.tabs + .executeScript({ + code: "location.href;", + runAt: "document_end", + allFrames: true, + }) + .then(result => { + browser.test.assertTrue( + Array.isArray(result), + "Result is an array" + ); + + browser.test.assertEq( + 2, + result.length, + "Result has correct length" + ); + + browser.test.assertTrue( + /\/file_iframe_document\.html$/.test(result[0]), + "First result is correct" + ); + browser.test.assertEq( + "http://mochi.test:8888/", + result[1], + "Second result is correct" + ); + }), + + browser.tabs + .executeScript({ + code: "location.href;", + frameId: frames[0].frameId, + }) + .then(result => { + browser.test.assertEq(1, result.length, "Expected one result"); + browser.test.assertTrue( + /\/file_iframe_document\.html$/.test(result[0]), + `Result for main frame (frameId:0) is correct: ${result[0]}` + ); + }), + + browser.tabs + .executeScript({ + code: "location.href;", + frameId: frames[1].frameId, + }) + .then(result => { + browser.test.assertEq(1, result.length, "Expected one result"); + browser.test.assertEq( + "http://mochi.test:8888/", + result[0], + "Result for frameId[1] is correct" + ); + }), + + browser.tabs.create({ url: "http://example.com/" }).then(async tab => { + let result = await browser.tabs.executeScript(tab.id, { + code: "location.href", + }); + + browser.test.assertEq( + "http://example.com/", + result[0], + "Script executed correctly in new tab" + ); + + await browser.tabs.remove(tab.id); + }), + + promiseRuntimeOnMessage, + ]); + + browser.test.notifyPass("executeScript"); + } catch (e) { + browser.test.fail(`Error: ${e} :: ${e.stack}`); + browser.test.notifyFail("executeScript"); + } + } + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: [ + "http://mochi.test/", + "http://example.com/", + "webNavigation", + ], + }, + + background, + + files: { + "script.js": function () { + browser.runtime.sendMessage("script ran"); + }, + + "script2.js": "27", + + "script3.js": "window", + }, + }); + + await extension.startup(); + + await extension.awaitFinish("executeScript"); + + await extension.unload(); + + BrowserTestUtils.removeTab(tab); + + // Make sure that we're not holding on to references to closed message + // managers. + is( + countMM(MessageChannel.messageManagers), + messageManagersSize, + "Message manager count" + ); + is(MessageChannel.pendingResponses.size, 0, "Pending response count"); +}); -- cgit v1.2.3