tests: added tests for renderTopLanguages & top-langs
This commit is contained in:
parent
b50555ad9a
commit
7c104cf8c5
4 changed files with 367 additions and 8 deletions
|
@ -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,
|
||||||
|
|
|
@ -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>
|
|
||||||
|
${
|
||||||
|
hide_title
|
||||||
|
? ""
|
||||||
|
: `<text data-testid="header" x="25" y="35" class="header">Top Languages</text>`
|
||||||
|
}
|
||||||
|
|
||||||
<svg x="25" y="55">
|
<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>
|
||||||
`;
|
`;
|
||||||
|
|
188
tests/renderTopLanguages.test.js
Normal file
188
tests/renderTopLanguages.test.js
Normal 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
142
tests/top-langs.test.js
Normal 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));
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Reference in a new issue