// 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.

const fs = require("fs");
const path = require("path");

const { walletHasRecoveryPhrase } = require("../src/shared/wallet");
const { RESTORABLE_VIEWS } = require("../src/shared/restorableViews");

const SHOW_PHRASE_VIEW = "show-phrase";

// helpers.js pulls in state.js, which reads chrome.storage.local at load.
function loadHelpers() {
    globalThis.chrome = {
        storage: { local: { get: async () => ({}), set: async () => {} } },
    };
    return require("../src/popup/views/helpers");
}

describe("which wallets have a recovery phrase", () => {
    test("an HD wallet does", () => {
        expect(walletHasRecoveryPhrase({ type: "hd" })).toBe(true);
    });

    // A key wallet holds a bare private key and an xprv wallet an extended
    // private key. Neither can be turned back into words, so neither may be
    // offered the action.
    test("a key wallet does not", () => {
        expect(walletHasRecoveryPhrase({ type: "key" })).toBe(false);
    });

    test("an xprv wallet does not", () => {
        expect(walletHasRecoveryPhrase({ type: "xprv" })).toBe(false);
    });

    test("an unknown or missing wallet type does not", () => {
        expect(walletHasRecoveryPhrase({ type: "something-new" })).toBe(false);
        expect(walletHasRecoveryPhrase({})).toBe(false);
        expect(walletHasRecoveryPhrase(undefined)).toBe(false);
    });
});

describe("views the popup may reopen onto", () => {
    // Restoring onto a secret screen would put the phrase on screen with no
    // password prompt in front of it, on a popup the user may have reopened
    // by accident.
    test("the recovery phrase screen is not restorable", () => {
        expect(RESTORABLE_VIEWS.has(SHOW_PHRASE_VIEW)).toBe(false);
    });

    test("the private key export screen is not restorable either", () => {
        expect(RESTORABLE_VIEWS.has("export-privkey")).toBe(false);
    });

    test("the recovery phrase screen is still a registered view", () => {
        const { VIEWS } = loadHelpers();
        expect(VIEWS).toContain(SHOW_PHRASE_VIEW);
    });

    // Guards the other direction: a restorable name that is not a real view
    // would leave restoreView() showing nothing at all.
    test("every restorable view is a registered view", () => {
        const { VIEWS } = loadHelpers();
        for (const view of RESTORABLE_VIEWS) {
            expect(VIEWS).toContain(view);
        }
    });
});

describe("the phrase cannot reach the logger", () => {
    const source = fs.readFileSync(
        path.join(__dirname, "..", "src", "popup", "views", "showPhrase.js"),
        "utf8",
    );

    // The decrypted phrase only ever lives in a local and in the DOM node
    // that displays it. The module has no logger to hand it to, and this
    // pins that: src/shared/log.js writes to the console, and a console
    // record of a recovery phrase outlives the popup.
    test("the view does not import src/shared/log.js", () => {
        expect(source).not.toMatch(/require\(["'][^"']*shared\/log["']\)/);
    });

    test("the view calls no logger method", () => {
        expect(source).not.toMatch(/\blog\.(debugf|infof|warnf|errorf)\b/);
    });
});
