Copies .dockerignore, .gitignore, .prettierignore, check.yml and REPO_POLICIES.md from sneak/prompts at dd4027b. The repo's own entries (dist/, release/, yarn files) are kept after the canonical content. The Dockerfile gets separate lint and test phases. Its last stage depends on both, checks the git describe version and runs make build. script/lint, test, check, cibuild and docker are the canonical models. check-censored moves into the lint phase and test-verify-build into the test phase. fmt and fmt-check fall back to the nvm-installed node. The e2e image builds are uncached. Comments that cited the old 20-second test cap now say 60. Model: opus-5-5
77 lines
3.1 KiB
JavaScript
77 lines
3.1 KiB
JavaScript
// balanceLine() is the row that issue #307 was reported against: every
|
|
// screen that lists a holding renders through it, and the symbol it renders
|
|
// is whatever an ERC-20's symbol() returned. This asserts against the
|
|
// string it emits, which is what gets assigned to innerHTML.
|
|
//
|
|
// The browser half of the same claim — that a real Chrome renders that
|
|
// string as text and puts no iframe in the popup DOM — is in
|
|
// tests/e2e/run.js. This half runs inside the 60-second make test cap.
|
|
|
|
"use strict";
|
|
|
|
// helpers.js reaches for both at module scope through the modules it pulls
|
|
// in. Neither is exercised by anything asserted here.
|
|
global.chrome = {
|
|
storage: {
|
|
local: {
|
|
get: () => Promise.resolve({}),
|
|
set: () => Promise.resolve(),
|
|
},
|
|
},
|
|
runtime: { sendMessage: () => {} },
|
|
};
|
|
global.document = {
|
|
getElementById: () => null,
|
|
createElement: () => ({ style: {}, classList: { toggle() {} } }),
|
|
body: { prepend: () => {} },
|
|
addEventListener: () => {},
|
|
};
|
|
|
|
const { balanceLine } = require("../src/popup/views/helpers");
|
|
const { MAX_SYMBOL_LENGTH } = require("../src/shared/symbolDisplay");
|
|
|
|
// The payload from the issue's reproduction, verbatim.
|
|
const HOSTILE_SYMBOL =
|
|
'<iframe id="pwn" src="https://dapp.e2e.test/" ' +
|
|
'style="position:fixed;left:0;top:0;width:360px;height:600px;z-index:99999"></iframe>';
|
|
|
|
describe("balanceLine", () => {
|
|
test("emits a hostile symbol as text, not as an element", () => {
|
|
// Deliberately asserted on the escaping alone. The cap truncates
|
|
// this payload before its id attribute, so an assertion about the
|
|
// rest of the payload would pass on the cap and say nothing about
|
|
// the escape.
|
|
const html = balanceLine(HOSTILE_SYMBOL, 1, null, null);
|
|
expect(html).not.toContain("<iframe");
|
|
expect(html).toContain("<iframe");
|
|
});
|
|
|
|
test("caps the symbol before rendering it", () => {
|
|
const html = balanceLine("A".repeat(4096), 1, null, null);
|
|
expect(html).toContain("A".repeat(MAX_SYMBOL_LENGTH - 1) + "…");
|
|
expect(html).not.toContain("A".repeat(MAX_SYMBOL_LENGTH + 1));
|
|
});
|
|
|
|
// The token id lands inside data-token="...", so a quote in it is a
|
|
// way out of the attribute and into a new one.
|
|
test("keeps a quote-bearing token id inside its attribute", () => {
|
|
const html = balanceLine("TKN", 1, null, '" onclick="alert(1)');
|
|
expect(html).not.toContain('onclick="');
|
|
expect(html).toContain('data-token="" onclick="alert(1)"');
|
|
});
|
|
|
|
test("renders an ordinary holding unchanged", () => {
|
|
const html = balanceLine("USDC", 1.5, null, "0xabc");
|
|
expect(html).toContain("<span>USDC</span>");
|
|
expect(html).toContain("<span>1.5000</span>");
|
|
expect(html).toContain('data-token="0xabc"');
|
|
});
|
|
|
|
// formatUsd() writes a value under a cent as "< $0.01".
|
|
test("escapes the USD value along with the symbol", () => {
|
|
const html = balanceLine("USDC", 0.001, 1, null);
|
|
expect(html).toContain("< $0.01");
|
|
expect(html).not.toContain("< $0.01");
|
|
});
|
|
});
|