| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- import { vi, expect } from 'vitest'
- import sinon from 'sinon'
- import mongodb from 'mongodb-legacy'
- const modulePath = '../../../../app/src/Features/Project/ProjectGetter.mjs'
- const { ObjectId } = mongodb
- describe('ProjectGetter', function () {
- beforeEach(async function (ctx) {
- ctx.project = { _id: new ObjectId() }
- ctx.projectIdStr = ctx.project._id.toString()
- ctx.deletedProject = { deleterData: { wombat: 'potato' } }
- ctx.userId = new ObjectId()
- ctx.DeletedProject = {
- find: sinon.stub().returns({
- exec: sinon.stub().resolves([ctx.deletedProject]),
- }),
- }
- ctx.Project = {
- find: sinon.stub().returns({
- exec: sinon.stub().resolves(),
- }),
- findOne: sinon.stub().returns({
- exec: sinon.stub().resolves(ctx.project),
- }),
- }
- ctx.CollaboratorsGetter = {
- promises: {
- getProjectsUserIsMemberOf: sinon.stub().resolves({
- readAndWrite: [],
- readOnly: [],
- tokenReadAndWrite: [],
- tokenReadOnly: [],
- }),
- },
- }
- ctx.LockManager = {
- promises: {
- runWithLock: sinon
- .stub()
- .callsFake((namespace, id, runner) => runner()),
- },
- }
- ctx.db = {
- projects: {
- findOne: sinon.stub().resolves(ctx.project),
- },
- users: {},
- }
- ctx.ProjectEntityMongoUpdateHandler = {
- lockKey: sinon.stub().returnsArg(0),
- }
- vi.doMock('../../../../app/src/infrastructure/mongodb', () => ({
- db: ctx.db,
- ObjectId,
- }))
- vi.doMock('../../../../app/src/models/Project', () => ({
- Project: ctx.Project,
- }))
- vi.doMock('../../../../app/src/models/DeletedProject', () => ({
- DeletedProject: ctx.DeletedProject,
- }))
- vi.doMock(
- '../../../../app/src/Features/Collaborators/CollaboratorsGetter',
- () => ({
- default: ctx.CollaboratorsGetter,
- })
- )
- vi.doMock('../../../../app/src/infrastructure/LockManager', () => ({
- default: ctx.LockManager,
- }))
- vi.doMock(
- '../../../../app/src/Features/Project/ProjectEntityMongoUpdateHandler',
- () => ({
- default: ctx.ProjectEntityMongoUpdateHandler,
- })
- )
- ctx.ProjectGetter = (await import(modulePath)).default
- })
- describe('getProjectWithoutDocLines', function () {
- beforeEach(function (ctx) {
- ctx.ProjectGetter.promises.getProject = sinon.stub().resolves()
- })
- describe('passing an id', function () {
- beforeEach(async function (ctx) {
- await ctx.ProjectGetter.promises.getProjectWithoutDocLines(
- ctx.project._id
- )
- })
- it('should call find with the project id', function (ctx) {
- ctx.ProjectGetter.promises.getProject
- .calledWith(ctx.project._id)
- .should.equal(true)
- })
- it('should exclude the doc lines', function (ctx) {
- const excludes = {
- 'rootFolder.docs.lines': 0,
- 'rootFolder.folders.docs.lines': 0,
- 'rootFolder.folders.folders.docs.lines': 0,
- 'rootFolder.folders.folders.folders.docs.lines': 0,
- 'rootFolder.folders.folders.folders.folders.docs.lines': 0,
- 'rootFolder.folders.folders.folders.folders.folders.docs.lines': 0,
- 'rootFolder.folders.folders.folders.folders.folders.folders.docs.lines': 0,
- 'rootFolder.folders.folders.folders.folders.folders.folders.folders.docs.lines': 0,
- }
- ctx.ProjectGetter.promises.getProject
- .calledWith(ctx.project._id, excludes)
- .should.equal(true)
- })
- })
- })
- describe('getProjectWithOnlyFolders', function () {
- beforeEach(function (ctx) {
- ctx.ProjectGetter.promises.getProject = sinon.stub().resolves()
- })
- describe('passing an id', function () {
- beforeEach(async function (ctx) {
- await ctx.ProjectGetter.promises.getProjectWithOnlyFolders(
- ctx.project._id
- )
- })
- it('should call find with the project id', function (ctx) {
- ctx.ProjectGetter.promises.getProject
- .calledWith(ctx.project._id)
- .should.equal(true)
- })
- it('should exclude the docs and files lines', function (ctx) {
- const excludes = {
- 'rootFolder.docs': 0,
- 'rootFolder.fileRefs': 0,
- 'rootFolder.folders.docs': 0,
- 'rootFolder.folders.fileRefs': 0,
- 'rootFolder.folders.folders.docs': 0,
- 'rootFolder.folders.folders.fileRefs': 0,
- 'rootFolder.folders.folders.folders.docs': 0,
- 'rootFolder.folders.folders.folders.fileRefs': 0,
- 'rootFolder.folders.folders.folders.folders.docs': 0,
- 'rootFolder.folders.folders.folders.folders.fileRefs': 0,
- 'rootFolder.folders.folders.folders.folders.folders.docs': 0,
- 'rootFolder.folders.folders.folders.folders.folders.fileRefs': 0,
- 'rootFolder.folders.folders.folders.folders.folders.folders.docs': 0,
- 'rootFolder.folders.folders.folders.folders.folders.folders.fileRefs': 0,
- 'rootFolder.folders.folders.folders.folders.folders.folders.folders.docs': 0,
- 'rootFolder.folders.folders.folders.folders.folders.folders.folders.fileRefs': 0,
- }
- ctx.ProjectGetter.promises.getProject
- .calledWith(ctx.project._id, excludes)
- .should.equal(true)
- })
- })
- })
- describe('getProject', function () {
- describe('without projection', function () {
- describe('with project id', function () {
- beforeEach(async function (ctx) {
- await ctx.ProjectGetter.promises.getProject(ctx.projectIdStr)
- })
- it('should call findOne with the project id', function (ctx) {
- expect(ctx.db.projects.findOne.callCount).to.equal(1)
- expect(
- ctx.db.projects.findOne.lastCall.args[0]._id.toString()
- ).to.equal(ctx.projectIdStr)
- })
- })
- describe('without project id', function () {
- it('should be rejected', function (ctx) {
- expect(
- ctx.ProjectGetter.promises.getProject(null)
- ).to.be.rejectedWith('no project id provided')
- expect(ctx.db.projects.findOne.callCount).to.equal(0)
- })
- })
- })
- describe('with projection', function () {
- beforeEach(function (ctx) {
- ctx.projection = { _id: 1 }
- })
- describe('with project id', function () {
- beforeEach(async function (ctx) {
- await ctx.ProjectGetter.promises.getProject(
- ctx.projectIdStr,
- ctx.projection
- )
- })
- it('should call findOne with the project id', function (ctx) {
- expect(ctx.db.projects.findOne.callCount).to.equal(1)
- expect(
- ctx.db.projects.findOne.lastCall.args[0]._id.toString()
- ).to.equal(ctx.projectIdStr)
- expect(ctx.db.projects.findOne.lastCall.args[1]).to.deep.equal({
- projection: ctx.projection,
- })
- })
- })
- describe('without project id', function () {
- it('should be rejected', function (ctx) {
- expect(
- ctx.ProjectGetter.promises.getProject(null)
- ).to.be.rejectedWith('no project id provided')
- expect(ctx.db.projects.findOne.callCount).to.equal(0)
- })
- })
- })
- })
- describe('getProjectWithoutLock', function () {
- describe('without projection', function () {
- describe('with project id', function () {
- beforeEach(async function (ctx) {
- await ctx.ProjectGetter.promises.getProjectWithoutLock(
- ctx.projectIdStr
- )
- })
- it('should call findOne with the project id', function (ctx) {
- expect(ctx.db.projects.findOne.callCount).to.equal(1)
- expect(
- ctx.db.projects.findOne.lastCall.args[0]._id.toString()
- ).to.equal(ctx.projectIdStr)
- })
- })
- describe('without project id', function () {
- it('should be rejected', function (ctx) {
- expect(
- ctx.ProjectGetter.promises.getProjectWithoutLock(null)
- ).to.be.rejectedWith('no project id provided')
- expect(ctx.db.projects.findOne.callCount).to.equal(0)
- })
- })
- })
- describe('with projection', function () {
- beforeEach(function (ctx) {
- ctx.projection = { _id: 1 }
- })
- describe('with project id', function () {
- beforeEach(async function (ctx) {
- await ctx.ProjectGetter.promises.getProjectWithoutLock(
- ctx.project._id,
- ctx.projection
- )
- })
- it('should call findOne with the project id', function (ctx) {
- expect(ctx.db.projects.findOne.callCount).to.equal(1)
- expect(
- ctx.db.projects.findOne.lastCall.args[0]._id.toString()
- ).to.equal(ctx.projectIdStr)
- expect(ctx.db.projects.findOne.lastCall.args[1]).to.deep.equal({
- projection: ctx.projection,
- })
- })
- })
- describe('without project id', function () {
- it('should be rejected', function (ctx) {
- expect(
- ctx.ProjectGetter.promises.getProjectWithoutLock(null)
- ).to.be.rejectedWith('no project id provided')
- expect(ctx.db.projects.findOne.callCount).to.equal(0)
- })
- })
- })
- })
- describe('findAllUsersProjects', function () {
- beforeEach(function (ctx) {
- ctx.fields = { mock: 'fields' }
- ctx.projectOwned = { _id: 'mock-owned-projects' }
- ctx.projectRW = { _id: 'mock-rw-projects' }
- ctx.projectReview = { _id: 'mock-review-projects' }
- ctx.projectRO = { _id: 'mock-ro-projects' }
- ctx.projectTokenRW = { _id: 'mock-token-rw-projects' }
- ctx.projectTokenRO = { _id: 'mock-token-ro-projects' }
- ctx.Project.find
- .withArgs({ owner_ref: ctx.userId }, ctx.fields)
- .returns({ exec: sinon.stub().resolves([ctx.projectOwned]) })
- })
- it('should return a promise with all the projects', async function (ctx) {
- ctx.CollaboratorsGetter.promises.getProjectsUserIsMemberOf.resolves({
- readAndWrite: [ctx.projectRW],
- readOnly: [ctx.projectRO],
- tokenReadAndWrite: [ctx.projectTokenRW],
- tokenReadOnly: [ctx.projectTokenRO],
- review: [ctx.projectReview],
- })
- const projects = await ctx.ProjectGetter.promises.findAllUsersProjects(
- ctx.userId,
- ctx.fields
- )
- expect(projects).to.deep.equal({
- owned: [ctx.projectOwned],
- readAndWrite: [ctx.projectRW],
- readOnly: [ctx.projectRO],
- tokenReadAndWrite: [ctx.projectTokenRW],
- tokenReadOnly: [ctx.projectTokenRO],
- review: [ctx.projectReview],
- })
- })
- it('should remove duplicate projects', async function (ctx) {
- ctx.CollaboratorsGetter.promises.getProjectsUserIsMemberOf.resolves({
- readAndWrite: [ctx.projectRW, ctx.projectOwned],
- readOnly: [ctx.projectRO, ctx.projectRW],
- tokenReadAndWrite: [ctx.projectTokenRW, ctx.projectRO],
- tokenReadOnly: [ctx.projectTokenRW, ctx.projectTokenRO, ctx.projectRO],
- review: [ctx.projectReview],
- })
- const projects = await ctx.ProjectGetter.promises.findAllUsersProjects(
- ctx.userId,
- ctx.fields
- )
- expect(projects).to.deep.equal({
- owned: [ctx.projectOwned],
- readAndWrite: [ctx.projectRW],
- readOnly: [ctx.projectRO],
- tokenReadAndWrite: [ctx.projectTokenRW],
- tokenReadOnly: [ctx.projectTokenRO],
- review: [ctx.projectReview],
- })
- })
- })
- describe('getProjectIdByReadAndWriteToken', function () {
- describe('when project find returns project', function () {
- beforeEach(async function (ctx) {
- ctx.projectIdFound =
- await ctx.ProjectGetter.promises.getProjectIdByReadAndWriteToken(
- 'token'
- )
- })
- it('should find project with token', function (ctx) {
- ctx.Project.findOne
- .calledWithMatch({ 'tokens.readAndWrite': 'token' })
- .should.equal(true)
- })
- it('should return the project id', function (ctx) {
- expect(ctx.projectIdFound).to.equal(ctx.project._id)
- })
- })
- describe('when project not found', function () {
- it('should return undefined', async function (ctx) {
- ctx.Project.findOne.returns({ exec: sinon.stub().resolves(null) })
- const projectId =
- await ctx.ProjectGetter.promises.getProjectIdByReadAndWriteToken(
- 'token'
- )
- expect(projectId).to.equal(undefined)
- })
- })
- describe('when project find returns error', function () {
- beforeEach(async function (ctx) {
- ctx.Project.findOne.returns({ exec: sinon.stub().rejects() })
- })
- it('should be rejected', function (ctx) {
- expect(
- ctx.ProjectGetter.promises.getProjectIdByReadAndWriteToken('token')
- ).to.be.rejected
- })
- })
- })
- describe('findUsersProjectsByName', function () {
- it('should perform a case-insensitive search', async function (ctx) {
- ctx.project1 = { _id: 1, name: 'find me!' }
- ctx.project2 = { _id: 2, name: 'not me!' }
- ctx.project3 = { _id: 3, name: 'FIND ME!' }
- ctx.project4 = { _id: 4, name: 'Find Me!' }
- ctx.Project.find.withArgs({ owner_ref: ctx.userId }).returns({
- exec: sinon
- .stub()
- .resolves([ctx.project1, ctx.project2, ctx.project3, ctx.project4]),
- })
- const projects = await ctx.ProjectGetter.promises.findUsersProjectsByName(
- ctx.userId,
- ctx.project1.name
- )
- const projectNames = projects.map(project => project.name)
- expect(projectNames).to.have.members([
- ctx.project1.name,
- ctx.project3.name,
- ctx.project4.name,
- ])
- })
- it('should search collaborations as well', async function (ctx) {
- ctx.project1 = { _id: 1, name: 'find me!' }
- ctx.project2 = { _id: 2, name: 'FIND ME!' }
- ctx.project3 = { _id: 3, name: 'Find Me!' }
- ctx.project4 = { _id: 4, name: 'find ME!' }
- ctx.project5 = { _id: 5, name: 'FIND me!' }
- ctx.Project.find
- .withArgs({ owner_ref: ctx.userId })
- .returns({ exec: sinon.stub().resolves([ctx.project1]) })
- ctx.CollaboratorsGetter.promises.getProjectsUserIsMemberOf.resolves({
- readAndWrite: [ctx.project2],
- readOnly: [ctx.project3],
- tokenReadAndWrite: [ctx.project4],
- tokenReadOnly: [ctx.project5],
- })
- const projects = await ctx.ProjectGetter.promises.findUsersProjectsByName(
- ctx.userId,
- ctx.project1.name
- )
- expect(projects.map(project => project.name)).to.have.members([
- ctx.project1.name,
- ctx.project2.name,
- ])
- })
- })
- describe('getUsersDeletedProjects', function () {
- it('should look up the deleted projects by deletedProjectOwnerId', async function (ctx) {
- await ctx.ProjectGetter.promises.getUsersDeletedProjects('giraffe')
- sinon.assert.calledWith(ctx.DeletedProject.find, {
- 'deleterData.deletedProjectOwnerId': 'giraffe',
- })
- })
- it('should pass the found projects to the callback', async function (ctx) {
- const docs =
- await ctx.ProjectGetter.promises.getUsersDeletedProjects('giraffe')
- expect(docs).to.deep.equal([ctx.deletedProject])
- })
- })
- })
|