tests: added tests for renderTopLanguages & top-langs

This commit is contained in:
anuraghazra 2020-07-21 18:04:58 +05:30
parent b50555ad9a
commit 7c104cf8c5
4 changed files with 367 additions and 8 deletions

View file

@ -1,11 +1,17 @@
require("dotenv").config(); require("dotenv").config();
const { renderError, clampValue, CONSTANTS } = require("../src/utils"); const {
renderError,
clampValue,
parseBoolean,
CONSTANTS,
} = require("../src/utils");
const fetchTopLanguages = require("../src/fetchTopLanguages"); const fetchTopLanguages = require("../src/fetchTopLanguages");
const renderTopLanguages = require("../src/renderTopLanguages"); const renderTopLanguages = require("../src/renderTopLanguages");
module.exports = async (req, res) => { module.exports = async (req, res) => {
const { const {
username, username,
hide_title,
card_width, card_width,
title_color, title_color,
text_color, text_color,
@ -34,6 +40,7 @@ module.exports = async (req, res) => {
res.send( res.send(
renderTopLanguages(topLangs, { renderTopLanguages(topLangs, {
theme, theme,
hide_title: parseBoolean(hide_title),
card_width: parseInt(card_width, 10), card_width: parseInt(card_width, 10),
title_color, title_color,
text_color, text_color,

View file

@ -7,17 +7,31 @@ const createProgressNode = ({ width, color, name, progress }) => {
const progressPercentage = clampValue(progress, 2, 100); const progressPercentage = clampValue(progress, 2, 100);
return ` return `
<text x="2" y="15" class="lang-name">${name}</text> <text data-testid="lang-name" x="2" y="15" class="lang-name">${name}</text>
<text x="${progressTextX}" y="34" class="lang-name">${progress}%</text> <text x="${progressTextX}" y="34" class="lang-name">${progress}%</text>
<svg width="${progressWidth}"> <svg width="${progressWidth}">
<rect rx="5" ry="5" x="0" y="25" width="${progressWidth}" height="8" fill="#ddd"></rect> <rect rx="5" ry="5" x="0" y="25" width="${progressWidth}" height="8" fill="#ddd"></rect>
<rect rx="5" ry="5" x="0" y="25" width="${progressPercentage}%" height="8" fill="${color}"></rect> <rect
height="8"
fill="${color}"
rx="5" ry="5" x="0" y="25"
data-testid="lang-progress"
width="${progressPercentage}%"
>
</rect>
</svg> </svg>
`; `;
}; };
const renderTopLanguages = (topLangs, options = {}) => { const renderTopLanguages = (topLangs, options = {}) => {
const { title_color, text_color, bg_color, theme, card_width } = options; const {
hide_title,
card_width,
title_color,
text_color,
bg_color,
theme,
} = options;
const langs = Object.values(topLangs); const langs = Object.values(topLangs);
@ -34,8 +48,11 @@ const renderTopLanguages = (topLangs, options = {}) => {
}); });
const width = isNaN(card_width) ? 300 : card_width; const width = isNaN(card_width) ? 300 : card_width;
const height = 45 + (langs.length + 1) * 40; let height = 45 + (langs.length + 1) * 40;
if (hide_title) {
height -= 30;
}
return ` return `
<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" fill="none" xmlns="http://www.w3.org/2000/svg">
<style> <style>
@ -44,9 +61,14 @@ const renderTopLanguages = (topLangs, options = {}) => {
</style> </style>
<rect data-testid="card-bg" x="0.5" y="0.5" width="99.7%" height="99%" rx="4.5" fill="${bgColor}" stroke="#E4E2E2"/> <rect data-testid="card-bg" x="0.5" y="0.5" width="99.7%" height="99%" rx="4.5" fill="${bgColor}" stroke="#E4E2E2"/>
<text x="25" y="35" class="header">Top Languages</text>
<svg x="25" y="55"> ${
hide_title
? ""
: `<text data-testid="header" x="25" y="35" class="header">Top Languages</text>`
}
<svg data-testid="lang-items" x="25" y="${hide_title ? 25 : 55}">
${FlexLayout({ ${FlexLayout({
items: langs.map((lang) => { items: langs.map((lang) => {
return createProgressNode({ return createProgressNode({
@ -58,7 +80,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
}), }),
gap: 40, gap: 40,
direction: "column", direction: "column",
})} }).join("")}
</svg> </svg>
</svg> </svg>
`; `;

View file

@ -0,0 +1,188 @@
require("@testing-library/jest-dom");
const cssToObject = require("css-to-object");
const renderTopLanguages = require("../src/renderTopLanguages");
const {
getByTestId,
queryByTestId,
queryAllByTestId,
} = require("@testing-library/dom");
const themes = require("../themes");
describe("Test renderTopLanguages", () => {
const langs = {
HTML: {
color: "#0f0",
name: "HTML",
size: 200,
},
javascript: {
color: "#0ff",
name: "javascript",
size: 200,
},
css: {
color: "#ff0",
name: "css",
size: 100,
},
};
it("should render correctly", () => {
document.body.innerHTML = renderTopLanguages(langs);
expect(queryByTestId(document.body, "header")).toHaveTextContent(
"Top Languages"
);
expect(queryAllByTestId(document.body, "lang-name")[0]).toHaveTextContent(
"HTML"
);
expect(queryAllByTestId(document.body, "lang-name")[1]).toHaveTextContent(
"javascript"
);
expect(queryAllByTestId(document.body, "lang-name")[2]).toHaveTextContent(
"css"
);
expect(queryAllByTestId(document.body, "lang-progress")[0]).toHaveAttribute(
"width",
"40%"
);
expect(queryAllByTestId(document.body, "lang-progress")[1]).toHaveAttribute(
"width",
"40%"
);
expect(queryAllByTestId(document.body, "lang-progress")[2]).toHaveAttribute(
"width",
"20%"
);
});
it("should resize the height correctly depending on langs", () => {
document.body.innerHTML = renderTopLanguages(langs, {});
expect(document.querySelector("svg")).toHaveAttribute("height", "205");
document.body.innerHTML = renderTopLanguages(
{
...langs,
python: {
color: "#ff0",
name: "python",
size: 100,
},
},
{}
);
expect(document.querySelector("svg")).toHaveAttribute("height", "245");
});
it("should hide_title", () => {
document.body.innerHTML = renderTopLanguages(langs, { hide_title: false });
expect(document.querySelector("svg")).toHaveAttribute("height", "205");
expect(queryByTestId(document.body, "lang-items")).toHaveAttribute(
"y",
"55"
);
// Lets hide now
document.body.innerHTML = renderTopLanguages(langs, { hide_title: true });
expect(document.querySelector("svg")).toHaveAttribute("height", "175");
expect(queryByTestId(document.body, "header")).not.toBeInTheDocument();
expect(queryByTestId(document.body, "lang-items")).toHaveAttribute(
"y",
"25"
);
});
it("should render with custom width set", () => {
document.body.innerHTML = renderTopLanguages(langs, {});
expect(document.querySelector("svg")).toHaveAttribute("width", "300");
document.body.innerHTML = renderTopLanguages(langs, { card_width: 400 });
expect(document.querySelector("svg")).toHaveAttribute("width", "400");
});
it("should render default colors properly", () => {
document.body.innerHTML = renderTopLanguages(langs);
const styleTag = document.querySelector("style");
const stylesObject = cssToObject(styleTag.textContent);
const headerStyles = stylesObject[".header"];
const langNameStyles = stylesObject[".lang-name"];
expect(headerStyles.fill).toBe("#2f80ed");
expect(langNameStyles.fill).toBe("#333");
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
"fill",
"#FFFEFE"
);
});
it("should render custom colors properly", () => {
const customColors = {
title_color: "5a0",
icon_color: "1b998b",
text_color: "9991",
bg_color: "252525",
};
document.body.innerHTML = renderTopLanguages(langs, { ...customColors });
const styleTag = document.querySelector("style");
const stylesObject = cssToObject(styleTag.innerHTML);
const headerStyles = stylesObject[".header"];
const langNameStyles = stylesObject[".lang-name"];
expect(headerStyles.fill).toBe(`#${customColors.title_color}`);
expect(langNameStyles.fill).toBe(`#${customColors.text_color}`);
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
"fill",
"#252525"
);
});
it("should render custom colors with themes", () => {
document.body.innerHTML = renderTopLanguages(langs, {
title_color: "5a0",
theme: "radical",
});
const styleTag = document.querySelector("style");
const stylesObject = cssToObject(styleTag.innerHTML);
const headerStyles = stylesObject[".header"];
const langNameStyles = stylesObject[".lang-name"];
expect(headerStyles.fill).toBe("#5a0");
expect(langNameStyles.fill).toBe(`#${themes.radical.text_color}`);
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
"fill",
`#${themes.radical.bg_color}`
);
});
it("should render with all the themes", () => {
Object.keys(themes).forEach((name) => {
document.body.innerHTML = renderTopLanguages(langs, {
theme: name,
});
const styleTag = document.querySelector("style");
const stylesObject = cssToObject(styleTag.innerHTML);
const headerStyles = stylesObject[".header"];
const langNameStyles = stylesObject[".lang-name"];
expect(headerStyles.fill).toBe(`#${themes[name].title_color}`);
expect(langNameStyles.fill).toBe(`#${themes[name].text_color}`);
expect(queryByTestId(document.body, "card-bg")).toHaveAttribute(
"fill",
`#${themes[name].bg_color}`
);
});
});
});

142
tests/top-langs.test.js Normal file
View file

@ -0,0 +1,142 @@
require("@testing-library/jest-dom");
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
const topLangs = require("../api/top-langs");
const renderTopLanguages = require("../src/renderTopLanguages");
const { renderError } = require("../src/utils");
const data_langs = {
data: {
user: {
repositories: {
nodes: [
{
languages: {
edges: [{ size: 100, node: { color: "#0f0", name: "HTML" } }],
},
},
{
languages: {
edges: [{ size: 100, node: { color: "#0f0", name: "HTML" } }],
},
},
{
languages: {
edges: [
{ size: 100, node: { color: "#0ff", name: "javascript" } },
],
},
},
{
languages: {
edges: [
{ size: 100, node: { color: "#0ff", name: "javascript" } },
],
},
},
],
},
},
},
};
const error = {
errors: [
{
type: "NOT_FOUND",
path: ["user"],
locations: [],
message: "Could not fetch user",
},
],
};
const langs = {
HTML: {
color: "#0f0",
name: "HTML",
size: 200,
},
javascript: {
color: "#0ff",
name: "javascript",
size: 200,
},
};
const mock = new MockAdapter(axios);
afterEach(() => {
mock.reset();
});
describe("Test /api/top-langs", () => {
it("should test the request", async () => {
const req = {
query: {
username: "anuraghazra",
},
};
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(renderTopLanguages(langs));
});
it("should work with the query options", async () => {
const req = {
query: {
username: "anuraghazra",
hide_title: true,
card_width: 100,
title_color: "fff",
icon_color: "fff",
text_color: "fff",
bg_color: "fff",
},
};
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(
renderTopLanguages(langs, {
hide_title: true,
card_width: 100,
title_color: "fff",
icon_color: "fff",
text_color: "fff",
bg_color: "fff",
})
);
});
it("should render error card on error", async () => {
const req = {
query: {
username: "anuraghazra",
},
};
const res = {
setHeader: jest.fn(),
send: jest.fn(),
};
mock.onPost("https://api.github.com/graphql").reply(200, error);
await topLangs(req, res);
expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
expect(res.send).toBeCalledWith(renderError(error.errors[0].message));
});
});