graphx
Version:
Visualize and analyse GraphQL query results in a true Graph.
1,161 lines (1,121 loc) • 36.1 kB
JavaScript
/**
* 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.
*/
var isbrowser = typeof(chai) != 'undefined';
var assert = isbrowser ? chai.assert : null;
var expect = isbrowser ? chai.expect : null;
var runtest = function(graphx, graphqls2s, assert, expect) {
var getSchemaAST = graphqls2s.getSchemaAST;
var extractNodes = graphx.extractNodes;
var d3Flatten = graphx.d3Flatten;
var getQueryAST = graphx.getQueryAST;
var compileGraphDataToD3 = graphx.compileGraphDataToD3;
var coalesceD3nodes = graphx.coalesceD3nodes;
var D3Obj = graphx.D3Obj;
var resultset = {
"data": {
"brands": {
"data": [
{
"id": "-KkL9EdTh9abV9xAwHUa",
"name": "Alineala llc",
"posts": {
"data": [
{
"author": {
"username": "edytherutkowski"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "edythemillard"
},
{
"rating": "LOVE",
"username": "benedictallmond"
}
]
}
},
{
"author": {
"username": "edytherutkowski"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "roseannedelancey"
}
]
}
},
{
"author": {
"username": "edythecantor"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "jolandadelancey"
},
{
"rating": "LOVE",
"username": "janetteterrio"
}
]
}
},
{
"author": {
"username": "marceldao"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "chancepeart"
}
]
}
},
{
"author": {
"username": "burtonwarrick"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "borisendicott"
}
]
}
},
{
"author": {
"username": "burtonwarrick"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "cythiasurface"
}
]
}
},
{
"author": {
"username": "sherillallmond"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "forrestjohnson"
}
]
}
},
{
"author": {
"username": "sherillallmond"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "pamilaneisler"
},
{
"rating": "LOVE",
"username": "sallywetherbee"
},
{
"rating": "LOVE",
"username": "annaleeiannuzzi"
}
]
}
},
{
"author": {
"username": "sherillallmond"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "olivarutkowski"
},
{
"rating": "LOVE",
"username": "katherynbelles"
},
{
"rating": "LOVE",
"username": "katherynbertucci"
}
]
}
},
{
"author": {
"username": "burtonmccolley"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "christinefurman"
}
]
}
},
{
"author": {
"username": "burtonmccolley"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "addieasuncion"
}
]
}
},
{
"author": {
"username": "burtonmccolley"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "pamilaabsher"
}
]
}
},
{
"author": {
"username": "deannclemens"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "venettabattle"
}
]
}
},
{
"author": {
"username": "hubertcantor"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "olivagaunce"
},
{
"rating": "LOVE",
"username": "annaleeasuncion"
}
]
}
},
{
"author": {
"username": "hubertcantor"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "noeliadey"
}
]
}
},
{
"author": {
"username": "geneviepuga"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "jolandaberak"
}
]
}
},
{
"author": {
"username": "geneviepuga"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "armidadelancey"
}
]
}
},
{
"author": {
"username": "roseannefenderson"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "venettaterrio"
}
]
}
},
{
"author": {
"username": "roseannefenderson"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "alaynamohn"
}
]
}
},
{
"author": {
"username": "roseannefenderson"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "olivajohnson"
}
]
}
},
{
"author": {
"username": "edythefenderson"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "roseannefenderson"
}
]
}
},
{
"author": {
"username": "kaleighangevine"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "burtonneisler"
}
]
}
},
{
"author": {
"username": "ginnyrutkowski"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "marthabertucci"
}
]
}
},
{
"author": {
"username": "ginnyrutkowski"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "katherynsurface"
}
]
}
},
{
"author": {
"username": "ginnyrutkowski"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "mohamedpasquariello"
}
]
}
},
{
"author": {
"username": "margrettdao"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "boristowell"
}
]
}
},
{
"author": {
"username": "margrettdao"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "armidakonrad"
}
]
}
},
{
"author": {
"username": "christinebresler"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "delorseendicott"
}
]
}
},
{
"author": {
"username": "dorcasdankert"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "gabrieldey"
}
]
}
},
{
"author": {
"username": "dorcasdankert"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "forrestjohnson"
}
]
}
},
{
"author": {
"username": "hangsurface"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "aguedamillard"
}
]
}
},
{
"author": {
"username": "cythiafogal"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "christinekonrad"
}
]
}
},
{
"author": {
"username": "cythiafogal"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "benedictfenderson"
}
]
}
},
{
"author": {
"username": "jamisonabsher"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "macmahon"
}
]
}
},
{
"author": {
"username": "jamisonabsher"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "douglasdey"
},
{
"rating": "LOVE",
"username": "mohamedknepp"
}
]
}
},
{
"author": {
"username": "jamisonabsher"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "margrettpasquariello"
}
]
}
},
{
"author": {
"username": "clintonbelles"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "noeliajohnson"
}
]
}
},
{
"author": {
"username": "clintonbelles"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "jolandadelancey"
}
]
}
},
{
"author": {
"username": "clintonbelles"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "susyendicott"
}
]
}
},
{
"author": {
"username": "clintonbelles"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "janetterutkowski"
}
]
}
},
{
"author": {
"username": "clintonbelles"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "pamilapuga"
}
]
}
},
{
"author": {
"username": "dorcaswetherbee"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "kaleighnance"
}
]
}
},
{
"author": {
"username": "nicolasallmond"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "armidaiannuzzi"
}
]
}
},
{
"author": {
"username": "armidarivenburg"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "clintonwetherbee"
}
]
}
},
{
"author": {
"username": "armidarivenburg"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "noeliapuga"
}
]
}
},
{
"author": {
"username": "armidarivenburg"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "susyendicott"
}
]
}
},
{
"author": {
"username": "susyneisler"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "noeliacantor"
}
]
}
},
{
"author": {
"username": "susyneisler"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "susyallmond"
}
]
}
},
{
"author": {
"username": "susyneisler"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "genevieknepp"
}
]
}
},
{
"author": {
"username": "geneviemaynez"
},
"users": {
"data": [
{
"rating": "LOVE",
"username": "marcelbelles"
}
]
}
}
]
}
}
]
}
}
}
var 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
}
}
}
}
}
}
}`
var schema_dxbahT5 = `
type Paged<T> {
data: [T]
cursor: ID
}
@node
type User {
id: ID!
username: ID!
}
type UserWithRating inherits User {
rating: UserRating
}
@node
type Post {
id: ID!
name: String!
text: String
@edge(<-['CREATED']-)
author: User
@edge(-['ABOUT']->)
brand: Brand
@edge((post)<-[(post, user) => 'RATED:' + user.rating]-(users.data))
users(where: WhereUserInput, page: PagegInput): Paged<UserWithRating>
}
@node
type Brand {
id: ID!
name: String!
@edge((brand)<-['ABOUT']-(posts.data))
posts(where: WherePostInput, page: PagegInput): Paged<Post>
}
enum UserRating {
LOVE
LIKE
NEUTRAL
DISLIKE
HATE
}
input PagegInput {
first: Int
}
input WhereBrandInput {
id: ID
}
input WherePostInput {
rating: UserRating
}
input WhereUserInput {
rating: UserRating
}
type Query {
brands(where: WhereBrandInput, page: PagegInput): Paged<Brand>
}
`
describe('graphx', () =>
describe('#astParse', () =>
it("Should create an AST from any string GraphQL query.", () => {
var schemaAST = getSchemaAST(schema_dxbahT5);
var queryAST = getQueryAST(query_cajYlQ207, schemaAST);
assert.isOk(queryAST);
assert.equal(queryAST.length, 1);
assert.equal(queryAST[0].name, 'brands');
assert.equal(queryAST[0].type, 'PagedBrand');
assert.equal(queryAST[0].isNode, false);
assert.isOk(!queryAST[0].edge);
assert.isOk(queryAST[0].args);
assert.isOk(queryAST[0].args.where);
assert.isOk(queryAST[0].args.page);
assert.equal(queryAST[0].args.where.id, "-KkL9EdTh9abV9xAwHUa");
assert.equal(queryAST[0].args.page.first, 10);
var brandsProps = queryAST[0].properties;
assert.isOk(brandsProps);
assert.equal(brandsProps.length, 1);
var data = brandsProps[0];
assert.equal(data.name, "data");
assert.equal(data.type, "[Brand]");
assert.equal(data.isNode, true);
assert.isOk(!data.args);
assert.isOk(!data.edge);
var dataProps = data.properties;
assert.isOk(dataProps);
assert.equal(dataProps.length, 3);
var posts = dataProps[2];
assert.equal(posts.name, "posts");
assert.equal(posts.type, "PagedPost");
assert.equal(posts.isNode, false);
assert.equal(posts.edge, "(brand)<-['ABOUT']-(posts.data)");
assert.isOk(posts.args);
assert.isOk(posts.args.where);
assert.equal(posts.args.where.rating, "LOVE");
})));
describe('graphx', () =>
describe('#extractNodes', () =>
it("Should extract all nodes(schema types marked with the '@node' attribute) for each query. Each node should also contains their successors with their edge.", () => {
var schemaAST = getSchemaAST(schema_dxbahT5);
var queryAST = getQueryAST(query_cajYlQ207, schemaAST);
var queryResponse = resultset;
var brandsQuery = queryAST[0];
var brandsQueryResp = resultset.data[brandsQuery.name];
assert.isOk(brandsQueryResp);
var result = extractNodes(brandsQuery, brandsQueryResp);
assert.isOk(result);
assert.equal(result.length, 1);
assert.equal(result[0]._node, "Brand");
assert.equal(result[0].id, "-KkL9EdTh9abV9xAwHUa");
assert.equal(result[0].name, "Alineala llc");
assert.isOk(!result[0]._edge);
assert.isOk(result[0]._successors);
assert.equal(result[0]._successors.length, 50);
var post = result[0]._successors[0];
assert.equal(post._node, "Post");
assert.isOk(post._successors);
assert.equal(post._successors.length, 3);
assert.isOk(post._successors[0]._edge);
assert.isOk(post._successors[1]._edge);
assert.isOk(post._successors[2]._edge);
assert.equal(post._successors[0]._edge.name, "CREATED");
assert.equal(post._successors[1]._edge.name, "RATED:LOVE");
assert.equal(post._successors[2]._edge.name, "RATED:LOVE");
assert.equal(post._successors[0]._edge.direction, "<");
assert.equal(post._successors[1]._edge.direction, "<");
assert.equal(post._successors[2]._edge.direction, "<");
})));
describe('graphx', () =>
describe('#d3Flatten', () =>
it("Should format all nodes extracted by the 'extractNodes' so they can be ingested by D3.", () => {
var schemaAST = getSchemaAST(schema_dxbahT5);
var queryAST = getQueryAST(query_cajYlQ207, schemaAST);
var queryResponse = resultset;
var brandsQuery = queryAST[0];
var brandsQueryResp = resultset.data[brandsQuery.name];
var nodes = extractNodes(brandsQuery, brandsQueryResp);
var d3Resp = d3Flatten(nodes);
assert.isOk(d3Resp);
assert.isOk(d3Resp.nodes);
assert.isOk(d3Resp.edges);
assert.equal(d3Resp.nodes.length, 159);
assert.equal(d3Resp.edges.length, 158);
assert.equal(d3Resp.nodes[0]._node, "Brand");
assert.equal(d3Resp.nodes[0].id, "-KkL9EdTh9abV9xAwHUa");
assert.equal(d3Resp.nodes[0].name, "Alineala llc");
assert.equal(d3Resp.nodes[1]._node, "Post");
assert.equal(d3Resp.nodes[2]._node, "User");
assert.equal(d3Resp.edges[0].source, 1);
assert.equal(d3Resp.edges[0].target, 0);
assert.equal(d3Resp.edges[0].name, "ABOUT");
})));
describe('graphx', () =>
describe('#compileGraphDataToD3', () =>
it("Should format all nodes extracted by the 'extractNodes' so they can be ingested by D3.", () => {
var d3Resp_1 = compileGraphDataToD3(query_cajYlQ207, resultset, schema_dxbahT5);
var schemaAST = getSchemaAST(schema_dxbahT5);
var d3Resp_2 = compileGraphDataToD3(query_cajYlQ207, resultset, schemaAST);
var validate = d3Resp => {
assert.isOk(d3Resp);
assert.isOk(d3Resp.nodes);
assert.isOk(d3Resp.edges);
assert.equal(d3Resp.nodes.length, 159);
assert.equal(d3Resp.edges.length, 158);
assert.equal(d3Resp.nodes[0]._node, "Brand");
assert.equal(d3Resp.nodes[0].id, "-KkL9EdTh9abV9xAwHUa");
assert.equal(d3Resp.nodes[0].name, "Alineala llc");
assert.equal(d3Resp.nodes[1]._node, "Post");
assert.equal(d3Resp.nodes[2]._node, "User");
assert.equal(d3Resp.edges[0].source, 1);
assert.equal(d3Resp.edges[0].target, 0);
assert.equal(d3Resp.edges[0].name, "ABOUT");
};
validate(d3Resp_1);
validate(d3Resp_2);
})));
var graph_cebjl7328 = {
nodes:[{
_position:0,
_node: "Brand",
name: "Group Rossignol",
id:1
},{
_position:1,
_node: "Post",
id:1
},{
_position:2,
_node: "Post",
id:2
},{
_position:3,
_node: "Post",
id:3
},{
_position:4,
_node: "User",
id:1
},{
_position:5,
_node: "User",
id:2
},{
_position:6,
_node: "User",
id:2
},{
_position:7,
_node: "User",
id:2
},{
_position:8,
_node: "User",
id:1
},{
_position:9,
_node: "Brand",
name: "Rossignol",
id:2
},{
_position:10,
_node: "Post",
id:4
},{
_position:11,
_node: "User",
id:3
}],
edges:[{
source: 1,
target: 0,
name: 'ABOUT'
},{
source: 2,
target: 0,
name: 'ABOUT'
},{
source: 3,
target: 0,
name: 'ABOUT'
},{
source: 4,
target: 1,
name: 'RATED:LOVE'
},{
source: 5,
target: 1,
name: 'RATED:LIKE'
},{
source: 6,
target: 2,
name: 'RATED:HATE'
},{
source: 7,
target: 3,
name: 'RATED:LOVE'
},{
source: 8,
target: 1,
name: 'CREATED'
},{
source: 10,
target: 9,
name: 'ABOUT'
},{
source: 11,
target: 10,
name: 'RATED:LOVE'
}]
}
describe('graphx', () =>
describe('#coalesceD3nodes', () =>
it("Should format all nodes extracted by the 'extractNodes' so they can be ingested by D3.", () => {
var sameUser = (a, b) => a.id == b.id && a._node == b._node && a._node == 'User';
var originGraph = new D3Obj(graph_cebjl7328.nodes, graph_cebjl7328.edges);
var graph_1 = coalesceD3nodes(originGraph, sameUser);
assert.equal(graph_1.nodes.length, 9);
assert.equal(graph_1.edges.length, 10);
assert.equal(graph_1.nodes[0]._node, 'Brand');
assert.equal(graph_1.nodes[0].id, 1);
assert.equal(graph_1.nodes[1]._node, 'Post');
assert.equal(graph_1.nodes[1].id, 1);
assert.equal(graph_1.nodes[2]._node, 'Post');
assert.equal(graph_1.nodes[2].id, 2);
assert.equal(graph_1.nodes[3]._node, 'Post');
assert.equal(graph_1.nodes[3].id, 3);
assert.equal(graph_1.nodes[4]._node, 'User');
assert.equal(graph_1.nodes[4].id, 1);
assert.equal(graph_1.nodes[5]._node, 'User');
assert.equal(graph_1.nodes[5].id, 2);
assert.equal(graph_1.nodes[6]._node, 'Brand');
assert.equal(graph_1.nodes[6].id, 2);
assert.equal(graph_1.nodes[7]._node, 'Post');
assert.equal(graph_1.nodes[7].id, 4);
assert.equal(graph_1.nodes[8]._node, 'User');
assert.equal(graph_1.nodes[8].id, 3);
assert.equal(graph_1.edges[0].source, 1);
assert.equal(graph_1.edges[0].name, 'ABOUT');
assert.equal(graph_1.edges[0].target, 0);
assert.equal(graph_1.edges[1].source, 2);
assert.equal(graph_1.edges[1].name, 'ABOUT');
assert.equal(graph_1.edges[1].target, 0);
assert.equal(graph_1.edges[2].source, 3);
assert.equal(graph_1.edges[2].name, 'ABOUT');
assert.equal(graph_1.edges[2].target, 0);
assert.equal(graph_1.edges[3].source, 4);
assert.equal(graph_1.edges[3].name, 'RATED:LOVE');
assert.equal(graph_1.edges[3].target, 1);
assert.equal(graph_1.edges[4].source, 4);
assert.equal(graph_1.edges[4].name, 'CREATED');
assert.equal(graph_1.edges[4].target, 1);
assert.equal(graph_1.edges[5].source, 5);
assert.equal(graph_1.edges[5].name, 'RATED:LIKE');
assert.equal(graph_1.edges[5].target, 1);
assert.equal(graph_1.edges[6].source, 5);
assert.equal(graph_1.edges[6].name, 'RATED:HATE');
assert.equal(graph_1.edges[6].target, 2);
assert.equal(graph_1.edges[7].source, 5);
assert.equal(graph_1.edges[7].name, 'RATED:LOVE');
assert.equal(graph_1.edges[7].target, 3);
assert.equal(graph_1.edges[8].source, 7);
assert.equal(graph_1.edges[8].name, 'ABOUT');
assert.equal(graph_1.edges[8].target, 6);
assert.equal(graph_1.edges[9].source, 8);
assert.equal(graph_1.edges[9].name, 'RATED:LOVE');
assert.equal(graph_1.edges[9].target, 7);
var mergeRossignol = (a, b) => a._node == b._node && a._node == 'Brand' && a.name.indexOf('Rossignol') >= 0 && b.name.indexOf('Rossignol') >= 0;
var graph_2 = coalesceD3nodes(originGraph, mergeRossignol);
assert.equal(graph_2.nodes.length, 11);
assert.equal(graph_2.edges.length, 10);
assert.equal(graph_2.nodes.reduce((a,b) => b._node == 'Brand' ? a+1 : a ,0), 1);
assert.equal(graph_2.edges.reduce((a,b) => b.target == 0 ? a+1 : a ,0), 4);
var graph_3 = coalesceD3nodes(originGraph, [sameUser, mergeRossignol]);
assert.equal(graph_3.nodes.length, 8);
assert.equal(graph_3.edges.length, 10);
assert.equal(graph_3.nodes.reduce((a,b) => b._node == 'Brand' ? a+1 : a ,0), 1);
assert.equal(graph_3.nodes.reduce((a,b) => b._node == 'User' ? a+1 : a ,0), 3);
assert.equal(graph_3.nodes.reduce((a,b) => b._node == 'Post' ? a+1 : a ,0), 4);
assert.equal(graph_3.edges.reduce((a,b) => b.target == 0 ? a+1 : a ,0), 4);
// console.log(graph_1);
// console.log(graph_2);
// console.log(graph_3);
})));
describe('graphx', () =>
describe('#D3Obj.addClassifier', () =>
it("Should support adding classifiers", () => {
var getColor = (name) => name == 'Brand' ? 1 : name == 'Post' ? 2 : name == 'User' ? 3 : 4;
var d3Resp_1 = compileGraphDataToD3(query_cajYlQ207, resultset, schema_dxbahT5);
d3Resp_1.addClassifier(
'default',
nodes => _.uniqBy(nodes, x => x._node).map(node => ({ name: node._node, color: getColor(node._node) })),
(node, classtype) => node._node == classtype.name);
const classtype = d3Resp_1.findClass(d3Resp_1.nodes[0], 'default');
assert.equal(classtype.name, 'Brand');
assert.equal(classtype.color, 1);
expect(() => d3Resp_1.findClass(d3Resp_1.nodes[0], 'hello')).to.throw();
})));
describe('graphx', () =>
describe('#coalesceD3nodes: PRESERVE CLASSIFIERS', () =>
it("Should preserve the classifiers defined in the original graph.", () => {
var sameUser = (a, b) => a.id == b.id && a._node == b._node && a._node == 'User';
var originGraph = new D3Obj(graph_cebjl7328.nodes, graph_cebjl7328.edges);
var getColor = (name) => name == 'Brand' ? 1 : name == 'Post' ? 2 : name == 'User' ? 3 : 4;
originGraph.addClassifier(
'default',
nodes => _.uniqBy(nodes, x => x._node).map(node => ({ name: node._node, color: getColor(node._node) })),
(node, classtype) => node._node == classtype.name);
const classtype = originGraph.findClass(originGraph.nodes[0], 'default');
assert.equal(classtype.name, 'Brand');
assert.equal(classtype.color, 1);
var graph_1 = coalesceD3nodes(originGraph, sameUser);
assert.equal(graph_1.nodes.length, 9);
assert.equal(graph_1.edges.length, 10);
const classtype_1 = graph_1.findClass(graph_1.nodes[0], 'default');
assert.equal(classtype_1.name, 'Brand');
assert.equal(classtype_1.color, 1);
})));
}
if (isbrowser) runtest(graphx, graphqls2s, assert, expect)
if (typeof(module) != 'undefined')
module.exports = {
runtest
}