Skip to content

Commit

Permalink
Generate payload for operation
Browse files Browse the repository at this point in the history
Reviewed By: jstejada

Differential Revision: D14406786

fbshipit-source-id: 929fc242a4127e368fa6785cd12585d92550cd2a
  • Loading branch information
alunyov authored and facebook-github-bot committed Mar 18, 2019
1 parent fdff791 commit 47d676d
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 15 deletions.
57 changes: 45 additions & 12 deletions packages/relay-test-utils/RelayMockPayloadGenerator.js
Expand Up @@ -47,9 +47,11 @@ import type {
ReaderSelection,
ReaderScalarField,
ReaderLinkedField,
NormalizationOperation,
NormalizationSelection,
NormalizationLinkedField,
NormalizationScalarField,
OperationDescriptor,
} from 'relay-runtime';

type ValueResolver = (
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -177,7 +183,7 @@ class RelayMockPayloadGenerator {
selections: $ReadOnlyArray<ReaderSelection | NormalizationSelection>,
typeName: string,
plural: boolean,
): mixed {
): MockData | $ReadOnlyArray<MockData> {
const generateListItem = () => {
const defaultValues = this._getDefaultValuesForObject(
typeName,
Expand Down Expand Up @@ -207,7 +213,7 @@ class RelayMockPayloadGenerator {
path: $ReadOnlyArray<string>,
prevData: ?MockData,
defaultValues: ?MockData,
): MockData | $ReadOnlyArray<MockData> {
): MockData {
const {selections, typeName} = traversable;

return this._traverseSelections(
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<MockData> {
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;
}
Expand All @@ -647,4 +679,5 @@ module.exports = {
DEFAULT_MOCK_TYPENAME,
generateVariables,
generateData,
generateDataForOperation,
};
Expand Up @@ -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';

Expand Down Expand Up @@ -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();
});
Expand Up @@ -132,7 +132,7 @@ fragment TestFragment on User {
},
"actor": {
"name": "<mock-value-for-field-\\"name\\">",
"id": "<__MockObject-mock-id-1>",
"id": "<mock-id-1>",
"__typename": "__MockObject"
},
"myActor": {
Expand Down Expand Up @@ -304,7 +304,7 @@ fragment TestFragment on User @argumentDefinitions(condition: {type: "Boolean!"}
"id": "<User-mock-id-1>",
"name": "<mock-value-for-field-\\"name\\">",
"myActor": {
"id": "<__MockObject-mock-id-2>",
"id": "<mock-id-2>",
"name": "<mock-value-for-field-\\"name\\">"
},
"customName": "<mock-value-for-field-\\"customName\\">",
Expand Down Expand Up @@ -452,7 +452,7 @@ Output: {
"variables": {},
"payload": {
"actor": {
"id": "<__MockObject-mock-id-1>",
"id": "<mock-id-1>",
"name": "<mock-value-for-field-\\"name\\">"
},
"backgroundImage": {
Expand Down Expand Up @@ -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": "<mock-id-1>",
"scale": 4.2
},
"data": {
"node": {
"__typename": "User",
"id": "<mock-id-1>",
"name": "<mock-value-for-field-\\"name\\">",
"profile_picture": {
"uri": "<mock-value-for-field-\\"uri\\">"
}
}
}
}
`;

exports[`should return \`null\` for selection if that is specified in default values 1`] = `
~~~~~~~~~~ INPUT ~~~~~~~~~~
fragment TestFragment on User {
Expand Down

0 comments on commit 47d676d

Please sign in to comment.