Commit 7c104cf8 authored by anuraghazra's avatar anuraghazra
Browse files

tests: added tests for renderTopLanguages & top-langs

parent b50555ad
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
require("dotenv").config();
const { renderError, clampValue, CONSTANTS } = require("../src/utils");
const {
  renderError,
  clampValue,
  parseBoolean,
  CONSTANTS,
} = require("../src/utils");
const fetchTopLanguages = require("../src/fetchTopLanguages");
const renderTopLanguages = require("../src/renderTopLanguages");

module.exports = async (req, res) => {
  const {
    username,
    hide_title,
    card_width,
    title_color,
    text_color,
@@ -34,6 +40,7 @@ module.exports = async (req, res) => {
  res.send(
    renderTopLanguages(topLangs, {
      theme,
      hide_title: parseBoolean(hide_title),
      card_width: parseInt(card_width, 10),
      title_color,
      text_color,
+29 −7
Original line number Diff line number Diff line
@@ -7,17 +7,31 @@ const createProgressNode = ({ width, color, name, progress }) => {
  const progressPercentage = clampValue(progress, 2, 100);

  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>
    <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="${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>
  `;
};

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);

@@ -34,8 +48,11 @@ const renderTopLanguages = (topLangs, options = {}) => {
  });

  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 `
    <svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" fill="none" xmlns="http://www.w3.org/2000/svg">
      <style>
@@ -44,9 +61,14 @@ const renderTopLanguages = (topLangs, options = {}) => {
      </style>
      <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({
        items: langs.map((lang) => {
          return createProgressNode({
@@ -58,7 +80,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
        }),
        gap: 40,
        direction: "column",
      })}
      }).join("")}
      </svg>
    </svg>
  `;
+188 −0
Original line number Diff line number Diff line
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 −0
Original line number Diff line number Diff line
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));
  });
});