Files
AutistMask/tests/balanceLineEscaping.test.js
T
sneak c28e27d509
check / check (push) Successful in 7m32s
e2e / e2e-chrome (push) Successful in 5m30s
e2e / e2e-firefox (push) Successful in 3m56s
chore: re-vendor canonical files from prompts at dd4027b (closes #472)
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
2026-10-06 03:44:35 +00:00

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("&lt;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="&quot; onclick=&quot;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("&lt; $0.01");
expect(html).not.toContain("< $0.01");
});
});