diff --git a/jest.config.js b/jest.config.js index 42a132d348..3fa3d9abd2 100644 --- a/jest.config.js +++ b/jest.config.js @@ -28,6 +28,7 @@ export default { '/scripts/__mocks__/@dicebear/collection.ts', '\\.svg\\?react$': '/scripts/__mocks__/fileMock.js', '\\.svg$': '/scripts/__mocks__/fileMock.js', + '^@pdfme/generator$': '/scripts/__mocks__/@pdfme/generator.ts' }, moduleFileExtensions: [ 'web.js', diff --git a/package-lock.json b/package-lock.json index 4e875229f7..876787bdb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "@mui/x-charts": "^7.22.1", "@mui/x-data-grid": "^7.22.1", "@mui/x-date-pickers": "^7.22.1", - "@pdfme/generator": "^4.5.2", + "@pdfme/generator": "^5.0.0", "@reduxjs/toolkit": "^2.3.0", "@vitejs/plugin-react": "^4.3.2", "babel-plugin-transform-import-meta": "^2.2.1", @@ -4170,9 +4170,9 @@ } }, "node_modules/@pdfme/generator": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/@pdfme/generator/-/generator-4.5.2.tgz", - "integrity": "sha512-lwvNnknTjAlmThkdxNJLcr/1/gYUW1H6xvtdX7t1OSQ/oEJfgcR9oFsUsR+OTnEYDN4zXkAmQbm1K/tnjNQWVA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@pdfme/generator/-/generator-5.0.0.tgz", + "integrity": "sha512-Pb3HrjfPxqVcPAI2RpBx9NlthftoDqbE/5fwfMIrnx6ihNopazvYq0k4R4cEj/NIe38uJkwkXxpJeIlMS0vGcg==", "dependencies": { "@pdfme/pdf-lib": "^1.18.3", "atob": "^2.1.2", diff --git a/package.json b/package.json index f5ac37d35e..6c1e324953 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "@mui/x-charts": "^7.22.1", "@mui/x-data-grid": "^7.22.1", "@mui/x-date-pickers": "^7.22.1", - "@pdfme/generator": "^4.5.2", + "@pdfme/generator": "^5.0.0", "@reduxjs/toolkit": "^2.3.0", "@vitejs/plugin-react": "^4.3.2", "babel-plugin-transform-import-meta": "^2.2.1", diff --git a/scripts/__mocks__/@pdfme/generator.test.ts b/scripts/__mocks__/@pdfme/generator.test.ts new file mode 100644 index 0000000000..592c193a71 --- /dev/null +++ b/scripts/__mocks__/@pdfme/generator.test.ts @@ -0,0 +1,47 @@ +import { generate } from './generator'; +import type { Template } from '@pdfme/common'; + +describe('Testing mock generate util', () => { + test('should return a Promise', async () => { + const result = generate({ + template: { schemas: [] } as Template, + inputs: [], + }); + expect(result).toBeInstanceOf(Promise); + }); + + test('should resolve to a Uint8Array', async () => { + const result = generate({ + template: { schemas: [] } as Template, + inputs: [], + }); + expect(result).toBeInstanceOf(Uint8Array); + }); + + it('should throw an error when template is empty', async () => { + const emptyTemplate = { schemas: [] } as Template; + const validInputs = [{ field1: 'value1' }]; + + await expect( + generate({ template: emptyTemplate, inputs: validInputs }), + ).rejects.toThrow('Template or inputs cannot be empty.'); + }); + + it('should throw an error when inputs are empty', async () => { + const validTemplate = { schemas: [{ name: 'field1' }] } as Template; + const emptyInputs: Record[] = []; + + await expect( + generate({ template: validTemplate, inputs: emptyInputs }), + ).rejects.toThrow('Template or inputs cannot be empty.'); + }); + + it('should throw an error when both template and inputs are empty', async () => { + const emptyTemplate = { schemas: [] } as Template; + const emptyInputs: Record[] = []; + + await expect( + generate({ template: emptyTemplate, inputs: emptyInputs }), + ).rejects.toThrow('Template or inputs cannot be empty.'); + }); +}); diff --git a/scripts/__mocks__/@pdfme/generator.ts b/scripts/__mocks__/@pdfme/generator.ts new file mode 100644 index 0000000000..ac03ae6210 --- /dev/null +++ b/scripts/__mocks__/@pdfme/generator.ts @@ -0,0 +1,22 @@ +import type { Template } from '@pdfme/common'; + +export const generate = async ({ + template, + inputs, +}: { + template: Template; + inputs: Record[]; +}): Promise => { + if (template.schemas.length === 0 || inputs.length === 0) { + // console.log('pdf error: length : ', template, inputs, inputs.length); + throw new Error('Template or inputs cannot be empty.'); + } + // Generate mock PDF-like header bytes + const pdfHeader = [0x25, 0x50, 0x44, 0x46]; // %PDF + // Add some random content based on input size + const contentSize = Math.min(template.schemas.length, inputs.length) * 10; + const mockContent = Array.from({ length: contentSize }, () => + Math.floor(Math.random() * 256), + ); + return Promise.resolve(new Uint8Array([...pdfHeader, ...mockContent])); +}; diff --git a/src/components/CheckIn/TableRow.test.tsx b/src/components/CheckIn/TableRow.test.tsx index 14c3d20c29..1a08f40a3d 100644 --- a/src/components/CheckIn/TableRow.test.tsx +++ b/src/components/CheckIn/TableRow.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, render, waitFor } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; import { TableRow } from './TableRow'; import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; @@ -130,4 +130,45 @@ describe('Testing Table Row for CheckIn Table', () => { expect(await findByText('Error checking in')).toBeInTheDocument(); expect(await findByText('Oops')).toBeInTheDocument(); }); + + test('If PDF generation fails, the error message should be shown', async () => { + const props = { + data: { + id: `123`, + name: '', + userId: `user123`, + checkIn: { + _id: '123', + time: '12:00:00', + }, + eventId: `event123`, + }, + refetch: jest.fn(), + }; + + const { findByText } = render( + + + + + + + + + + + + , + ); + + // Mocking the PDF generation function to throw an error + global.URL.createObjectURL = jest.fn(() => 'mockURL'); + global.window.open = jest.fn(); + + fireEvent.click(await findByText('Download Tag')); + + expect( + await findByText('Error generating pdf: Invalid or empty name provided'), + ).toBeInTheDocument(); + }); }); diff --git a/src/components/CheckIn/TableRow.tsx b/src/components/CheckIn/TableRow.tsx index 38d1dda912..b2bd6e11cb 100644 --- a/src/components/CheckIn/TableRow.tsx +++ b/src/components/CheckIn/TableRow.tsx @@ -66,7 +66,11 @@ export const TableRow = ({ */ const generateTag = async (): Promise => { try { - const inputs = [{ name: data.name }]; + const inputs = []; + if (typeof data.name !== 'string' || !data.name.trim()) { + throw new Error('Invalid or empty name provided'); + } + inputs.push({ name: data.name.trim() }); const pdf = await generate({ template: tagTemplate, inputs }); // istanbul ignore next const blob = new Blob([pdf.buffer], { type: 'application/pdf' });