{
+ const cachedLabel = nomenclatureCache.getLabelFromCache(storeName, id);
+ if (cachedLabel) {
+ return cachedLabel;
+ }
+
+ const items = await this.getNomenclatures(storeName, nomenclatureSourceUri);
+ return items.find(item => item.id === id)?.label;
+ }
+
+}
+
+export const nomenclatureLoaderService = new NomenclatureLoaderService();
\ No newline at end of file
From adc70390f4a8cb1b16c72063d8563277c9c5fc4d Mon Sep 17 00:00:00 2001
From: Mailine Nguyen <64129348+MailineN@users.noreply.github.com>
Date: Fri, 5 Dec 2025 14:19:18 +0100
Subject: [PATCH 3/3] tests: add some tests to the suggester component
---
src/components/Suggester.test.tsx | 137 +++++++++++++++++++++++++
src/components/Suggester.tsx | 2 +-
src/utils/nomenclatureCacheService.ts | 2 +-
src/utils/nomenclatureLoaderService.ts | 2 +-
4 files changed, 140 insertions(+), 3 deletions(-)
create mode 100644 src/components/Suggester.test.tsx
diff --git a/src/components/Suggester.test.tsx b/src/components/Suggester.test.tsx
new file mode 100644
index 0000000..23ab8ab
--- /dev/null
+++ b/src/components/Suggester.test.tsx
@@ -0,0 +1,137 @@
+import { ReactNode } from 'react';
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { Table } from './Table';
+import type { VTLExpression } from '../types';
+import { render, screen } from '@testing-library/react';
+
+import '@testing-library/jest-dom';
+import { nomenclatureCache } from '../utils/nomenclatureCacheService';
+import { Suggester } from './Suggester';
+import { Interpreter } from '../utils/vtl';
+
+vi.mock('../utils/nomenclatureCacheService', () => ({
+ nomenclatureCache: {
+ getLabelFromCache: vi.fn(),
+ },
+}));
+vi.mock('@react-pdf/renderer', () => ({
+ Text: ({ children, style }: any) => {children},
+ View: ({ children, style }: any) => {children}
,
+ StyleSheet: {
+ create: (styles: any) => styles,
+ },
+}));
+
+
+vi.mock('./ValueWithLabel', () => ({
+ ValueWithLabel: ({ children, label, interpret }: any) => {
+ const interpretedLabel = interpret ? interpret(label) : label;
+
+ return (
+
+ {interpretedLabel &&
{interpretedLabel}
}
+ {children}
+
+ );
+ },
+}));
+
+vi.mock('./LunaticComponent', () => ({
+ LunaticComponent: ({ component }: any) => (
+ {component.componentType}
+ ),
+}));
+
+vi.mock('../utils/markdownParser', () => ({
+ renderContent: vi.fn((interpret, label, style) => {
+ const interpretedLabel = interpret(label);
+ return {interpretedLabel};
+ })
+}));
+
+
+const mockInterpret = vi.fn((expr: string | VTLExpression | undefined): ReactNode => {
+ if (typeof expr === 'string') {
+ return '12345';
+ }
+ if (expr && typeof expr === 'object' && 'value' in expr) {
+ return expr.value;
+ }
+ return '';
+});
+
+describe('Suggester Component', () => {
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ mockInterpret.mockClear();
+ });
+
+ const mockProps = {
+ interpret: mockInterpret,
+ id: 'suggester-1',
+ label: { value: 'Select your place', type: 'VTL|MD' } as VTLExpression,
+ response: { name: 'TEST_PLACE' },
+ storeName: 'L_PLACES',
+ componentType: 'Suggester' as const,
+ }
+
+ it('renders collected value and nomenclature label when available', async () => {
+ const mockGetLabel = vi.mocked(nomenclatureCache.getLabelFromCache);
+ mockGetLabel.mockReturnValue('Monoco\'s Station');
+
+ render();
+
+ expect(mockInterpret).toHaveBeenCalledWith('TEST_PLACE');
+ expect(mockGetLabel).toHaveBeenCalledWith('L_PLACES', '12345');
+
+ expect(screen.getByTestId('value-with-label')).toBeInTheDocument();
+ expect(screen.getByTestId('label')).toHaveTextContent('Select your place');
+ expect(screen.getByTestId('pdf-text')).toHaveTextContent("Monoco's Station");
+
+ });
+
+ it('should display __ when response is missing', () => {
+
+ const emptyInterpret = vi.fn(() => undefined) as unknown as Interpreter;
+
+ const mockGetLabel = vi.mocked(nomenclatureCache.getLabelFromCache);
+ mockGetLabel.mockReturnValue(undefined);
+
+ const mockProps = {
+ interpret: emptyInterpret,
+ id: 'suggester-1',
+ label: { value: 'Select your place', type: 'VTL|MD' } as VTLExpression,
+ response: { name: '' },
+ storeName: 'L_PLACES',
+ componentType: 'Suggester' as const,
+ }
+ render();
+
+ expect(mockGetLabel).not.toHaveBeenCalled();
+
+ expect(screen.getByTestId('value-with-label')).toBeInTheDocument();
+ expect(screen.getByTestId('pdf-text')).toHaveTextContent('__');
+ });
+
+ it('renders collected value when nomenclature is not found', () => {
+ const mockGetLabel = vi.mocked(nomenclatureCache.getLabelFromCache);
+ mockGetLabel.mockReturnValue(undefined);
+
+ const mockPropsNoStore = {
+ interpret: mockInterpret,
+ id: 'suggester-1',
+ label: { value: 'Select your place', type: 'VTL|MD' } as VTLExpression,
+ response: { name: 'TEST_PLACE' },
+ storeName: 'UNKNOWN_STORE',
+ componentType: 'Suggester' as const,
+ }
+ render();
+ expect(mockInterpret).toHaveBeenCalledWith('TEST_PLACE');
+
+ expect(screen.getByTestId('value-with-label')).toBeInTheDocument();
+ expect(screen.getByTestId('label')).toHaveTextContent('Select your place');
+ expect(screen.getByTestId('pdf-text')).toHaveTextContent('12345');
+ });
+
+});
diff --git a/src/components/Suggester.tsx b/src/components/Suggester.tsx
index ea8ed73..21dd556 100644
--- a/src/components/Suggester.tsx
+++ b/src/components/Suggester.tsx
@@ -13,7 +13,7 @@ export function Suggester({ interpret, label, response, storeName }: Props) {
// Get label from cache
// TODO: handle missing nomenclature (async fetch if not in cache) not currently handled if the fetching somehow fails
- const nomenclatureLabel = storeName
+ const nomenclatureLabel = storeName && collectedValue
? nomenclatureCache.getLabelFromCache(storeName, collectedValue)
: undefined;
diff --git a/src/utils/nomenclatureCacheService.ts b/src/utils/nomenclatureCacheService.ts
index 46ac206..61d47bc 100644
--- a/src/utils/nomenclatureCacheService.ts
+++ b/src/utils/nomenclatureCacheService.ts
@@ -1,7 +1,7 @@
import { Nomenclature, NomenclatureItem } from "../models/nomenclature";
class NomenclatureCacheService {
- private cache: Map = new Map();
+ readonly cache: Map = new Map();
/**
* Set one nomenclature items in cache
diff --git a/src/utils/nomenclatureLoaderService.ts b/src/utils/nomenclatureLoaderService.ts
index ae7b16d..8518416 100644
--- a/src/utils/nomenclatureLoaderService.ts
+++ b/src/utils/nomenclatureLoaderService.ts
@@ -2,7 +2,7 @@ import { Nomenclature, NomenclatureItem } from "../models/nomenclature";
import { nomenclatureCache } from "./nomenclatureCacheService";
class NomenclatureLoaderService {
- private fetchPromises: Map> = new Map();
+ readonly fetchPromises: Map> = new Map();
/**
* Get nomenclature items by storeName