From a6737cbcb352761ecea6cfe24c46ae39e0886920 Mon Sep 17 00:00:00 2001 From: Prantadas Date: Sun, 28 Jul 2024 10:03:40 +0600 Subject: [PATCH] feat: chapter api wrapped and tested --- src/api.ts | 3 ++ src/quran/chapter.test.ts | 70 +++++++++++++++++++++++++++++++++++++++ src/quran/chapter.ts | 39 ++++++++++++++++++++++ src/types.ts | 42 +++++++++++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 src/quran/chapter.test.ts create mode 100644 src/quran/chapter.ts diff --git a/src/api.ts b/src/api.ts index 7d52be6..ce76db2 100644 --- a/src/api.ts +++ b/src/api.ts @@ -27,6 +27,9 @@ const Api = ( }, httpsAgent: keepAliveAgent, maxBodyLength: Infinity, + validateStatus: (status) => { + return status >= 200 && status < 500; + } }); axiosInstance.interceptors.request.use((config) => { diff --git a/src/quran/chapter.test.ts b/src/quran/chapter.test.ts new file mode 100644 index 0000000..4956116 --- /dev/null +++ b/src/quran/chapter.test.ts @@ -0,0 +1,70 @@ +import { ListChapters } from "../types"; +import chapter from "./chapter"; + +describe("Fetch all the chapter according to language", () => { + beforeEach(() => jest.clearAllMocks()); + + it("Should fetch all the chapter", async () => { + const res = await chapter.listChapters() as ListChapters; + expect(res).toHaveProperty('chapters'); + }); + + it("Shoud Throw an error if invalid language code is provided", async () => { + try { + await chapter.listChapters("bla-bla"); + } catch (err: any) { + expect(err.message).toEqual('Provided language is not supported'); + } + }); +}); + +describe("Fetch a specific chapter according to provided chapter id and language", () => { + + beforeEach(() => jest.clearAllMocks()); + + it("Should fetch the chapter when a valid id and language is provided", async () => { + const res: any = await chapter.getChapter(1, 'ha'); + expect(res).toHaveProperty('chapter'); + expect(res.chapter).toHaveProperty('id'); + expect(res.chapter).toHaveProperty('translated_name'); + }); + + + it("Should throw and error if invalid chapter id provided", async () => { + try { + const res: any = await chapter.getChapter(3434343, 'ha'); + expect(res).toHaveProperty('status'); + expect(res.status).toEqual(404); + expect(res.error).toEqual('Surah number or slug is invalid. Please select valid slug or surah number from 1-114.'); + } catch (err: any) { + console.log(err.response); + expect(err.message).toEqual('Request failed with status code 404'); + } + }); +}); + + +describe("Fetching the chapter info", () => { + beforeEach(() => jest.clearAllMocks()); + + it("Should fetch the chapter info according to the chapter id and language provided", async () => { + const res: any = await chapter.getChapterInfo(1, 'ha'); + expect(res).toHaveProperty('chapter_info'); + expect(res.chapter_info).toHaveProperty('id'); + expect(res.chapter_info).toHaveProperty('text'); + expect(res.chapter_info.language_name).toEqual('english'); + }); + + it("Should throw and error if invalid chapter id provided", async () => { + try { + const res: any = await chapter.getChapterInfo(3434343, 'ha'); + expect(res).toHaveProperty('status'); + expect(res.status).toEqual(404); + expect(res.error).toEqual('Surah number or slug is invalid. Please select valid slug or surah number from 1-114.'); + } catch (err: any) { + console.log(err.response); + expect(err.message).toEqual('Request failed with status code 404'); + } + }); + +}); \ No newline at end of file diff --git a/src/quran/chapter.ts b/src/quran/chapter.ts new file mode 100644 index 0000000..0106031 --- /dev/null +++ b/src/quran/chapter.ts @@ -0,0 +1,39 @@ +import { AxiosError } from "axios"; +import Api from "../api"; +import { ChapterApi, ListChapters, Chapter, ChapterInfo } from "../types"; +import { handleError, handleResponse } from "../utils"; + +const api = Api(); + +const ALLOWED_LANGUAGES = new Set(['en', 'ur', 'bn', 'tr', 'es', 'fr', 'bs', 'ru', 'ml', 'id', 'uz', 'nl', 'de', 'tg', 'ta', 'ja', 'it', 'vi', 'zh', 'sq', 'fa', 'bg', 'bm', 'ha', 'pt', 'ro', 'hi', 'sw', 'kk', 'th', 'tl', 'km', 'as', 'ko', 'so', 'az', 'ku', 'dv', 'ms', 'prs', 'zgh', 'am', 'ce', 'cs', 'fi', 'gu', 'he', 'ka', 'kn', 'ks', 'lg', 'mk', 'mr', 'mrn', 'ne', 'no', 'om', 'pl', 'ps', 'rw', 'sd', 'se', 'si', 'sr', 'sv', 'te', 'tt', 'ug', 'uk', 'sq', 'yo']); + + +const chapter: ChapterApi = { + listChapters(language = 'en'): Promise { + const isLanguageSupported = language && ALLOWED_LANGUAGES.has(language); + if (!isLanguageSupported) return Promise.reject(new Error("Provided language is not supported")); + return new Promise((resolve, reject) => { + api.get(`/chapters?${new URLSearchParams({ language })}`) + .then(handleResponse(resolve)) + .catch(handleError(reject)); + }); + }, + getChapter(id: number, language = 'en'): Promise { + if (language && !ALLOWED_LANGUAGES.has(language)) return Promise.reject(new Error("Provided language is not supported")); + return new Promise((resolve, reject) => { + api.get(`/chapters/${id}?${new URLSearchParams({ language })}`) + .then(handleResponse(resolve)) + .catch(handleError(reject)); + }); + }, + getChapterInfo(chapter_id: number, language = 'en'): Promise { + if (language && !ALLOWED_LANGUAGES.has(language)) return Promise.reject(new Error("Provided language is not supported")); + return new Promise((resolve, reject) => { + api.get(`/chapters/${chapter_id}/info?${new URLSearchParams({ language })}`) + .then(handleResponse(resolve)) + .catch(handleError(reject)); + }); + } +}; + +export default chapter; \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index ce3c0af..dca9138 100644 --- a/src/types.ts +++ b/src/types.ts @@ -125,4 +125,46 @@ export interface AudioApi { getAyahRecitationForSpecificRubelHizb(recitation_id: number, rub_el_hizb_number: number): Promise; getAyahRecitationForSpecificHizb(recitation_id: number, hizb_number: number): Promise; getAyahRecitationForSpecificAyah(recitation_id: number, ayah_key: string): Promise; +}; + +export interface ChapterTranslate { + language_name: string; + name: string; +}; + + +export interface Chapter { + id: number; + revelation_place: string; + revelation_order: number; + bismillah_pre: boolean; + name_simple: string; + name_complex: string; + name_arabic: string; + verses_count: number; + pages: number[]; + translated_name: ChapterTranslate; +}; + +export interface ListChapters { + chapters?: Chapter[]; +}; + +export interface ChapterInfo { + id: number; + chapter_id: number; + language_name: string; + short_text: string; + source: string; + text: string; +}; + +export interface ChapterInfoResponse { + chapter_info?: ChapterInfo; +}; + +export interface ChapterApi { + listChapters: (language?: string) => Promise; + getChapter: (id: number, language?: string) => Promise; + getChapterInfo: (chapter_id: number, language?: string) => Promise; }; \ No newline at end of file