mirror of
https://github.com/zen-browser/desktop.git
synced 2026-08-01 04:38:55 +00:00
322 lines
10 KiB
JavaScript
322 lines
10 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
ChromeUtils.defineESModuleGetters(this, {
|
|
DEFAULT_PROTOCOL_URLS:
|
|
"moz-src:///browser/components/shell/ShellService.sys.mjs",
|
|
SET_DEFAULT_REDIRECT_PREF:
|
|
"moz-src:///browser/components/shell/WindowsSetDefaultRedirect.sys.mjs",
|
|
WindowsSetDefaultRedirect:
|
|
"moz-src:///browser/components/shell/WindowsSetDefaultRedirect.sys.mjs",
|
|
sinon: "resource://testing-common/Sinon.sys.mjs",
|
|
});
|
|
|
|
// Everything here is Windows.
|
|
Assert.equal(AppConstants.platform, "win", "Platform is Windows");
|
|
|
|
// Protocol defaults carry OPEN_WITH_PROTOCOL_MESSAGING on top of the
|
|
// set-handler flag, unlike the file-type flags in browser_setDefaultPDFHandler.
|
|
const SET_PROTOCOL_WIN11 =
|
|
Ci.nsIWindowsShellService.OPEN_WITH_SET_HANDLER |
|
|
Ci.nsIWindowsShellService.OPEN_WITH_PROTOCOL_MESSAGING;
|
|
const SET_PROTOCOL_WIN10 =
|
|
Ci.nsIWindowsShellService.OPEN_WITH_SET_HANDLER_WIN10 |
|
|
Ci.nsIWindowsShellService.OPEN_WITH_PROTOCOL_MESSAGING;
|
|
|
|
const launchSetDefaultAppPickerStub = sinon.stub();
|
|
const launchModernSettingsDialogDefaultAppsStub = sinon.stub();
|
|
const shellStub = sinon.stub(ShellService, "shellService").value({
|
|
launchSetDefaultAppPicker: launchSetDefaultAppPickerStub,
|
|
launchModernSettingsDialogDefaultApps:
|
|
launchModernSettingsDialogDefaultAppsStub,
|
|
QueryInterface: ChromeUtils.generateQI([]),
|
|
});
|
|
|
|
registerCleanupFunction(() => {
|
|
shellStub.restore();
|
|
Services.prefs.clearUserPref(SET_DEFAULT_REDIRECT_PREF);
|
|
});
|
|
|
|
function resetState() {
|
|
launchSetDefaultAppPickerStub.reset();
|
|
launchModernSettingsDialogDefaultAppsStub.reset();
|
|
Services.prefs.clearUserPref(SET_DEFAULT_REDIRECT_PREF);
|
|
}
|
|
|
|
function readPrefObject() {
|
|
return JSON.parse(
|
|
Services.prefs.getStringPref(SET_DEFAULT_REDIRECT_PREF, "")
|
|
);
|
|
}
|
|
|
|
add_task(async function test_default_https_uses_url_and_win11_flag() {
|
|
resetState();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(ShellService, "_isWindows11").returns(true);
|
|
|
|
try {
|
|
await ShellService.setAsDefaultProtocolHandler("https");
|
|
|
|
Assert.ok(
|
|
launchSetDefaultAppPickerStub.calledOnce,
|
|
"Picker invoked once for the https default"
|
|
);
|
|
Assert.deepEqual(
|
|
launchSetDefaultAppPickerStub.firstCall.args,
|
|
[DEFAULT_PROTOCOL_URLS.https, SET_PROTOCOL_WIN11],
|
|
"Picker called with https URL and SET_HANDLER | PROTOCOL_MESSAGING"
|
|
);
|
|
Assert.ok(
|
|
launchModernSettingsDialogDefaultAppsStub.notCalled,
|
|
"Modern settings not invoked when launcher succeeds"
|
|
);
|
|
Assert.deepEqual(
|
|
readPrefObject(),
|
|
{
|
|
openWithArg: DEFAULT_PROTOCOL_URLS.https,
|
|
overrideUri: null,
|
|
type: WindowsSetDefaultRedirect.TYPE.PROTOCOL,
|
|
},
|
|
"Pref records the URL; overrideUri null so the round-trip is suppressed"
|
|
);
|
|
} finally {
|
|
sandbox.restore();
|
|
}
|
|
});
|
|
|
|
add_task(async function test_custom_url_overrides_protocol_default() {
|
|
resetState();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(ShellService, "_isWindows11").returns(true);
|
|
|
|
try {
|
|
const customUrl = "https://custom.example.com/handler-check";
|
|
await ShellService.setAsDefaultProtocolHandler("https", customUrl, true);
|
|
|
|
Assert.deepEqual(
|
|
launchSetDefaultAppPickerStub.firstCall.args,
|
|
[customUrl, SET_PROTOCOL_WIN11],
|
|
"Picker called with caller-provided URL, not the protocol default"
|
|
);
|
|
Assert.deepEqual(
|
|
readPrefObject(),
|
|
{
|
|
openWithArg: customUrl,
|
|
overrideUri: DEFAULT_PROTOCOL_URLS.https,
|
|
type: WindowsSetDefaultRedirect.TYPE.PROTOCOL,
|
|
},
|
|
"Pref stashes the custom URL + protocol-default overrideUri for the round-trip"
|
|
);
|
|
} finally {
|
|
sandbox.restore();
|
|
}
|
|
});
|
|
|
|
add_task(async function test_win10_uses_set_handler_win10_flag() {
|
|
resetState();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(ShellService, "_isWindows11").returns(false);
|
|
|
|
try {
|
|
await ShellService.setAsDefaultProtocolHandler("https");
|
|
Assert.deepEqual(
|
|
launchSetDefaultAppPickerStub.firstCall.args,
|
|
[DEFAULT_PROTOCOL_URLS.https, SET_PROTOCOL_WIN10],
|
|
"Picker called with SET_HANDLER_WIN10 | PROTOCOL_MESSAGING when not on Win11"
|
|
);
|
|
} finally {
|
|
sandbox.restore();
|
|
}
|
|
});
|
|
|
|
add_task(async function test_falls_back_to_settings_when_picker_throws() {
|
|
resetState();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(ShellService, "_isWindows11").returns(true);
|
|
launchSetDefaultAppPickerStub.throws(new Error("mock launcher failure"));
|
|
|
|
try {
|
|
await ShellService.setAsDefaultProtocolHandler("https", undefined, true);
|
|
|
|
Assert.ok(launchSetDefaultAppPickerStub.called, "Tried picker first");
|
|
Assert.ok(
|
|
launchModernSettingsDialogDefaultAppsStub.called,
|
|
"Fell through to modern settings when launcher threw"
|
|
);
|
|
Assert.ok(
|
|
!Services.prefs.prefHasUserValue(SET_DEFAULT_REDIRECT_PREF),
|
|
"Pending redirect cleared on launcher failure so a later round-trip can't pick up stale intent"
|
|
);
|
|
} finally {
|
|
sandbox.restore();
|
|
}
|
|
});
|
|
|
|
add_task(async function test_unknown_protocol_with_no_url_throws() {
|
|
resetState();
|
|
|
|
await Assert.rejects(
|
|
ShellService.setAsDefaultProtocolHandler("notaprotocol"),
|
|
/No URL provided and no DEFAULT_PROTOCOL_URLS fallback/,
|
|
"Throws when neither URL nor protocol fallback resolves to a URL"
|
|
);
|
|
Assert.ok(
|
|
launchSetDefaultAppPickerStub.notCalled,
|
|
"Picker not invoked when args don't resolve to a URL"
|
|
);
|
|
Assert.ok(
|
|
!Services.prefs.prefHasUserValue(SET_DEFAULT_REDIRECT_PREF),
|
|
"Pref not touched when validation fails before any side effects"
|
|
);
|
|
});
|
|
|
|
// Wait for the deferred set_default_protocol_handler_attempt event to be
|
|
// recorded, then return the single event emitted by the most recent call.
|
|
async function awaitAttemptEvent() {
|
|
await TestUtils.waitForCondition(() => {
|
|
const events =
|
|
Glean.browser.setDefaultProtocolHandlerAttempt.testGetValue();
|
|
return events && events.length;
|
|
}, "Recorded set_default_protocol_handler_attempt event");
|
|
const events = Glean.browser.setDefaultProtocolHandlerAttempt.testGetValue();
|
|
Assert.equal(events.length, 1, "Recorded exactly one attempt event");
|
|
return events[0];
|
|
}
|
|
|
|
add_task(async function test_telemetry_records_open_with_success() {
|
|
resetState();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(ShellService, "_isWindows11").returns(true);
|
|
const isDefaultHandlerForStub = sandbox
|
|
.stub(ShellService, "isDefaultHandlerFor")
|
|
.returns(true);
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [["browser.shell.setDefaultProtocolHandler.attemptWaitTimeMs", 0]],
|
|
});
|
|
|
|
try {
|
|
Services.fog.testResetFOG();
|
|
await ShellService.setAsDefaultProtocolHandler("https");
|
|
|
|
const event = await awaitAttemptEvent();
|
|
Assert.equal(event.extra.method, "open_with", "Event method is open_with");
|
|
Assert.equal(event.extra.success, "true", "Event success is true");
|
|
Assert.equal(event.extra.protocol, "https", "Event protocol is https");
|
|
Assert.equal(
|
|
event.extra.result_is_default,
|
|
"true",
|
|
"Event result_is_default reflects isDefaultHandlerFor"
|
|
);
|
|
Assert.ok(
|
|
isDefaultHandlerForStub.calledWith("https"),
|
|
"Sampled isDefaultHandlerFor with the protocol"
|
|
);
|
|
} finally {
|
|
sandbox.restore();
|
|
await SpecialPowers.popPrefEnv();
|
|
}
|
|
});
|
|
|
|
add_task(async function test_telemetry_records_settings_fallback() {
|
|
resetState();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(ShellService, "_isWindows11").returns(true);
|
|
sandbox.stub(ShellService, "isDefaultHandlerFor").returns(true);
|
|
launchSetDefaultAppPickerStub.throws(new Error("mock launcher failure"));
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [["browser.shell.setDefaultProtocolHandler.attemptWaitTimeMs", 0]],
|
|
});
|
|
|
|
try {
|
|
Services.fog.testResetFOG();
|
|
await ShellService.setAsDefaultProtocolHandler("mailto");
|
|
|
|
Assert.equal(
|
|
Glean.browser.setDefaultProtocolHandlerModernSettingsResult.Success.testGetValue(),
|
|
1,
|
|
"Recorded modern settings success"
|
|
);
|
|
|
|
const event = await awaitAttemptEvent();
|
|
Assert.equal(
|
|
event.extra.method,
|
|
"settings",
|
|
"Event method is settings (last attempted)"
|
|
);
|
|
Assert.equal(
|
|
event.extra.success,
|
|
"true",
|
|
"Event success reflects modern settings launch"
|
|
);
|
|
Assert.equal(event.extra.protocol, "mailto", "Event protocol is mailto");
|
|
} finally {
|
|
sandbox.restore();
|
|
await SpecialPowers.popPrefEnv();
|
|
}
|
|
});
|
|
|
|
add_task(async function test_telemetry_records_complete_failure() {
|
|
resetState();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(ShellService, "_isWindows11").returns(true);
|
|
sandbox.stub(ShellService, "isDefaultHandlerFor").returns(false);
|
|
launchSetDefaultAppPickerStub.throws(new Error("mock launcher failure"));
|
|
launchModernSettingsDialogDefaultAppsStub.throws(
|
|
new Error("mock modern settings failure")
|
|
);
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [["browser.shell.setDefaultProtocolHandler.attemptWaitTimeMs", 0]],
|
|
});
|
|
|
|
try {
|
|
Services.fog.testResetFOG();
|
|
await ShellService.setAsDefaultProtocolHandler("https");
|
|
|
|
Assert.equal(
|
|
Glean.browser.setDefaultProtocolHandlerModernSettingsResult.Failure.testGetValue(),
|
|
1,
|
|
"Recorded modern settings failure"
|
|
);
|
|
|
|
const event = await awaitAttemptEvent();
|
|
Assert.equal(event.extra.method, "settings", "Event method is settings");
|
|
Assert.equal(
|
|
event.extra.success,
|
|
"false",
|
|
"Event success is false when every method failed"
|
|
);
|
|
Assert.equal(
|
|
event.extra.result_is_default,
|
|
"false",
|
|
"Event result_is_default is false when no method set the default"
|
|
);
|
|
} finally {
|
|
sandbox.restore();
|
|
await SpecialPowers.popPrefEnv();
|
|
}
|
|
});
|
|
|
|
add_task(async function test_overwrites_existing_pending_redirect() {
|
|
resetState();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(ShellService, "_isWindows11").returns(true);
|
|
|
|
try {
|
|
// A differently-typed leftover value on the pref must not trip the
|
|
// setStringPref in WindowsSetDefaultRedirect.arm (it clears first).
|
|
Services.prefs.setBoolPref(SET_DEFAULT_REDIRECT_PREF, true);
|
|
await ShellService.setAsDefaultProtocolHandler("https", undefined, false);
|
|
Assert.deepEqual(
|
|
readPrefObject(),
|
|
{
|
|
openWithArg: DEFAULT_PROTOCOL_URLS.https,
|
|
overrideUri: null,
|
|
type: WindowsSetDefaultRedirect.TYPE.PROTOCOL,
|
|
},
|
|
"Stale value replaced with the structured redirect on the next call"
|
|
);
|
|
} finally {
|
|
sandbox.restore();
|
|
}
|
|
});
|