fix: Back from Settings no longer lands on a secret screen left by the gear (closes #461)
Leaving the private key export or recovery phrase screen drops the selection it was showing, but the settings gear had just pushed the screen onto the Back stack, so Back from Settings landed on a password prompt that could only fail. Each screen's leave handler now also takes it off the top of the stack, which is what a reopened popup already does to these screens. Back from Settings goes to the address screen for the export screen; for the recovery phrase screen, opened from Settings, it stays on Settings once, as after a reopen. Jest tests drive the gear and then Back, and each screen's own Back, for both screens; leavePrivkeyScreen() in the e2e suite expects the address screen. Model: opus-5-5
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
// Tests for the recovery phrase display (issue #161).
|
||||
//
|
||||
// These cover the parts that do not need a DOM: which wallet types may be
|
||||
// offered the action at all, the exclusion of the screen from the set of
|
||||
// views the popup may reopen onto, and the absence of any path from this
|
||||
// module to the logger. The DOM behaviour it guards — nothing rendered
|
||||
// before the password is accepted, a wrong password revealing nothing, and
|
||||
// the wipe on leaving — is driven against the real popup in a real browser
|
||||
// by tests/e2e/run.js, which is where every other view behaviour is tested.
|
||||
// These cover which wallet types may be offered the action at all, the
|
||||
// exclusion of the screen from the set of views the popup may reopen onto,
|
||||
// the absence of any path from this module to the logger, and, against a
|
||||
// minimal DOM stub, where Back goes after the screen is left by the settings
|
||||
// gear or by its own Back. The rest of the DOM behaviour it guards — nothing rendered before the
|
||||
// password is accepted, a wrong password revealing nothing, and the wipe on
|
||||
// leaving — is driven against the real popup in a real browser by
|
||||
// tests/e2e/run.js, which is where every other view behaviour is tested.
|
||||
|
||||
jest.mock("../src/shared/vault", () => ({
|
||||
decryptWithPassword: jest.fn(),
|
||||
}));
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
@@ -74,6 +79,86 @@ describe("views the popup may reopen onto", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// Just enough document for helpers.showView() and this view: every element
|
||||
// is made on first lookup and keeps what the view writes to it, its click
|
||||
// handler included.
|
||||
function makeDocument() {
|
||||
const els = new Map();
|
||||
function makeElement() {
|
||||
const classes = new Set();
|
||||
const el = {
|
||||
textContent: "",
|
||||
value: "",
|
||||
style: {},
|
||||
classList: {
|
||||
add: (name) => classes.add(name),
|
||||
remove: (name) => classes.delete(name),
|
||||
contains: (name) => classes.has(name),
|
||||
toggle: (name, on) =>
|
||||
on ? classes.add(name) : classes.delete(name),
|
||||
},
|
||||
addEventListener: (name, fn) => {
|
||||
if (name === "click") el.onClick = fn;
|
||||
},
|
||||
};
|
||||
return el;
|
||||
}
|
||||
return {
|
||||
getElementById(id) {
|
||||
// Created on demand by helpers.js; absent on a mainnet popup
|
||||
// that is not a debug build.
|
||||
if (id === "debug-banner") return null;
|
||||
if (!els.has(id)) els.set(id, makeElement());
|
||||
return els.get(id);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("Back from Settings after leaving by the settings gear", () => {
|
||||
// On Settings, opened from Home.
|
||||
function load() {
|
||||
jest.resetModules();
|
||||
globalThis.document = makeDocument();
|
||||
const helpers = loadHelpers();
|
||||
const { state } = require("../src/shared/state");
|
||||
const showPhrase = require("../src/popup/views/showPhrase");
|
||||
showPhrase.init();
|
||||
state.wallets = [{ name: "Wallet 1", type: "hd", addresses: [] }];
|
||||
state.currentView = "settings";
|
||||
state.viewStack = ["main"];
|
||||
return { helpers, state, showPhrase };
|
||||
}
|
||||
|
||||
// https://git.eeqj.de/sneak/AutistMask/issues/461: leaving drops the
|
||||
// wallet selection, so Back onto this screen showed a password prompt
|
||||
// that could only answer "No wallet is selected."
|
||||
test("does not land on the recovery phrase screen", () => {
|
||||
const { helpers, state, showPhrase } = load();
|
||||
|
||||
// Opened from the wallet list in Settings, then left by the gear:
|
||||
// push the current view, then show Settings.
|
||||
showPhrase.show(0);
|
||||
helpers.pushCurrentView();
|
||||
helpers.showView("settings");
|
||||
|
||||
expect(state.viewStack).toEqual(["main", "settings"]);
|
||||
helpers.goBack();
|
||||
expect(state.currentView).not.toBe(SHOW_PHRASE_VIEW);
|
||||
});
|
||||
|
||||
// This Back takes Settings off the stack before the screen is left, so
|
||||
// the stack's top is then the entry Back from Settings will need.
|
||||
test("its own Back button leaves the rest of the stack alone", () => {
|
||||
const { state, showPhrase } = load();
|
||||
showPhrase.show(0);
|
||||
|
||||
globalThis.document.getElementById("btn-show-phrase-back").onClick();
|
||||
|
||||
expect(state.currentView).toBe("settings");
|
||||
expect(state.viewStack).toEqual(["main"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("the phrase cannot reach the logger", () => {
|
||||
const source = fs.readFileSync(
|
||||
path.join(__dirname, "..", "src", "popup", "views", "showPhrase.js"),
|
||||
|
||||
Reference in New Issue
Block a user