add repo filter

This commit is contained in:
martin-mfg
2025-05-18 21:53:13 +02:00
parent 12f4f57e25
commit f91b400c43
11 changed files with 284 additions and 62 deletions
+37 -25
View File
@@ -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(
+15 -1
View File
@@ -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=<user_or_organization>/<repository>`. 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 | `<username> 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)
+75 -11
View File
@@ -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 = ({
</svg>
`
: "";
return `
<g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)">
return (
`
<g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)">` +
(link ? `<a href="${link}">` : "") +
`
${iconSvg}
<text class="stat ${
bold ? " bold" : "not_bold"
@@ -70,9 +75,12 @@ const createTextNode = ({
x="${(showIcons ? 140 : 120) + shiftValuePos}"
y="12.5"
data-testid="${id}"
>${kValue}${unitSymbol ? ` ${unitSymbol}` : ""}</text>
>${kValue}${unitSymbol ? ` ${unitSymbol}` : ""}</text>` +
(link ? "</a>" : "") +
`
</g>
`;
`
);
};
/**
@@ -199,7 +207,7 @@ const getStyles = ({
* @param {Partial<StatCardOptions>} 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}&amp;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}&amp;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}&amp;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}&amp;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}&amp;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,
+1
View File
@@ -11,6 +11,7 @@ const icons = {
reviews: `<path fill-rule="evenodd" d="M8 2c1.981 0 3.671.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.62 1.62 0 0 1 0 1.798c-.45.678-1.367 1.932-2.637 3.023C11.67 13.008 9.981 14 8 14c-1.981 0-3.671-.992-4.933-2.078C1.797 10.83.88 9.576.43 8.898a1.62 1.62 0 0 1 0-1.798c.45-.677 1.367-1.931 2.637-3.022C4.33 2.992 6.019 2 8 2ZM1.679 7.932a.12.12 0 0 0 0 .136c.411.622 1.241 1.75 2.366 2.717C5.176 11.758 6.527 12.5 8 12.5c1.473 0 2.825-.742 3.955-1.715 1.124-.967 1.954-2.096 2.366-2.717a.12.12 0 0 0 0-.136c-.412-.621-1.242-1.75-2.366-2.717C10.824 4.242 9.473 3.5 8 3.5c-1.473 0-2.825.742-3.955 1.715-1.124.967-1.954 2.096-2.366 2.717ZM8 10a2 2 0 1 1-.001-3.999A2 2 0 0 1 8 10Z"/>`,
discussions_started: `<path fill-rule="evenodd" d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z" />`,
discussions_answered: `<path fill-rule="evenodd" d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z" />`,
comments: `<path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z" />`,
gist: `<path fill-rule="evenodd" d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z" />`,
};
+2 -2
View File
@@ -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);
+67 -6
View File
@@ -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) {
+5
View File
@@ -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 };
};
+15
View File
@@ -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 总数",
+7 -2
View File
@@ -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(
+55 -4
View File
@@ -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,
});
});
+5 -11
View File
@@ -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", () => {