mirror of
https://github.com/tiennm99/ccstatusline.git
synced 2026-10-14 12:16:37 +00:00
test: stabilize CI by isolating cross-file mocks
Convert module-level mocks to scoped spies and restore global stubs between tests to prevent Bun/Vitest cross-file leakage and flaky Actions failures.
This commit is contained in:
1 parent
78c7bc16f0
commit
59d43589c9
13 files changed
+174
-151
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { execSync } from 'child_process';
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
@@ -14,18 +15,22 @@ import {
|
||||
|
||||
vi.mock('child_process', () => ({ execSync: vi.fn() }));
|
||||
|
||||
const mockExecSync = execSync as unknown as {
|
||||
mock: { calls: unknown[][] };
|
||||
mockImplementationOnce: (impl: () => never) => void;
|
||||
mockReturnValueOnce: (value: string) => void;
|
||||
};
|
||||
|
||||
describe('terminal utils', () => {
|
||||
const mockExecSync = execSync as unknown as {
|
||||
mock: { calls: unknown[][] };
|
||||
mockImplementationOnce: (impl: () => never) => void;
|
||||
mockReturnValueOnce: (value: string) => void;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('returns width from tty probe when available', () => {
|
||||
mockExecSync.mockReturnValueOnce('ttys001\n');
|
||||
mockExecSync.mockReturnValueOnce('120\n');
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
@@ -6,25 +8,32 @@ import {
|
||||
} from 'vitest';
|
||||
|
||||
import type { WidgetItem } from '../../types/Widget';
|
||||
import { fetchUsageData } from '../usage';
|
||||
import * as usage from '../usage';
|
||||
import {
|
||||
hasUsageDependentWidgets,
|
||||
prefetchUsageDataIfNeeded
|
||||
} from '../usage-prefetch';
|
||||
|
||||
vi.mock('../usage', () => ({ fetchUsageData: vi.fn() }));
|
||||
|
||||
const mockFetchUsageData = fetchUsageData as unknown as {
|
||||
mockClear: () => void;
|
||||
mockResolvedValue: (value: unknown) => void;
|
||||
mock: { calls: unknown[][] };
|
||||
};
|
||||
import type { UsageData } from '../usage-types';
|
||||
|
||||
function makeLines(...lineItems: WidgetItem[][]): WidgetItem[][] {
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
describe('usage prefetch', () => {
|
||||
let mockFetchUsageData: {
|
||||
mock: { calls: unknown[][] };
|
||||
mockResolvedValue: (value: UsageData) => void;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
mockFetchUsageData = vi.spyOn(usage, 'fetchUsageData');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
expected: true,
|
||||
@@ -47,7 +56,6 @@ describe('usage prefetch', () => {
|
||||
});
|
||||
|
||||
it('fetches usage data once when at least one usage widget exists', async () => {
|
||||
mockFetchUsageData.mockClear();
|
||||
mockFetchUsageData.mockResolvedValue({ sessionUsage: 12.3 });
|
||||
|
||||
const lines = makeLines(
|
||||
@@ -62,8 +70,6 @@ describe('usage prefetch', () => {
|
||||
});
|
||||
|
||||
it('does not fetch usage data when no usage widgets exist', async () => {
|
||||
mockFetchUsageData.mockClear();
|
||||
|
||||
const lines = makeLines(
|
||||
[{ id: '1', type: 'model' }],
|
||||
[{ id: '2', type: 'git-branch' }]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
@@ -7,27 +8,32 @@ import {
|
||||
} from 'vitest';
|
||||
|
||||
import type { BlockMetrics } from '../../types';
|
||||
import { getCachedBlockMetrics } from '../jsonl';
|
||||
import * as jsonl from '../jsonl';
|
||||
import {
|
||||
FIVE_HOUR_BLOCK_MS,
|
||||
SEVEN_DAY_WINDOW_MS,
|
||||
SEVEN_DAY_WINDOW_MS
|
||||
} from '../usage-types';
|
||||
import {
|
||||
formatUsageDuration,
|
||||
getUsageWindowFromResetAt,
|
||||
getWeeklyUsageWindowFromResetAt,
|
||||
resolveUsageWindowWithFallback,
|
||||
resolveWeeklyUsageWindow
|
||||
} from '../usage';
|
||||
|
||||
vi.mock('../jsonl', () => ({ getCachedBlockMetrics: vi.fn() }));
|
||||
|
||||
const mockGetCachedBlockMetrics = getCachedBlockMetrics as unknown as {
|
||||
mock: { calls: unknown[][] };
|
||||
mockReturnValue: (value: BlockMetrics | null) => void;
|
||||
};
|
||||
} from '../usage-windows';
|
||||
|
||||
describe('usage window helpers', () => {
|
||||
let mockGetCachedBlockMetrics: {
|
||||
mock: { calls: unknown[][] };
|
||||
mockReturnValue: (value: BlockMetrics | null) => void;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.restoreAllMocks();
|
||||
mockGetCachedBlockMetrics = vi.spyOn(jsonl, 'getCachedBlockMetrics');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('parses usage reset timestamp into elapsed and remaining metrics', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
@@ -9,32 +10,30 @@ import {
|
||||
import type { RenderContext } from '../../types/RenderContext';
|
||||
import { DEFAULT_SETTINGS } from '../../types/Settings';
|
||||
import type { WidgetItem } from '../../types/Widget';
|
||||
import {
|
||||
formatUsageDuration,
|
||||
getUsageErrorMessage,
|
||||
resolveUsageWindowWithFallback
|
||||
} from '../../utils/usage';
|
||||
import * as usage from '../../utils/usage';
|
||||
import type { UsageWindowMetrics } from '../../utils/usage-types';
|
||||
import { BlockResetTimerWidget } from '../BlockResetTimer';
|
||||
|
||||
import { runUsageTimerEditorSuite } from './helpers/usage-widget-suites';
|
||||
|
||||
vi.mock('../../utils/usage', () => ({
|
||||
formatUsageDuration: vi.fn(),
|
||||
getUsageErrorMessage: vi.fn(),
|
||||
resolveUsageWindowWithFallback: vi.fn()
|
||||
}));
|
||||
|
||||
const mockFormatUsageDuration = formatUsageDuration as unknown as { mockReturnValue: (value: string) => void };
|
||||
const mockGetUsageErrorMessage = getUsageErrorMessage as unknown as { mockReturnValue: (value: string) => void };
|
||||
const mockResolveUsageWindowWithFallback = resolveUsageWindowWithFallback as unknown as { mockReturnValue: (value: unknown) => void };
|
||||
|
||||
function render(widget: BlockResetTimerWidget, item: WidgetItem, context: RenderContext = {}): string | null {
|
||||
return widget.render(item, context, DEFAULT_SETTINGS);
|
||||
}
|
||||
|
||||
describe('BlockResetTimerWidget', () => {
|
||||
let mockFormatUsageDuration: { mockReturnValue: (value: string) => void };
|
||||
let mockGetUsageErrorMessage: { mockReturnValue: (value: string) => void };
|
||||
let mockResolveUsageWindowWithFallback: { mockReturnValue: (value: UsageWindowMetrics | null) => void };
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.restoreAllMocks();
|
||||
mockFormatUsageDuration = vi.spyOn(usage, 'formatUsageDuration');
|
||||
mockGetUsageErrorMessage = vi.spyOn(usage, 'getUsageErrorMessage');
|
||||
mockResolveUsageWindowWithFallback = vi.spyOn(usage, 'resolveUsageWindowWithFallback');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders preview using block-style reset format', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
@@ -9,29 +10,28 @@ import {
|
||||
import type { RenderContext } from '../../types/RenderContext';
|
||||
import { DEFAULT_SETTINGS } from '../../types/Settings';
|
||||
import type { WidgetItem } from '../../types/Widget';
|
||||
import {
|
||||
formatUsageDuration,
|
||||
resolveUsageWindowWithFallback
|
||||
} from '../../utils/usage';
|
||||
import * as usage from '../../utils/usage';
|
||||
import type { UsageWindowMetrics } from '../../utils/usage-types';
|
||||
import { BlockTimerWidget } from '../BlockTimer';
|
||||
|
||||
import { runUsageTimerEditorSuite } from './helpers/usage-widget-suites';
|
||||
|
||||
vi.mock('../../utils/usage', () => ({
|
||||
formatUsageDuration: vi.fn(),
|
||||
resolveUsageWindowWithFallback: vi.fn()
|
||||
}));
|
||||
|
||||
const mockFormatUsageDuration = formatUsageDuration as unknown as { mockReturnValue: (value: string) => void };
|
||||
const mockResolveUsageWindowWithFallback = resolveUsageWindowWithFallback as unknown as { mockReturnValue: (value: unknown) => void };
|
||||
|
||||
function render(widget: BlockTimerWidget, item: WidgetItem, context: RenderContext = {}): string | null {
|
||||
return widget.render(item, context, DEFAULT_SETTINGS);
|
||||
}
|
||||
|
||||
describe('BlockTimerWidget', () => {
|
||||
let mockFormatUsageDuration: { mockReturnValue: (value: string) => void };
|
||||
let mockResolveUsageWindowWithFallback: { mockReturnValue: (value: UsageWindowMetrics | null) => void };
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.restoreAllMocks();
|
||||
mockFormatUsageDuration = vi.spyOn(usage, 'formatUsageDuration');
|
||||
mockResolveUsageWindowWithFallback = vi.spyOn(usage, 'resolveUsageWindowWithFallback');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders elapsed time in time mode', () => {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
@@ -7,11 +9,19 @@ import {
|
||||
|
||||
import type { RenderContext } from '../../types';
|
||||
import { DEFAULT_SETTINGS } from '../../types/Settings';
|
||||
import * as usage from '../../utils/usage';
|
||||
import { ContextBarWidget } from '../ContextBar';
|
||||
|
||||
vi.mock('../../utils/usage', () => ({ makeUsageProgressBar: vi.fn((percent: number, width = 15) => `[bar:${percent.toFixed(1)}:${width}]`) }));
|
||||
|
||||
describe('ContextBarWidget', () => {
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.spyOn(usage, 'makeUsageProgressBar').mockImplementation((percent: number, width = 15) => `[bar:${percent.toFixed(1)}:${width}]`);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders from context_window data when available', () => {
|
||||
const context: RenderContext = {
|
||||
data: {
|
||||
|
||||
@@ -13,24 +13,18 @@ import type { Settings } from '../../types/Settings';
|
||||
import type { WidgetItem } from '../../types/Widget';
|
||||
import { CurrentWorkingDirWidget } from '../CurrentWorkingDir';
|
||||
|
||||
vi.mock('node:os', () => ({ homedir: vi.fn() }));
|
||||
|
||||
const mockHomedir = os.homedir as unknown as {
|
||||
mockReset: () => void;
|
||||
mockReturnValue: (value: string) => void;
|
||||
};
|
||||
|
||||
describe('CurrentWorkingDirWidget', () => {
|
||||
const widget = new CurrentWorkingDirWidget();
|
||||
const defaultHomeDir = '/Users/alice';
|
||||
let mockHomedir: { mockReturnValue: (value: string) => void };
|
||||
|
||||
beforeEach(() => {
|
||||
mockHomedir.mockReset();
|
||||
mockHomedir.mockReturnValue(defaultHomeDir);
|
||||
vi.restoreAllMocks();
|
||||
mockHomedir = vi.spyOn(os, 'homedir').mockReturnValue(defaultHomeDir);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
const createContext = (cwd?: string, isPreview = false): RenderContext => ({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { execSync } from 'child_process';
|
||||
import * as childProcess from 'child_process';
|
||||
import os from 'os';
|
||||
import {
|
||||
afterEach,
|
||||
@@ -16,47 +16,22 @@ import type {
|
||||
import { DEFAULT_SETTINGS } from '../../types/Settings';
|
||||
import { FreeMemoryWidget } from '../FreeMemory';
|
||||
|
||||
vi.mock('child_process', () => ({ execSync: vi.fn() }));
|
||||
vi.mock('os', () => {
|
||||
const mockOs = {
|
||||
totalmem: vi.fn(),
|
||||
freemem: vi.fn(),
|
||||
platform: vi.fn()
|
||||
};
|
||||
|
||||
return {
|
||||
default: mockOs,
|
||||
...mockOs
|
||||
};
|
||||
});
|
||||
|
||||
const mockTotalmem = os.totalmem as unknown as {
|
||||
mockReturnValue: (value: number) => void;
|
||||
mockReset: () => void;
|
||||
};
|
||||
const mockFreemem = os.freemem as unknown as {
|
||||
mockReturnValue: (value: number) => void;
|
||||
mockReset: () => void;
|
||||
};
|
||||
const mockPlatform = os.platform as unknown as {
|
||||
mockReturnValue: (value: NodeJS.Platform) => void;
|
||||
mockReset: () => void;
|
||||
};
|
||||
const mockExecSync = execSync as unknown as {
|
||||
mockReturnValue: (value: string) => void;
|
||||
mockImplementation: (impl: () => never) => void;
|
||||
mockReset: () => void;
|
||||
};
|
||||
|
||||
describe('FreeMemoryWidget', () => {
|
||||
const widget = new FreeMemoryWidget();
|
||||
let mockTotalmem: { mockReturnValue: (value: number) => void };
|
||||
let mockFreemem: { mockReturnValue: (value: number) => void };
|
||||
let mockPlatform: { mockReturnValue: (value: NodeJS.Platform) => void };
|
||||
let mockExecSync: {
|
||||
mockImplementation: (fn: () => never) => void;
|
||||
mockReturnValue: (value: string) => void;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockTotalmem.mockReset();
|
||||
mockFreemem.mockReset();
|
||||
mockPlatform.mockReset();
|
||||
mockExecSync.mockReset();
|
||||
vi.restoreAllMocks();
|
||||
mockTotalmem = vi.spyOn(os, 'totalmem');
|
||||
mockFreemem = vi.spyOn(os, 'freemem');
|
||||
mockPlatform = vi.spyOn(os, 'platform');
|
||||
mockExecSync = vi.spyOn(childProcess, 'execSync');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import * as fs from 'fs';
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
@@ -15,12 +15,7 @@ import type {
|
||||
import { DEFAULT_SETTINGS } from '../../types/Settings';
|
||||
import { SessionNameWidget } from '../SessionName';
|
||||
|
||||
vi.mock('fs', () => ({ readFileSync: vi.fn() }));
|
||||
|
||||
const mockReadFileSync = readFileSync as unknown as {
|
||||
mockImplementation: (impl: () => string) => void;
|
||||
mockReset: () => void;
|
||||
};
|
||||
let mockReadFileSync: { mockImplementation: (fn: () => string | never) => void };
|
||||
|
||||
function render(transcriptPath: string | undefined, fileContent: string | null, rawValue = false, isPreview = false) {
|
||||
const widget = new SessionNameWidget();
|
||||
@@ -47,8 +42,8 @@ function render(transcriptPath: string | undefined, fileContent: string | null,
|
||||
|
||||
describe('SessionNameWidget', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockReadFileSync.mockReset();
|
||||
vi.restoreAllMocks();
|
||||
mockReadFileSync = vi.spyOn(fs, 'readFileSync');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
vi
|
||||
} from 'vitest';
|
||||
@@ -6,27 +8,37 @@ import {
|
||||
import type { RenderContext } from '../../types/RenderContext';
|
||||
import { DEFAULT_SETTINGS } from '../../types/Settings';
|
||||
import type { WidgetItem } from '../../types/Widget';
|
||||
import { getUsageErrorMessage } from '../../utils/usage';
|
||||
import * as usage from '../../utils/usage';
|
||||
import { SessionUsageWidget } from '../SessionUsage';
|
||||
|
||||
import { runUsagePercentWidgetSuite } from './helpers/usage-widget-suites';
|
||||
|
||||
vi.mock('../../utils/usage', () => ({
|
||||
getUsageErrorMessage: vi.fn(),
|
||||
makeUsageProgressBar: vi.fn((percent: number, width = 15) => `[bar:${percent.toFixed(1)}:${width}]`)
|
||||
}));
|
||||
|
||||
const mockGetUsageErrorMessage = getUsageErrorMessage as unknown as { mockReturnValue: (value: string) => void };
|
||||
let mockGetUsageErrorMessage: { mockReturnValue: (value: string) => void };
|
||||
const usageErrorMessageMock = {
|
||||
mockReturnValue(value: string): void {
|
||||
mockGetUsageErrorMessage.mockReturnValue(value);
|
||||
}
|
||||
};
|
||||
|
||||
function render(widget: SessionUsageWidget, item: WidgetItem, context: RenderContext = {}): string | null {
|
||||
return widget.render(item, context, DEFAULT_SETTINGS);
|
||||
}
|
||||
|
||||
describe('SessionUsageWidget', () => {
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
mockGetUsageErrorMessage = vi.spyOn(usage, 'getUsageErrorMessage');
|
||||
vi.spyOn(usage, 'makeUsageProgressBar').mockImplementation((percent: number, width = 15) => `[bar:${percent.toFixed(1)}:${width}]`);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
runUsagePercentWidgetSuite({
|
||||
baseItem: { id: 'session', type: 'session-usage' },
|
||||
createWidget: () => new SessionUsageWidget(),
|
||||
errorMessageMock: mockGetUsageErrorMessage,
|
||||
errorMessageMock: usageErrorMessageMock,
|
||||
expectedModifierText: '(short bar, inverted)',
|
||||
expectedProgress: 'Session: [bar:76.5:16] 76.5%',
|
||||
expectedRawProgress: '[bar:23.4:32] 23.4%',
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
@@ -7,8 +9,7 @@ import {
|
||||
|
||||
import type { RenderContext } from '../../types';
|
||||
import { DEFAULT_SETTINGS } from '../../types/Settings';
|
||||
|
||||
vi.mock('../../utils/renderer', () => ({ formatTokens: vi.fn((value: number) => `fmt:${value}`) }));
|
||||
import * as renderer from '../../utils/renderer';
|
||||
|
||||
async function loadWidgets() {
|
||||
const [{ TokensInputWidget }, { TokensOutputWidget }, { TokensCachedWidget }, { TokensTotalWidget }] = await Promise.all([
|
||||
@@ -27,6 +28,15 @@ async function loadWidgets() {
|
||||
}
|
||||
|
||||
describe('Token widgets', () => {
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.spyOn(renderer, 'formatTokens').mockImplementation((value: number) => `fmt:${value}`);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('use context_window values for input/output and tokenMetrics totals for cached/total', async () => {
|
||||
const { TokensCachedWidget, TokensInputWidget, TokensOutputWidget, TokensTotalWidget } = await loadWidgets();
|
||||
const context: RenderContext = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
@@ -9,32 +10,30 @@ import {
|
||||
import type { RenderContext } from '../../types/RenderContext';
|
||||
import { DEFAULT_SETTINGS } from '../../types/Settings';
|
||||
import type { WidgetItem } from '../../types/Widget';
|
||||
import {
|
||||
formatUsageDuration,
|
||||
getUsageErrorMessage,
|
||||
resolveWeeklyUsageWindow
|
||||
} from '../../utils/usage';
|
||||
import * as usage from '../../utils/usage';
|
||||
import type { UsageWindowMetrics } from '../../utils/usage-types';
|
||||
import { WeeklyResetTimerWidget } from '../WeeklyResetTimer';
|
||||
|
||||
import { runUsageTimerEditorSuite } from './helpers/usage-widget-suites';
|
||||
|
||||
vi.mock('../../utils/usage', () => ({
|
||||
formatUsageDuration: vi.fn(),
|
||||
getUsageErrorMessage: vi.fn(),
|
||||
resolveWeeklyUsageWindow: vi.fn()
|
||||
}));
|
||||
|
||||
const mockFormatUsageDuration = formatUsageDuration as unknown as { mockReturnValue: (value: string) => void };
|
||||
const mockGetUsageErrorMessage = getUsageErrorMessage as unknown as { mockReturnValue: (value: string) => void };
|
||||
const mockResolveWeeklyUsageWindow = resolveWeeklyUsageWindow as unknown as { mockReturnValue: (value: unknown) => void };
|
||||
|
||||
function render(widget: WeeklyResetTimerWidget, item: WidgetItem, context: RenderContext = {}): string | null {
|
||||
return widget.render(item, context, DEFAULT_SETTINGS);
|
||||
}
|
||||
|
||||
describe('WeeklyResetTimerWidget', () => {
|
||||
let mockFormatUsageDuration: { mockReturnValue: (value: string) => void };
|
||||
let mockGetUsageErrorMessage: { mockReturnValue: (value: string) => void };
|
||||
let mockResolveWeeklyUsageWindow: { mockReturnValue: (value: UsageWindowMetrics | null) => void };
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.restoreAllMocks();
|
||||
mockFormatUsageDuration = vi.spyOn(usage, 'formatUsageDuration');
|
||||
mockGetUsageErrorMessage = vi.spyOn(usage, 'getUsageErrorMessage');
|
||||
mockResolveWeeklyUsageWindow = vi.spyOn(usage, 'resolveWeeklyUsageWindow');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders preview using weekly reset format', () => {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
vi
|
||||
} from 'vitest';
|
||||
@@ -6,27 +8,37 @@ import {
|
||||
import type { RenderContext } from '../../types/RenderContext';
|
||||
import { DEFAULT_SETTINGS } from '../../types/Settings';
|
||||
import type { WidgetItem } from '../../types/Widget';
|
||||
import { getUsageErrorMessage } from '../../utils/usage';
|
||||
import * as usage from '../../utils/usage';
|
||||
import { WeeklyUsageWidget } from '../WeeklyUsage';
|
||||
|
||||
import { runUsagePercentWidgetSuite } from './helpers/usage-widget-suites';
|
||||
|
||||
vi.mock('../../utils/usage', () => ({
|
||||
getUsageErrorMessage: vi.fn(),
|
||||
makeUsageProgressBar: vi.fn((percent: number, width = 15) => `[bar:${percent.toFixed(1)}:${width}]`)
|
||||
}));
|
||||
|
||||
const mockGetUsageErrorMessage = getUsageErrorMessage as unknown as { mockReturnValue: (value: string) => void };
|
||||
let mockGetUsageErrorMessage: { mockReturnValue: (value: string) => void };
|
||||
const usageErrorMessageMock = {
|
||||
mockReturnValue(value: string): void {
|
||||
mockGetUsageErrorMessage.mockReturnValue(value);
|
||||
}
|
||||
};
|
||||
|
||||
function render(widget: WeeklyUsageWidget, item: WidgetItem, context: RenderContext = {}): string | null {
|
||||
return widget.render(item, context, DEFAULT_SETTINGS);
|
||||
}
|
||||
|
||||
describe('WeeklyUsageWidget', () => {
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
mockGetUsageErrorMessage = vi.spyOn(usage, 'getUsageErrorMessage');
|
||||
vi.spyOn(usage, 'makeUsageProgressBar').mockImplementation((percent: number, width = 15) => `[bar:${percent.toFixed(1)}:${width}]`);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
runUsagePercentWidgetSuite({
|
||||
baseItem: { id: 'weekly', type: 'weekly-usage' },
|
||||
createWidget: () => new WeeklyUsageWidget(),
|
||||
errorMessageMock: mockGetUsageErrorMessage,
|
||||
errorMessageMock: usageErrorMessageMock,
|
||||
expectedModifierText: '(progress bar, inverted)',
|
||||
expectedProgress: 'Weekly: [bar:57.9:32] 57.9%',
|
||||
expectedRawProgress: '[bar:42.1:16] 42.1%',
|
||||
|
||||
Reference in new issue
Block a user