UNPKG

graphx

Version:

Visualize and analyse GraphQL query results in a true Graph.

344 lines (316 loc) 12.1 kB
/** * Copyright (c) 2017, Neap Pty Ltd. * 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. */ const _ = require('lodash'); const assert = require('assert'); const { chain, throwError, isScalarType, getEdge, log, set, newShortId, removeMultiSpaces, escapeGraphQlSchema, astParse, cleanAndFormatQuery, escapeArguments, jsonify, escapeEnumValues, blockify, getBlockProperties, getEscapedProperties, replaceBlocksAndArgs, getEdgeDesc, isNodeType, flattenNodes, getQueryFields } = require('../../src/utilities'); describe('utilities', () => describe('#getEdge', () => it("Should extract relations info from edges like <-['CREATED']-", () => { const edge = getEdge("<-['CREATED']-"); assert.ok(edge); assert.equal(edge.leftnode, 'default'); assert.equal(edge.rightnode, 'default'); assert.ok(edge.relation); assert.equal(edge.relation.label, "'CREATED'"); assert.equal(edge.relation.direction, "<"); }))); describe('utilities', () => describe('#getEdge', () => it("Should extract relations info from edges like (brand)<-['ABOUT']-(posts.data)", () => { const edge = getEdge("(brand)<-['ABOUT']-(posts.data)"); assert.ok(edge); assert.equal(edge.leftnode, 'default'); assert.equal(edge.rightnode, 'data'); assert.ok(edge.relation); assert.equal(edge.relation.label, "'ABOUT'"); assert.equal(edge.relation.direction, "<"); }))); describe('utilities', () => describe('#getEdge', () => it("Should extract relations info from relations like (brand)<-['ABOUT']-(posts.data)", () => { const edge = getEdge("<-['ABOUT']-(posts.data)"); assert.ok(edge); assert.equal(edge.leftnode, 'default'); assert.equal(edge.rightnode, 'data'); assert.ok(edge.relation); assert.equal(edge.relation.label, "'ABOUT'"); assert.equal(edge.relation.direction, "<"); }))); describe('utilities', () => describe('#getEdge', () => it("Should extract relations info from edges like (post)<-[(post, user) => 'RATED:' + user.rating]-(users.data)", () => { const edge = getEdge("(post)<-[(post, user) => 'RATED:' + user.rating]-(users.data)"); assert.ok(edge); assert.equal(edge.leftnode, 'default'); assert.equal(edge.rightnode, 'data'); assert.ok(edge.relation); assert.equal(edge.relation.label, "(post, user) => 'RATED:' + user.rating"); assert.equal(edge.relation.direction, "<"); }))); describe('utilities', () => describe('#getEdge', () => it("Should throw an error if the relation's direction is badly formatted.", () => { assert.throws(() => getEdge("(post)-[(post, user) => 'RATED:' + user.rating]-(users.data)"), /Failed to extract the relation's direction/); }))); describe('utilities', () => describe('#getEdge', () => it("Should throw an error if the relation is badly formatted.", () => { assert.throws(() => getEdge("(post)<-[(post, user) => 'RATED:' + user.rating-(users.data)"), /Failed to extract the relation/); }))); describe('utilities', () => describe('#getEdge', () => it("Should generate a dynamic relation for edges like <-['CREATED']-", () => { const edge = getEdge("<-['CREATED']-"); assert.ok(edge); assert.ok(edge.relation); assert.equal(edge.relation.generate(null, { rating:'love' }), "CREATED"); }))); describe('utilities', () => describe('#getEdge', () => it("Should generate a dynamic relation for edges like (post)<-[(post, user) => 'RATED:' + user.rating-(users.data)", () => { const edge = getEdge("(post)<-[(post, user) => 'RATED:' + user.rating]-(users.data)"); assert.ok(edge); assert.ok(edge.relation); assert.equal(edge.relation.generate(null, { rating:'love' }), "RATED:love"); }))); describe('utilities', () => describe('#set', () => it("Should set a specific property of an object to a specific value (e.g. set(a, 'name', 'Peter'))", () => { const a = {}; const b = set(a, 'name', 'Peter'); assert.equal(b.name, "Peter"); }))); describe('utilities', () => describe('#set', () => it("Should set a specific properties of an object to a set of specific values (e.g. set(a, ['name', 'age'], ['Peter', 3]))", () => { const a = {}; const b = set(a, ['name', 'age'], ['Peter', 3]); assert.equal(b.name, "Peter"); assert.equal(b.age, 3); }))); describe('utilities', () => describe('#set', () => it("Should mutate an object if a mutate function is passed as the 4th argument", () => { const a = { array:[] }; const b = set(a, ['name', 'age'], ['Peter', 3], x => x.array.push(2)); assert.equal(b.name, "Peter"); assert.equal(b.age, 3); assert.equal(a.array.length, 1); assert.equal(a.array[0], 2); }))); const query_47298dn = ` query { brands(where: {id: 1}){ data { id name } } }` const query_debuqc6e32 = ` query { brands { name } }` const query_47328dewiu = ` { brands { name } }` describe('utilities', () => describe('#cleanAndFormatQuery', () => it("Should validate that the request is a legit query and not a mutation.", () => { const q = cleanAndFormatQuery(query_debuqc6e32); assert.equal((q.match(/^{/) || [])[0], "{"); const q2 = cleanAndFormatQuery(query_debuqc6e32); assert.equal((q2.match(/^{/) || [])[0], "{"); }))); const query_3782db = ` mutation { brands { name } }` describe('utilities', () => describe('#cleanAndFormatQuery', () => it("Should throw an error if the request is a mutation.", () => { assert.throws(() => cleanAndFormatQuery(query_3782db), /Error in method 'cleanAndFormatQuery': Cannot process mutations./); }))); describe('utilities', () => describe('#getEscapedProperties', () => it("Should extract each block's properties from an escaped block line.", () => { const v = _.toArray(_(getEscapedProperties('id name posts--643289--__r1tul89vzb__ posts __HJPdlL5Pzb__ firstname')).sortBy(x => x)); assert.equal(v.length, 5); assert.equal(v[0], 'firstname'); assert.equal(v[1], 'id'); assert.equal(v[2], 'name'); assert.equal(v[3], 'posts __HJPdlL5Pzb__'); assert.equal(v[4], 'posts--643289--__r1tul89vzb__'); const v2 = _.toArray(_(getEscapedProperties('id name')).sortBy(x => x)); assert.equal(v2.length, 2); assert.equal(v2[0], 'id'); assert.equal(v2[1], 'name'); const v3 = _.toArray(_(getEscapedProperties('')).sortBy(x => x)); assert.equal(v3.length, 0); const v4 = _.toArray(_(getEscapedProperties('where:__r1tul89vzb__ page: __HJPdlL5Pzb__')).sortBy(x => x)); assert.equal(v4.length, 2); assert.equal(v4[0], 'page: __HJPdlL5Pzb__'); assert.equal(v4[1], 'where:__r1tul89vzb__'); }))); const query_cwkjbTL31Y = ` query { brands(where: {id: 1}){ data { id name } } }` describe('utilities', () => describe('#escapeArguments', () => it("Should escape all argument blocks from the GraphQL query.", () => { const result = escapeArguments(cleanAndFormatQuery(query_cwkjbTL31Y)); assert.ok(result); assert.ok(result.query); assert.ok(result.argBlocks); assert.equal(result.argBlocks.length, 1); assert.ok(result.argBlocks[0].alias); assert.ok(result.argBlocks[0].value); const m = result.query.match(/{ brands(.*?){ data { id name } } }/); assert.ok(m); assert.equal(m[1], result.argBlocks[0].alias); assert.equal(JSON.stringify(result.argBlocks[0].value), '{"where":{"id":1}}') }))); describe('utilities', () => describe('#escapeEnumValues', () => it("Should wrap GraphQL enum values between double-quotes so we can parse them as a JSON object.", () => { const result = escapeEnumValues("{ where : {id: 1 voted: SUCK page :1} nickname: 'Ella' page : {first: 10} rating:LOVE}"); assert.equal(result, '{ where : {id: 1 voted:"SUCK" page :1} nickname: \'Ella\' page : {first: 10} rating:"LOVE"}'); }))); describe('utilities', () => describe('#jsonify', () => it("Should parse a non-conventional JSON string into a JSON object", () => { const result = jsonify('( where : {id: "-KkL9EdTh9abV: 9xAwHUa" page :1} nickname: "Ella" page : {first: 10})'); assert.ok(result); assert.ok(result.where); assert.ok(result.page); assert.equal(result.nickname, "Ella"); assert.equal(result.where.id, "-KkL9EdTh9abV: 9xAwHUa"); assert.equal(result.where.page, 1); assert.equal(result.page.first, 10); }))); const query_cajYlQ207 = ` query { brands( # some comments to make things harder to parse where:{id: '-KkL9EdTh9abV9xAwHUa'}, page:{first:10}) { # { some comments to make things harder to parse data { id name # some comments to make things harder to parse posts(where:{rating:LOVE}){ data { author { username } users(have:{id: "-TiL9Eddwd&9abV9xAwHUa", rated:LOVE}){ data { rating username } } } } } } }` describe('utilities', () => describe('#astParse', () => it("Should create an AST from any string GraphQL query.", () => { const ast = astParse(query_cajYlQ207); assert.ok(ast); assert.equal(ast.length, 1); const prop1 = ast[0]; assert.equal(prop1.name, "brands"); assert.ok(prop1.args.where); assert.ok(prop1.args.page); assert.equal(prop1.args.where.id,"-KkL9EdTh9abV9xAwHUa"); assert.equal(prop1.args.page.first, 10); assert.ok(prop1.properties); assert.equal(prop1.properties.length, 1); const prop1_0 = prop1.properties[0]; assert.equal(prop1_0.name, "data"); assert.ok(prop1_0.properties); assert.equal(prop1_0.properties.length, 3); assert.equal(prop1_0.properties[0].name, "id"); assert.equal(prop1_0.properties[1].name, "name"); assert.equal(prop1_0.properties[2].name, "posts"); assert.ok(prop1_0.properties[2].args); assert.ok(prop1_0.properties[2].args.where); assert.equal(prop1_0.properties[2].args.where.rating, "LOVE"); assert.equal(prop1_0.properties[2].properties[0].properties[1].name, "users"); assert.equal(prop1_0.properties[2].properties[0].properties[1].args.have.id, "-TiL9Eddwd&9abV9xAwHUa"); }))); const schemaAST_4dnedu6 = [{ "type": "TYPE", "name": "User", "metadata": { "name": "node", "body": "", "schemaType": "TYPE", "schemaName": "User", "parent": null }, }, { "type": "TYPE", "name": "PagedBrand", "metadata": null, "genericType": "T" }] describe('utilities', () => describe('#isNodeType', () => it("Should create an AST from any string GraphQL query.", () => { assert.equal(isNodeType('ID', schemaAST_4dnedu6), false); assert.equal(isNodeType('ID!', schemaAST_4dnedu6), false); assert.equal(isNodeType('String', schemaAST_4dnedu6), false); assert.equal(isNodeType('String!', schemaAST_4dnedu6), false); assert.equal(isNodeType('Float', schemaAST_4dnedu6), false); assert.equal(isNodeType('Float!', schemaAST_4dnedu6), false); assert.equal(isNodeType('Int', schemaAST_4dnedu6), false); assert.equal(isNodeType('Int!', schemaAST_4dnedu6), false); assert.equal(isNodeType('User', schemaAST_4dnedu6), true); assert.equal(isNodeType('[User]', schemaAST_4dnedu6), true); assert.equal(isNodeType('PagedBrand', schemaAST_4dnedu6), false); assert.throws(() => isNodeType('Hello', schemaAST_4dnedu6), /Type 'Hello' does not exist in the GraphQL schema/); })));