UNPKG

jai-server

Version:

Fast , simple and powerful web framework for creating REST APIs for your next project. RESTFul API server

601 lines (481 loc) 17.7 kB
const request = require('supertest'); var JaiServer = require('../dist/index'); const http = require('http'); const path = require('path'); describe('Jai-Server Tests', () => { let app; let server; // Mock middleware that always throws an error const errorMiddleware = (req, res, next) => { throw new Error('Test Error'); }; // Mock middleware that sets an error on the request object const setErrorMiddleware = (req, res, next) => { req.error = new Error('Test error from middleware'); next(req.error); }; // Mock async middleware that rejects const asyncErrorMiddleware = async (req, res, next) => { await Promise.reject(new Error('Async error')); }; beforeEach((done) => { try { app = new JaiServer({ static: { dir: path.join(__dirname, 'public') } }); const randomPort = Math.floor(Math.random() * 1000) + 3000; server = http.createServer(app).listen(randomPort, () => { done() }); app.use('/error-middleware', errorMiddleware, (req, res) => res.send('OK')); app.use('/set-error', setErrorMiddleware, (req, res) => res.send('OK')); app.use('/async-error', asyncErrorMiddleware, (req, res) => res.send('OK')); } catch (e) { console.error("Error starting server:", e); throw e; } }); afterEach((done) => { server.close(() => { done(); }) }); // Basic routing test('GET / should return 200 OK', async () => { app.get('/', (req, res) => { res.status(200).send('Hello, World!'); }); const response = await request(app).get('/'); expect(response.status).toBe(200); expect(response.text).toBe('Hello, World!'); }); //return // Route parameters test('GET /users/:id should return user ID', async () => { app.get('/users/:id', (req, res) => { res.status(200).send(`User ID: ${req.params.id}`); }); const response = await request(server).get('/users/123'); console.log(response.status, response.text); expect(response.status).toBe(200); expect(response.text).toBe('User ID: 123'); }); // Query parameters test('GET /search should handle query parameters', async () => { app.get('/search', (req, res) => { res.status(200).send(`Search query: ${req.query.q}`); }); const response = await request(server).get('/search?q=testquery'); expect(response.status).toBe(200); expect(response.text).toBe('Search query: testquery'); }); // POST request with JSON body test('POST /api/data should handle JSON body', async () => { app.post('/api/data', (req, res) => { res.status(201).json({ received: req.body }); }); const response = await request(server) .post('/api/data') .send({ name: 'John', age: 30 }) .set('Content-Type', 'application/json'); expect(response.status).toBe(201); expect(response.body).toEqual({ received: { name: 'John', age: 30 } }); }); // Middleware test('Middleware should modify request', async () => { app.use((req, res, next) => { req.customProp = 'Modified by middleware'; next(); }); app.get('/middleware-test', (req, res) => { res.status(200).send(req.customProp); }); const response = await request(server).get('/middleware-test'); expect(response.status).toBe(200); expect(response.text).toBe('Modified by middleware'); }); // Error handling // test('Should handle errors', async () => { // app.get('/error', (req, res) => { // throw new Error('Test error'); // }); // app.use((err, req, res, next) => { // res.status(500).json({ error: err.message }); // }); // const response = await request(server).get('/error'); // expect(response.status).toBe(500); // expect(response.body).toEqual({ error: 'Test error' }); // }); // 404 Not Found test('Should return 404 for undefined routes', async () => { const response = await request(server).get('/undefined-route'); expect(response.status).toBe(404); }); // Multiple methods for the same route test('Should handle multiple methods for the same route', async () => { app.get('/multi-method', (req, res) => { res.status(200).send('GET'); }); app.post('/multi-method', (req, res) => { res.status(200).send('POST'); }); const getResponse = await request(server).get('/multi-method'); expect(getResponse.status).toBe(200); expect(getResponse.text).toBe('GET'); const postResponse = await request(server).post('/multi-method'); expect(postResponse.status).toBe(200); expect(postResponse.text).toBe('POST'); }); // Large payload test('Should handle large payload', async () => { app.post('/large-payload', (req, res) => { res.status(200).json({ size: JSON.stringify(req.body).length }); }); const largeObject = { data: 'x'.repeat(1000000) }; // 1MB of data const response = await request(server) .post('/large-payload') .send(largeObject) .set('Content-Type', 'application/json'); expect(response.status).toBe(200); expect(response.body.size).toBeGreaterThan(1000000); }); // Chained middleware test('Should handle chained middleware', async () => { const middleware1 = (req, res, next) => { req.value = 1; next(); }; const middleware2 = (req, res, next) => { req.value += 1; next(); }; app.get('/chained-middleware', middleware1, middleware2, (req, res) => { res.status(200).json({ value: req.value }); }); const response = await request(server).get('/chained-middleware'); expect(response.status).toBe(200); expect(response.body).toEqual({ value: 2 }); }); test('GET request to root path', async () => { app.get('/', (req, res) => { res.send('Hello World!'); }); const response = await request(app).get('/'); expect(response.status).toBe(200); expect(response.text).toBe('Hello World!'); }); test('POST request with JSON body', async () => { app.post('/api/data', (req, res) => { res.json({ received: req.body }); }); const response = await request(app) .post('/api/data') .send({ name: 'John', age: 30 }) .set('Content-Type', 'application/json'); expect(response.status).toBe(200); expect(response.body).toEqual({ received: { name: 'John', age: 30 } }); }); test('Route parameters', async () => { app.get('/users/:id', (req, res) => { res.json({ userId: req.params.id }); }); const response = await request(app).get('/users/123'); expect(response.status).toBe(200); expect(response.body).toEqual({ userId: '123' }); }); test('Custom middleware execution', async () => { const middleware = (req, res, next) => { req.customProp = 'test'; next(); }; app.use(middleware); app.get('/middleware-test', (req, res) => { res.send(req.customProp); }); const response = await request(app).get('/middleware-test'); expect(response.status).toBe(200); expect(response.text).toBe('test'); }); test('Multiple middleware execution order', async () => { const middleware1 = (req, res, next) => { req.order = ['first']; next(); }; const middleware2 = (req, res, next) => { req.order.push('second'); next(); }; app.use(middleware1, middleware2); app.get('/multi-middleware', (req, res) => { res.json(req.order); }); const response = await request(app).get('/multi-middleware'); expect(response.status).toBe(200); expect(response.body).toEqual(['first', 'second']); }); describe('Router', () => { test('Basic Router functionality', async () => { const router = JaiServer.Router(); router.get('/test', (req, res) => { res.send('Router Test'); }); app.use('/router', router); const response = await request(app).get('/router/test'); expect(response.status).toBe(200); expect(response.text).toBe('Router Test'); }); test('Router with middleware', async () => { const router = JaiServer.Router(); router.use((req, res, next) => { req.routerMiddleware = true; next(); }); router.get('/middleware', (req, res) => { res.json({ routerMiddleware: req.routerMiddleware }); }); app.use('/router', router); const response = await request(app).get('/router/middleware'); expect(response.status).toBe(200); expect(response.body).toEqual({ routerMiddleware: true }); }); }); describe('Error Handling', () => { test('404 for undefined routes', async () => { const response = await request(app).get('/undefined-route'); expect(response.status).toBe(404); }); test('Custom error handler', async () => { app.get('/error', (req, res) => { throw new Error('Test error'); }); app.use((err, req, res, next) => { res.status(500).json({ error: err.message }); }); const response = await request(app).get('/error'); expect(response.status).toBe(500); expect(response.body.error).toEqual('Test error'); }); }); describe('Request and Response Objects', () => { test('Request query parameters', async () => { app.get('/query', (req, res) => { res.json(req.query); }); const response = await request(app).get('/query?name=John&age=30'); expect(response.status).toBe(200); expect(response.body).toEqual({ name: 'John', age: '30' }); }); test('Response status and headers', async () => { app.get('/custom-response', (req, res) => { res.status(201).header('X-Custom-Header', 'Test').send('Created'); }); const response = await request(app).get('/custom-response'); expect(response.status).toBe(201); expect(response.headers['x-custom-header']).toBe('Test'); expect(response.text).toBe('Created'); }); test('Request body parsing (JSON)', async () => { app.post('/parse-json', (req, res) => { res.json(req.body); }); const response = await request(app) .post('/parse-json') .send({ key: 'value' }) .set('Content-Type', 'application/json'); expect(response.status).toBe(200); expect(response.body).toEqual({ key: 'value' }); }); test('Request body parsing (URL-encoded)', async () => { app.post('/parse-urlencoded', (req, res) => { console.log(req.body); res.json(req.body); }); const response = await request(app) .post('/parse-urlencoded') .send('key=value') .set('Content-Type', 'application/x-www-form-urlencoded'); expect(response.status).toBe(200); expect(response.body).toEqual({ key: 'value' }); }); }); describe('Static File Serving', () => { test('Serve static files', async () => { // Assuming there's a file named 'test.txt' in the 'public' directory const response = await request(app).get('/public/test.text'); expect(response.status).toBe(200); // Add more specific assertions based on the content of your static files }); }); describe("Throw Error on Build Time", () => { test('Should handle errors on Empty Use', async () => { // THIS WILL THROW ERROR expect(() => app.use()).toThrow(); }); test('Should handle errors on empty Url', async () => { // THIS WILL THROW ERROR expect(() => app.use(null, () => { })).toThrow(); }); test('Should handle errors on Null', async () => { // THIS WILL THROW ERROR expect(() => app.use(null, null, null)).toThrow(); }); test('Should handle errors on Wrong Type', async () => { // THIS WILL THROW ERROR expect(() => app.use(() => { }, () => { }, 1)).toThrow(); }); test('Should handle errors on Valid Url not invalid Middleware', async () => { // THIS WILL THROW ERROR expect(() => app.use('/', 12)).toThrow(); }); }); describe('Middleware Error Handling', () => { test('Synchronous error in middleware', async () => { const response = await request(app).get('/error-middleware'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('error', 'Test Error'); expect(response.body).not.toHaveProperty('stack'); expect(response.body).toHaveProperty('message', 'Internal Server Error - Jai Server'); }); test('Error set on request object', async () => { const response = await request(app).get('/set-error'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('error', 'Test error from middleware'); expect(response.body).not.toHaveProperty('stack'); expect(response.body).toHaveProperty('message', 'Internal Server Error - Jai Server'); }); test('Asynchronous error in middleware', async () => { const response = await request(app).get('/async-error'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('error', 'Async error'); expect(response.body).not.toHaveProperty('stack'); expect(response.body).toHaveProperty('message', 'Internal Server Error - Jai Server'); }); test('Error in middleware stack', async () => { // Add a route with multiple middleware where one throws an error app.use('/middleware-stack', (req, res, next) => next(), errorMiddleware, (req, res) => res.send('OK') ); const response = await request(app).get('/middleware-stack'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('error', 'Test Error'); }); test('Custom error handling middleware', async () => { // Define a custom error handling middleware const customErrorHandler = (err, req, res, next) => { res.status(500).json({ customError: err.message }); }; // Add a route that uses the custom error handler app.use('/custom-error', errorMiddleware); app.use(customErrorHandler); const response = await request(app).get('/custom-error'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('customError', 'Test Error'); }); }); test('Automatic Error Handle When no Error Handler', async () => { app.stack = []; app.get('/error', (req, res) => { throw new Error('Test error'); }); app.use((req, res, next) => { res.status(500).json({ error: err.message }); }); //console.log(app.stack); const response = await request(app).get('/error'); expect(response.status).toBe(500); }) test('Automatic Error Handle When Error Handler available', async () => { app.stack = []; app.get('/error', (req, res) => { throw new Error('Test error'); }); app.use((err, req, res, next) => { res.status(500).json({ error: err.message }); }); //console.log(app.stack); const response = await request(app).get('/error'); expect(response.status).toBe(500); expect(response.body.error).toBe('Test error'); }) test('Nested Router', async () => { app.stack = []; const router = JaiServer.Router(); const routerNested = JaiServer.Router(); router.get('/test', (req, res) => { res.send('Router Test'); }) routerNested.get('*', (req, res) => { res.send('Router Nested') }) router.use(routerNested) app.use(router); app.get('/error', (req, res) => { throw new Error('Test error'); }); //console.log(app.stack); const response = await request(app).get('/error'); expect(response.status).toBe(200); expect(response.text).toBe('Router Nested'); }) test('Nested Router Error', async () => { app.stack = []; const router = JaiServer.Router(); const routerNested = JaiServer.Router(); router.get('/test', (req, res) => { res.send('Router Test'); }) routerNested.get('*', (req, res) => { throw new Error('Router Nested') }) router.use(routerNested) app.use(router); app.get('/error', (req, res) => { throw new Error('Test error'); }); //console.log(app.stack); const response = await request(app).get('/error'); expect(response.status).toBe(500); expect(response.body.error).toBe('Router Nested'); }) test('Multi URL Route', async () => { app.stack = []; jest.clearAllMocks(); const router = JaiServer.Router(); const routerNested = JaiServer.Router(); router.get(['/url1', 'url1', 'url3'], (req, res) => { res.send('Ok'); }) routerNested.get('*', (req, res) => { throw new Error('Router Nested') }) router.use(routerNested) app.use(router); //console.log(app.stack); const response = await request(app).get('/url1'); expect(response.status).toBe(200); expect(response.text).toBe('Ok'); }) test('Multi URL Router', async () => { app.stack = []; jest.clearAllMocks(); const router = JaiServer.Router(); const routerNested = JaiServer.Router(); router.get(['/url1', 'url1', 'url3'], (req, res) => { res.send('Ok'); }) routerNested.get('*', (req, res) => { //throw new Error('Router Nested') res.send("abc") }) router.use(['api1', 'api2'], router, routerNested) app.use(router); //console.log(app.stack); const response = await request(app).get('/api2/url1'); expect(response.status).toBe(200); expect(response.text).toBe('Ok'); }) });