Home Reference Source Repository

src/query/__tests__/toGraphQL-test.js

/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @emails oncall+relay
 */

'use strict';

require('configureForRelayOSS');

const Relay = require('Relay');
const RelayTestUtils = require('RelayTestUtils');

const filterObject = require('filterObject');
const splitDeferredRelayQueries = require('splitDeferredRelayQueries');
const toGraphQL = require('toGraphQL');

describe('toGraphQL', function() {
  const {defer, getNode} = RelayTestUtils;

  const CONCRETE_KEYS = {
    alias: true,
    arguments: true,
    calls: true,
    children: true,
    directives: true,
    fieldName: true,
    isDeferred: true,
    jsonPath: true,
    kind: true,
    metadata: true,
    name: true,
    responseType: true,
    sourceQueryID: true,
    type: true,
    value: true,
  };

  function filterGraphQLNode(node) {
    node = filterObject(node, (value, key) => {
      if (!CONCRETE_KEYS[key]) {
        return false;
      }
      return !!value && (!Array.isArray(value) || value.length);
    });
    if (node.calls) {
      node.calls = node.calls.length ?
        node.calls.map(filterGraphQLNode) :
        null;
    }
    if (node.children) {
      node.children = node.children.length ?
        node.children.map(filterGraphQLNode) :
        null;
    }
    if (node.directives) {
      node.directives = node.directives.length ?
        node.directives.map(filterGraphQLNode) :
        null;
    }
    if (node.metadata) {
      node.metadata = filterObject(
        node.metadata,
        value => !!value
      );
    }
    return node;
  }

  beforeEach(function() {
    jest.resetModuleRegistry();

    jasmine.addMatchers({
      toConvert() {
        return {
          compare(actual, query) {
            // This filters out extraneous properties from `GraphQL.*` nodes
            // such as `fields` or `fragments`, and reduces metadata down to
            // compare only truthy values. Once the printer outputs plain values
            // the filter step can be removed or simplified (might want to still
            // filter metadata).
            const expected = filterGraphQLNode(query);
            expect(filterGraphQLNode(actual(getNode(query)))).toEqual(expected);
            return {
              pass: true,
            };
          },
        };
      },
    });
  });

  it('converts query', () => {
    expect(toGraphQL.Query).toConvert(Relay.QL`
      query {
        viewer {
          actor {
            id
            name
          }
        }
      }
    `);
  });

  it('converts query with root args', () => {
    expect(toGraphQL.Query).toConvert(Relay.QL`
      query {
        nodes(ids:["1","2","3"]) {
          id
          name
        }
      }
    `);
  });

  it('converts fragment', () => {
    expect(toGraphQL.Fragment).toConvert(Relay.QL`
      fragment on Viewer {
        actor {
          id
          name
        }
      }
    `);
  });

  it('converts field with calls', () => {
    expect(toGraphQL.Query).toConvert(Relay.QL`
      query {
        viewer {
          actor {
            id
            url(site:"www")
          }
        }
      }
    `);
  });

  it('converts connection and generated fields', () => {
    expect(toGraphQL.Query).toConvert(Relay.QL`
      query {
        viewer {
          actor {
            friends(first:"5") {
              edges {
                node {
                  name
                }
              }
            }
          }
        }
      }
    `);
  });

  it('preserves batch call information', () => {
    const fragment = Relay.QL`
      fragment on User {
        name
      }
    `;
    const query = Relay.QL`
      query {
        viewer {
          actor {
            ${defer(fragment)}
          }
        }
      }
    `;
    const splitQueries = splitDeferredRelayQueries(getNode(query));
    const deferredQuery = toGraphQL.Query(splitQueries.deferred[0].required);
    const batchCall = deferredQuery.calls[0].value;

    expect(deferredQuery.isDeferred).toBe(true);
    expect(batchCall.sourceQueryID).toBe('q1');
    expect(batchCall.jsonPath).toBe('$.*.actor.id');
  });

  it('does not double-encode argument values', () => {
    const value = {query: 'Menlo Park'};
    const relayQuery = getNode(Relay.QL`
      query {
        checkinSearchQuery(query:$q) {
          query
        }
      }
    `, {
      q: value,
    });
    const identifyingArg = relayQuery.getIdentifyingArg();
    expect(identifyingArg).toBeDefined();
    expect(identifyingArg.value).toEqual(value);
    const convertedQuery = toGraphQL.Query(relayQuery);
    expect(convertedQuery.calls[0].value.callValue).toBe(value);
  });
});