tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 0303dcecad6003c2b682c16f7a9002a0f19c361d
parent c16d30d0e6c9bfe1a961bf67ecad24e6b171c948
Author: Ben Dean-Kawamura <bdk@mozilla.com>
Date:   Thu,  2 Oct 2025 15:37:57 +0000

Bug 1989840 - Adding JS tests, r=markh,robwu

This was fixed in the app-services code, but I wanted to add some JS
tests to make sure we don't regress.

Differential Revision: https://phabricator.services.mozilla.com/D265971

Diffstat:
Mtoolkit/components/extensions/test/xpcshell/head_storage.js | 41+++++++++++++++++++++++++++++++++++++++++
Mtoolkit/components/extensions/test/xpcshell/test_StorageSyncService.js | 47+++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 88 insertions(+), 0 deletions(-)

diff --git a/toolkit/components/extensions/test/xpcshell/head_storage.js b/toolkit/components/extensions/test/xpcshell/head_storage.js @@ -209,6 +209,40 @@ async function test_background_page_storage(testAreaName) { ); } + // Regression test https://bugzilla.mozilla.org/show_bug.cgi?id=1989840 + async function testDeeplyNestedObject(areaName) { + const obj = {}; + let current = obj; + for (let i = 0; i < 127; i++) { + const next = {}; + current.foo = next; + current = next; + } + let storage = browser.storage[areaName]; + if (areaName == "sync") { + // TODO(bug 1990313) + // Storing a deeply nested object currently fails for the Rust sync storage, but not Kinto. + // Let's make sure it doesn't crash in any case. + let errorMessage = null; + try { + await storage.set(obj); + } catch (e) { + errorMessage = e.toString(); + // The caller expects one storage event. To make sure that the event is + // fired, trigger a dummy change. + storage.set({ foo: "dummy" }); + } + browser.test.assertTrue( + errorMessage === null || + errorMessage.includes("An unexpected error occurred"), + `Invalid exception message when storing deeply nested object: ${errorMessage}` + ); + } else { + // Storing a deeply nested object should succeed for non-sync engines. + await storage.set(obj); + } + } + async function testFalseyValues(areaName) { let storage = browser.storage[areaName]; const dataInitial = { @@ -625,6 +659,13 @@ async function test_background_page_storage(testAreaName) { clearGlobalChanges(); await storage.clear(); await globalChanges; + + clearGlobalChanges(); + await testDeeplyNestedObject(areaName); + await globalChanges; + clearGlobalChanges(); + await storage.clear(); + await globalChanges; } catch (e) { browser.test.fail(`Error: ${e} :: ${e.stack}`); browser.test.notifyFail("storage"); diff --git a/toolkit/components/extensions/test/xpcshell/test_StorageSyncService.js b/toolkit/components/extensions/test/xpcshell/test_StorageSyncService.js @@ -260,3 +260,50 @@ add_task(async function test_storage_sync_quota() { "should reject with QuotaError" ); }); + +// Test trying to storing invalid JSON +// +// The main test is that this doesn't crash the browser: +// https://bugzilla.mozilla.org/show_bug.cgi?id=1989840 +add_task(async function test_invalid_json() { + let engine = new ExtensionStorageEngineBridge(Service); + await engine.initialize(); + let service = engine._rustStore; + + await engine._bridge.wipe(); + await Assert.rejects( + service.set("ext-1", "{invalid-json"), + /Failed to convert arg 'val'/, + "should reject invalid JSON" + ); +}); + +// Test sending deeply-nested objects +// +// Right now this fails, although it doesn't need to. +// For example, the sync engine only cares about top-level object members, +// so we could call `JSON.stringify` on each value +// and send the raw JSON string across the FFI. +// +// Let's wait for getting more info before doing anything though: +// https://bugzilla.mozilla.org/show_bug.cgi?id=1990313 +add_task(async function test_storage_sync_recursion_limit() { + let engine = new ExtensionStorageEngineBridge(Service); + await engine.initialize(); + let service = engine._rustStore; + + await engine._bridge.wipe(); + // Construct an object with lots of nested fields + const obj = {}; + let current = obj; + for (let i = 0; i < 127; i++) { + const next = {}; + current.foo = next; + current = next; + } + await Assert.rejects( + service.set("ext-1", JSON.stringify(obj)), + /Failed to convert arg 'val'/, + "should reject deeply-nested JSON" + ); +});