From 47d676d0510ff89cc1bcb647e70c5e6e0f2befb8 Mon Sep 17 00:00:00 2001 From: Andrey Lunyov Date: Mon, 18 Mar 2019 16:13:41 -0700 Subject: [PATCH] Generate payload for operation Reviewed By: jstejada Differential Revision: D14406786 fbshipit-source-id: 929fc242a4127e368fa6785cd12585d92550cd2a --- .../RelayMockPayloadGenerator.js | 57 +++++++++++++++---- .../RelayMockPayloadGenerator-test.js | 32 +++++++++++ .../RelayMockPayloadGenerator-test.js.snap | 38 ++++++++++++- 3 files changed, 112 insertions(+), 15 deletions(-) diff --git a/packages/relay-test-utils/RelayMockPayloadGenerator.js b/packages/relay-test-utils/RelayMockPayloadGenerator.js index 7ffae7a66f187..3c6e73b67e481 100644 --- a/packages/relay-test-utils/RelayMockPayloadGenerator.js +++ b/packages/relay-test-utils/RelayMockPayloadGenerator.js @@ -47,9 +47,11 @@ import type { ReaderSelection, ReaderScalarField, ReaderLinkedField, + NormalizationOperation, NormalizationSelection, NormalizationLinkedField, NormalizationScalarField, + OperationDescriptor, } from 'relay-runtime'; type ValueResolver = ( @@ -88,7 +90,11 @@ function createIdGenerator() { const DEFAULT_MOCK_RESOLVERS = { ID(context, generateId: () => number) { - return `<${context.parentType}-mock-id-${generateId()}>`; + return `<${ + context.parentType != null && context.parentType !== DEFAULT_MOCK_TYPENAME + ? context.parentType + '-' + : '' + }mock-id-${generateId()}>`; }, Boolean() { return false; @@ -177,7 +183,7 @@ class RelayMockPayloadGenerator { selections: $ReadOnlyArray, typeName: string, plural: boolean, - ): mixed { + ): MockData | $ReadOnlyArray { const generateListItem = () => { const defaultValues = this._getDefaultValuesForObject( typeName, @@ -207,7 +213,7 @@ class RelayMockPayloadGenerator { path: $ReadOnlyArray, prevData: ?MockData, defaultValues: ?MockData, - ): MockData | $ReadOnlyArray { + ): MockData { const {selections, typeName} = traversable; return this._traverseSelections( @@ -588,11 +594,11 @@ class RelayMockPayloadGenerator { * Generate mock variables for ReaderFragment */ function generateVariables( - fragment: ReaderFragment, + node: ReaderFragment | NormalizationOperation, mockResolvers: ?MockResolvers, ): Variables { const variables = {}; - const {argumentDefinitions} = fragment; + const {argumentDefinitions} = node; const argumentValueGenerator = createValueResolver({ ...DEFAULT_MOCK_RESOLVERS, ...mockResolvers, @@ -625,20 +631,46 @@ function generateVariables( * Generate mock data for ReaderFragment selection */ function generateData( - fragment: ReaderFragment, + node: ReaderFragment | NormalizationOperation, mockResolvers: ?MockResolvers, - variables?: Variables = generateVariables(fragment, mockResolvers), + variables?: Variables = generateVariables(node, mockResolvers), schema?: ?GraphQLSchema, -): mixed { +): MockData | $ReadOnlyArray { const mockGenerator = new RelayMockPayloadGenerator({ variables, schema, mockResolvers, }); - const data = mockGenerator.generate( - fragment.selections, - fragment.type, - fragment.metadata?.plural ?? false, + let typeName; + if (node.kind === 'Operation') { + if (node.name.endsWith('Mutation')) { + typeName = 'Mutation'; + } else if (node.name.endsWith('Subscription')) { + typeName = 'Subscription'; + } else { + typeName = 'Query'; + } + } else { + typeName = node.type; + } + const plural = + node.kind === 'Operation' ? false : node.metadata?.plural ?? false; + const data = mockGenerator.generate(node.selections, typeName, plural); + return data; +} + +function generateDataForOperation( + operation: OperationDescriptor, + mockResolvers: ?MockResolvers, +): MockData { + const data = generateData( + operation.node.operation, + mockResolvers, + operation.variables, + ); + invariant( + !Array.isArray(data), + 'RelayMockPayloadGenerator: Invalid generated payload, unexpected array.', ); return data; } @@ -647,4 +679,5 @@ module.exports = { DEFAULT_MOCK_TYPENAME, generateVariables, generateData, + generateDataForOperation, }; diff --git a/packages/relay-test-utils/__tests__/RelayMockPayloadGenerator-test.js b/packages/relay-test-utils/__tests__/RelayMockPayloadGenerator-test.js index 2b8da526db89c..d64cee1904c15 100644 --- a/packages/relay-test-utils/__tests__/RelayMockPayloadGenerator-test.js +++ b/packages/relay-test-utils/__tests__/RelayMockPayloadGenerator-test.js @@ -17,6 +17,7 @@ const RelayTestSchema = require('../RelayTestSchema'); // $FlowFixMe const {FIXTURE_TAG, generateAndCompile} = require('../RelayModernTestUtils'); const {parse, print} = require('graphql'); +const {getRequest, createOperationDescriptor} = require('relay-runtime'); import type {MockResolvers} from '../RelayMockPayloadGenerator'; @@ -619,3 +620,34 @@ test('should return `null` for selection if that is specified in default values' }, ); }); + +test('generate payload for operation', () => { + const graphql = ` + query TestQuery($id: ID!, $scale: Float) { + node(id: $id) { + ... on User { + name + profile_picture(scale: $scale) { + uri + } + } + } + } + `; + const {TestQuery: query} = compile(graphql); + const variables = RelayMockPayloadGenerator.generateVariables(query.fragment); + const operation = createOperationDescriptor(getRequest(query), variables); + const data = RelayMockPayloadGenerator.generateDataForOperation(operation); + expect({ + [FIXTURE_TAG]: true, + input: print(parse(graphql)), + output: JSON.stringify( + { + variables, + data, + }, + null, + 2, + ), + }).toMatchSnapshot(); +}); diff --git a/packages/relay-test-utils/__tests__/__snapshots__/RelayMockPayloadGenerator-test.js.snap b/packages/relay-test-utils/__tests__/__snapshots__/RelayMockPayloadGenerator-test.js.snap index 9e8021eeb9ad4..537016672e7fa 100644 --- a/packages/relay-test-utils/__tests__/__snapshots__/RelayMockPayloadGenerator-test.js.snap +++ b/packages/relay-test-utils/__tests__/__snapshots__/RelayMockPayloadGenerator-test.js.snap @@ -132,7 +132,7 @@ fragment TestFragment on User { }, "actor": { "name": "", - "id": "<__MockObject-mock-id-1>", + "id": "", "__typename": "__MockObject" }, "myActor": { @@ -304,7 +304,7 @@ fragment TestFragment on User @argumentDefinitions(condition: {type: "Boolean!"} "id": "", "name": "", "myActor": { - "id": "<__MockObject-mock-id-2>", + "id": "", "name": "" }, "customName": "", @@ -452,7 +452,7 @@ Output: { "variables": {}, "payload": { "actor": { - "id": "<__MockObject-mock-id-1>", + "id": "", "name": "" }, "backgroundImage": { @@ -789,6 +789,38 @@ fragment TestFragment on User { } `; +exports[`generate payload for operation 1`] = ` +~~~~~~~~~~ INPUT ~~~~~~~~~~ +query TestQuery($id: ID!, $scale: Float) { + node(id: $id) { + ... on User { + name + profile_picture(scale: $scale) { + uri + } + } + } +} + +~~~~~~~~~~ OUTPUT ~~~~~~~~~~ +{ + "variables": { + "id": "", + "scale": 4.2 + }, + "data": { + "node": { + "__typename": "User", + "id": "", + "name": "", + "profile_picture": { + "uri": "" + } + } + } +} +`; + exports[`should return \`null\` for selection if that is specified in default values 1`] = ` ~~~~~~~~~~ INPUT ~~~~~~~~~~ fragment TestFragment on User {