Files
speckle-server/modules/core/tests/graph.spec.js
T
Dimitrie Stefanescu e4f213d4f6 test(subscriptions): works with separate run test server, figuring out starting it from test file
doing `npm run dev:server:test` and running the test with that server over port 3000 works. seems
like ws upgrade requests are not honoured when the server is started from the test file (on 3001).
2020-08-20 10:27:48 +03:00

947 lines
37 KiB
JavaScript

/* istanbul ignore file */
const crypto = require( 'crypto' )
const chai = require( 'chai' )
const chaiHttp = require( 'chai-http' )
const assert = require( 'assert' )
const appRoot = require( 'app-root-path' )
const { init, startHttp } = require( `${appRoot}/app` )
const expect = chai.expect
chai.use( chaiHttp )
const knex = require( `${appRoot}/db/knex` )
const { createUser } = require( '../services/users' )
const { createPersonalAccessToken } = require( '../services/tokens' )
const { createObject, createObjects } = require( '../services/objects' )
let addr
let wsAddr
describe( 'GraphQL API Core', ( ) => {
let userA = { name: 'd1', username: 'd1', email: 'd.1@speckle.systems', password: 'wow' }
let userB = { name: 'd2', username: 'd2', email: 'd.2@speckle.systems', password: 'wow' }
let userC = { name: 'd3', username: 'd3', email: 'd.3@speckle.systems', password: 'wow' }
let testServer
// set up app & two basic users to ping pong permissions around
before( async ( ) => {
await knex.migrate.rollback( )
await knex.migrate.latest( )
let { app } = await init( )
let { server } = await startHttp( app )
testServer = server
userA.id = await createUser( userA )
userA.token = `Bearer ${( await createPersonalAccessToken( userA.id, 'test token user A', [ 'streams:read', 'streams:write', 'users:read', 'users:email', 'tokens:write', 'tokens:read', 'profile:read', 'profile:email' ] ) )}`
userB.id = await createUser( userB )
userB.token = `Bearer ${( await createPersonalAccessToken( userB.id, 'test token user B', [ 'streams:read', 'streams:write', 'users:read', 'users:email', 'tokens:write', 'tokens:read', 'profile:read', 'profile:email' ] ) )}`
userC.id = await createUser( userC )
userC.token = `Bearer ${( await createPersonalAccessToken( userC.id, 'test token user B', [ 'streams:read', 'streams:write', 'users:read', 'users:email', 'tokens:write', 'tokens:read', 'profile:read', 'profile:email' ] ) )}`
addr = `http://localhost:${process.env.PORT || 3000}`
wsAddr = `ws://localhost:${process.env.PORT || 3000}`
} )
after( async ( ) => {
testServer.close( )
} )
// the four stream ids
let ts1
let ts2
let ts3
let ts4
let ts5
// some api tokens
let token1
let token2
let token3
// object ids
let objIds
// some commits
let c1 = {}
let c2 = {}
// some branches
let b1 = {}
let b2 = {}
let b3 = {}
describe( 'Mutations', ( ) => {
describe( 'Users & Api tokens', ( ) => {
it( 'Should create some api tokens', async ( ) => {
const res1 = await sendRequest( userA.token, { query: `mutation { apiTokenCreate(name:"Token 1", scopes: ["streams:read", "users:read", "tokens:read" ]) }` } )
expect( res1 ).to.be.json
expect( res1.body.errors ).to.not.exist
expect( res1.body.data.apiTokenCreate ).to.be.a( 'string' )
token1 = `Bearer ${res1.body.data.apiTokenCreate}`
const res2 = await sendRequest( userA.token, { query: `mutation { apiTokenCreate(name:"Token 1", scopes: ["streams:write", "streams:read", "users:email"]) }` } )
token2 = `Bearer ${res2.body.data.apiTokenCreate}`
const res3 = await sendRequest( userB.token, { query: `mutation { apiTokenCreate(name:"Token 1", scopes: ["streams:write", "streams:read", "users:email"]) }` } )
token3 = `Bearer ${res3.body.data.apiTokenCreate}`
} )
it( 'Should revoke an api token that the user owns', async ( ) => {
const res = await sendRequest( userA.token, { query: `mutation{ apiTokenRevoke(token:"${token2}")}` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.apiTokenRevoke ).to.equal( true )
} )
it( 'Should fail to revoke an api token that I do not own', async ( ) => {
const res = await sendRequest( userA.token, { query: `mutation{ apiTokenRevoke(token:"${token3}")}` } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
} )
it( 'Should fail to create a stream with an invalid scope token', async ( ) => {
// Note: token1 has only stream read access
const res = await sendRequest( token1, { query: `mutation { streamCreate(stream: { name: "INVALID TS1 (u A) Private", description: "Hello World", isPublic:false } ) }` } )
expect( res.body.errors ).to.exist
} )
it( 'Should edit my profile', async ( ) => {
const res = await sendRequest( userA.token, { query: `mutation($user:UserEditInput!) { userEdit( user: $user) } `, variables: { user: { name: 'Miticå', bio: 'He never really knows what he is doing.' } } } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.userEdit ).to.equal( true )
} )
} )
describe( 'Streams', ( ) => {
it( 'Should create some streams', async ( ) => {
const resS1 = await sendRequest( userA.token, { query: `mutation { streamCreate(stream: { name: "TS1 (u A) Private", description: "Hello World", isPublic:false } ) }` } )
expect( resS1 ).to.be.json
expect( resS1.body.errors ).to.not.exist
expect( resS1.body.data ).to.have.property( 'streamCreate' )
expect( resS1.body.data.streamCreate ).to.be.a( 'string' )
ts1 = resS1.body.data.streamCreate
const resS2 = await sendRequest( userA.token, { query: `mutation { streamCreate(stream: { name: "TS2 (u A)", description: "Hello Darkness", isPublic:true } ) }` } )
ts2 = resS2.body.data.streamCreate
const resS3 = await sendRequest( userB.token, { query: `mutation { streamCreate(stream: { name: "TS3 (u B) Private", description: "Hello Pumba", isPublic:false } ) }` } )
ts3 = resS3.body.data.streamCreate
const resS4 = await sendRequest( userB.token, { query: `mutation { streamCreate(stream: { name: "TS4 (u B)", description: "Hello Julian", isPublic:true } ) }` } )
ts4 = resS4.body.data.streamCreate
const resS5 = await sendRequest( userB.token, { query: `mutation { streamCreate(stream: { name: "TS5 (u B)", description: "Hello King", isPublic:true } ) }` } )
ts5 = resS5.body.data.streamCreate
} )
it( 'Should update a stream', async ( ) => {
const resS1 = await sendRequest( userA.token, { query: `mutation { streamUpdate(stream: {id:"${ts1}" name: "TS1 (u A) Private UPDATED", description: "Hello World, Again!", isPublic:false } ) }` } )
// console.log( resS1.body.errors )
expect( resS1 ).to.be.json
expect( resS1.body.errors ).to.not.exist
expect( resS1.body.data ).to.have.property( 'streamUpdate' )
expect( resS1.body.data.streamUpdate ).to.equal( true )
} )
it( 'Should grant some permissions', async ( ) => {
const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:owner") }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.streamGrantPermission ).to.equal( true )
const res2 = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts5}", userId: "${userA.id}" role: "stream:owner") }` } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.not.exist
const res3 = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts3}", userId: "${userC.id}" role: "stream:owner") }` } )
expect( res3 ).to.be.json
expect( res3.body.errors ).to.not.exist
} )
it( 'Should fail to grant permissions if not owner', async ( ) => {
const res = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:owner") }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
} )
it( 'Should fail to grant myself permissions', async ( ) => {
const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userA.id}" role: "stream:owner") }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
} )
it( 'Should update permissions', async ( ) => {
const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:contributor") }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.streamGrantPermission ).to.equal( true )
} )
it( 'Should revoke permissions', async ( ) => {
// first test if we can get it
const res = await sendRequest( userC.token, { query: `query { stream(id:"${ts3}") { id name } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.stream.name ).to.equal( 'TS3 (u B) Private' )
const revokeRes = await sendRequest( userB.token, { query: `mutation { streamRevokePermission( streamId: "${ts3}", userId:"${userC.id}")} ` } )
expect( revokeRes ).to.be.json
expect( revokeRes.body.errors ).to.not.exist
expect( revokeRes.body.data.streamRevokePermission ).to.equal( true )
const resNotAuth = await sendRequest( userC.token, { query: `query { stream(id:"${ts3}") { id name role } }` } )
expect( resNotAuth ).to.be.json
expect( resNotAuth.body.errors ).to.exist
} )
it( 'Should fail to edit/write on a public stream if no access is provided', async ( ) => {
// ts4 is a public stream from uesrB
const res = await sendRequest( userA.token, { query: `mutation { streamUpdate(stream: {id:"${ts4}" name: "HACK", description: "Hello World, Again!", isPublic:false } ) }` } )
expect( res.body.errors ).to.exist
} )
it( 'Should fail editing a private stream if no access has been granted', async ( ) => {
const res = await sendRequest( userA.token, { query: `mutation { streamUpdate(stream: {id:"${ts3}" name: "HACK", description: "Hello World, Again!", isPublic:false } ) }` } )
expect( res.body.errors ).to.exist
} )
it( 'Should fail to delete a stream because of permissions', async ( ) => {
const res = await sendRequest( userB.token, { query: `mutation { streamDelete( id:"${ts1}")}` } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
expect( res.body.errors[ 0 ].extensions.code ).to.equal( 'FORBIDDEN' )
} )
it( 'Should delete a stream', async ( ) => {
const res = await sendRequest( userB.token, { query: `mutation { streamDelete( id:"${ts4}")}` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'streamDelete' )
expect( res.body.data.streamDelete ).to.equal( true )
} )
} )
describe( 'Objects, Commits & Branches', ( ) => {
it( 'Should create some objects', async ( ) => {
let objs = [ ]
for ( let i = 0; i < 500; i++ ) {
if ( i % 2 === 0 ) objs.push( { applicationId: i, type: 'Point', x: i, y: 1, z: i * 0.42, extra: { super: true, arr: [ 1, 2, 3, 4 ] } } )
else if ( i % 3 === 0 ) objs.push( { applicationId: i, type: 'Line', start: { x: i, y: 1, z: i * 0.42 }, end: { x: 0, y: 2, z: i * i }, extra: { super: false, arr: [ 12, 23, 34, 42, { imp: [ 'possible', 'this', 'sturcture', 'is' ] } ] } } )
else objs.push( { cool: [ 's', 't', [ 'u', 'f', 'f', i ], { that: true } ], iValue: i + i / 3 } )
}
const res = await sendRequest( userA.token, { query: `mutation( $objs: [JSONObject]! ) { objectCreate( streamId:"${ts1}", objects: $objs ) }`, variables: { objs: objs } } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.objectCreate ).to.have.lengthOf( objs.length )
objIds = res.body.data.objectCreate
} )
it( 'Should create several commits', async ( ) => {
c1.message = 'what a message for a first commit'
c1.streamId = ts1
c1.objectId = objIds[ 0 ]
c1.branchName = 'master'
let res = await sendRequest( userA.token, { query: `mutation( $myCommit: CommitCreateInput! ) { commitCreate( commit: $myCommit ) }`, variables: { myCommit: c1 } } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'commitCreate' )
expect( res.body.data.commitCreate ).to.be.a( 'string' )
c1.id = res.body.data.commitCreate
c2.message = 'what a message for a second commit'
c2.streamId = ts1
c2.objectId = objIds[ 1 ]
c2.branchName = 'master'
c2.previousCommitIds = [ c1.id ]
res = await sendRequest( userA.token, { query: `mutation( $myCommit: CommitCreateInput! ) { commitCreate( commit: $myCommit ) }`, variables: { myCommit: c2 } } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'commitCreate' )
expect( res.body.data.commitCreate ).to.be.a( 'string' )
c2.id = res.body.data.commitCreate
} )
it( 'Should update a commit', async ( ) => {
let updatePayload = {
streamId: ts1,
id: c1.id,
message: 'first commit'
}
let res = await sendRequest( userA.token, { query: `mutation( $myCommit: CommitUpdateInput! ) { commitUpdate( commit: $myCommit ) }`, variables: { myCommit: updatePayload } } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'commitUpdate' )
let res2 = await sendRequest( userB.token, { query: `mutation( $myCommit: CommitUpdateInput! ) { commitUpdate( commit: $myCommit ) }`, variables: { myCommit: updatePayload } } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.exist
} )
it( 'Should delete a commit', async ( ) => {
let payload = { streamId: ts1, id: c2.id }
let res = await sendRequest( userB.token, { query: `mutation( $myCommit: CommitDeleteInput! ) { commitDelete( commit: $myCommit ) }`, variables: { myCommit: payload } } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
let res2 = await sendRequest( userA.token, { query: `mutation( $myCommit: CommitDeleteInput! ) { commitDelete( commit: $myCommit ) }`, variables: { myCommit: payload } } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.not.exist
expect( res2.body.data ).to.have.property( 'commitDelete' )
} )
it( 'Should create several branches', async ( ) => {
b1 = { streamId: ts1, name: 'dim/dev', description: 'dimitries development branch' }
const res1 = await sendRequest( userA.token, { query: `mutation( $branch:BranchCreateInput! ) { branchCreate( branch:$branch ) }`, variables: { branch: b1 } } )
expect( res1 ).to.be.json
expect( res1.body.errors ).to.not.exist
expect( res1.body.data ).to.have.property( 'branchCreate' )
expect( res1.body.data.branchCreate ).to.be.a( 'string' )
b1.id = res1.body.data.branchCreate
b2 = { streamId: ts1, name: 'dim/dev/api-surgery', description: 'another branch' }
const res2 = await sendRequest( userB.token, { query: `mutation( $branch:BranchCreateInput! ) { branchCreate( branch:$branch ) }`, variables: { branch: b2 } } )
expect( res2.body.errors ).to.not.exist
b2.id = res2.body.data.branchCreate
b3 = { streamId: ts1, name: 'userB/dev/api', description: 'more branches branch' }
const res3 = await sendRequest( userB.token, { query: `mutation( $branch:BranchCreateInput! ) { branchCreate( branch:$branch ) }`, variables: { branch: b3 } } )
expect( res3.body.errors ).to.not.exist
b3.id = res3.body.data.branchCreate
} )
it( 'Should update a branch', async ( ) => {
let payload = {
streamId: ts1,
id: b2.id,
name: 'userb/whatever/whatever'
}
const res1 = await sendRequest( userA.token, { query: `mutation( $branch:BranchUpdateInput! ) { branchUpdate( branch:$branch ) }`, variables: { branch: payload } } )
expect( res1 ).to.be.json
expect( res1.body.errors ).to.not.exist
expect( res1.body.data ).to.have.property( 'branchUpdate' )
expect( res1.body.data.branchUpdate ).to.equal( true )
} )
it( 'Should delete a branch', async ( ) => {
// give C some access permissions
const perms = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userC.id}" role: "stream:contributor") }` } )
let payload = {
streamId: ts1,
id: b2.id
}
let badPayload = {
streamId: ts1,
id: 'APRIL FOOOLS!'
}
const res = await sendRequest( userC.token, { query: `mutation( $branch:BranchDeleteInput! ) { branchDelete( branch: $branch ) }`, variables: { branch: badPayload } } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
expect( res.body.errors[ 0 ].message ).to.equal( 'Branch not found.' )
const res1 = await sendRequest( userC.token, { query: `mutation( $branch:BranchDeleteInput! ) { branchDelete( branch: $branch ) }`, variables: { branch: payload } } )
expect( res1 ).to.be.json
expect( res1.body.errors ).to.exist
expect( res1.body.errors[ 0 ].message ).to.equal( 'Only the branch creator or stream owners are allowed to delete branches.' )
const res2 = await sendRequest( userA.token, { query: `mutation( $branch:BranchDeleteInput! ) { branchDelete( branch: $branch ) }`, variables: { branch: payload } } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.not.exist
// revoke perms for c back (dont' wanna mess up our integration-unit tests below)
await sendRequest( userA.token, { query: `mutation{ streamRevokePermission( streamId: "${ts1}", userId: "${userC.id}" ) }` } )
} )
it( 'Should commit to a non-master branch as well...', async ( ) => {
let cc = {}
cc.message = 'what a message for a second commit'
cc.streamId = ts1
cc.objectId = objIds[ 3 ]
cc.branchName = 'userB/dev/api'
let res = await sendRequest( userB.token, { query: `mutation( $myCommit: CommitCreateInput! ) { commitCreate( commit: $myCommit ) }`, variables: { myCommit: cc } } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'commitCreate' )
expect( res.body.data.commitCreate ).to.be.a( 'string' )
} )
} )
} )
describe( 'Queries', ( ) => {
describe( 'My Profile', ( ) => {
it( 'Should retrieve my profile', async ( ) => {
const res = await sendRequest( userA.token, { query: `{ user { id name email role apiTokens { id name } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'user' )
expect( res.body.data.user.name ).to.equal( 'Miticå' )
expect( res.body.data.user.email ).to.equal( 'd.1@speckle.systems' )
expect( res.body.data.user.role ).to.equal( 'server:admin' )
} )
it( 'Should retrieve my streams', async ( ) => {
// add more streams
await sendRequest(
userA.token, {
query: `mutation( $myStream: StreamCreateInput! ) { streamCreate( stream: $myStream ) }`,
variables: { myStream: { name: 'o hai' } }
} )
await sendRequest(
userA.token, {
query: `mutation( $myStream: StreamCreateInput! ) { streamCreate( stream: $myStream ) }`,
variables: { myStream: { name: 'bai now' } }
} )
await sendRequest(
userA.token, {
query: `mutation( $myStream: StreamCreateInput! ) { streamCreate( stream: $myStream ) }`,
variables: { myStream: { name: 'one more for the road' } }
} )
const res = await sendRequest( userA.token, { query: `{ user { streams( limit: 3 ) { totalCount cursor items { id name } } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.streams.items.length ).to.equal( 3 )
const res2 = await sendRequest( userA.token, { query: `{ user { streams( limit: 3, cursor: "${res.body.data.user.streams.cursor}" ) { totalCount cursor items { id name } } } }` } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.not.exist
expect( res2.body.data.user.streams.items.length ).to.equal( 3 )
let streams = res2.body.data.user.streams.items
let s1 = streams.find( s => s.name === 'TS1 (u A) Private UPDATED' )
expect( s1 ).to.exist
} )
it( 'Should retrieve my commits (across all streams)', async ( ) => {
for ( let i = 10; i < 20; i++ ) {
let c1 = {
message: `what a message for commit number ${i}`,
streamId: ts1,
objectId: objIds[ i ],
branchName: 'master',
}
let res = await sendRequest( userA.token, { query: `mutation( $myCommit: CommitCreateInput! ) { commitCreate( commit: $myCommit ) }`, variables: { myCommit: c1 } } )
}
const res = await sendRequest( userA.token, { query: `{ user { commits( limit: 3 ) { totalCount cursor items { id message referencedObject } } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.commits.totalCount ).to.equal( 11 )
expect( res.body.data.user.commits.cursor ).to.exist
expect( res.body.data.user.commits.items.length ).to.equal( 3 )
const res2 = await sendRequest( userA.token, { query: `{ user { commits( limit: 3, cursor: "${res.body.data.user.commits.cursor}") { totalCount cursor items { id message referencedObject } } } }` } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.not.exist
expect( res2.body.data.user.commits.totalCount ).to.equal( 11 )
expect( res2.body.data.user.commits.items.length ).to.equal( 3 )
} )
} )
describe( 'Different Users` Profile', ( ) => {
it( 'Should retrieve a different profile profile', async ( ) => {
const res = await sendRequest( userA.token, { query: ` { user(id:"${userB.id}") { id name email } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'user' )
expect( res.body.data.user.name ).to.equal( 'd2' )
expect( res.body.data.user.email ).to.equal( 'd.2@speckle.systems' )
} )
it( 'Should not retrieve a profile if no auth', async ( ) => {
const res = await sendRequest( null, { query: `{ user { id name email } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
} )
it( 'Should not retrieve user email field if out of scope', async ( ) => {
// token1 has only users:read scope
const res = await sendRequest( token1, { query: ` { user(id:"${userB.id}") { id name email } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.email ).to.be.null
} )
it( 'Should only retrieve public streams from a different user profile ', async ( ) => {
const res = await sendRequest( token1, { query: `query { user( id:"${userB.id}" ) { streams { totalCount items { id name isPublic } } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.streams.totalCount ).to.equal( 1 )
} )
} )
describe( 'Streams', ( ) => {
let retrievedStream
it( 'Should retrieve a stream', async ( ) => {
const res = await sendRequest( userA.token, { query: `
query {
stream(id:"${ts1}") {
id
name
createdAt
updatedAt
collaborators {
id
name
role
}
}
}` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
let stream = res.body.data.stream
retrievedStream = stream
expect( stream.name ).to.equal( 'TS1 (u A) Private UPDATED' )
expect( stream.collaborators ).to.have.lengthOf( 2 )
expect( stream.collaborators[ 0 ].role ).to.equal( 'stream:contributor' )
expect( stream.collaborators[ 1 ].role ).to.equal( 'stream:owner' )
} )
let bees = [ ]
it( 'should retrieve all stream branches', async ( ) => {
let query = `
query{
stream(id: "${ts1}"){
branches( limit: 2 ) {
totalCount
cursor
items {
id
name
author {
id
name
}
}
}
}
}
`
let res = await sendRequest( userA.token, { query } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.stream.branches.items.length ).to.equal( 2 )
expect( res.body.data.stream.branches.totalCount ).to.equal( 3 )
expect( res.body.data.stream.branches.cursor ).to.exist
bees = res.body.data.stream.branches.items
let query2 = `
query{
stream(id: "${ts1}"){
branches( limit: 2, cursor: "${ res.body.data.stream.branches.cursor }" ) {
totalCount
cursor
items {
id
name
author {
id
name
}
}
}
}
}
`
let res2 = await sendRequest( userA.token, { query: query2 } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.not.exist
expect( res2.body.data.stream.branches.items.length ).to.equal( 1 )
expect( res2.body.data.stream.branches.totalCount ).to.equal( 3 )
} )
it( 'should retrieve a stream branch', async ( ) => {
const res = await sendRequest( userA.token, { query: `query { stream(id:"${ts1}") { branch( name: "${bees[1].name}" ) { name description } } } ` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.stream.branch.name ).to.equal( 'dim/dev' )
} )
it( 'should retrieve a branch`s commits', async ( ) => {
let query = `
query {
stream( id: "${ts1}" ) {
branch( name: "master" ) {
id
name
commits( limit: 5 ) {
totalCount
cursor
items {
id
message
createdAt
referencedObject
authorId
}
}
}
}
}
`
const res = await sendRequest( userA.token, { query: query } )
expect( res.body.data.stream.branch.commits.items.length ).to.equal( 5 )
expect( res.body.data.stream.branch.commits.items[ 0 ] ).to.have.property( 'id' )
expect( res.body.data.stream.branch.commits.items[ 0 ] ).to.have.property( 'message' )
expect( res.body.data.stream.branch.commits.items[ 0 ] ).to.have.property( 'createdAt' )
let query2 = `
query {
stream( id: "${ts1}" ) {
branch( name: "master" ) {
id
name
commits( limit: 3, cursor: "${res.body.data.stream.branch.commits.cursor}" ) {
totalCount
cursor
items {
id
message
createdAt
referencedObject
authorId
authorName
}
}
}
}
}`
const res2 = await sendRequest( userA.token, { query: query2 } )
// console.log( res2.body.errors )
// console.log( res2.body.data.stream.branch.commits )
expect( res2.body.data.stream.branch.commits.items.length ).to.equal( 3 )
expect( res2.body.data.stream.branch.commits.items[ 0 ] ).to.have.property( 'id' )
expect( res2.body.data.stream.branch.commits.items[ 0 ] ).to.have.property( 'message' )
expect( res2.body.data.stream.branch.commits.items[ 0 ] ).to.have.property( 'createdAt' )
} )
let commitList
it( 'should retrieve all stream commits', async ( ) => {
let query = `
query {
stream( id: "${ts1}" ) {
commits( limit: 10 ) {
totalCount
cursor
items {
id
message
authorId
authorName
}
}
}
}
`
const res = await sendRequest( userA.token, { query: query } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.stream.commits.items.length ).to.equal( 10 )
expect( res.body.data.stream.commits.totalCount ).to.equal( 12 )
commitList = res.body.data.stream.commits.items
let query2 = `
query {
stream( id: "${ts1}" ) {
commits( limit: 10, cursor: "${res.body.data.stream.commits.cursor}" ) {
totalCount
cursor
items {
id
message
authorId
authorName
}
}
}
}
`
const res2 = await sendRequest( userA.token, { query: query2 } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.not.exist
expect( res2.body.data.stream.commits.items.length ).to.equal( 2 )
} )
it( 'should retrieve a stream commit', async ( ) => {
const res = await sendRequest( userA.token, { query: `query { stream( id:"${ts1}" ) { commit( id: "${commitList[ 0 ].id}" ) { id message referencedObject } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.stream.commit.message ).to.equal( 'what a message for commit number 19' ) // should be the last created one
} )
} )
describe( 'Objects', ( ) => {
let myCommit
let myObjs
before( async ( ) => {
let { commit, objs } = generateManyObjects( 100, 'noise__' )
myCommit = commit
myObjs = objs
} )
it( 'should save many objects', async ( ) => {
let everything = [ myCommit, ...myObjs ]
const res = await sendRequest( userA.token, { query: `mutation($objs:[JSONObject]!) { objectCreate(streamId:"${ts1}", objects: $objs) }`, variables: { objs: everything } } )
let objIds = res.body.data.objectCreate
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( objIds.length ).to.equal( 101 ) // +1 for the actual "commit" object
} )
it( `should get an object's subojects objects`, async ( ) => {
let first = await sendRequest( userA.token, {
query: `
query {
stream( id:"${ts1}" ) {
id
name
object( id:"${myCommit.id}" ) {
createdAt
children( limit: 2 ) {
totalCount
cursor
objects {
id
}
}
}
}
}
`
} )
expect( first ).to.be.json
expect( first.body.errors ).to.not.exist
expect( first.body.data.stream ).to.be.an( 'object' )
expect( first.body.data.stream.object ).to.be.an( 'object' )
expect( first.body.data.stream.object.children.objects.length ).to.equal( 2 )
let second = await sendRequest( userA.token, {
query: `
query {
stream(id:"${ts1}") {
id
name
object( id:"${myCommit.id}" ) {
createdAt
children( limit: 20, cursor: "${first.body.data.stream.object.children.cursor}", select: ["sortValueA", "nest.arr[2]"] ) {
totalCount
objects {
id
data
}
}
}
}
}
`
} )
expect( second ).to.be.json
expect( second.body.errors ).to.not.exist
expect( second.body.data.stream ).to.be.an( 'object' )
expect( second.body.data.stream.object ).to.be.an( 'object' )
expect( second.body.data.stream.object.children.objects.length ).to.equal( 20 )
expect( second.body.data.stream.object.children.objects[ 0 ].data.sortValueA ).to.equal( 52 ) // when sorting by id, it's always 52
expect( second.body.data.stream.object.children.objects[ 0 ].data.nest.arr[ 2 ] ).to.equal( 52 ) // when sorting by id, it's always 52
} )
it( `should query an object's subojects`, async ( ) => {
let first = await sendRequest( userA.token, {
query: `
query( $query: [JSONObject!], $orderBy: JSONObject ) {
stream(id:"${ts1}") {
id
name
object( id:"${myCommit.id}" ) {
createdAt
children( limit: 20, select:[ "sortValueA" ], query: $query, orderBy: $orderBy ) {
totalCount
cursor
objects {
id
data
}
}
}
}
}
`,
variables: { query: [ { field: 'sortValueA', operator: '>=', value: 42 } ], orderBy: { field: 'sortValueA' } }
} )
expect( first ).to.be.json
expect( first.body.errors ).to.not.exist
expect( first.body.data.stream ).to.be.an( 'object' )
expect( first.body.data.stream.object ).to.be.an( 'object' )
expect( first.body.data.stream.object.children.objects.length ).to.equal( 20 )
expect( first.body.data.stream.object.children.objects[ 0 ].data.sortValueA ).to.equal( 42 )
expect( first.body.data.stream.object.children.objects[ 1 ].data.sortValueA ).to.equal( 43 )
} )
} )
} )
describe( 'Server Info', ( ) => {
it( 'Should return a valid server information object', async ( ) => {
let q = `
query{
serverInfo{
name
adminContact
termsOfService
description
roles{
name
description
resourceTarget
}
scopes{
name
description
}
}
}`
let res = await sendRequest( null, { query: q } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.serverInfo ).to.be.an( 'object' )
let si = res.body.data.serverInfo
expect( si.name ).to.be.a( 'string' )
expect( si.adminContact ).to.be.a( 'string' )
expect( si.termsOfService ).to.be.a( 'string' )
expect( si.description ).to.be.a( 'string' )
expect( si.roles ).to.be.a( 'array' )
expect( si.scopes ).to.be.a( 'array' )
} )
} )
} )
/**
* Sends a graphql request. Convenience wrapper.
* @param {string} auth the user's token
* @param {string} obj the query/mutation to send
* @return {Promise} the awaitable request
*/
function sendRequest( auth, obj, address = addr ) {
return chai.request( address ).post( '/graphql' ).set( 'Authorization', auth ).send( obj )
}
// const crypto = require( 'crypto' )
function generateManyObjects( shitTon, noise ) {
shitTon = shitTon || 10000
noise = noise || Math.random( ) * 100
let objs = [ ]
let base = { name: 'base bastard 2', noise: noise, __closure: {} }
// objs.push( base )
let k = 0
for ( let i = 0; i < shitTon; i++ ) {
let baby = {
name: `mr. ${i}`,
nest: { duck: i % 2 === 0, mallard: 'falsey', arr: [ i + 42, i, i ] },
test: { value: i, secondValue: 'mallard ' + i % 10 },
similar: k,
even: i % 2 === 0,
objArr: [ { a: i }, { b: i * i }, { c: true } ],
noise: noise,
sortValueA: i,
sortValueB: i * 0.42 * i
}
if ( i % 3 === 0 ) k++
getAnIdForThisOnePlease( baby )
base.__closure[ baby.id ] = 1
objs.push( baby )
}
getAnIdForThisOnePlease( base )
return { commit: base, objs: objs }
}
function getAnIdForThisOnePlease( obj ) {
obj.id = obj.id || crypto.createHash( 'md5' ).update( JSON.stringify( obj ) ).digest( 'hex' )
}