diff --git a/test/api.test.ts b/test/api.test.ts index d27d2d65..09c804d7 100644 --- a/test/api.test.ts +++ b/test/api.test.ts @@ -24,7 +24,6 @@ PouchDB.plugin(require('pouchdb-find')); import request from 'supertest'; import {app} from '../src/routes'; -import {initialiseDatabases} from '../src/couchdb'; import { getUserFromEmailOrUsername, createUser, @@ -33,10 +32,13 @@ import { import {createAuthKey} from '../src/authkeys/create'; import {getSigningKey} from '../src/authkeys/signing_keys'; import fs from 'fs'; -import {createNotebook} from '../src/couchdb/notebooks'; +import {createNotebook, getNotebooks} from '../src/couchdb/notebooks'; import {ProjectUIModel} from 'faims3-datamodel'; import {DEVELOPER_MODE} from '../src/buildconfig'; import {expect} from 'chai'; +import {resetDatabases} from './mocks'; +import { restoreFromBackup } from '../src/couchdb/backupRestore'; +import e from 'express'; const uispec: ProjectUIModel = { fields: [], @@ -48,238 +50,306 @@ const uispec: ProjectUIModel = { let adminToken = ''; const username = 'bobalooba'; -before(async () => { - await initialiseDatabases(); - const signing_key = await getSigningKey(); - const adminUser = await getUserFromEmailOrUsername('admin'); - if (adminUser) { - adminToken = await createAuthKey(adminUser, signing_key); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [user, _error] = await createUser('', username); - if (user) { - await saveUser(user); +describe('API tests', () => { + beforeEach(async () => { + await resetDatabases(); + const signing_key = await getSigningKey(); + const adminUser = await getUserFromEmailOrUsername('admin'); + if (adminUser) { + adminToken = await createAuthKey(adminUser, signing_key); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [user, _error] = await createUser('', username); + if (user) { + await saveUser(user); + } } - } -}); + }); -it('check is up - not authenticated', async () => { - const result = await request(app).get('/api/hello'); - expect(result.statusCode).to.equal(401); -}); + it('check is up - not authenticated', async () => { + const result = await request(app).get('/api/hello'); + expect(result.statusCode).to.equal(401); + }); -it('check is up - authenticated', async () => { - console.log('check is up - authenticated'); - const result = await request(app) - .get('/api/hello') - .set('Authorization', `Bearer ${adminToken}`); - expect(result.statusCode).to.equal(200); -}); + it('check is up - authenticated', async () => { + console.log('check is up - authenticated'); + const result = await request(app) + .get('/api/hello') + .set('Authorization', `Bearer ${adminToken}`); + expect(result.statusCode).to.equal(200); + }); -it('get notebooks', () => { - return request(app) - .get('/api/notebooks') - .set('Authorization', `Bearer ${adminToken}`) - .expect(200) - .expect(response => { - expect(response.body).to.be.empty; - }); -}); + it('get notebooks', async () => { + const filename = 'notebooks/sample_notebook.json'; + const jsonText = fs.readFileSync(filename, 'utf-8'); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); -it('create notebook', () => { - const filename = 'notebooks/sample_notebook.json'; - const jsonText = fs.readFileSync(filename, 'utf-8'); - const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); - - return request(app) - .post('/api/notebooks') - .send({ - 'ui-specification': uiSpec, - metadata: metadata, - name: 'test notebook', - }) - .set('Authorization', `Bearer ${adminToken}`) - .set('Content-Type', 'application/json') - .expect(200) - .expect(response => { - expect(response.body.notebook).to.include('-test-notebook'); - }); -}); + const project_id = await createNotebook('test-notebook', uiSpec, metadata); + + return request(app) + .get('/api/notebooks') + .set('Authorization', `Bearer ${adminToken}`) + .expect(200) + .expect(response => { + expect(response.body).to.have.lengthOf(1); + }); + }); + + it('create notebook', () => { + const filename = 'notebooks/sample_notebook.json'; + const jsonText = fs.readFileSync(filename, 'utf-8'); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + + return request(app) + .post('/api/notebooks') + .send({ + 'ui-specification': uiSpec, + metadata: metadata, + name: 'test notebook', + }) + .set('Authorization', `Bearer ${adminToken}`) + .set('Content-Type', 'application/json') + .expect(200) + .expect(response => { + expect(response.body.notebook).to.include('-test-notebook'); + }); + }); -it('update notebook', () => { - const filename = 'notebooks/sample_notebook.json'; - const jsonText = fs.readFileSync(filename, 'utf-8'); - const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); - - let projectID; - - // create notebook - return request(app) - .post('/api/notebooks') - .send({ - 'ui-specification': uiSpec, - metadata: metadata, - name: 'test notebook', - }) - .set('Authorization', `Bearer ${adminToken}`) - .set('Content-Type', 'application/json') - .expect(200) - .expect(async response => { - projectID = response.body.notebook; - console.log('got response', response.body); - - metadata['name'] = 'Updated Test Notebook'; - metadata['project_lead'] = 'Bob Bobalooba'; - uiSpec.fviews['FORM1SECTION1']['label'] = 'Updated Label'; - - // add a new autoincrementer field - const newField = { - 'component-namespace': 'faims-custom', - 'component-name': 'BasicAutoIncrementer', - 'type-returned': 'faims-core::String', - 'component-parameters': { - name: 'newincrementor', - id: 'newincrementor', - variant: 'outlined', - required: false, - num_digits: 5, - form_id: 'FORM1SECTION1', - label: 'FeatureIDincrementor', - }, - validationSchema: [['yup.string'], ['yup.required']], - initialValue: null, - access: ['admin'], - meta: { - annotation_label: 'annotation', - annotation: true, - uncertainty: { - include: false, - label: 'uncertainty', + it('update notebook', () => { + const filename = 'notebooks/sample_notebook.json'; + const jsonText = fs.readFileSync(filename, 'utf-8'); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + + let projectID; + + // create notebook + return request(app) + .post('/api/notebooks') + .send({ + 'ui-specification': uiSpec, + metadata: metadata, + name: 'test notebook', + }) + .set('Authorization', `Bearer ${adminToken}`) + .set('Content-Type', 'application/json') + .expect(200) + .expect(async response => { + projectID = response.body.notebook; + console.log('got response', response.body); + + metadata['name'] = 'Updated Test Notebook'; + metadata['project_lead'] = 'Bob Bobalooba'; + uiSpec.fviews['FORM1SECTION1']['label'] = 'Updated Label'; + + // add a new autoincrementer field + const newField = { + 'component-namespace': 'faims-custom', + 'component-name': 'BasicAutoIncrementer', + 'type-returned': 'faims-core::String', + 'component-parameters': { + name: 'newincrementor', + id: 'newincrementor', + variant: 'outlined', + required: false, + num_digits: 5, + form_id: 'FORM1SECTION1', + label: 'FeatureIDincrementor', }, - }, - }; + validationSchema: [['yup.string'], ['yup.required']], + initialValue: null, + access: ['admin'], + meta: { + annotation_label: 'annotation', + annotation: true, + uncertainty: { + include: false, + label: 'uncertainty', + }, + }, + }; + + uiSpec.fields['newincrementor'] = newField; + uiSpec.fviews['FORM1SECTION1']['fields'].push('newincrementor'); - uiSpec.fields['newincrementor'] = newField; - uiSpec.fviews['FORM1SECTION1']['fields'].push('newincrementor'); + await request(app) + .put(`/api/notebooks/${projectID}`) + .send({ + 'ui-specification': uiSpec, + metadata: metadata, + name: 'test notebook', + }) + .set('Authorization', `Bearer ${adminToken}`) + .set('Content-Type', 'application/json') + .expect(200) + .expect(response => { + expect(response.body.notebook).to.include('-test-notebook'); + }); + }); + }); + it('get notebook', async () => { + const filename = 'notebooks/sample_notebook.json'; + const jsonText = fs.readFileSync(filename, 'utf-8'); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + + const project_id = await createNotebook('test-notebook', uiSpec, metadata); + + expect(project_id).not.to.be.undefined; + return request(app) + .get('/api/notebooks/' + project_id) + .set('Authorization', `Bearer ${adminToken}`) + .set('Content-Type', 'application/json') + .expect(200) + .expect(response => { + expect(response.body.metadata.name).to.equal('test-notebook'); + }); + }); + + it('can delete a notebook', async () => { + await resetDatabases(); + const filename = 'notebooks/sample_notebook.json'; + const jsonText = fs.readFileSync(filename, 'utf-8'); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + const adminUser = await getUserFromEmailOrUsername('admin'); + + if (adminUser) { + const project_id = await createNotebook( + 'test-notebook', + uiSpec, + metadata + ); + let notebooks = await getNotebooks(adminUser); + expect(notebooks).to.have.lengthOf(1); + console.log('deleting', project_id); + expect(project_id).not.to.be.undefined; await request(app) - .put(`/api/notebooks/${projectID}`) - .send({ - 'ui-specification': uiSpec, - metadata: metadata, - name: 'test notebook', - }) + .post('/api/notebooks/' + project_id + '/delete') .set('Authorization', `Bearer ${adminToken}`) .set('Content-Type', 'application/json') - .expect(200) - .expect(response => { - expect(response.body.notebook).to.include('-test-notebook'); - }); - }); -}); - -it('get notebook', async () => { - const filename = 'notebooks/sample_notebook.json'; - const jsonText = fs.readFileSync(filename, 'utf-8'); - const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); - - const project_id = await createNotebook('test-notebook', uiSpec, metadata); - - expect(project_id).not.to.be.undefined; - return request(app) - .get('/api/notebooks/' + project_id) - .set('Authorization', `Bearer ${adminToken}`) - .set('Content-Type', 'application/json') - .expect(200) - .expect(response => { - expect(response.body.metadata.name).to.equal('test-notebook'); - }); -}); + .expect(302) + .expect('Location', '/notebooks/'); + notebooks = await getNotebooks(adminUser); + expect(notebooks).to.be.empty; + } + }); -it('update admin user - no auth', async () => { - return await request(app) - .post(`/api/users/${username}/admin`) - .send({addrole: true}) - .set('Content-Type', 'application/json') - .expect(401); -}); + it('update admin user - no auth', async () => { + return await request(app) + .post(`/api/users/${username}/admin`) + .send({addrole: true}) + .set('Content-Type', 'application/json') + .expect(401); + }); -it('update admin user - add role', async () => { - return await request(app) - .post(`/api/users/${username}/admin`) - .set('Authorization', `Bearer ${adminToken}`) - .set('Content-Type', 'application/json') - .send({addrole: true}) - .expect(200) - .expect({status: 'success'}); -}); + it('update admin user - add role', async () => { + return await request(app) + .post(`/api/users/${username}/admin`) + .set('Authorization', `Bearer ${adminToken}`) + .set('Content-Type', 'application/json') + .send({addrole: true}) + .expect(200) + .expect({status: 'success'}); + }); -it('update admin user - remove role', () => { - return request(app) - .post(`/api/users/${username}/admin`) - .set('Authorization', `Bearer ${adminToken}`) - .set('Content-Type', 'application/json') - .send({addrole: false}) - .expect(200) - .expect({status: 'success'}); -}); + it('update admin user - remove role', () => { + return request(app) + .post(`/api/users/${username}/admin`) + .set('Authorization', `Bearer ${adminToken}`) + .set('Content-Type', 'application/json') + .send({addrole: false}) + .expect(200) + .expect({status: 'success'}); + }); -it('get notebook users', async () => { - const filename = 'notebooks/sample_notebook.json'; - const jsonText = fs.readFileSync(filename, 'utf-8'); - const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); - - const project_id = await createNotebook('test-notebook', uiSpec, metadata); - - return request(app) - .get(`/api/notebooks/${project_id}/users`) - .set('Authorization', `Bearer ${adminToken}`) - .set('Content-Type', 'application/json') - .expect(200) - .then(response => { - expect(response.body.roles).to.deep.equal([ - 'admin', - 'moderator', - 'team', - 'user', - ]); - expect(response.body.users.length).to.equal(1); - }); -}); + it('get notebook users', async () => { + const filename = 'notebooks/sample_notebook.json'; + const jsonText = fs.readFileSync(filename, 'utf-8'); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); -it('update notebook roles', async () => { - // make some notebooks - const nb1 = await createNotebook('NB1', uispec, {}); + const project_id = await createNotebook('test-notebook', uiSpec, metadata); - if (nb1) { return request(app) - .post(`/api/notebooks/${nb1}/users/`) + .get(`/api/notebooks/${project_id}/users`) .set('Authorization', `Bearer ${adminToken}`) .set('Content-Type', 'application/json') - .send({ - username: username, - role: 'user', - addrole: true, - }) - .expect({status: 'success'}) - .expect(200); - } else { - throw new Error('could not make test notebooks'); - } -}); + .expect(200) + .then(response => { + expect(response.body.roles).to.deep.equal([ + 'admin', + 'moderator', + 'team', + 'user', + ]); + expect(response.body.users.length).to.equal(1); + }); + }); -if (DEVELOPER_MODE) { - it('create random record', async () => { + it('update notebook roles', async () => { + // make some notebooks const nb1 = await createNotebook('NB1', uispec, {}); if (nb1) { return request(app) - .post(`/api/notebooks/${nb1}/generate`) + .post(`/api/notebooks/${nb1}/users/`) .set('Authorization', `Bearer ${adminToken}`) .set('Content-Type', 'application/json') - .send({count: 10}) + .send({ + username: username, + role: 'user', + addrole: true, + }) + .expect({status: 'success'}) .expect(200); } else { - throw new Error('could not make test notebook'); + throw new Error('could not make test notebooks'); } }); -} + + it('can download records as csv', async () => { + // pull in some test data + await restoreFromBackup('test/backup.jsonl'); + + const adminUser = await getUserFromEmailOrUsername('admin'); + if (adminUser) { + const notebooks = await getNotebooks(adminUser); + expect(notebooks).to.have.lengthOf(2); + + await request(app) + .get('/api/notebooks/1693291182736-campus-survey-demo/FORM2.csv') + .set('Authorization', `Bearer ${adminToken}`) + .set('Content-Type', 'application/json') + .expect(200) + .expect('Content-Type', 'text/csv') + .expect(response => { + // response body should be csv data + expect(response.text).to.contain('identifier'); + const lines = response.text.split('\n'); + lines.forEach(line => { + if (line !== '' && !line.startsWith('identifier')) { + expect(line).to.contain('rec'); + expect(line).to.contain('FORM2'); + expect(line).to.contain('frev'); + } + }); + // one more newline than the number of records + header + expect(lines).to.have.lengthOf(19); + }); + } + }); + + if (DEVELOPER_MODE) { + it('create random record', async () => { + const nb1 = await createNotebook('NB1', uispec, {}); + + if (nb1) { + return request(app) + .post(`/api/notebooks/${nb1}/generate`) + .set('Authorization', `Bearer ${adminToken}`) + .set('Content-Type', 'application/json') + .send({count: 10}) + .expect(200); + } else { + throw new Error('could not make test notebook'); + } + }); + } +}); diff --git a/test/backup.test.ts b/test/backup.test.ts index db401591..1d6ea56c 100644 --- a/test/backup.test.ts +++ b/test/backup.test.ts @@ -18,7 +18,6 @@ * Tests for the interface to couchDB */ import PouchDB from 'pouchdb'; -import {initialiseDatabases} from '../src/couchdb'; import {restoreFromBackup} from '../src/couchdb/backupRestore'; import {getNotebooks, notebookRecordIterator} from '../src/couchdb/notebooks'; import {registerClient} from 'faims3-datamodel'; @@ -27,14 +26,14 @@ PouchDB.plugin(require('pouchdb-adapter-memory')); // enable memory adapter for PouchDB.plugin(require('pouchdb-find')); import {expect} from 'chai'; -import {callbackObject, cleanDataDBS} from './mocks'; +import {callbackObject, cleanDataDBS, resetDatabases} from './mocks'; // register our mock database clients with the module registerClient(callbackObject); describe('Backup and restore', () => { it('restore backup', async () => { - await initialiseDatabases(); + await resetDatabases(); await cleanDataDBS(); await restoreFromBackup('test/backup.jsonl'); diff --git a/test/couchdb.test.ts b/test/couchdb.test.ts index d3d42bb1..e955eb15 100644 --- a/test/couchdb.test.ts +++ b/test/couchdb.test.ts @@ -58,240 +58,265 @@ const uispec: ProjectUIModel = { const username = 'bobalooba'; let bobalooba: Express.User; -beforeEach(async () => { - await resetDatabases(); - const adminUser = await getUserFromEmailOrUsername('admin'); - if (adminUser) { - const [user, error] = await createUser('', username); - if (user) { - await saveUser(user); - bobalooba = user; - } else { - throw new Error(error); +describe('notebook api', () => { + beforeEach(async () => { + await resetDatabases(); + const adminUser = await getUserFromEmailOrUsername('admin'); + if (adminUser) { + const [user, error] = await createUser('', username); + if (user) { + await saveUser(user); + bobalooba = user; + } else { + throw new Error(error); + } } - } -}); - -it('check initialise', async () => { - await initialiseDatabases(); - - const directoryDB = getDirectoryDB(); - expect(directoryDB).not.to.equal(undefined); - if (directoryDB) { - const default_document = (await directoryDB.get('default')) as any; - expect(default_document.name).to.equal(CONDUCTOR_INSTANCE_NAME); - - const permissions_document = (await directoryDB.get( - '_design/permissions' - )) as any; - expect(permissions_document['_id']).to.equal('_design/permissions'); - } -}); - -it('project roles', async () => { - // make some notebooks - const nb1 = await createNotebook('NB1', uispec, {}); - const nb2 = await createNotebook('NB2', uispec, {}); - - if (nb1 && nb2) { - // give user access to two of them - addProjectRoleToUser(bobalooba, nb1, 'user'); - expect(userHasPermission(bobalooba, nb1, 'read')).to.equal(true); - addProjectRoleToUser(bobalooba, nb2, 'admin'); - expect(userHasPermission(bobalooba, nb2, 'modify')).to.equal(true); - // and this should still be true - expect(userHasPermission(bobalooba, nb1, 'read')).to.equal(true); - - removeProjectRoleFromUser(bobalooba, nb1, 'user'); - expect(userHasPermission(bobalooba, nb1, 'read')).to.equal(false); - // but still... - expect(userHasPermission(bobalooba, nb2, 'modify')).to.equal(true); - } -}); - -it('getNotebooks', async () => { - // make some notebooks - const nb1 = await createNotebook('NB1', uispec, {}); - const nb2 = await createNotebook('NB2', uispec, {}); - const nb3 = await createNotebook('NB3', uispec, {}); - const nb4 = await createNotebook('NB4', uispec, {}); - - if (nb1 && nb2 && nb3 && nb4) { - // give user access to two of them - addProjectRoleToUser(bobalooba, nb1, 'user'); - addProjectRoleToUser(bobalooba, nb2, 'user'); - await saveUser(bobalooba); - - const notebooks = await getNotebooks(bobalooba); - expect(notebooks.length).to.equal(2); - } else { - throw new Error('could not make test notebooks'); - } -}); - -it('createNotebook', async () => { - await initialiseDatabases(); - const user = await getUserFromEmailOrUsername('admin'); - - const jsonText = fs.readFileSync('./notebooks/sample_notebook.json', 'utf-8'); - const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + }); - const projectID = await createNotebook(' Test Nõtebõõk', uiSpec, metadata); + it('check initialise', async () => { + await initialiseDatabases(); - expect(projectID).not.to.equal(undefined); - expect(user).not.to.be.null; + const directoryDB = getDirectoryDB(); + expect(directoryDB).not.to.equal(undefined); + if (directoryDB) { + const default_document = (await directoryDB.get('default')) as any; + expect(default_document.name).to.equal(CONDUCTOR_INSTANCE_NAME); - if (projectID && user) { - expect(projectID.substring(13)).to.equal('-test-notebook'); - - const notebooks = await getNotebooks(user); - expect(notebooks.length).to.equal(1); - const db = await getProjectMetaDB(projectID); - if (db) { - const autoInc = (await db.get('local-autoincrementers')) as any; - expect(autoInc.references.length).to.equal(2); - expect(autoInc.references[0].form_id).to.equal('FORM1SECTION1'); + const permissions_document = (await directoryDB.get( + '_design/permissions' + )) as any; + expect(permissions_document['_id']).to.equal('_design/permissions'); } - } -}); - -it('getNotebookMetadata', async () => { - await initialiseDatabases(); - - const jsonText = fs.readFileSync('./notebooks/sample_notebook.json', 'utf-8'); - const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); - const name = 'Test Notebook'; - const projectID = await createNotebook(name, uiSpec, metadata); - expect(projectID).not.to.equal(undefined); - if (projectID) { - const retrievedMetadata = await getNotebookMetadata(projectID); - - expect(retrievedMetadata).not.to.be.null; - if (retrievedMetadata) { - expect(retrievedMetadata['lead_institution']).to.equal( - metadata['lead_institution'] - ); - expect(retrievedMetadata['name']).to.equal(name); + }); + + it('project roles', async () => { + // make some notebooks + const nb1 = await createNotebook('NB1', uispec, {}); + const nb2 = await createNotebook('NB2', uispec, {}); + + if (nb1 && nb2) { + // give user access to two of them + addProjectRoleToUser(bobalooba, nb1, 'user'); + expect(userHasPermission(bobalooba, nb1, 'read')).to.equal(true); + addProjectRoleToUser(bobalooba, nb2, 'admin'); + expect(userHasPermission(bobalooba, nb2, 'modify')).to.equal(true); + // and this should still be true + expect(userHasPermission(bobalooba, nb1, 'read')).to.equal(true); + + removeProjectRoleFromUser(bobalooba, nb1, 'user'); + expect(userHasPermission(bobalooba, nb1, 'read')).to.equal(false); + // but still... + expect(userHasPermission(bobalooba, nb2, 'modify')).to.equal(true); } - } -}); - -it('getNotebookUISpec', async () => { - await initialiseDatabases(); - - const jsonText = fs.readFileSync('./notebooks/sample_notebook.json', 'utf-8'); - const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); - const name = 'Test Notebook'; - const projectID = await createNotebook(name, uiSpec, metadata); - - expect(projectID).not.to.equal(undefined); - if (projectID) { - const retrieved = await getNotebookUISpec(projectID); - - expect(retrieved).not.to.be.null; - if (retrieved) { - expect(retrieved['fviews'].length).to.equal(uiSpec.fviews.length); - expect(retrieved['fields']).not.to.equal(undefined); + }); + + it('getNotebooks', async () => { + // make some notebooks + const nb1 = await createNotebook('NB1', uispec, {}); + const nb2 = await createNotebook('NB2', uispec, {}); + const nb3 = await createNotebook('NB3', uispec, {}); + const nb4 = await createNotebook('NB4', uispec, {}); + + if (nb1 && nb2 && nb3 && nb4) { + // give user access to two of them + addProjectRoleToUser(bobalooba, nb1, 'user'); + addProjectRoleToUser(bobalooba, nb2, 'user'); + await saveUser(bobalooba); + + const notebooks = await getNotebooks(bobalooba); + expect(notebooks.length).to.equal(2); + } else { + throw new Error('could not make test notebooks'); } - } -}); - -it('get notebook roles', async () => { - await initialiseDatabases(); - - const jsonText = fs.readFileSync('./notebooks/sample_notebook.json', 'utf-8'); - const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); - const name = 'Test Notebook'; - const projectID = await createNotebook(name, uiSpec, metadata); - - expect(projectID).not.to.equal(undefined); - if (projectID) { - const roles = await getRolesForNotebook(projectID); - expect(roles.length).to.equal(4); - expect(roles).to.include('admin'); // admin role should always be present - expect(roles).to.include('team'); // specified in the UISpec - expect(roles).to.include('moderator'); // specified in the UISpec - expect(roles).to.include('user'); // user role should always be present - } -}); - -it('updateNotebook', async () => { - await initialiseDatabases(); - const user = await getUserFromEmailOrUsername('admin'); - - const jsonText = fs.readFileSync('./notebooks/sample_notebook.json', 'utf-8'); - const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); - - const projectID = await createNotebook(' Test Nõtebõõk', uiSpec, metadata); - - expect(projectID).not.to.equal(undefined); - expect(user).not.to.be.null; - - if (projectID && user) { - // now update it with a minor change - - metadata['name'] = 'Updated Test Notebook'; - metadata['project_lead'] = 'Bob Bobalooba'; - - uiSpec.fviews['FORM1SECTION1']['label'] = 'Updated Label'; - - // add a new autoincrementer field - const newField = { - 'component-namespace': 'faims-custom', - 'component-name': 'BasicAutoIncrementer', - 'type-returned': 'faims-core::String', - 'component-parameters': { - name: 'newincrementor', - id: 'newincrementor', - variant: 'outlined', - required: false, - num_digits: 5, - form_id: 'FORM1SECTION1', - label: 'FeatureIDincrementor', - }, - validationSchema: [['yup.string'], ['yup.required']], - initialValue: null, - access: ['admin'], - meta: { - annotation_label: 'annotation', - annotation: true, - uncertainty: { - include: false, - label: 'uncertainty', - }, - }, - }; - - uiSpec.fields['newincrementor'] = newField; - uiSpec.fviews['FORM1SECTION1']['fields'].push('newincrementor'); - - // now update the notebook - const newProjectID = await updateNotebook(projectID, uiSpec, metadata); - - expect(newProjectID).to.equal(projectID); - - expect(projectID.substring(13)).to.equal('-test-notebook'); - - const notebooks = await getNotebooks(user); - expect(notebooks.length).to.equal(1); - const db = await getProjectMetaDB(projectID); - if (db) { - const newUISpec = await getNotebookUISpec(projectID); - if (newUISpec) { - expect(newUISpec['fviews']['FORM1SECTION1']['label']).to.equal( - 'Updated Label' + }); + + it('can create a notebook', async () => { + await initialiseDatabases(); + const user = await getUserFromEmailOrUsername('admin'); + + const jsonText = fs.readFileSync( + './notebooks/sample_notebook.json', + 'utf-8' + ); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + + const projectID = await createNotebook( + ' Test Nõtebõõk', + uiSpec, + metadata + ); + + expect(projectID).not.to.equal(undefined); + expect(user).not.to.be.null; + + if (projectID && user) { + expect(projectID.substring(13)).to.equal('-test-notebook'); + + const notebooks = await getNotebooks(user); + expect(notebooks.length).to.equal(1); + const db = await getProjectMetaDB(projectID); + if (db) { + const autoInc = (await db.get('local-autoincrementers')) as any; + expect(autoInc.references.length).to.equal(2); + expect(autoInc.references[0].form_id).to.equal('FORM1SECTION1'); + } + } + }); + + it('getNotebookMetadata', async () => { + await initialiseDatabases(); + + const jsonText = fs.readFileSync( + './notebooks/sample_notebook.json', + 'utf-8' + ); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + const name = 'Test Notebook'; + const projectID = await createNotebook(name, uiSpec, metadata); + expect(projectID).not.to.equal(undefined); + if (projectID) { + const retrievedMetadata = await getNotebookMetadata(projectID); + + expect(retrievedMetadata).not.to.be.null; + if (retrievedMetadata) { + expect(retrievedMetadata['lead_institution']).to.equal( + metadata['lead_institution'] ); + expect(retrievedMetadata['name']).to.equal(name); } - const newMetadata = await getNotebookMetadata(projectID); - if (newMetadata) { - expect(newMetadata['name']).to.equal('Updated Test Notebook'); - expect(newMetadata['project_lead']).to.equal('Bob Bobalooba'); + } + }); + + it('getNotebookUISpec', async () => { + await initialiseDatabases(); + + const jsonText = fs.readFileSync( + './notebooks/sample_notebook.json', + 'utf-8' + ); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + const name = 'Test Notebook'; + const projectID = await createNotebook(name, uiSpec, metadata); + + expect(projectID).not.to.equal(undefined); + if (projectID) { + const retrieved = await getNotebookUISpec(projectID); + + expect(retrieved).not.to.be.null; + if (retrieved) { + expect(retrieved['fviews'].length).to.equal(uiSpec.fviews.length); + expect(retrieved['fields']).not.to.equal(undefined); } - const metaDB = await getProjectMetaDB(projectID); - if (metaDB) { - const autoInc = (await metaDB.get('local-autoincrementers')) as any; - expect(autoInc.references.length).to.equal(3); + } + }); + + it('get notebook roles', async () => { + await initialiseDatabases(); + + const jsonText = fs.readFileSync( + './notebooks/sample_notebook.json', + 'utf-8' + ); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + const name = 'Test Notebook'; + const projectID = await createNotebook(name, uiSpec, metadata); + + expect(projectID).not.to.equal(undefined); + if (projectID) { + const roles = await getRolesForNotebook(projectID); + expect(roles.length).to.equal(4); + expect(roles).to.include('admin'); // admin role should always be present + expect(roles).to.include('team'); // specified in the UISpec + expect(roles).to.include('moderator'); // specified in the UISpec + expect(roles).to.include('user'); // user role should always be present + } + }); + + it('updateNotebook', async () => { + await initialiseDatabases(); + const user = await getUserFromEmailOrUsername('admin'); + + const jsonText = fs.readFileSync( + './notebooks/sample_notebook.json', + 'utf-8' + ); + const {metadata, 'ui-specification': uiSpec} = JSON.parse(jsonText); + + const projectID = await createNotebook( + ' Test Nõtebõõk', + uiSpec, + metadata + ); + + expect(projectID).not.to.equal(undefined); + expect(user).not.to.be.null; + + if (projectID && user) { + // now update it with a minor change + + metadata['name'] = 'Updated Test Notebook'; + metadata['project_lead'] = 'Bob Bobalooba'; + + uiSpec.fviews['FORM1SECTION1']['label'] = 'Updated Label'; + + // add a new autoincrementer field + const newField = { + 'component-namespace': 'faims-custom', + 'component-name': 'BasicAutoIncrementer', + 'type-returned': 'faims-core::String', + 'component-parameters': { + name: 'newincrementor', + id: 'newincrementor', + variant: 'outlined', + required: false, + num_digits: 5, + form_id: 'FORM1SECTION1', + label: 'FeatureIDincrementor', + }, + validationSchema: [['yup.string'], ['yup.required']], + initialValue: null, + access: ['admin'], + meta: { + annotation_label: 'annotation', + annotation: true, + uncertainty: { + include: false, + label: 'uncertainty', + }, + }, + }; + + uiSpec.fields['newincrementor'] = newField; + uiSpec.fviews['FORM1SECTION1']['fields'].push('newincrementor'); + + // now update the notebook + const newProjectID = await updateNotebook(projectID, uiSpec, metadata); + + expect(newProjectID).to.equal(projectID); + + expect(projectID.substring(13)).to.equal('-test-notebook'); + + const notebooks = await getNotebooks(user); + expect(notebooks.length).to.equal(1); + const db = await getProjectMetaDB(projectID); + if (db) { + const newUISpec = await getNotebookUISpec(projectID); + if (newUISpec) { + expect(newUISpec['fviews']['FORM1SECTION1']['label']).to.equal( + 'Updated Label' + ); + } + const newMetadata = await getNotebookMetadata(projectID); + if (newMetadata) { + expect(newMetadata['name']).to.equal('Updated Test Notebook'); + expect(newMetadata['project_lead']).to.equal('Bob Bobalooba'); + } + const metaDB = await getProjectMetaDB(projectID); + if (metaDB) { + const autoInc = (await metaDB.get('local-autoincrementers')) as any; + expect(autoInc.references.length).to.equal(3); + } } } - } + }); });