Compare commits

..
10 Commits
Author SHA1 Message Date
Anurag 430c614c1d chore: update 2023-06-06 20:34:35 +05:30
Anurag 024a469797 chore: added new dono link 2023-06-06 20:33:08 +05:30
Alexandr Garbuzovandrickstaa 894f2e2c5a Different default languages count for different languages card layouts (#2774)
* Different default languages count for different layouts

* docs: update default  documentation

Updates the README so that the new `langs_count` default behavoir is
explained to users.

---------

Co-authored-by: rickstaa <rick.staa@outlook.com>
2023-06-06 16:42:46 +02:00
Rick Staa cec5ee3462 ci: add top themes and labels to 'top issues dashboard' action (#2711) 2023-06-06 14:24:17 +05:30
Alexandr Garbuzov fa4d7ee7a1 Cover with test changes in #2770 pull request (#2775) 2023-06-06 08:56:23 +02:00
Alexandr Garbuzov 14fe4cf1db Remove redundant async notation from several top languages card tests (#2767) 2023-06-05 12:14:33 +02:00
Alexandr Garbuzov 1e0183d202 Conver with test changes in #2755 pull request (#2766) 2023-06-05 12:11:55 +02:00
Alexandr Garbuzov 98b047751e Fixed layout toLowerCase bug (#2770) 2023-06-05 12:10:22 +02:00
Rick Staa 1a2a82c3be test: add new ranking to e2e test (#2750) 2023-06-02 14:44:12 +05:30
Rick StaaandHakula Chen c301289f7d fix: Make WakaTime card compatible with new API (#2707)
* fix: Make WakaTime card compatible with new API

This commit makes sure that the WakaTime card works with the new
WakaTime API. See https://github.com/anuraghazra/github-readme-stats/issues/2698
for more information.

* fix: fix chinese simplified translations

* fix: improve WakaTime range order

* test: fix WakaTime tests

* refactor: remove WakaTime range loop

* refactor: remove redundant WakaTime call

* test: fix e2e tests

Co-authored-by: Hakula Chen <i@hakula.xyz>

---------

Co-authored-by: Hakula Chen <i@hakula.xyz>
2023-06-02 14:37:59 +05:30
20 changed files with 211 additions and 106 deletions
+6 -1
View File
@@ -15,10 +15,15 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
with:
filter: "1772"
label: false
label: true
dashboard: true
dashboard_show_total_reactions: true
top_issues: true
top_bugs: true
top_features: true
top_pull_requests: true
custom_pull_requests_label: themes
top_custom_pull_requests_label: ":star: top themes"
top_custom_pull_requests_label_description:
The description used for the top custom pull requests.
top_custom_pull_requests_label_colour: #A23599
+10
View File
@@ -44,6 +44,16 @@ export default async (req, res) => {
return res.send(renderError("Something went wrong", "Locale not found"));
}
if (
layout !== undefined &&
(typeof layout !== "string" ||
!["compact", "normal", "donut", "donut-vertical", "pie"].includes(layout))
) {
return res.send(
renderError("Something went wrong", "Incorrect layout input"),
);
}
try {
const topLangs = await fetchTopLanguages(
username,
+1 -2
View File
@@ -28,7 +28,6 @@ export default async (req, res) => {
langs_count,
hide,
api_domain,
range,
border_radius,
border_color,
} = req.query;
@@ -40,7 +39,7 @@ export default async (req, res) => {
}
try {
const stats = await fetchWakatimeStats({ username, api_domain, range });
const stats = await fetchWakatimeStats({ username, api_domain });
let cacheSeconds = clampValue(
parseInt(cache_seconds || CONSTANTS.FOUR_HOURS, 10),
+11 -9
View File
@@ -69,12 +69,15 @@
<img src="https://cfstatic.give.do/logo.png" alt="Give india logo" width="200" />
</a>
Are you considering supporting the project by donating? Please DO NOT!!
Are you considering supporting the project by donating to me? Please DO NOT!!
Instead, Help India fight the second deadly wave of COVID-19.
Thousands of people are dying in India because of a lack of Oxygen & also COVID-related infrastructure.
Visit <https://indiafightscorona.giveindia.org> and make a small donation to help us fight COVID and overcome this crisis. A small donation goes a long way. :heart:
<img src="https://cfstatic.give.do/910ede2a-7892-43fe-8c8a-dea45e96d950.webp" alt="Picture of Coromandel Express train tragedy" width="35%">
India just suffered one of the most devastating train accident and your help will be immensely valuable for the people who were effected by this tragedy.
Please visit [this link](https://give.do/fundraisers/stand-beside-the-victims-of-the-coromandel-express-train-tragedy-in-odisha-donate-now) and make a small donation to help the people in need. A small donation goes a long way. :heart:
</p>
@@ -292,7 +295,7 @@ You can provide multiple comma-separated values in the bg_color option to render
- `hide_title` - _(boolean)_. Default: `false`.
- `layout` - Switch between five available layouts `normal` & `compact` & `donut` & `donut-vertical` & `pie`. Default: `normal`.
- `card_width` - Set the card's width manually _(number)_. Default `300`.
- `langs_count` - Show more languages on the card, between 1-10 _(number)_. Default `5`.
- `langs_count` - Show more languages on the card, between 1-10 _(number)_. Default: `5` for `normal` and `donut`, `6` for other layouts.
- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
- `custom_title` - Sets a custom title for the card _(string)_. Default `Most Used Languages`.
- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
@@ -315,7 +318,6 @@ You can provide multiple comma-separated values in the bg_color option to render
- `layout` - Switch between two available layouts `default` & `compact`. Default `default`.
- `langs_count` - Limit the number of languages on the card, defaults to all reported languages _(number)_.
- `api_domain` - Set a custom API domain for the card, e.g. to use services like [Hakatime](https://github.com/mujx/hakatime) or [Wakapi](https://github.com/muety/wakapi) _(string)_. Default `Waka API`.
- `range` Request a range different from your WakaTime default, e.g. `last_7_days`. See [WakaTime API docs](https://wakatime.com/developers#stats) for a list of available options. _(YYYY-MM, last_7_days, last_30_days, last_6_months, last_year, or all_time)_. Default `all_time`.
* * *
@@ -468,15 +470,15 @@ You can use the `&hide_progress=true` option to hide the percentages and the pro
# Wakatime Week Stats
> **Warning**
> Please be aware that we currently only show data from Wakatime profiles that are public. You therefore have to make sure that **BOTH** `Display code time publicly` and `Display languages, editors, os, categories publicly` are enabled.
Change the `?username=` value to your [Wakatime](https://wakatime.com) username.
```md
[![Harlok's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=Harlok)](https://github.com/anuraghazra/github-readme-stats)
```
> **Note**:
> Please be aware that we currently only show data from Wakatime profiles that are public.
### Demo
[![Harlok's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=Harlok)](https://github.com/anuraghazra/github-readme-stats)
+29 -25
View File
@@ -1,10 +1,5 @@
function exponential_cdf(x) {
return 1 - 2 ** -x;
}
function log_normal_cdf(x) {
// approximation
return x / (1 + x);
function expsf(x, lambda = 1) {
return 2 ** (-lambda * x);
}
/**
@@ -18,7 +13,7 @@ function log_normal_cdf(x) {
* @param {number} params.repos Total number of repos.
* @param {number} params.stars The number of stars.
* @param {number} params.followers The number of followers.
* @returns {{level: string, percentile: number}}} The users rank.
* @returns {{level: string, score: number}}} The users rank.
*/
function calculateRank({
all_commits,
@@ -29,15 +24,15 @@ function calculateRank({
stars,
followers,
}) {
const COMMITS_MEDIAN = all_commits ? 1000 : 250,
const COMMITS_MEAN = all_commits ? 1000 : 250,
COMMITS_WEIGHT = 2;
const PRS_MEDIAN = 50,
const PRS_MEAN = 50,
PRS_WEIGHT = 3;
const ISSUES_MEDIAN = 25,
const ISSUES_MEAN = 25,
ISSUES_WEIGHT = 1;
const STARS_MEDIAN = 50,
const STARS_MEAN = 250,
STARS_WEIGHT = 4;
const FOLLOWERS_MEDIAN = 10,
const FOLLOWERS_MEAN = 25,
FOLLOWERS_WEIGHT = 1;
const TOTAL_WEIGHT =
@@ -47,21 +42,30 @@ function calculateRank({
STARS_WEIGHT +
FOLLOWERS_WEIGHT;
const THRESHOLDS = [1, 12.5, 25, 37.5, 50, 62.5, 75, 87.5, 100];
const LEVELS = ["S", "A+", "A", "A-", "B+", "B", "B-", "C+", "C"];
const rank =
1 -
(COMMITS_WEIGHT * exponential_cdf(commits / COMMITS_MEDIAN) +
PRS_WEIGHT * exponential_cdf(prs / PRS_MEDIAN) +
ISSUES_WEIGHT * exponential_cdf(issues / ISSUES_MEDIAN) +
STARS_WEIGHT * log_normal_cdf(stars / STARS_MEDIAN) +
FOLLOWERS_WEIGHT * log_normal_cdf(followers / FOLLOWERS_MEDIAN)) /
TOTAL_WEIGHT;
(COMMITS_WEIGHT * expsf(commits, 1 / COMMITS_MEAN) +
PRS_WEIGHT * expsf(prs, 1 / PRS_MEAN) +
ISSUES_WEIGHT * expsf(issues, 1 / ISSUES_MEAN) +
STARS_WEIGHT * expsf(stars, 1 / STARS_MEAN) +
FOLLOWERS_WEIGHT * expsf(followers, 1 / FOLLOWERS_MEAN)) /
TOTAL_WEIGHT;
const level = LEVELS[THRESHOLDS.findIndex((t) => rank * 100 <= t)];
const RANK_S_PLUS = 0.025;
const RANK_S = 0.1;
const RANK_A_PLUS = 0.25;
const RANK_A = 0.5;
const RANK_B_PLUS = 0.75;
return { level: level, percentile: rank * 100 };
const level = (() => {
if (rank <= RANK_S_PLUS) return "S+";
if (rank <= RANK_S) return "S";
if (rank <= RANK_A_PLUS) return "A+";
if (rank <= RANK_A) return "A";
if (rank <= RANK_B_PLUS) return "B+";
return "B";
})();
return { level, score: rank * 100 };
}
export { calculateRank };
+3 -2
View File
@@ -209,8 +209,9 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
hide_rank ? 0 : 150,
);
// the lower the user's percentile the better
const progress = 100 - rank.percentile;
// the better user's score the the rank will be closer to zero so
// subtracting 100 to get the progress in 100%
const progress = 100 - rank.score;
const cssStyles = getStyles({
titleColor,
ringColor,
+29 -3
View File
@@ -14,11 +14,16 @@ import { langCardLocales } from "../translations.js";
const DEFAULT_CARD_WIDTH = 300;
const MIN_CARD_WIDTH = 280;
const DEFAULT_LANGS_COUNT = 5;
const DEFAULT_LANG_COLOR = "#858585";
const CARD_PADDING = 25;
const COMPACT_LAYOUT_BASE_HEIGHT = 90;
const NORMAL_LAYOUT_DEFAULT_LANGS_COUNT = 5;
const COMPACT_LAYOUT_DEFAULT_LANGS_COUNT = 6;
const DONUT_LAYOUT_DEFAULT_LANGS_COUNT = 5;
const PIE_LAYOUT_DEFAULT_LANGS_COUNT = 6;
const DONUT_VERTICAL_LAYOUT_DEFAULT_LANGS_COUNT = 6;
/**
* @typedef {import("../fetchers/types").Lang} Lang
*/
@@ -668,6 +673,26 @@ const noLanguagesDataNode = ({ color, text, layout }) => {
`;
};
/**
* Get default languages count for provided card layout.
*
* @param {import("./types").TopLangOptions["layout"] | undefined} layout Input layout string
* @return {number} Default languages count for input layout
*/
const getDefaultLanguagesCountByLayout = (layout) => {
if (layout === "compact") {
return COMPACT_LAYOUT_DEFAULT_LANGS_COUNT;
} else if (layout === "donut") {
return DONUT_LAYOUT_DEFAULT_LANGS_COUNT;
} else if (layout === "donut-vertical") {
return DONUT_VERTICAL_LAYOUT_DEFAULT_LANGS_COUNT;
} else if (layout === "pie") {
return PIE_LAYOUT_DEFAULT_LANGS_COUNT;
} else {
return NORMAL_LAYOUT_DEFAULT_LANGS_COUNT;
}
};
/**
* Renders card that display user's most frequently used programming languages.
*
@@ -689,7 +714,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
layout,
custom_title,
locale,
langs_count = DEFAULT_LANGS_COUNT,
langs_count = getDefaultLanguagesCountByLayout(layout),
border_radius,
border_color,
disable_animations,
@@ -746,7 +771,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
totalLanguageSize,
hide_progress,
);
} else if (layout?.toLowerCase() === "donut") {
} else if (layout === "donut") {
height = calculateDonutLayoutHeight(langs.length);
width = width + 50; // padding
finalLayout = renderDonutLayout(langs, width, totalLanguageSize);
@@ -837,4 +862,5 @@ export {
trimTopLanguages,
renderTopLanguages,
MIN_CARD_WIDTH,
getDefaultLanguagesCountByLayout,
};
+22 -3
View File
@@ -279,7 +279,11 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
: noCodingActivityNode({
// @ts-ignore
color: textColor,
text: i18n.t("wakatimecard.nocodingactivity"),
text: !stats.is_coding_activity_visible
? i18n.t("wakatimecard.notpublic")
: stats.is_other_usage_visible
? i18n.t("wakatimecard.nocodingactivity")
: i18n.t("wakatimecard.nocodedetails"),
})
}
`;
@@ -304,7 +308,11 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
noCodingActivityNode({
// @ts-ignore
color: textColor,
text: i18n.t("wakatimecard.nocodingactivity"),
text: !stats.is_coding_activity_visible
? i18n.t("wakatimecard.notpublic")
: stats.is_other_usage_visible
? i18n.t("wakatimecard.nocodingactivity")
: i18n.t("wakatimecard.nocodedetails"),
}),
],
gap: lheight,
@@ -312,9 +320,20 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
}).join("");
}
// Get title range text
let titleText = i18n.t("wakatimecard.title");
switch (stats.range) {
case "last_7_days":
titleText += ` (${i18n.t("wakatimecard.last7days")})`;
break;
case "last_year":
titleText += ` (${i18n.t("wakatimecard.lastyear")})`;
break;
}
const card = new Card({
customTitle: custom_title,
defaultTitle: i18n.t("wakatimecard.title"),
defaultTitle: titleText,
width: 495,
height,
border_radius,
+2
View File
@@ -305,6 +305,7 @@ const SECONDARY_ERROR_MESSAGES = {
"Please add an env variable called PAT_1 with your github token in vercel",
USER_NOT_FOUND: "Make sure the provided username is not an organization",
GRAPHQL_ERROR: "Please try again later",
WAKATIME_USER_NOT_FOUND: "Make sure you have a public WakaTime profile",
};
/**
@@ -324,6 +325,7 @@ class CustomError extends Error {
static MAX_RETRY = "MAX_RETRY";
static USER_NOT_FOUND = "USER_NOT_FOUND";
static GRAPHQL_ERROR = "GRAPHQL_ERROR";
static WAKATIME_ERROR = "WAKATIME_ERROR";
}
/**
+1 -1
View File
@@ -192,7 +192,7 @@ const fetchStats = async (
totalIssues: 0,
totalStars: 0,
contributedTo: 0,
rank: { level: "C", percentile: 100 },
rank: { level: "B", score: 0 },
};
let res = await statsFetcher(username);
+1 -1
View File
@@ -22,7 +22,7 @@ export type StatsData = {
totalIssues: number;
totalStars: number;
contributedTo: number;
rank: { level: string; percentile: number };
rank: { level: string; score: number };
};
export type Lang = {
+8 -8
View File
@@ -1,29 +1,29 @@
import axios from "axios";
import { MissingParamError } from "../common/utils.js";
import { CustomError, MissingParamError } from "../common/utils.js";
import { I18n } from "../common/I18n.js";
/**
* WakaTime data fetcher.
*
* @param {{username: string, api_domain: string, range: string}} props Fetcher props.
* @param {{username: string, api_domain: string }} props Fetcher props.
* @returns {Promise<WakaTimeData>} WakaTime data response.
*/
const fetchWakatimeStats = async ({ username, api_domain, range }) => {
const fetchWakatimeStats = async ({ username, api_domain }) => {
if (!username) throw new MissingParamError(["username"]);
try {
const { data } = await axios.get(
`https://${
api_domain ? api_domain.replace(/\/$/gi, "") : "wakatime.com"
}/api/v1/users/${username}/stats/${
range || "all_time"
}?is_including_today=true`,
}/api/v1/users/${username}/stats?is_including_today=true`,
);
return data.data;
} catch (err) {
if (err.response.status < 200 || err.response.status > 299) {
throw new Error(
"Wakatime user not found, make sure you have a wakatime profile",
throw new CustomError(
`Could not resolve to a User with the login of '${username}'`,
"WAKATIME_USER_NOT_FOUND",
);
}
throw err;
+16
View File
@@ -356,6 +356,22 @@ const wakatimeCardLocales = {
vi: "Thống Kê Wakatime",
se: "Wakatime statistik",
},
"wakatimecard.lastyear": {
en: "last year",
cn: "去年",
},
"wakatimecard.last7days": {
en: "last 7 days",
cn: "最近 7 天",
},
"wakatimecard.notpublic": {
en: "Wakatime user profile not public",
cn: "Wakatime 用户个人资料未公开",
},
"wakatimecard.nocodedetails": {
en: "User doesn't publicly share detailed code statistics",
cn: "用户不公开分享详细的代码统计信息",
},
"wakatimecard.nocodingactivity": {
ar: "لا يوجد نشاط برمجي لهذا الأسبوع",
cn: "本周没有编程活动",
@@ -123,7 +123,7 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1
y="0"
class="header"
data-testid="header"
>Wakatime Stats</text>
>Wakatime Stats (last 7 days)</text>
</g>
</g>
@@ -303,7 +303,7 @@ exports[`Test Render Wakatime Card should render correctly with compact layout w
y="0"
class="header"
data-testid="header"
>Wakatime Stats</text>
>Wakatime Stats (last 7 days)</text>
</g>
</g>
+25 -39
View File
@@ -2,7 +2,7 @@ import "@testing-library/jest-dom";
import { calculateRank } from "../src/calculateRank.js";
describe("Test calculateRank", () => {
it("new user gets C rank", () => {
it("new user gets B rank", () => {
expect(
calculateRank({
all_commits: false,
@@ -13,24 +13,10 @@ describe("Test calculateRank", () => {
stars: 0,
followers: 0,
}),
).toStrictEqual({ level: "C", percentile: 100 });
).toStrictEqual({ level: "B", score: 100 });
});
it("beginner user gets B- rank", () => {
expect(
calculateRank({
all_commits: false,
commits: 125,
prs: 25,
issues: 10,
repos: 0,
stars: 25,
followers: 5,
}),
).toStrictEqual({ level: "B-", percentile: 69.333868386557 });
});
it("median user gets B+ rank", () => {
it("average user gets A rank", () => {
expect(
calculateRank({
all_commits: false,
@@ -38,13 +24,13 @@ describe("Test calculateRank", () => {
prs: 50,
issues: 25,
repos: 0,
stars: 50,
followers: 10,
stars: 250,
followers: 25,
}),
).toStrictEqual({ level: "B+", percentile: 50 });
).toStrictEqual({ level: "A", score: 50 });
});
it("average user gets B+ rank (include_all_commits)", () => {
it("average user gets A rank (include_all_commits)", () => {
expect(
calculateRank({
all_commits: true,
@@ -52,13 +38,13 @@ describe("Test calculateRank", () => {
prs: 50,
issues: 25,
repos: 0,
stars: 50,
followers: 10,
stars: 250,
followers: 25,
}),
).toStrictEqual({ level: "B+", percentile: 50 });
).toStrictEqual({ level: "A", score: 50 });
});
it("advanced user gets A rank", () => {
it("more than average user gets A+ rank", () => {
expect(
calculateRank({
all_commits: false,
@@ -66,13 +52,13 @@ describe("Test calculateRank", () => {
prs: 100,
issues: 50,
repos: 0,
stars: 200,
followers: 40,
stars: 500,
followers: 50,
}),
).toStrictEqual({ level: "A", percentile: 22.72727272727273 });
).toStrictEqual({ level: "A+", score: 25 });
});
it("expert user gets A+ rank", () => {
it("expert user gets S rank", () => {
expect(
calculateRank({
all_commits: false,
@@ -80,23 +66,23 @@ describe("Test calculateRank", () => {
prs: 200,
issues: 100,
repos: 0,
stars: 800,
followers: 160,
stars: 1000,
followers: 100,
}),
).toStrictEqual({ level: "A+", percentile: 6.082887700534744 });
).toStrictEqual({ level: "S", score: 6.25 });
});
it("sindresorhus gets S rank", () => {
it("ezyang gets S+ rank", () => {
expect(
calculateRank({
all_commits: false,
commits: 1300,
prs: 1500,
issues: 4500,
commits: 1000,
prs: 4000,
issues: 2000,
repos: 0,
stars: 600000,
followers: 50000,
stars: 5000,
followers: 2000,
}),
).toStrictEqual({ level: "S", percentile: 0.49947889605312934 });
).toStrictEqual({ level: "S+", score: 1.1363983154296875 });
});
});
+2 -5
View File
@@ -20,10 +20,7 @@ const STATS_DATA = {
totalIssues: 1,
totalStars: 1,
contributedTo: 1,
rank: {
level: "A+",
score: 50.88831151384285,
},
rank: { level: "B", score: 98.50610674501908 },
};
const LANGS_DATA = {
@@ -54,7 +51,7 @@ const WAKATIME_DATA = {
is_up_to_date: false,
is_up_to_date_pending_future: false,
percent_calculated: 0,
range: "last_7_days",
range: "all_time",
status: "pending_update",
timeout: 15,
username: USER,
+1 -1
View File
@@ -105,7 +105,7 @@ describe("Wakatime fetcher", () => {
const username = "anuraghazra";
mock
.onGet(
`https://wakatime.com/api/v1/users/${username}/stats/all_time?is_including_today=true`,
`https://wakatime.com/api/v1/users/${username}/stats?is_including_today=true`,
)
.reply(200, wakaTimeData);
+19 -2
View File
@@ -16,6 +16,7 @@ import {
trimTopLanguages,
renderTopLanguages,
MIN_CARD_WIDTH,
getDefaultLanguagesCountByLayout,
} from "../src/cards/top-languages-card.js";
// adds special assertions like toHaveTextContent
@@ -328,6 +329,15 @@ describe("Test renderTopLanguages helper functions", () => {
totalLanguageSize: 300,
});
});
it("getDefaultLanguagesCountByLayout", () => {
expect(getDefaultLanguagesCountByLayout("normal")).toStrictEqual(5);
expect(getDefaultLanguagesCountByLayout(undefined)).toStrictEqual(5);
expect(getDefaultLanguagesCountByLayout("compact")).toStrictEqual(6);
expect(getDefaultLanguagesCountByLayout("donut")).toStrictEqual(5);
expect(getDefaultLanguagesCountByLayout("donut-vertical")).toStrictEqual(6);
expect(getDefaultLanguagesCountByLayout("pie")).toStrictEqual(6);
});
});
describe("Test renderTopLanguages", () => {
@@ -797,7 +807,7 @@ describe("Test renderTopLanguages", () => {
expect(document.querySelector("rect")).toHaveAttribute("rx", "4.5");
});
it("should render langs with specified langs_count", async () => {
it("should render langs with specified langs_count", () => {
const options = {
langs_count: 1,
};
@@ -807,7 +817,7 @@ describe("Test renderTopLanguages", () => {
);
});
it("should render langs with specified langs_count even when hide is set", async () => {
it("should render langs with specified langs_count even when hide is set", () => {
const options = {
hide: ["HTML"],
langs_count: 2,
@@ -817,4 +827,11 @@ describe("Test renderTopLanguages", () => {
options.langs_count,
);
});
it('should show "No languages data." message instead of empty card when nothing to show', () => {
document.body.innerHTML = renderTopLanguages({});
expect(document.querySelector(".stat").textContent).toBe(
"No languages data.",
);
});
});
+1 -1
View File
@@ -43,7 +43,7 @@ describe("Test Render Wakatime Card", () => {
expect(
document.querySelector('g[transform="translate(0, 0)"]>text.stat.bold')
.textContent,
).toBe("本周没有编程活动");
).toBe("Wakatime 用户个人资料未公开");
});
it("should render without rounding", () => {
+22 -1
View File
@@ -123,7 +123,7 @@ describe("Test /api/top-langs", () => {
);
});
it("should render error card on error", async () => {
it("should render error card on user data fetch error", async () => {
const req = {
query: {
username: "anuraghazra",
@@ -140,4 +140,25 @@ describe("Test /api/top-langs", () => {
expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
expect(res.send).toBeCalledWith(renderError(error.errors[0].message));
});
it("should render error card on incorrect layout input", async () => {
const req = {
query: {
username: "anuraghazra",
layout: ["pie"],
},
};
const res = {
setHeader: jest.fn(),
send: jest.fn(),
};
mock.onPost("https://api.github.com/graphql").reply(200, data_langs);
await topLangs(req, res);
expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
expect(res.send).toBeCalledWith(
renderError("Something went wrong", "Incorrect layout input"),
);
});
});