@@ -151,6 +151,48 @@ describe('ParseGraphQL Query Complexity', () => {
151151 const result = await masterClient . query ( { query } ) ;
152152 expect ( result . data . users ) . toBeDefined ( ) ;
153153 } ) ;
154+
155+ it ( 'should allow queries with maintenance key even when exceeding fields limit' , async ( ) => {
156+ await reconfigureServer ( {
157+ maintenanceKey : 'maintenanceKey123' ,
158+ maxGraphQLQueryComplexity : {
159+ fields : 3 ,
160+ } ,
161+ } ) ;
162+
163+ const httpLinkWithMaintenance = createHttpLink ( {
164+ uri : 'http://localhost:13378/graphql' ,
165+ fetch : ( ...args ) => import ( 'node-fetch' ) . then ( ( { default : fetch } ) => fetch ( ...args ) ) ,
166+ headers : {
167+ 'X-Parse-Application-Id' : 'test' ,
168+ 'X-Parse-Maintenance-Key' : 'maintenanceKey123' ,
169+ } ,
170+ } ) ;
171+
172+ const maintenanceClient = new ApolloClient ( {
173+ link : httpLinkWithMaintenance ,
174+ cache : new InMemoryCache ( ) ,
175+ } ) ;
176+
177+ const query = gql `
178+ query {
179+ users {
180+ edges {
181+ node {
182+ objectId
183+ username
184+ createdAt
185+ updatedAt
186+ email
187+ }
188+ }
189+ }
190+ }
191+ ` ;
192+
193+ const result = await maintenanceClient . query ( { query } ) ;
194+ expect ( result . data . users ) . toBeDefined ( ) ;
195+ } ) ;
154196 } ) ;
155197
156198 describe ( 'maxGraphQLQueryComplexity.depth' , ( ) => {
@@ -660,5 +702,335 @@ describe('ParseGraphQL Query Complexity', () => {
660702 expect ( deepResult . errors [ 0 ] . message ) . toContain ( 'Query depth exceeds maximum allowed depth' ) ;
661703 } ) ;
662704 } ) ;
705+
706+ describe ( 'Skipping validation with -1' , ( ) => {
707+ it ( 'should skip depth validation when depth is -1' , async ( ) => {
708+ await reconfigureServer ( {
709+ maxGraphQLQueryComplexity : {
710+ depth : - 1 ,
711+ fields : 50 ,
712+ } ,
713+ } ) ;
714+
715+ // Very deep query that would normally fail
716+ const query = gql `
717+ query {
718+ users {
719+ edges {
720+ node {
721+ objectId
722+ username
723+ createdAt
724+ updatedAt
725+ email
726+ emailVerified
727+ username
728+ }
729+ }
730+ }
731+ }
732+ ` ;
733+
734+ const result = await apolloClient . query ( { query } ) ;
735+ expect ( result . data . users ) . toBeDefined ( ) ;
736+ } ) ;
737+
738+ it ( 'should skip fields validation when fields is -1' , async ( ) => {
739+ await reconfigureServer ( {
740+ maxGraphQLQueryComplexity : {
741+ depth : 10 ,
742+ fields : - 1 ,
743+ } ,
744+ } ) ;
745+
746+ // Many fields query that would normally fail
747+ const query = gql `
748+ query {
749+ users {
750+ edges {
751+ node {
752+ objectId
753+ username
754+ createdAt
755+ updatedAt
756+ email
757+ emailVerified
758+ }
759+ }
760+ }
761+ }
762+ ` ;
763+
764+ const result = await apolloClient . query ( { query } ) ;
765+ expect ( result . data . users ) . toBeDefined ( ) ;
766+ } ) ;
767+
768+ it ( 'should skip both validations when both are -1' , async ( ) => {
769+ await reconfigureServer ( {
770+ maxGraphQLQueryComplexity : {
771+ depth : - 1 ,
772+ fields : - 1 ,
773+ } ,
774+ } ) ;
775+
776+ // Very complex query
777+ const query = gql `
778+ query {
779+ users {
780+ edges {
781+ node {
782+ objectId
783+ username
784+ createdAt
785+ updatedAt
786+ email
787+ emailVerified
788+ }
789+ }
790+ }
791+ }
792+ ` ;
793+
794+ const result = await apolloClient . query ( { query } ) ;
795+ expect ( result . data . users ) . toBeDefined ( ) ;
796+ } ) ;
797+
798+ it ( 'should enforce fields limit when depth is -1' , async ( ) => {
799+ await reconfigureServer ( {
800+ maxGraphQLQueryComplexity : {
801+ depth : - 1 ,
802+ fields : 3 ,
803+ } ,
804+ } ) ;
805+
806+ const query = gql `
807+ query {
808+ users {
809+ edges {
810+ node {
811+ objectId
812+ username
813+ createdAt
814+ updatedAt
815+ }
816+ }
817+ }
818+ }
819+ ` ;
820+
821+ try {
822+ await apolloClient . query ( { query } ) ;
823+ fail ( 'Should have thrown an error' ) ;
824+ } catch ( error ) {
825+ expect ( error . networkError . result . errors [ 0 ] . message ) . toContain ( 'Number of fields selected exceeds maximum allowed' ) ;
826+ }
827+ } ) ;
828+ } ) ;
829+
830+ describe ( 'Restricting with depth 0' , ( ) => {
831+ it ( 'should reject all queries when depth is 0' , async ( ) => {
832+ await reconfigureServer ( {
833+ maxGraphQLQueryComplexity : {
834+ depth : 0 ,
835+ } ,
836+ } ) ;
837+
838+ const query = gql `
839+ query {
840+ users {
841+ edges {
842+ node {
843+ objectId
844+ }
845+ }
846+ }
847+ }
848+ ` ;
849+
850+ try {
851+ await apolloClient . query ( { query } ) ;
852+ fail ( 'Should have thrown an error' ) ;
853+ } catch ( error ) {
854+ expect ( error . networkError . result . errors [ 0 ] . message ) . toContain ( 'Query depth exceeds maximum allowed depth' ) ;
855+ }
856+ } ) ;
857+
858+ it ( 'should reject all queries when fields is 0' , async ( ) => {
859+ await reconfigureServer ( {
860+ maxGraphQLQueryComplexity : {
861+ fields : 0 ,
862+ } ,
863+ } ) ;
864+
865+ const query = gql `
866+ query {
867+ users {
868+ edges {
869+ node {
870+ objectId
871+ }
872+ }
873+ }
874+ }
875+ ` ;
876+
877+ try {
878+ await apolloClient . query ( { query } ) ;
879+ fail ( 'Should have thrown an error' ) ;
880+ } catch ( error ) {
881+ expect ( error . networkError . result . errors [ 0 ] . message ) . toContain ( 'Number of fields selected exceeds maximum allowed' ) ;
882+ }
883+ } ) ;
884+
885+ it ( 'should allow master key even with depth 0' , async ( ) => {
886+ await reconfigureServer ( {
887+ maxGraphQLQueryComplexity : {
888+ depth : 0 ,
889+ } ,
890+ } ) ;
891+
892+ const httpLinkWithMaster = createHttpLink ( {
893+ uri : 'http://localhost:13378/graphql' ,
894+ fetch : ( ...args ) => import ( 'node-fetch' ) . then ( ( { default : fetch } ) => fetch ( ...args ) ) ,
895+ headers : {
896+ 'X-Parse-Application-Id' : 'test' ,
897+ 'X-Parse-Master-Key' : 'test' ,
898+ } ,
899+ } ) ;
900+
901+ const masterClient = new ApolloClient ( {
902+ link : httpLinkWithMaster ,
903+ cache : new InMemoryCache ( ) ,
904+ } ) ;
905+
906+ const query = gql `
907+ query {
908+ users {
909+ edges {
910+ node {
911+ objectId
912+ }
913+ }
914+ }
915+ }
916+ ` ;
917+
918+ const result = await masterClient . query ( { query } ) ;
919+ expect ( result . data . users ) . toBeDefined ( ) ;
920+ } ) ;
921+
922+ it ( 'should allow master key even with fields 0' , async ( ) => {
923+ await reconfigureServer ( {
924+ maxGraphQLQueryComplexity : {
925+ fields : 0 ,
926+ } ,
927+ } ) ;
928+
929+ const httpLinkWithMaster = createHttpLink ( {
930+ uri : 'http://localhost:13378/graphql' ,
931+ fetch : ( ...args ) => import ( 'node-fetch' ) . then ( ( { default : fetch } ) => fetch ( ...args ) ) ,
932+ headers : {
933+ 'X-Parse-Application-Id' : 'test' ,
934+ 'X-Parse-Master-Key' : 'test' ,
935+ } ,
936+ } ) ;
937+
938+ const masterClient = new ApolloClient ( {
939+ link : httpLinkWithMaster ,
940+ cache : new InMemoryCache ( ) ,
941+ } ) ;
942+
943+ const query = gql `
944+ query {
945+ users {
946+ edges {
947+ node {
948+ objectId
949+ }
950+ }
951+ }
952+ }
953+ ` ;
954+
955+ const result = await masterClient . query ( { query } ) ;
956+ expect ( result . data . users ) . toBeDefined ( ) ;
957+ } ) ;
958+
959+ it ( 'should allow maintenance key even with depth 0' , async ( ) => {
960+ await reconfigureServer ( {
961+ maintenanceKey : 'maintenanceKey123' ,
962+ maxGraphQLQueryComplexity : {
963+ depth : 0 ,
964+ } ,
965+ } ) ;
966+
967+ const httpLinkWithMaintenance = createHttpLink ( {
968+ uri : 'http://localhost:13378/graphql' ,
969+ fetch : ( ...args ) => import ( 'node-fetch' ) . then ( ( { default : fetch } ) => fetch ( ...args ) ) ,
970+ headers : {
971+ 'X-Parse-Application-Id' : 'test' ,
972+ 'X-Parse-Maintenance-Key' : 'maintenanceKey123' ,
973+ } ,
974+ } ) ;
975+
976+ const maintenanceClient = new ApolloClient ( {
977+ link : httpLinkWithMaintenance ,
978+ cache : new InMemoryCache ( ) ,
979+ } ) ;
980+
981+ const query = gql `
982+ query {
983+ users {
984+ edges {
985+ node {
986+ objectId
987+ }
988+ }
989+ }
990+ }
991+ ` ;
992+
993+ const result = await maintenanceClient . query ( { query } ) ;
994+ expect ( result . data . users ) . toBeDefined ( ) ;
995+ } ) ;
996+
997+ it ( 'should allow maintenance key even with fields 0' , async ( ) => {
998+ await reconfigureServer ( {
999+ maintenanceKey : 'maintenanceKey123' ,
1000+ maxGraphQLQueryComplexity : {
1001+ fields : 0 ,
1002+ } ,
1003+ } ) ;
1004+
1005+ const httpLinkWithMaintenance = createHttpLink ( {
1006+ uri : 'http://localhost:13378/graphql' ,
1007+ fetch : ( ...args ) => import ( 'node-fetch' ) . then ( ( { default : fetch } ) => fetch ( ...args ) ) ,
1008+ headers : {
1009+ 'X-Parse-Application-Id' : 'test' ,
1010+ 'X-Parse-Maintenance-Key' : 'maintenanceKey123' ,
1011+ } ,
1012+ } ) ;
1013+
1014+ const maintenanceClient = new ApolloClient ( {
1015+ link : httpLinkWithMaintenance ,
1016+ cache : new InMemoryCache ( ) ,
1017+ } ) ;
1018+
1019+ const query = gql `
1020+ query {
1021+ users {
1022+ edges {
1023+ node {
1024+ objectId
1025+ }
1026+ }
1027+ }
1028+ }
1029+ ` ;
1030+
1031+ const result = await maintenanceClient . query ( { query } ) ;
1032+ expect ( result . data . users ) . toBeDefined ( ) ;
1033+ } ) ;
1034+ } ) ;
6631035} ) ;
6641036
0 commit comments