Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / docs-core / lib / UseCase / SquashDocument.spec.ts
blob119992c3bd50f5cce3b160c6ed1b9fb79aeaa82e
1 import { ApiResult, Result } from '@proton/docs-shared'
2 import type { DocsApi } from '../Api/DocsApi'
3 import type { DecryptCommit } from './DecryptCommit'
4 import type { EncryptMessage } from './EncryptMessage'
5 import type { SquashAlgorithm } from './SquashAlgorithm'
6 import type { SquashDocumentDTO } from './SquashDocument'
7 import { SquashDocument } from './SquashDocument'
8 import type { VerifyCommit } from './VerifyCommit'
9 import { SquashVerificationObjectionDecision } from '../Types/SquashVerificationObjection'
10 import type { LoggerInterface } from '@proton/utils/logs'
12 jest.mock('@proton/docs-proto', () => ({
13   ...jest.requireActual('@proton/docs-proto'),
14   SquashLock: {
15     deserializeBinary: jest.fn().mockReturnValue({
16       commit: {
17         updates: {
18           documentUpdates: [{}],
19         },
20       },
21       commitId: 'commitId',
22     }),
23   },
24 }))
26 describe('SquashDocument', () => {
27   let usecase: SquashDocument
28   let docsApi: DocsApi
29   let decryptCommit: DecryptCommit
30   let verifyCommit: VerifyCommit
31   let squashAlgorithm: SquashAlgorithm
32   let encryptMessage: EncryptMessage
33   let logger: LoggerInterface
35   const dto: SquashDocumentDTO = {
36     nodeMeta: {} as any,
37     commitId: 'commitId',
38     keys: {} as any,
39     handleVerificationObjection: jest.fn(),
40   }
42   beforeEach(() => {
43     docsApi = {
44       lockDocument: jest.fn().mockReturnValue(Result.ok({})),
45       squashCommit: jest.fn().mockReturnValue(Result.ok({})),
46     } as unknown as DocsApi
48     decryptCommit = {
49       execute: jest.fn().mockReturnValue(
50         Result.ok({
51           updates: [],
52         }),
53       ),
54     } as unknown as DecryptCommit
56     verifyCommit = {
57       execute: jest.fn().mockReturnValue(Result.ok(true)),
58     } as unknown as VerifyCommit
60     encryptMessage = {
61       execute: jest.fn().mockReturnValue(Result.ok({})),
62     } as unknown as EncryptMessage
64     squashAlgorithm = {
65       execute: jest.fn().mockReturnValue(
66         Result.ok({
67           updatesAsSquashed: new Uint8Array(),
68           unmodifiedUpdates: [],
69         }),
70       ),
71     } as unknown as SquashAlgorithm
73     logger = {
74       info: jest.fn(),
75     } as unknown as LoggerInterface
77     usecase = new SquashDocument(docsApi, encryptMessage, decryptCommit, verifyCommit, squashAlgorithm, logger)
78   })
80   afterEach(() => {
81     jest.clearAllMocks()
82   })
84   it('should lock document before doing anything else', async () => {
85     const lockDocumentSpy = jest.spyOn(docsApi, 'lockDocument')
87     decryptCommit.execute = jest.fn().mockResolvedValue(Result.fail('failed'))
88     const decryptCommitSpy = jest.spyOn(decryptCommit, 'execute')
90     await usecase.execute(dto)
92     expect(lockDocumentSpy).toHaveBeenCalled()
93     expect(decryptCommitSpy).toHaveBeenCalled()
95     expect(lockDocumentSpy.mock.invocationCallOrder[0]).toBeLessThan(decryptCommitSpy.mock.invocationCallOrder[0])
96   })
98   it('should fail if lock document fails', async () => {
99     docsApi.lockDocument = jest.fn().mockReturnValue(ApiResult.fail({ message: 'failed', code: 0 }))
101     const result = await usecase.execute(dto)
103     expect(result.isFailed()).toBe(true)
104   })
106   it('should verify signature of data', async () => {
107     const verifyCommitSpy = jest.spyOn(verifyCommit, 'execute')
109     await usecase.execute(dto)
111     expect(verifyCommitSpy).toHaveBeenCalled()
112   })
114   it('should issue objection is verification fails', async () => {
115     const verificationResult = Result.fail('failed')
116     verifyCommit.execute = jest.fn().mockReturnValue(verificationResult)
117     const verifyCommitSpy = jest.spyOn(verifyCommit, 'execute')
119     dto.handleVerificationObjection = jest.fn().mockReturnValue(SquashVerificationObjectionDecision.AbortSquash)
121     await usecase.execute(dto)
123     expect(verifyCommitSpy).toHaveBeenCalled()
124     expect(dto.handleVerificationObjection).toHaveBeenCalled()
125   })
127   it('should abort squash if verification object decision is to abort', async () => {
128     const verificationResult = Result.fail('failed')
129     verifyCommit.execute = jest.fn().mockReturnValue(verificationResult)
131     dto.handleVerificationObjection = jest.fn().mockReturnValue(SquashVerificationObjectionDecision.AbortSquash)
133     const squashTheCommitSpy = jest.spyOn(usecase, 'squashTheCommit')
135     const result = await usecase.execute(dto)
137     expect(result.isFailed()).toBe(true)
138     expect(squashTheCommitSpy).not.toHaveBeenCalled()
139   })
141   it('should continue squash if verification object decision is to continue', async () => {
142     const verificationResult = Result.fail('failed')
143     verifyCommit.execute = jest.fn().mockReturnValue(verificationResult)
145     dto.handleVerificationObjection = jest.fn().mockReturnValue(SquashVerificationObjectionDecision.ContinueSquash)
147     const squashTheCommitSpy = jest.spyOn(usecase, 'squashTheCommit')
149     await usecase.execute(dto)
151     expect(squashTheCommitSpy).toHaveBeenCalled()
152   })
154   it('should upload the squashed commit', async () => {
155     const commitResult = Result.ok({})
156     docsApi.squashCommit = jest.fn().mockReturnValue(commitResult)
158     await usecase.execute(dto)
160     expect(docsApi.squashCommit).toHaveBeenCalled()
161   })
163   describe('squashTheCommit', () => {
164     it('should encrypt the result', async () => {
165       decryptCommit.execute = jest.fn().mockResolvedValue(Result.ok({ updates: [{}] }))
167       const encryptSpy = jest.spyOn(usecase, 'encryptSquashResult')
169       await usecase.execute(dto)
171       expect(encryptSpy).toHaveBeenCalled()
172     })
173   })