From cf06399c67bf8f4d717cc7ddeb574fef3e833067 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 29 Jun 2026 16:20:18 +0000 Subject: [PATCH] Fix coverage status card: use shields.io non-redirecting badge URL shields.io deprecated the /coveralls/ badge path. It now 301-redirects to a /coverallsCoverage/ URL whose response lacks CORS headers, so on dashban.com the browser blocked status-cards.js from reading the SVG body cross-origin and the coverage card fell back to "unknown". Point buildBadgeUrl('coverage') at the current /coverallsCoverage/ endpoint, which serves the badge directly with access-control-allow-origin: *, and join the cache-buster with & since that URL already carries ?branch=main. Full suite green at 100% coverage; lint clean. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_019VQjXJyM3EZPd4joy3EwaB --- src/status-cards.js | 10 ++++++++-- tests/status-cards.test.js | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/status-cards.js b/src/status-cards.js index 13bb3e1..3bf4b5c 100644 --- a/src/status-cards.js +++ b/src/status-cards.js @@ -118,7 +118,11 @@ document.addEventListener('DOMContentLoaded', function() { if (type === 'workflow') { return `https://img.shields.io/github/actions/workflow/status/${OWNER}/${REPO}/${workflowFile}`; } else if (type === 'coverage') { - return `https://img.shields.io/coveralls/github/${OWNER}/${REPO}/main.svg`; + // shields.io deprecated the /coveralls/ path — it now 301-redirects + // to a URL that fails CORS, which breaks reading the SVG body from + // the browser. The current /coverallsCoverage/ endpoint serves the + // badge directly with CORS headers. + return `https://img.shields.io/coverallsCoverage/github/${OWNER}/${REPO}?branch=main`; } throw new Error(`Unknown badge type: ${type}`); } @@ -214,7 +218,9 @@ document.addEventListener('DOMContentLoaded', function() { async function fetchCoverageStatus() { try { - const badgeUrl = `${buildBadgeUrl('coverage')}?t=${Date.now()}`; + // The coverage badge URL already carries a query (?branch=main), so + // join the cache-buster with & rather than ?. + const badgeUrl = `${buildBadgeUrl('coverage')}&t=${Date.now()}`; const svgText = await fetch(badgeUrl).then(r => r.text()); const coverage = parseCoverageFromSVG(svgText); diff --git a/tests/status-cards.test.js b/tests/status-cards.test.js index e27cc58..7778198 100644 --- a/tests/status-cards.test.js +++ b/tests/status-cards.test.js @@ -303,7 +303,7 @@ describe('Status Cards Functions', () => { test('should build coverage badge URL correctly', () => { const result = statusAPI.buildBadgeUrl('coverage'); - expect(result).toBe('https://img.shields.io/coveralls/github/super3/dashban/main.svg'); + expect(result).toBe('https://img.shields.io/coverallsCoverage/github/super3/dashban?branch=main'); }); test('should throw error for unknown badge type', () => { @@ -960,7 +960,7 @@ describe('Status Cards Functions', () => { // With no GitHubAuth setup, it uses default config expect(fetch).toHaveBeenCalledWith( - expect.stringContaining('https://img.shields.io/coveralls/github/super3/dashban/main.svg?t=') + expect.stringContaining('https://img.shields.io/coverallsCoverage/github/super3/dashban?branch=main&t=') ); });