Skip to content

Commit

Permalink
Merge branch 'alpha' into fix/parse-community#2098
Browse files Browse the repository at this point in the history
  • Loading branch information
mtrezza authored Apr 29, 2024
2 parents 3b6684d + 8f30edf commit a7333c4
Show file tree
Hide file tree
Showing 34 changed files with 537 additions and 170 deletions.
21 changes: 19 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ jobs:
- run: npm ci
- name: Check Docs
run: npm run docs
check-lint:
name: Lint
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
cache: npm
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
build:
runs-on: ubuntu-latest
timeout-minutes: 30
Expand All @@ -55,12 +69,15 @@ jobs:
node-version: ${{ matrix.NODE_VERSION }}
cache: npm
- run: npm ci
- run: npm run lint
- run: npm test -- --maxWorkers=4
- run: npm run test:mongodb
env:
CI: true
- run: bash <(curl -s https://codecov.io/bash)
- name: Upload code coverage
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ A library that gives you access to the powerful Parse Server backend from your J

- [Getting Started](#getting-started)
- [Using Parse on Different Platforms](#using-parse-on-different-platforms)
- [Core Manager](#core-manager)
- [Compatibility](#compatibility)
- [Parse Server](#parse-server)
- [Node.js](#nodejs)
Expand Down Expand Up @@ -89,6 +90,18 @@ $ npm install @types/parse

Types are updated manually after every release. If a definition doesn't exist, please submit a pull request to [@types/parse][types-parse]

#### Core Manager

The SDK has a [Core Manager](src/CoreManager.js) that handles all configurations and controllers. These modules can be swapped out for customization before you initialize the SDK. For full list of all available modules take a look at the [Core Manager Documentation](src/CoreManager.js).

```js
// Configuration example
Parse.CoreManager.set('REQUEST_ATTEMPT_LIMIT', 1)

// Controller example
Parse.CoreManager.setRESTController(MyRESTController);
```

## Compatibility

### Parse Server
Expand Down
35 changes: 35 additions & 0 deletions changelogs/CHANGELOG_alpha.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
# [5.1.0-alpha.6](https://github.com/parse-community/Parse-SDK-JS/compare/5.1.0-alpha.5...5.1.0-alpha.6) (2024-04-25)


### Features

* Allow setting custom queue for handling offline operations via `Parse.EventuallyQueue` ([#2106](https://github.com/parse-community/Parse-SDK-JS/issues/2106)) ([f92e4d4](https://github.com/parse-community/Parse-SDK-JS/commit/f92e4d42afdc1e55bcfff1ba9d0658d39943f3f0))

# [5.1.0-alpha.5](https://github.com/parse-community/Parse-SDK-JS/compare/5.1.0-alpha.4...5.1.0-alpha.5) (2024-04-22)


### Bug Fixes

* Chrome browser console warning about unsafe header `access-control-expose-headers` when calling Cloud Function ([#2095](https://github.com/parse-community/Parse-SDK-JS/issues/2095)) ([7b73c03](https://github.com/parse-community/Parse-SDK-JS/commit/7b73c033eef8977c3e6c7e4af7146ffa74deed0c))

# [5.1.0-alpha.4](https://github.com/parse-community/Parse-SDK-JS/compare/5.1.0-alpha.3...5.1.0-alpha.4) (2024-04-15)


### Bug Fixes

* Live Query not working on Expo React Native ([#2109](https://github.com/parse-community/Parse-SDK-JS/issues/2109)) ([7a89665](https://github.com/parse-community/Parse-SDK-JS/commit/7a8966522f06efb3f0303b2a3c6fd08f41d8aff9))

# [5.1.0-alpha.3](https://github.com/parse-community/Parse-SDK-JS/compare/5.1.0-alpha.2...5.1.0-alpha.3) (2024-04-14)


### Features

* Lazy load `Parse.CoreManager` controllers to add support for swappable `CryptoController`, `LocalDatastoreController`, `StorageController`, `WebSocketController`, `ParseLiveQuery` ([#2100](https://github.com/parse-community/Parse-SDK-JS/issues/2100)) ([fbd0ab1](https://github.com/parse-community/Parse-SDK-JS/commit/fbd0ab1402792e241c4d9d6496b451e4cc268b8b))

# [5.1.0-alpha.2](https://github.com/parse-community/Parse-SDK-JS/compare/5.1.0-alpha.1...5.1.0-alpha.2) (2024-04-13)


### Bug Fixes

* Local datastore throws error when `Parse.Query.notEqualTo` is set to `null` ([#2102](https://github.com/parse-community/Parse-SDK-JS/issues/2102)) ([6afd32a](https://github.com/parse-community/Parse-SDK-JS/commit/6afd32af3517c88b570505d5cb25bd5ab449f039))

# [5.1.0-alpha.1](https://github.com/parse-community/Parse-SDK-JS/compare/5.0.0...5.1.0-alpha.1) (2024-03-31)


Expand Down
33 changes: 5 additions & 28 deletions integration/test/ParseEventuallyQueueTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,22 +195,15 @@ describe('Parse EventuallyQueue', () => {
const object = new TestObject({ hash: 'saveSecret' });
await new Promise((resolve) => parseServer.server.close(resolve));
await object.saveEventually();
let length = await Parse.EventuallyQueue.length();

const length = await Parse.EventuallyQueue.length();
assert(Parse.EventuallyQueue.isPolling());
assert.strictEqual(length, 1);

await reconfigureServer({});
while (Parse.EventuallyQueue.isPolling()) {
await sleep(100);
}
assert.strictEqual(Parse.EventuallyQueue.isPolling(), false);

while (await Parse.EventuallyQueue.length()) {
await sleep(100);
}
length = await Parse.EventuallyQueue.length();
assert.strictEqual(length, 0);

const query = new Parse.Query(TestObject);
query.equalTo('hash', 'saveSecret');
let results = await query.find();
Expand All @@ -233,10 +226,9 @@ describe('Parse EventuallyQueue', () => {
object.setACL(acl);

await new Promise((resolve) => parseServer.server.close(resolve));

await object.saveEventually();

let length = await Parse.EventuallyQueue.length();
const length = await Parse.EventuallyQueue.length();
assert(Parse.EventuallyQueue.isPolling());
assert.strictEqual(length, 1);

Expand All @@ -245,15 +237,6 @@ describe('Parse EventuallyQueue', () => {
while (Parse.EventuallyQueue.isPolling()) {
await sleep(100);
}
assert.strictEqual(Parse.EventuallyQueue.isPolling(), false);

length = await Parse.EventuallyQueue.length();
while (length) {
await sleep(100);
}
length = await Parse.EventuallyQueue.length();
assert.strictEqual(length, 0);

const query = new Parse.Query('TestObject');
query.equalTo('hash', 'saveSecret');
let results = await query.find();
Expand All @@ -269,21 +252,15 @@ describe('Parse EventuallyQueue', () => {
await object.save();
await new Promise((resolve) => parseServer.server.close(resolve));
await object.destroyEventually();
let length = await Parse.EventuallyQueue.length();
const length = await Parse.EventuallyQueue.length();

assert(Parse.EventuallyQueue.isPolling());
assert.strictEqual(length, 1);

await reconfigureServer({});
while (Parse.EventuallyQueue.isPolling()) {
await sleep(100);
}
assert.strictEqual(Parse.EventuallyQueue.isPolling(), false);
while (await Parse.EventuallyQueue.length()) {
await sleep(100);
}
length = await Parse.EventuallyQueue.length();
assert.strictEqual(length, 0);

const query = new Parse.Query(TestObject);
query.equalTo('hash', 'deleteSecret');
let results = await query.find();
Expand Down
38 changes: 38 additions & 0 deletions integration/test/ParseLiveQueryTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const assert = require('assert');
const Parse = require('../../node');
const sleep = require('./sleep');
const { resolvingPromise } = require('../../lib/node/promiseUtils');
const { EventEmitter } = require('events');

describe('Parse LiveQuery', () => {
beforeEach(() => {
Expand Down Expand Up @@ -367,4 +368,41 @@ describe('Parse LiveQuery', () => {
client.state = 'closed';
await client.close();
});

it('can subscribe to query with EventEmitter private fields', async () => {
class CustomEmitter {
#privateEmitter;

constructor() {
this.#privateEmitter = new EventEmitter();
}
on(event, listener) {
this.#privateEmitter.on(event, listener);
}
emit(event, ...args) {
this.#privateEmitter.emit(event, ...args);
}
}

const EV = Parse.CoreManager.getEventEmitter();

Parse.CoreManager.setEventEmitter(CustomEmitter);
const object = new TestObject();
await object.save();
const installationId = await Parse.CoreManager.getInstallationController().currentInstallationId();

const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
const promise = resolvingPromise();
subscription.on('update', (object, original, response) => {
assert.equal(object.get('foo'), 'bar');
assert.equal(response.installationId, installationId);
promise.resolve();
});
object.set({ foo: 'bar' });
await object.save();
await promise;
Parse.CoreManager.setEventEmitter(EV);
});
});
10 changes: 10 additions & 0 deletions integration/test/ParseLocalDatastoreTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,16 @@ function runTest(controller) {
assert.equal(results.length, 9);
});

it(`${controller.name} can perform notEqualTo null queries`, async () => {
const nullObject = new Parse.Object({ className: 'BoxedNumber', number: null });
await nullObject.save();
const query = new Parse.Query('BoxedNumber');
query.notEqualTo('number', null);
query.fromLocalDatastore();
const results = await query.find();
assert.equal(results.length, 10);
});

it(`${controller.name} can perform containedIn queries`, async () => {
const query = new Parse.Query('BoxedNumber');
query.containedIn('number', [3, 5, 7, 9, 11]);
Expand Down
104 changes: 104 additions & 0 deletions integration/test/ParseReactNativeTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use strict';

const Parse = require('../../react-native');
const { resolvingPromise } = require('../../lib/react-native/promiseUtils');
const CryptoController = require('../../lib/react-native/CryptoController');
const LocalDatastoreController = require('../../lib/react-native/LocalDatastoreController.default');
const StorageController = require('../../lib/react-native/StorageController.default');
const RESTController = require('../../lib/react-native/RESTController');

RESTController._setXHR(require('xmlhttprequest').XMLHttpRequest);

describe('Parse React Native', () => {
beforeEach(() => {
// Set up missing controllers and configurations
Parse.CoreManager.setWebSocketController(require('ws'));
Parse.CoreManager.setEventEmitter(require('events').EventEmitter);
Parse.CoreManager.setLocalDatastoreController(LocalDatastoreController);
Parse.CoreManager.setStorageController(StorageController);
Parse.CoreManager.setRESTController(RESTController);
Parse.CoreManager.setCryptoController(CryptoController);

Parse.initialize('integration');
Parse.CoreManager.set('SERVER_URL', 'http://localhost:1337/parse');
Parse.CoreManager.set('MASTER_KEY', 'notsosecret');
Parse.enableLocalDatastore();
});

afterEach(async () => {
await Parse.User.logOut();
Parse.Storage._clear();
});

it('can log in a user', async () => {
// Handle Storage Controller
await Parse.User.signUp('asdf', 'zxcv')
const user = await Parse.User.logIn('asdf', 'zxcv');
expect(user.get('username')).toBe('asdf');
expect(user.existed()).toBe(true);
});

it('can encrypt user', async () => {
// Handle Crypto Controller
Parse.User.enableUnsafeCurrentUser();
Parse.enableEncryptedUser();
Parse.secret = 'My Secret Key';
const user = new Parse.User();
user.setUsername('usernameENC');
user.setPassword('passwordENC');
await user.signUp();

const path = Parse.Storage.generatePath('currentUser');
const encryptedUser = Parse.Storage.getItem(path);

const crypto = Parse.CoreManager.getCryptoController();

const decryptedUser = crypto.decrypt(encryptedUser, Parse.CoreManager.get('ENCRYPTED_KEY'));
expect(JSON.parse(decryptedUser).objectId).toBe(user.id);

const currentUser = Parse.User.current();
expect(currentUser).toEqual(user);

const currentUserAsync = await Parse.User.currentAsync();
expect(currentUserAsync).toEqual(user);
await Parse.User.logOut();
Parse.CoreManager.set('ENCRYPTED_USER', false);
Parse.CoreManager.set('ENCRYPTED_KEY', null);
});

it('can pin saved object LDS', async () => {
// Handle LocalDatastore Controller
function LDS_KEY(object) {
return Parse.LocalDatastore.getKeyForObject(object);
}
const object = new Parse.Object('TestObject');
object.set('field', 'test');
await object.save();
await object.pin();
const localDatastore = await Parse.LocalDatastore._getAllContents();
const cachedObject = localDatastore[LDS_KEY(object)][0];
expect(Object.keys(localDatastore).length).toBe(2);
expect(cachedObject.objectId).toBe(object.id);
expect(cachedObject.field).toBe('test');
});

it('can subscribe to query', async () => {
// Handle WebSocket Controller
const object = new Parse.Object('TestObject');
await object.save();
const installationId = await Parse.CoreManager.getInstallationController().currentInstallationId();

const query = new Parse.Query('TestObject');
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
const promise = resolvingPromise();
subscription.on('update', (object, _, response) => {
expect(object.get('foo')).toBe('bar');
expect(response.installationId).toBe(installationId);
promise.resolve();
});
object.set({ foo: 'bar' });
await object.save();
await promise;
});
});
1 change: 1 addition & 0 deletions integration/test/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const defaultConfiguration = {
revokeSessionOnPasswordReset: false,
allowCustomObjectId: false,
allowClientClassCreation: true,
encodeParseObjectInCloudFunction: true,
emailAdapter: MockEmailAdapterWithOptions({
fromAddress: '[email protected]',
apiKey: 'k',
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "parse",
"version": "5.1.0-alpha.1",
"version": "5.1.0-alpha.6",
"description": "Parse JavaScript SDK",
"homepage": "https://parseplatform.org",
"keywords": [
Expand Down
Loading

0 comments on commit a7333c4

Please sign in to comment.