diff --git a/api/gist.js b/api/gist.js index aab85ba9..7c5f9e68 100644 --- a/api/gist.js +++ b/api/gist.js @@ -47,12 +47,16 @@ export default async (req, res) => { if (locale && !isLocaleAvailable(locale)) { return res.send( - renderError("Something went wrong", "Language not found", { - title_color, - text_color, - bg_color, - border_color, - theme, + renderError({ + message: "Something went wrong", + secondaryMessage: "Language not found", + renderOptions: { + title_color, + text_color, + bg_color, + border_color, + theme, + }, }), ); } @@ -85,12 +89,16 @@ export default async (req, res) => { } catch (err) { setErrorCacheHeaders(res); return res.send( - renderError(err.message, err.secondaryMessage, { - title_color, - text_color, - bg_color, - border_color, - theme, + renderError({ + message: err.message, + secondaryMessage: err.secondaryMessage, + renderOptions: { + title_color, + text_color, + bg_color, + border_color, + theme, + }, }), ); } diff --git a/api/index.js b/api/index.js index a5887fb0..37a29841 100644 --- a/api/index.js +++ b/api/index.js @@ -66,12 +66,16 @@ export default async (req, res) => { if (locale && !isLocaleAvailable(locale)) { return res.send( - renderError("Something went wrong", "Language not found", { - title_color, - text_color, - bg_color, - border_color, - theme, + renderError({ + message: "Something went wrong", + secondaryMessage: "Language not found", + renderOptions: { + title_color, + text_color, + bg_color, + border_color, + theme, + }, }), ); } @@ -128,12 +132,16 @@ export default async (req, res) => { } catch (err) { setErrorCacheHeaders(res); return res.send( - renderError(err.message, err.secondaryMessage, { - title_color, - text_color, - bg_color, - border_color, - theme, + renderError({ + message: err.message, + secondaryMessage: err.secondaryMessage, + renderOptions: { + title_color, + text_color, + bg_color, + border_color, + theme, + }, }), ); } diff --git a/api/pin.js b/api/pin.js index ebb0d8af..2183c8f1 100644 --- a/api/pin.js +++ b/api/pin.js @@ -49,12 +49,16 @@ export default async (req, res) => { if (locale && !isLocaleAvailable(locale)) { return res.send( - renderError("Something went wrong", "Language not found", { - title_color, - text_color, - bg_color, - border_color, - theme, + renderError({ + message: "Something went wrong", + secondaryMessage: "Language not found", + renderOptions: { + title_color, + text_color, + bg_color, + border_color, + theme, + }, }), ); } @@ -88,12 +92,16 @@ export default async (req, res) => { } catch (err) { setErrorCacheHeaders(res); return res.send( - renderError(err.message, err.secondaryMessage, { - title_color, - text_color, - bg_color, - border_color, - theme, + renderError({ + message: err.message, + secondaryMessage: err.secondaryMessage, + renderOptions: { + title_color, + text_color, + bg_color, + border_color, + theme, + }, }), ); } diff --git a/api/top-langs.js b/api/top-langs.js index f80528ae..d4b51c6b 100644 --- a/api/top-langs.js +++ b/api/top-langs.js @@ -60,7 +60,12 @@ export default async (req, res) => { } if (locale && !isLocaleAvailable(locale)) { - return res.send(renderError("Something went wrong", "Locale not found")); + return res.send( + renderError({ + message: "Something went wrong", + secondaryMessage: "Locale not found", + }), + ); } if ( @@ -69,7 +74,10 @@ export default async (req, res) => { !["compact", "normal", "donut", "donut-vertical", "pie"].includes(layout)) ) { return res.send( - renderError("Something went wrong", "Incorrect layout input"), + renderError({ + message: "Something went wrong", + secondaryMessage: "Incorrect layout input", + }), ); } @@ -79,7 +87,10 @@ export default async (req, res) => { !["bytes", "percentages"].includes(stats_format)) ) { return res.send( - renderError("Something went wrong", "Incorrect stats_format input"), + renderError({ + message: "Something went wrong", + secondaryMessage: "Incorrect stats_format input", + }), ); } @@ -123,12 +134,16 @@ export default async (req, res) => { } catch (err) { setErrorCacheHeaders(res); return res.send( - renderError(err.message, err.secondaryMessage, { - title_color, - text_color, - bg_color, - border_color, - theme, + renderError({ + message: err.message, + secondaryMessage: err.secondaryMessage, + renderOptions: { + title_color, + text_color, + bg_color, + border_color, + theme, + }, }), ); } diff --git a/api/wakatime.js b/api/wakatime.js index 9cbf779f..7b5571eb 100644 --- a/api/wakatime.js +++ b/api/wakatime.js @@ -62,12 +62,16 @@ export default async (req, res) => { if (locale && !isLocaleAvailable(locale)) { return res.send( - renderError("Something went wrong", "Language not found", { - title_color, - text_color, - bg_color, - border_color, - theme, + renderError({ + message: "Something went wrong", + secondaryMessage: "Language not found", + renderOptions: { + title_color, + text_color, + bg_color, + border_color, + theme, + }, }), ); } @@ -109,12 +113,16 @@ export default async (req, res) => { } catch (err) { setErrorCacheHeaders(res); return res.send( - renderError(err.message, err.secondaryMessage, { - title_color, - text_color, - bg_color, - border_color, - theme, + renderError({ + message: err.message, + secondaryMessage: err.secondaryMessage, + renderOptions: { + title_color, + text_color, + bg_color, + border_color, + theme, + }, }), ); } diff --git a/src/common/access.js b/src/common/access.js index 959e17af..5b15dc5d 100644 --- a/src/common/access.js +++ b/src/common/access.js @@ -33,9 +33,13 @@ const guardAccess = ({ res, id, type, colors }) => { if (Array.isArray(currentWhitelist) && !currentWhitelist.includes(id)) { const result = res.send( - renderError(notWhitelistedMsg, "Please deploy your own instance", { - ...colors, - show_repo_link: false, + renderError({ + message: notWhitelistedMsg, + secondaryMessage: "Please deploy your own instance", + renderOptions: { + ...colors, + show_repo_link: false, + }, }), ); return { isPassed: false, result }; @@ -47,9 +51,13 @@ const guardAccess = ({ res, id, type, colors }) => { blacklist.includes(id) ) { const result = res.send( - renderError(BLACKLISTED_MESSAGE, "Please deploy your own instance", { - ...colors, - show_repo_link: false, + renderError({ + message: BLACKLISTED_MESSAGE, + secondaryMessage: "Please deploy your own instance", + renderOptions: { + ...colors, + show_repo_link: false, + }, }), ); return { isPassed: false, result }; diff --git a/src/common/utils.js b/src/common/utils.js index 04b02e2c..3dac650b 100644 --- a/src/common/utils.js +++ b/src/common/utils.js @@ -352,18 +352,23 @@ const UPSTREAM_API_ERRORS = [ /** * Renders error message on the card. * - * @param {string} message Main error message. - * @param {string} secondaryMessage The secondary error message. - * @param {object} options Function options. - * @param {string=} options.title_color Card title color. - * @param {string=} options.text_color Card text color. - * @param {string=} options.bg_color Card background color. - * @param {string=} options.border_color Card border color. - * @param {string=} options.theme Card theme. - * @param {boolean=} options.show_repo_link Whether to show repo link or not. + * @param {object} args Function arguments. + * @param {string} args.message Main error message. + * @param {string} [args.secondaryMessage=""] The secondary error message. + * @param {object} [args.renderOptions={}] Render options. + * @param {string=} args.renderOptions.title_color Card title color. + * @param {string=} args.renderOptions.text_color Card text color. + * @param {string=} args.renderOptions.bg_color Card background color. + * @param {string=} args.renderOptions.border_color Card border color. + * @param {string=} args.renderOptions.theme Card theme. + * @param {boolean=} args.renderOptions.show_repo_link Whether to show repo link or not. * @returns {string} The SVG markup. */ -const renderError = (message, secondaryMessage = "", options = {}) => { +const renderError = ({ + message, + secondaryMessage = "", + renderOptions = {}, +}) => { const { title_color, text_color, @@ -371,7 +376,7 @@ const renderError = (message, secondaryMessage = "", options = {}) => { border_color, theme = "default", show_repo_link = true, - } = options; + } = renderOptions; // returns theme based colors with proper overrides and defaults const { titleColor, textColor, bgColor, borderColor } = getCardColors({ diff --git a/tests/api.test.js b/tests/api.test.js index e77775e9..2b4f83c9 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -1,3 +1,5 @@ +// @ts-check + import { jest } from "@jest/globals"; import axios from "axios"; import MockAdapter from "axios-mock-adapter"; @@ -7,6 +9,9 @@ import { renderStatsCard } from "../src/cards/stats.js"; import { CONSTANTS, renderError } from "../src/common/utils.js"; import { expect, it, describe, afterEach } from "@jest/globals"; +/** + * @type {import("../src/fetchers/stats").StatsData} + */ const stats = { name: "Anurag Hazra", totalStars: 100, @@ -19,7 +24,7 @@ const stats = { totalDiscussionsStarted: 10, totalDiscussionsAnswered: 40, contributedTo: 50, - rank: null, + rank: { level: "DEV", percentile: 0 }, }; stats.rank = calculateRank({ @@ -115,10 +120,11 @@ describe("Test /api/", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError( - error.errors[0].message, - "Make sure the provided username is not an organization", - ), + renderError({ + message: error.errors[0].message, + secondaryMessage: + "Make sure the provided username is not an organization", + }), ); }); @@ -129,11 +135,12 @@ describe("Test /api/", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError( - error.errors[0].message, - "Make sure the provided username is not an organization", - { theme: "merko" }, - ), + renderError({ + message: error.errors[0].message, + secondaryMessage: + "Make sure the provided username is not an organization", + renderOptions: { theme: "merko" }, + }), ); }); @@ -307,11 +314,11 @@ describe("Test /api/", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError( - "This username is blacklisted", - "Please deploy your own instance", - { show_repo_link: false }, - ), + renderError({ + message: "This username is blacklisted", + secondaryMessage: "Please deploy your own instance", + renderOptions: { show_repo_link: false }, + }), ); }); @@ -322,7 +329,10 @@ describe("Test /api/", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError("Something went wrong", "Language not found"), + renderError({ + message: "Something went wrong", + secondaryMessage: "Language not found", + }), ); }); @@ -340,7 +350,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({ + message: "Could not fetch total commits.", + secondaryMessage: "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/gist.test.js b/tests/gist.test.js index d6cd5621..bfe5d774 100644 --- a/tests/gist.test.js +++ b/tests/gist.test.js @@ -1,3 +1,5 @@ +// @ts-check + import { jest } from "@jest/globals"; import "@testing-library/jest-dom"; import axios from "axios"; @@ -124,10 +126,10 @@ describe("Test /api/gist", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError( - 'Missing params "id" make sure you pass the parameters in URL', - "/api/gist?id=GIST_ID", - ), + renderError({ + message: 'Missing params "id" make sure you pass the parameters in URL', + secondaryMessage: "/api/gist?id=GIST_ID", + }), ); }); @@ -148,7 +150,7 @@ describe("Test /api/gist", () => { await gist(req, res); expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith(renderError("Gist not found")); + expect(res.send).toBeCalledWith(renderError({ message: "Gist not found" })); }); it("should render error if wrong locale is provided", async () => { @@ -167,7 +169,10 @@ describe("Test /api/gist", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError("Something went wrong", "Language not found"), + renderError({ + message: "Something went wrong", + secondaryMessage: "Language not found", + }), ); }); diff --git a/tests/pin.test.js b/tests/pin.test.js index 10324d44..88e43165 100644 --- a/tests/pin.test.js +++ b/tests/pin.test.js @@ -1,3 +1,5 @@ +// @ts-check + import { jest } from "@jest/globals"; import "@testing-library/jest-dom"; import axios from "axios"; @@ -56,6 +58,7 @@ describe("Test /api/pin", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( + // @ts-ignore renderRepoCard({ ...data_repo.repository, starCount: data_repo.repository.stargazers.totalCount, @@ -86,6 +89,7 @@ describe("Test /api/pin", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( renderRepoCard( + // @ts-ignore { ...data_repo.repository, starCount: data_repo.repository.stargazers.totalCount, @@ -113,7 +117,9 @@ describe("Test /api/pin", () => { await pin(req, res); expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith(renderError("User Repository Not found")); + expect(res.send).toBeCalledWith( + renderError({ message: "User Repository Not found" }), + ); }); it("should render error card if org repo not found", async () => { @@ -135,7 +141,7 @@ describe("Test /api/pin", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError("Organization Repository Not found"), + renderError({ message: "Organization Repository Not found" }), ); }); @@ -156,11 +162,11 @@ describe("Test /api/pin", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError( - "This username is blacklisted", - "Please deploy your own instance", - { show_repo_link: false }, - ), + renderError({ + message: "This username is blacklisted", + secondaryMessage: "Please deploy your own instance", + renderOptions: { show_repo_link: false }, + }), ); }); @@ -182,7 +188,10 @@ describe("Test /api/pin", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError("Something went wrong", "Language not found"), + renderError({ + message: "Something went wrong", + secondaryMessage: "Language not found", + }), ); }); @@ -199,10 +208,11 @@ describe("Test /api/pin", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError( - 'Missing params "username", "repo" make sure you pass the parameters in URL', - "/api/pin?username=USERNAME&repo=REPO_NAME", - ), + renderError({ + message: + 'Missing params "username", "repo" make sure you pass the parameters in URL', + secondaryMessage: "/api/pin?username=USERNAME&repo=REPO_NAME", + }), ); }); diff --git a/tests/top-langs.test.js b/tests/top-langs.test.js index 0a51d4e3..cdd47d72 100644 --- a/tests/top-langs.test.js +++ b/tests/top-langs.test.js @@ -1,3 +1,5 @@ +// @ts-check + import { jest } from "@jest/globals"; import "@testing-library/jest-dom"; import axios from "axios"; @@ -140,10 +142,11 @@ describe("Test /api/top-langs", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError( - error.errors[0].message, - "Make sure the provided username is not an organization", - ), + renderError({ + message: error.errors[0].message, + secondaryMessage: + "Make sure the provided username is not an organization", + }), ); }); @@ -164,7 +167,10 @@ describe("Test /api/top-langs", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError("Something went wrong", "Incorrect layout input"), + renderError({ + message: "Something went wrong", + secondaryMessage: "Incorrect layout input", + }), ); }); @@ -184,11 +190,11 @@ describe("Test /api/top-langs", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError( - "This username is blacklisted", - "Please deploy your own instance", - { show_repo_link: false }, - ), + renderError({ + message: "This username is blacklisted", + secondaryMessage: "Please deploy your own instance", + renderOptions: { show_repo_link: false }, + }), ); }); @@ -209,7 +215,10 @@ describe("Test /api/top-langs", () => { expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); expect(res.send).toBeCalledWith( - renderError("Something went wrong", "Locale not found"), + renderError({ + message: "Something went wrong", + secondaryMessage: "Locale not found", + }), ); }); diff --git a/tests/utils.test.js b/tests/utils.test.js index 7277b95d..ad72b8c5 100644 --- a/tests/utils.test.js +++ b/tests/utils.test.js @@ -46,7 +46,7 @@ describe("Test utils.js", () => { }); it("should test renderError", () => { - document.body.innerHTML = renderError("Something went wrong"); + document.body.innerHTML = renderError({ message: "Something went wrong" }); expect( queryByTestId(document.body, "message").children[0], ).toHaveTextContent(/Something went wrong/gim); @@ -55,10 +55,10 @@ describe("Test utils.js", () => { ).toBeEmptyDOMElement(2); // Secondary message - document.body.innerHTML = renderError( - "Something went wrong", - "Secondary Message", - ); + document.body.innerHTML = renderError({ + message: "Something went wrong", + secondaryMessage: "Secondary Message", + }); expect( queryByTestId(document.body, "message").children[1], ).toHaveTextContent(/Secondary Message/gim);