From abcedbda879b4b7c136a07c8916b9848a2122ec8 Mon Sep 17 00:00:00 2001 From: Fabiano Eger Date: Thu, 6 Jun 2024 15:02:48 -0300 Subject: [PATCH] unit test and validation message improvements --- src/functions/tagoio-validator.ts | 4 +- src/helpers/build.test.ts | 39 +++++++++++++ src/helpers/create-connectors.ts | 2 +- src/helpers/create-networks.ts | 2 +- src/helpers/resolve-payload.test.ts | 41 ++++++++++++++ src/validator/connector.test.ts | 71 +++++++++++++++++++++++ src/validator/network.test.ts | 87 +++++++++++++++++++++++++++++ 7 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 src/helpers/build.test.ts create mode 100644 src/helpers/resolve-payload.test.ts create mode 100644 src/validator/connector.test.ts create mode 100644 src/validator/network.test.ts diff --git a/src/functions/tagoio-validator.ts b/src/functions/tagoio-validator.ts index 550801e4..3668716c 100644 --- a/src/functions/tagoio-validator.ts +++ b/src/functions/tagoio-validator.ts @@ -59,7 +59,7 @@ async function validateNetworkFiles(directoryPath: string): Promise { const networkPath = path.join(filePath, "network.jsonc"); if (!fs.existsSync(networkPath)) { - throw `Network file not found in ${filePath}`; + throw `network.jsonc manifest file not found in ${filePath}`; } const networkData: Network = JSON.parse( @@ -112,7 +112,7 @@ async function validateConnectorFiles(directoryPath: string): Promise { const connectorPath = path.join(modelPath, "connector.jsonc"); if (!fs.existsSync(connectorPath)) { - throw `Connector file not found in ${modelPath}`; + throw `connector.jsonc manifest file not found in ${modelPath}`; } const connectorData: Connector = JSON.parse( diff --git a/src/helpers/build.test.ts b/src/helpers/build.test.ts new file mode 100644 index 00000000..a4499e4c --- /dev/null +++ b/src/helpers/build.test.ts @@ -0,0 +1,39 @@ +import { describe, it, expect } from 'vitest'; +import { buildTS } from './build-ts'; + +const cleanCode = (code: string): string => { + return code.replace(/\s+/g, ''); +}; + +describe('buildTS function', () => { + it('should transform TypeScript code correctly', () => { + const inputCode = ` + function add(a: number, b: number): number { + return a + b; + } + console.log(add(1, 2)); + `; + + const expectedCode = ` + function add(a, b) { + return a + b; + } + console.log(add(1, 2)); + `; + + const transformedCode = buildTS(inputCode); + + expect(cleanCode(transformedCode)).toBe(cleanCode(expectedCode)); + }); + + it('should throw an error for invalid TypeScript code', () => { + const invalidCode = ` + function add(a: number, b: number) { + return new.Date(); // wrong code + } + console.log(add(1, 2)); + `; + + expect(() => buildTS(invalidCode)).toThrow(); + }); +}); diff --git a/src/helpers/create-connectors.ts b/src/helpers/create-connectors.ts index a5bc6c53..29f264af 100644 --- a/src/helpers/create-connectors.ts +++ b/src/helpers/create-connectors.ts @@ -67,7 +67,7 @@ async function createConnectors(knexClient: Knex, directoryPath: string): Promis const connectorPath = path.join(modelPath, "connector.jsonc"); if (!fs.existsSync(connectorPath)) { - throw `Connector file not found in ${modelPath}`; + throw `connector.jsonc manifest file not found in ${modelPath}`; } const connectorData: Connector = JSON.parse(fs.readFileSync(connectorPath, "utf8")); diff --git a/src/helpers/create-networks.ts b/src/helpers/create-networks.ts index 4f4f9509..7e3d9322 100644 --- a/src/helpers/create-networks.ts +++ b/src/helpers/create-networks.ts @@ -58,7 +58,7 @@ async function createNetworks(knexClient: Knex, directoryPath: string): Promise< } const networkPath = path.join(filePath, "network.jsonc"); if (!fs.existsSync(networkPath)) { - throw `Network file not found in ${filePath}`; + throw `network.jsonc manifest file not found in ${filePath}`; } const networkData: Network = JSON.parse( fs.readFileSync(networkPath, "utf8") diff --git a/src/helpers/resolve-payload.test.ts b/src/helpers/resolve-payload.test.ts new file mode 100644 index 00000000..23d8bcec --- /dev/null +++ b/src/helpers/resolve-payload.test.ts @@ -0,0 +1,41 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { resolvePayload } from './resolve-payload'; // Adjust the path as needed + +// Mock the module dependencies +vi.mock('./read-file', () => ({ + readFileFromPath: () => { + return Buffer.from("Hello JS"); + }, +})); + +vi.mock('./build-ts', () => ({ + buildTS: () => { + return `console.log("Hello, world TS!");`; + }, +})); + +describe('resolvePayload function', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should correctly resolve payload for a TypeScript file', async () => { + const path = '/some/path'; + const filename = 'example.ts'; + + const resultBuff = resolvePayload(path, filename); + + const result = resultBuff.toString(); + expect(result).toBe('console.log("Hello, world TS!");'); + }); + + it('should correctly resolve payload for a non-TypeScript file', async () => { + const path = '/some/path'; + const filename = 'example.js'; + + const resultBuff = resolvePayload(path, filename); + + const result = resultBuff.toString(); + expect(result).toBe('Hello JS'); + }); +}); diff --git a/src/validator/connector.test.ts b/src/validator/connector.test.ts new file mode 100644 index 00000000..96966168 --- /dev/null +++ b/src/validator/connector.test.ts @@ -0,0 +1,71 @@ +import { describe, it, expect } from 'vitest'; +import { zConnector, TypeConnector } from './connector'; // Adjust the path as needed + +describe('zConnector schema', () => { + it('should validate a correct connector object', () => { + const validData = { + id: '123456789012345678901234', + name: 'Test Connector', + version: '1.0.0', + networks: ['network1', 'network2'], + description: 'A test connector description', + install_text: 'Installation instructions', + install_end_text: 'End of installation instructions', + device_annotation: 'Device annotation text', + device_parameters: [{}], + logo: Buffer.from('logo data'), + payload_decoder: Buffer.from('decoder data'), + }; + + const result = zConnector.safeParse(validData); + + expect(result.success).toBe(true); + }); + + it('should fail validation for a connector object with invalid data', () => { + const invalidData = { + id: '123', // too short + name: 'Test Connector', + version: '1.0.0', + networks: [], // empty array + description: 'A very long description that exceeds the maximum allowed length of five hundred characters' + + 'A very long description that exceeds the maximum allowed length of five hundred characters' + + 'A very long description that exceeds the maximum allowed length of five hundred characters' + + 'A very long description that exceeds the maximum allowed length of five hundred characters', + install_text: 'Installation instructions', + install_end_text: 'End of installation instructions', + device_annotation: 'Device annotation text', + device_parameters: { /* add invalid data according to zIntegrationParameters */ }, + logo: 123, // not a buffer or string + payload_decoder: 'too long data that exceeds the 64-byte limit', // too long + }; + + const result = zConnector.safeParse(invalidData); + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.issues[0].path[0]).toBe('networks'); + expect(result.error.issues[0].message).toBe('Array must contain at least 1 element(s)'); + + expect(result.error.issues[1].path[0]).toBe('device_parameters'); + expect(result.error.issues[1].message).toBe('Expected array, received object'); + + expect(result.error.issues[2].path[0]).toBe('logo'); + expect(result.error.issues[2].message).toBe('Invalid input'); + + expect(result.error.issues[3].path[0]).toBe('payload_decoder'); + expect(result.error.issues[3].message).toBe('Invalid Payload Parser'); + } + }); + + it('should transform networks to JSON string', () => { + const data = { + id: '123456789012345678901234', + name: 'Test Connector', + version: '1.0.0', + networks: ['network1', 'network2'], + }; + + const result = zConnector.parse(data); + expect(result.networks).toBe(JSON.stringify(['network1', 'network2'])); + }); +}); diff --git a/src/validator/network.test.ts b/src/validator/network.test.ts new file mode 100644 index 00000000..37613cbb --- /dev/null +++ b/src/validator/network.test.ts @@ -0,0 +1,87 @@ +import { describe, it, expect } from 'vitest'; +import { zNetwork, TypeNetwork } from './network'; // Adjust the path as needed + +describe('zNetwork schema', () => { + it('should validate a correct network object', () => { + const validData = { + id: '123456789012345678901234', + name: 'Test Network', + version: '1.0.0', + description: 'A test network description', + documentation_url: 'http://example.com', + middleware_endpoint: 'middleware.example.com', + serial_number: { + case: 'upper', + image: Buffer.from('image data'), + label: 'Test Label', + mask: 'Test Mask', + required: true, + }, + device_parameters: null, + icon: Buffer.from('icon data'), + logo: 'logo data', + banner: Buffer.from('banner data'), + payload_decoder: Buffer.from('decoder data'), + }; + + const result = zNetwork.safeParse(validData); + + expect(result.success).toBe(true); + }); + + it('should fail validation for a network object with invalid data', () => { + const invalidData = { + id: '123', // too short + name: 'Test Network', + version: '1.0.0', + description: 'A test network description', + documentation_url: 'invalid-url', // not a valid URL + middleware_endpoint: 'invalid-url', // not a valid URL + serial_number: { + case: 'invalid-case', // not a valid enum value + image: 'not a buffer or string', + label: 'A very long label that exceeds the maximum allowed length of one hundred characters' + + 'A very long label that exceeds the maximum allowed length of one hundred characters', + mask: 'A very long mask that exceeds the maximum allowed length of one hundred characters' + + 'A very long mask that exceeds the maximum allowed length of one hundred characters', + required: 'not a boolean', // should be boolean + }, + device_parameters: { /* add invalid data according to zIntegrationParameters */ }, + icon: 123, // not a buffer or string + logo: 123, // not a buffer or string + banner: 123, // not a buffer or string + payload_decoder: 'too long data that exceeds the 64-byte limit', // too long + }; + + const result = zNetwork.safeParse(invalidData); + + expect(result.success).toBe(false); + expect(result.error?.issues[0].path[0]).toBe('middleware_endpoint'); + expect(result.error?.issues[0].message).toBe('Invalid domain'); + expect(result.error?.issues[1].path[0]).toBe('serial_number'); + expect(result.error?.issues[1].message).toBe("Invalid enum value. Expected 'lower' | 'upper' | '', received 'invalid-case'"); + expect(result.error?.issues[2].path[0]).toBe('serial_number'); + expect(result.error?.issues[2].message).toBe('String must contain at most 100 character(s)'); + + }); + + it('should transform serial_number to JSON string', () => { + const data = { + id: '123456789012345678901234', + name: 'Test Network', + version: '1.0.0', + serial_number: { + case: 'lower', + label: 'Test Label', + required: true, + }, + }; + + const result = zNetwork.parse(data); + expect(result.serial_number).toBe(JSON.stringify({ + case: 'lower', + label: 'Test Label', + required: true, + })); + }); +});