Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
let utilGlobal;
let stopStoreSubscription;
add_setup(() => {
// Setup required to load the module into a global that we can access, since
// the test utils inject into their globalThis instead of exporting.
const principal = Services.scriptSecurityManager.getSystemPrincipal();
const webnav = Services.appShell.createWindowlessBrowser(true);
const docShell = webnav.docShell;
docShell.createAboutBlankDocumentViewer(principal, principal);
utilGlobal = webnav.document.defaultView;
utilGlobal.eval(`
const { store } = ChromeUtils.importESModule(
"moz-src:///comm/mail/base/content/state/store.mjs",
{ global: "current" }
);
globalThis.store = store;
// Just imported for the side-effect injecting the slice.
ChromeUtils.importESModule(
{ global: "current" }
);
ChromeUtils.importESModule(
{ global: "current" }
);
`);
registerCleanupFunction(() => stopStoreSubscription?.());
});
add_task(function test_exportedToGlobal() {
Assert.equal(
typeof utilGlobal.ReduxTestUtils,
"object",
"Should export a test utils object as a side-effect"
);
});
add_task(async function test_waitForAction() {
Assert.equal(
typeof utilGlobal.ReduxTestUtils.waitForAction,
"function",
"Should have a waitForAction function on the utils"
);
const action = { type: "foo", payload: "test" };
const actionObserved = utilGlobal.ReduxTestUtils.waitForAction(
"foo",
incomingAction => incomingAction === action
);
utilGlobal.store.dispatch(action);
const resultingAction = await actionObserved;
Assert.strictEqual(
resultingAction,
action,
"Should have seen the same action as we dispatched"
);
});
add_task(async function test_waitForAction_checkFunctionThrows() {
const action = { type: "foo", payload: "test" };
const testError = new Error("test");
const actionObserved = utilGlobal.ReduxTestUtils.waitForAction("foo", () => {
throw testError;
});
utilGlobal.store.dispatch(action);
await Assert.rejects(
actionObserved,
error => error === testError,
"Should reject with the error raised by the check function"
);
});
add_task(async function test_dispatchAction() {
Assert.equal(
typeof utilGlobal.ReduxTestUtils.dispatchAction,
"function",
"Should have a dispatchAction function on the utils"
);
const actionObserved = utilGlobal.ReduxTestUtils.waitForAction("test");
info("Dispatching action...");
const dispatchedAction = await utilGlobal.ReduxTestUtils.dispatchAction(
"testAction",
"foo bar"
);
info("Waiting for the action to be observed...");
const observedAction = await actionObserved;
Assert.deepEqual(
dispatchedAction,
{ type: "test", payload: "foo bar" },
"Should have dispatched the expected action"
);
Assert.deepEqual(
observedAction,
dispatchedAction,
"Should have observed the same action that was generated by dispatchAction"
);
});
add_task(function test_subscribe() {
const notifications = [];
let dispatchReturned = false;
stopStoreSubscription = utilGlobal.ReduxTestUtils.subscribe(() => {
notifications.push({
dispatchReturned,
state: utilGlobal.ReduxTestUtils.getState(),
});
});
utilGlobal.store.dispatch({ type: "test-subscription" });
dispatchReturned = true;
Assert.equal(
notifications.length,
1,
"The listener should run once for a dispatch that leaves state unchanged"
);
Assert.equal(
notifications[0].dispatchReturned,
false,
"The listener should run before dispatch returns"
);
Assert.strictEqual(
notifications[0].state,
utilGlobal.store.getState(),
"The listener should read the current store state without copying it"
);
stopStoreSubscription();
stopStoreSubscription = null;
utilGlobal.store.dispatch({ type: "test-subscription-stopped" });
Assert.equal(
notifications.length,
1,
"Removing the listener should stop later dispatch notifications"
);
});
add_task(function test_getState() {
Assert.strictEqual(
utilGlobal.ReduxTestUtils.getState(),
utilGlobal.store.getState(),
"The helper should return its context's current state without copying it"
);
});
add_task(async function test_selectValue() {
const result = await utilGlobal.ReduxTestUtils.selectValue(
"testSelector",
"foo",
"bar"
);
Assert.deepEqual(
result,
["lorem", "foo", "bar"],
"The selector should receive the current state and extra arguments"
);
const state = await utilGlobal.ReduxTestUtils.selectValue(
"testStateSelector"
);
Assert.strictEqual(
state,
utilGlobal.store.getState(),
"The selector result should keep its identity in the helper's context"
);
});
add_task(async function test_dispatchActionWithThunk() {
const actionObserved = utilGlobal.ReduxTestUtils.waitForAction("test");
const result = await utilGlobal.ReduxTestUtils.dispatchAction(
"testThunk",
"thunk value"
);
const observedAction = await actionObserved;
Assert.deepEqual(
observedAction,
{ type: "test", payload: "thunk value" },
"The function action should dispatch to the helper's store"
);
Assert.deepEqual(
result,
["lorem", "thunk value"],
"Dispatch should wait for the function action's selector result"
);
});
add_task(async function test_assertSelector() {
Assert.equal(
typeof utilGlobal.ReduxTestUtils.assertSelector,
"function",
"Should have a assertSelector function on the utils"
);
await utilGlobal.ReduxTestUtils.assertSelector(
"testSelector",
["lorem", "foo", "bar"],
"Should have the initial value in the store and pass along the extra arguments",
"foo",
"bar"
);
});