Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: update example
  • Loading branch information
dblythy committed Jan 13, 2025
commit 4ecec3105759ce10d5a2629a9ac266bc836b9aa3
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ jobs:
run: npm install
- name: Check Linting
run: npm run lint
- name: Run Tests
run: npm run test
- name: Run Unit Tests
run: npm run test:unit
- name: Run e2e Tests
run: npm run test:e2e
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
2 changes: 1 addition & 1 deletion .nycrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"text-summary"
],
"exclude": [
"**/spec/**"
"**/e2e/**"
]
}

36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,43 @@ These scripts can help you to develop your app for Parse Server:
* `npm run lint` will check the linting of your cloud code, tests and `index.js`, as defined in `.eslintrc.json`.
* `npm run lint-fix` will attempt fix the linting of your cloud code, tests and `index.js`.
* `npm run prettier` will help improve the formatting and layout of your cloud code, tests and `index.js`, as defined in `.prettierrc`.
* `npm run test` will run any tests that are written in `/spec`.
* `npm run test:e2e` will run any e2e tests that are written in `/e2e`.
* `npm run test:unit` will run any unit tests that are written in `tests`
* `npm test` will run all tests
* `npm run coverage` will run tests and check coverage. Output is available in the `/coverage` folder.

## Testing

Effective testing is crucial for maintaining the stability and reliability of your application. The testing pyramid is a widely adopted strategy to balance different types of tests and ensure a robust testing process.

### Testing Pyramid
The testing pyramid emphasizes the following layers:

1. Unit Tests:
- Focus on testing individual functions or components in isolation.
- Fast, reliable, and provide detailed feedback on specific parts of your code.
- Recommended to have a large amount of unit tests that test small units of code
- Example: Testing a utility function or a cloud function independently.
- Command: `npm run test:unit`

2. Integration Tests:
- Validate that different modules or components work together correctly.
- Useful for testing database interactions, API endpoints, or cloud function workflows.
- Recommended to have a medium amount of integration tests that test the integration of units.
- Typically slower than unit tests but cover a broader scope.

3. End-to-End (E2E) Tests:
- Test the application as a whole, simulating real user interactions.
- Validate that the entire system works as expected, from the user interface to the backend.
- Recommmended to have a small amount of e2e tests.
- Example: Testing user login or data submission flows.
- Command: `npm run test:e2e`

## Configuration

Configuration is located in `config.js`.


# Remote Deployment

## Heroku
Expand Down
17 changes: 11 additions & 6 deletions cloud/functions.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
Parse.Cloud.define('hello', req => {
// It is recommended to promote modularity by grouping cloud functions and hooks together.
// Suggestion would be to create a file /cloud/Test.js and include all the functions related to the Test class in that file.
export const hiFunction = req => {
req.log.info(req);
return 'Hi';
});
};
Parse.Cloud.define('hello', hiFunction);

Parse.Cloud.define('asyncFunction', async req => {
export const asyncFunction = async req => {
await new Promise(resolve => setTimeout(resolve, 1000));
req.log.info(req);
return 'Hi async';
});
};
Parse.Cloud.define('asyncFunction', asyncFunction);

Parse.Cloud.beforeSave('Test', () => {
export const beforeSaveTest = () => {
throw new Parse.Error(9001, 'Saving test objects is not available.');
});
};
Parse.Cloud.beforeSave('Test', beforeSaveTest);
2 changes: 1 addition & 1 deletion cloud/main.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// It is best practise to organize your cloud functions group into their own file. You can then import them in your main.js.
await import('./functions.js');
import('./functions.js');
10 changes: 10 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const config = {
databaseURI: process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || './cloud/main.js',
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse', // Don't forget to change to https if needed
liveQuery: {
classNames: ['Posts', 'Comments'], // List of classes to support for query subscriptions
},
};
File renamed without changes.
21 changes: 21 additions & 0 deletions e2e/Tests.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// E2E tests should be minimal and only test the integration of the Parse Server.
// Unit tests are preferred as they are faster and more reliable, and do not require a running Parse Server.
describe('Parse Server example', () => {
Parse.User.enableUnsafeCurrentUser();
it('call function', async () => {
const result = await Parse.Cloud.run('hello');
expect(result).toBe('Hi');
});

it('call async function', async () => {
const result = await Parse.Cloud.run('asyncFunction');
expect(result).toBe('Hi async');
});

it('failing test', async () => {
const obj = new Parse.Object('Test');
await expectAsync(obj.save()).toBeRejectedWith(
new Parse.Error(9001, 'Saving test objects is not available.')
);
});
});
9 changes: 6 additions & 3 deletions spec/helper.js → e2e/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ if (dns.setDefaultResultOrder) {
dns.setDefaultResultOrder('ipv4first');
}

beforeAll(async () => {
await startParseServer();
}, 100 * 60 * 20);
beforeAll(
async () => {
await startParseServer();
},
100 * 60 * 20
);

afterAll(async () => {
await dropDB();
Expand Down
7 changes: 6 additions & 1 deletion spec/utils/test-runner.js → e2e/utils/test-runner.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import http from 'http';
import { ParseServer } from 'parse-server';
import { app, config } from '../../index.js';
import { config } from '../../config.js';
import express from 'express';

export const dropDB = async () => {
await Parse.User.logOut();
Expand Down Expand Up @@ -29,14 +30,18 @@ export async function startParseServer() {
});
const parseServer = new ParseServer(parseServerOptions);
await parseServer.start();

const app = express();
app.use(parseServerOptions.mountPath, parseServer.app);
const httpServer = http.createServer(app);
await new Promise(resolve => httpServer.listen(parseServerOptions.port, resolve));

Object.assign(parseServerState, {
parseServer,
httpServer,
parseServerOptions,
});

return parseServerOptions;
}

Expand Down
49 changes: 14 additions & 35 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,19 @@
import express from 'express';
import { ParseServer } from 'parse-server';
import path from 'path';
const __dirname = path.resolve();
import http from 'http';

export const config = {
databaseURI:
process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse', // Don't forget to change to https if needed
liveQuery: {
classNames: ['Posts', 'Comments'], // List of classes to support for query subscriptions
},
};
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey

export const app = express();

app.set('trust proxy', true);
import { config } from './config.js';
const __dirname = path.resolve();
const app = express();

// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));

// Serve the Parse API on the /parse URL prefix
if (!process.env.TESTING) {
const mountPath = process.env.PARSE_MOUNT || '/parse';
const server = new ParseServer(config);
await server.start();
app.use(mountPath, server.app);
}
const mountPath = process.env.PARSE_MOUNT || '/parse';
const server = new ParseServer(config);
await server.start();
app.use(mountPath, server.app);

// Parse Server plays nicely with the rest of your web routes
app.get('/', function (req, res) {
Expand All @@ -48,12 +29,10 @@ app.get('/test', function (req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});

if (!process.env.TESTING) {
const port = process.env.PORT || 1337;
const httpServer = http.createServer(app);
httpServer.listen(port, function () {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
await ParseServer.createLiveQueryServer(httpServer);
}
const port = process.env.PORT || 1337;
const httpServer = http.createServer(app);
httpServer.listen(port, function () {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
await ParseServer.createLiveQueryServer(httpServer);
3 changes: 3 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
setupFiles: ["<rootDir>/jest.setup.js"],
};
14 changes: 14 additions & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import jest from 'jest-mock';
global.Parse = {
Cloud: {
define: jest.fn(),
beforeSave: jest.fn(),
run: jest.fn(),
},
Error: class ParseError extends Error {
constructor(code, message) {
super(message);
this.code = code;
}
},
}
Loading
Loading