diff --git a/test/data/data-sources/sqlite/sqlite-instrument_model-data-source.test.ts b/test/data/data-sources/sqlite/sqlite-instrument_model-data-source.test.ts new file mode 100644 index 0000000..82e0c1f --- /dev/null +++ b/test/data/data-sources/sqlite/sqlite-instrument_model-data-source.test.ts @@ -0,0 +1,267 @@ + +import { SQLiteInstrumentModelDataSource } from '../../../../src/data/data-sources/sqlite/sqlite-instrument_model-data-source' +import sqlite3 from 'sqlite3' +import fs from 'fs'; + +const config = { + TEST_DBSOURCE: 'TEST_DB_SOURCE_INSTRUMENT_MODEL' +} + +function initializeInstrumentModelDB() { + const db = new sqlite3.Database(config.TEST_DBSOURCE, (err) => { + if (err) { + // Cannot open database + console.error(err.message) + throw err + } + }); + // Enable foreign keys in sqlite + db.get("PRAGMA foreign_keys = ON") + + return new SQLiteInstrumentModelDataSource(db) + +} + +function cleanInstrumentModelDB() { + try { + // Delete db file + fs.unlinkSync(config.TEST_DBSOURCE); + console.log("Database file deleted successfully."); + } catch (error) { + if (error.code === 'ENOENT') { + console.log("Database file does not exist. No action needed."); + } else { + console.error("Error occurred while deleting database file:", error); + } + } +} + +describe('SQLiteInstrumentModelDataSource', () => { + let dataSource: SQLiteInstrumentModelDataSource; + + beforeAll(() => { + dataSource = initializeInstrumentModelDB(); + }); + + afterAll(() => { + cleanInstrumentModelDB(); + }); + + describe('init', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource).toBeDefined(); + }); + + // instruments should be automatically created when the db is initialized + // const sql_admin = "INSERT OR IGNORE INTO instrument_model (instrument_model_name, bodc_url) VALUES ('UVP5HD', 'https://vocab.nerc.ac.uk/collection/L22/current/TOOL1577/'), ('UVP5SD', 'https://vocab.nerc.ac.uk/collection/L22/current/TOOL1577/'), ('UVP5Z', 'https://vocab.nerc.ac.uk/collection/L22/current/TOOL1577/'), ('UVP6LP', 'https://vocab.nerc.ac.uk/collection/L22/current/TOOL1578/'), ('UVP6HF', 'https://vocab.nerc.ac.uk/collection/L22/current/TOOL1578/'), ('UVP6MHP','Not registred in BODC for now'), ('UVP6MHF', 'Not registred in BODC for now');" + test('instruments should have been created when the db was initialized', async () => { + // Call the getAll method sorted by id + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [], sort_by: [{ sort_by: 'instrument_model_id', order_by: 'ASC' }] }); + + // Expect the instrument_model ID to be returned + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.items.length).toEqual(7); + // expect instruments names + expect(getAllOutput.items[0].instrument_model_name).toEqual('UVP5HD'); + expect(getAllOutput.items[1].instrument_model_name).toEqual('UVP5SD'); + expect(getAllOutput.items[2].instrument_model_name).toEqual('UVP5Z'); + expect(getAllOutput.items[3].instrument_model_name).toEqual('UVP6LP'); + expect(getAllOutput.items[4].instrument_model_name).toEqual('UVP6HF'); + expect(getAllOutput.items[5].instrument_model_name).toEqual('UVP6MHP'); + expect(getAllOutput.items[6].instrument_model_name).toEqual('UVP6MHF'); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(7); + }) + }); + + describe('create', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource).toBeDefined(); + }); + + test('should create a instrument_model', async () => { + // Call the create method + const instrument_model_id = await dataSource.create({ instrument_model_name: 'UVP7HD', bodc_url: 'http://uvp7hd.com' }); + console.log(instrument_model_id) + // Expect the instrument_model ID to be returned + expect(instrument_model_id).toBeDefined(); + expect(instrument_model_id).toEqual(8); + }); + + test('should not create a instrument_model with the same name', async () => { + try { + // Call the create method + await dataSource.create({ instrument_model_name: 'UVP7HD', bodc_url: 'http://uvp7hd.com' }); + } catch (error) { + // expected error message + expect(error.message).toEqual('SQLITE_CONSTRAINT: UNIQUE constraint failed: instrument_model.instrument_model_name'); + } + }); + }); + + describe('getAll', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource).toBeDefined(); + }); + test('should return all instrument_models', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [], sort_by: [] }); + + // Expect the instrument_model ID to be returned + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(8); + }); + test('should return all instrument_models with pagination', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 1, filter: [], sort_by: [] }); + + // Expect the instrument_model ID to be returned + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(8); + expect(getAllOutput.items.length).toEqual(1); + }); + test('should return all instrument_models with filtering', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'instrument_model_name', operator: 'LIKE', value: 'UVP5%' }], sort_by: [{ sort_by: 'instrument_model_id', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(3); + expect(getAllOutput.items.length).toEqual(3); + expect(getAllOutput.items[0].instrument_model_name).toEqual('UVP5HD'); + }); + test('should return all instrument_models with filtering on not null', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'instrument_model_name', operator: '!=', value: 'null' }], sort_by: [{ sort_by: 'instrument_model_id', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(8); + expect(getAllOutput.items.length).toEqual(8); + expect(getAllOutput.items[0].instrument_model_name).toEqual('UVP5HD'); + }); + test('should return all instrument_models with filtering on null', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'instrument_model_name', operator: '=', value: 'null' }], sort_by: [] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(0); + expect(getAllOutput.items.length).toEqual(0); + }); + test('should return all instrument_models with sorting', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [], sort_by: [{ sort_by: 'instrument_model_name', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(8); + expect(getAllOutput.items.length).toEqual(8); + expect(getAllOutput.items[0].instrument_model_name).toEqual('UVP5HD'); + }); + test('should return all instrument_models with sorting', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [], sort_by: [{ sort_by: 'instrument_model_name', order_by: 'DESC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(8); + expect(getAllOutput.items.length).toEqual(8); + expect(getAllOutput.items[0].instrument_model_name).toEqual('UVP7HD'); + }); + + test('should return all instrument_models with sorting filtering and pagination', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 2, filter: [{ field: 'instrument_model_name', operator: 'LIKE', value: 'UVP5%' }], sort_by: [{ sort_by: 'instrument_model_creation_date', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(3); + expect(getAllOutput.items.length).toEqual(2); + expect(getAllOutput.items[0].instrument_model_name).toEqual('UVP5HD'); + expect(getAllOutput.items[1].instrument_model_name).toEqual('UVP5SD'); + }); + test('should return all instrument_models with sorting filtering and pagination', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 2, filter: [{ field: 'instrument_model_name', operator: '=', value: 'UVP5HD' }], sort_by: [{ sort_by: 'instrument_model_creation_date', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(1); + expect(getAllOutput.items.length).toEqual(1); + expect(getAllOutput.items[0].instrument_model_name).toEqual('UVP5HD'); + }); + test('should return all instrument_models with sorting filtering and pagination', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 2, filter: [{ field: 'instrument_model_name', operator: 'IN', value: ['UVP5HD', 'UVP5SD'] }], sort_by: [{ sort_by: 'instrument_model_creation_date', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(2); + expect(getAllOutput.items.length).toEqual(2); + expect(getAllOutput.items[0].instrument_model_name).toEqual('UVP5HD'); + expect(getAllOutput.items[1].instrument_model_name).toEqual('UVP5SD'); + }); + + }); + + describe('updateOne', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource).toBeDefined(); + }); + test('should update a instrument_model', async () => { + // Call the updateOne method + const updated = await dataSource.updateOne({ instrument_model_id: 8, instrument_model_name: 'UVP8', bodc_url: 'http://uvp8.com' }); + + // Expect the NUMBER of updated rows to be returned + expect(updated).toBeDefined(); + expect(updated).toEqual(1); + // Call the getAll method where the instrument_model is updated + const getAllOutput = await dataSource.getOne({ instrument_model_id: 8 }); + expect(getAllOutput).toBeDefined(); + expect(getAllOutput?.instrument_model_name).toEqual('UVP8'); + expect(getAllOutput?.bodc_url).toEqual('http://uvp8.com'); + }); + test('should not update a instrument_model with the same name', async () => { + try { + // Call the updateOne method + await dataSource.updateOne({ instrument_model_id: 8, instrument_model_name: 'UVP5HD', bodc_url: 'http://uvp7hd.com' }); + } catch (error) { + // expected error message + expect(error.message).toEqual('SQLITE_CONSTRAINT: UNIQUE constraint failed: instrument_model.instrument_model_name'); + } + }); + }); + describe('getOne', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource).toBeDefined(); + }); + test('get one by instrument_model_id : no matchs', async () => { + // Call the getOne method + const instrument_model = await dataSource.getOne({ instrument_model_id: 5678 }); + expect(instrument_model).toBeDefined(); + // not null + expect(instrument_model).toBeNull(); + }); + test('get one by instrument_model_id', async () => { + // Call the getOne method + const instrument_model = await dataSource.getOne({ instrument_model_id: 8 }); + expect(instrument_model).toBeDefined(); + // not null + expect(instrument_model).not.toBeNull(); + if (instrument_model) { + // Compare each property individually, excluding the instrument_model_creation_date + expect(instrument_model.instrument_model_id).toEqual(8); + expect(instrument_model.instrument_model_name).toEqual('UVP8'); + expect(instrument_model.bodc_url).toEqual('http://uvp8.com'); + } + }); + test('get one by instrument_model_id : no matchs', async () => { + // Call the getOne method + const instrument_model = await dataSource.getOne({ instrument_model_id: 5678 }); + expect(instrument_model).toBeDefined(); + expect(instrument_model).toBeNull(); + }); + }); + +}); + diff --git a/test/data/data-sources/sqlite/sqlite-privileges-data-source.test.ts b/test/data/data-sources/sqlite/sqlite-privileges-data-source.test.ts new file mode 100644 index 0000000..60920a5 --- /dev/null +++ b/test/data/data-sources/sqlite/sqlite-privileges-data-source.test.ts @@ -0,0 +1,348 @@ + + +import { SQLitePrivilegeDataSource } from '../../../../src/data/data-sources/sqlite/sqlite-privilege-data-source'; +import { SQLiteProjectDataSource } from '../../../../src/data/data-sources/sqlite/sqlite-project-data-source'; +import { SQLiteUserDataSource } from '../../../../src/data/data-sources/sqlite/sqlite-user-data-source'; +import { SQLiteInstrumentModelDataSource } from '../../../../src/data/data-sources/sqlite/sqlite-instrument_model-data-source'; + +import sqlite3 from 'sqlite3' +import fs from 'fs'; +import { userRequestCreationModel_1, userRequestCreationModel_2 } from '../../../entities/user'; +import { projectRequestCreationModelForRepository } from '../../../entities/project'; +import { PrivilegeRequestModel } from '../../../../src/domain/entities/privilege'; + +const config = { + TEST_DBSOURCE: 'TEST_DB_SOURCE_PRIVILEGE' +} + +function initializeDB() { + const db = new sqlite3.Database(config.TEST_DBSOURCE, (err) => { + if (err) { + // Cannot open database + console.error(err.message) + throw err + } + }); + // Enable foreign keys in sqlite + db.get("PRAGMA foreign_keys = ON") + return db +} +function initializePrivilegeDB(db: sqlite3.Database) { + return new SQLitePrivilegeDataSource(db) +} +function initializeProjectDB(db: sqlite3.Database) { + return new SQLiteProjectDataSource(db) +} +function initializeUserDB(db: sqlite3.Database) { + return new SQLiteUserDataSource(db) +} +function initializeInstrumentModelDB(db: sqlite3.Database) { + return new SQLiteInstrumentModelDataSource(db) +} + +function cleanDB() { + try { + // Delete db file + fs.unlinkSync(config.TEST_DBSOURCE); + console.log("Database file deleted successfully."); + } catch (error) { + if (error.code === 'ENOENT') { + console.log("Database file does not exist. No action needed."); + } else { + console.error("Error occurred while deleting database file:", error); + } + } +} + +describe('SQLitePrivilegeDataSource', () => { + let db: sqlite3.Database; + let dataSource_Privilege: SQLitePrivilegeDataSource; + let dataSource_Project: SQLiteProjectDataSource; + let dataSource_User: SQLiteUserDataSource; + let dataSource_InstrumentModel: SQLiteInstrumentModelDataSource; + + beforeAll(() => { + db = initializeDB(); + dataSource_Privilege = initializePrivilegeDB(db); + dataSource_Project = initializeProjectDB(db); + dataSource_User = initializeUserDB(db); + dataSource_InstrumentModel = initializeInstrumentModelDB(db); + }); + + afterAll(() => { + cleanDB(); + }); + + describe('create', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource_Privilege).toBeDefined(); + expect(dataSource_Project).toBeDefined(); + expect(dataSource_User).toBeDefined(); + expect(dataSource_InstrumentModel).toBeDefined(); + }); + + test('should create a privilege', async () => { + + const user_id = await dataSource_User.create(userRequestCreationModel_1) + const project_id = await dataSource_Project.create(projectRequestCreationModelForRepository) + // Call the create method + //member or manager + //user_id, project_id, privilege_name, contact + const privilege_id = await dataSource_Privilege.create({ user_id: user_id, project_id: project_id, privilege_name: 'manager', contact: true }); + console.log(privilege_id) + // Expect the privilege ID to be returned + expect(privilege_id).toBeDefined(); + expect(privilege_id).toEqual(1); + }); + + test('should not create a privilege for an unknown user', async () => { + try { + // Call the create method with an unknown user_id + await dataSource_Privilege.create({ user_id: 1234567899, project_id: 1, privilege_name: 'manager', contact: true }); + + // If it doesn't throw, the test should fail + expect(true).toBeFalsy(); + } catch (error) { + // Log the error message to see what is being caught + console.log('Caught error:', error.message); + + // If it throws, check the error message + expect(error).toBeDefined(); + expect(error.message).toEqual('SQLITE_CONSTRAINT: FOREIGN KEY constraint failed'); + } + }); + + + test('should not create a privilege fo an unknown project', async () => { + try { + // Call the create method + await dataSource_Privilege.create({ user_id: 1, project_id: 1234, privilege_name: 'manager', contact: true }); + expect(true).toBeFalsy(); + } catch (error) { + // expected error message + expect(error.message).toEqual('SQLITE_CONSTRAINT: FOREIGN KEY constraint failed'); + } + + }); + }); + + describe('deleteOne', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource_Privilege).toBeDefined(); + expect(dataSource_Project).toBeDefined(); + expect(dataSource_User).toBeDefined(); + expect(dataSource_InstrumentModel).toBeDefined(); + }); + + test('should delete a privilege', async () => { + // Call the deleteOne method + const deleted = await dataSource_Privilege.deleteOne({ privilege_id: 1 }); + + // Expect the NUMBER of deleted rows to be returned + expect(deleted).toBeDefined(); + expect(deleted).toEqual(1); + }); + + test('should not delete a privilege that does not exist', async () => { + // Call the deleteOne method + const deleted = await dataSource_Privilege.deleteOne({ privilege_id: 1234 }); + + // Expect the NUMBER of deleted rows to be returned + expect(deleted).toBeDefined(); + expect(deleted).toEqual(0); + }); + }); + + describe('deleteAll', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource_Privilege).toBeDefined(); + expect(dataSource_Project).toBeDefined(); + expect(dataSource_User).toBeDefined(); + expect(dataSource_InstrumentModel).toBeDefined(); + }); + + test('should delete all privileges for the given user_id', async () => { + + const project_id_1 = await dataSource_Project.create(projectRequestCreationModelForRepository) + const project_id_2 = await dataSource_Project.create(projectRequestCreationModelForRepository) + await dataSource_Privilege.create({ user_id: 1, project_id: project_id_1, privilege_name: 'manager', contact: true }); + await dataSource_Privilege.create({ user_id: 1, project_id: project_id_2, privilege_name: 'member', contact: false }); + + // count how many privileges are in the database for user 1 + const privilegesBefore = await dataSource_Privilege.getAll({ + page: 1, limit: 10, filter: [{ + field: 'user_id', + operator: '=', + value: 1 + }], sort_by: [] + }); + const numberOfPrivilegesBefore = privilegesBefore.total + // Call the deleteAll method + const privilege: PrivilegeRequestModel = { user_id: 1 } + const deleted = await dataSource_Privilege.deleteAll(privilege); + + // Expect the NUMBER of deleted rows to be returned + expect(deleted).toBeDefined(); + expect(deleted).toEqual(numberOfPrivilegesBefore); + }); + + test('should delete all privileges for the given project_id', async () => { + + await dataSource_Privilege.create({ user_id: 1, project_id: 1, privilege_name: 'manager', contact: true }); + + // count how many privileges are in the database for project 1 + const privilegesBefore = await dataSource_Privilege.getAll({ + page: 1, limit: 10, filter: [{ + field: 'project_id', + operator: '=', + value: 1 + }], sort_by: [] + }); + const numberOfPrivilegesBefore = privilegesBefore.total + // Call the deleteAll method + const privilege: PrivilegeRequestModel = { project_id: 1 } + const deleted = await dataSource_Privilege.deleteAll(privilege); + + // Expect the NUMBER of deleted rows to be returned + expect(deleted).toBeDefined(); + expect(deleted).toEqual(numberOfPrivilegesBefore); + }); + }); + + describe('getAll', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource_Privilege).toBeDefined(); + expect(dataSource_Project).toBeDefined(); + expect(dataSource_User).toBeDefined(); + expect(dataSource_InstrumentModel).toBeDefined(); + }); + + test('should return all privileges', async () => { + const project_id_1 = await dataSource_Project.create(projectRequestCreationModelForRepository) + const project_id_2 = await dataSource_Project.create(projectRequestCreationModelForRepository) + await dataSource_Privilege.create({ user_id: 1, project_id: project_id_1, privilege_name: 'manager', contact: true }); + await dataSource_Privilege.create({ user_id: 1, project_id: project_id_2, privilege_name: 'member', contact: false }); + + // Call the getAll method + const getAllOutput = await dataSource_Privilege.getAll({ page: 1, limit: 10, filter: [], sort_by: [] }); + + // Expect the privilege ID to be returned + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(2); + }); + + test('should return all privileges with pagination', async () => { + // Call the getAll method + const getAllOutput = await dataSource_Privilege.getAll({ page: 1, limit: 1, filter: [], sort_by: [] }); + + // Expect the privilege ID to be returned + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(2); + expect(getAllOutput.items.length).toEqual(1); + }); + + test('should return all privileges with filtering', async () => { + // Call the getAll method + const getAllOutput = await dataSource_Privilege.getAll({ page: 1, limit: 10, filter: [{ field: 'privilege_name', operator: 'LIKE', value: 'manager' }], sort_by: [{ sort_by: 'privilege_id', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(1); + expect(getAllOutput.items.length).toEqual(1); + expect(getAllOutput.items[0].privilege_name).toEqual('manager'); + }); + + test('should return all privileges with filtering on not null', async () => { + // Call the getAll method + const getAllOutput = await dataSource_Privilege.getAll({ page: 1, limit: 10, filter: [{ field: 'privilege_name', operator: '!=', value: 'null' }], sort_by: [{ sort_by: 'privilege_id', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(2); + expect(getAllOutput.items.length).toEqual(2); + expect(getAllOutput.items[0].privilege_name).toEqual('manager'); + }); + + test('should return all privileges with filtering on null', async () => { + // Call the getAll method + const getAllOutput = await dataSource_Privilege.getAll({ page: 1, limit: 10, filter: [{ field: 'user_id', operator: '=', value: 'null' }], sort_by: [] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(0); + expect(getAllOutput.items.length).toEqual(0); + }); + + test('should return all privileges with sorting', async () => { + // Call the getAll method + const getAllOutput = await dataSource_Privilege.getAll({ page: 1, limit: 10, filter: [], sort_by: [{ sort_by: 'project_id', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(2); + expect(getAllOutput.items.length).toEqual(2); + expect(getAllOutput.items[0].project_id).toEqual(4); + }); + + test('should return all privileges with sorting', async () => { + // Call the getAll method + const getAllOutput = await dataSource_Privilege.getAll({ page: 1, limit: 10, filter: [], sort_by: [{ sort_by: 'project_id', order_by: 'DESC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(2); + expect(getAllOutput.items.length).toEqual(2); + expect(getAllOutput.items[0].project_id).toEqual(5); + }); + + test('should return all privileges with sorting filtering and pagination', async () => { + // Call the getAll method + const getAllOutput = await dataSource_Privilege.getAll({ page: 1, limit: 2, filter: [{ field: 'privilege_name', operator: 'LIKE', value: 'm%' }], sort_by: [{ sort_by: 'privilege_creation_date', order_by: 'ASC' }] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(2); + expect(getAllOutput.items.length).toEqual(2); + expect(getAllOutput.items[0].privilege_name).toEqual('manager'); + }); + }); + + describe('getOne', () => { + test('init the db', async () => { + // Test initializing the database + expect(dataSource_Privilege).toBeDefined(); + expect(dataSource_Project).toBeDefined(); + expect(dataSource_User).toBeDefined(); + expect(dataSource_InstrumentModel).toBeDefined(); + }); + + test('get one by privilege_id : no matchs', async () => { + // Call the getOne method + const privilege = await dataSource_Privilege.getOne({ privilege_id: 5678 }); + expect(privilege).toBeDefined(); + // not null + expect(privilege).toBeNull(); + }); + + test('get one by privilege_id', async () => { + // create a privilege + const user_id = await dataSource_User.create(userRequestCreationModel_2) + const project_id = await dataSource_Project.create(projectRequestCreationModelForRepository) + const privilege_id = await dataSource_Privilege.create({ user_id: user_id, project_id: project_id, privilege_name: 'manager', contact: true }); + // Call the getOne method + const privilege = await dataSource_Privilege.getOne({ privilege_id: privilege_id }); + expect(privilege).toBeDefined(); + // not null + expect(privilege).not.toBeNull(); + if (privilege) { + // Compare each property individually, excluding the privilege_creation_date + expect(privilege.privilege_id).toEqual(privilege_id); + expect(privilege.privilege_name).toEqual('manager'); + expect(privilege.contact).toEqual(true); + expect(privilege.user_id).toEqual(user_id); + expect(privilege.project_id).toEqual(project_id); + } + }); + }); +}); + diff --git a/test/data/data-sources/sqlite/sqlite-project-data-source.test.ts b/test/data/data-sources/sqlite/sqlite-project-data-source.test.ts index 740a1e9..73c8fe2 100644 --- a/test/data/data-sources/sqlite/sqlite-project-data-source.test.ts +++ b/test/data/data-sources/sqlite/sqlite-project-data-source.test.ts @@ -1,13 +1,12 @@ import { SQLiteProjectDataSource } from '../../../../src/data/data-sources/sqlite/sqlite-project-data-source' import { SQLiteInstrumentModelDataSource } from '../../../../src/data/data-sources/sqlite/sqlite-instrument_model-data-source' import sqlite3 from 'sqlite3' -import 'dotenv/config' import { ProjectRequestCreationModel, ProjectUpdateModel } from '../../../../src/domain/entities/project'; import fs from 'fs'; import { data_source_projectRequestCreationModel_2, data_source_projectRequestCreationModel_3, data_source_projectRequestCreationModel_4, data_source_projectRequestCreationModel_5, data_source_projectRequestCreationModel_6, privateProjectUpdateModel, projectRequestCreationModel_3 } from '../../../entities/project'; const config = { - TEST_DBSOURCE: process.env.TEST_DBSOURCE || '', + TEST_DBSOURCE: 'TEST_DB_SOURCE_PROJECT' } function initializeProjectDB() { @@ -18,6 +17,9 @@ function initializeProjectDB() { throw err } }); + // Enable foreign keys in sqlite + db.get("PRAGMA foreign_keys = ON") + new SQLiteInstrumentModelDataSource(db) return new SQLiteProjectDataSource(db) } @@ -113,6 +115,24 @@ describe('SQLiteProjectDataSource', () => { expect(getAllOutput.items.length).toEqual(1); expect(getAllOutput.items[0].project_title).toEqual('joan project_title'); }); + test('should return all projects with filtering on not null', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'override_depth_offset', operator: '!=', value: 'null' }], sort_by: [] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(1); + expect(getAllOutput.items.length).toEqual(1); + expect(getAllOutput.items[0].project_title).toEqual('joan project_title'); + }); + test('should return all projects with filtering on null', async () => { + // Call the getAll method + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'override_depth_offset', operator: '=', value: 'null' }], sort_by: [] }); + expect(getAllOutput.items).toBeDefined(); + expect(getAllOutput.total).toBeDefined(); + expect(getAllOutput.total).toEqual(1); + expect(getAllOutput.items.length).toEqual(1); + expect(getAllOutput.items[0].project_title).toEqual('john project_title'); + }); test('should return all projects with filtering', async () => { // Call the getAll method const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'project_title', operator: 'LIKE', value: 'jo%' }], sort_by: [] }); @@ -221,6 +241,7 @@ describe('SQLiteProjectDataSource', () => { expect(getAllOutput.total).toBeDefined(); expect(getAllOutput.total).toEqual(1); expect(getAllOutput.items.length).toEqual(1); + expect(getAllOutput.items[0].enable_descent_filter).toEqual(true); expect(getAllOutput.items[0].operator_email).toEqual("edited_user@email.com"); expect(getAllOutput.items[0].operator_name).toEqual("Edited name"); }); diff --git a/test/data/data-sources/sqlite/sqlite-user-data-source.test.ts b/test/data/data-sources/sqlite/sqlite-user-data-source.test.ts index 704a0dc..b8f521d 100644 --- a/test/data/data-sources/sqlite/sqlite-user-data-source.test.ts +++ b/test/data/data-sources/sqlite/sqlite-user-data-source.test.ts @@ -1,11 +1,10 @@ import { SQLiteUserDataSource } from '../../../../src/data/data-sources/sqlite/sqlite-user-data-source' import sqlite3 from 'sqlite3' -import 'dotenv/config' import { UserRequestCreationModel, UserUpdateModel } from '../../../../src/domain/entities/user'; import fs from 'fs'; const config = { - TEST_DBSOURCE: process.env.TEST_DBSOURCE || '', + TEST_DBSOURCE: 'TEST_DB_SOURCE_USER' } function initializeUserDB() { @@ -16,6 +15,9 @@ function initializeUserDB() { throw err } }); + // Enable foreign keys in sqlite + db.get("PRAGMA foreign_keys = ON") + return new SQLiteUserDataSource(db) } @@ -86,14 +88,21 @@ describe('SQLiteUserDataSource', () => { user_planned_usage: 'Usage' }; + // Insert the user the first time + await dataSource.create(user); + try { + // Attempt to insert the user a second time await dataSource.create(user); - } - catch (error) { + // If it doesn't throw, the test should fail + expect(true).toBeFalsy(); + } catch (error) { + // If it throws, check the error message expect(error).toBeDefined(); expect(error.message).toEqual('SQLITE_CONSTRAINT: UNIQUE constraint failed: user.email'); } }); + }); describe('getAll', () => { test('init the db', async () => { @@ -244,7 +253,7 @@ describe('SQLiteUserDataSource', () => { }); test('should return all users with sorting and filtering and pagination null', async () => { // Call the getAll method - const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'deleted', operator: '=', value: null }], sort_by: [] }); + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'deleted', operator: '=', value: 'null' }], sort_by: [] }); expect(getAllOutput.items).toBeDefined(); expect(getAllOutput.total).toBeDefined(); expect(getAllOutput.total).toEqual(6); @@ -252,7 +261,7 @@ describe('SQLiteUserDataSource', () => { }); test('should return all users with sorting and filtering and pagination null', async () => { // Call the getAll method - const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'deleted', operator: '!=', value: null }], sort_by: [] }); + const getAllOutput = await dataSource.getAll({ page: 1, limit: 10, filter: [{ field: 'deleted', operator: '!=', value: 'null' }], sort_by: [] }); expect(getAllOutput.items).toBeDefined(); expect(getAllOutput.total).toBeDefined(); expect(getAllOutput.total).toEqual(0); diff --git a/test/domain/repositories/instrument_model-repository.test.ts b/test/domain/repositories/instrument_model-repository.test.ts new file mode 100644 index 0000000..4298197 --- /dev/null +++ b/test/domain/repositories/instrument_model-repository.test.ts @@ -0,0 +1,382 @@ +//test/domain/repositories/instrument_model-repository.test.ts +import { cat } from "shelljs"; +import { InstrumentModelDataSource } from "../../../src/data/interfaces/data-sources/instrument_model-data-source"; +import { InstrumentModelRepository } from "../../../src/domain/interfaces/repositories/instrument_model-repository"; +import { InstrumentModelRepositoryImpl } from "../../../src/domain/repositories/instrument_model-repository"; +import { instrument_model_request_id, instrument_model_response } from "../../entities/instrumentModel"; +import { MockInstrumentModelDataSource } from "../../mocks/instrumentModel-mock"; + +import 'dotenv/config' + +describe("InstrumentModel Repository", () => { + let mockInstrumentModelDataSource: InstrumentModelDataSource; + + let instrument_modelRepository: InstrumentModelRepository + + beforeEach(() => { + jest.clearAllMocks(); + mockInstrumentModelDataSource = new MockInstrumentModelDataSource() + instrument_modelRepository = new InstrumentModelRepositoryImpl(mockInstrumentModelDataSource) + }) + + // to test getOneInstrumentModel, standardGetInstrumentModels, getInstrumentByName + + describe("GetOneInstrumentModel", () => { + test("Should get a instrument_model", async () => { + + jest.spyOn(mockInstrumentModelDataSource, 'getOne').mockResolvedValue(instrument_model_response) + + const result = await instrument_modelRepository.getOneInstrumentModel(instrument_model_request_id) + + expect(mockInstrumentModelDataSource.getOne).toBeCalledWith(instrument_model_request_id) + expect(result).toBe(instrument_model_response) + }) + test("Should return null if no instrument_model is found", async () => { + + jest.spyOn(mockInstrumentModelDataSource, 'getOne').mockResolvedValue(null) + + const result = await instrument_modelRepository.getOneInstrumentModel(instrument_model_request_id) + + expect(mockInstrumentModelDataSource.getOne).toBeCalledWith(instrument_model_request_id) + expect(result).toBe(null) + }); + }); + + describe("StandardGetInstrumentModels", () => { + test("Should get all instrument_models", async () => { + const options = { page: 1, limit: 10, sort_by: [], filter: [] } + const result = { items: [instrument_model_response], total: 1 } + + jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue(result) + + const response = await instrument_modelRepository.standardGetInstrumentModels(options) + + expect(mockInstrumentModelDataSource.getAll).toBeCalledWith(options) + expect(response).toBe(result) + }) + test("Should get all instrument_models with sort_by and filter", async () => { + const result = { items: [instrument_model_response], total: 1 } + const options = { + page: 1, + limit: 10, + sort_by: [{ sort_by: "instrument_model_name", order_by: "asc" }], + filter: [{ field: "instrument_model_name", operator: "LIKE", value: "UVP%" }] + } + jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue(result) + + const response = await instrument_modelRepository.standardGetInstrumentModels(options) + + expect(mockInstrumentModelDataSource.getAll).toBeCalledWith(options) + expect(response).toBe(result) + }); + test("Should return error for unauthorized sort_by", async () => { + const options = { + page: 1, + limit: 10, + sort_by: [{ sort_by: "unauthorized_param", order_by: "asc" }], + filter: [{ field: "instrument_model_name", operator: "LIKE", value: "UVP%" }] + } + jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue({ items: [], total: 0 }) + + try { + await instrument_modelRepository.standardGetInstrumentModels(options) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("Unauthorized or unexisting parameters : Unauthorized sort_by: unauthorized_param") + } + expect(mockInstrumentModelDataSource.getAll).not.toBeCalled() + }); + test("Should return error for unauthorized order_by", async () => { + const options = { + page: 1, + limit: 10, + sort_by: [{ sort_by: "instrument_model_name", order_by: "unauthorized_param" }], + filter: [{ field: "instrument_model_name", operator: "LIKE", value: "UVP%" }] + } + jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue({ items: [], total: 0 }) + + try { + await instrument_modelRepository.standardGetInstrumentModels(options) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("Unauthorized or unexisting parameters : Unauthorized order_by: unauthorized_param") + } + expect(mockInstrumentModelDataSource.getAll).not.toBeCalled() + }); + test("Should return error for unauthorized filter field", async () => { + const options = { + page: 1, + limit: 10, + sort_by: [], + filter: [{ field: "unauthorized_param", operator: "IN", value: "[1,2]" }] + } + jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue({ items: [], total: 0 }) + + try { + await instrument_modelRepository.standardGetInstrumentModels(options) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("Unauthorized or unexisting parameters : Filter field: unauthorized_param") + } + expect(mockInstrumentModelDataSource.getAll).not.toBeCalled() + }); + test("Should return error for unauthorized filter operator", async () => { + const options = { + page: 1, + limit: 10, + sort_by: [], + filter: [{ field: "instrument_model_name", operator: "unauthorized_param", value: "UVP%" }] + } + jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue({ items: [], total: 0 }) + + try { + await instrument_modelRepository.standardGetInstrumentModels(options) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("Unauthorized or unexisting parameters : Filter operator: unauthorized_param") + } + expect(mockInstrumentModelDataSource.getAll).not.toBeCalled() + }); + }); + describe("GetInstrumentByName", () => { + test("Should get a instrument_model by name", async () => { + const instrument_model_name = "UVP5HD" + + jest.spyOn(mockInstrumentModelDataSource, 'getOne').mockResolvedValue(instrument_model_response) + + const result = await instrument_modelRepository.getInstrumentByName(instrument_model_name) + + expect(mockInstrumentModelDataSource.getOne).toBeCalledWith({ "instrument_model_name": instrument_model_name }) + expect(result).toBe(instrument_model_response) + + }) + test("Should return null if no instrument_model is found", async () => { + const instrument_model_name = "UVP5HD" + + jest.spyOn(mockInstrumentModelDataSource, 'getOne').mockResolvedValue(null) + try { + await instrument_modelRepository.getInstrumentByName(instrument_model_name) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("Instrument not found") + expect(mockInstrumentModelDataSource.getOne).toBeCalledWith({ "instrument_model_name": instrument_model_name }) + } + }); + }); + + + + + // describe("CreateInstrumentModel", () => { + // test("Should create a instrument_model", async () => { + // const instrument_model: InstrumentModelRequestCreationModel = instrument_modelRequestCreationModelForRepository + + // jest.spyOn(mockInstrumentModelDataSource, 'create').mockResolvedValue(1) + + // const result = await instrument_modelRepository.cre(instrument_model) + + // expect(mockInstrumentModelDataSource.create).toBeCalledWith(instrument_model) + // expect(result).toBe(1) + // }) + // }) + + // describe("GetInstrumentModel", () => { + // test("Should get a instrument_model", async () => { + // const instrument_model: InstrumentModelRequestModel = { instrument_model_id: 1 } + // const instrument_modelResponse: InstrumentModelResponseModel = instrument_modelResponseModel + + // jest.spyOn(mockInstrumentModelDataSource, 'getOne').mockResolvedValue(instrument_modelResponse) + + // const result = await instrument_modelRepository.getInstrumentModel(instrument_model) + + // expect(mockInstrumentModelDataSource.getOne).toBeCalledWith(instrument_model) + // expect(result).toBe(instrument_modelResponse) + // }) + + // }) + + // describe("ComputeDefaultDepthOffset", () => { + // test("Should compute default depth offset", async () => { + // const instrument_model = "UVP5HD" + // const result = instrument_modelRepository.computeDefaultDepthOffset(instrument_model) + + // expect(result).toBe(1.2) + // }) + + // test("Should throw an error if instrument is undefined", async () => { + // const instrument_model = undefined as any + // expect(() => instrument_modelRepository.computeDefaultDepthOffset(instrument_model)).toThrowError("Instrument is required") + // }) + + // test("Should return undefined if instrument is not uvp5", async () => { + // const instrument_model = "not_uvp5" + // const result = instrument_modelRepository.computeDefaultDepthOffset(instrument_model) + + // expect(result).toBe(undefined) + // }) + // }) + + // describe("DeleteInstrumentModel", () => { + // test("Should delete a instrument_model", async () => { + // const instrument_model: InstrumentModelRequestModel = { instrument_model_id: 1 } + + // jest.spyOn(mockInstrumentModelDataSource, 'deleteOne').mockResolvedValue(1) + + // const result = await instrument_modelRepository.deleteInstrumentModel(instrument_model) + + // expect(mockInstrumentModelDataSource.deleteOne).toBeCalledWith(instrument_model) + // expect(result).toBe(1) + // }) + // }); + + // describe("UpdateInstrumentModel", () => { + // //TODO + // test("Should update a instrument_model", async () => { + // const instrument_model: InstrumentModelUpdateModel = privateInstrumentModelUpdateModel + + // jest.spyOn(mockInstrumentModelDataSource, 'updateOne').mockResolvedValue(1) + + // const result = await instrument_modelRepository.standardUpdateInstrumentModel(instrument_model) + + // expect(mockInstrumentModelDataSource.updateOne).toBeCalledWith(instrument_model) + // expect(result).toBe(1) + // }) + + // test("Should throw an error if unauthorized params are found", async () => { + // const instrument_model = instrument_modelUpdateModel_withBadData + + // jest.spyOn(mockInstrumentModelDataSource, "updateOne").mockImplementation(() => Promise.resolve(1)) + + // try { + // await instrument_modelRepository.standardUpdateInstrumentModel(instrument_model) + // } catch (e) { + // expect(e).toBeInstanceOf(Error) + // expect(e.message).toBe("Unauthorized or unexisting parameters : unauthorized_param") + // } + // // exceptget all have been called with + // expect(mockInstrumentModelDataSource.updateOne).not.toBeCalled() + + // }) + + // test("Should throw an error if no valid parameter is provided", async () => { + // const instrument_model = { instrument_model_id: 1 } + + // jest.spyOn(mockInstrumentModelDataSource, "updateOne").mockImplementation(() => Promise.resolve(1)) + + // try { + // await instrument_modelRepository.standardUpdateInstrumentModel(instrument_model as InstrumentModelUpdateModel) + // } catch (e) { + // expect(e).toBeInstanceOf(Error) + // expect(e.message).toBe("Please provide at least one valid parameter to update") + // } + // // exceptget all have been called with + // expect(mockInstrumentModelDataSource.updateOne).not.toBeCalled() + // }) + + // }); + // describe("GetInstrumentModels", () => { + // test("Should get all instrument_models", async () => { + // const options = { page: 1, limit: 10, sort_by: [], filter: [] } + // const result: SearchResult = { + // items: instrument_modelResponseModelArray, + // total: 2 + // } + + // jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue(result) + + // const response = await instrument_modelRepository.standardGetInstrumentModels(options) + + // expect(mockInstrumentModelDataSource.getAll).toBeCalledWith(options) + // expect(response).toBe(result) + // }) + // test("Should get all instrument_models with sort_by and filter", async () => { + // const result: SearchResult = { + // items: instrument_modelResponseModelArray, + // total: 2 + // } + // const options = { + // page: 1, + // limit: 10, + // sort_by: [{ sort_by: "instrument_model_title", order_by: "asc" }], + // filter: [{ field: "instrument_model_id", operator: "IN", value: "[1,2]" }] + // } + // jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue(result) + + // const response = await instrument_modelRepository.standardGetInstrumentModels(options) + + // expect(mockInstrumentModelDataSource.getAll).toBeCalledWith(options) + // expect(response).toBe(result) + // }) + // test("Should return error for unauthorized sort_by", async () => { + // const options = { + // page: 1, + // limit: 10, + // sort_by: [{ sort_by: "unauthorized_param", order_by: "asc" }], + // filter: [{ field: "instrument_model_id", operator: "IN", value: "[1,2]" }] + // } + // jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue({ items: [], total: 0 }) + + // try { + // await instrument_modelRepository.standardGetInstrumentModels(options) + // } catch (e) { + // expect(e).toBeInstanceOf(Error) + // expect(e.message).toBe("Unauthorized or unexisting parameters : Unauthorized sort_by: unauthorized_param") + // } + // expect(mockInstrumentModelDataSource.getAll).not.toBeCalled() + // }) + // test("Should return error for unauthorized order_by", async () => { + // const options = { + // page: 1, + // limit: 10, + // sort_by: [{ sort_by: "instrument_model_title", order_by: "unauthorized_param" }], + // filter: [{ field: "instrument_model_id", operator: "IN", value: "[1,2]" }] + // } + // jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue({ items: [], total: 0 }) + + // try { + // await instrument_modelRepository.standardGetInstrumentModels(options) + // } catch (e) { + // expect(e).toBeInstanceOf(Error) + // expect(e.message).toBe("Unauthorized or unexisting parameters : Unauthorized order_by: unauthorized_param") + // } + // expect(mockInstrumentModelDataSource.getAll).not.toBeCalled() + // }) + // test("Should return error for unauthorized filter field", async () => { + // const options = { + // page: 1, + // limit: 10, + // sort_by: [{ sort_by: "instrument_model_title", order_by: "asc" }], + // filter: [{ field: "unauthorized_param", operator: "IN", value: "[1,2]" }] + // } + // jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue({ items: [], total: 0 }) + + // try { + // await instrument_modelRepository.standardGetInstrumentModels(options) + // } catch (e) { + // expect(e).toBeInstanceOf(Error) + // expect(e.message).toBe("Unauthorized or unexisting parameters : Filter field: unauthorized_param") + // } + // expect(mockInstrumentModelDataSource.getAll).not.toBeCalled() + // }) + // test("Should return error for unauthorized filter operator", async () => { + // const options = { + // page: 1, + // limit: 10, + // sort_by: [{ sort_by: "instrument_model_title", order_by: "asc" }], + // filter: [{ field: "instrument_model_id", operator: "unauthorized_param", value: "[1,2]" }] + // } + // jest.spyOn(mockInstrumentModelDataSource, 'getAll').mockResolvedValue({ items: [], total: 0 }) + + // try { + // await instrument_modelRepository.standardGetInstrumentModels(options) + // } catch (e) { + // expect(e).toBeInstanceOf(Error) + // expect(e.message).toBe("Unauthorized or unexisting parameters : Filter operator: unauthorized_param") + // } + // expect(mockInstrumentModelDataSource.getAll).not.toBeCalled() + // }) + + // }) + + +}) diff --git a/test/domain/repositories/privilege-repository.test.ts b/test/domain/repositories/privilege-repository.test.ts new file mode 100644 index 0000000..3ee69af --- /dev/null +++ b/test/domain/repositories/privilege-repository.test.ts @@ -0,0 +1,344 @@ +//test/domain/repositories/privilege-repository.test.ts +import { PrivilegeDataSource } from "../../../src/data/interfaces/data-sources/privilege-data-source"; +import { PrivilegeResponseModel, PublicPrivilege } from "../../../src/domain/entities/privilege"; +import { SearchResult } from "../../../src/domain/entities/search"; +import { PrivilegeRepository } from "../../../src/domain/interfaces/repositories/privilege-repository"; +import { PrivilegeRepositoryImpl } from "../../../src/domain/repositories/privilege-repository"; +import { coherentPrivileges, privilegesRequestCreation_WithMemberAndManager, privilegesResponse_WithMemberAndManager, privileges_WithContactNetherManagerNorMember, privileges_WithNoManager, privileges_WithOneUserMemberAndManager, publicPrivilegesResponse_WithMemberAndManager, publicPrivileges_WithMemberAndManager } from "../../entities/privilege"; +import { MockPrivilegeDataSource } from "../../mocks/privilege-mock"; + +import 'dotenv/config' + +describe("Privilege Repository", () => { + let mockPrivilegeDataSource: PrivilegeDataSource; + + let privilegeRepository: PrivilegeRepository + + beforeEach(() => { + jest.clearAllMocks(); + mockPrivilegeDataSource = new MockPrivilegeDataSource() + privilegeRepository = new PrivilegeRepositoryImpl(mockPrivilegeDataSource) + }) + + // to test : createPrivileges, getPublicPrivileges, getProjectsByUser, getProjectsByUsers, getProjectsByContacts, getProjectsByManagers, getProjectsByMembers, isGranted, isManager, getContact, deletePrivileges, ensurePrivilegeCoherence + + describe("CreatePrivileges", () => { + test("Should create a privilege and return 1", async () => { + const privilege: PublicPrivilege = publicPrivileges_WithMemberAndManager + + jest.spyOn(mockPrivilegeDataSource, 'create').mockResolvedValue(1) + + const result = await privilegeRepository.createPrivileges(privilege) + + expect(mockPrivilegeDataSource.create).toBeCalledTimes(2) + expect(mockPrivilegeDataSource.create).toHaveBeenNthCalledWith(1, privilegesRequestCreation_WithMemberAndManager[0]) + expect(mockPrivilegeDataSource.create).toHaveBeenNthCalledWith(2, privilegesRequestCreation_WithMemberAndManager[1]) + + expect(result).toBe(2) + }); + test("Should return 0 if no privilege is created", async () => { + const privilege: PublicPrivilege = publicPrivileges_WithMemberAndManager + + jest.spyOn(mockPrivilegeDataSource, 'create').mockImplementation(() => Promise.reject(new Error("Error"))) + + const result = await privilegeRepository.createPrivileges(privilege) + + expect(mockPrivilegeDataSource.create).toBeCalledTimes(2) + expect(mockPrivilegeDataSource.create).toHaveBeenNthCalledWith(1, privilegesRequestCreation_WithMemberAndManager[0]) + expect(mockPrivilegeDataSource.create).toHaveBeenNthCalledWith(2, privilegesRequestCreation_WithMemberAndManager[1]) + + expect(result).toBe(0) + }); + }); + + describe("GetPublicPrivileges", () => { + test("Should return public privileges", async () => { + const all_projects: SearchResult = { total: 2, items: privilegesResponse_WithMemberAndManager } + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(all_projects) + + const result = await privilegeRepository.getPublicPrivileges({ project_id: 1 }) + + expect(result).toStrictEqual(publicPrivilegesResponse_WithMemberAndManager) + }); + }); + describe("GetProjectsByUser", () => { + test("Should return projects by user", async () => { + const projects_ids: number[] = [1] + const privileges: SearchResult = { total: 2, items: [privilegesResponse_WithMemberAndManager[0]] } + const privilege = { user_id: 1 } + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByUser(privilege) + + expect(result).toStrictEqual(projects_ids) + }); + test("Should return empty array if no project is found", async () => { + const projects_ids: number[] = [] + const privileges: SearchResult = { total: 0, items: [] } + const privilege = { user_id: 1 } + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByUser(privilege) + + expect(result).toStrictEqual(projects_ids) + }); + }); + describe("GetProjectsByUsers", () => { + test("Should return projects by users", async () => { + const projects_ids: number[] = [1] + const privileges: SearchResult = { total: 2, items: privilegesResponse_WithMemberAndManager } + const privilege_users = [1, 2] + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByUsers(privilege_users) + + expect(result).toStrictEqual(projects_ids) + }); + test("Should return empty array if no project is found", async () => { + const projects_ids: number[] = [] + const privileges: SearchResult = { total: 0, items: [] } + const privilege_users = [1, 2] + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByUsers(privilege_users) + + expect(result).toStrictEqual(projects_ids) + }); + }); + describe("GetProjectsByContacts", () => { + test("Should return all projects where a list of user ids are contact", async () => { + const projects_ids: number[] = [1] + const privileges: SearchResult = { total: 1, items: [privilegesResponse_WithMemberAndManager[1]] } + const privilege_contacts = [1, 2] + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByContacts(privilege_contacts) + + expect(result).toStrictEqual(projects_ids) + }); + test("Should return empty array if no project is found", async () => { + const projects_ids: number[] = [] + const privileges: SearchResult = { total: 0, items: [] } + const privilege_contacts = [2] + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByContacts(privilege_contacts) + + expect(result).toStrictEqual(projects_ids) + }); + }); + describe("GetProjectsByManagers", () => { + test("Should return all projects where a list of user ids are managers", async () => { + const projects_ids: number[] = [1] + const privileges: SearchResult = { total: 1, items: [privilegesResponse_WithMemberAndManager[0]] } + const privilege_managers = [1, 2] + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByManagers(privilege_managers) + + expect(result).toStrictEqual(projects_ids) + }); + test("Should return empty array if no project is found", async () => { + const projects_ids: number[] = [] + const privileges: SearchResult = { total: 0, items: [] } + const privilege_managers = [2] + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByManagers(privilege_managers) + + expect(result).toStrictEqual(projects_ids) + }); + }); + describe("GetProjectsByMembers", () => { + test("Should return all projects where a list of user ids are members", async () => { + const projects_ids: number[] = [1] + const privileges: SearchResult = { total: 1, items: [privilegesResponse_WithMemberAndManager[1]] } + const privilege_members = [2] + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByMembers(privilege_members) + + expect(result).toStrictEqual(projects_ids) + }); + test("Should return empty array if no project is found", async () => { + const projects_ids: number[] = [] + const privileges: SearchResult = { total: 0, items: [] } + const privilege_members = [1] + + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue(privileges) + + const result = await privilegeRepository.getProjectsByMembers(privilege_members) + + expect(result).toStrictEqual(projects_ids) + }); + }); + + describe("IsGranted", () => { + test("Should return true if privilege is granted", async () => { + const privilege = { user_id: 1, project_id: 1 } + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue({ total: 1, items: [privilegesResponse_WithMemberAndManager[0]] }) + + const result = await privilegeRepository.isGranted(privilege) + + expect(result).toBe(true) + }); + test("Should return false if privilege is not granted", async () => { + const privilege = { user_id: 1, project_id: 1 } + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue({ total: 0, items: [] }) + + const result = await privilegeRepository.isGranted(privilege) + + expect(result).toBe(false) + }); + test("Please provide a valid user_id and project_id to check if a privilege is granted for a project and a user", async () => { + const privilege = { user_id: 1 } + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue({ total: 0, items: [] }) + + try { + await privilegeRepository.isGranted(privilege) + expect(true).toBe(false) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("Please provide a valid user_id and project_id to check if a privilege is granted for a project and a user") + } + }); + }); + describe("IsManager", () => { + test("Should return true if user is manager", async () => { + const privilege = { user_id: 1, project_id: 1 } + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue({ total: 1, items: [privilegesResponse_WithMemberAndManager[0]] }) + + const result = await privilegeRepository.isManager(privilege) + + expect(result).toBe(true) + }); + test("Should return false if user is not manager", async () => { + const privilege = { user_id: 1, project_id: 1 } + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue({ total: 0, items: [] }) + + const result = await privilegeRepository.isManager(privilege) + + expect(result).toBe(false) + }); + test("Please provide a valid user_id and project_id to check if a user is a manager for a project", async () => { + const privilege = { user_id: 1 } + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue({ total: 0, items: [] }) + + try { + await privilegeRepository.isManager(privilege) + expect(true).toBe(false) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("Please provide a valid user_id and project_id to check if a user is a manager for a project") + } + }); + }); + describe("GetContact", () => { + test("Should return contact", async () => { + const project_request = { project_id: 1 } + const contact = privilegesResponse_WithMemberAndManager[0] + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue({ total: 1, items: [privilegesResponse_WithMemberAndManager[0]] }) + + const result = await privilegeRepository.getContact(project_request) + + expect(result).toStrictEqual(contact) + }); + test("Should return null if no contact is found", async () => { + const project_request = { project_id: 1 } + jest.spyOn(mockPrivilegeDataSource, 'getAll').mockResolvedValue({ total: 0, items: [] }) + try { + await privilegeRepository.getContact(project_request) + expect(true).toBe(false) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("No contact found for this project") + } + + }); + }); + describe("DeletePrivileges", () => { + test("Should delete privileges", async () => { + const privilege = { project_id: 1 } + jest.spyOn(mockPrivilegeDataSource, 'deleteAll').mockResolvedValue(1) + + const result = await privilegeRepository.deletePrivileges(privilege) + + expect(mockPrivilegeDataSource.deleteAll).toBeCalledWith(privilege) + expect(result).toBe(1) + }); + test("Should return 0 if no privilege is deleted", async () => { + const privilege = { project_id: 1 } + jest.spyOn(mockPrivilegeDataSource, 'deleteAll').mockResolvedValue(0) + + const result = await privilegeRepository.deletePrivileges(privilege) + + expect(mockPrivilegeDataSource.deleteAll).toBeCalledWith(privilege) + expect(result).toBe(0) + }); + test("Should throw an error if no valid parameter is provided", async () => { + const privilege = { privilege_name: "manager" } + jest.spyOn(mockPrivilegeDataSource, 'deleteAll').mockResolvedValue(0) + + try { + await privilegeRepository.deletePrivileges(privilege) + expect(true).toBe(false) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("Please provide at least one valid parameter to delete privilege") + } + }); + }); + describe("EnsurePrivilegeCoherence", () => { + test("Should return true if privileges are coherent", async () => { + + try { + privilegeRepository.ensurePrivilegeCoherence(coherentPrivileges) + } catch (e) { + expect(true).toBe(false) + } + }); + test("Contact user must be either in members or managers", async () => { + const privilege = privileges_WithContactNetherManagerNorMember + + try { + privilegeRepository.ensurePrivilegeCoherence(privilege) + expect(true).toBe(false) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("Contact user must be either in members or managers") + } + }); + test("At least one user must be a manager", async () => { + const privilege = privileges_WithNoManager + + try { + privilegeRepository.ensurePrivilegeCoherence(privilege) + expect(true).toBe(false) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("At least one user must be a manager") + } + }); + test("A user cannot be both a member and a manager", async () => { + const privilege = privileges_WithOneUserMemberAndManager + + try { + privilegeRepository.ensurePrivilegeCoherence(privilege) + expect(true).toBe(false) + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("A user cannot be both a member and a manager") + } + }); + }); +}) diff --git a/test/domain/repositories/project-repository.test.ts b/test/domain/repositories/project-repository.test.ts index d9299a6..160e1bf 100644 --- a/test/domain/repositories/project-repository.test.ts +++ b/test/domain/repositories/project-repository.test.ts @@ -4,7 +4,9 @@ import { ProjectRequestCreationModel, ProjectRequestModel, ProjectResponseModel, import { SearchResult } from "../../../src/domain/entities/search"; import { ProjectRepository } from "../../../src/domain/interfaces/repositories/project-repository"; import { ProjectRepositoryImpl } from "../../../src/domain/repositories/project-repository"; -import { privateProjectUpdateModel, projectRequestCreationModelForRepository, projectResponseModel, projectResponseModelArray, projectUpdateModel_withBadData } from "../../entities/project"; +import { instrument_model_response } from "../../entities/instrumentModel"; +import { publicPrivileges_WithMemberAndManager } from "../../entities/privilege"; +import { privateProjectUpdateModel, projectRequestCreationModel, projectRequestCreationModelForRepository, projectResponseModel, projectResponseModelArray, projectUpdateModel_withBadData } from "../../entities/project"; import { MockProjectDataSource } from "../../mocks/project-mock"; import 'dotenv/config' @@ -232,5 +234,17 @@ describe("Project Repository", () => { }) + describe("formatProjectRequestCreationModel", () => { + test("Should format project request creation model", () => { + const result = projectRepository.formatProjectRequestCreationModel(projectRequestCreationModel, instrument_model_response) + expect(result).toStrictEqual(projectRequestCreationModelForRepository) + }); + }); + describe("toPublicProject", () => { + test("Should return public project", () => { + const result = projectRepository.toPublicProject(projectResponseModel, publicPrivileges_WithMemberAndManager) + expect(result).toStrictEqual(projectResponseModel) + }); + }); }) diff --git a/test/domain/repositories/search-repository.test.ts b/test/domain/repositories/search-repository.test.ts index 976f072..515b715 100644 --- a/test/domain/repositories/search-repository.test.ts +++ b/test/domain/repositories/search-repository.test.ts @@ -1,5 +1,6 @@ import { SearchRepository } from "../../../src/domain/interfaces/repositories/search-repository"; import { SearchRepositoryImpl } from "../../../src/domain/repositories/search-repository"; +import { SearchOptions } from "../../../src/domain/entities/search"; describe("Search Repository", () => { @@ -9,6 +10,48 @@ describe("Search Repository", () => { jest.clearAllMocks(); searchRepository = new SearchRepositoryImpl() }) + describe("formatSearchInfo", () => { + test("Should return formatted search info", () => { + const result = { + total: 100, + items: ["item1", "item2"] + } + const options: SearchOptions = { + limit: 2, + page: 1, + sort_by: [], + } + const expected_search_info = { + total: 100, + limit: 2, + total_on_page: 2, + page: 1, + pages: 50 + } + const search_info = searchRepository.formatSearchInfo(result, options) + expect(search_info).toStrictEqual(expected_search_info) + }); + test("Should return formatted search info with default page and limit when no result", () => { + const result = { + total: 0, + items: [] + } + const options: SearchOptions = { + limit: 2, + page: 1, + sort_by: [], + } + const expected_search_info = { + total: 0, + limit: 2, + total_on_page: 0, + page: 1, + pages: 1 + } + const search_info = searchRepository.formatSearchInfo(result, options) + expect(search_info).toStrictEqual(expected_search_info) + }); + }); describe("formatSortBy", () => { test("Should return prepared sort by", () => { diff --git a/test/domain/repositories/user-repository.test.ts b/test/domain/repositories/user-repository.test.ts index 87188be..939f6ac 100644 --- a/test/domain/repositories/user-repository.test.ts +++ b/test/domain/repositories/user-repository.test.ts @@ -10,6 +10,7 @@ import { JwtAdapter } from "../../../src/infra/auth/jsonwebtoken" import 'dotenv/config' import { JwtPayload } from "jsonwebtoken"; import { decodedToken } from "../../entities/auth"; +import { deletedUser, unvalidUser, validUser } from "../../entities/user"; class MockUserDataSource implements UserDataSource { deleteOne(): void { @@ -865,6 +866,82 @@ describe("User Repository", () => { }); }); + describe("ensureUserCanBeUsed", () => { + test("Should run without error", async () => { + jest.spyOn(mockUserDataSource, "getOne").mockImplementation(() => Promise.resolve(validUser)) + try { + await userRepository.ensureUserCanBeUsed(1); + } catch (e) { + expect(true).toBe(false) + } + }); + test("Should throw error if user is deleted", async () => { + jest.spyOn(mockUserDataSource, "getOne").mockImplementation(() => Promise.resolve(deletedUser)) + try { + await userRepository.ensureUserCanBeUsed(1); + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("User cannot be used") + } + }); + test("Should throw error if user is unvalid", async () => { + jest.spyOn(mockUserDataSource, "getOne").mockImplementation(() => Promise.resolve(unvalidUser)) + try { + await userRepository.ensureUserCanBeUsed(1); + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("User cannot be used") + } + }); + }); + describe("ensureTypedUserCanBeUsed", () => { + test("Should run without error", async () => { + jest.spyOn(mockUserDataSource, "getOne").mockImplementation(() => Promise.resolve(validUser)) + try { + await userRepository.ensureTypedUserCanBeUsed(1, "admin"); + } catch (e) { + expect(true).toBe(false) + } + }); + test("Should throw error if user is deleted", async () => { + jest.spyOn(mockUserDataSource, "getOne").mockImplementation(() => Promise.resolve(deletedUser)) + try { + await userRepository.ensureTypedUserCanBeUsed(1, "member"); + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("member with ID 1 cannot be used: User cannot be used") + } + }); + test("Should throw error if user is unvalid", async () => { + jest.spyOn(mockUserDataSource, "getOne").mockImplementation(() => Promise.resolve(unvalidUser)) + try { + await userRepository.ensureTypedUserCanBeUsed(1, "manager"); + } catch (e) { + expect(e).toBeInstanceOf(Error) + expect(e.message).toBe("manager with ID 1 cannot be used: User cannot be used") + } + }); + }); + describe("isDeleted", () => { + test("Should return true for a deleted user", async () => { + const result = await userRepository.isDeleted(deletedUser); + expect(result).toBe(true) + }); + test("Should return false for a non deleted user", async () => { + const result = await userRepository.isDeleted(validUser); + expect(result).toBe(false) + }); + }); + describe("isValidated", () => { + test("Should return true for a validated user", async () => { + const result = await userRepository.isValidated(validUser); + expect(result).toBe(true) + }); + test("Should return false for a non validated user", async () => { + const result = await userRepository.isValidated(unvalidUser); + expect(result).toBe(false) + }); + }); describe("DeleteUser", () => { test("user deletion is a sucess", async () => { diff --git a/test/domain/use-cases/auth/login.test.ts b/test/domain/use-cases/auth/login.test.ts index 999ba50..9b68b64 100644 --- a/test/domain/use-cases/auth/login.test.ts +++ b/test/domain/use-cases/auth/login.test.ts @@ -115,7 +115,6 @@ describe("Create User Use Case", () => { const loginUserUseCase = new LoginUser(mockUserRepository, mockAuthRepository) try { const result = await loginUserUseCase.execute(InputData); - // Should not go there expect(result).toBe(true); } catch (err) { expect(err.message).toBe("User cannot be used"); @@ -135,7 +134,6 @@ describe("Create User Use Case", () => { const loginUserUseCase = new LoginUser(mockUserRepository, mockAuthRepository) try { const result = await loginUserUseCase.execute(InputData); - // Should not go there expect(result).toBe(true); } catch (err) { expect(err.message).toBe("Cannot find user"); @@ -168,10 +166,43 @@ describe("Create User Use Case", () => { const loginUserUseCase = new LoginUser(mockUserRepository, mockAuthRepository) try { const result = await loginUserUseCase.execute(InputData); - // Should not go there expect(result).toBe(true); } catch (err) { expect(err.message).toBe("User cannot be used"); } }); + describe("Login with unverified user", () => { + test("Should handle unverified email and throw error", async () => { + const InputData: AuthUserCredentialsModel = { + email: "test@email.com", + password: "good_password" + } + const OutputUserData: UserResponseModel = { + user_id: 1, + last_name: "Smith", + first_name: "John", + email: "john@gmail.com", + is_admin: false, + valid_email: false, + organisation: "LOV", + country: "France", + user_planned_usage: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + user_creation_date: '2023-08-01 10:30:00' + } + + jest.spyOn(mockUserRepository, "verifyUserLogin").mockImplementation(() => Promise.resolve(true)) + jest.spyOn(mockUserRepository, "getUser").mockImplementation(() => Promise.resolve(OutputUserData)) + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockAuthRepository, "generateAccessToken").mockImplementation(() => { return "access_token" }) + jest.spyOn(mockAuthRepository, "generateRefreshToken").mockImplementation(() => { return "refresh_token" }) + const loginUserUseCase = new LoginUser(mockUserRepository, mockAuthRepository) + try { + await loginUserUseCase.execute(InputData); + expect(false).toBe(true); + } catch (err) { + expect(err.message).toBe("User email not verified"); + } + }); + }); + }) diff --git a/test/domain/use-cases/project/create-project.test.ts b/test/domain/use-cases/project/create-project.test.ts index 9885ece..ed96795 100644 --- a/test/domain/use-cases/project/create-project.test.ts +++ b/test/domain/use-cases/project/create-project.test.ts @@ -8,7 +8,7 @@ import { ProjectResponseModel, PublicProjectRequestCreationModel } from "../../. import { MockInstrumentModelRepository } from "../../../mocks/instrumentModel-mock"; import { MockPrivilegeRepository } from "../../../mocks/privilege-mock"; import { instrument_model_response } from "../../../entities/instrumentModel"; -import { publicPrivileges } from "../../../entities/privilege"; +import { publicPrivileges, publicPrivileges_WithMemberAndManager } from "../../../entities/privilege"; let mockUserRepository: UserRepository; let mockProjectRepository: MockProjectRepository; @@ -38,8 +38,8 @@ test("Try to add a project return created project", async () => { jest.spyOn(mockUserRepository, "ensureTypedUserCanBeUsed").mockImplementation(() => Promise.resolve()) jest.spyOn(mockPrivilegeRepository, "ensurePrivilegeCoherence").mockImplementation(() => Promise.resolve()) jest.spyOn(mockProjectRepository, "formatProjectRequestCreationModel").mockImplementation(() => projectRequestCreationModelForRepository) - jest.spyOn(mockPrivilegeRepository, "createPrivileges").mockImplementation(() => Promise.resolve(1)) - jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockPrivilegeRepository, "createPrivileges").mockImplementation(() => Promise.resolve(2)) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges_WithMemberAndManager)) jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementation(() => projectResponseModel) const createProjectUseCase = new CreateProject(mockUserRepository, mockProjectRepository, mockInstrumentModelRepository, mockPrivilegeRepository) @@ -69,8 +69,8 @@ test("Create a project without override_depth_offset", async () => { jest.spyOn(mockUserRepository, "ensureTypedUserCanBeUsed").mockImplementation(() => Promise.resolve()) jest.spyOn(mockPrivilegeRepository, "ensurePrivilegeCoherence").mockImplementation(() => Promise.resolve()) jest.spyOn(mockProjectRepository, "formatProjectRequestCreationModel").mockImplementation(() => projectRequestCreationModelForRepository) - jest.spyOn(mockPrivilegeRepository, "createPrivileges").mockImplementation(() => Promise.resolve(1)) - jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockPrivilegeRepository, "createPrivileges").mockImplementation(() => Promise.resolve(2)) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges_WithMemberAndManager)) jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementation(() => projectResponseModel) @@ -131,3 +131,61 @@ test("Cannot create project because user is deleted", async () => { expect(mockProjectRepository.getProject).not.toBeCalled(); }); + +test("Create project but something went wrong during privilege creation", async () => { + const InputData: PublicProjectRequestCreationModel = projectRequestCreationModel + const current_user: UserUpdateModel = { + user_id: 1 + } + const outputError = new Error("Privileges partially created, please check members, managers and contact") + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementationOnce(() => Promise.resolve()) + jest.spyOn(mockProjectRepository, "computeDefaultDepthOffset") + jest.spyOn(mockProjectRepository, "createProject").mockImplementation(() => Promise.resolve(1)) + jest.spyOn(mockProjectRepository, "getProject").mockImplementation(() => Promise.resolve(projectResponseModel)) + jest.spyOn(mockInstrumentModelRepository, "getInstrumentByName").mockImplementation(() => Promise.resolve(instrument_model_response)) + jest.spyOn(mockUserRepository, "ensureTypedUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "ensurePrivilegeCoherence").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockProjectRepository, "formatProjectRequestCreationModel").mockImplementation(() => projectRequestCreationModelForRepository) + jest.spyOn(mockPrivilegeRepository, "createPrivileges").mockImplementation(() => Promise.resolve(0)) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementation(() => projectResponseModel) + + const createProjectUseCase = new CreateProject(mockUserRepository, mockProjectRepository, mockInstrumentModelRepository, mockPrivilegeRepository) + + await expect(createProjectUseCase.execute(current_user, InputData)).rejects.toThrowError(outputError); + + + expect(mockUserRepository.ensureUserCanBeUsed).toHaveBeenCalledWith(current_user.user_id); + expect(mockProjectRepository.computeDefaultDepthOffset).not.toBeCalled(); + expect(mockProjectRepository.createProject).toHaveBeenCalledWith(projectRequestCreationModelForRepository); + expect(mockProjectRepository.getProject).toHaveBeenCalledWith({ project_id: 1 }); +}); +test("Create project but something went wrong when fetching created privileges", async () => { + const InputData: PublicProjectRequestCreationModel = projectRequestCreationModel + const current_user: UserUpdateModel = { + user_id: 1 + } + const outputError = new Error("Cant find created privileges, please check members, managers and contact") + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementationOnce(() => Promise.resolve()) + jest.spyOn(mockProjectRepository, "computeDefaultDepthOffset") + jest.spyOn(mockProjectRepository, "createProject").mockImplementation(() => Promise.resolve(1)) + jest.spyOn(mockProjectRepository, "getProject").mockImplementation(() => Promise.resolve(projectResponseModel)) + jest.spyOn(mockInstrumentModelRepository, "getInstrumentByName").mockImplementation(() => Promise.resolve(instrument_model_response)) + jest.spyOn(mockUserRepository, "ensureTypedUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "ensurePrivilegeCoherence").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockProjectRepository, "formatProjectRequestCreationModel").mockImplementation(() => projectRequestCreationModelForRepository) + jest.spyOn(mockPrivilegeRepository, "createPrivileges").mockImplementation(() => Promise.resolve(2)) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementation(() => projectResponseModel) + + const createProjectUseCase = new CreateProject(mockUserRepository, mockProjectRepository, mockInstrumentModelRepository, mockPrivilegeRepository) + + await expect(createProjectUseCase.execute(current_user, InputData)).rejects.toThrowError(outputError); + + expect(mockUserRepository.ensureUserCanBeUsed).toHaveBeenCalledWith(current_user.user_id); + expect(mockProjectRepository.computeDefaultDepthOffset).not.toBeCalled(); + expect(mockProjectRepository.createProject).toHaveBeenCalledWith(projectRequestCreationModelForRepository); + expect(mockProjectRepository.getProject).toHaveBeenCalledWith({ project_id: 1 }); +}); \ No newline at end of file diff --git a/test/domain/use-cases/project/delete-project.test.ts b/test/domain/use-cases/project/delete-project.test.ts index 83ddf55..e9ed931 100644 --- a/test/domain/use-cases/project/delete-project.test.ts +++ b/test/domain/use-cases/project/delete-project.test.ts @@ -158,6 +158,31 @@ describe("Delete Project Use Case", () => { expect(mockUserRepository.isAdmin).toBeCalledWith(current_user.user_id); expect(mockProjectRepository.deleteProject).toBeCalledWith(project_to_delete); }); + test("User is not admin and not manager", async () => { + const current_user: UserUpdateModel = { + user_id: 1 + } + const project_to_delete: ProjectUpdateModel = { + project_id: 1 + } + const preexistent_project: ProjectResponseModel = projectResponseModel + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockProjectRepository, "getProject").mockImplementation(() => Promise.resolve(preexistent_project)) + jest.spyOn(mockPrivilegeRepository, "isManager").mockImplementation(() => Promise.resolve(false)) + jest.spyOn(mockUserRepository, "isAdmin").mockImplementation(() => Promise.resolve(false)) + jest.spyOn(mockProjectRepository, "deleteProject").mockImplementation(() => Promise.resolve(1)) + const deleteProjectUseCase = new DeleteProject(mockUserRepository, mockProjectRepository, mockPrivilegeRepository) + try { + await deleteProjectUseCase.execute(current_user, project_to_delete); + } catch (err) { + expect(err.message).toBe("Logged user cannot delete this project"); + } + + expect(mockProjectRepository.getProject).toBeCalledWith(project_to_delete); + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(current_user.user_id); + expect(mockUserRepository.isAdmin).toBeCalledWith(current_user.user_id); + expect(mockProjectRepository.deleteProject).not.toBeCalled(); + }); }) \ No newline at end of file diff --git a/test/domain/use-cases/project/search-project.test.ts b/test/domain/use-cases/project/search-project.test.ts index 7fadcb9..8b4c093 100644 --- a/test/domain/use-cases/project/search-project.test.ts +++ b/test/domain/use-cases/project/search-project.test.ts @@ -12,6 +12,7 @@ import { projectResponseModel, projectResponseModel2, projectResponseModelArray import { MockInstrumentModelRepository } from "../../../mocks/instrumentModel-mock"; import { MockPrivilegeRepository } from "../../../mocks/privilege-mock"; import { publicPrivileges } from "../../../entities/privilege"; +import { instrument_model_response } from "../../../entities/instrumentModel"; let mockUserRepository: UserRepository; let mockSearchRepository: SearchRepository; @@ -177,4 +178,402 @@ test("No data to return", async () => { expect(mockProjectRepository.standardGetProjects).toBeCalledWith({ filter: [], limit: 10, page: 1, sort_by: [] }) expect(result).toStrictEqual(expectedResponse) -}); \ No newline at end of file +}); +test("Should return data for user with filter on instrument model", async () => { + + const ExpectedResult = { + items: projectResponseModelArray, + total: 2 + } + const expectedResponse = { + projects: projectResponseModelArray, + search_info: { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + } + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filters: FilterSearchOptions[] = [{ field: "instrument_model", operator: "=", value: "UVP5HD" }] + const search_info = { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + const filters_IN = { field: "instrument_model", operator: "IN", value: [1] } + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve(ExpectedResult)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementationOnce(() => projectResponseModel).mockImplementationOnce(() => projectResponseModel2) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockInstrumentModelRepository, "standardGetInstrumentModels").mockImplementation(() => Promise.resolve({ items: [instrument_model_response], total: 1 })) + + const result = await searchProjectUseCase.execute(current_user, options, filters); + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith([filters_IN]) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).toBeCalledWith({ filter: [filters_IN], limit: 10, page: 1, sort_by: [], }) + + expect(result).toStrictEqual(expectedResponse) +}); +test("Should return Instrument model not found with filter on unexisting instrument model", async () => { + + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filters: FilterSearchOptions[] = [{ field: "instrument_model", operator: "=", value: "UVP0" }] + const search_info = { total: 0, limit: 10, total_on_page: 0, page: 1, pages: 0 } + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve({ items: [], total: 0 })) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockInstrumentModelRepository, "standardGetInstrumentModels").mockImplementation(() => Promise.resolve({ items: [], total: 0 })) + + await expect(searchProjectUseCase.execute(current_user, options, filters)).rejects.toThrow(new Error("Instrument model not found")) + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith(filters) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).not.toBeCalled() +}); + +test("Should return data for user with filter on managing = true", async () => { + const ExpectedResult = { + items: projectResponseModelArray, + total: 2 + } + const expectedResponse = { + projects: projectResponseModelArray, + search_info: { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + } + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filter = { field: "for_managing", operator: "=", value: true } + const filters: FilterSearchOptions[] = [filter] + const search_info = { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + const projectIds = [1, 2] + const filters_IN = [{ field: "project_id", operator: "IN", value: projectIds }] + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve(ExpectedResult)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementationOnce(() => projectResponseModel).mockImplementationOnce(() => projectResponseModel2) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockPrivilegeRepository, "getProjectsByUser").mockImplementation(() => Promise.resolve(projectIds)) + const result = await searchProjectUseCase.execute(current_user, options, filters); + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith(filters) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).toBeCalledWith({ filter: filters_IN, limit: 10, page: 1, sort_by: [], }) + + expect(result).toStrictEqual(expectedResponse) +}); +test("Should return data for user with filter on managing = false", async () => { + const ExpectedResult = { + items: projectResponseModelArray, + total: 2 + } + const expectedResponse = { + projects: projectResponseModelArray, + search_info: { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + } + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filter = { field: "for_managing", operator: "=", value: false } + const filters: FilterSearchOptions[] = [filter] + const search_info = { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve(ExpectedResult)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementationOnce(() => projectResponseModel).mockImplementationOnce(() => projectResponseModel2) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockPrivilegeRepository, "getProjectsByUser").mockImplementation(() => Promise.resolve([])) + const result = await searchProjectUseCase.execute(current_user, options, filters); + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith(filters) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).toBeCalledWith({ filter: [], limit: 10, page: 1, sort_by: [], }) + + expect(result).toStrictEqual(expectedResponse) +}); +test("Should return data for user with filter on contact", async () => { + const ExpectedResult = { + items: projectResponseModelArray, + total: 2 + } + const expectedResponse = { + projects: projectResponseModelArray, + search_info: { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + } + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filter = { field: "contact", operator: "=", value: 1 } + const filters: FilterSearchOptions[] = [filter] + const search_info = { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + const projectIds = [1, 2] + const filters_IN = [{ field: "project_id", operator: "IN", value: projectIds }] + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve(ExpectedResult)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementationOnce(() => projectResponseModel).mockImplementationOnce(() => projectResponseModel2) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockPrivilegeRepository, "getProjectsByContacts").mockImplementation(() => Promise.resolve(projectIds)) + const result = await searchProjectUseCase.execute(current_user, options, filters); + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith(filters) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).toBeCalledWith({ + filter: filters_IN, limit: 10, page: 1, sort_by: [], + }) + expect(result).toStrictEqual(expectedResponse) + +}); +test("Should return data for user with filter on user-based filters such as granted_users", async () => { + const ExpectedResult = { + items: projectResponseModelArray, + total: 2 + } + const expectedResponse = { + projects: projectResponseModelArray, + search_info: { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + } + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filters: FilterSearchOptions[] = [{ field: "granted_users", operator: "IN", value: [1, 2] }] + const search_info = { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + const projectIds = [1, 2] + const filters_IN = [{ field: "project_id", operator: "IN", value: projectIds }] + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve(ExpectedResult)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementationOnce(() => projectResponseModel).mockImplementationOnce(() => projectResponseModel2) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockPrivilegeRepository, "getProjectsByUsers").mockImplementation(() => Promise.resolve(projectIds)) + const result = await searchProjectUseCase.execute(current_user, options, filters); + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith(filters) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).toBeCalledWith({ + filter: filters_IN, limit: 10, page: 1, sort_by: [], + }) + + expect(result).toStrictEqual(expectedResponse) +}); +test("Should return data for user with filter on user-based filters such as managers, members", async () => { + const ExpectedResult = { + items: projectResponseModelArray, + total: 2 + } + const expectedResponse = { + projects: projectResponseModelArray, + search_info: { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + } + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filters: FilterSearchOptions[] = [{ field: "managers", operator: "=", value: 1 }, { field: "members", operator: "=", value: 2 }] + const search_info = { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + const projectIds = [1, 2] + const projectIds2 = [2, 4] + const filters_IN = [{ field: "project_id", operator: "IN", value: projectIds }, { field: "project_id", operator: "IN", value: projectIds2 }] + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve(ExpectedResult)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementationOnce(() => projectResponseModel).mockImplementationOnce(() => projectResponseModel2) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockPrivilegeRepository, "getProjectsByManagers").mockImplementation(() => Promise.resolve(projectIds)) + jest.spyOn(mockPrivilegeRepository, "getProjectsByMembers").mockImplementation(() => Promise.resolve(projectIds2)) + const result = await searchProjectUseCase.execute(current_user, options, filters); + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith(filters) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).toBeCalledWith({ + filter: filters_IN, limit: 10, page: 1, sort_by: [], + }) + + expect(result).toStrictEqual(expectedResponse) +}); +test("Should return error if filter is not valid : operator IN and not an array of numbers", async () => { + const ExpectedResult = { + items: projectResponseModelArray, + total: 2 + } + + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filter = { field: "contact", operator: "IN", value: ["julie", "lena"] } + const filters: FilterSearchOptions[] = [filter] + const search_info = { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + const projectIds = [1, 2] + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve(ExpectedResult)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementationOnce(() => projectResponseModel).mockImplementationOnce(() => projectResponseModel2) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockPrivilegeRepository, "getProjectsByContacts").mockImplementation(() => Promise.resolve(projectIds)) + + await expect(searchProjectUseCase.execute(current_user, options, filters)).rejects.toThrow(new Error("contact should be an array of numbers")) + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith(filters) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).not.toBeCalled() +}); +test("Should return error if filter is not valid : operator = and not a number", async () => { + const ExpectedResult = { + items: projectResponseModelArray, + total: 2 + } + + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filter = { field: "contact", operator: "=", value: "contact" } + const filters: FilterSearchOptions[] = [filter] + const search_info = { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + const projectIds = [1, 2] + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve(ExpectedResult)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementationOnce(() => projectResponseModel).mockImplementationOnce(() => projectResponseModel2) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockPrivilegeRepository, "getProjectsByContacts").mockImplementation(() => Promise.resolve(projectIds)) + + await expect(searchProjectUseCase.execute(current_user, options, filters)).rejects.toThrow(new Error("contact should be a number")) + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith(filters) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).not.toBeCalled() +}); +test("Should return error if filter is not valid : operator different of = or IN", async () => { + const ExpectedResult = { + items: projectResponseModelArray, + total: 2 + } + + const current_user: UserUpdateModel = { + user_id: 1, + } + + const options = { + page: 1, + limit: 10, + sort_by: [] + } + const filter = { field: "contact", operator: "LIKE", value: "%contact" } + const filters: FilterSearchOptions[] = [filter] + const search_info = { total: 2, limit: 10, total_on_page: 2, page: 1, pages: 1 } + const projectIds = [1, 2] + + jest.spyOn(mockUserRepository, "ensureUserCanBeUsed").mockImplementation(() => Promise.resolve()) + jest.spyOn(mockPrivilegeRepository, "getPublicPrivileges").mockImplementation(() => Promise.resolve(publicPrivileges)) + jest.spyOn(mockSearchRepository, "formatFilters").mockImplementation(() => { return filters }) + jest.spyOn(mockSearchRepository, "formatSortBy").mockImplementation(() => { return [] }) + jest.spyOn(mockProjectRepository, "standardGetProjects").mockImplementation(() => Promise.resolve(ExpectedResult)) + jest.spyOn(mockProjectRepository, "toPublicProject").mockImplementationOnce(() => projectResponseModel).mockImplementationOnce(() => projectResponseModel2) + jest.spyOn(mockSearchRepository, "formatSearchInfo").mockImplementation(() => { return search_info }) + jest.spyOn(mockPrivilegeRepository, "getProjectsByContacts").mockImplementation(() => Promise.resolve(projectIds)) + + await expect(searchProjectUseCase.execute(current_user, options, filters)).rejects.toThrow(new Error("contact should be an array of numbers or a number")) + + // expect functions ahve been called with + expect(mockUserRepository.ensureUserCanBeUsed).toBeCalledWith(1) + expect(mockSearchRepository.formatFilters).toBeCalledWith(filters) + expect(mockSearchRepository.formatSortBy).toBeCalledWith([]) + expect(mockProjectRepository.standardGetProjects).not.toBeCalled() +}); diff --git a/test/entities/instrumentModel.ts b/test/entities/instrumentModel.ts index f97d7f6..9313cee 100644 --- a/test/entities/instrumentModel.ts +++ b/test/entities/instrumentModel.ts @@ -1,11 +1,31 @@ // define an example of project entities to use in the tests -import { InstrumentModelResponseModel } from "../../src/domain/entities/instrument_model" +import { InstrumentModelRequestCreationModel, InstrumentModelRequestModel, InstrumentModelResponseModel } from "../../src/domain/entities/instrument_model" export const instrument_model_response: InstrumentModelResponseModel = { instrument_model_id: 1, instrument_model_creation_date: '2023-08-01 10:30:00', instrument_model_name: "UVP5HD", bodc_url: "http://uvp5hd.com", +} +export const instrument_model_response_UVP6: InstrumentModelResponseModel = { + instrument_model_id: 2, + instrument_model_creation_date: '2024-08-01 10:30:00', + instrument_model_name: "UVP6HF", + bodc_url: "http://uvp6hf.com", +} +export const instrument_model_creation_UVP5HD: InstrumentModelRequestCreationModel = { + instrument_model_name: "UVP5HD", + bodc_url: "http://uvp5hd.com", +} +export const instrument_model_creation_UVP6HF: InstrumentModelRequestCreationModel = { + instrument_model_name: "UVP6HF", + bodc_url: "http://uvp6hf.com", +} +export const instrument_model_request_id: InstrumentModelRequestModel = { + instrument_model_id: 1, +} +export const instrument_model_request_name: InstrumentModelRequestModel = { + instrument_model_name: "UVP5HD", } \ No newline at end of file diff --git a/test/entities/privilege.ts b/test/entities/privilege.ts index 0f15fb6..5114b99 100644 --- a/test/entities/privilege.ts +++ b/test/entities/privilege.ts @@ -1,7 +1,7 @@ // define an example of project entities to use in the tests -import { PublicPrivilege } from "../../src/domain/entities/privilege" +import { PrivilegeRequestCreationModel, PrivilegeResponseModel, PublicPrivilege } from "../../src/domain/entities/privilege" import { MinimalUserModel } from "../../src/domain/entities/user" export const publicPrivileges: PublicPrivilege = { @@ -9,4 +9,95 @@ export const publicPrivileges: PublicPrivilege = { managers: [{ user_id: 1 } as MinimalUserModel], members: [], contact: { user_id: 1 } as MinimalUserModel +} +export const publicPrivileges_WithMemberAndManager: PublicPrivilege = { + project_id: 1, + managers: [{ user_id: 1 } as MinimalUserModel], + members: [{ user_id: 2 } as MinimalUserModel], + contact: { user_id: 1 } as MinimalUserModel +} +export const publicPrivilegesResponse_WithMemberAndManager: PublicPrivilege = { + project_id: 1, + managers: [{ + user_id: 1, + user_name: "user1", + email: "test", + }], + members: [{ + user_id: 2, + user_name: "user2", + email: "test", + }], + contact: { + user_id: 1, + user_name: "user1", + email: "test", + } +} + +export const privilegesResponse_WithMemberAndManager: PrivilegeResponseModel[] = [ + { + privilege_id: 1, + user_id: 1, + project_id: 1, + privilege_name: "manager", + contact: true, + user_name: "user1", + email: "test", + privilege_creation_date: "2021-01-01" + }, + { + privilege_id: 2, + user_id: 2, + project_id: 1, + privilege_name: "member", + contact: false, + user_name: "user2", + email: "test", + privilege_creation_date: "2021-01-01" + }] +export const privilegesRequestCreation_WithMemberAndManager: PrivilegeRequestCreationModel[] = [ + { + user_id: 1, + project_id: 1, + privilege_name: "manager", + contact: true + }, + { + user_id: 2, + project_id: 1, + privilege_name: "member", + contact: false + }] + +export const privileges_WithOneUserMemberAndManager: PublicPrivilege = +{ + project_id: 1, + managers: [{ user_id: 1 } as MinimalUserModel], + members: [{ user_id: 1 } as MinimalUserModel], + contact: { user_id: 1 } as MinimalUserModel +} + +export const privileges_WithContactNetherManagerNorMember: PublicPrivilege = +{ + project_id: 1, + managers: [{ user_id: 1 } as MinimalUserModel], + members: [{ user_id: 2 } as MinimalUserModel], + contact: { user_id: 3 } as MinimalUserModel +} + + +export const privileges_WithNoManager: PublicPrivilege = +{ + project_id: 1, + managers: [], + members: [{ user_id: 1 } as MinimalUserModel], + contact: { user_id: 1 } as MinimalUserModel +} + +export const coherentPrivileges: PublicPrivilege = { + project_id: 1, + managers: [{ user_id: 1 } as MinimalUserModel], + members: [{ user_id: 2 } as MinimalUserModel], + contact: { user_id: 1 } as MinimalUserModel } \ No newline at end of file diff --git a/test/entities/project.ts b/test/entities/project.ts index 704c15a..5e93f77 100644 --- a/test/entities/project.ts +++ b/test/entities/project.ts @@ -139,7 +139,6 @@ export const data_source_projectRequestCreationModel_3: ProjectRequestCreationMo operator_email: 'operator_email@email.fr', chief_scientist_name: 'chief_scientist_name', chief_scientist_email: 'chief_scientist_email@email.fr', - override_depth_offset: 1, enable_descent_filter: true, privacy_duration: 1, visible_duration: 1, @@ -415,6 +414,7 @@ export const projectResponseModel: PublicProjectResponseModel = { project_id: 1, project_creation_date: '2024-04-29 15:43:10' } + export const projectResponseModel2: PublicProjectResponseModel = { ...projectRequestCreationModel, project_id: 2, @@ -445,6 +445,7 @@ export const projectUpdateModel: PublicProjectUpdateModel = { export const privateProjectUpdateModel: ProjectUpdateModel = { operator_email: "edited_user@email.com", operator_name: "Edited name", + enable_descent_filter: true, project_id: 1 } @@ -453,5 +454,21 @@ export const projectUpdateModel_withBadData: ProjectUpdateModel = { unauthorized_param: "unauthorized_param" } -// define unvalid example of project entities to use in the tests +export const projectUpdateModel_withPrivilegeUpdate: PublicProjectUpdateModel = { + ...projectUpdateModel, + managers: [{ user_id: 2 } as MinimalUserModel], + members: [{ user_id: 3 } as MinimalUserModel], + contact: { user_id: 4 } as MinimalUserModel, +} + +export const projectUpdateModel_withInstrumentModel: PublicProjectUpdateModel = { + ...projectUpdateModel, + instrument_model: "UVP5HD" +} + +export const projectUpdateModel_withPartialPrivilegeUpdate: PublicProjectUpdateModel = { + ...projectUpdateModel, + managers: [{ user_id: 2 } as MinimalUserModel], + members: [{ user_id: 3 } as MinimalUserModel] +} \ No newline at end of file diff --git a/test/entities/user.ts b/test/entities/user.ts new file mode 100644 index 0000000..9bce513 --- /dev/null +++ b/test/entities/user.ts @@ -0,0 +1,60 @@ +import { UserRequestCreationModel, UserResponseModel } from "../../src/domain/entities/user"; + +export const userRequestCreationModel_1: UserRequestCreationModel = { + last_name: "Smith", + first_name: "John", + email: "john@gmail.com", + password: "test123!", + organisation: "LOV", + country: "France", + user_planned_usage: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." +} +export const userRequestCreationModel_2: UserRequestCreationModel = { + last_name: "Smith", + first_name: "John", + email: "johny@gmail.com", + password: "test123!", + organisation: "LOV", + country: "France", + user_planned_usage: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." +} + +export const validUser: UserResponseModel = { + user_id: 1, + last_name: "Smith", + first_name: "John", + email: "john@gmail.com", + valid_email: true, + is_admin: false, + organisation: "LOV", + country: "France", + user_planned_usage: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + user_creation_date: '2023-08-01 10:30:00' +} +export const deletedUser: UserResponseModel = { + user_id: 1, + last_name: "anonym_1", + first_name: "anonym_1", + email: "anonym_1", + valid_email: false, + confirmation_code: null, + is_admin: false, + organisation: "anonymized", + country: "anonymized", + user_planned_usage: "anonymized", + reset_password_code: null, + deleted: "2021-08-10T00:00:00.000Z", + user_creation_date: "121212" +} +export const unvalidUser: UserResponseModel = { + user_id: 1, + last_name: "Smith", + first_name: "John", + email: "john@gmail.com", + valid_email: false, + is_admin: false, + organisation: "LOV", + country: "France", + user_planned_usage: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + user_creation_date: '2023-08-01 10:30:00' +} \ No newline at end of file diff --git a/test/mocks/instrumentModel-mock.ts b/test/mocks/instrumentModel-mock.ts index c3b8957..fd38402 100644 --- a/test/mocks/instrumentModel-mock.ts +++ b/test/mocks/instrumentModel-mock.ts @@ -1,3 +1,4 @@ +import { InstrumentModelDataSource } from "../../src/data/interfaces/data-sources/instrument_model-data-source"; import { InstrumentModelResponseModel } from "../../src/domain/entities/instrument_model"; import { SearchResult } from "../../src/domain/entities/search"; import { InstrumentModelRepository } from "../../src/domain/interfaces/repositories/instrument_model-repository"; @@ -12,4 +13,22 @@ export class MockInstrumentModelRepository implements InstrumentModelRepository getInstrumentByName(): Promise { throw new Error("Method not implemented for getInstrumentByName"); } +} + +export class MockInstrumentModelDataSource implements InstrumentModelDataSource { + create(): Promise { + throw new Error("Method not implemented : create"); + } + getAll(): Promise> { + throw new Error("Method not implemented : getAll"); + } + updateOne(): Promise { + throw new Error("Method not implemented : updateOne"); + } + getOne(): Promise { + throw new Error("Method not implemented : getOne"); + } + deleteOne(): Promise { + throw new Error("Method not implemented : deleteOne"); + } } \ No newline at end of file diff --git a/test/mocks/privilege-mock.ts b/test/mocks/privilege-mock.ts index 3b9c0aa..73c8571 100644 --- a/test/mocks/privilege-mock.ts +++ b/test/mocks/privilege-mock.ts @@ -1,7 +1,12 @@ -import { PublicPrivilege } from "../../src/domain/entities/privilege"; +import { PrivilegeResponseModel, PublicPrivilege } from "../../src/domain/entities/privilege"; +import { SearchResult } from "../../src/domain/entities/search"; import { PrivilegeRepository } from "../../src/domain/interfaces/repositories/privilege-repository"; +import { PrivilegeDataSource } from "../../src/data/interfaces/data-sources/privilege-data-source"; export class MockPrivilegeRepository implements PrivilegeRepository { + getContact(): Promise { + throw new Error("Method not implemented for privilege mock getContact"); + } isManager(): unknown { throw new Error("Method not implemented for privilege mock isManager"); } @@ -36,4 +41,24 @@ export class MockPrivilegeRepository implements PrivilegeRepository { throw new Error("Method not implemented for privilege mock deletePrivileges"); } +} +export class MockPrivilegeDataSource implements PrivilegeDataSource { + deleteAll(): Promise { + throw new Error("Method not implemented."); + } + create(): Promise { + throw new Error("Method not implemented : create"); + } + getAll(): Promise> { + throw new Error("Method not implemented : getAll"); + } + updateOne(): Promise { + throw new Error("Method not implemented : updateOne"); + } + getOne(): Promise { + throw new Error("Method not implemented : getOne"); + } + deleteOne(): Promise { + throw new Error("Method not implemented : deleteOne"); + } } \ No newline at end of file