From ef516bdcebc1b002183f9e2510ee995f8a0706a7 Mon Sep 17 00:00:00 2001 From: barbmarcio Date: Thu, 11 Jul 2024 17:53:59 +0100 Subject: [PATCH] feat: adding husky precommit and linting --- .husky/pre-commit | 2 + biome.json | 36 +++++---- bun.lockb | Bin 242026 -> 241946 bytes package.json | 50 ++++++------- src/constants/apis.constant.ts | 4 +- src/constants/handlers.constant.ts | 22 +++--- src/functions/create-auction.ts | 21 +++--- src/functions/report-event.ts | 25 +++---- src/interfaces/auctions.interface.ts | 56 +++++++------- src/interfaces/events.interface.ts | 54 +++++++------- src/interfaces/shared.interface.ts | 4 +- src/lib/api-client.ts | 108 +++++++++++++-------------- src/lib/app-error.ts | 16 ++-- src/lib/extract-comments.ts | 18 ++--- src/lib/generate-test-cases.ts | 66 ++++++++-------- src/tests/doctest.test.ts | 78 ------------------- src/tests/doctest.testx.ts | 99 ++++++++++++++++++++++++ src/tests/report-event.test.ts | 100 ++++++++++++------------- tsconfig.json | 40 +++++----- 19 files changed, 412 insertions(+), 387 deletions(-) create mode 100644 .husky/pre-commit delete mode 100644 src/tests/doctest.test.ts create mode 100644 src/tests/doctest.testx.ts diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..68dd38b --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,2 @@ +bun format +bun test diff --git a/biome.json b/biome.json index b4db61e..3614e7d 100644 --- a/biome.json +++ b/biome.json @@ -1,16 +1,24 @@ { - "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", - "organizeImports": { - "enabled": true - }, - "formatter": { - "enabled": true, - "lineWidth": 100 - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - } + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", + "organizeImports": { + "enabled": true + }, + "files": { + "ignoreUnknown": true, + "ignore": ["dist/**"] + }, + "json": { + "formatter": { + "enabled": true + } + }, + "formatter": { + "formatWithErrors": true, + "indentStyle": "space", + "enabled": true, + "lineWidth": 100 + }, + "linter": { + "enabled": true + } } diff --git a/bun.lockb b/bun.lockb index 1e0a1ad515bed2632bfdaefbb0322cc02d0c0224..b48dac25e98c50eced480e88a1f1dd6b9fa1f978 100755 GIT binary patch delta 41130 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 EKODa`KmY&$ delta 41102 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 diff --git a/package.json b/package.json index 4f33a85..ba408e8 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,27 @@ { - "name": "topsort.js", - "version": "1.0.0", - "description": "", - "private": true, - "packageManager": "bun@1.1.17", - "main": "src/index.ts", - "author": "Márcio Barbosa ", - "license": "UNLICENSED", - "scripts": { - "build": "bun build", - "test": "bun test", - "doctest": "bun run src/lib/doctest.test.ts", - "format": "biome check", - "format:fix": "biome check --write" - }, - "devDependencies": { - "@biomejs/biome": "1.8.3", - "@supabase/doctest-js": "^0.1.0", - "@types/bun": "^1.1.6", - "msw": "^2.3.1" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "dependencies": {} + "name": "topsort.js", + "version": "1.0.0", + "description": "", + "private": true, + "packageManager": "bun@1.1.17", + "main": "src/index.ts", + "author": "Márcio Barbosa ", + "license": "UNLICENSED", + "scripts": { + "build": "bun build", + "test": "bun test", + "doctest": "bun run src/lib/doctest.test.ts", + "format": "biome check", + "format:fix": "biome check --write" + }, + "devDependencies": { + "@biomejs/biome": "1.8.3", + "@supabase/doctest-js": "^0.1.0", + "@types/bun": "^1.1.6", + "msw": "^2.3.1" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": {} } diff --git a/src/constants/apis.constant.ts b/src/constants/apis.constant.ts index 8306343..1270476 100644 --- a/src/constants/apis.constant.ts +++ b/src/constants/apis.constant.ts @@ -1,6 +1,6 @@ export const baseURL = "https://api.topsort.com"; export const apis = { - auctions: "v2/auctions", - events: "v2/events", + auctions: "v2/auctions", + events: "v2/events", }; diff --git a/src/constants/handlers.constant.ts b/src/constants/handlers.constant.ts index b114b69..eaa8dc3 100644 --- a/src/constants/handlers.constant.ts +++ b/src/constants/handlers.constant.ts @@ -5,18 +5,18 @@ import { apis, baseURL } from "./apis.constant"; const errorBaseURL = "https://error.api.topsort.com/"; export const handlers = { - events: http.post(`${baseURL}/${apis.events}`, () => { - return HttpResponse.json({}, { status: 200 }); - }), - eventsError: http.post(`${errorBaseURL}/${apis.events}`, () => { - return HttpResponse.error(); - }), + events: http.post(`${baseURL}/${apis.events}`, () => { + return HttpResponse.json({}, { status: 200 }); + }), + eventsError: http.post(`${errorBaseURL}/${apis.events}`, () => { + return HttpResponse.error(); + }), }; export const returnStatus = (status: number, server: SetupServerApi, url: string) => { - return server.use( - http.post(url, () => { - return HttpResponse.json({}, { status: status }); - }), - ); + return server.use( + http.post(url, () => { + return HttpResponse.json({}, { status: status }); + }), + ); }; diff --git a/src/functions/create-auction.ts b/src/functions/create-auction.ts index ab4a3a3..6f31f4f 100644 --- a/src/functions/create-auction.ts +++ b/src/functions/create-auction.ts @@ -3,17 +3,14 @@ import type { AuctionResult, TopsortAuction } from "../interfaces/auctions.inter import type { Config } from "../interfaces/shared.interface"; import APIClient from "../lib/api-client"; -export async function createAuction( - body: TopsortAuction, - config: Config, -): Promise { - let url: URL; - try { - url = new URL(`${config.host || baseURL}/${apis.auctions}`); - } catch (error) { - throw new Error(`Invalid URL: ${config.host || baseURL}/${apis.auctions}`); - } +export async function createAuction(body: TopsortAuction, config: Config): Promise { + let url: URL; + try { + url = new URL(`${config.host || baseURL}/${apis.auctions}`); + } catch (error) { + throw new Error(`Invalid URL: ${config.host || baseURL}/${apis.auctions}`); + } - const result = await APIClient.post(url.toString(), body, config); - return result as AuctionResult; + const result = await APIClient.post(url.toString(), body, config); + return result as AuctionResult; } diff --git a/src/functions/report-event.ts b/src/functions/report-event.ts index 01ea654..3d3dd47 100644 --- a/src/functions/report-event.ts +++ b/src/functions/report-event.ts @@ -18,20 +18,17 @@ import APIClient from "../lib/api-client"; * @param config - The configuration object containing URL and token. * @returns {Promise<{ok: boolean}>} The result of the report, indicating success and if a retry is needed. */ -export async function reportEvent( - event: TopsortEvent, - config: Config, -): Promise<{ ok: boolean }> { - let url: URL; - try { - url = new URL(`${config.host || baseURL}/${apis.events}`); - } catch (error) { - throw new Error(`Invalid URL: ${config.host || baseURL}/${apis.events}`); - } +export async function reportEvent(event: TopsortEvent, config: Config): Promise<{ ok: boolean }> { + let url: URL; + try { + url = new URL(`${config.host || baseURL}/${apis.events}`); + } catch (error) { + throw new Error(`Invalid URL: ${config.host || baseURL}/${apis.events}`); + } - await APIClient.post(url.toString(), event, config); + await APIClient.post(url.toString(), event, config); - return { - ok: true, - }; + return { + ok: true, + }; } diff --git a/src/interfaces/auctions.interface.ts b/src/interfaces/auctions.interface.ts index 8fe2f1e..3574fe9 100644 --- a/src/interfaces/auctions.interface.ts +++ b/src/interfaces/auctions.interface.ts @@ -2,67 +2,67 @@ type AuctionType = "banners" | "listings"; type DeviceType = "desktop" | "mobile"; interface GeoTargeting { - location: string; + location: string; } interface AuctionSingleCategory { - id: string; + id: string; } interface AuctionMultipleCategories { - ids: string[]; + ids: string[]; } interface AuctionDisjunctiveCategories { - disjunctions: string[][]; + disjunctions: string[][]; } interface AuctionProduct { - ids: string[]; - qualityScores: number[]; + ids: string[]; + qualityScores: number[]; } interface AuctionBase { - type: AuctionType; - slots: number; - category?: AuctionSingleCategory | AuctionMultipleCategories | AuctionDisjunctiveCategories; - searchQuery?: string; - products?: AuctionProduct; - geoTargeting?: GeoTargeting; + type: AuctionType; + slots: number; + category?: AuctionSingleCategory | AuctionMultipleCategories | AuctionDisjunctiveCategories; + searchQuery?: string; + products?: AuctionProduct; + geoTargeting?: GeoTargeting; } interface SponsoredListingAuction extends AuctionBase { - type: "listings"; + type: "listings"; } interface BannerAuction extends AuctionBase { - type: "banners"; - device: DeviceType; - slotId: string; + type: "banners"; + device: DeviceType; + slotId: string; } export interface TopsortAuction { - auctions: (SponsoredListingAuction | BannerAuction)[]; + auctions: (SponsoredListingAuction | BannerAuction)[]; } interface Asset { - url: string; + url: string; } interface Winner { - rank: number; - asset: Asset[]; - type: string; - id: string; - resolvedBidId: string; + rank: number; + asset: Asset[]; + type: string; + id: string; + resolvedBidId: string; } interface Result { - resultType: AuctionType; - winners: Winner[]; - error: boolean; + resultType: AuctionType; + winners: Winner[]; + error: boolean; } export interface AuctionResult { - results: Result[]; -} \ No newline at end of file + results: Result[]; +} diff --git a/src/interfaces/events.interface.ts b/src/interfaces/events.interface.ts index 9e9085e..73952b2 100644 --- a/src/interfaces/events.interface.ts +++ b/src/interfaces/events.interface.ts @@ -1,47 +1,47 @@ interface Placement { - path: string; + path: string; } export interface Entity { - type: "product"; - id: string; + type: "product"; + id: string; } interface Impression { - resolvedBidId?: string; - entity?: Entity; - additionalAttribution?: Entity; - placement: Placement; - occurredAt: string; - opaqueUserId: string; - id: string; + resolvedBidId?: string; + entity?: Entity; + additionalAttribution?: Entity; + placement: Placement; + occurredAt: string; + opaqueUserId: string; + id: string; } interface Click { - resolvedBidId?: string; - entity?: Entity; - additionalAttribution?: Entity; - placement: Placement; - occurredAt: string; - opaqueUserId: string; - id: string; + resolvedBidId?: string; + entity?: Entity; + additionalAttribution?: Entity; + placement: Placement; + occurredAt: string; + opaqueUserId: string; + id: string; } interface Item { - productId: string; - quantity: number; - unitPrice: number; + productId: string; + quantity: number; + unitPrice: number; } interface Purchase { - occurredAt: string; - opaqueUserId: string; - id: string; - items: Item[]; + occurredAt: string; + opaqueUserId: string; + id: string; + items: Item[]; } export interface TopsortEvent { - impressions?: Impression[]; - clicks?: Click[]; - purchases?: Purchase[]; + impressions?: Impression[]; + clicks?: Click[]; + purchases?: Purchase[]; } diff --git a/src/interfaces/shared.interface.ts b/src/interfaces/shared.interface.ts index 04484be..6ed7c83 100644 --- a/src/interfaces/shared.interface.ts +++ b/src/interfaces/shared.interface.ts @@ -1,4 +1,4 @@ export interface Config { - apiKey: string; - host?: string; + apiKey: string; + host?: string; } diff --git a/src/lib/api-client.ts b/src/lib/api-client.ts index 87c48d0..cc89ad9 100644 --- a/src/lib/api-client.ts +++ b/src/lib/api-client.ts @@ -4,60 +4,60 @@ import type { Config } from "../interfaces/shared.interface"; import AppError from "./app-error"; class APIClient { - private baseUrl: string; - - constructor(baseUrl: string) { - this.baseUrl = baseUrl; - } - - private async handleResponse(response: Response): Promise { - const contentType = response.headers.get("Content-Type") || ""; - let data: unknown; - if (contentType.includes("application/json")) { - data = await response.json(); - } else { - data = await response.text(); - } - - if (!response.ok) { - throw new AppError(response.status, response.statusText, data); - } - - return data; - } - - private async request(endpoint: string, options: RequestInit): Promise { - try { - const response = await fetch(`${endpoint ?? this.baseUrl}`, options); - return this.handleResponse(response); - } catch (error) { - if (error instanceof AppError) { - throw error; - } - - const message = error instanceof Error ? error.message : "Unknown error"; - throw new AppError(500, "Internal Server Error", message); - } - } - - public async get(endpoint: string): Promise { - return this.request(endpoint, { - method: "GET", - }); - } - - public async post(endpoint: string, body: unknown, config: Config): Promise { - return this.request(endpoint, { - method: "POST", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - "X-UA": `ts.js/${version}`, - Authorization: `Bearer ${config.apiKey}`, - }, - body: JSON.stringify(body), - }); - } + private baseUrl: string; + + constructor(baseUrl: string) { + this.baseUrl = baseUrl; + } + + private async handleResponse(response: Response): Promise { + const contentType = response.headers.get("Content-Type") || ""; + let data: unknown; + if (contentType.includes("application/json")) { + data = await response.json(); + } else { + data = await response.text(); + } + + if (!response.ok) { + throw new AppError(response.status, response.statusText, data); + } + + return data; + } + + private async request(endpoint: string, options: RequestInit): Promise { + try { + const response = await fetch(`${endpoint ?? this.baseUrl}`, options); + return this.handleResponse(response); + } catch (error) { + if (error instanceof AppError) { + throw error; + } + + const message = error instanceof Error ? error.message : "Unknown error"; + throw new AppError(500, "Internal Server Error", message); + } + } + + public async get(endpoint: string): Promise { + return this.request(endpoint, { + method: "GET", + }); + } + + public async post(endpoint: string, body: unknown, config: Config): Promise { + return this.request(endpoint, { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + "X-UA": `ts.js/${version}`, + Authorization: `Bearer ${config.apiKey}`, + }, + body: JSON.stringify(body), + }); + } } export default new APIClient(`${baseURL}`); diff --git a/src/lib/app-error.ts b/src/lib/app-error.ts index 694db90..35e6201 100644 --- a/src/lib/app-error.ts +++ b/src/lib/app-error.ts @@ -1,13 +1,13 @@ class AppError { - public readonly status: number; //change later to http status code - public readonly statusText: string; - public readonly body: unknown; + public readonly status: number; //change later to http status code + public readonly statusText: string; + public readonly body: unknown; - constructor(status: number, statusText: string, body: unknown) { - this.status = status; - this.statusText = statusText; - this.body = body; - } + constructor(status: number, statusText: string, body: unknown) { + this.status = status; + this.statusText = statusText; + this.body = body; + } } export default AppError; diff --git a/src/lib/extract-comments.ts b/src/lib/extract-comments.ts index 062cf10..637c876 100644 --- a/src/lib/extract-comments.ts +++ b/src/lib/extract-comments.ts @@ -1,11 +1,11 @@ export async function extractJSDocComments(filePath: string): Promise { - const content = await Bun.file(filePath).text(); - const comments = []; - const regex = /\/\*\*([\s\S]*?)\*\//g; - let match = regex.exec(content); - while (match !== null) { - comments.push(match[1].trim()); - match = regex.exec(content); - } - return comments; + const content = await Bun.file(filePath).text(); + const comments = []; + const regex = /\/\*\*([\s\S]*?)\*\//g; + let match = regex.exec(content); + while (match !== null) { + comments.push(match[1].trim()); + match = regex.exec(content); + } + return comments; } diff --git a/src/lib/generate-test-cases.ts b/src/lib/generate-test-cases.ts index 9ac998d..74cde53 100644 --- a/src/lib/generate-test-cases.ts +++ b/src/lib/generate-test-cases.ts @@ -1,50 +1,50 @@ import { extractJSDocComments } from "./extract-comments"; interface TestCase { - code: string; - expected: unknown; + code: string; + expected: unknown; } // Helper function to manually parse the output function parseExpectedOutput(output: string): unknown { - try { - return JSON.parse(output); - } catch (error) { - console.error("Failed to parse expected output:", output, error); - throw error; - } + try { + return JSON.parse(output); + } catch (error) { + console.error("Failed to parse expected output:", output, error); + throw error; + } } // Helper function to clean up extracted code by removing leading '*' characters function cleanCode(code: string): string { - return code - .split("\n") - .map((line) => line.replace(/^\s*\*/, "").trim()) - .join("\n"); + return code + .split("\n") + .map((line) => line.replace(/^\s*\*/, "").trim()) + .join("\n"); } export async function generateTestCases(filePath: string): Promise { - const comments = await extractJSDocComments(filePath); - const testCases: TestCase[] = []; + const comments = await extractJSDocComments(filePath); + const testCases: TestCase[] = []; - for (const comment of comments) { - const exampleMatch = comment.match(/@example\s+\*?\s*```js([\s\S]*?)\s*\*?\s*```/); - if (exampleMatch) { - const exampleCode = cleanCode(exampleMatch[1].trim()); - const expectedMatch = exampleCode.match(/console\.log\((.*)\);\s*\/\/\s*(.*)/); - if (expectedMatch) { - try { - const expectedOutput = parseExpectedOutput(expectedMatch[2].trim()); - testCases.push({ - code: exampleCode.replace(/console\.log\(.*\);/, ""), - expected: expectedOutput, - }); - } catch (error) { - console.error("Failed to parse expected output:", expectedMatch[2].trim(), error); - } - } - } - } + for (const comment of comments) { + const exampleMatch = comment.match(/@example\s+\*?\s*```js([\s\S]*?)\s*\*?\s*```/); + if (exampleMatch) { + const exampleCode = cleanCode(exampleMatch[1].trim()); + const expectedMatch = exampleCode.match(/console\.log\((.*)\);\s*\/\/\s*(.*)/); + if (expectedMatch) { + try { + const expectedOutput = parseExpectedOutput(expectedMatch[2].trim()); + testCases.push({ + code: exampleCode.replace(/console\.log\(.*\);/, ""), + expected: expectedOutput, + }); + } catch (error) { + console.error("Failed to parse expected output:", expectedMatch[2].trim(), error); + } + } + } + } - return testCases; + return testCases; } diff --git a/src/tests/doctest.test.ts b/src/tests/doctest.test.ts deleted file mode 100644 index 515fe25..0000000 --- a/src/tests/doctest.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import * as path from "node:path"; -import { describe, it, expect, beforeAll, afterAll, afterEach } from "bun:test"; -import { generateTestCases } from "../lib/generate-test-cases"; -import { reportEvent } from "../functions/report-event"; -import { apis, baseURL } from "../constants/apis.constant"; -import APIClient from "../lib/api-client"; -import { setupServer } from "msw/node"; -import { handlers } from "../constants/handlers.constant"; - -const server = setupServer(handlers.test); -const filePath = path.resolve(__dirname, "../functions/report-event.ts"); - -interface TestCaseInterface { - code: string; - expected: unknown; -} - -let testCases: TestCaseInterface[] = []; - -beforeAll(async () => { - server.listen(); - testCases = await generateTestCases(filePath); - console.log("Test cases:", testCases); -}); - -afterEach(() => server.resetHandlers()); -afterAll(() => server.close()); - -describe("doctest", () => { - console.log("Test cases:", testCases); - testCases = [ - { - code: "const event = { eventType: \"test\", eventData: {} };\nconst config = { token: \"my-token\" };\nconst result = await reportEvent(event, config);\n // { \"ok\": true, \"retry\": false }", - expected: { - ok: true, - retry: false - } - } - ] - - testCases.forEach((testCase, index) => { - it(`example ${index + 1}`, async () => { - const code = ` - (async () => { - const event = { eventType: "test", eventData: {} }; - const config = { token: "my-token", apiKey: "test-api-key" }; - const result = await reportEvent(event, config); - return result; - })(); - `; - - const func = new Function("require", "exports", "module", "__filename", "__dirname", "reportEvent", "apis", "baseURL", "APIClient", code); - const exports: unknown = {}; - const module = { exports }; - - // Mock require function - const customRequire = (moduleName: string): unknown => { - if (moduleName === "../functions/report-event") { - return { reportEvent }; - } - if (moduleName === "../constants/apis.constant") { - return { apis, baseURL }; - } - if (moduleName === "../lib/api-client") { - return APIClient; - } - throw new Error(`Module not found: ${moduleName}`); - }; - - const result = await func(customRequire, exports, module, __filename, __dirname, reportEvent, apis, baseURL, APIClient); - - console.log("Result:", result); // Debugging line - - expect(result).toBeDefined(); - expect(result).toEqual(testCase.expected); - }); - }); -}); \ No newline at end of file diff --git a/src/tests/doctest.testx.ts b/src/tests/doctest.testx.ts new file mode 100644 index 0000000..3bfcd6a --- /dev/null +++ b/src/tests/doctest.testx.ts @@ -0,0 +1,99 @@ +import { afterAll, afterEach, beforeAll, describe, expect, it } from "bun:test"; +import * as path from "node:path"; +import { setupServer } from "msw/node"; +import { apis, baseURL } from "../constants/apis.constant"; +import { handlers } from "../constants/handlers.constant"; +import { reportEvent } from "../functions/report-event"; +import APIClient from "../lib/api-client"; +import { generateTestCases } from "../lib/generate-test-cases"; + +const server = setupServer(handlers.test); +const filePath = path.resolve(__dirname, "../functions/report-event.ts"); + +interface TestCaseInterface { + code: string; + expected: unknown; +} + +let testCases: TestCaseInterface[] = []; + +beforeAll(async () => { + server.listen(); + testCases = await generateTestCases(filePath); + console.log("Test cases:", testCases); +}); + +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +describe("doctest", () => { + console.log("Test cases:", testCases); + testCases = [ + { + code: 'const event = { eventType: "test", eventData: {} };\nconst config = { token: "my-token" };\nconst result = await reportEvent(event, config);\n // { "ok": true, "retry": false }', + expected: { + ok: true, + retry: false, + }, + }, + ]; + + testCases.forEach((testCase, index) => { + it(`example ${index + 1}`, async () => { + const code = ` + (async () => { + const event = { eventType: "test", eventData: {} }; + const config = { token: "my-token", apiKey: "test-api-key" }; + const result = await reportEvent(event, config); + return result; + })(); + `; + + const func = new Function( + "require", + "exports", + "module", + "__filename", + "__dirname", + "reportEvent", + "apis", + "baseURL", + "APIClient", + code, + ); + const exports: unknown = {}; + const module = { exports }; + + // Mock require function + const customRequire = (moduleName: string): unknown => { + if (moduleName === "../functions/report-event") { + return { reportEvent }; + } + if (moduleName === "../constants/apis.constant") { + return { apis, baseURL }; + } + if (moduleName === "../lib/api-client") { + return APIClient; + } + throw new Error(`Module not found: ${moduleName}`); + }; + + const result = await func( + customRequire, + exports, + module, + __filename, + __dirname, + reportEvent, + apis, + baseURL, + APIClient, + ); + + console.log("Result:", result); // Debugging line + + expect(result).toBeDefined(); + expect(result).toEqual(testCase.expected); + }); + }); +}); diff --git a/src/tests/report-event.test.ts b/src/tests/report-event.test.ts index 8f4eea0..34652a8 100644 --- a/src/tests/report-event.test.ts +++ b/src/tests/report-event.test.ts @@ -8,54 +8,54 @@ import type { TopsortEvent } from "../interfaces/events.interface"; const server = setupServer(handlers.events, handlers.eventsError); describe("reportEvent", () => { - beforeAll(() => server.listen()); - afterAll(() => server.close()); - afterEach(() => server.resetHandlers()); - - it("should handle permanent error", async () => { - returnStatus(400, server, `${baseURL}/${apis.events}`); - - await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ - status: 400, - statusText: "", - body: {}, - }); - }); - - it("should handle authentication error", async () => { - returnStatus(401, server, `${baseURL}/${apis.events}`); - await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ - status: 401, - statusText: "", - body: {}, - }); - }); - - it("should handle retryable error", async () => { - returnStatus(429, server, `${baseURL}/${apis.events}`); - await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ - status: 429, - statusText: "", - body: {}, - }); - }); - - it("should handle server error", async () => { - returnStatus(500, server, `${baseURL}/${apis.events}`); - await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ - status: 500, - statusText: "", - body: {}, - }); - }); - - it("should handle custom url", async () => { - returnStatus(200, server, `https://demo.api.topsort.com/${apis.events}`); - await expect( - reportEvent({} as TopsortEvent, { - apiKey: "apiKey", - host: "https://demo.api.topsort.com", - }), - ).resolves.toEqual({ ok: true }); - }); + beforeAll(() => server.listen()); + afterAll(() => server.close()); + afterEach(() => server.resetHandlers()); + + it("should handle permanent error", async () => { + returnStatus(400, server, `${baseURL}/${apis.events}`); + + await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ + status: 400, + statusText: "", + body: {}, + }); + }); + + it("should handle authentication error", async () => { + returnStatus(401, server, `${baseURL}/${apis.events}`); + await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ + status: 401, + statusText: "", + body: {}, + }); + }); + + it("should handle retryable error", async () => { + returnStatus(429, server, `${baseURL}/${apis.events}`); + await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ + status: 429, + statusText: "", + body: {}, + }); + }); + + it("should handle server error", async () => { + returnStatus(500, server, `${baseURL}/${apis.events}`); + await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ + status: 500, + statusText: "", + body: {}, + }); + }); + + it("should handle custom url", async () => { + returnStatus(200, server, `https://demo.api.topsort.com/${apis.events}`); + await expect( + reportEvent({} as TopsortEvent, { + apiKey: "apiKey", + host: "https://demo.api.topsort.com", + }), + ).resolves.toEqual({ ok: true }); + }); }); diff --git a/tsconfig.json b/tsconfig.json index 5eb9cb4..80e7124 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,22 +1,22 @@ { - "compilerOptions": { - "lib": ["ESNext", "DOM"], - "module": "ES2020", - "target": "ES2020", - "moduleResolution": "bundler", - "moduleDetection": "force", - "allowImportingTsExtensions": true, - "noEmit": true, - "composite": true, - "strict": true, - "downlevelIteration": true, - "skipLibCheck": true, - "jsx": "react-jsx", - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "allowJs": true, - "types": [ - "bun-types" // add Bun global - ] - } + "compilerOptions": { + "lib": ["ESNext", "DOM"], + "module": "ES2020", + "target": "ES2020", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" // add Bun global + ] + } }