From 0e06972b501ce4647eb3e83fabdef27a6e90723e Mon Sep 17 00:00:00 2001 From: jonmartin721 Date: Sun, 8 Mar 2026 19:53:47 -0500 Subject: [PATCH 1/3] Harden tests and coverage checks --- package.json | 3 +- tests/background.test.js | 7 ++ tests/export-import-controller.test.js | 6 ++ tests/options-main.test.js | 6 ++ tests/options-token-controller.test.js | 5 +- tests/options.test.js | 5 ++ tests/phase1.test.js | 10 +++ tests/setup.js | 103 ++++++++++++++++++++++--- tests/state-manager.test.js | 5 ++ 9 files changed, 137 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 5207d48..6ae6a50 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,12 @@ "type": "module", "scripts": { "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", + "test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage", "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch", "lint": "eslint .", "typecheck": "tsc --noEmit -p jsconfig.json", "build": "node scripts/build.js", - "validate": "npm run lint && npm run typecheck && npm test && npm run build", + "validate": "npm run lint && npm run typecheck && npm run test:coverage && npm run build", "format": "prettier --write \"**/*.{js,json,md}\"", "prepare": "husky" }, diff --git a/tests/background.test.js b/tests/background.test.js index b3e4e30..afda3db 100644 --- a/tests/background.test.js +++ b/tests/background.test.js @@ -18,6 +18,13 @@ import { describe('Background Service Worker', () => { beforeEach(() => { jest.clearAllMocks(); + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); + }); + + afterEach(() => { + console.error.mockRestore(); + console.warn.mockRestore(); }); describe.skip('fetchRepoActivity', () => { diff --git a/tests/export-import-controller.test.js b/tests/export-import-controller.test.js index 21b701f..b8d8893 100644 --- a/tests/export-import-controller.test.js +++ b/tests/export-import-controller.test.js @@ -24,6 +24,8 @@ window.location = { reload: mockReload }; describe('export-import-controller', () => { beforeEach(() => { + jest.spyOn(console, 'error').mockImplementation(() => {}); + // Clear mocks individually instead of using jest.clearAllMocks() mockReload.mockClear(); mockNotifications.success.mockClear(); @@ -57,6 +59,10 @@ describe('export-import-controller', () => { document.body.innerHTML = ''; }); + afterEach(() => { + console.error.mockRestore(); + }); + describe('exportSettings', () => { test('exports all settings with default values', async () => { chrome.storage.sync.get.mockResolvedValueOnce({}); diff --git a/tests/options-main.test.js b/tests/options-main.test.js index 31efee7..5e8ee72 100644 --- a/tests/options-main.test.js +++ b/tests/options-main.test.js @@ -9,6 +9,8 @@ const { describe('Options Main Functions', () => { beforeEach(() => { + jest.spyOn(console, 'error').mockImplementation(() => {}); + // Setup complete DOM structure for options page document.body.innerHTML = ` @@ -69,6 +71,10 @@ describe('Options Main Functions', () => { global.fetch = jest.fn(); }); + afterEach(() => { + console.error.mockRestore(); + }); + describe('formatNumber', () => { test('formats numbers under 1000 as-is', () => { expect(formatNumber(0)).toBe('0'); diff --git a/tests/options-token-controller.test.js b/tests/options-token-controller.test.js index 677fa61..d358cdc 100644 --- a/tests/options-token-controller.test.js +++ b/tests/options-token-controller.test.js @@ -17,6 +17,9 @@ describe('Token Controller', () => { // Chrome mocks are provided by setup.js global.confirm = jest.fn(() => true); global.fetch = jest.fn(); + chrome.storage.local.set.mockImplementation((items, callback) => { + if (callback) callback(); + }); }); test('clearToken does nothing when cancelled', async () => { @@ -53,7 +56,7 @@ describe('Token Controller', () => { expect(statusEl.textContent).toContain('Invalid'); }); - test.skip('clearToken clears all fields when confirmed', async () => { + test('clearToken clears all fields when confirmed', async () => { global.confirm.mockReturnValue(true); const tokenInput = document.getElementById('githubToken'); diff --git a/tests/options.test.js b/tests/options.test.js index bd2f2f0..6e0fd40 100644 --- a/tests/options.test.js +++ b/tests/options.test.js @@ -67,6 +67,11 @@ const { describe('Options Page - Repository Management', () => { beforeEach(() => { jest.clearAllMocks(); + jest.spyOn(console, 'error').mockImplementation(() => {}); + }); + + afterEach(() => { + console.error.mockRestore(); }); describe('fetchGitHubRepoFromNpm', () => { diff --git a/tests/phase1.test.js b/tests/phase1.test.js index ec5f07a..a2403de 100644 --- a/tests/phase1.test.js +++ b/tests/phase1.test.js @@ -67,6 +67,7 @@ import { applyTheme } from '../shared/utils.js'; describe('Dark Mode', () => { beforeEach(() => { + jest.spyOn(console, 'error').mockImplementation(() => {}); document.body.className = ''; document.body.innerHTML = `