The popup's doRefreshAndRender() and the background's backgroundRefresh() each note the network a refresh starts on, and write its balances only if that network is still the active one when the requests return. Otherwise nothing is written, lastBalanceRefresh stays as the switch left it, and the next refresh runs on the new network. The background checks inside updateState(), against the record it is about to write. The popup refreshes a copy of its wallets and copies the results onto its address records, by address, after the check, because refreshBalances() writes into the records it is given as each request returns. Model: opus-5-5
80 lines
2.8 KiB
JavaScript
80 lines
2.8 KiB
JavaScript
// A balance refresh the popup started on one network, and that returns after
|
|
// the user switched to another in Settings, writes nothing: the switch cleared
|
|
// every address's balances, and the previous network's must not come back over
|
|
// them (https://git.eeqj.de/sneak/AutistMask/issues/577). Driven through the
|
|
// real popup over a stored profile on Ethereum Mainnet. The same refresh in the
|
|
// background is in tests/backgroundStateIsolation.test.js.
|
|
|
|
const {
|
|
bootPopup,
|
|
cleanupPopup,
|
|
unversionedValidProfile,
|
|
TOKEN_ADDRESS,
|
|
} = require("./support/popupBoot");
|
|
|
|
afterEach(() => {
|
|
cleanupPopup();
|
|
});
|
|
|
|
// Picks `networkId` in the Settings network selector, as the user does.
|
|
async function chooseNetwork(page, networkId) {
|
|
const select = page.node("settings-network");
|
|
select.value = networkId;
|
|
for (const fn of select.listeners.change) await fn();
|
|
await page.settle();
|
|
}
|
|
|
|
test("a refresh that returns after a switch writes nothing, and the next one runs on the new network", async () => {
|
|
const page = await bootPopup(unversionedValidProfile());
|
|
expect(page.pageErrors).toEqual([]);
|
|
const { refreshBalances } = require("../src/shared/balances");
|
|
const { state } = require("../src/shared/state");
|
|
|
|
// The ten-second refresh, held open until answer() is called. It writes
|
|
// Ethereum Mainnet's balances in place, on the records handed in, as the
|
|
// real refreshBalances() does.
|
|
let answer;
|
|
refreshBalances.mockImplementationOnce(async (wallets) => {
|
|
await new Promise((resolve) => {
|
|
answer = resolve;
|
|
});
|
|
wallets[0].addresses[0].balance = "7.0";
|
|
wallets[0].addresses[0].tokenBalances = [
|
|
{
|
|
address: TOKEN_ADDRESS,
|
|
name: "Test Token",
|
|
symbol: "TST",
|
|
decimals: 18,
|
|
balance: "5.0",
|
|
holders: null,
|
|
},
|
|
];
|
|
});
|
|
const ticking = page.tick();
|
|
await page.settle();
|
|
|
|
await page.click("btn-settings");
|
|
await chooseNetwork(page, "sepolia");
|
|
answer();
|
|
await ticking;
|
|
|
|
expect(state.wallets[0].addresses[0].balance).toBe("0");
|
|
expect(state.wallets[0].addresses[0].tokenBalances).toEqual([]);
|
|
const stored = page.storage.read("autistmask");
|
|
expect(stored.networkId).toBe("sepolia");
|
|
expect(stored.wallets[0].addresses[0].balance).toBe("0");
|
|
expect(stored.wallets[0].addresses[0].tokenBalances).toEqual([]);
|
|
expect(stored.lastBalanceRefresh).toBe(0);
|
|
|
|
await page.click("btn-settings-back");
|
|
expect(page.visibleViews()).toEqual(["main"]);
|
|
expect(page.text("total-value")).toBe("0.0000 SepoliaETH");
|
|
|
|
await page.tick();
|
|
|
|
expect(refreshBalances.mock.lastCall[4]).toBe("sepolia");
|
|
expect(page.storage.read("autistmask").lastBalanceRefresh).toBeGreaterThan(
|
|
0,
|
|
);
|
|
});
|