Skip to content

Commit 3f22657

Browse files
committed
add unit tests
1 parent f259993 commit 3f22657

File tree

12 files changed

+288
-212
lines changed

12 files changed

+288
-212
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ The testing pyramid emphasizes the following layers:
7373
- Focus on testing individual functions or components in isolation.
7474
- Fast, reliable, and provide detailed feedback on specific parts of your code.
7575
- Recommended to have a large amount of unit tests that test small units of code
76+
- These tests should use mocks to simulate dependencies, eliminating the need for the entire system to be operational.
7677
- Example: Testing a utility function or a cloud function independently.
7778
- Command: `npm run test:unit`
7879

cloud/Hello/functions.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Parse.Cloud.define('hello', req => {
2+
req.log.info(req);
3+
return 'Hi';
4+
});
5+
6+
Parse.Cloud.define('helloAsyncFunction', async req => {
7+
await new Promise(resolve => setTimeout(resolve, 1000));
8+
req.log.info(req);
9+
return 'Hi async';
10+
});

cloud/TestObject/beforeSave.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// breaking down the beforeSave into smaller methods allows for easier testing and better separation of concerns
2+
export class TestObjectBeforeSave {
3+
constructor(request) {
4+
this.request = request;
5+
}
6+
7+
async execute() {
8+
const object = this.request.object;
9+
this.validateRequest();
10+
this.addBeforeSaveFlag(object);
11+
await this.performAdditionalProcessing(object);
12+
}
13+
14+
validateRequest() {
15+
if (!this.request || !this.request.object) {
16+
throw new Error('Invalid request object.');
17+
}
18+
}
19+
20+
addBeforeSaveFlag(object) {
21+
object.set('beforeSave', true);
22+
}
23+
24+
async performAdditionalProcessing(object) {
25+
// Simulate some async operation
26+
const additionalData = await this.fetchAdditionalData();
27+
object.set('additionalData', additionalData);
28+
}
29+
30+
async fetchAdditionalData() {
31+
// Mock some external operation, e.g., fetching data from a database
32+
return 'mockedData';
33+
}
34+
}
35+
36+
Parse.Cloud.beforeSave('TestObject', (req) => {
37+
const beforeSaveTestObject = new TestObjectBeforeSave(req);
38+
return beforeSaveTestObject.execute();
39+
});

cloud/functions.js

Lines changed: 0 additions & 19 deletions
This file was deleted.

cloud/main.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
// It is best practise to organize your cloud functions group into their own file. You can then import them in your main.js.
2-
await import('./functions.js');
2+
await Promise.all([
3+
import('./Hello/functions.js'),
4+
import('./TestObject/beforeSave.js')
5+
]);

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ httpServer.listen(port, function () {
3636
});
3737
// This will enable the Live Query real-time server
3838
await ParseServer.createLiveQueryServer(httpServer);
39+
console.log(`Visit http://localhost:${port}/test to check the Parse Server`);

jest.setup.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
1-
import jest from 'jest-mock';
2-
global.Parse = {
3-
Cloud: {
4-
define: jest.fn(),
5-
beforeSave: jest.fn(),
6-
run: jest.fn(),
7-
},
8-
Error: class ParseError extends Error {
9-
constructor(code, message) {
10-
super(message);
11-
this.code = code;
12-
}
13-
},
14-
}
1+
// This is a setup file for Jest that mocks the Parse Cloud Code triggers.
2+
import Parse from 'parse/node';
3+
Parse.initialize('myAppId');
4+
const triggerStore = {};
5+
Parse.Cloud = new Proxy(
6+
{},
7+
{
8+
get(target, prop) {
9+
if (prop === 'getTrigger') {
10+
return (triggerType, name) => {
11+
const trigger = triggerStore[triggerType][name];
12+
if (!trigger) {
13+
throw new Error(`Trigger ${triggerType}.${name} not found`);
14+
}
15+
return trigger;
16+
}
17+
}
18+
if (!(prop in triggerStore)) {
19+
triggerStore[prop] = {};
20+
}
21+
return (name, func) => {
22+
triggerStore[prop][name] = func;
23+
};
24+
},
25+
}
26+
);
27+
global.Parse = Parse;

0 commit comments

Comments
 (0)