From f91b400c439624c97c607115512228dc1c275ffb Mon Sep 17 00:00:00 2001 From: martin-mfg <2026226+martin-mfg@users.noreply.github.com> Date: Sun, 18 May 2025 21:53:13 +0200 Subject: [PATCH] add repo filter --- api/index.js | 62 +++++++++++++++---------- readme.md | 16 ++++++- src/cards/stats-card.js | 86 ++++++++++++++++++++++++++++++----- src/common/icons.js | 1 + src/common/retryer.js | 4 +- src/fetchers/stats-fetcher.js | 73 ++++++++++++++++++++++++++--- src/fetchers/types.d.ts | 5 ++ src/translations.js | 15 ++++++ tests/api.test.js | 9 +++- tests/fetchStats.test.js | 59 ++++++++++++++++++++++-- tests/renderStatsCard.test.js | 16 ++----- 11 files changed, 284 insertions(+), 62 deletions(-) diff --git a/api/index.js b/api/index.js index c42bc048..123a03d6 100644 --- a/api/index.js +++ b/api/index.js @@ -13,6 +13,7 @@ import { isLocaleAvailable } from "../src/translations.js"; export default async (req, res) => { const { username, + repo, hide, hide_title, hide_border, @@ -75,6 +76,12 @@ export default async (req, res) => { showStats.includes("prs_merged_percentage"), showStats.includes("discussions_started"), showStats.includes("discussions_answered"), + repo, + showStats.includes("prs_authored"), + showStats.includes("prs_commented"), + showStats.includes("prs_reviewed"), + showStats.includes("issues_authored"), + showStats.includes("issues_commented"), ); let cacheSeconds = clampValue( @@ -92,31 +99,36 @@ export default async (req, res) => { ); return res.send( - renderStatsCard(stats, { - hide: parseArray(hide), - show_icons: parseBoolean(show_icons), - hide_title: parseBoolean(hide_title), - hide_border: parseBoolean(hide_border), - card_width: parseInt(card_width, 10), - hide_rank: parseBoolean(hide_rank), - include_all_commits: parseBoolean(include_all_commits), - line_height, - title_color, - ring_color, - icon_color, - text_color, - text_bold: parseBoolean(text_bold), - bg_color, - theme, - custom_title, - border_radius, - border_color, - number_format, - locale: locale ? locale.toLowerCase() : null, - disable_animations: parseBoolean(disable_animations), - rank_icon, - show: showStats, - }), + renderStatsCard( + stats, + { + hide: parseArray(hide), + show_icons: parseBoolean(show_icons), + hide_title: parseBoolean(hide_title), + hide_border: parseBoolean(hide_border), + card_width: parseInt(card_width, 10), + hide_rank: parseBoolean(hide_rank), + include_all_commits: parseBoolean(include_all_commits), + line_height, + title_color, + ring_color, + icon_color, + text_color, + text_bold: parseBoolean(text_bold), + bg_color, + theme, + custom_title, + border_radius, + border_color, + number_format, + locale: locale ? locale.toLowerCase() : null, + disable_animations: parseBoolean(disable_animations), + rank_icon, + show: showStats, + }, + username, + repo, + ), ); } catch (err) { res.setHeader( diff --git a/readme.md b/readme.md index 363b008b..7363686f 100644 --- a/readme.md +++ b/readme.md @@ -89,6 +89,7 @@ Please visit [this link](https://give.do/fundraisers/stand-beside-the-victims-of - [Hiding individual stats](#hiding-individual-stats) - [Showing additional individual stats](#showing-additional-individual-stats) - [Showing icons](#showing-icons) + - [Filtering by repository](#filtering-by-repository) - [Themes](#themes) - [Customization](#customization) - [GitHub Extra Pins](#github-extra-pins) @@ -175,6 +176,14 @@ To enable icons, you can pass `&show_icons=true` in the query param, like so: ![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true) ``` +### Filtering by repository + +To exclude specific repositories, you can use the [`&exclude_repo` parameter](#stats-card-exclusive-options). + +To compute your stats for only one specific repository, you can pass a query parameter `&repo=/`. This filter is supported by the following items: `prs_authored`, `prs_commented`, `prs_reviewed`, `issues_authored` and `issues_commented`. Note that these items are not displayed by default, but [you can enable them individually](#showing-additional-individual-stats). + +(Some of these mentioned items are similar to other items which are included by default, e.g. `issues_authored` is similar to `issues`. The difference is how these values are retrieved - [via GraphQL or via REST API](https://github.com/anuraghazra/github-readme-stats/discussions/1770#number-of-commits-is-incorrect). The default items use GraphQL, but filtering by repository works better via REST API.) + ### Themes With inbuilt themes, you can customize the look of the card without doing any [manual customization](#customization). @@ -377,12 +386,13 @@ If we don't support your language, please consider contributing! You can find mo | `include_all_commits` | Count total commits instead of just the current year commits. | boolean | `false` | | `line_height` | Sets the line height between text. | integer | `25` | | `exclude_repo` | Excludes specified repositories. | string (comma-separated values) | `null` | +| `repo` | Count only stats from the specified repository. Affects only the items `prs_authored`, `prs_commented`, `prs_reviewed`, `issues_authored` and `issues_commented`. | string | `null` | | `custom_title` | Sets a custom title for the card. | string | ` GitHub Stats` | | `text_bold` | Uses bold text. | boolean | `true` | | `disable_animations` | Disables all animations in the card. | boolean | `false` | | `ring_color` | Color of the rank circle. | string (hex color) | `2f80ed` | | `number_format` | Switches between two available formats for displaying the card values `short` (i.e. `6.6k`) and `long` (i.e. `6626`). | enum | `short` | -| `show` | Shows [additional items](#showing-additional-individual-stats) on stats card (i.e. `reviews`, `discussions_started`, `discussions_answered`, `prs_merged` or `prs_merged_percentage`). | string (comma-separated values) | `null` | +| `show` | Shows [additional items](#showing-additional-individual-stats) on stats card (i.e. `reviews`, `discussions_started`, `discussions_answered`, `prs_merged` or `prs_merged_percentage`. And/Or the following, which support the `repo` filter: `prs_authored`, `prs_commented`, `prs_reviewed`, `issues_authored` or `issues_commented`). | string (comma-separated values) | `null` | > [!NOTE]\ > When hide\_rank=`true`, the minimum card width is 270 px + the title length and padding. @@ -653,6 +663,10 @@ Change the `?username=` value to your [WakaTime](https://wakatime.com) username. ![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra\&show_icons=true\&show=reviews,discussions_started,discussions_answered,prs_merged,prs_merged_percentage) +* Showing stats for a specific repository + +![Anurag's GitHub stats for anuraghazra/github-readme-stats](https://github-readme-stats.vercel.app/api?username=anuraghazra\&repo=anuraghazra/github-readme-stats\&hide=prs,issues,stars,commits,contribs\&show=prs_authored,prs_commented,prs_reviewed,issues_authored,issues_commented\&hide_rank=true\&custom_title=Anurag%27s%20Stats%20for%20github-readme-stats\&card_width=370) + * Showing icons ![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra\&hide=issues\&show_icons=true) diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js index 5b7f0d26..a9b4ca7b 100644 --- a/src/cards/stats-card.js +++ b/src/cards/stats-card.js @@ -33,6 +33,7 @@ const RANK_ONLY_CARD_DEFAULT_WIDTH = 290; * @param {number} createTextNodeParams.shiftValuePos Number of pixels the value has to be shifted to the right. * @param {boolean} createTextNodeParams.bold Whether to bold the label. * @param {string} createTextNodeParams.number_format The format of numbers on card. + * @param {string} createTextNodeParams.link Url to link to. * @returns {string} The stats card text item SVG object. */ const createTextNode = ({ @@ -46,6 +47,7 @@ const createTextNode = ({ shiftValuePos, bold, number_format, + link, }) => { const kValue = number_format.toLowerCase() === "long" ? value : kFormatter(value); @@ -59,8 +61,11 @@ const createTextNode = ({ ` : ""; - return ` - + return ( + ` + ` + + (link ? `` : "") + + ` ${iconSvg} ${kValue}${unitSymbol ? ` ${unitSymbol}` : ""} + >${kValue}${unitSymbol ? ` ${unitSymbol}` : ""}` + + (link ? "" : "") + + ` - `; + ` + ); }; /** @@ -199,7 +207,7 @@ const getStyles = ({ * @param {Partial} options The card options. * @returns {string} The stats card SVG object. */ -const renderStatsCard = (stats, options = {}) => { +const renderStatsCard = (stats, options = {}, username, repo) => { const { name, totalStars, @@ -212,6 +220,11 @@ const renderStatsCard = (stats, options = {}) => { totalDiscussionsStarted, totalDiscussionsAnswered, contributedTo, + totalPRsAuthored, + totalPRsCommented, + totalPRsReviewed, + totalIssuesAuthored, + totalIssuesCommented, rank, } = stats; const { @@ -338,6 +351,53 @@ const renderStatsCard = (stats, options = {}) => { }; } + let repoFilter = repo ? "repo%3A" + encodeURIComponent(repo) + "+" : ""; + if (show.includes("prs_authored")) { + STATS.prs_authored = { + icon: icons.prs, + label: i18n.t("statcard.prs-authored"), + value: totalPRsAuthored, + id: "prs_authored", + link: `https://github.com/search?q=${repoFilter}author%3A${username}&type=pullrequests`, + }; + } + if (show.includes("prs_commented")) { + STATS.prs_commented = { + icon: icons.comments, + label: i18n.t("statcard.prs-commented"), + value: totalPRsCommented, + id: "prs_commented", + link: `https://github.com/search?q=${repoFilter}commenter%3A${username}+-author%3A${username}&type=pullrequests`, + }; + } + if (show.includes("prs_reviewed")) { + STATS.prs_reviewed = { + icon: icons.reviews, + label: i18n.t("statcard.prs-reviewed"), + value: totalPRsReviewed, + id: "prs_reviewed", + link: `https://github.com/search?q=${repoFilter}reviewed-by%3A${username}+-author%3A${username}&type=pullrequests`, + }; + } + if (show.includes("issues_authored")) { + STATS.issues_authored = { + icon: icons.issues, + label: i18n.t("statcard.issues-authored"), + value: totalIssuesAuthored, + id: "issues_authored", + link: `https://github.com/search?q=${repoFilter}author%3A${username}&type=issues`, + }; + } + if (show.includes("issues_commented")) { + STATS.issues_commented = { + icon: icons.discussions_started, + label: i18n.t("statcard.issues-commented"), + value: totalIssuesCommented, + id: "issues_commented", + link: `https://github.com/search?q=${repoFilter}commenter%3A${username}+-author%3A${username}&type=issues`, + }; + } + STATS.contribs = { icon: icons.contribs, label: i18n.t("statcard.contribs"), @@ -363,6 +423,12 @@ const renderStatsCard = (stats, options = {}) => { ]; const isLongLocale = locale ? longLocales.includes(locale) : false; + // check if all used labels are short + const longLabels = + Object.keys(STATS) + .filter((key) => !hide.includes(key)) + .filter((key) => STATS[key].label.length > 18).length > 0; + // filter out hidden stats defined by user & create the text nodes const statItems = Object.keys(STATS) .filter((key) => !hide.includes(key)) @@ -376,9 +442,10 @@ const renderStatsCard = (stats, options = {}) => { unitSymbol: STATS[key].unitSymbol, index, showIcons: show_icons, - shiftValuePos: 79.01 + (isLongLocale ? 50 : 0), + shiftValuePos: 29.01 + (longLabels ? 50 : 0) + (isLongLocale ? 50 : 0), bold: text_bold, number_format, + link: STATS[key].link, }), ); @@ -441,12 +508,9 @@ const renderStatsCard = (stats, options = {}) => { : RANK_ONLY_CARD_DEFAULT_WIDTH) + iconWidth; let width = card_width ? isNaN(card_width) - ? defaultCardWidth + ? Math.max(defaultCardWidth, minCardWidth) : card_width - : defaultCardWidth; - if (width < minCardWidth) { - width = minCardWidth; - } + : Math.max(defaultCardWidth, minCardWidth); const card = new Card({ customTitle: custom_title, diff --git a/src/common/icons.js b/src/common/icons.js index 771704a3..b08f3fbb 100644 --- a/src/common/icons.js +++ b/src/common/icons.js @@ -11,6 +11,7 @@ const icons = { reviews: ``, discussions_started: ``, discussions_answered: ``, + comments: ``, gist: ``, }; diff --git a/src/common/retryer.js b/src/common/retryer.js index 3f294d37..bbef173f 100644 --- a/src/common/retryer.js +++ b/src/common/retryer.js @@ -45,7 +45,7 @@ const retryer = async (fetcher, variables, retries = 0) => { // if rate limit is hit increase the RETRIES and recursively call the retryer // with username, and current RETRIES if (isRateExceeded) { - logger.log(`PAT_${retries + 1} Failed`); + logger.log(`PAT_${retries + 1} Failed due to rate limiting`); retries++; // directly return from the function return retryer(fetcher, variables, retries); @@ -62,7 +62,7 @@ const retryer = async (fetcher, variables, retries = 0) => { err.response.data.message === "Sorry. Your account was suspended."; if (isBadCredential || isAccountSuspended) { - logger.log(`PAT_${retries + 1} Failed`); + logger.log(`PAT_${retries + 1} Failed due to bad credentials`); retries++; // directly return from the function return retryer(fetcher, variables, retries); diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index 115cd50a..62cae1ce 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -167,17 +167,22 @@ const statsFetcher = async ({ * @description Done like this because the GitHub API does not provide a way to fetch all the commits. See * #92#issuecomment-661026467 and #211 for more information. */ -const totalCommitsFetcher = async (username) => { +const totalItemsFetcher = async (username, repo, type, filter) => { if (!githubUsernameRegex.test(username)) { logger.log("Invalid username provided."); throw new Error("Invalid username provided."); } // https://developer.github.com/v3/search/#search-commits - const fetchTotalCommits = (variables, token) => { + const fetchTotalItems = (variables, token) => { return axios({ method: "get", - url: `https://api.github.com/search/commits?q=author:${variables.login}`, + url: + `https://api.github.com/search/` + + type + + `?per_page=1&q=` + + filter + + (variables.repo ? `+repo:${variables.repo}` : ``), headers: { "Content-Type": "application/json", Accept: "application/vnd.github.cloak-preview", @@ -188,7 +193,7 @@ const totalCommitsFetcher = async (username) => { let res; try { - res = await retryer(fetchTotalCommits, { login: username }); + res = await retryer(fetchTotalItems, { login: username, repo }); } catch (err) { logger.log(err); throw new Error(err); @@ -197,7 +202,7 @@ const totalCommitsFetcher = async (username) => { const totalCount = res.data.total_count; if (!totalCount || isNaN(totalCount)) { throw new CustomError( - "Could not fetch total commits.", + "Could not fetch data from GitHub REST API.", CustomError.GITHUB_REST_API_ERROR, ); } @@ -226,6 +231,12 @@ const fetchStats = async ( include_merged_pull_requests = false, include_discussions = false, include_discussions_answers = false, + repo = null, + include_prs_authored = false, + include_prs_commented = false, + include_prs_reviewed = false, + include_issues_authored = false, + include_issues_commented = false, ) => { if (!username) { throw new MissingParamError(["username"]); @@ -243,6 +254,11 @@ const fetchStats = async ( totalDiscussionsStarted: 0, totalDiscussionsAnswered: 0, contributedTo: 0, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank: { level: "C", percentile: 100 }, }; @@ -280,10 +296,55 @@ const fetchStats = async ( // if include_all_commits, fetch all commits using the REST API. if (include_all_commits) { - stats.totalCommits = await totalCommitsFetcher(username); + stats.totalCommits = await totalItemsFetcher( + username, + repo, + "commits", + `author:${username}`, + ); } else { stats.totalCommits = user.contributionsCollection.totalCommitContributions; } + if (include_prs_authored) { + stats.totalPRsAuthored = await totalItemsFetcher( + username, + repo, + "issues", + `author:${username}+type:pr`, + ); + } + if (include_prs_commented) { + stats.totalPRsCommented = await totalItemsFetcher( + username, + repo, + "issues", + `commenter:${username}+-author:${username}+type:pr`, + ); + } + if (include_prs_reviewed) { + stats.totalPRsReviewed = await totalItemsFetcher( + username, + repo, + "issues", + `reviewed-by:${username}+-author:${username}+type:pr`, + ); + } + if (include_issues_authored) { + stats.totalIssuesAuthored = await totalItemsFetcher( + username, + repo, + "issues", + `author:${username}+type:issue`, + ); + } + if (include_issues_commented) { + stats.totalIssuesCommented = await totalItemsFetcher( + username, + repo, + "issues", + `commenter:${username}+-author:${username}+type:issue`, + ); + } stats.totalPRs = user.pullRequests.totalCount; if (include_merged_pull_requests) { diff --git a/src/fetchers/types.d.ts b/src/fetchers/types.d.ts index affb407b..942e3af3 100644 --- a/src/fetchers/types.d.ts +++ b/src/fetchers/types.d.ts @@ -36,6 +36,11 @@ export type StatsData = { totalDiscussionsStarted: number; totalDiscussionsAnswered: number; contributedTo: number; + totalPRsAuthored: number; + totalPRsCommented: number; + totalPRsReviewed: number; + totalIssuesAuthored: number; + totalIssuesCommented: number; rank: { level: string; percentile: number }; }; diff --git a/src/translations.js b/src/translations.js index aa8744d7..4baab403 100644 --- a/src/translations.js +++ b/src/translations.js @@ -325,6 +325,21 @@ const statCardLocales = ({ name, apostrophe }) => { vi: "Tổng Số Thảo Luận Đã Trả Lời", se: "Totalt antal diskussioner besvarade", }, + "statcard.prs-authored": { + en: "PRs Created", + }, + "statcard.prs-commented": { + en: "PRs Commented", + }, + "statcard.prs-reviewed": { + en: "PRs Reviewed", + }, + "statcard.issues-authored": { + en: "Issues Created", + }, + "statcard.issues-commented": { + en: "Issues Commented", + }, "statcard.prs-merged": { ar: "مجموع الطلبات المدمجة", cn: "合并的 PR 总数", diff --git a/tests/api.test.js b/tests/api.test.js index c155220c..48dc0846 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -242,7 +242,9 @@ describe("Test /api/", () => { it("should render error card when include_all_commits true and upstream API fails", async () => { mock - .onGet("https://api.github.com/search/commits?q=author:anuraghazra") + .onGet( + "https://api.github.com/search/commits?per_page=1&q=author:anuraghazra", + ) .reply(200, { error: "Some test error message" }); const { req, res } = faker( @@ -254,7 +256,10 @@ describe("Test /api/", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError("Could not fetch total commits.", "Please try again later"), + renderError( + "Could not fetch data from GitHub REST API.", + "Please try again later", + ), ); // Received SVG output should not contain string "https://tiny.one/readme-stats" expect(res.send.mock.calls[0][0]).not.toContain( diff --git a/tests/fetchStats.test.js b/tests/fetchStats.test.js index ca8d7bc3..4908d11e 100644 --- a/tests/fetchStats.test.js +++ b/tests/fetchStats.test.js @@ -128,6 +128,11 @@ describe("Test fetchStats", () => { totalStars: 300, totalDiscussionsStarted: 0, totalDiscussionsAnswered: 0, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank, }); }); @@ -164,6 +169,11 @@ describe("Test fetchStats", () => { totalStars: 300, totalDiscussionsStarted: 0, totalDiscussionsAnswered: 0, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank, }); }); @@ -179,7 +189,9 @@ describe("Test fetchStats", () => { it("should fetch total commits", async () => { mock - .onGet("https://api.github.com/search/commits?q=author:anuraghazra") + .onGet( + "https://api.github.com/search/commits?per_page=1&q=author:anuraghazra", + ) .reply(200, { total_count: 1000 }); let stats = await fetchStats("anuraghazra", true); @@ -206,6 +218,11 @@ describe("Test fetchStats", () => { totalStars: 300, totalDiscussionsStarted: 0, totalDiscussionsAnswered: 0, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank, }); }); @@ -218,17 +235,21 @@ describe("Test fetchStats", () => { it("should throw specific error when include_all_commits true and API returns error", async () => { mock - .onGet("https://api.github.com/search/commits?q=author:anuraghazra") + .onGet( + "https://api.github.com/search/commits?per_page=1&q=author:anuraghazra", + ) .reply(200, { error: "Some test error message" }); expect(fetchStats("anuraghazra", true)).rejects.toThrow( - new Error("Could not fetch total commits."), + new Error("Could not fetch data from GitHub REST API."), ); }); it("should exclude stars of the `test-repo-1` repository", async () => { mock - .onGet("https://api.github.com/search/commits?q=author:anuraghazra") + .onGet( + "https://api.github.com/search/commits?per_page=1&q=author:anuraghazra", + ) .reply(200, { total_count: 1000 }); let stats = await fetchStats("anuraghazra", true, ["test-repo-1"]); @@ -255,6 +276,11 @@ describe("Test fetchStats", () => { totalStars: 200, totalDiscussionsStarted: 0, totalDiscussionsAnswered: 0, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank, }); }); @@ -286,6 +312,11 @@ describe("Test fetchStats", () => { totalStars: 400, totalDiscussionsStarted: 0, totalDiscussionsAnswered: 0, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank, }); }); @@ -317,6 +348,11 @@ describe("Test fetchStats", () => { totalStars: 300, totalDiscussionsStarted: 0, totalDiscussionsAnswered: 0, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank, }); }); @@ -348,6 +384,11 @@ describe("Test fetchStats", () => { totalStars: 300, totalDiscussionsStarted: 0, totalDiscussionsAnswered: 0, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank, }); }); @@ -377,6 +418,11 @@ describe("Test fetchStats", () => { totalStars: 300, totalDiscussionsStarted: 0, totalDiscussionsAnswered: 0, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank, }); }); @@ -406,6 +452,11 @@ describe("Test fetchStats", () => { totalStars: 300, totalDiscussionsStarted: 10, totalDiscussionsAnswered: 40, + totalPRsAuthored: 0, + totalPRsCommented: 0, + totalPRsReviewed: 0, + totalIssuesAuthored: 0, + totalIssuesCommented: 0, rank, }); }); diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js index 973ee0a5..1b822942 100644 --- a/tests/renderStatsCard.test.js +++ b/tests/renderStatsCard.test.js @@ -139,17 +139,14 @@ describe("Test renderStatsCard", () => { it("should render with custom width set and limit minimum width", () => { document.body.innerHTML = renderStatsCard(stats, { card_width: 1 }); - expect(document.querySelector("svg")).toHaveAttribute("width", "420"); + expect(document.querySelector("svg")).toHaveAttribute("width", "1"); // Test default minimum card width without rank circle. document.body.innerHTML = renderStatsCard(stats, { card_width: 1, hide_rank: true, }); - expect(document.querySelector("svg")).toHaveAttribute( - "width", - "305.81250000000006", - ); + expect(document.querySelector("svg")).toHaveAttribute("width", "1"); // Test minimum card width with rank and icons. document.body.innerHTML = renderStatsCard(stats, { @@ -157,10 +154,7 @@ describe("Test renderStatsCard", () => { hide_rank: true, show_icons: true, }); - expect(document.querySelector("svg")).toHaveAttribute( - "width", - "322.81250000000006", - ); + expect(document.querySelector("svg")).toHaveAttribute("width", "1"); // Test minimum card width with icons but without rank. document.body.innerHTML = renderStatsCard(stats, { @@ -168,7 +162,7 @@ describe("Test renderStatsCard", () => { hide_rank: false, show_icons: true, }); - expect(document.querySelector("svg")).toHaveAttribute("width", "437"); + expect(document.querySelector("svg")).toHaveAttribute("width", "1"); // Test minimum card width without icons or rank. document.body.innerHTML = renderStatsCard(stats, { @@ -176,7 +170,7 @@ describe("Test renderStatsCard", () => { hide_rank: false, show_icons: false, }); - expect(document.querySelector("svg")).toHaveAttribute("width", "420"); + expect(document.querySelector("svg")).toHaveAttribute("width", "1"); }); it("should render default colors properly", () => {