Skip to content

Commit ab46ca1

Browse files
committed
added testing for app.ts and mapping.ts
1 parent 1165fb2 commit ab46ca1

File tree

4 files changed

+421
-2
lines changed

4 files changed

+421
-2
lines changed

src/tests/app.test.ts

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
import request from 'supertest';
2+
import app from '../app';
3+
import { authUrl, redeemCode } from '../auth';
4+
import * as properties from '../properties';
5+
import * as mappings from '../mappings';
6+
import * as utils from '../utils/utils';
7+
import { describe, beforeEach, it, expect, jest } from '@jest/globals';
8+
import { afterAll, beforeAll } from '@jest/globals';
9+
10+
const Objects = {
11+
Contact: 'Contact',
12+
Company: 'Company'
13+
} as const;
14+
15+
const PropertyType = {
16+
String: 'String',
17+
Number: 'Number',
18+
Option: 'Option'
19+
} as const;
20+
21+
const Direction = {
22+
toHubSpot: 'toHubSpot',
23+
toNative: 'toNative',
24+
biDirectional: 'biDirectional'
25+
} as const;
26+
27+
// Mock the modules
28+
jest.mock('../auth', () => ({
29+
authUrl: 'mock-auth-url',
30+
redeemCode: jest.fn()
31+
}));
32+
33+
jest.mock('../properties', () => ({
34+
checkForPropertyOrGroup: jest.fn(),
35+
getHubSpotProperties: jest.fn(),
36+
convertToPropertyForDB: jest.fn(),
37+
createNativeProperty: jest.fn(),
38+
createPropertyGroupForContacts: jest.fn().mockImplementation(async () => {
39+
// Function returns void
40+
})
41+
}));
42+
43+
jest.mock('../mappings', () => ({
44+
saveMapping: jest.fn(),
45+
deleteMapping: jest.fn()
46+
}));
47+
48+
jest.mock('../utils/utils', () => ({
49+
getCustomerId: jest.fn()
50+
}));
51+
52+
jest.mock('../utils/logger');
53+
54+
describe('API Endpoints', () => {
55+
// Setup and teardown
56+
beforeEach(() => {
57+
jest.clearAllMocks();
58+
});
59+
60+
afterAll(async () => {
61+
await app.close();
62+
});
63+
64+
describe('GET /api/install', () => {
65+
it('should return auth URL', async () => {
66+
const response = await request(app).get('/api/install');
67+
expect(response.status).toBe(200);
68+
expect(response.text).toBe(authUrl);
69+
});
70+
});
71+
72+
describe('GET /oauth-callback', () => {
73+
74+
it('should handle OAuth callback error', async () => {
75+
const mockCode = 'invalid-code';
76+
(redeemCode as jest.MockedFunction<typeof redeemCode>).mockRejectedValue(new Error('OAuth Error'));
77+
78+
const response = await request(app)
79+
.get('/oauth-callback')
80+
.query({ code: mockCode });
81+
82+
expect(response.status).toBe(302);
83+
expect(response.header.location).toContain('errMessage');
84+
});
85+
});
86+
87+
describe('GET /api/hubspot-properties', () => {
88+
it('should return hubspot properties', async () => {
89+
const mockProperties = {
90+
contactProperties: [{ name: 'test-prop' }],
91+
companyProperties: [{ name: 'test-company-prop' }]
92+
};
93+
94+
(utils.getCustomerId as jest.MockedFunction<typeof utils.getCustomerId>).mockReturnValue('test-customer');
95+
(properties.getHubSpotProperties as jest.MockedFunction<typeof properties.getHubSpotProperties>).mockResolvedValue(mockProperties);
96+
97+
const response = await request(app).get('/api/hubspot-properties');
98+
99+
expect(response.status).toBe(200);
100+
expect(response.body).toEqual(mockProperties);
101+
});
102+
103+
it('should handle errors', async () => {
104+
(utils.getCustomerId as jest.MockedFunction<typeof utils.getCustomerId>).mockReturnValue('test-customer');
105+
(properties.getHubSpotProperties as jest.MockedFunction<typeof properties.getHubSpotProperties>).mockRejectedValue(new Error('Test error'));
106+
107+
const response = await request(app).get('/api/hubspot-properties');
108+
109+
expect(response.status).toBe(500);
110+
expect(response.text).toBe('Internal Server Error');
111+
});
112+
});
113+
114+
describe('POST /api/native-properties', () => {
115+
it('should create a native property', async () => {
116+
const mockProperty = {
117+
object: Objects.Contact,
118+
name: 'test-prop',
119+
customerId: 'test-customer',
120+
label: 'Test Property',
121+
type: PropertyType.String,
122+
unique: false,
123+
modificationMetadata: {}
124+
};
125+
126+
const mockCustomerId = 'test-customer';
127+
128+
(utils.getCustomerId as jest.MockedFunction<typeof utils.getCustomerId>).mockReturnValue(mockCustomerId);
129+
(properties.convertToPropertyForDB as jest.MockedFunction<typeof properties.convertToPropertyForDB>).mockReturnValue(mockProperty);
130+
(properties.createNativeProperty as jest.MockedFunction<typeof properties.createNativeProperty>).mockResolvedValue(mockProperty);
131+
132+
const response = await request(app)
133+
.post('/api/native-properties/')
134+
.send(mockProperty);
135+
136+
expect(response.status).toBe(200);
137+
expect(response.body).toEqual(mockProperty);
138+
});
139+
});
140+
141+
describe('POST /api/mappings', () => {
142+
it('should create a new mapping', async () => {
143+
const mockMapping = {
144+
object: Objects.Contact,
145+
customerId: 'test-customer',
146+
modificationMetadata: {},
147+
id: 1,
148+
nativeName: 'test',
149+
hubspotName: 'test',
150+
hubspotLabel: 'Test Label',
151+
direction: Direction.biDirectional
152+
};
153+
154+
(mappings.saveMapping as jest.MockedFunction<typeof mappings.saveMapping>).mockResolvedValue(mockMapping);
155+
156+
const response = await request(app)
157+
.post('/api/mappings')
158+
.send(mockMapping);
159+
160+
expect(response.status).toBe(200);
161+
expect(response.body).toEqual(mockMapping);
162+
});
163+
164+
it('should handle errors', async () => {
165+
(mappings.saveMapping as jest.MockedFunction<typeof mappings.saveMapping>).mockRejectedValue(new Error('Test error'));
166+
167+
const response = await request(app)
168+
.post('/api/mappings')
169+
.send({});
170+
171+
expect(response.status).toBe(500);
172+
expect(response.text).toBe('Error saving mapping');
173+
});
174+
});
175+
176+
describe('DELETE /api/mappings/:mappingId', () => {
177+
it('should delete a mapping', async () => {
178+
const mockMappingId = 1;
179+
const mockDeleteResult = {
180+
object: Objects.Contact,
181+
customerId: 'test-customer',
182+
modificationMetadata: {},
183+
id: mockMappingId,
184+
nativeName: 'test',
185+
hubspotName: 'test',
186+
hubspotLabel: 'Test Label',
187+
direction: Direction.biDirectional
188+
};
189+
190+
(mappings.deleteMapping as jest.MockedFunction<typeof mappings.deleteMapping>).mockResolvedValue(mockDeleteResult);
191+
192+
const response = await request(app)
193+
.delete(`/api/mappings/${mockMappingId}`);
194+
195+
expect(response.status).toBe(200);
196+
expect(response.body).toEqual(mockDeleteResult);
197+
});
198+
199+
it('should handle invalid mapping ID', async () => {
200+
const response = await request(app)
201+
.delete('/api/mappings/invalid');
202+
203+
expect(response.status).toBe(400);
204+
expect(response.text).toBe('Invalid mapping Id format');
205+
});
206+
});
207+
});

src/tests/mappings.test.ts

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import { getMappings, deleteMapping, saveMapping } from '../mappings';
2+
import { jest, describe, it, expect, beforeEach } from '@jest/globals';
3+
import prisma from '../../prisma/seed';
4+
import * as utils from '../utils/utils';
5+
import { Mapping } from '@prisma/client';
6+
import handleError from '../utils/error';
7+
8+
// Mock the Prisma client
9+
jest.mock('../../prisma/seed', () => ({
10+
mapping: {
11+
findMany: jest.fn(),
12+
findUnique: jest.fn(),
13+
upsert: jest.fn(),
14+
delete: jest.fn(),
15+
},
16+
}));
17+
18+
// Mock utils - this needs to be updated
19+
jest.mock('../utils/utils', () => ({
20+
getCustomerId: jest.fn(() => 'cust_123') // Provide a default mock implementation
21+
}));
22+
23+
// Mock error handler
24+
jest.mock('../utils/error', () => ({
25+
__esModule: true,
26+
default: jest.fn(),
27+
}));
28+
29+
describe('Mappings Database Client', () => {
30+
const mockMapping: Mapping = {
31+
id: 1,
32+
nativeName: 'test_mapping',
33+
hubspotName: 'test_hubspot',
34+
hubspotLabel: 'Test Label',
35+
object: 'Contact',
36+
direction: 'biDirectional',
37+
customerId: 'cust_123',
38+
modificationMetadata: {
39+
archivable: true,
40+
readOnlyValue: false,
41+
readOnlyDefinition: false,
42+
}
43+
};
44+
45+
beforeEach(() => {
46+
jest.clearAllMocks();
47+
});
48+
49+
describe('getMappings', () => {
50+
it('should successfully fetch mappings by customer ID', async () => {
51+
const mockResults = [mockMapping];
52+
(prisma.mapping.findMany as jest.Mock).mockResolvedValue(mockResults);
53+
54+
const result = await getMappings('cust_123');
55+
56+
expect(result).toEqual(mockResults);
57+
expect(prisma.mapping.findMany).toHaveBeenCalledWith({
58+
select: {
59+
nativeName: true,
60+
hubspotLabel: true,
61+
hubspotName: true,
62+
id: true,
63+
object: true,
64+
direction: true,
65+
customerId: true,
66+
modificationMetadata: true,
67+
},
68+
where: {
69+
customerId: 'cust_123',
70+
},
71+
});
72+
});
73+
74+
it('should handle empty results', async () => {
75+
(prisma.mapping.findMany as jest.Mock).mockResolvedValue([]);
76+
77+
const result = await getMappings('cust_123');
78+
79+
expect(result).toEqual([]);
80+
});
81+
82+
it('should handle database errors', async () => {
83+
const mockError = new Error('Database error');
84+
(prisma.mapping.findMany as jest.Mock).mockRejectedValue(mockError);
85+
86+
const result = await getMappings('cust_123');
87+
88+
expect(result).toBeUndefined();
89+
expect(handleError).toHaveBeenCalledWith(
90+
mockError,
91+
'There was an issue while querying property mappings '
92+
);
93+
});
94+
});
95+
96+
describe('deleteMapping', () => {
97+
it('should successfully delete a mapping', async () => {
98+
(prisma.mapping.delete as jest.Mock).mockResolvedValue(mockMapping);
99+
100+
const result = await deleteMapping(1);
101+
102+
expect(result).toEqual(mockMapping);
103+
expect(prisma.mapping.delete).toHaveBeenCalledWith({
104+
where: {
105+
id: 1,
106+
},
107+
});
108+
});
109+
110+
it('should handle non-existent mapping', async () => {
111+
(prisma.mapping.delete as jest.Mock).mockResolvedValue(null);
112+
113+
const result = await deleteMapping(999);
114+
115+
expect(result).toBeNull();
116+
});
117+
118+
it('should handle deletion errors', async () => {
119+
const mockError = new Error('Database error');
120+
(prisma.mapping.delete as jest.Mock).mockRejectedValue(mockError);
121+
122+
const result = await deleteMapping(1);
123+
124+
expect(result).toBeUndefined();
125+
expect(handleError).toHaveBeenCalledWith(
126+
mockError,
127+
'There was an issue while attempting to delete property mappings '
128+
);
129+
});
130+
});
131+
132+
describe('saveMapping', () => {
133+
it('should successfully create a new mapping', async () => {
134+
(prisma.mapping.upsert as jest.Mock).mockImplementation((args) => Promise.resolve({
135+
...mockMapping,
136+
nativeName: args.where.nativeName_object_customerId.nativeName,
137+
customerId: args.where.nativeName_object_customerId.customerId,
138+
object: args.where.nativeName_object_customerId.object,
139+
}));
140+
141+
const result = await saveMapping(mockMapping);
142+
143+
expect(result).toEqual(mockMapping);
144+
expect(prisma.mapping.upsert).toHaveBeenCalledWith({
145+
where: {
146+
nativeName_object_customerId: {
147+
nativeName: mockMapping.nativeName,
148+
customerId: 'cust_123',
149+
object: mockMapping.object,
150+
},
151+
},
152+
update: {
153+
hubspotLabel: mockMapping.hubspotLabel,
154+
hubspotName: mockMapping.hubspotName,
155+
direction: mockMapping.direction,
156+
},
157+
create: {
158+
hubspotLabel: mockMapping.hubspotLabel,
159+
hubspotName: mockMapping.hubspotName,
160+
nativeName: mockMapping.nativeName,
161+
object: mockMapping.object,
162+
customerId: 'cust_123',
163+
direction: mockMapping.direction,
164+
modificationMetadata: mockMapping.modificationMetadata,
165+
},
166+
});
167+
});
168+
169+
it('should handle save errors', async () => {
170+
const mockError = new Error('Database error');
171+
(prisma.mapping.upsert as jest.Mock).mockRejectedValue(mockError);
172+
173+
const result = await saveMapping(mockMapping);
174+
175+
expect(result).toBeUndefined();
176+
expect(handleError).toHaveBeenCalledWith(
177+
mockError,
178+
'There was an issue while attempting to save the property mapping '
179+
);
180+
});
181+
});
182+
});

0 commit comments

Comments
 (0)