1 import type { DocumentMetaInterface, InternalEventBusInterface } from '@proton/docs-shared'
2 import { DocumentRole } from '@proton/docs-shared'
3 import type { DecryptedNode, DriveCompat } from '@proton/drive-store'
4 import type { LoggerInterface } from '@proton/utils/logs'
5 import { Result } from '@proton/docs-shared'
6 import type { DocumentEntitlements } from '../Types/DocumentEntitlements'
7 import type { CreateNewDocument } from '../UseCase/CreateNewDocument'
8 import type { DuplicateDocument } from '../UseCase/DuplicateDocument'
9 import type { SeedInitialCommit } from '../UseCase/SeedInitialCommit'
10 import type { SquashDocument } from '../UseCase/SquashDocument'
11 import { AuthenticatedDocController } from './AuthenticatedDocController'
12 import { DocumentMeta } from '../Models/DocumentMeta'
13 import type { GetNode } from '../UseCase/GetNode'
14 import type { DocumentStateValues } from '../State/DocumentState'
15 import { DocumentState } from '../State/DocumentState'
17 describe('AuthenticatedDocController', () => {
18 let controller: AuthenticatedDocController
21 trashDocument: jest.fn(),
22 restoreDocument: jest.fn(),
23 getShareId: jest.fn(),
25 let documentState: DocumentState
27 beforeEach(async () => {
28 documentState = new DocumentState({
29 ...DocumentState.defaults,
31 latestCommitId: () => '123',
32 } as unknown as DocumentMetaInterface,
33 entitlements: { keys: {}, role: new DocumentRole('Editor') } as unknown as DocumentEntitlements,
34 decryptedNode: {} as DecryptedNode,
35 } as DocumentStateValues)
37 controller = new AuthenticatedDocController(
39 driveCompat as unknown as jest.Mocked<DriveCompat>,
40 {} as jest.Mocked<SquashDocument>,
41 {} as jest.Mocked<SeedInitialCommit>,
42 {} as jest.Mocked<DuplicateDocument>,
43 {} as jest.Mocked<CreateNewDocument>,
45 execute: jest.fn().mockReturnValue(Result.ok({})),
46 } as unknown as jest.Mocked<GetNode>,
48 addEventHandler: jest.fn(),
50 } as unknown as jest.Mocked<InternalEventBusInterface>,
56 } as unknown as jest.Mocked<LoggerInterface>,
60 describe('handleEditorProvidingInitialConversionContent', () => {
62 controller.createInitialCommit = jest.fn().mockReturnValue(Result.ok({ commitId: '123' }))
65 it('should create initial commit', async () => {
66 await controller.handleEditorProvidingInitialConversionContent(new Uint8Array())
68 expect(controller.createInitialCommit).toHaveBeenCalled()
72 describe('trashDocument', () => {
74 documentState.setProperty('documentMeta', new DocumentMeta('volume-id-def', ['ghi'], 123, 456, 'jkl'))
76 documentState.setProperty('decryptedNode', { parentNodeId: '123', trashed: true } as unknown as DecryptedNode)
78 documentState.setProperty('documentTrashState', 'not_trashed')
81 it('trashState should be trashing initially', () => {
82 const promise = controller.trashDocument()
83 expect(documentState.getProperty('documentTrashState')).toBe('trashing')
87 it('trashState should be trashed when complete', async () => {
88 await controller.trashDocument()
89 expect(documentState.getProperty('documentTrashState')).toBe('trashed')
92 it('should refreshNodeAndDocMeta', async () => {
93 const refreshNodeAndDocMeta = jest.spyOn(controller, 'refreshNodeAndDocMeta')
95 await controller.trashDocument()
96 expect(refreshNodeAndDocMeta).toHaveBeenCalled()
99 it('should set didTrashDocInCurrentSession to true', async () => {
100 expect(controller.didTrashDocInCurrentSession).toBe(false)
102 await controller.trashDocument()
104 expect(controller.didTrashDocInCurrentSession).toBe(true)
108 describe('restoreDocument', () => {
110 documentState.setProperty('documentMeta', new DocumentMeta('volume-id-def', ['ghi'], 123, 456, 'jkl'))
112 documentState.setProperty('decryptedNode', { parentNodeId: '123', trashed: true } as unknown as DecryptedNode)
114 documentState.setProperty('documentTrashState', 'trashed')
117 it('trashState should be restoring initially', () => {
118 const promise = controller.restoreDocument()
119 expect(documentState.getProperty('documentTrashState')).toBe('restoring')
123 it('trashState should be restored when complete', async () => {
124 controller._getNode.execute = jest
126 .mockResolvedValue(Result.ok({ node: { parentNodeId: '123', trashed: false } }))
127 await controller.restoreDocument()
128 expect(documentState.getProperty('documentTrashState')).toBe('not_trashed')
131 it('should refreshNodeAndDocMeta', async () => {
132 const refreshNodeAndDocMeta = jest.spyOn(controller, 'refreshNodeAndDocMeta')
134 await controller.restoreDocument()
135 expect(refreshNodeAndDocMeta).toHaveBeenCalled()
139 describe('refreshNodeAndDocMeta', () => {
140 it('trashed state will be not_trashed if DecryptedNode trashed property is null', async () => {
141 documentState.setProperty('documentMeta', new DocumentMeta('volume-id-def', ['ghi'], 123, 456, 'jkl'))
143 controller._getNode.execute = jest
145 .mockResolvedValueOnce(Result.ok({ node: { parentNodeId: 123, trashed: null } }))
147 await controller.refreshNodeAndDocMeta({ imposeTrashState: undefined })
148 expect(documentState.getProperty('documentTrashState')).toBe('not_trashed')
151 it('trashed state will be not_trashed if DecryptedNode trashed property is omitted', async () => {
152 documentState.setProperty('documentMeta', new DocumentMeta('volume-id-def', ['ghi'], 123, 456, 'jkl'))
154 controller._getNode.execute = jest.fn().mockResolvedValueOnce(Result.ok({ node: { parentNodeId: 123 } }))
156 await controller.refreshNodeAndDocMeta({ imposeTrashState: undefined })
157 expect(documentState.getProperty('documentTrashState')).toBe('not_trashed')
160 it('trashed state will be trashed if DecryptedNode trashed property is populated', async () => {
161 documentState.setProperty('documentMeta', new DocumentMeta('volume-id-def', ['ghi'], 123, 456, 'jkl'))
163 controller._getNode.execute = jest
165 .mockResolvedValueOnce(Result.ok({ node: { parentNodeId: 123, trashed: 123 } }))
167 await controller.refreshNodeAndDocMeta({ imposeTrashState: undefined })
168 expect(documentState.getProperty('documentTrashState')).toBe('trashed')