* Initial RESTful API

* RESTful API tests

* Scrapping error handling refactored

* Initial GraphQL API

* GraphQL API tests
This commit is contained in:
David
2021-03-28 23:17:47 +02:00
committed by GitHub
parent 7288e9ace7
commit 2938f780aa
15 changed files with 1873 additions and 671 deletions

View File

@@ -0,0 +1,179 @@
import { createTestClient } from "apollo-server-testing";
import { ApolloServer } from "apollo-server-micro";
import faker from "faker";
import { htmlRes, resolveFetchWith } from "../../commonUtils";
import { typeDefs, resolvers } from "../../../pages/api/graphql";
beforeEach(() => {
fetchMock.resetMocks();
});
const { query } = createTestClient(new ApolloServer({ typeDefs, resolvers }));
it("doesn't trigger fetch if neither target nor audio are specified", async () => {
const text = faker.random.words();
const { data } = await query({
query: `
query($text: String!) {
translation(query: $text) {
source {
text
}
}
}
`,
variables: { text }
});
expect(data).toMatchObject({ translation: { source: { text } } });
expect(fetch).not.toHaveBeenCalled();
});
it("returns translation triggering fetch", async () => {
const text = faker.random.words();
const translation = faker.random.words();
resolveFetchWith(htmlRes(translation));
const { data } = await query({
query: `
query($text: String!) {
translation(query: $text) {
target {
text
}
}
}
`,
variables: { text }
});
expect(data).toMatchObject({ translation: { target: { text: translation } } });
expect(fetch).toHaveBeenCalledTimes(1);
});
it("returns audio triggering fetch", async () => {
const lang = faker.random.locale();
const text = faker.random.words();
resolveFetchWith({ status: 200 });
const { data } = await query({
query: `
query($lang: String! $text: String!) {
audio(lang: $lang query: $text) {
lang
text
audio
}
}
`,
variables: { lang, text }
});
expect(data).toMatchObject({ audio: { lang, text, audio: expect.any(Array) } });
expect(fetch).toHaveBeenCalledTimes(1);
});
it("returns null on translation error", async () => {
const text = faker.random.words();
fetchMock.mockRejectOnce();
const { data } = await query({
query: `
query($text: String!) {
translation(query: $text) {
target {
text
}
}
}
`,
variables: { text }
});
expect(data).toMatchObject({ translation: { target: { text: null } } });
});
it("returns null on audio error", async () => {
const lang = faker.random.locale();
const text = faker.random.words();
fetchMock.mockRejectOnce();
const { data } = await query({
query: `
query($lang: String! $text: String!) {
audio(lang: $lang query: $text) {
audio
}
}
`,
variables: { lang, text }
});
expect(data).toMatchObject({ audio: { audio: null } });
});
it("keeps a default value for both source and target languages", async () => {
const text = faker.random.words();
fetchMock.mockRejectOnce();
const { data } = await query({
query: `
query($text: String!) {
translation(query: $text) {
source {
lang
}
target {
lang
}
}
}
`,
variables: { text }
});
expect(data).toMatchObject({ translation: { source: { lang: "auto" }, target: { lang: "en" } } });
});
it("throws error on empty query in translation", async () => {
const { errors } = await query({
query: `
query {
translation {
source {
lang
}
target {
lang
}
}
}
`
});
expect(errors).toBeTruthy();
});
it("throws error on empty lang or query in audio", async () => {
const lang = faker.random.locale();
const text = faker.random.words();
const { errors: queryErrors } = await query({
query: `
query($lang: String!) {
audio(lang: $lang) {
lang
text
}
}
`,
variables: { lang }
});
expect(queryErrors).toBeTruthy();
const { errors: langErrors } = await query({
query: `
query($text: String!) {
audio(query: $text) {
lang
text
}
}
`,
variables: { text }
});
expect(langErrors).toBeTruthy();
});

View File

@@ -0,0 +1,95 @@
import httpMocks from "node-mocks-http";
import faker from "faker";
import { htmlRes, resolveFetchWith } from "../../../commonUtils";
import handler from "../../../../pages/api/v1/[[...slug]]";
beforeEach(() => {
fetchMock.resetMocks();
});
const source = faker.random.locale();
const target = faker.random.locale();
const query = faker.random.words();
const slug = [source, target, query];
it("returns 404 on <3 params", async () => {
const { req, res } = httpMocks.createMocks<any, any>({
method: "GET",
query: { slug: [source, target] }
});
await handler(req, res);
expect(res.statusCode).toBe(404);
});
it("returns 404 on >3 params", async () => {
const { req, res } = httpMocks.createMocks<any, any>({
method: "GET",
query: { slug: [source, target, query, ""] }
});
await handler(req, res);
expect(res.statusCode).toBe(404);
});
it("returns 405 on forbidden method", async () => {
const { req, res } = httpMocks.createMocks<any, any>({
method: "POST",
query: { slug }
});
await handler(req, res);
expect(res.statusCode).toBe(405);
});
it("returns translation on scrapping resolve", async () => {
const translationRes = faker.random.words();
resolveFetchWith(htmlRes(translationRes));
const { req, res } = httpMocks.createMocks<any, any>({
method: "GET",
query: { slug }
});
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(res._getJSONData()).toStrictEqual({ translation: translationRes });
});
it("returns 500 on scrapping error", async () => {
fetchMock.mockRejectOnce();
const { req, res } = httpMocks.createMocks<any, any>({
method: "GET",
query: { slug }
});
await handler(req, res);
expect(res.statusCode).toBe(500);
expect(res._getJSONData()).toStrictEqual({ error: expect.any(String) });
});
it("returns audio on audio request", async () => {
resolveFetchWith({ status: 200 });
const { req, res } = httpMocks.createMocks<any, any>({
method: "GET",
query: { slug: ["audio", target, query] }
});
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(res._getJSONData()).toStrictEqual({ audio: expect.any(Array) });
});
it("returns 500 on audio request error", async () => {
fetchMock.mockRejectOnce();
const { req, res } = httpMocks.createMocks<any, any>({
method: "GET",
query: { slug: ["audio", target, query] }
});
await handler(req, res);
expect(res.statusCode).toBe(500);
});