@@ -6,13 +6,18 @@ import {
66 authMenuFocusKey ,
77 currentMarkerLabel ,
88 formatAccountHint ,
9+ formatDate ,
910 formatRelativeTime ,
1011 mainMenuTitleWithVersion ,
1112 statusBadge ,
1213 type AccountInfo ,
1314 type AuthMenuAction ,
1415} from "../lib/ui/auth-menu-builder.js" ;
15- import { getUiRuntimeOptions } from "../lib/ui/runtime.js" ;
16+ import {
17+ getUiRuntimeOptions ,
18+ resetUiRuntimeOptions ,
19+ setUiRuntimeOptions ,
20+ } from "../lib/ui/runtime.js" ;
1621import { UI_COPY } from "../lib/ui/ui-copy.js" ;
1722
1823const NOW = Date . now ( ) ;
@@ -96,12 +101,18 @@ describe("accountTitle", () => {
96101 ) . toBe ( "2. a@b.c" ) ;
97102 } ) ;
98103
99- it ( "strips ANSI escapes and control characters from identity fields" , ( ) => {
100- // A hostile accountLabel must not be able to repaint the menu row.
101- const title = accountTitle (
102- account ( { accountLabel : "\x1b[31mEvil\x1b[0m Label" } ) ,
104+ it ( "strips ANSI escapes and control characters from every identity field" , ( ) => {
105+ // Hostile identity values must not be able to repaint the menu row,
106+ // regardless of which field carries them.
107+ expect (
108+ accountTitle ( account ( { accountLabel : "\x1b[31mEvil\x1b[0m Label" } ) ) ,
109+ ) . toBe ( "1. Evil Label" ) ;
110+ expect (
111+ accountTitle ( account ( { email : "\x1b[2Jevil@example.com" } ) ) ,
112+ ) . toBe ( "1. evil@example.com" ) ;
113+ expect ( accountTitle ( account ( { accountId : "acc\x1b[31m_red" } ) ) ) . toBe (
114+ "1. acc_red" ,
103115 ) ;
104- expect ( title ) . toBe ( "1. Evil Label" ) ;
105116 } ) ;
106117} ) ;
107118
@@ -166,6 +177,14 @@ describe("statusBadge", () => {
166177 } ) ;
167178} ) ;
168179
180+ describe ( "formatDate" , ( ) => {
181+ it ( "renders unknown for missing timestamps and a locale date otherwise" , ( ) => {
182+ expect ( formatDate ( undefined ) ) . toBe ( "unknown" ) ;
183+ const ts = NOW - 10 * DAY_MS ;
184+ expect ( formatDate ( ts ) ) . toBe ( new Date ( ts ) . toLocaleDateString ( ) ) ;
185+ } ) ;
186+ } ) ;
187+
169188describe ( "currentMarkerLabel" , ( ) => {
170189 it ( "humanizes in-use and passes other markers through" , ( ) => {
171190 expect ( currentMarkerLabel ( "in-use" ) ) . toBe ( "in use" ) ;
@@ -248,6 +267,33 @@ describe("formatAccountHint", () => {
248267 } ) ;
249268} ) ;
250269
270+ describe ( "legacy (v1) palette rendering" , ( ) => {
271+ it ( "renders badges and hints with the same text content when v2 is off" , ( ) => {
272+ setUiRuntimeOptions ( { v2Enabled : false } ) ;
273+ try {
274+ expect ( stripAnsi ( statusBadge ( "rate-limited" ) ) ) . toContain (
275+ "rate-limited" ,
276+ ) ;
277+ expect ( stripAnsi ( statusBadge ( undefined ) ) ) . toContain ( "unknown" ) ;
278+
279+ const hint = stripAnsi (
280+ formatAccountHint (
281+ account ( {
282+ lastUsed : NOW - 1_000 ,
283+ quota5hLeftPercent : 50 ,
284+ quota5hResetAtMs : NOW + 30_000 ,
285+ } ) ,
286+ getUiRuntimeOptions ( ) ,
287+ ) ,
288+ ) ;
289+ expect ( hint ) . toMatch ( / ^ L a s t u s e d : t o d a y \| L i m i t s : 5 h / ) ;
290+ expect ( hint ) . toContain ( "50%" ) ;
291+ } finally {
292+ resetUiRuntimeOptions ( ) ;
293+ }
294+ } ) ;
295+ } ) ;
296+
251297describe ( "authMenuFocusKey" , ( ) => {
252298 it ( "keys account actions by their storage position" , ( ) => {
253299 const row = account ( { index : 2 , sourceIndex : 5 } ) ;
0 commit comments