made some basic structure changes and made some tests too
Test Workflow / test-and-lint (pull_request) Failing after 23s
Test Workflow / test-and-lint (pull_request) Failing after 23s
This commit is contained in:
@@ -1,20 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Check if the lint fix command fails
|
|
||||||
# If it does, exit with a non-zero status to prevent the commit.
|
|
||||||
|
|
||||||
echo "Running lint fix..."
|
|
||||||
# Replace with your actual lint fix command
|
|
||||||
# This is just an example, adapt it to your linter and project
|
|
||||||
npm run lint:fix # e.g., "eslint . --fix"
|
|
||||||
|
|
||||||
# Example: Capture the exit code of the command
|
|
||||||
lint_fix_result=$?
|
|
||||||
|
|
||||||
if [ $lint_fix_result -ne 0 ]; then
|
|
||||||
echo "Linting failed. Commit aborted."
|
|
||||||
exit 1 # Exit with a non-zero status to prevent the commit
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Lint fix completed successfully. Commit allowed."
|
|
||||||
exit 0 # Exit with a zero status to allow the commit
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
name: Test Workflow
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-and-lint:
|
||||||
|
# Use the label matching your registered runner
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Or specify a custom image directly if your runner supports it
|
||||||
|
container:
|
||||||
|
image: node:24-alpine
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Run linter
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: npm test
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
presets: [['@babel/preset-env', {targets: {node: 'current'}}]],
|
||||||
|
}
|
||||||
+7
-4
@@ -4,12 +4,11 @@
|
|||||||
"description": "A basic Express application with PostgreSQL integration.",
|
"description": "A basic Express application with PostgreSQL integration.",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node app.js",
|
|
||||||
"dev": "nodemon app.js",
|
"dev": "nodemon app.js",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"format": "prettier --config prettier.config.js --write .",
|
"migrate": "node-pg-migrate",
|
||||||
"migrate": "node-pg-migrate"
|
"test": "jest --forceExit"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -34,6 +33,9 @@
|
|||||||
"pg": "^8.20.0"
|
"pg": "^8.20.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.29.0",
|
||||||
|
"@babel/preset-env": "^7.29.5",
|
||||||
|
"babel-jest": "^30.4.1",
|
||||||
"eslint": "^10.3.0",
|
"eslint": "^10.3.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-import": "^2.32.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
@@ -41,6 +43,7 @@
|
|||||||
"jest": "^29.0.0",
|
"jest": "^29.0.0",
|
||||||
"node-pg-migrate": "^8.0.4",
|
"node-pg-migrate": "^8.0.4",
|
||||||
"nodemon": "^3.0.0",
|
"nodemon": "^3.0.0",
|
||||||
"prettier": "^3.8.3"
|
"prettier": "^3.8.3",
|
||||||
|
"supertest": "^7.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
import express from 'express'
|
|
||||||
const { Pool } = require('pg')
|
|
||||||
import jwt from 'jsonwebtoken'
|
|
||||||
import bcrypt from 'bcryptjs'
|
|
||||||
|
|
||||||
const router = express.Router()
|
|
||||||
|
|
||||||
// Database connection pool
|
|
||||||
const pool = new Pool({
|
|
||||||
user: process.env.DB_USER,
|
|
||||||
host: process.env.DB_HOST,
|
|
||||||
database: process.env.DB_NAME,
|
|
||||||
password: process.env.DB_PASS,
|
|
||||||
port: process.env.DB_PORT,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Route to handle login and issue JWT token
|
|
||||||
router.post('/login', async (req, res) => {
|
|
||||||
const { username, password } = req.body
|
|
||||||
|
|
||||||
try {
|
|
||||||
const client = await pool.connect()
|
|
||||||
const queryText = 'SELECT * FROM users WHERE username = $1'
|
|
||||||
const result = await client.query(queryText, [username])
|
|
||||||
|
|
||||||
if (!result.rows.length) {
|
|
||||||
return res.status(401).json({ message: 'Invalid credentials' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = result.rows[0]
|
|
||||||
|
|
||||||
// Compare passwords
|
|
||||||
const passwordMatch = await bcrypt.compare(password, user.password)
|
|
||||||
|
|
||||||
if (!passwordMatch) {
|
|
||||||
return res.status(401).json({ message: 'Invalid credentials' })
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issue JWT token
|
|
||||||
const token = jwt.sign({ id: user.id, username: user.username }, process.env.JWT_SECRET, { expiresIn: '1h' })
|
|
||||||
|
|
||||||
res.json({ token })
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
res.status(500).json({ message: 'Internal server error' })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// Route to refresh JWT token
|
|
||||||
router.post('/refresh-token', async (req, res) => {
|
|
||||||
const { refreshToken } = req.body
|
|
||||||
|
|
||||||
if (!refreshToken) {
|
|
||||||
return res.status(401).json({ message: 'Refresh token is required' })
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Verify the refresh token
|
|
||||||
const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET)
|
|
||||||
|
|
||||||
// Create a new access token (JWT)
|
|
||||||
const token = jwt.sign({ id: decoded.id, username: decoded.username }, process.env.JWT_SECRET, { expiresIn: '1h' })
|
|
||||||
|
|
||||||
res.json({ token })
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
res.status(403).json({ message: 'Invalid refresh token' })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
export default router
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import express from 'express'
|
|
||||||
|
|
||||||
const router = exporess.Router()
|
|
||||||
|
|
||||||
router.get('/', (req, res) => res.json({ status: "UP" }))
|
|
||||||
|
|
||||||
export default router
|
|
||||||
@@ -24,3 +24,5 @@ app.use((req, res, next) => {
|
|||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Server listening on port ${port}`)
|
console.log(`Server listening on port ${port}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export default app
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import express from 'express'
|
||||||
|
import jwt from 'jsonwebtoken'
|
||||||
|
import bcrypt from 'bcryptjs'
|
||||||
|
import { database } from '../../config'
|
||||||
|
|
||||||
|
const { Pool } = require('pg')
|
||||||
|
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
// Database connection pool
|
||||||
|
const pool = new Pool(database)
|
||||||
|
|
||||||
|
// Route to handle login and issue JWT token
|
||||||
|
router.post('/login', async (req, res) => {
|
||||||
|
const { username, password } = req.body
|
||||||
|
|
||||||
|
try {
|
||||||
|
const client = await pool.connect()
|
||||||
|
const queryText = 'SELECT * FROM users WHERE username = $1'
|
||||||
|
const result = await client.query(queryText, [username])
|
||||||
|
|
||||||
|
if (!result.rows.length) {
|
||||||
|
return res.status(401).json({ message: 'Invalid credentials' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = result.rows[0]
|
||||||
|
|
||||||
|
// Compare passwords
|
||||||
|
const passwordMatch = await bcrypt.compare(password, user.password)
|
||||||
|
|
||||||
|
if (!passwordMatch) {
|
||||||
|
return res.status(401).json({ message: 'Invalid credentials' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue JWT token
|
||||||
|
const token = jwt.sign(
|
||||||
|
{ id: user.id, username: user.username },
|
||||||
|
process.env.JWT_SECRET,
|
||||||
|
{ expiresIn: '1h' }
|
||||||
|
)
|
||||||
|
|
||||||
|
res.json({ token })
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
res.status(500).json({ message: 'Internal server error' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Route to refresh JWT token
|
||||||
|
router.post('/refresh-token', async (req, res) => {
|
||||||
|
const { refreshToken } = req.body
|
||||||
|
|
||||||
|
if (!refreshToken) {
|
||||||
|
return res.status(401).json({ message: 'Refresh token is required' })
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Verify the refresh token
|
||||||
|
const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET)
|
||||||
|
|
||||||
|
// Create a new access token (JWT)
|
||||||
|
const token = jwt.sign(
|
||||||
|
{ id: decoded.id, username: decoded.username },
|
||||||
|
process.env.JWT_SECRET,
|
||||||
|
{ expiresIn: '1h' }
|
||||||
|
)
|
||||||
|
|
||||||
|
res.json({ token })
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
res.status(403).json({ message: 'Invalid refresh token' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import express from 'express'
|
||||||
|
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.get('/', (req, res) => res.json({ status: 'UP' }))
|
||||||
|
|
||||||
|
export default router
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// src/routes/healthcheck/test.js
|
||||||
|
|
||||||
|
import request from 'supertest'
|
||||||
|
import app from '../../app'
|
||||||
|
|
||||||
|
describe('Health Check Endpoint', () => {
|
||||||
|
it('should respond with status up', async () => {
|
||||||
|
const response = await request(app).get('/healthcheck')
|
||||||
|
|
||||||
|
expect(response.status).toBe(200)
|
||||||
|
expect(response.body).toEqual({ status: 'UP' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return a JSON response', async () => {
|
||||||
|
const response = await request(app).get('/healthcheck')
|
||||||
|
|
||||||
|
expect(response.type).toBe('application/json')
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user