diff --git a/package.json b/package.json index c4f9acb..56521ff 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "start": "node src/index.js", - "test": "jest --coverage" + "test": "NODE_ENV=test jest --coverage" }, "repository": { "type": "git", diff --git a/src/api/badge.js b/src/api/badge.js index ac12604..978314a 100644 --- a/src/api/badge.js +++ b/src/api/badge.js @@ -47,6 +47,9 @@ router.get('/badge', async (req, res) => { const textPadding = Math.round(iconSize * 0.4); const radius = style === 'flat' ? 3 : 0; const textWidth = estimateTextWidth(effectiveLabel, fontSize); + + // Kinyerjük az ikon SVG-ből a width és height attribútumokat (ha vannak) + let iconViewBoxWidth = iconSize; let iconViewBoxHeight = iconSize; const widthMatch = iconSVG.match(/width="(\d+\.?\d*)"/); const heightMatch = iconSVG.match(/height="(\d+\.?\d*)"/); diff --git a/src/lib/logger.js b/src/lib/logger.js index fb548c1..ce6c541 100644 --- a/src/lib/logger.js +++ b/src/lib/logger.js @@ -2,10 +2,12 @@ const pino = require('pino'); +const isTest = process.env.NODE_ENV === 'test'; + const logger = pino({ - level: process.env.LOG_LEVEL || 'info', + level: isTest ? 'silent' : (process.env.LOG_LEVEL || 'info'), transport: - process.env.NODE_ENV !== 'production' + !isTest && process.env.NODE_ENV !== 'production' ? { target: 'pino-pretty', options: { colorize: true } } : undefined, }); diff --git a/test/badge.api.test.js b/test/badge.api.test.js index 0ef12ff..a902a2e 100644 --- a/test/badge.api.test.js +++ b/test/badge.api.test.js @@ -1,94 +1,257 @@ const request = require('supertest'); const express = require('express'); const helmet = require('helmet'); -const badgeRouter = require('../src/api/badge'); -const app = express(); -app.use(helmet({ crossOriginResourcePolicy: false })); -app.use(badgeRouter); +// --- Mock axios before requiring the router --- +jest.mock('axios'); +const axios = require('axios'); + +const MOCK_SVG = `SimpleIcons`; + +beforeEach(() => { + axios.get.mockResolvedValue({ status: 200, data: MOCK_SVG }); +}); + +afterEach(() => { + jest.restoreAllMocks(); +}); + +// Fresh app for each test to avoid middleware leakage +function createApp() { + const badgeRouter = require('../src/api/badge'); + const app = express(); + app.use(helmet({ crossOriginResourcePolicy: false })); + app.use(badgeRouter); + return app; +} describe('GET /badge', () => { + + // --- Basic happy-path tests --- + it('should return SVG with default params', async () => { - const res = await request(app).get('/badge'); - const resBody = Buffer.from(res.body).toString(); + const res = await request(createApp()).get('/badge'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); expect(res.headers['content-type']).toMatch(/image\/svg\+xml/); - expect(resBody).toContain(' { - const res = await request(app).get('/badge?icon=github&label=GitHub'); - const resBody = Buffer.from(res.body).toString(); + const res = await request(createApp()).get('/badge?icon=github&label=GitHub'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); - expect(resBody).toContain('GitHub'); - expect(resBody).toContain(' { - const res = await request(app).get('/badge?icon=github'); - const resBody = Buffer.from(res.body).toString(); + const res = await request(createApp()).get('/badge?icon=github'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); - expect(resBody).toContain(' { - const res = await request(app).get('/badge?bgicon=none'); - const resBody = Buffer.from(res.body).toString(); + const res = await request(createApp()).get('/badge?bgicon=none'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); - expect(resBody).toContain('fill="none"'); + expect(body).toContain('fill="none"'); }); it('should set label background to transparent', async () => { - const res = await request(app).get('/badge?bglabel=none'); - const resBody = Buffer.from(res.body).toString(); + const res = await request(createApp()).get('/badge?bglabel=none'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); - expect(resBody).toContain('fill="none"'); + expect(body).toContain('fill="none"'); }); - it('should use flat style with rounded corners', async () => { - const res = await request(app).get('/badge?style=flat'); - const resBody = Buffer.from(res.body).toString(); + it('should apply custom bgicon and bglabel colours', async () => { + const res = await request(createApp()).get('/badge?bgicon=red&bglabel=blue'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); - expect(resBody).toContain('rx="'); + expect(body).toContain('fill="red"'); + expect(body).toContain('fill="blue"'); }); + it('should apply custom text colour', async () => { + const res = await request(createApp()).get('/badge?color=white'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain('fill="white"'); + }); + + // --- Styles --- + + it('should use flat style with rounded corners (rx=3)', async () => { + const res = await request(createApp()).get('/badge?style=flat'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain('rx="3"'); + }); + + it('should use rect style with square corners (rx=0)', async () => { + const res = await request(createApp()).get('/badge?style=rect'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain('rx="0"'); + }); + + it('should fall back to rect for invalid style', async () => { + const res = await request(createApp()).get('/badge?style=invalid'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain('rx="0"'); + }); + + // --- labelpos --- + it('should handle labelpos left', async () => { - const res = await request(app).get('/badge?labelpos=left'); - const resBody = Buffer.from(res.body).toString(); + const res = await request(createApp()).get('/badge?labelpos=left'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); - expect(resBody).toContain(' { - const res = await request(app).get('/badge?labelpos=above'); - const resBody = Buffer.from(res.body).toString(); + const res = await request(createApp()).get('/badge?labelpos=above'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); - expect(resBody).toContain(' { - const res = await request(app).get('/badge?labelpos=below'); - const resBody = Buffer.from(res.body).toString(); + const res = await request(createApp()).get('/badge?labelpos=below'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); - expect(resBody).toContain(' { - const res = await request(app).get('/badge?fontweight=bold'); - const resBody = Buffer.from(res.body).toString(); + it('should fall back to right for invalid labelpos', async () => { + const res = await request(createApp()).get('/badge?labelpos=diagonal'); + const body = Buffer.from(res.body).toString(); expect(res.statusCode).toBe(200); - expect(resBody).toContain('font-weight="bold"'); + expect(body).toContain(' { - const res = await request(app).get('/badge?icon=notarealicon'); + // --- fontweight --- + + it('should handle custom fontweight bold', async () => { + const res = await request(createApp()).get('/badge?fontweight=bold'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain('font-weight="bold"'); + }); + + it('should handle numeric fontweight 600', async () => { + const res = await request(createApp()).get('/badge?fontweight=600'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain('font-weight="600"'); + }); + + it('should fall back to normal for invalid fontweight', async () => { + const res = await request(createApp()).get('/badge?fontweight=ultra'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain('font-weight="normal"'); + }); + + // --- size --- + + it('should handle minimum valid size (8)', async () => { + const res = await request(createApp()).get('/badge?size=8'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain(' { + const res = await request(createApp()).get('/badge?size=128'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain(' { + const res = await request(createApp()).get('/badge?size=abc'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain(' { + const res = await request(createApp()).get('/badge?size=-5'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain(' { + const res = await request(createApp()).get('/badge?size=9999'); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).toContain(' { + const res = await request(createApp()).get('/badge?label='); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).not.toContain(''); + const body = Buffer.from(res.body).toString(); + expect(res.statusCode).toBe(200); + expect(body).not.toContain('