2019-11-22 15:23:04 -06:00
'use strict' ;
2025-03-27 15:38:51 -05:00
const http = require ( 'http' ) ;
2023-01-09 08:02:12 +11:00
const Auth = require ( '../lib/Auth' ) ;
2020-10-25 15:06:58 -05:00
const UserController = require ( '../lib/Controllers/UserController' ) . UserController ;
2020-10-09 17:21:34 +02:00
const Config = require ( '../lib/Config' ) ;
2023-06-08 19:04:49 +10:00
const ParseServer = require ( '../lib/index' ) . ParseServer ;
2023-05-11 19:39:54 -05:00
const triggers = require ( '../lib/triggers' ) ;
2025-03-27 15:38:51 -05:00
const { resolvingPromise , sleep , getConnectionsCount } = require ( '../lib/TestUtils' ) ;
const request = require ( '../lib/request' ) ;
2020-10-26 04:36:54 +11:00
const validatorFail = ( ) => {
throw 'you are not authorized' ;
} ;
2020-07-17 11:36:38 +10:00
describe ( 'ParseLiveQuery' , function ( ) {
2023-01-26 20:49:03 +11:00
beforeEach ( ( ) => {
Parse . CoreManager . getLiveQueryController ( ) . setDefaultLiveQueryClient ( null ) ;
} ) ;
afterEach ( async ( ) => {
const client = await Parse . CoreManager . getLiveQueryController ( ) . getDefaultLiveQueryClient ( ) ;
2024-07-08 16:05:43 -05:00
await client . close ( ) ;
2023-01-26 20:49:03 +11:00
} ) ;
2020-12-04 11:36:41 +11:00
it ( 'access user on onLiveQueryEvent disconnect' , async done => {
const requestedUser = new Parse . User ( ) ;
requestedUser . setUsername ( 'username' ) ;
requestedUser . setPassword ( 'password' ) ;
Parse . Cloud . onLiveQueryEvent ( req => {
const { event , sessionToken } = req ;
if ( event === 'ws_disconnect' ) {
2021-03-13 09:05:22 -06:00
Parse . Cloud . _removeAllHooks ( ) ;
2020-12-04 11:36:41 +11:00
expect ( sessionToken ) . toBeDefined ( ) ;
expect ( sessionToken ) . toBe ( requestedUser . getSessionToken ( ) ) ;
done ( ) ;
}
} ) ;
await requestedUser . signUp ( ) ;
const query = new Parse . Query ( TestObject ) ;
await query . subscribe ( ) ;
const client = await Parse . CoreManager . getLiveQueryController ( ) . getDefaultLiveQueryClient ( ) ;
2024-07-08 16:05:43 -05:00
await client . close ( ) ;
2020-12-04 11:36:41 +11:00
} ) ;
2019-11-22 15:23:04 -06:00
it ( 'can subscribe to query' , async done => {
const object = new TestObject ( ) ;
await object . save ( ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
2020-10-20 02:38:55 +11:00
subscription . on ( 'update' , object => {
2019-11-22 15:23:04 -06:00
expect ( object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
done ( ) ;
} ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
} ) ;
2020-12-04 11:36:41 +11:00
2021-01-20 01:19:11 +03:00
it ( 'can use patterns in className' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'Test.*' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , object => {
expect ( object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
done ( ) ;
} ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
} ) ;
2020-10-20 02:38:55 +11:00
it ( 'expect afterEvent create' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , req => {
2020-11-25 08:58:35 +11:00
expect ( req . event ) . toBe ( 'create' ) ;
2020-10-20 02:38:55 +11:00
expect ( req . user ) . toBeUndefined ( ) ;
expect ( req . object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'create' , object => {
expect ( object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
done ( ) ;
} ) ;
const object = new TestObject ( ) ;
object . set ( 'foo' , 'bar' ) ;
await object . save ( ) ;
} ) ;
it ( 'expect afterEvent payload' , async done => {
const object = new TestObject ( ) ;
await object . save ( ) ;
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , req => {
2020-11-25 08:58:35 +11:00
expect ( req . event ) . toBe ( 'update' ) ;
2020-10-20 02:38:55 +11:00
expect ( req . user ) . toBeUndefined ( ) ;
expect ( req . object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
expect ( req . original . get ( 'foo' ) ) . toBeUndefined ( ) ;
done ( ) ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
await query . subscribe ( ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
} ) ;
it ( 'expect afterEvent enter' , async done => {
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , req => {
2020-11-25 08:58:35 +11:00
expect ( req . event ) . toBe ( 'enter' ) ;
2020-10-20 02:38:55 +11:00
expect ( req . user ) . toBeUndefined ( ) ;
expect ( req . object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
expect ( req . original . get ( 'foo' ) ) . toBeUndefined ( ) ;
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'foo' , 'bar' ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'enter' , object => {
expect ( object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
done ( ) ;
} ) ;
object . set ( 'foo' , 'bar' ) ;
await object . save ( ) ;
} ) ;
it ( 'expect afterEvent leave' , async done => {
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , req => {
2020-11-25 08:58:35 +11:00
expect ( req . event ) . toBe ( 'leave' ) ;
2020-10-20 02:38:55 +11:00
expect ( req . user ) . toBeUndefined ( ) ;
expect ( req . object . get ( 'foo' ) ) . toBeUndefined ( ) ;
expect ( req . original . get ( 'foo' ) ) . toBe ( 'bar' ) ;
} ) ;
const object = new TestObject ( ) ;
object . set ( 'foo' , 'bar' ) ;
await object . save ( ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'foo' , 'bar' ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'leave' , object => {
expect ( object . get ( 'foo' ) ) . toBeUndefined ( ) ;
done ( ) ;
} ) ;
object . unset ( 'foo' ) ;
await object . save ( ) ;
} ) ;
it ( 'expect afterEvent delete' , async done => {
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , req => {
2020-11-25 08:58:35 +11:00
expect ( req . event ) . toBe ( 'delete' ) ;
2020-10-20 02:38:55 +11:00
expect ( req . user ) . toBeUndefined ( ) ;
req . object . set ( 'foo' , 'bar' ) ;
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'delete' , object => {
expect ( object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
done ( ) ;
} ) ;
await object . destroy ( ) ;
} ) ;
it ( 'can handle afterEvent modification' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , req => {
const current = req . object ;
current . set ( 'foo' , 'yolo' ) ;
const original = req . original ;
original . set ( 'yolo' , 'foo' ) ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , ( object , original ) => {
expect ( object . get ( 'foo' ) ) . toBe ( 'yolo' ) ;
expect ( original . get ( 'yolo' ) ) . toBe ( 'foo' ) ;
done ( ) ;
} ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
} ) ;
it ( 'can return different object in afterEvent' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , req => {
const object = new Parse . Object ( 'Yolo' ) ;
req . object = object ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , object => {
expect ( object . className ) . toBe ( 'Yolo' ) ;
done ( ) ;
} ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
} ) ;
2020-10-26 04:36:54 +11:00
2020-10-20 02:38:55 +11:00
it ( 'can handle afterEvent throw' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
2020-10-22 08:50:21 +11:00
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , ( ) => {
throw 'Throw error from LQ afterEvent.' ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , ( ) => {
fail ( 'update should not have been called.' ) ;
} ) ;
subscription . on ( 'error' , e => {
expect ( e ) . toBe ( 'Throw error from LQ afterEvent.' ) ;
done ( ) ;
} ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
} ) ;
2022-03-23 12:11:39 +11:00
it ( 'can log on afterLiveQueryEvent throw' , async ( ) => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
const logger = require ( '../lib/logger' ) . logger ;
spyOn ( logger , 'error' ) . and . callFake ( ( ) => { } ) ;
let session = undefined ;
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , ( { sessionToken } ) => {
session = sessionToken ;
/* eslint-disable no-undef */
foo . bar ( ) ;
/* eslint-enable no-undef */
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
await new Promise ( resolve => subscription . on ( 'error' , resolve ) ) ;
expect ( logger . error ) . toHaveBeenCalledWith (
` Failed running afterLiveQueryEvent on class TestObject for event update with session ${ session } with: \n Error: {"message":"foo is not defined","code":141} `
) ;
} ) ;
2024-07-08 16:05:43 -05:00
it ( 'can handle afterEvent sendEvent to false' , async ( ) => {
2020-10-22 08:50:21 +11:00
const object = new TestObject ( ) ;
await object . save ( ) ;
2024-07-08 16:05:43 -05:00
const promise = resolvingPromise ( ) ;
2020-10-20 02:38:55 +11:00
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , req => {
const current = req . object ;
const original = req . original ;
if ( current . get ( 'foo' ) != original . get ( 'foo' ) ) {
2020-10-22 08:50:21 +11:00
req . sendEvent = false ;
2020-10-20 02:38:55 +11:00
}
2024-07-08 16:05:43 -05:00
promise . resolve ( ) ;
2020-10-20 02:38:55 +11:00
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , ( ) => {
fail ( 'update should not have been called.' ) ;
} ) ;
subscription . on ( 'error' , ( ) => {
fail ( 'error should not have been called.' ) ;
} ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
2024-07-08 16:05:43 -05:00
await promise ;
2020-10-20 02:38:55 +11:00
} ) ;
2020-10-26 04:36:54 +11:00
2024-07-08 16:05:43 -05:00
it ( 'can handle live query with fields' , async ( ) => {
2023-01-16 22:32:22 +11:00
await reconfigureServer ( {
liveQuery : {
classNames : [ 'Test' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const query = new Parse . Query ( 'Test' ) ;
query . watch ( 'yolo' ) ;
const subscription = await query . subscribe ( ) ;
const spy = {
create ( obj ) {
if ( ! obj . get ( 'yolo' ) ) {
fail ( 'create should not have been called' ) ;
}
} ,
update ( object , original ) {
if ( object . get ( 'yolo' ) === original . get ( 'yolo' ) ) {
fail ( 'create should not have been called' ) ;
}
} ,
} ;
const createSpy = spyOn ( spy , 'create' ) . and . callThrough ( ) ;
const updateSpy = spyOn ( spy , 'update' ) . and . callThrough ( ) ;
subscription . on ( 'create' , spy . create ) ;
subscription . on ( 'update' , spy . update ) ;
const obj = new Parse . Object ( 'Test' ) ;
obj . set ( 'foo' , 'bar' ) ;
await obj . save ( ) ;
obj . set ( 'foo' , 'xyz' ) ;
obj . set ( 'yolo' , 'xyz' ) ;
await obj . save ( ) ;
const obj2 = new Parse . Object ( 'Test' ) ;
obj2 . set ( 'foo' , 'bar' ) ;
obj2 . set ( 'yolo' , 'bar' ) ;
await obj2 . save ( ) ;
obj2 . set ( 'foo' , 'bart' ) ;
await obj2 . save ( ) ;
expect ( createSpy ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( updateSpy ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
2021-10-09 11:34:09 +11:00
it ( 'can handle afterEvent set pointers' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
const secondObject = new Parse . Object ( 'Test2' ) ;
secondObject . set ( 'foo' , 'bar' ) ;
await secondObject . save ( ) ;
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , async ( { object } ) => {
const query = new Parse . Query ( 'Test2' ) ;
const obj = await query . first ( ) ;
object . set ( 'obj' , obj ) ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , object => {
expect ( object . get ( 'obj' ) ) . toBeDefined ( ) ;
expect ( object . get ( 'obj' ) . get ( 'foo' ) ) . toBe ( 'bar' ) ;
done ( ) ;
} ) ;
subscription . on ( 'error' , ( ) => {
fail ( 'error should not have been called.' ) ;
} ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
} ) ;
2020-10-20 02:38:55 +11:00
it ( 'can handle async afterEvent modification' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const parent = new TestObject ( ) ;
const child = new TestObject ( ) ;
child . set ( 'bar' , 'foo' ) ;
await Parse . Object . saveAll ( [ parent , child ] ) ;
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , async req => {
const current = req . object ;
const pointer = current . get ( 'child' ) ;
await pointer . fetch ( ) ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , parent . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , object => {
expect ( object . get ( 'child' ) ) . toBeDefined ( ) ;
expect ( object . get ( 'child' ) . get ( 'bar' ) ) . toBe ( 'foo' ) ;
done ( ) ;
} ) ;
parent . set ( 'child' , child ) ;
await parent . save ( ) ;
} ) ;
2019-11-22 15:23:04 -06:00
2020-07-17 11:36:38 +10:00
it ( 'can handle beforeConnect / beforeSubscribe hooks' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
2023-01-26 20:49:03 +11:00
const hooks = {
beforeSubscribe ( req ) {
expect ( req . op ) . toBe ( 'subscribe' ) ;
expect ( req . requestId ) . toBe ( 1 ) ;
expect ( req . query ) . toBeDefined ( ) ;
expect ( req . user ) . toBeUndefined ( ) ;
} ,
beforeConnect ( req ) {
expect ( req . event ) . toBe ( 'connect' ) ;
expect ( req . clients ) . toBe ( 0 ) ;
expect ( req . subscriptions ) . toBe ( 0 ) ;
expect ( req . useMasterKey ) . toBe ( false ) ;
expect ( req . installationId ) . toBeDefined ( ) ;
expect ( req . user ) . toBeUndefined ( ) ;
expect ( req . client ) . toBeDefined ( ) ;
} ,
} ;
spyOn ( hooks , 'beforeSubscribe' ) . and . callThrough ( ) ;
spyOn ( hooks , 'beforeConnect' ) . and . callThrough ( ) ;
Parse . Cloud . beforeSubscribe ( 'TestObject' , hooks . beforeSubscribe ) ;
Parse . Cloud . beforeConnect ( hooks . beforeConnect ) ;
2020-07-17 11:36:38 +10:00
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
2020-10-20 02:38:55 +11:00
subscription . on ( 'update' , object => {
2020-07-17 11:36:38 +10:00
expect ( object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
2023-01-26 20:49:03 +11:00
expect ( hooks . beforeConnect ) . toHaveBeenCalled ( ) ;
expect ( hooks . beforeSubscribe ) . toHaveBeenCalled ( ) ;
2020-07-17 11:36:38 +10:00
done ( ) ;
} ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
} ) ;
2023-01-26 20:49:03 +11:00
it ( 'can handle beforeConnect validation function' , async ( ) => {
2020-10-26 04:36:54 +11:00
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
Parse . Cloud . beforeConnect ( ( ) => { } , validatorFail ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
2023-01-26 20:49:03 +11:00
await expectAsync ( query . subscribe ( ) ) . toBeRejectedWith (
new Parse . Error ( Parse . Error . VALIDATION _ERROR , 'you are not authorized' )
) ;
2020-10-26 04:36:54 +11:00
} ) ;
2023-01-26 20:49:03 +11:00
it ( 'can handle beforeSubscribe validation function' , async ( ) => {
2020-10-26 04:36:54 +11:00
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
Parse . Cloud . beforeSubscribe ( TestObject , ( ) => { } , validatorFail ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
2023-01-26 20:49:03 +11:00
await expectAsync ( query . subscribe ( ) ) . toBeRejectedWith (
new Parse . Error ( Parse . Error . VALIDATION _ERROR , 'you are not authorized' )
) ;
2020-10-26 04:36:54 +11:00
} ) ;
it ( 'can handle afterEvent validation function' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , ( ) => { } , validatorFail ) ;
const query = new Parse . Query ( TestObject ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'error' , error => {
expect ( error ) . toBe ( 'you are not authorized' ) ;
done ( ) ;
} ) ;
const object = new TestObject ( ) ;
object . set ( 'foo' , 'bar' ) ;
await object . save ( ) ;
} ) ;
2023-01-26 20:49:03 +11:00
it ( 'can handle beforeConnect error' , async ( ) => {
2020-07-17 11:36:38 +10:00
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
Parse . Cloud . beforeConnect ( ( ) => {
throw new Error ( 'You shall not pass!' ) ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
2023-01-26 20:49:03 +11:00
await expectAsync ( query . subscribe ( ) ) . toBeRejectedWith ( new Error ( 'You shall not pass!' ) ) ;
2020-07-17 11:36:38 +10:00
} ) ;
2022-03-23 12:11:39 +11:00
it ( 'can log on beforeConnect throw' , async ( ) => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const logger = require ( '../lib/logger' ) . logger ;
spyOn ( logger , 'error' ) . and . callFake ( ( ) => { } ) ;
let token = undefined ;
Parse . Cloud . beforeConnect ( ( { sessionToken } ) => {
token = sessionToken ;
/* eslint-disable no-undef */
foo . bar ( ) ;
/* eslint-enable no-undef */
} ) ;
2023-01-26 20:49:03 +11:00
await expectAsync ( new Parse . Query ( TestObject ) . subscribe ( ) ) . toBeRejectedWith (
new Error ( 'foo is not defined' )
) ;
2022-03-23 12:11:39 +11:00
expect ( logger . error ) . toHaveBeenCalledWith (
` Failed running beforeConnect for session ${ token } with: \n Error: {"message":"foo is not defined","code":141} `
) ;
} ) ;
2023-01-26 20:49:03 +11:00
it ( 'can handle beforeSubscribe error' , async ( ) => {
2020-07-17 11:36:38 +10:00
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
Parse . Cloud . beforeSubscribe ( TestObject , ( ) => {
throw new Error ( 'You shall not subscribe!' ) ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
2023-01-26 20:49:03 +11:00
await expectAsync ( query . subscribe ( ) ) . toBeRejectedWith ( new Error ( 'You shall not subscribe!' ) ) ;
2020-07-17 11:36:38 +10:00
} ) ;
2022-03-23 12:11:39 +11:00
it ( 'can log on beforeSubscribe error' , async ( ) => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const logger = require ( '../lib/logger' ) . logger ;
spyOn ( logger , 'error' ) . and . callFake ( ( ) => { } ) ;
Parse . Cloud . beforeSubscribe ( TestObject , ( ) => {
/* eslint-disable no-undef */
foo . bar ( ) ;
/* eslint-enable no-undef */
} ) ;
const query = new Parse . Query ( TestObject ) ;
2023-01-26 20:49:03 +11:00
await expectAsync ( query . subscribe ( ) ) . toBeRejectedWith ( new Error ( 'foo is not defined' ) ) ;
2022-03-23 12:11:39 +11:00
expect ( logger . error ) . toHaveBeenCalledWith (
` Failed running beforeSubscribe on TestObject for session undefined with: \n Error: {"message":"foo is not defined","code":141} `
) ;
} ) ;
2020-08-26 00:35:48 +10:00
it ( 'can handle mutate beforeSubscribe query' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
2023-01-26 20:49:03 +11:00
const hook = {
beforeSubscribe ( request ) {
request . query . equalTo ( 'yolo' , 'abc' ) ;
} ,
} ;
spyOn ( hook , 'beforeSubscribe' ) . and . callThrough ( ) ;
Parse . Cloud . beforeSubscribe ( 'TestObject' , hook . beforeSubscribe ) ;
2020-08-26 00:35:48 +10:00
const object = new TestObject ( ) ;
await object . save ( ) ;
2023-01-26 20:49:03 +11:00
const query = new Parse . Query ( 'TestObject' ) ;
2020-08-26 00:35:48 +10:00
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , ( ) => {
2023-01-26 20:49:03 +11:00
fail ( 'beforeSubscribe should restrict subscription' ) ;
2020-08-26 00:35:48 +10:00
} ) ;
2023-01-26 20:49:03 +11:00
subscription . on ( 'enter' , object => {
if ( object . get ( 'yolo' ) === 'abc' ) {
done ( ) ;
} else {
fail ( 'beforeSubscribe should restrict queries' ) ;
}
} ) ;
object . set ( { yolo : 'bar' } ) ;
2020-08-26 00:35:48 +10:00
await object . save ( ) ;
2023-01-26 20:49:03 +11:00
object . set ( { yolo : 'abc' } ) ;
await object . save ( ) ;
expect ( hook . beforeSubscribe ) . toHaveBeenCalled ( ) ;
2020-08-26 00:35:48 +10:00
} ) ;
it ( 'can return a new beforeSubscribe query' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
Parse . Cloud . beforeSubscribe ( TestObject , request => {
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'foo' , 'yolo' ) ;
request . query = query ;
} ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'foo' , 'bar' ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'create' , object => {
expect ( object . get ( 'foo' ) ) . toBe ( 'yolo' ) ;
done ( ) ;
} ) ;
const object = new TestObject ( ) ;
object . set ( { foo : 'yolo' } ) ;
await object . save ( ) ;
} ) ;
it ( 'can handle select beforeSubscribe query' , async done => {
Parse . Cloud . beforeSubscribe ( TestObject , request => {
const query = request . query ;
query . select ( 'yolo' ) ;
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , object => {
expect ( object . get ( 'foo' ) ) . toBeUndefined ( ) ;
expect ( object . get ( 'yolo' ) ) . toBe ( 'abc' ) ;
done ( ) ;
} ) ;
object . set ( { foo : 'bar' , yolo : 'abc' } ) ;
await object . save ( ) ;
} ) ;
2021-05-02 19:23:46 +10:00
it ( 'LiveQuery with ACL' , async ( ) => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'Chat' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const user = new Parse . User ( ) ;
user . setUsername ( 'username' ) ;
user . setPassword ( 'password' ) ;
await user . signUp ( ) ;
const calls = {
beforeConnect ( req ) {
expect ( req . event ) . toBe ( 'connect' ) ;
expect ( req . clients ) . toBe ( 0 ) ;
expect ( req . subscriptions ) . toBe ( 0 ) ;
expect ( req . useMasterKey ) . toBe ( false ) ;
expect ( req . installationId ) . toBeDefined ( ) ;
expect ( req . client ) . toBeDefined ( ) ;
} ,
beforeSubscribe ( req ) {
expect ( req . op ) . toBe ( 'subscribe' ) ;
expect ( req . requestId ) . toBe ( 1 ) ;
expect ( req . query ) . toBeDefined ( ) ;
expect ( req . user ) . toBeDefined ( ) ;
} ,
afterLiveQueryEvent ( req ) {
expect ( req . user ) . toBeDefined ( ) ;
expect ( req . object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
} ,
create ( object ) {
expect ( object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
} ,
delete ( object ) {
expect ( object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
} ,
} ;
for ( const key in calls ) {
spyOn ( calls , key ) . and . callThrough ( ) ;
}
Parse . Cloud . beforeConnect ( calls . beforeConnect ) ;
Parse . Cloud . beforeSubscribe ( 'Chat' , calls . beforeSubscribe ) ;
Parse . Cloud . afterLiveQueryEvent ( 'Chat' , calls . afterLiveQueryEvent ) ;
const chatQuery = new Parse . Query ( 'Chat' ) ;
const subscription = await chatQuery . subscribe ( ) ;
subscription . on ( 'create' , calls . create ) ;
subscription . on ( 'delete' , calls . delete ) ;
const object = new Parse . Object ( 'Chat' ) ;
const acl = new Parse . ACL ( user ) ;
object . setACL ( acl ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
await object . destroy ( ) ;
2024-07-08 16:05:43 -05:00
await sleep ( 200 ) ;
2021-05-02 19:23:46 +10:00
for ( const key in calls ) {
expect ( calls [ key ] ) . toHaveBeenCalled ( ) ;
}
} ) ;
2022-06-11 18:21:55 +10:00
it ( 'LiveQuery should work with changing role' , async ( ) => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'Chat' ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const user = new Parse . User ( ) ;
user . setUsername ( 'username' ) ;
user . setPassword ( 'password' ) ;
await user . signUp ( ) ;
const role = new Parse . Role ( 'Test' , new Parse . ACL ( user ) ) ;
await role . save ( ) ;
const chatQuery = new Parse . Query ( 'Chat' ) ;
const subscription = await chatQuery . subscribe ( ) ;
subscription . on ( 'create' , ( ) => {
fail ( 'should not call create as user is not part of role.' ) ;
} ) ;
const object = new Parse . Object ( 'Chat' ) ;
const acl = new Parse . ACL ( ) ;
acl . setRoleReadAccess ( role , true ) ;
object . setACL ( acl ) ;
object . set ( { foo : 'bar' } ) ;
await object . save ( null , { useMasterKey : true } ) ;
role . getUsers ( ) . add ( user ) ;
2024-07-08 16:05:43 -05:00
await sleep ( 1000 ) ;
2022-06-11 18:21:55 +10:00
await role . save ( ) ;
2024-07-08 16:05:43 -05:00
await sleep ( 1000 ) ;
2022-06-11 18:21:55 +10:00
object . set ( 'foo' , 'yolo' ) ;
await Promise . all ( [
new Promise ( resolve => {
subscription . on ( 'update' , obj => {
expect ( obj . get ( 'foo' ) ) . toBe ( 'yolo' ) ;
expect ( obj . getACL ( ) . toJSON ( ) ) . toEqual ( { 'role:Test' : { read : true } } ) ;
resolve ( ) ;
} ) ;
} ) ,
object . save ( null , { useMasterKey : true } ) ,
] ) ;
} ) ;
2021-10-09 02:24:33 +11:00
it ( 'liveQuery on Session class' , async done => {
await reconfigureServer ( {
liveQuery : { classNames : [ Parse . Session ] } ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const user = new Parse . User ( ) ;
user . setUsername ( 'username' ) ;
user . setPassword ( 'password' ) ;
await user . signUp ( ) ;
const query = new Parse . Query ( Parse . Session ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'create' , async obj => {
expect ( obj . get ( 'user' ) . id ) . toBe ( user . id ) ;
expect ( obj . get ( 'createdWith' ) ) . toEqual ( { action : 'login' , authProvider : 'password' } ) ;
expect ( obj . get ( 'expiresAt' ) ) . toBeInstanceOf ( Date ) ;
expect ( obj . get ( 'installationId' ) ) . toBeDefined ( ) ;
expect ( obj . get ( 'createdAt' ) ) . toBeInstanceOf ( Date ) ;
expect ( obj . get ( 'updatedAt' ) ) . toBeInstanceOf ( Date ) ;
done ( ) ;
} ) ;
await Parse . User . logIn ( 'username' , 'password' ) ;
} ) ;
2023-01-26 20:49:03 +11:00
it ( 'prevent liveQuery on Session class when not logged in' , async ( ) => {
2021-10-09 02:24:33 +11:00
await reconfigureServer ( {
liveQuery : {
classNames : [ Parse . Session ] ,
} ,
startLiveQueryServer : true ,
} ) ;
const query = new Parse . Query ( Parse . Session ) ;
2023-01-26 20:49:03 +11:00
await expectAsync ( query . subscribe ( ) ) . toBeRejectedWith ( new Error ( 'Invalid session token' ) ) ;
2021-10-09 02:24:33 +11:00
} ) ;
2024-08-13 22:13:19 +02:00
it _id ( '4ccc9508-ae6a-46ec-932a-9f5e49ab3b9e' ) ( it ) ( 'handle invalid websocket payload length' , async done => {
2020-02-19 03:30:23 -06:00
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
websocketTimeout : 100 ,
} ) ;
const object = new TestObject ( ) ;
await object . save ( ) ;
const query = new Parse . Query ( TestObject ) ;
query . equalTo ( 'objectId' , object . id ) ;
const subscription = await query . subscribe ( ) ;
// All control frames must have a payload length of 125 bytes or less.
// https://tools.ietf.org/html/rfc6455#section-5.5
//
// 0x89 = 10001001 = ping
// 0xfe = 11111110 = first bit is masking the remaining 7 are 1111110 or 126 the payload length
// https://tools.ietf.org/html/rfc6455#section-5.2
const client = await Parse . CoreManager . getLiveQueryController ( ) . getDefaultLiveQueryClient ( ) ;
client . socket . _socket . write ( Buffer . from ( [ 0x89 , 0xfe ] ) ) ;
subscription . on ( 'update' , async object => {
expect ( object . get ( 'foo' ) ) . toBe ( 'bar' ) ;
done ( ) ;
} ) ;
// Wait for Websocket timeout to reconnect
setTimeout ( async ( ) => {
object . set ( { foo : 'bar' } ) ;
await object . save ( ) ;
} , 1000 ) ;
} ) ;
2024-08-13 22:13:19 +02:00
it _id ( '39a9191f-26dd-4e05-a379-297a67928de8' ) ( it ) ( 'should execute live query update on email validation' , async done => {
2020-10-09 17:21:34 +02:00
const emailAdapter = {
sendVerificationEmail : ( ) => { } ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
sendMail : ( ) => { } ,
} ;
await reconfigureServer ( {
2023-01-09 08:02:12 +11:00
maintenanceKey : 'test2' ,
2020-10-09 17:21:34 +02:00
liveQuery : {
2021-10-09 02:24:33 +11:00
classNames : [ Parse . User ] ,
2020-10-09 17:21:34 +02:00
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
websocketTimeout : 100 ,
appName : 'liveQueryEmailValidation' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
emailVerifyTokenValidityDuration : 20 , // 0.5 second
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( ( ) => {
const user = new Parse . User ( ) ;
user . set ( 'password' , 'asdf' ) ;
user . set ( 'email' , 'asdf@example.com' ) ;
user . set ( 'username' , 'zxcv' ) ;
user
. signUp ( )
. then ( ( ) => {
const config = Config . get ( 'test' ) ;
2023-01-09 08:02:12 +11:00
return config . database . find (
'_User' ,
{
username : 'zxcv' ,
} ,
{ } ,
Auth . maintenance ( config )
) ;
2020-10-09 17:21:34 +02:00
} )
. then ( async results => {
const foundUser = results [ 0 ] ;
const query = new Parse . Query ( '_User' ) ;
query . equalTo ( 'objectId' , foundUser . objectId ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , async object => {
expect ( object ) . toBeDefined ( ) ;
expect ( object . get ( 'emailVerified' ) ) . toBe ( true ) ;
done ( ) ;
} ) ;
const userController = new UserController ( emailAdapter , 'test' , {
verifyUserEmails : true ,
} ) ;
2025-03-02 12:32:43 +11:00
userController . verifyEmail ( foundUser . _email _verify _token ) ;
2020-10-09 17:21:34 +02:00
} ) ;
} ) ;
} ) ;
2020-10-21 16:32:07 -07:00
it ( 'should not broadcast event to client with invalid session token - avisory GHSA-2xm2-xj2q-qgpj' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
liveQueryServerOptions : {
cacheTimeout : 100 ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
cacheTTL : 100 ,
} ) ;
const user = new Parse . User ( ) ;
user . setUsername ( 'username' ) ;
user . setPassword ( 'password' ) ;
await user . signUp ( ) ;
const obj1 = new Parse . Object ( 'TestObject' ) ;
const obj1ACL = new Parse . ACL ( ) ;
obj1ACL . setPublicReadAccess ( false ) ;
obj1ACL . setReadAccess ( user , true ) ;
obj1 . setACL ( obj1ACL ) ;
const obj2 = new Parse . Object ( 'TestObject' ) ;
const obj2ACL = new Parse . ACL ( ) ;
obj2ACL . setPublicReadAccess ( false ) ;
obj2ACL . setReadAccess ( user , true ) ;
obj2 . setACL ( obj2ACL ) ;
const query = new Parse . Query ( 'TestObject' ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'create' , obj => {
if ( obj . id !== obj1 . id ) {
done . fail ( 'should not fire' ) ;
}
} ) ;
await obj1 . save ( ) ;
await Parse . User . logOut ( ) ;
await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ;
await obj2 . save ( ) ;
await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ;
done ( ) ;
} ) ;
2021-09-30 12:52:12 +10:00
it ( 'should strip out session token in LiveQuery' , async ( ) => {
await reconfigureServer ( {
liveQuery : { classNames : [ '_User' ] } ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const user = new Parse . User ( ) ;
user . setUsername ( 'username' ) ;
user . setPassword ( 'password' ) ;
user . set ( 'foo' , 'bar' ) ;
2022-11-17 08:59:44 +11:00
const acl = new Parse . ACL ( ) ;
acl . setPublicReadAccess ( true ) ;
user . setACL ( acl ) ;
2021-09-30 12:52:12 +10:00
const query = new Parse . Query ( Parse . User ) ;
query . equalTo ( 'foo' , 'bar' ) ;
const subscription = await query . subscribe ( ) ;
const events = [ 'create' , 'update' , 'enter' , 'leave' , 'delete' ] ;
const response = ( obj , prev ) => {
expect ( obj . get ( 'sessionToken' ) ) . toBeUndefined ( ) ;
expect ( obj . sessionToken ) . toBeUndefined ( ) ;
2021-09-30 21:41:04 +10:00
expect ( prev && prev . sessionToken ) . toBeUndefined ( ) ;
2021-09-30 12:52:12 +10:00
if ( prev && prev . get ) {
expect ( prev . get ( 'sessionToken' ) ) . toBeUndefined ( ) ;
}
} ;
const calls = { } ;
for ( const key of events ) {
calls [ key ] = response ;
spyOn ( calls , key ) . and . callThrough ( ) ;
subscription . on ( key , calls [ key ] ) ;
}
await user . signUp ( ) ;
user . unset ( 'foo' ) ;
await user . save ( ) ;
user . set ( 'foo' , 'bar' ) ;
await user . save ( ) ;
user . set ( 'yolo' , 'bar' ) ;
await user . save ( ) ;
await user . destroy ( ) ;
2021-10-30 19:21:24 +02:00
await new Promise ( resolve => setTimeout ( resolve , 10 ) ) ;
2021-09-30 12:52:12 +10:00
for ( const key of events ) {
expect ( calls [ key ] ) . toHaveBeenCalled ( ) ;
}
} ) ;
2022-06-30 13:01:40 +02:00
it ( 'should strip out protected fields' , async ( ) => {
await reconfigureServer ( {
liveQuery : { classNames : [ 'Test' ] } ,
startLiveQueryServer : true ,
} ) ;
const obj1 = new Parse . Object ( 'Test' ) ;
obj1 . set ( 'foo' , 'foo' ) ;
obj1 . set ( 'bar' , 'bar' ) ;
obj1 . set ( 'qux' , 'qux' ) ;
await obj1 . save ( ) ;
const config = Config . get ( Parse . applicationId ) ;
const schemaController = await config . database . loadSchema ( ) ;
await schemaController . updateClass (
'Test' ,
{ } ,
{
get : { '*' : true } ,
find : { '*' : true } ,
update : { '*' : true } ,
protectedFields : {
'*' : [ 'foo' ] ,
} ,
}
) ;
const object = await obj1 . fetch ( ) ;
expect ( object . get ( 'foo' ) ) . toBe ( undefined ) ;
expect ( object . get ( 'bar' ) ) . toBeDefined ( ) ;
expect ( object . get ( 'qux' ) ) . toBeDefined ( ) ;
const subscription = await new Parse . Query ( 'Test' ) . subscribe ( ) ;
await Promise . all ( [
new Promise ( resolve => {
subscription . on ( 'update' , ( obj , original ) => {
expect ( obj . get ( 'foo' ) ) . toBe ( undefined ) ;
expect ( obj . get ( 'bar' ) ) . toBeDefined ( ) ;
expect ( obj . get ( 'qux' ) ) . toBeDefined ( ) ;
expect ( original . get ( 'foo' ) ) . toBe ( undefined ) ;
expect ( original . get ( 'bar' ) ) . toBeDefined ( ) ;
expect ( original . get ( 'qux' ) ) . toBeDefined ( ) ;
resolve ( ) ;
} ) ;
} ) ,
obj1 . save ( { foo : 'abc' } ) ,
] ) ;
} ) ;
2022-10-11 17:27:29 -05:00
it ( 'can subscribe to query and return object with withinKilometers with last parameter on update' , async done => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const object = new TestObject ( ) ;
const firstPoint = new Parse . GeoPoint ( { latitude : 40.0 , longitude : - 30.0 } ) ;
object . set ( { location : firstPoint } ) ;
await object . save ( ) ;
// unsorted will use $centerSphere operator
const sorted = false ;
const query = new Parse . Query ( TestObject ) ;
query . withinKilometers (
'location' ,
new Parse . GeoPoint ( { latitude : 40.0 , longitude : - 30.0 } ) ,
2 ,
sorted
) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'update' , obj => {
expect ( obj . id ) . toBe ( object . id ) ;
done ( ) ;
} ) ;
const secondPoint = new Parse . GeoPoint ( { latitude : 40.0 , longitude : - 30.0 } ) ;
object . set ( { location : secondPoint } ) ;
await object . save ( ) ;
} ) ;
2023-05-11 19:39:54 -05:00
2024-08-13 22:13:19 +02:00
it _id ( '2f95d8a9-7675-45ba-a4a6-e45cb7efb1fb' ) ( it ) ( 'does shutdown liveQuery server' , async ( ) => {
2023-06-08 19:04:49 +10:00
await reconfigureServer ( { appId : 'test_app_id' } ) ;
const config = {
appId : 'hello_test' ,
masterKey : 'world' ,
port : 1345 ,
mountPath : '/1' ,
serverURL : 'http://localhost:1345/1' ,
liveQuery : {
classNames : [ 'Yolo' ] ,
} ,
startLiveQueryServer : true ,
2024-07-08 16:05:43 -05:00
verbose : false ,
silent : true ,
2023-06-08 19:04:49 +10:00
} ;
if ( process . env . PARSE _SERVER _TEST _DB === 'postgres' ) {
config . databaseAdapter = new databaseAdapter . constructor ( {
uri : databaseURI ,
collectionPrefix : 'test_' ,
} ) ;
config . filesAdapter = defaultConfiguration . filesAdapter ;
}
const server = await ParseServer . startApp ( config ) ;
const client = await Parse . CoreManager . getLiveQueryController ( ) . getDefaultLiveQueryClient ( ) ;
client . serverURL = 'ws://localhost:1345/1' ;
const query = await new Parse . Query ( 'Yolo' ) . subscribe ( ) ;
2025-04-06 21:01:36 -05:00
let liveQueryConnectionCount = await getConnectionsCount ( server . liveQueryServer . server ) ;
expect ( liveQueryConnectionCount > 0 ) . toBe ( true ) ;
2023-06-08 19:04:49 +10:00
await Promise . all ( [
server . handleShutdown ( ) ,
new Promise ( resolve => query . on ( 'close' , resolve ) ) ,
] ) ;
2025-04-06 21:01:36 -05:00
await sleep ( 100 ) ;
2023-06-08 19:04:49 +10:00
expect ( server . liveQueryServer . server . address ( ) ) . toBeNull ( ) ;
expect ( server . liveQueryServer . subscriber . isOpen ) . toBeFalse ( ) ;
2025-07-04 20:24:08 +02:00
2025-04-06 21:01:36 -05:00
liveQueryConnectionCount = await getConnectionsCount ( server . liveQueryServer . server ) ;
expect ( liveQueryConnectionCount ) . toBe ( 0 ) ;
2023-06-08 19:04:49 +10:00
} ) ;
2025-03-27 15:38:51 -05:00
it _id ( '45655b74-716f-4fa1-a058-67eb21f3c3db' ) ( it ) ( 'does shutdown separate liveQuery server' , async ( ) => {
await reconfigureServer ( { appId : 'test_app_id' } ) ;
let close = false ;
const config = {
appId : 'hello_test' ,
masterKey : 'world' ,
port : 1345 ,
mountPath : '/1' ,
serverURL : 'http://localhost:1345/1' ,
liveQuery : {
classNames : [ 'Yolo' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
liveQueryServerOptions : {
port : 1346 ,
} ,
serverCloseComplete : ( ) => {
close = true ;
} ,
} ;
if ( process . env . PARSE _SERVER _TEST _DB === 'postgres' ) {
config . databaseAdapter = new databaseAdapter . constructor ( {
uri : databaseURI ,
collectionPrefix : 'test_' ,
} ) ;
config . filesAdapter = defaultConfiguration . filesAdapter ;
}
const parseServer = await ParseServer . startApp ( config ) ;
expect ( parseServer . liveQueryServer ) . toBeDefined ( ) ;
expect ( parseServer . liveQueryServer . server ) . not . toBe ( parseServer . server ) ;
// Open a connection to the liveQuery server
const client = await Parse . CoreManager . getLiveQueryController ( ) . getDefaultLiveQueryClient ( ) ;
client . serverURL = 'ws://localhost:1346/1' ;
const query = await new Parse . Query ( 'Yolo' ) . subscribe ( ) ;
// Open a connection to the parse server
const health = await request ( {
method : 'GET' ,
url : ` http://localhost:1345/1/health ` ,
json : true ,
headers : {
'X-Parse-Application-Id' : 'hello_test' ,
'X-Parse-Master-Key' : 'world' ,
'Content-Type' : 'application/json' ,
} ,
agent : new http . Agent ( { keepAlive : true } ) ,
} ) . then ( res => res . data ) ;
expect ( health . status ) . toBe ( 'ok' ) ;
let parseConnectionCount = await getConnectionsCount ( parseServer . server ) ;
let liveQueryConnectionCount = await getConnectionsCount ( parseServer . liveQueryServer . server ) ;
expect ( parseConnectionCount > 0 ) . toBe ( true ) ;
expect ( liveQueryConnectionCount > 0 ) . toBe ( true ) ;
await Promise . all ( [
parseServer . handleShutdown ( ) ,
new Promise ( resolve => query . on ( 'close' , resolve ) ) ,
] ) ;
expect ( close ) . toBe ( true ) ;
2025-04-06 21:01:36 -05:00
await sleep ( 100 ) ;
2025-03-27 15:38:51 -05:00
expect ( parseServer . liveQueryServer . server . address ( ) ) . toBeNull ( ) ;
expect ( parseServer . liveQueryServer . subscriber . isOpen ) . toBeFalse ( ) ;
parseConnectionCount = await getConnectionsCount ( parseServer . server ) ;
liveQueryConnectionCount = await getConnectionsCount ( parseServer . liveQueryServer . server ) ;
expect ( parseConnectionCount ) . toBe ( 0 ) ;
expect ( liveQueryConnectionCount ) . toBe ( 0 ) ;
} ) ;
2023-05-11 19:39:54 -05:00
it ( 'prevent afterSave trigger if not exists' , async ( ) => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
spyOn ( triggers , 'maybeRunTrigger' ) . and . callThrough ( ) ;
const object1 = new TestObject ( ) ;
const object2 = new TestObject ( ) ;
const object3 = new TestObject ( ) ;
await Parse . Object . saveAll ( [ object1 , object2 , object3 ] ) ;
expect ( triggers . maybeRunTrigger ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( object1 . id ) . toBeDefined ( ) ;
expect ( object2 . id ) . toBeDefined ( ) ;
expect ( object3 . id ) . toBeDefined ( ) ;
} ) ;
2024-06-12 01:01:10 +05:30
it ( 'triggers query event with constraint not equal to null' , async ( ) => {
await reconfigureServer ( {
liveQuery : {
classNames : [ 'TestObject' ] ,
} ,
startLiveQueryServer : true ,
verbose : false ,
silent : true ,
} ) ;
const spy = {
create ( obj ) {
expect ( obj . attributes . foo ) . toEqual ( 'bar' ) ;
} ,
} ;
const createSpy = spyOn ( spy , 'create' ) ;
const query = new Parse . Query ( TestObject ) ;
query . notEqualTo ( 'foo' , null ) ;
const subscription = await query . subscribe ( ) ;
subscription . on ( 'create' , spy . create ) ;
const object1 = new TestObject ( ) ;
object1 . set ( 'foo' , 'bar' ) ;
await object1 . save ( ) ;
await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
expect ( createSpy ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
2019-11-22 15:23:04 -06:00
} ) ;