Tests refactored
This commit is contained in:
13
tests/commonUtils.ts
Normal file
13
tests/commonUtils.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { MockResponseInit } from "jest-fetch-mock";
|
||||||
|
|
||||||
|
export const htmlRes = (translation: string, className = "result-container") => `
|
||||||
|
<div>
|
||||||
|
<div class=${className}>
|
||||||
|
${translation}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const resolveFetchWith = (params: string | MockResponseInit) => (
|
||||||
|
fetchMock.mockResponseOnce(async () => params)
|
||||||
|
);
|
||||||
@@ -1,18 +1,12 @@
|
|||||||
import { screen, waitFor } from "@testing-library/react";
|
import { screen, waitFor } from "@testing-library/react";
|
||||||
import userEvent from "@testing-library/user-event";
|
import userEvent from "@testing-library/user-event";
|
||||||
|
import { htmlRes, resolveFetchWith } from "../commonUtils";
|
||||||
import Router from "next/router";
|
import Router from "next/router";
|
||||||
import { getPage } from "next-page-tester";
|
import { getPage } from "next-page-tester";
|
||||||
import faker from "faker";
|
import faker from "faker";
|
||||||
import { getStaticProps } from "../../pages/[[...slug]]";
|
import { getStaticProps } from "../../pages/[[...slug]]";
|
||||||
|
|
||||||
const mockPush = jest.fn().mockImplementation(async () => true);
|
const mockPush = jest.spyOn(Router, "push").mockImplementation(async () => true);
|
||||||
Router.push = mockPush;
|
|
||||||
|
|
||||||
const html = (translation: string) => `
|
|
||||||
<div class="result-container">
|
|
||||||
${translation}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fetchMock.resetMocks();
|
fetchMock.resetMocks();
|
||||||
@@ -45,7 +39,8 @@ describe("getStaticProps", () => {
|
|||||||
|
|
||||||
it("returns translation & initial values on 3 params", async () => {
|
it("returns translation & initial values on 3 params", async () => {
|
||||||
const translation = faker.random.words();
|
const translation = faker.random.words();
|
||||||
fetchMock.mockResponseOnce(async () => ({ body: html(translation) }));
|
const html = htmlRes(translation);
|
||||||
|
resolveFetchWith(html);
|
||||||
|
|
||||||
const slug = [source, target, query];
|
const slug = [source, target, query];
|
||||||
expect(await getStaticProps({ params: { slug } })).toStrictEqual({
|
expect(await getStaticProps({ params: { slug } })).toStrictEqual({
|
||||||
@@ -72,6 +67,10 @@ describe("Page", () => {
|
|||||||
const query = screen.getByRole("textbox", { name: /query/i });
|
const query = screen.getByRole("textbox", { name: /query/i });
|
||||||
userEvent.type(query, faker.random.words());
|
userEvent.type(query, faker.random.words());
|
||||||
|
|
||||||
|
await waitFor(
|
||||||
|
() => expect(Router.push).not.toHaveBeenCalled(),
|
||||||
|
{ timeout: 250 }
|
||||||
|
);
|
||||||
await waitFor(
|
await waitFor(
|
||||||
() => expect(Router.push).toHaveBeenCalledTimes(1),
|
() => expect(Router.push).toHaveBeenCalledTimes(1),
|
||||||
{ timeout: 2500 }
|
{ timeout: 2500 }
|
||||||
@@ -82,10 +81,10 @@ describe("Page", () => {
|
|||||||
const initial = {
|
const initial = {
|
||||||
source: "ca",
|
source: "ca",
|
||||||
target: "es",
|
target: "es",
|
||||||
query: faker.random.words()
|
query: encodeURIComponent(faker.random.words())
|
||||||
};
|
};
|
||||||
const translation = faker.random.words();
|
const translation = faker.random.words();
|
||||||
fetchMock.mockResponseOnce(async () => ({ body: html(translation) }));
|
resolveFetchWith(htmlRes(translation));
|
||||||
|
|
||||||
const { render } = await getPage({
|
const { render } = await getPage({
|
||||||
route: `/${initial.source}/${initial.target}/${initial.query}`
|
route: `/${initial.source}/${initial.target}/${initial.query}`
|
||||||
@@ -93,22 +92,22 @@ describe("Page", () => {
|
|||||||
render();
|
render();
|
||||||
|
|
||||||
expect(await screen.findByText(translation)).toBeVisible();
|
expect(await screen.findByText(translation)).toBeVisible();
|
||||||
const query = screen.getByRole("textbox", { name: /query/i });
|
|
||||||
expect(query).toHaveValue(encodeURIComponent(initial.query));
|
|
||||||
const source = screen.getByRole("combobox", { name: /source/i });
|
const source = screen.getByRole("combobox", { name: /source/i });
|
||||||
expect(source).toHaveValue(initial.source);
|
expect(source).toHaveValue(initial.source);
|
||||||
const target = screen.getByRole("combobox", { name: /target/i });
|
const target = screen.getByRole("combobox", { name: /target/i });
|
||||||
expect(target).toHaveValue(initial.target);
|
expect(target).toHaveValue(initial.target);
|
||||||
|
const query = screen.getByRole("textbox", { name: /query/i });
|
||||||
|
expect(query).toHaveValue(initial.query);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("parses urlencoding correctly", async () => {
|
it("parses urlencoding correctly", async () => {
|
||||||
const initial = {
|
const initial = {
|
||||||
source: "zh",
|
source: "zh",
|
||||||
target: "en",
|
target: "en",
|
||||||
query: "你好"
|
query: encodeURIComponent("你好")
|
||||||
};
|
};
|
||||||
const translation = "Hello";
|
const translation = "Hello";
|
||||||
fetchMock.mockResponseOnce(async () => ({ body: html(translation) }));
|
resolveFetchWith(htmlRes(translation));
|
||||||
|
|
||||||
const { render } = await getPage({
|
const { render } = await getPage({
|
||||||
route: `/${initial.source}/${initial.target}/${initial.query}`
|
route: `/${initial.source}/${initial.target}/${initial.query}`
|
||||||
@@ -121,11 +120,11 @@ describe("Page", () => {
|
|||||||
const target = screen.getByRole("combobox", { name: /target/i });
|
const target = screen.getByRole("combobox", { name: /target/i });
|
||||||
expect(target).toHaveValue(initial.target);
|
expect(target).toHaveValue(initial.target);
|
||||||
const query = screen.getByRole("textbox", { name: /query/i });
|
const query = screen.getByRole("textbox", { name: /query/i });
|
||||||
expect(query).toHaveValue(encodeURIComponent(initial.query));
|
expect(query).toHaveValue(initial.query);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("switches the page on language change", async () => {
|
it("switches the page on language change", async () => {
|
||||||
fetchMock.mockResponseOnce(async () => ({ body: html(faker.random.words()) }));
|
resolveFetchWith(htmlRes(faker.random.words()));
|
||||||
|
|
||||||
const { render } = await getPage({
|
const { render } = await getPage({
|
||||||
route: `/auto/en/${faker.random.words()}`
|
route: `/auto/en/${faker.random.words()}`
|
||||||
|
|||||||
@@ -1,46 +1,51 @@
|
|||||||
import faker from "faker";
|
import faker from "faker";
|
||||||
import { replaceBoth, retrieveFiltered } from "../../utils/language";
|
import { replaceBoth, retrieveFiltered, CheckType, LangType } from "../../utils/language";
|
||||||
import { languages, exceptions, mappings } from "../../utils/languages.json";
|
import { languages, exceptions, mappings } from "../../utils/languages.json";
|
||||||
|
|
||||||
describe("replaceBoth", () => {
|
describe("replaceBoth", () => {
|
||||||
|
const testReplacer = (
|
||||||
|
checkType: CheckType,
|
||||||
|
checkObj: {
|
||||||
|
[key in LangType]: {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
||||||
|
},
|
||||||
|
langType: LangType
|
||||||
|
) => (
|
||||||
|
Object.entries(checkObj[langType]).forEach(([code, replacement]) => {
|
||||||
|
const res = replaceBoth(checkType, { source: "", target: "", [langType]: code })
|
||||||
|
expect(res[langType]).toBe(replacement);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
it("replaces excepted sources correctly", () => {
|
it("replaces excepted sources correctly", () => {
|
||||||
Object.entries(exceptions.source).forEach(([code, replacement]) => {
|
testReplacer("exception", exceptions, "source");
|
||||||
const { source } = replaceBoth("exception", { source: code, target: "" })
|
|
||||||
expect(source).toBe(replacement);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("replaces excepted targets correctly", () => {
|
it("replaces excepted targets correctly", () => {
|
||||||
Object.entries(exceptions.target).forEach(([code, replacement]) => {
|
testReplacer("exception", exceptions, "target");
|
||||||
const { target } = replaceBoth("exception", { source: "", target: code })
|
|
||||||
expect(target).toBe(replacement);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("replaces mapped sources correctly", () => {
|
it("replaces mapped sources correctly", () => {
|
||||||
Object.entries(mappings.source).forEach(([code, replacement]) => {
|
testReplacer("mapping", mappings, "source");
|
||||||
const { source } = replaceBoth("mapping", { source: code, target: "" })
|
|
||||||
expect(source).toBe(replacement);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("replaces mapped targets correctly", () => {
|
it("replaces mapped targets correctly", () => {
|
||||||
Object.entries(mappings.target).forEach(([code, replacement]) => {
|
testReplacer("mapping", mappings, "target");
|
||||||
const { target } = replaceBoth("mapping", { source: "", target: code })
|
|
||||||
expect(target).toBe(replacement);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("retrieveFiltered", () => {
|
describe("retrieveFiltered", () => {
|
||||||
|
const filteredEntries = (langType: LangType, current: string) => (
|
||||||
|
Object.entries(languages).filter(([code]) => !Object.keys(exceptions[langType]).includes(code) && code !== current)
|
||||||
|
);
|
||||||
|
|
||||||
it("filters by exceptions & by opposite values", () => {
|
it("filters by exceptions & by opposite values", () => {
|
||||||
const source = faker.random.locale();
|
const source = faker.random.locale();
|
||||||
const target = faker.random.locale();
|
const target = faker.random.locale();
|
||||||
const sourceKeys = Object.keys(languages).filter(code => !Object.keys(exceptions.source).includes(code) && code !== target);
|
|
||||||
const targetKeys = Object.keys(languages).filter(code => !Object.keys(exceptions.target).includes(code) && code !== source);
|
|
||||||
|
|
||||||
const { sourceLangs, targetLangs } = retrieveFiltered(source, target);
|
const { sourceLangs, targetLangs } = retrieveFiltered(source, target);
|
||||||
expect(sourceLangs.map(([code]) => code)).toStrictEqual(sourceKeys);
|
expect(sourceLangs).toStrictEqual(filteredEntries("source", target));
|
||||||
expect(targetLangs.map(([code]) => code)).toStrictEqual(targetKeys);
|
expect(targetLangs).toStrictEqual(filteredEntries("target", source));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { htmlRes, resolveFetchWith } from "../commonUtils";
|
||||||
import faker from "faker";
|
import faker from "faker";
|
||||||
import { googleScrape, extractSlug } from "../../utils/translate";
|
import { googleScrape, extractSlug } from "../../utils/translate";
|
||||||
|
|
||||||
@@ -12,20 +13,15 @@ describe("googleScrape", () => {
|
|||||||
|
|
||||||
it("parses html response correctly", async () => {
|
it("parses html response correctly", async () => {
|
||||||
const translation = faker.random.words();
|
const translation = faker.random.words();
|
||||||
const className = "result-container";
|
const html = htmlRes(translation);
|
||||||
const html = `
|
resolveFetchWith(html);
|
||||||
<div class=${className}>
|
|
||||||
${translation}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
fetchMock.mockResponseOnce(async () => ({ body: html }));
|
|
||||||
|
|
||||||
expect(await googleScrape(source, target, query)).toStrictEqual({ translation });
|
expect(await googleScrape(source, target, query)).toStrictEqual({ translation });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns status code on request error", async () => {
|
it("returns status code on request error", async () => {
|
||||||
const status = faker.random.number({ min: 400, max: 499 });
|
const status = faker.random.number({ min: 400, max: 499 });
|
||||||
fetchMock.mockResponseOnce(async () => ({ status }));
|
resolveFetchWith({ status });
|
||||||
|
|
||||||
expect(await googleScrape(source, target, query)).toStrictEqual({ statusCode: status });
|
expect(await googleScrape(source, target, query)).toStrictEqual({ statusCode: status });
|
||||||
});
|
});
|
||||||
@@ -40,12 +36,8 @@ describe("googleScrape", () => {
|
|||||||
it("returns correct message on parsing wrong class", async () => {
|
it("returns correct message on parsing wrong class", async () => {
|
||||||
const translation = faker.random.words();
|
const translation = faker.random.words();
|
||||||
const className = "wrong-container";
|
const className = "wrong-container";
|
||||||
const html = `
|
const html = htmlRes(translation, className);
|
||||||
<div class=${className}>
|
resolveFetchWith(html);
|
||||||
${translation}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
fetchMock.mockResponseOnce(async () => ({ body: html }));
|
|
||||||
|
|
||||||
const res = await googleScrape(source, target, query);
|
const res = await googleScrape(source, target, query);
|
||||||
expect(res?.errorMsg).toMatch(/parsing/);
|
expect(res?.errorMsg).toMatch(/parsing/);
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ import { languages, exceptions, mappings } from "./languages.json";
|
|||||||
const checkTypes = {
|
const checkTypes = {
|
||||||
exception: exceptions,
|
exception: exceptions,
|
||||||
mapping: mappings
|
mapping: mappings
|
||||||
}
|
};
|
||||||
|
|
||||||
type CheckType = keyof typeof checkTypes;
|
export type CheckType = keyof typeof checkTypes;
|
||||||
|
|
||||||
const langTypes = [
|
const langTypes = [
|
||||||
"source",
|
"source",
|
||||||
"target"
|
"target"
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
type LangType = typeof langTypes[number];
|
export type LangType = typeof langTypes[number];
|
||||||
|
|
||||||
const isKeyOf = <T extends object>(obj: T) => (key: keyof any): key is keyof T => key in obj;
|
const isKeyOf = <T extends object>(obj: T) => (key: keyof any): key is keyof T => key in obj;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user