@@ -2519,6 +2519,201 @@ describe('afterFind hooks', () => {
25192519 } ) ;
25202520 } ) ;
25212521
2522+ it ( 'should throw error if context header is malformed' , async ( ) => {
2523+ let calledBefore = false ;
2524+ let calledAfter = false ;
2525+ Parse . Cloud . beforeSave ( 'TestObject' , ( ) => {
2526+ calledBefore = true ;
2527+ } ) ;
2528+ Parse . Cloud . afterSave ( 'TestObject' , ( ) => {
2529+ calledAfter = true ;
2530+ } ) ;
2531+ const req = request ( {
2532+ method : 'POST' ,
2533+ url : 'http://localhost:8378/1/classes/TestObject' ,
2534+ headers : {
2535+ 'X-Parse-Application-Id' : 'test' ,
2536+ 'X-Parse-REST-API-Key' : 'rest' ,
2537+ 'X-Parse-Cloud-Context' : 'key' ,
2538+ } ,
2539+ body : {
2540+ foo : 'bar' ,
2541+ } ,
2542+ } ) ;
2543+ try {
2544+ await req ;
2545+ fail ( 'Should have thrown error' ) ;
2546+ } catch ( e ) {
2547+ expect ( e ) . toBeDefined ( ) ;
2548+ expect ( e . data . code ) . toEqual ( Parse . Error . INVALID_JSON ) ;
2549+ }
2550+ expect ( calledBefore ) . toBe ( false ) ;
2551+ expect ( calledAfter ) . toBe ( false ) ;
2552+ } ) ;
2553+
2554+ it ( 'should throw error if context header is string "1"' , async ( ) => {
2555+ let calledBefore = false ;
2556+ let calledAfter = false ;
2557+ Parse . Cloud . beforeSave ( 'TestObject' , ( ) => {
2558+ calledBefore = true ;
2559+ } ) ;
2560+ Parse . Cloud . afterSave ( 'TestObject' , ( ) => {
2561+ calledAfter = true ;
2562+ } ) ;
2563+ const req = request ( {
2564+ method : 'POST' ,
2565+ url : 'http://localhost:8378/1/classes/TestObject' ,
2566+ headers : {
2567+ 'X-Parse-Application-Id' : 'test' ,
2568+ 'X-Parse-REST-API-Key' : 'rest' ,
2569+ 'X-Parse-Cloud-Context' : '1' ,
2570+ } ,
2571+ body : {
2572+ foo : 'bar' ,
2573+ } ,
2574+ } ) ;
2575+ try {
2576+ await req ;
2577+ fail ( 'Should have thrown error' ) ;
2578+ } catch ( e ) {
2579+ expect ( e ) . toBeDefined ( ) ;
2580+ expect ( e . data . code ) . toEqual ( Parse . Error . INVALID_JSON ) ;
2581+ }
2582+ expect ( calledBefore ) . toBe ( false ) ;
2583+ expect ( calledAfter ) . toBe ( false ) ;
2584+ } ) ;
2585+
2586+ it ( 'should expose context in beforeSave/afterSave via header' , async ( ) => {
2587+ let calledBefore = false ;
2588+ let calledAfter = false ;
2589+ Parse . Cloud . beforeSave ( 'TestObject' , req => {
2590+ expect ( req . object . get ( 'foo' ) ) . toEqual ( 'bar' ) ;
2591+ expect ( req . context . otherKey ) . toBe ( 1 ) ;
2592+ expect ( req . context . key ) . toBe ( 'value' ) ;
2593+ calledBefore = true ;
2594+ } ) ;
2595+ Parse . Cloud . afterSave ( 'TestObject' , req => {
2596+ expect ( req . object . get ( 'foo' ) ) . toEqual ( 'bar' ) ;
2597+ expect ( req . context . otherKey ) . toBe ( 1 ) ;
2598+ expect ( req . context . key ) . toBe ( 'value' ) ;
2599+ calledAfter = true ;
2600+ } ) ;
2601+ const req = request ( {
2602+ method : 'POST' ,
2603+ url : 'http://localhost:8378/1/classes/TestObject' ,
2604+ headers : {
2605+ 'X-Parse-Application-Id' : 'test' ,
2606+ 'X-Parse-REST-API-Key' : 'rest' ,
2607+ 'X-Parse-Cloud-Context' : '{"key":"value","otherKey":1}' ,
2608+ } ,
2609+ body : {
2610+ foo : 'bar' ,
2611+ } ,
2612+ } ) ;
2613+ await req ;
2614+ expect ( calledBefore ) . toBe ( true ) ;
2615+ expect ( calledAfter ) . toBe ( true ) ;
2616+ } ) ;
2617+
2618+ it ( 'should override header context with body context in beforeSave/afterSave' , async ( ) => {
2619+ let calledBefore = false ;
2620+ let calledAfter = false ;
2621+ Parse . Cloud . beforeSave ( 'TestObject' , req => {
2622+ expect ( req . object . get ( 'foo' ) ) . toEqual ( 'bar' ) ;
2623+ expect ( req . context . otherKey ) . toBe ( 10 ) ;
2624+ expect ( req . context . key ) . toBe ( 'hello' ) ;
2625+ calledBefore = true ;
2626+ } ) ;
2627+ Parse . Cloud . afterSave ( 'TestObject' , req => {
2628+ expect ( req . object . get ( 'foo' ) ) . toEqual ( 'bar' ) ;
2629+ expect ( req . context . otherKey ) . toBe ( 10 ) ;
2630+ expect ( req . context . key ) . toBe ( 'hello' ) ;
2631+ calledAfter = true ;
2632+ } ) ;
2633+ const req = request ( {
2634+ method : 'POST' ,
2635+ url : 'http://localhost:8378/1/classes/TestObject' ,
2636+ headers : {
2637+ 'X-Parse-REST-API-Key' : 'rest' ,
2638+ 'X-Parse-Cloud-Context' : '{"key":"value","otherKey":1}' ,
2639+ } ,
2640+ body : {
2641+ foo : 'bar' ,
2642+ _ApplicationId : 'test' ,
2643+ _context : '{"key":"hello","otherKey":10}' ,
2644+ } ,
2645+ } ) ;
2646+ await req ;
2647+ expect ( calledBefore ) . toBe ( true ) ;
2648+ expect ( calledAfter ) . toBe ( true ) ;
2649+ } ) ;
2650+
2651+ it ( 'should throw error if context body is malformed' , async ( ) => {
2652+ let calledBefore = false ;
2653+ let calledAfter = false ;
2654+ Parse . Cloud . beforeSave ( 'TestObject' , ( ) => {
2655+ calledBefore = true ;
2656+ } ) ;
2657+ Parse . Cloud . afterSave ( 'TestObject' , ( ) => {
2658+ calledAfter = true ;
2659+ } ) ;
2660+ const req = request ( {
2661+ method : 'POST' ,
2662+ url : 'http://localhost:8378/1/classes/TestObject' ,
2663+ headers : {
2664+ 'X-Parse-REST-API-Key' : 'rest' ,
2665+ 'X-Parse-Cloud-Context' : '{"key":"value","otherKey":1}' ,
2666+ } ,
2667+ body : {
2668+ foo : 'bar' ,
2669+ _ApplicationId : 'test' ,
2670+ _context : 'key' ,
2671+ } ,
2672+ } ) ;
2673+ try {
2674+ await req ;
2675+ fail ( 'Should have thrown error' ) ;
2676+ } catch ( e ) {
2677+ expect ( e ) . toBeDefined ( ) ;
2678+ expect ( e . data . code ) . toEqual ( Parse . Error . INVALID_JSON ) ;
2679+ }
2680+ expect ( calledBefore ) . toBe ( false ) ;
2681+ expect ( calledAfter ) . toBe ( false ) ;
2682+ } ) ;
2683+
2684+ it ( 'should throw error if context body is string "true"' , async ( ) => {
2685+ let calledBefore = false ;
2686+ let calledAfter = false ;
2687+ Parse . Cloud . beforeSave ( 'TestObject' , ( ) => {
2688+ calledBefore = true ;
2689+ } ) ;
2690+ Parse . Cloud . afterSave ( 'TestObject' , ( ) => {
2691+ calledAfter = true ;
2692+ } ) ;
2693+ const req = request ( {
2694+ method : 'POST' ,
2695+ url : 'http://localhost:8378/1/classes/TestObject' ,
2696+ headers : {
2697+ 'X-Parse-REST-API-Key' : 'rest' ,
2698+ 'X-Parse-Cloud-Context' : '{"key":"value","otherKey":1}' ,
2699+ } ,
2700+ body : {
2701+ foo : 'bar' ,
2702+ _ApplicationId : 'test' ,
2703+ _context : 'true' ,
2704+ } ,
2705+ } ) ;
2706+ try {
2707+ await req ;
2708+ fail ( 'Should have thrown error' ) ;
2709+ } catch ( e ) {
2710+ expect ( e ) . toBeDefined ( ) ;
2711+ expect ( e . data . code ) . toEqual ( Parse . Error . INVALID_JSON ) ;
2712+ }
2713+ expect ( calledBefore ) . toBe ( false ) ;
2714+ expect ( calledAfter ) . toBe ( false ) ;
2715+ } ) ;
2716+
25222717 it ( 'should expose context in before and afterSave' , async ( ) => {
25232718 let calledBefore = false ;
25242719 let calledAfter = false ;
@@ -2804,6 +2999,26 @@ describe('afterLogin hook', () => {
28042999 done ( ) ;
28053000 } ) ;
28063001
3002+ it ( 'context options should override _context object property when saving a new object' , async ( ) => {
3003+ Parse . Cloud . beforeSave ( 'TestObject' , req => {
3004+ expect ( req . context . a ) . toEqual ( 'a' ) ;
3005+ expect ( req . context . hello ) . not . toBeDefined ( ) ;
3006+ expect ( req . _context ) . not . toBeDefined ( ) ;
3007+ expect ( req . object . _context ) . not . toBeDefined ( ) ;
3008+ expect ( req . object . context ) . not . toBeDefined ( ) ;
3009+ } ) ;
3010+ Parse . Cloud . afterSave ( 'TestObject' , req => {
3011+ expect ( req . context . a ) . toEqual ( 'a' ) ;
3012+ expect ( req . context . hello ) . not . toBeDefined ( ) ;
3013+ expect ( req . _context ) . not . toBeDefined ( ) ;
3014+ expect ( req . object . _context ) . not . toBeDefined ( ) ;
3015+ expect ( req . object . context ) . not . toBeDefined ( ) ;
3016+ } ) ;
3017+ const obj = new TestObject ( ) ;
3018+ obj . set ( '_context' , { hello : 'world' } ) ;
3019+ await obj . save ( null , { context : { a : 'a' } } ) ;
3020+ } ) ;
3021+
28073022 it ( 'should have access to context when saving a new object' , async ( ) => {
28083023 Parse . Cloud . beforeSave ( 'TestObject' , req => {
28093024 expect ( req . context . a ) . toEqual ( 'a' ) ;
0 commit comments