@@ -9,6 +9,16 @@ const queryHashValue = 'hash';
99const testUserId = 'userId' ;
1010const testClassName = 'TestObject' ;
1111
12+ const ASYNC_TEST_WAIT_TIME = 100 ;
13+
14+ function resolveAfter ( result , msTimeout ) {
15+ return new Promise ( res => {
16+ setTimeout ( ( ) => {
17+ res ( result ) ;
18+ } , msTimeout ) ;
19+ } ) ;
20+ }
21+
1222describe ( 'ParseLiveQueryServer' , function ( ) {
1323 beforeEach ( function ( done ) {
1424 // Mock ParseWebSocketServer
@@ -753,7 +763,7 @@ describe('ParseLiveQueryServer', function () {
753763 setTimeout ( function ( ) {
754764 expect ( client . pushDelete ) . toHaveBeenCalled ( ) ;
755765 done ( ) ;
756- } , jasmine . ASYNC_TEST_WAIT_TIME ) ;
766+ } , ASYNC_TEST_WAIT_TIME ) ;
757767 } ) ;
758768
759769 it ( 'has no subscription and can handle object save command' , async ( ) => {
@@ -792,7 +802,7 @@ describe('ParseLiveQueryServer', function () {
792802 expect ( client . pushDelete ) . not . toHaveBeenCalled ( ) ;
793803 expect ( client . pushLeave ) . not . toHaveBeenCalled ( ) ;
794804 done ( ) ;
795- } , jasmine . ASYNC_TEST_WAIT_TIME ) ;
805+ } , ASYNC_TEST_WAIT_TIME ) ;
796806 } ) ;
797807
798808 it ( 'can handle object enter command which matches some subscriptions' , async done => {
@@ -829,7 +839,7 @@ describe('ParseLiveQueryServer', function () {
829839 expect ( client . pushDelete ) . not . toHaveBeenCalled ( ) ;
830840 expect ( client . pushLeave ) . not . toHaveBeenCalled ( ) ;
831841 done ( ) ;
832- } , jasmine . ASYNC_TEST_WAIT_TIME ) ;
842+ } , ASYNC_TEST_WAIT_TIME ) ;
833843 } ) ;
834844
835845 it ( 'can handle object update command which matches some subscriptions' , async done => {
@@ -862,7 +872,7 @@ describe('ParseLiveQueryServer', function () {
862872 expect ( client . pushDelete ) . not . toHaveBeenCalled ( ) ;
863873 expect ( client . pushLeave ) . not . toHaveBeenCalled ( ) ;
864874 done ( ) ;
865- } , jasmine . ASYNC_TEST_WAIT_TIME ) ;
875+ } , ASYNC_TEST_WAIT_TIME ) ;
866876 } ) ;
867877
868878 it ( 'can handle object leave command which matches some subscriptions' , async done => {
@@ -899,7 +909,74 @@ describe('ParseLiveQueryServer', function () {
899909 expect ( client . pushDelete ) . not . toHaveBeenCalled ( ) ;
900910 expect ( client . pushLeave ) . toHaveBeenCalled ( ) ;
901911 done ( ) ;
902- } , jasmine . ASYNC_TEST_WAIT_TIME ) ;
912+ } , ASYNC_TEST_WAIT_TIME ) ;
913+ } ) ;
914+
915+ it ( 'can handle object multiple commands which matches some subscriptions' , async done => {
916+ const parseLiveQueryServer = new ParseLiveQueryServer ( { } ) ;
917+
918+ Parse . Cloud . afterLiveQueryEvent ( 'TestObject' , ( ) => {
919+ // Simulate delay due to trigger, auth, etc.
920+ return resolveAfter ( null , 10 ) ;
921+ } ) ;
922+
923+ // Make mock request message
924+ const message = generateMockMessage ( true ) ;
925+ // Add mock client
926+ const clientId = 1 ;
927+ const client = addMockClient ( parseLiveQueryServer , clientId ) ;
928+ client . sessionToken = 'sessionToken' ;
929+
930+ // Mock queryHash for this special test
931+ const mockQueryHash = jasmine . createSpy ( 'matchesQuery' ) . and . returnValue ( 'hash1' ) ;
932+ jasmine . mockLibrary ( '../lib/LiveQuery/QueryTools' , 'queryHash' , mockQueryHash ) ;
933+ // Add mock subscription 1
934+ const requestId2 = 2 ;
935+ await addMockSubscription ( parseLiveQueryServer , clientId , requestId2 , null , null , 'hash1' ) ;
936+
937+ // Mock queryHash for this special test
938+ const mockQueryHash2 = jasmine . createSpy ( 'matchesQuery' ) . and . returnValue ( 'hash2' ) ;
939+ jasmine . mockLibrary ( '../lib/LiveQuery/QueryTools' , 'queryHash' , mockQueryHash2 ) ;
940+ // Add mock subscription 2
941+ const requestId3 = 3 ;
942+ await addMockSubscription ( parseLiveQueryServer , clientId , requestId3 , null , null , 'hash2' ) ;
943+ // Mock _matchesSubscription to return matching
944+ // In order to mimic a leave, then enter, we need original match return true
945+ // and the current match return false, then the other way around
946+ let counter = 0 ;
947+ parseLiveQueryServer . _matchesSubscription = function ( parseObject ) {
948+ if ( ! parseObject ) {
949+ return false ;
950+ }
951+ counter += 1 ;
952+ // true, false, false, true
953+ return counter < 2 || counter > 3 ;
954+ } ;
955+ parseLiveQueryServer . _matchesACL = function ( ) {
956+ // Simulate call
957+ return resolveAfter ( true , 10 ) ;
958+ } ;
959+ parseLiveQueryServer . _onAfterSave ( message ) ;
960+
961+ // Make sure we send leave and enter command to client
962+ setTimeout ( function ( ) {
963+ expect ( client . pushCreate ) . not . toHaveBeenCalled ( ) ;
964+ expect ( client . pushEnter ) . toHaveBeenCalledTimes ( 1 ) ;
965+ expect ( client . pushEnter ) . toHaveBeenCalledWith (
966+ requestId3 ,
967+ { key : 'value' , className : 'TestObject' } ,
968+ { key : 'originalValue' , className : 'TestObject' }
969+ ) ;
970+ expect ( client . pushUpdate ) . not . toHaveBeenCalled ( ) ;
971+ expect ( client . pushDelete ) . not . toHaveBeenCalled ( ) ;
972+ expect ( client . pushLeave ) . toHaveBeenCalledTimes ( 1 ) ;
973+ expect ( client . pushLeave ) . toHaveBeenCalledWith (
974+ requestId2 ,
975+ { key : 'value' , className : 'TestObject' } ,
976+ { key : 'originalValue' , className : 'TestObject' }
977+ ) ;
978+ done ( ) ;
979+ } , ASYNC_TEST_WAIT_TIME ) ;
903980 } ) ;
904981
905982 it ( 'can handle update command with original object' , async done => {
@@ -944,7 +1021,7 @@ describe('ParseLiveQueryServer', function () {
9441021 expect ( toSend . object ) . toBeDefined ( ) ;
9451022 expect ( toSend . original ) . toBeDefined ( ) ;
9461023 done ( ) ;
947- } , jasmine . ASYNC_TEST_WAIT_TIME ) ;
1024+ } , ASYNC_TEST_WAIT_TIME ) ;
9481025 } ) ;
9491026
9501027 it ( 'can handle object create command which matches some subscriptions' , async done => {
@@ -977,7 +1054,7 @@ describe('ParseLiveQueryServer', function () {
9771054 expect ( client . pushDelete ) . not . toHaveBeenCalled ( ) ;
9781055 expect ( client . pushLeave ) . not . toHaveBeenCalled ( ) ;
9791056 done ( ) ;
980- } , jasmine . ASYNC_TEST_WAIT_TIME ) ;
1057+ } , ASYNC_TEST_WAIT_TIME ) ;
9811058 } ) ;
9821059
9831060 it ( 'can handle create command with fields' , async done => {
@@ -1027,7 +1104,7 @@ describe('ParseLiveQueryServer', function () {
10271104 expect ( toSend . object ) . toBeDefined ( ) ;
10281105 expect ( toSend . original ) . toBeUndefined ( ) ;
10291106 done ( ) ;
1030- } , jasmine . ASYNC_TEST_WAIT_TIME ) ;
1107+ } , ASYNC_TEST_WAIT_TIME ) ;
10311108 } ) ;
10321109
10331110 it ( 'can match subscription for null or undefined parse object' , function ( ) {
@@ -1737,7 +1814,8 @@ describe('ParseLiveQueryServer', function () {
17371814 clientId ,
17381815 requestId ,
17391816 parseWebSocket ,
1740- query
1817+ query ,
1818+ customQueryHashValue
17411819 ) {
17421820 // If parseWebSocket is null, we use the default one
17431821 if ( ! parseWebSocket ) {
@@ -1765,12 +1843,12 @@ describe('ParseLiveQueryServer', function () {
17651843 // Make mock subscription
17661844 const subscription = parseLiveQueryServer . subscriptions
17671845 . get ( query . className )
1768- . get ( queryHashValue ) ;
1846+ . get ( customQueryHashValue || queryHashValue ) ;
17691847 subscription . hasSubscribingClient = function ( ) {
17701848 return false ;
17711849 } ;
17721850 subscription . className = query . className ;
1773- subscription . hash = queryHashValue ;
1851+ subscription . hash = customQueryHashValue || queryHashValue ;
17741852 if ( subscription . clientRequestIds && subscription . clientRequestIds . has ( clientId ) ) {
17751853 subscription . clientRequestIds . get ( clientId ) . push ( requestId ) ;
17761854 } else {
0 commit comments