From 596d0225c63deef50c0d6401e34a101904fe888a Mon Sep 17 00:00:00 2001 From: theanand108 Date: Fri, 17 Apr 2026 01:10:57 +0530 Subject: [PATCH] test: improve branch coverage for CRE API and controllers --- .../controllers/health_controller_test.exs | 8 ++ .../src/domain/cre/creController.test.ts | 37 +++++- .../domain/mapping/mappingController.test.ts | 20 ++- .../api/cre/[edition]/[lang]/server.test.ts | 120 ++++++++++++++++++ 4 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 copi.owasp.org/test/copi_web/controllers/health_controller_test.exs create mode 100644 cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/server.test.ts diff --git a/copi.owasp.org/test/copi_web/controllers/health_controller_test.exs b/copi.owasp.org/test/copi_web/controllers/health_controller_test.exs new file mode 100644 index 000000000..4703952b6 --- /dev/null +++ b/copi.owasp.org/test/copi_web/controllers/health_controller_test.exs @@ -0,0 +1,8 @@ +defmodule CopiWeb.HealthControllerTest do + use CopiWeb.ConnCase + + test "GET /health", %{conn: conn} do + conn = get(conn, "/health") + assert response(conn, 200) + end +end diff --git a/cornucopia.owasp.org/src/domain/cre/creController.test.ts b/cornucopia.owasp.org/src/domain/cre/creController.test.ts index 55e8e72f2..15c126779 100644 --- a/cornucopia.owasp.org/src/domain/cre/creController.test.ts +++ b/cornucopia.owasp.org/src/domain/cre/creController.test.ts @@ -235,6 +235,41 @@ describe('CreController tests', () => { expect(result.links).toHaveLength(0); }); + it('should handle missing CRE mapping data', () => { + mockMappingController.getCardMappings = vi.fn().mockReturnValue({}); + + const mockCard: Card = { + id: 'card-missing-cre', + edition: 'webapp', + suitNameLocal: 'Test', + desc: 'Test', + url: '/test', + suit: 'TS', + value: '4', + lang: 'en' + } as unknown as Card; + + const result = creController.generateDoc(mockCard); + expect(result.links).toHaveLength(0); + }); + + it('should throw when card mapping is undefined', () => { + mockMappingController.getCardMappings = vi.fn().mockReturnValue(undefined); + + const mockCard: Card = { + id: 'card-without-mapping', + edition: 'webapp', + suitNameLocal: 'Test', + desc: 'Test', + url: '/test', + suit: 'TS', + value: '5', + lang: 'en' + } as unknown as Card; + + expect(() => creController.generateDoc(mockCard)).toThrow(); + }); + it('should handle single CRE mapping', () => { mockMappingController.getCardMappings = vi.fn().mockReturnValue({ owasp_cre: { @@ -342,4 +377,4 @@ describe('CreController tests', () => { expect(result.standards).toHaveLength(2); }); }); -}); \ No newline at end of file +}); diff --git a/cornucopia.owasp.org/src/domain/mapping/mappingController.test.ts b/cornucopia.owasp.org/src/domain/mapping/mappingController.test.ts index 0e23007a3..7dcb0d22d 100644 --- a/cornucopia.owasp.org/src/domain/mapping/mappingController.test.ts +++ b/cornucopia.owasp.org/src/domain/mapping/mappingController.test.ts @@ -70,6 +70,24 @@ describe('MappingController tests', () => { expect(Object.keys(webAppMapping2).length).toBe(0); }); + it("should return empty mapping when card id does not match existing cards.", async () => { + const mappingData = { + suits: [ + { + cards: [ + { + id: "different-card" + } + ] + } + ] + }; + const controller = new MappingController(mappingData); + const mapping = controller.getCardMappings("missing-card"); + expect(mapping).toBeDefined(); + expect(Object.keys(mapping).length).toBe(0); + }); + it("should return meta information.", async () => { const mappingData = { meta: { version: "1.0", date: "2024-01-01" }, @@ -81,4 +99,4 @@ describe('MappingController tests', () => { expect(meta.version).toBe("1.0"); expect(meta.date).toBe("2024-01-01"); }); -}); \ No newline at end of file +}); diff --git a/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/server.test.ts b/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/server.test.ts new file mode 100644 index 000000000..5804952c9 --- /dev/null +++ b/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/server.test.ts @@ -0,0 +1,120 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { GET } from './+server'; +import { DeckService } from '$lib/services/deckService'; +import { MappingService } from '$lib/services/mappingService'; + +describe('GET /api/cre/[edition]/[lang]', () => { + beforeEach(() => { + vi.restoreAllMocks(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('throws 404 when language is invalid', () => { + try { + GET({ url: new URL('http://localhost/api/cre/webapp/invalid') } as any); + + expect.fail('Expected GET to throw 404 HttpError'); + } catch (err: any) { + expect(err?.status || err?.body?.status).toBe(404); + } + }); + + it('throws 404 when edition is invalid', () => { + try { + GET({ url: new URL('http://localhost/api/cre/unknown/en') } as any); + + expect.fail('Expected GET to throw 404 HttpError'); + } catch (err: any) { + expect(err?.status || err?.body?.status).toBe(404); + } + }); + + it('throws 500 when cards are not found', () => { + vi.spyOn(DeckService, 'getLatestVersion').mockReturnValue('3.0'); + vi.spyOn(DeckService.prototype, 'getCardDataForEditionVersionLang') + .mockReturnValue(null as any); + + try { + GET({ url: new URL('http://localhost/api/cre/webapp/en') } as any); + + expect.fail('Expected GET to throw 500 HttpError'); + } catch (err: any) { + expect(err?.status || err?.body?.status).toBe(500); + } + }); + + it('throws 500 when mappings are not found', () => { + vi.spyOn(DeckService, 'getLatestVersion').mockReturnValue('3.0'); + + // Ensure cards exist so it reaches mapping check + vi.spyOn(DeckService.prototype, 'getCardDataForEditionVersionLang') + .mockReturnValue(new Map([ + ['VE2', { id: 'VE2' }] + ]) as any); + + vi.spyOn(MappingService.prototype, 'getCardMappingForLatestEdtions') + .mockReturnValue(null as any); + + try { + GET({ url: new URL('http://localhost/api/cre/webapp/en') } as any); + + expect.fail('Expected GET to throw 500 HttpError'); + } catch (err: any) { + expect(err?.status || err?.body?.status).toBe(500); + } + }); + + it('handles missing mapping for specific edition', () => { + vi.spyOn(DeckService, 'getLatestVersion').mockReturnValue('3.0'); + + vi.spyOn(DeckService.prototype, 'getCardDataForEditionVersionLang') + .mockReturnValue(new Map([ + ['VE2', { id: 'VE2' }] + ]) as any); + + // mapping exists but edition missing + vi.spyOn(MappingService.prototype, 'getCardMappingForLatestEdtions') + .mockReturnValue(new Map([['other', {}]]) as any); + + const response = GET({ url: new URL('http://localhost/api/cre/webapp/en') } as any); + + expect(response).toBeDefined(); + }); + + it('returns valid CRE mapping response', () => { + vi.spyOn(DeckService, 'getLatestVersion').mockReturnValue('3.0'); + + vi.spyOn(DeckService.prototype, 'getCardDataForEditionVersionLang') + .mockReturnValue(new Map([ + ['VE2', { + id: 'VE2', + edition: 'webapp', + url: '/cards/VE2', + suitNameLocal: 'Validation', + desc: 'Validate input' + }] + ]) as any); + + vi.spyOn(MappingService.prototype, 'getCardMappingForLatestEdtions') + .mockReturnValue(new Map([ + ['webapp', { + meta: { version: '3.0' }, + suits: [{ + cards: [{ + id: 'VE2', + owasp_cre: { owasp_asvs: ['123-456'] } + }] + }] + }] + ]) as any); + + const response = GET({ url: new URL('http://localhost/api/cre/webapp/en') } as any); + + expect(response).toBeDefined(); +}); + + +}); \ No newline at end of file