From e2eca38ce0fd9cdd19b17b1c9258d7aaf71401a3 Mon Sep 17 00:00:00 2001 From: Mathieu Lefebvre Date: Thu, 12 Oct 2023 16:40:00 -0400 Subject: [PATCH] make local test, banner, git action, gitignore --- .github/workflows/bun-test.yml | 25 +++++++ .gitignore | 133 +++++++++++++++++++++++++++++++++ bun.lockb | Bin 5993 -> 5993 bytes src/banner.ts | 25 +++++++ src/index.ts | 40 +++++++++- src/{query.ts => queries.ts} | 8 ++ test/index.spec.ts | 122 ++++++++++++++++++++++++++++++ 7 files changed, 349 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/bun-test.yml create mode 100644 .gitignore create mode 100644 src/banner.ts rename src/{query.ts => queries.ts} (95%) create mode 100644 test/index.spec.ts diff --git a/.github/workflows/bun-test.yml b/.github/workflows/bun-test.yml new file mode 100644 index 0000000..075278c --- /dev/null +++ b/.github/workflows/bun-test.yml @@ -0,0 +1,25 @@ +on: + push: + branches: + - main +jobs: + bun-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Use Node.js "18" + uses: actions/setup-node@v3 + with: + node-version: '18' + - name: Install bun + uses: oven-sh/setup-bun@v1 + - name: 'Install Dependencies' + run: | + bun install + - name: 'Run test' + run: | + npm run test + env: + HOSTNAME: localhost + PORT: 8080 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..577f4c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,133 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# Sublime Text +*.sublime* \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 4e5f341dc76acc61178bc987ebe5291918e7c1b5..67cb82d96211109f5c82235af5c8370439a03004 100755 GIT binary patch delta 20 bcmaE<_fl_zp&&bBoSB}5p221dK|?kGNj3$v delta 20 YcmaE<_fl_zp&&aG0~lt<8 diff --git a/src/banner.ts b/src/banner.ts new file mode 100644 index 0000000..dad7c6a --- /dev/null +++ b/src/banner.ts @@ -0,0 +1,25 @@ +import pkg from "../package.json" assert { type: "json" }; + +// https://fsymbols.com/generators/carty/ +export function banner() { + let text =` + + ███████╗██████╗░░█████╗░██████╗░░█████╗░  ░█████╗░██████╗░██╗ + ██╔════╝██╔══██╗██╔══██╗╚════██╗██╔══██╗  ██╔══██╗██╔══██╗██║ + █████╗░░██████╔╝██║░░╚═╝░░███╔═╝██║░░██║  ███████║██████╔╝██║ + ██╔══╝░░██╔══██╗██║░░██╗██╔══╝░░██║░░██║  ██╔══██║██╔═══╝░██║ + ███████╗██║░░██║╚█████╔╝███████╗╚█████╔╝  ██║░░██║██║░░░░░██║ + ╚══════╝╚═╝░░╚═╝░╚════╝░╚══════╝░╚════╝░  ╚═╝░░╚═╝╚═╝░░░░░╚═╝ + +` + text += ` 🚀 ${pkg.description} (v${pkg.version}) + + Documentation: ${pkg.homepage} + + HTTP GET + /supply?address=&block= + /contract?address= + /balance?wallet=&address=&block= +` + return text; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index eb1bec9..674a1c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,30 +1,62 @@ import { Hono } from 'hono' -import { getTotalSupply, getContract, getBalance } from './query'; +import { getTotalSupply, getContract, getBalance } from './queries'; import config from './config' +import { HTTPException } from 'hono/http-exception'; + +import { banner } from "./banner"; const app = new Hono() +app.get('/', (c) => c.text(banner())); + app.get('/supply', async (c) => { let res = await getTotalSupply(c.req.query("address"), c.req.query("block")); - console.log(res); + + if (res && (typeof res === 'object') && 'error' in res) { + throw new HTTPException(400, { + message: res.error + }); + } return c.json(res); }) app.get('/contract', async (c) => { let res = await getContract(c.req.query("address")); - console.log(res); + + if (res && (typeof res === 'object') && 'error' in res) { + throw new HTTPException(400, { + message: res.error + }); + } return c.json(res); }) app.get('/balance', async (c) => { let res = await getBalance(c.req.query("wallet"), c.req.query("address"), c.req.query("block")); - console.log(res); + + if (res && (typeof res === 'object') && 'error' in res) { + throw new HTTPException(400, { + message: res.error + }); + } return c.json(res); }) +app.onError((err, c) => { + let error_message = `${err}`; + let error_code = 500; + + if (err instanceof HTTPException){ + error_message = err.message; + error_code = err.status; + } + console.log(error_message) + return c.json({ message: error_message }, error_code); +}); export default { port: config.PORT, fetch: app.fetch, + app: app } \ No newline at end of file diff --git a/src/query.ts b/src/queries.ts similarity index 95% rename from src/query.ts rename to src/queries.ts index eb1c1ec..f18c6c4 100644 --- a/src/query.ts +++ b/src/queries.ts @@ -26,6 +26,10 @@ export async function getTotalSupply(address: string | undefined, block?: string LIMIT 1`; } + else{ + console.log("Invalid Block") + return { error: "Invalid Block" }; + } } else { @@ -109,6 +113,10 @@ export async function getBalance(wallet: string | undefined, address?: string | `; } + else{ + console.log("Invalid Block") + return { error: "Invalid Block" }; + } } //GET balance of a specific contract for a wallet LATEST BLOCK diff --git a/test/index.spec.ts b/test/index.spec.ts new file mode 100644 index 0000000..436601a --- /dev/null +++ b/test/index.spec.ts @@ -0,0 +1,122 @@ +import { describe, expect, it, beforeAll } from 'bun:test'; + +import index from '../src/index'; +import { banner } from "../src/banner"; +import { getTotalSupply, getBalance, getContract } from "../src/queries"; + +describe('Index page (/)', () => { + it('Should return 200 Response', async () => { + const res = await index.app.request('/'); + expect(res.status).toBe(200); + }); + + it('Should have the banner as the body', async () => { + const res = await index.app.request('/'); + expect(await res.text()).toBe(banner()); + }); +}); + +describe('Supply page (/supply)', () => { + + it('Should return 200 Response for valid address', async () => { + + const validAddress = "cb9df5dc2ed5d7d3972f601acfe35cdbe57341e0" + const res = await index.app.request('/supply?address=' + validAddress); + + const json = await res.json() as {message: string}; + expect(res.status === 200 || json.message === "Contract data not available").toBe(true); + }); + + it('Should return 200 Response for valid address and block', async () => { + + const validAddress = "cb9df5dc2ed5d7d3972f601acfe35cdbe57341e0" + const res = await index.app.request('/supply?address=' + validAddress + '&block=1004162'); + + const json = await res.json() as {message: string}; + expect(res.status === 200 || json.message === "Contract data not available").toBe(true); + + }); + + it('Should return 400 Response for invalid address', async () => { + + const validAddress = "awdawd" + const res = await index.app.request('/supply?address=' + validAddress); + expect(res.status).toBe(400); + }); + + it('Should return 400 Response for valid address but invalid block', async () => { + + const validAddress = "cb9df5dc2ed5d7d3972f601acfe35cdbe57341e0" + const res = await index.app.request('/supply?address=' + validAddress + '&block=awdawd'); + expect(res.status).toBe(400); + }); +}); + +describe('Contract page (/contract)', () => { + + it('Should return 200 Response for valid address', async () => { + + const validAddress = "cb9df5dc2ed5d7d3972f601acfe35cdbe57341e0" + const res = await index.app.request('/contract?address=' + validAddress); + const json = await res.json() as {message: string}; + expect(res.status === 200 || json.message === "Contract data not available").toBe(true); + }); + + it('Should return 400 Response for invalid address', async () => { + + const validAddress = "awdawd" + const res = await index.app.request('/contract?address=' + validAddress); + expect(res.status).toBe(400); + }); +}); + + +describe('Balance page (/balance)', () => { + + it('Should return 200 Response for valid address', async () => { + + const validWallet = "0x39fA8c5f2793459D6622857E7D9FbB4BD91766d3" + const res = await index.app.request('/balance?wallet=' + validWallet); + const json = await res.json() as {message: string}; + expect(res.status === 200 || json.message === "Contract data not available").toBe(true); + }); + + it('Should return 200 Response for valid wallet and block', async () => { + + const validWallet = "0x39fA8c5f2793459D6622857E7D9FbB4BD91766d3" + const res = await index.app.request('/balance?wallet=' + validWallet + '&block=1000000'); + const json = await res.json() as {message: string}; + expect(res.status === 200 || json.message === "Contract data not available").toBe(true); + + }); + + + it('Should return 200 Response for valid wallet and valid address', async () => { + + const validWallet = "0x39fA8c5f2793459D6622857E7D9FbB4BD91766d3" + const res = await index.app.request('/balance?wallet=' + validWallet + '&address=0xc083e9947Cf02b8FfC7D3090AE9AEA72DF98FD47'); + const json = await res.json() as {message: string}; + expect(res.status === 200 || json.message === "Contract data not available").toBe(true); + }); + + it('Should return 400 Response for valid wallet and invalid address', async () => { + + const validWallet = "0x39fA8c5f2793459D6622857E7D9FbB4BD91766d3" + const res = await index.app.request('/balance?address=' + validWallet + '&address=3rrw3r'); + expect(res.status).toBe(400); + }); + + it('Should return 400 Response for invalid wallet', async () => { + + const validWallet = "awdawdaw" + const res = await index.app.request('/balance?wallet=' + validWallet); + expect(res.status).toBe(400); + }); + + it('Should return 400 Response for valid wallet but invalid block', async () => { + + const validWallet = "0x39fA8c5f2793459D6622857E7D9FbB4BD91766d3" + const res = await index.app.request('/balance?wallet=' + validWallet + '&block=awdawd'); + expect(res.status).toBe(400); + }); +}); \ No newline at end of file