Skip to content

Commit

Permalink
Merge pull request #1 from Doczilla-APP/improvements
Browse files Browse the repository at this point in the history
chore: Added testing
  • Loading branch information
TriPSs authored Dec 23, 2023
2 parents bbd7adc + 579be5d commit a77f03c
Show file tree
Hide file tree
Showing 14 changed files with 5,563 additions and 152 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
94 changes: 94 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": [
"@typescript-eslint",
"simple-import-sort"
],
"overrides": [
{
"files": [
"*.ts"
],
"rules": {
"no-unneeded-ternary": [
"error"
],
"no-nested-ternary": [
"error"
],
"multiline-ternary": [
"error",
"always-multiline"
],
"operator-linebreak": [
"error",
"before"
],
"simple-import-sort/imports": [
"warn",
{
"groups": [
[
"^@?\\w"
],
// "type" imports.
[
"^.*\\u0000$"
],
// Absolute imports and other imports such as Vue-style `@/foo`.
// Anything not matched in another group.
[
"^"
],
// Relative imports.
// Anything that starts with a dot.
[
"^\\."
]
]
}
],
"simple-import-sort/exports": "warn",
"object-curly-spacing": [
"error",
"always"
],
"quotes": [
"warn",
"single"
],
"func-style": [
"warn",
"declaration"
]
}
},
{
"files": [
"*.spec.ts",
"*.spec.tsx",
"*.spec.js",
"*.spec.jsx"
],
"env": {
"jest": true
},
"rules": {}
},
{
"files": "*.json",
"parser": "jsonc-eslint-parser",
"rules": {}
}
]
}
73 changes: 73 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: "Check PR"
on:
pull_request:

jobs:
build:
name: Build
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Cache node modules
id: cache
uses: actions/cache@v3
with:
path: |
~/.cache
**/node_modules
key: cache-node-modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
cache-node-modules-
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20

- name: yarn install
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: yarn install --immutable

- name: Build
shell: bash
run: yarn build

test:
name: Test (${{ matrix.node }})
needs: [build]
strategy:
matrix:
os:
- "ubuntu-latest"
node:
- "20"
- "18"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2

- name: Setup node
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}

- name: Print Node.js version
run: node -v

- name: Cache node modules
id: cache
uses: actions/cache@v3
with:
path: |
~/.cache
**/node_modules
key: cache-node-modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
cache-node-modules-
- name: Test
run: yarn test
5 changes: 5 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node'
}
19 changes: 17 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,30 @@
"module": "./dist/esm/index.js",
"scripts": {
"build": "tsc && tsc -p tsconfig.esm.json",
"generate:sdk": "node ./generate-models.js && yarn build"
"generate:sdk": "node ./generate-models.js && yarn build",
"lint": "eslint --ext .ts .",
"test": "jest"
},
"dependencies": {
"axios": "^1.6.2"
},
"devDependencies": {
"@jest/globals": "^29.7.0",
"@types/jest": "^29.5.11",
"@types/node": "^20.10.4",
"@typescript-eslint/eslint-plugin": "^6.15.0",
"@typescript-eslint/parser": "^6.15.0",
"axios-mock-adapter": "^1.22.0",
"eslint": "8.56.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-simple-import-sort": "^10.0.0",
"jest": "^29.7.0",
"openapi-typescript-codegen": "^0.25.0",
"ts-jest": "^29.1.1",
"typescript": "^5.3"
},
"packageManager": "[email protected]"
"packageManager": "[email protected]",
"engines": {
"node": ">=18.*"
}
}
6 changes: 5 additions & 1 deletion src/Doczilla.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import axios, { Axios } from 'axios'

import { version } from '../package.json'
import { PdfService } from './services/PdfService'
import { ScreenshotService } from './services/ScreenshotService'
import { WebhookService } from './services/WebhookService'
import { version } from '../package.json'

interface DoczillaOptions {
baseURL?: string
Expand All @@ -18,6 +18,10 @@ export default class Doczilla {
public readonly webhook: WebhookService

constructor(token: string, options: DoczillaOptions = {}) {
if (!token) {
throw new Error('No token provided!')
}

this.client = axios.create({
baseURL: options.baseURL || 'https://api.doczilla.app',
headers: {
Expand Down
19 changes: 19 additions & 0 deletions src/__tests__/Doczilla.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { describe, expect, test } from '@jest/globals'

import Doczilla from '../Doczilla'

describe('Doczilla', () => {

test('it should throw an error if no api key is provided', () => {
let error: Error
try {
// @ts-expect-error
new Doczilla()
} catch (err) {
error = err
}

expect(error.message).toEqual('No token provided!')
})

})
29 changes: 29 additions & 0 deletions src/__tests__/page.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { describe, expect, test } from '@jest/globals'
import MockAdapter from 'axios-mock-adapter'

import Doczilla from '../Doczilla'

describe('Page', () => {

const client = new Doczilla('fake-api-token')
// @ts-expect-error private property
const axiosMock = new MockAdapter(client.client)

axiosMock.onAny().reply(200, Buffer.from(''))

test('it encode the page.html option', async () => {
await client.pdf.direct({
page: {
html: '<div>Your first Doczilla PDF</div>'
}
})

expect(axiosMock.history.post.length).toBe(1)
expect(axiosMock.history.post[0].data).toEqual(JSON.stringify({
page: {
html: 'PGRpdj5Zb3VyIGZpcnN0IERvY3ppbGxhIFBERjwvZGl2Pg=='
}
}))
})

})
37 changes: 37 additions & 0 deletions src/__tests__/pdf.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, expect, test } from '@jest/globals'
import MockAdapter from 'axios-mock-adapter'

import Doczilla from '../Doczilla'

describe('PDF', () => {

const client = new Doczilla('fake-api-token')
// @ts-expect-error private property
const axiosMock = new MockAdapter(client.client)

axiosMock.onAny().reply(200, Buffer.from(''))

test('it should encode the pdf.headerTemplate and pdf.footerTemplate options', async () => {
await client.pdf.direct({
page: {
html: '<div>Your first Doczilla PDF</div>'
},
pdf: {
headerTemplate: '<div>Header template</div>',
footerTemplate: '<div>Footer template</div>'
}
})

expect(axiosMock.history.post.length).toBe(1)
expect(axiosMock.history.post[0].data).toEqual(JSON.stringify({
page: {
html: 'PGRpdj5Zb3VyIGZpcnN0IERvY3ppbGxhIFBERjwvZGl2Pg=='
},
pdf: {
headerTemplate: 'PGRpdj5IZWFkZXIgdGVtcGxhdGU8L2Rpdj4=',
footerTemplate: 'PGRpdj5Gb290ZXIgdGVtcGxhdGU8L2Rpdj4='
}
}))
})

})
29 changes: 27 additions & 2 deletions src/services/BaseService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { Axios, AxiosHeaders, AxiosRequestConfig, isAxiosError } from 'axios'

import type { AsyncPdf, AsyncScreenshot, CreatePdf, CreateScreenshot, SyncPdf, SyncScreenshot } from '../generated'

type PdfRequests = CreatePdf | SyncPdf | AsyncPdf
type ScreenshotRequests = CreateScreenshot | SyncScreenshot | AsyncScreenshot
type RequestBody = PdfRequests | ScreenshotRequests

export class BaseService {

private rateLimit = {
Expand All @@ -16,11 +22,11 @@ export class BaseService {

constructor(private readonly client: Axios) {}

protected async post<T>(url: string, requestBody: object, config: AxiosRequestConfig = {}, retries = 1): Promise<T> {
protected async post<T>(url: string, requestBody: RequestBody, config: AxiosRequestConfig = {}, retries = 1): Promise<T> {
try {
await this.waitForRateLimit()

const axiosResponse = await this.client.post<T>(url, requestBody, config)
const axiosResponse = await this.client.post<T>(url, this.encodeRequestBody(requestBody), config)
this.processRateLimit(new AxiosHeaders(axiosResponse.headers))

if (config.responseType === 'arraybuffer') {
Expand All @@ -37,6 +43,22 @@ export class BaseService {
}
}

private encodeRequestBody(requestBody: PdfRequests): object {
if (requestBody.page.html) {
requestBody.page.html = this.baseEncodeContent(requestBody.page.html)
}

if (requestBody.pdf?.headerTemplate) {
requestBody.pdf.headerTemplate = this.baseEncodeContent(requestBody.pdf.headerTemplate)
}

if (requestBody.pdf?.footerTemplate) {
requestBody.pdf.footerTemplate = this.baseEncodeContent(requestBody.pdf.footerTemplate)
}

return requestBody
}

private async waitForRateLimit(): Promise<void> {
// Minus 1 to be safe
if ((this.rateLimit.remaining - 1) <= 0) {
Expand All @@ -56,4 +78,7 @@ export class BaseService {
}
}

private baseEncodeContent(content: string): string {
return Buffer.from(content).toString('base64')
}
}
1 change: 1 addition & 0 deletions src/services/PdfService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { AsyncJob, AsyncPdf, CreatePdf, SyncJob, SyncPdf } from '../generated'

import { BaseService } from './BaseService'

export class PdfService extends BaseService {
Expand Down
3 changes: 2 additions & 1 deletion src/services/ScreenshotService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BaseService } from './BaseService'
import type { AsyncJob, AsyncScreenshot, CreateScreenshot, SyncJob, SyncScreenshot } from '../generated'

import { BaseService } from './BaseService'

export class ScreenshotService extends BaseService {

/**
Expand Down
Loading

0 comments on commit a77f03c

Please sign in to comment.