fix: a save merges this page's tracked token change into the stored list (closes #717)
A save wrote `trackedTokens` whole, so two pages on one network dropped each other's adds and brought back each other's removals. A save that keeps the network now merges this page's change into the stored list by contract address. A save that switches networks is unchanged. `mergeTrackedTokens()` does that merge, and the two other merges of tracked tokens now call it. It keeps one record per contract address, this page's for a token both lists hold, so a token held twice no longer multiplies. Model: opus-5-5
This commit was merged in pull request #726.
This commit is contained in:
@@ -117,6 +117,17 @@ async function chooseNetwork(boot, networkId) {
|
||||
await boot.settle();
|
||||
}
|
||||
|
||||
// Adds NEW_TOKEN_ADDRESS by contract address on SettingsAddToken, as the user
|
||||
// does. Returns the record the add tracks.
|
||||
async function addNewToken(boot) {
|
||||
const { lookupTokenInfo } = require("../src/shared/balances");
|
||||
const info = { symbol: "NEW", decimals: 18, name: "New Token" };
|
||||
lookupTokenInfo.mockResolvedValueOnce(info);
|
||||
boot.node("settings-addtoken-address").value = NEW_TOKEN_ADDRESS;
|
||||
await boot.click("btn-settings-addtoken-manual");
|
||||
return { address: NEW_TOKEN_ADDRESS, ...info, balanceNotFetched: true };
|
||||
}
|
||||
|
||||
// The Settings gear, a switch to Sepolia, and Back.
|
||||
async function gearSwitchBack(boot) {
|
||||
await boot.click("btn-settings");
|
||||
@@ -685,6 +696,113 @@ test("a token removed while this page waits to take another page's switch is gon
|
||||
expect(stored.networkTrackedTokens.mainnet).toEqual([]);
|
||||
});
|
||||
|
||||
// Another popup page tracks DAI after this page's last save. This page then
|
||||
// adds a token. Its save keeps DAI.
|
||||
test("a token another page added stays when this page adds a token", async () => {
|
||||
const boot = await bootOnAddToken("mainnet");
|
||||
expect(boot.pageErrors).toEqual([]);
|
||||
boot.storage.write("autistmask", {
|
||||
...boot.storage.read("autistmask"),
|
||||
trackedTokens: [MAINNET_TOKEN],
|
||||
});
|
||||
|
||||
const added = await addNewToken(boot);
|
||||
|
||||
expect(boot.storage.read("autistmask").trackedTokens).toEqual([
|
||||
MAINNET_TOKEN,
|
||||
added,
|
||||
]);
|
||||
});
|
||||
|
||||
// Another popup page tracks a new token after this page's last save. This page
|
||||
// then removes DAI, as the `[x]` on a tracked token in Settings does. Its save
|
||||
// keeps the new token.
|
||||
test("a token another page added stays when this page removes a token", async () => {
|
||||
const boot = await bootPopup(
|
||||
unversionedValidProfile({ trackedTokens: [MAINNET_TOKEN] }),
|
||||
);
|
||||
expect(boot.pageErrors).toEqual([]);
|
||||
const otherPageToken = {
|
||||
address: NEW_TOKEN_ADDRESS,
|
||||
symbol: "NEW",
|
||||
decimals: 18,
|
||||
name: "New Token",
|
||||
};
|
||||
boot.storage.write("autistmask", {
|
||||
...boot.storage.read("autistmask"),
|
||||
trackedTokens: [MAINNET_TOKEN, otherPageToken],
|
||||
});
|
||||
|
||||
const { state, saveState } = require("../src/shared/state");
|
||||
state.trackedTokens.splice(0, 1);
|
||||
await saveState();
|
||||
|
||||
expect(boot.storage.read("autistmask").trackedTokens).toEqual([
|
||||
otherPageToken,
|
||||
]);
|
||||
});
|
||||
|
||||
// Another popup page stops tracking DAI after this page's last save. This page
|
||||
// still holds DAI and adds a token. Its save does not store DAI again.
|
||||
test("a token another page removed stays removed when this page adds a token", async () => {
|
||||
const boot = await bootOnAddToken("mainnet", {
|
||||
trackedTokens: [MAINNET_TOKEN],
|
||||
});
|
||||
expect(boot.pageErrors).toEqual([]);
|
||||
boot.storage.write("autistmask", {
|
||||
...boot.storage.read("autistmask"),
|
||||
trackedTokens: [],
|
||||
});
|
||||
|
||||
const added = await addNewToken(boot);
|
||||
|
||||
expect(boot.storage.read("autistmask").trackedTokens).toEqual([added]);
|
||||
});
|
||||
|
||||
// Another popup page tracks DAI and the new token after this page's last save,
|
||||
// and its refresh has read the new token's balance. This page adds the new token
|
||||
// too, so the two pages hold different records for it. The save stores one
|
||||
// record for the new token, this page's, and keeps DAI.
|
||||
test("a token both pages added is stored once, with this page's record", async () => {
|
||||
const boot = await bootOnAddToken("mainnet");
|
||||
expect(boot.pageErrors).toEqual([]);
|
||||
boot.storage.write("autistmask", {
|
||||
...boot.storage.read("autistmask"),
|
||||
trackedTokens: [
|
||||
MAINNET_TOKEN,
|
||||
{
|
||||
address: NEW_TOKEN_ADDRESS,
|
||||
symbol: "NEW",
|
||||
decimals: 18,
|
||||
name: "New Token",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const added = await addNewToken(boot);
|
||||
|
||||
expect(boot.storage.read("autistmask").trackedTokens).toEqual([
|
||||
MAINNET_TOKEN,
|
||||
added,
|
||||
]);
|
||||
});
|
||||
|
||||
// This page and the stored list each hold DAI twice. This page then adds a
|
||||
// token. Its save stores DAI once.
|
||||
test("a token held twice is stored once when this page adds a token", async () => {
|
||||
const boot = await bootOnAddToken("mainnet", {
|
||||
trackedTokens: [MAINNET_TOKEN, MAINNET_TOKEN],
|
||||
});
|
||||
expect(boot.pageErrors).toEqual([]);
|
||||
|
||||
const added = await addNewToken(boot);
|
||||
|
||||
expect(boot.storage.read("autistmask").trackedTokens).toEqual([
|
||||
MAINNET_TOKEN,
|
||||
added,
|
||||
]);
|
||||
});
|
||||
|
||||
describe("Back after a switch from the Settings gear", () => {
|
||||
test("SettingsAddToken no longer offers the common tokens", async () => {
|
||||
const boot = await bootOnAddToken("mainnet");
|
||||
|
||||
Reference in New Issue
Block a user