/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; add_task(async function test_handle_multi_action() { const action = { type: "MULTI_ACTION", data: { actions: [ { type: "DISABLE_DOH", }, { type: "OPEN_AWESOME_BAR", }, ], }, }; const DOH_DOORHANGER_DECISION_PREF = "doh-rollout.doorhanger-decision"; const NETWORK_TRR_MODE_PREF = "network.trr.mode"; await SpecialPowers.pushPrefEnv({ set: [ [DOH_DOORHANGER_DECISION_PREF, "mochitest"], [NETWORK_TRR_MODE_PREF, 0], ], }); await SMATestUtils.executeAndValidateAction(action); Assert.equal( Services.prefs.getStringPref(DOH_DOORHANGER_DECISION_PREF, ""), "UIDisabled", "Pref should be set on disabled" ); Assert.equal( Services.prefs.getIntPref(NETWORK_TRR_MODE_PREF, 0), 5, "Pref should be set on disabled" ); Assert.ok(gURLBar.focused, "Focus should be on awesome bar"); }); add_task(async function test_handle_multi_action_with_invalid_action() { const action = { type: "MULTI_ACTION", data: { actions: [ { type: "NONSENSE", }, ], }, }; await SMATestUtils.validateAction(action); let error; try { await SpecialMessageActions.handleAction(action, gBrowser); } catch (e) { error = e; } ok(error, "should throw if an unexpected event is handled"); Assert.equal( error.message, "Error in MULTI_ACTION event: Special message action with type NONSENSE is unsupported." ); }); add_task(async function test_multi_action_set_pref_ordered_execution() { const TEST_MULTI_PREF = "test.multi.pref"; Services.prefs.clearUserPref(TEST_MULTI_PREF); let callOrder = []; const originalSetPref = SpecialMessageActions.setPref.bind( SpecialMessageActions ); const originalHandleAction = SpecialMessageActions.handleAction.bind( SpecialMessageActions ); sinon .stub(SpecialMessageActions, "handleAction") .callsFake(async function (action, browser) { if (action.type === "SET_PREF") { // Increase the delay for each subsequent item to ensure earlier items // would take longer to finish if they weren't executing sequentially let delay = 60 - callOrder.length * 10; // eslint-disable-next-line mozilla/no-arbitrary-setTimeout await new Promise(resolve => setTimeout(resolve, delay)); callOrder.push(action.data.pref.value); originalSetPref(action.data.pref); } return originalHandleAction(action, browser); }); const action = { type: "MULTI_ACTION", data: { orderedExecution: true, actions: [ { type: "SET_PREF", data: { pref: { name: TEST_MULTI_PREF, value: "first" } }, }, { type: "SET_PREF", data: { pref: { name: TEST_MULTI_PREF, value: "second" } }, }, { type: "SET_PREF", data: { pref: { name: TEST_MULTI_PREF, value: "third" } }, }, ], }, }; Services.prefs.clearUserPref(`messaging-system-action.${TEST_MULTI_PREF}`); let browser = gBrowser || { ownerGlobal: window }; let start = Date.now(); await originalHandleAction(action, browser); let duration = Date.now() - start; // Total minimum delay: 60 + 50 + 20 = 130ms. Assert.greaterOrEqual( duration, 130, "Ordered execution should take at least 130ms" ); Assert.deepEqual( callOrder, ["first", "second", "third"], "Actions executed sequentially" ); Assert.equal( Services.prefs.getStringPref(`messaging-system-action.${TEST_MULTI_PREF}`), "third", "Pref was set" ); Services.prefs.clearUserPref(TEST_MULTI_PREF); sinon.restore(); }); add_task( async function test_multi_action_ordered_execution_requires_previous() { const TEST_SET_PREF = "test.set.pref"; let sandbox = sinon.createSandbox(); const originalHandleAction = SpecialMessageActions.handleAction.bind( SpecialMessageActions ); sandbox .stub(SpecialMessageActions, "handleAction") .callsFake(function (action, browser) { if (action.type == "RETURN_TRUE") { return true; } else if (action.type == "RETURN_FALSE") { return false; } return originalHandleAction(action, browser); }); // Checks that both actions complete if the first succeeds // and the second has requiresPrevious: true const successAction = { type: "MULTI_ACTION", data: { orderedExecution: true, actions: [ { type: "RETURN_TRUE", }, { type: "SET_PREF", data: { pref: { name: TEST_SET_PREF, value: true } }, requiresPrevious: true, }, ], }, }; await SpecialMessageActions.handleAction(successAction, gBrowser); Assert.equal( Services.prefs.getBoolPref(`messaging-system-action.${TEST_SET_PREF}`), true, "Pref should be set" ); Services.prefs.clearUserPref(`messaging-system-action.${TEST_SET_PREF}`); // Checks that the second action does not complete // if the first action fails and the second has requiresPrevious: true const failureAction = { type: "MULTI_ACTION", data: { orderedExecution: true, actions: [ { type: "RETURN_FALSE", }, { type: "SET_PREF", data: { pref: { name: TEST_SET_PREF, value: true } }, requiresPrevious: true, }, ], }, }; await SpecialMessageActions.handleAction(failureAction, gBrowser); Assert.ok( !Services.prefs.getBoolPref( `messaging-system-action.${TEST_SET_PREF}`, false ), "Pref should not be set" ); Services.prefs.clearUserPref(TEST_SET_PREF); // Check that the second action still completes if the first fails // and requiresPrevious is not set const failureActionDoNoPrevious = { type: "MULTI_ACTION", data: { orderedExecution: true, actions: [ { type: "RETURN_FALSE", }, { type: "SET_PREF", data: { pref: { name: TEST_SET_PREF, value: true } }, }, ], }, }; await SpecialMessageActions.handleAction( failureActionDoNoPrevious, gBrowser ); Assert.equal( Services.prefs.getBoolPref(`messaging-system-action.${TEST_SET_PREF}`), true, "Pref should be set" ); Services.prefs.clearUserPref(`messaging-system-action.${TEST_SET_PREF}`); sandbox.restore(); } );