From 100f2052ee7b14f39415635c0eee1d88c834f7e9 Mon Sep 17 00:00:00 2001 From: NeaByteLab <209737579+NeaByteLab@users.noreply.github.com> Date: Fri, 4 Jul 2025 13:33:59 +0700 Subject: [PATCH 1/2] docs(readme): update README with unit test info, CI, and clean repo :books: --- .github/workflows/test.yml | 24 ++++++++++++++++++++++++ .gitkeep | 0 README.md | 10 +++++++++- package.json | 7 ++++++- src/.keep | 0 src/middleware/.keep | 0 src/routes/.keep | 0 src/utils/.keep | 0 test/.keep | 0 test/errorDocPage.test.js | 12 ++++++++++++ test/sendProblem.test.js | 13 +++++++++++++ test/sendSuccess.test.js | 12 ++++++++++++ 12 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/test.yml delete mode 100644 .gitkeep delete mode 100644 src/.keep delete mode 100644 src/middleware/.keep delete mode 100644 src/routes/.keep delete mode 100644 src/utils/.keep delete mode 100644 test/.keep create mode 100644 test/errorDocPage.test.js create mode 100644 test/sendProblem.test.js create mode 100644 test/sendSuccess.test.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..ba51e82 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,24 @@ +name: Test CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test \ No newline at end of file diff --git a/.gitkeep b/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/README.md b/README.md index d002b80..cd3a85e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # API Standard RFC7807 +![CI](https://github.com/NeaDigitra/API-Standard-RFC7807/actions/workflows/test.yml/badge.svg) + A production-ready Express.js API boilerplate implementing **RFC7807 Problem Details** standard, configurable error documentation, and universal success/error responses. Built for scalable API development with clean PR history and coding standards. --- @@ -12,6 +14,7 @@ A production-ready Express.js API boilerplate implementing **RFC7807 Problem Det * ✅ **Environment-based config with dotenv** * ✅ **Example API route with validation** * ✅ **Express 5 ready** +* ✅ **Built-in unit tests with Jest + node-mocks-http** --- @@ -30,6 +33,10 @@ src/ └── utils/ ├── sendProblem.js # RFC7807 error response helper └── sendSuccess.js # Success response helper +test/ + ├── errorDocPage.test.js # Unit test for HTML generator + ├── sendProblem.test.js # Unit test for RFC7807 helper + └── sendSuccess.test.js # Unit test for success helper ``` --- @@ -50,7 +57,8 @@ ERROR_BASE_URL=https://api.domain.com/errors ```bash npm install -node src/app.js +npm test # run unit tests +npm start # # start the server ``` * Access API: `http://localhost:3000/api/example?email=test@example.com` diff --git a/package.json b/package.json index 526d091..3345299 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "API Standard RFC7807 implementation for error and success response, including documentation generator for organizations.", "main": "index.js", "scripts": { - "start": "node src/app.js" + "start": "node src/app.js", + "test": "jest" }, "repository": { "type": "git", @@ -19,5 +20,9 @@ "dependencies": { "dotenv": "^17.0.1", "express": "^5.1.0" + }, + "devDependencies": { + "jest": "^30.0.4", + "node-mocks-http": "^1.17.2" } } diff --git a/src/.keep b/src/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/middleware/.keep b/src/middleware/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/routes/.keep b/src/routes/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/utils/.keep b/src/utils/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/.keep b/test/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/errorDocPage.test.js b/test/errorDocPage.test.js new file mode 100644 index 0000000..ecf326b --- /dev/null +++ b/test/errorDocPage.test.js @@ -0,0 +1,12 @@ +const errorDocPage = require('../src/middleware/errorDocPage') + +test('should return HTML for known error key', () => { + const html = errorDocPage('validation') + expect(html).toMatch(//) + expect(html).toMatch(/Validation Failed/) +}) + +test('should return null for unknown error key', () => { + const html = errorDocPage('unknown') + expect(html).toBeNull() +}) \ No newline at end of file diff --git a/test/sendProblem.test.js b/test/sendProblem.test.js new file mode 100644 index 0000000..c51bf9d --- /dev/null +++ b/test/sendProblem.test.js @@ -0,0 +1,13 @@ +const sendProblem = require('../src/utils/sendProblem') +const httpMocks = require('node-mocks-http') + +test('should return RFC7807 validation error response', () => { + const response = httpMocks.createResponse() + sendProblem(response, 422, 'validation', 'Input invalid.', '/api/example', { email: ['Invalid'] }) + const data = response._getJSONData() + expect(response.statusCode).toBe(422) + expect(data.type).toMatch(/validation$/) + expect(data.title).toBe('Validation Failed') + expect(data.detail).toBe('Input invalid.') + expect(data.errors).toHaveProperty('email') +}) \ No newline at end of file diff --git a/test/sendSuccess.test.js b/test/sendSuccess.test.js new file mode 100644 index 0000000..6b3cdfd --- /dev/null +++ b/test/sendSuccess.test.js @@ -0,0 +1,12 @@ +const sendSuccess = require('../src/utils/sendSuccess') +const httpMocks = require('node-mocks-http') + +test('should return success response with data', () => { + const response = httpMocks.createResponse() + sendSuccess(response, { test: true }, 'Success') + const data = response._getJSONData() + expect(response.statusCode).toBe(200) + expect(data.status).toBe(200) + expect(data.message).toBe('Success') + expect(data.data.test).toBe(true) +}) \ No newline at end of file From 0b140d27c095b0e3bb299e4fbaf60cd4b9302690 Mon Sep 17 00:00:00 2001 From: NeaByteLab <209737579+NeaByteLab@users.noreply.github.com> Date: Fri, 4 Jul 2025 13:38:21 +0700 Subject: [PATCH 2/2] test(utils): add Content-Type header assertions; docs: fix comment typo :white_check_mark: :pencil: --- README.md | 2 +- test/sendProblem.test.js | 1 + test/sendSuccess.test.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd3a85e..3e63274 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ ERROR_BASE_URL=https://api.domain.com/errors ```bash npm install npm test # run unit tests -npm start # # start the server +npm start # start the server ``` * Access API: `http://localhost:3000/api/example?email=test@example.com` diff --git a/test/sendProblem.test.js b/test/sendProblem.test.js index c51bf9d..17875f5 100644 --- a/test/sendProblem.test.js +++ b/test/sendProblem.test.js @@ -6,6 +6,7 @@ test('should return RFC7807 validation error response', () => { sendProblem(response, 422, 'validation', 'Input invalid.', '/api/example', { email: ['Invalid'] }) const data = response._getJSONData() expect(response.statusCode).toBe(422) + expect(response.getHeader('Content-Type')).toMatch(/application\/json/) expect(data.type).toMatch(/validation$/) expect(data.title).toBe('Validation Failed') expect(data.detail).toBe('Input invalid.') diff --git a/test/sendSuccess.test.js b/test/sendSuccess.test.js index 6b3cdfd..f0ea59b 100644 --- a/test/sendSuccess.test.js +++ b/test/sendSuccess.test.js @@ -6,6 +6,7 @@ test('should return success response with data', () => { sendSuccess(response, { test: true }, 'Success') const data = response._getJSONData() expect(response.statusCode).toBe(200) + expect(response.getHeader('Content-Type')).toMatch(/application\/json/) expect(data.status).toBe(200) expect(data.message).toBe('Success') expect(data.data.test).toBe(true)