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..3e63274 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..17875f5 --- /dev/null +++ b/test/sendProblem.test.js @@ -0,0 +1,14 @@ +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(response.getHeader('Content-Type')).toMatch(/application\/json/) + 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..f0ea59b --- /dev/null +++ b/test/sendSuccess.test.js @@ -0,0 +1,13 @@ +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(response.getHeader('Content-Type')).toMatch(/application\/json/) + expect(data.status).toBe(200) + expect(data.message).toBe('Success') + expect(data.data.test).toBe(true) +}) \ No newline at end of file