@sync-in/server 1.4.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +2 -1
- package/package.json +5 -5
- package/server/applications/comments/comments.controller.spec.js +103 -4
- package/server/applications/comments/comments.controller.spec.js.map +1 -1
- package/server/applications/comments/services/comments-manager.service.spec.js +409 -9
- package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js +333 -0
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js.map +1 -0
- package/server/applications/files/constants/routes.js +6 -1
- package/server/applications/files/constants/routes.js.map +1 -1
- package/server/applications/files/files-only-office.controller.js +11 -0
- package/server/applications/files/files-only-office.controller.js.map +1 -1
- package/server/applications/files/files-only-office.controller.spec.js +97 -3
- package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
- package/server/applications/files/files-tasks.controller.spec.js +91 -1
- package/server/applications/files/files-tasks.controller.spec.js.map +1 -1
- package/server/applications/files/files.controller.spec.js +268 -46
- package/server/applications/files/files.controller.spec.js.map +1 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js +77 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js.map +1 -1
- package/server/applications/files/services/files-only-office-manager.service.js +5 -0
- package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
- package/server/applications/links/links.controller.spec.js +91 -58
- package/server/applications/links/links.controller.spec.js.map +1 -1
- package/server/applications/links/services/links-manager.service.js +4 -6
- package/server/applications/links/services/links-manager.service.js.map +1 -1
- package/server/applications/links/services/links-manager.service.spec.js +378 -14
- package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
- package/server/applications/links/services/links-queries.service.js +1 -1
- package/server/applications/links/services/links-queries.service.js.map +1 -1
- package/server/applications/notifications/notifications.controller.spec.js +56 -1
- package/server/applications/notifications/notifications.controller.spec.js.map +1 -1
- package/server/applications/notifications/services/notifications-manager.service.spec.js +461 -5
- package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.spec.js +590 -14
- package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js +120 -0
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js.map +1 -0
- package/server/applications/sync/services/sync-clients-manager.service.spec.js +548 -8
- package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-manager.service.spec.js +837 -5
- package/server/applications/sync/services/sync-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.spec.js +900 -7
- package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.js +22 -24
- package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js +763 -17
- package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-manager.service.js +1 -1
- package/server/applications/users/services/users-manager.service.js.map +1 -1
- package/server/applications/users/services/users-manager.service.spec.js +938 -49
- package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
- package/server/applications/webdav/decorators/if-header.decorator.js +4 -1
- package/server/applications/webdav/decorators/if-header.decorator.js.map +1 -1
- package/server/applications/webdav/filters/webdav.filter.spec.js +77 -0
- package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.js +3 -7
- package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +580 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -0
- package/server/applications/webdav/services/webdav-methods.service.spec.js +1582 -3
- package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
- package/server/applications/webdav/services/webdav-spaces.service.spec.js +390 -2
- package/server/applications/webdav/services/webdav-spaces.service.spec.js.map +1 -1
- package/server/applications/webdav/webdav.controller.js +2 -2
- package/server/applications/webdav/webdav.controller.js.map +1 -1
- package/server/authentication/guards/auth-basic.guard.js.map +1 -1
- package/server/authentication/guards/auth-digest.guard.js +1 -2
- package/server/authentication/guards/auth-digest.guard.js.map +1 -1
- package/server/authentication/guards/auth-local.guard.js.map +1 -1
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js +135 -0
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js.map +1 -0
- package/static/3rdpartylicenses.txt +26 -26
- package/static/assets/pdfjs/build/pdf.mjs +1177 -255
- package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.sandbox.mjs +25 -2
- package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.worker.mjs +140 -16
- package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
- package/static/assets/pdfjs/version +1 -1
- package/static/assets/pdfjs/web/debugger.css +31 -0
- package/static/assets/pdfjs/web/debugger.mjs +144 -2
- package/static/assets/pdfjs/web/images/comment-editButton.svg +6 -1
- package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/be/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bs/viewer.ftl +22 -0
- package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/cs/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/cy/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/da/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/de/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/el/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -0
- package/static/assets/pdfjs/web/locale/eo/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -6
- package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -57
- package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/fi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fr/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/gl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/gn/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/he/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hu/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -49
- package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ia/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/it/viewer.ftl +31 -0
- package/static/assets/pdfjs/web/locale/ja/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/ka/viewer.ftl +48 -10
- package/static/assets/pdfjs/web/locale/kab/viewer.ftl +5 -0
- package/static/assets/pdfjs/web/locale/kk/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -75
- package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +44 -6
- package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nl/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +45 -1
- package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -31
- package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -1
- package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ro/viewer.ftl +355 -1
- package/static/assets/pdfjs/web/locale/ru/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -38
- package/static/assets/pdfjs/web/locale/scn/viewer.ftl +0 -92
- package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -51
- package/static/assets/pdfjs/web/locale/sk/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -27
- package/static/assets/pdfjs/web/locale/sl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -33
- package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/tg/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/tr/viewer.ftl +40 -2
- package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -72
- package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/vi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/wo/viewer.ftl +0 -77
- package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/viewer.css +649 -120
- package/static/assets/pdfjs/web/viewer.html +19 -0
- package/static/assets/pdfjs/web/viewer.mjs +489 -38
- package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
- package/static/chunk-22EANI6R.js +1 -0
- package/static/{chunk-N2LYWNTC.js → chunk-2456KVFZ.js} +1 -1
- package/static/{chunk-YCINY2YI.js → chunk-2LVCLKCK.js} +1 -1
- package/static/{chunk-5YKWZT33.js → chunk-2V5S7DWD.js} +1 -1
- package/static/{chunk-3GC2BQZD.js → chunk-44YDXGNZ.js} +1 -1
- package/static/{chunk-W3QXNDI5.js → chunk-4LSJLWYV.js} +1 -1
- package/static/{chunk-T55FAU2O.js → chunk-4UT5VH7R.js} +1 -1
- package/static/{chunk-VMQMD36Z.js → chunk-5GOMMRRE.js} +1 -1
- package/static/{chunk-TXPODW5Q.js → chunk-5J4VRDKB.js} +1 -1
- package/static/{chunk-FQ4AFNGE.js → chunk-6PVKNZ7Q.js} +1 -1
- package/static/{chunk-XE5YHU5J.js → chunk-BIUNUYZ5.js} +1 -1
- package/static/{chunk-X43VWRFP.js → chunk-DFQKHCDR.js} +1 -1
- package/static/{chunk-TDQAEVZN.js → chunk-EE2TDTY4.js} +1 -1
- package/static/{chunk-MOVWEZ7J.js → chunk-ESNDJ5T6.js} +1 -1
- package/static/{chunk-TCFKH6K6.js → chunk-GDKKLLEU.js} +1 -1
- package/static/{chunk-VHYIXL7R.js → chunk-GSR2MCQG.js} +1 -1
- package/static/{chunk-LJIGRUEF.js → chunk-HR7KS5BR.js} +1 -1
- package/static/chunk-HW2H3ISM.js +559 -0
- package/static/{chunk-HZA7R43P.js → chunk-IMB3C547.js} +1 -1
- package/static/{chunk-B2Y2RNFP.js → chunk-J4ALHUDX.js} +1 -1
- package/static/{chunk-PF4K7MVG.js → chunk-KP6LSQTK.js} +1 -1
- package/static/{chunk-C23BPTJZ.js → chunk-LUZCOHFN.js} +1 -1
- package/static/{chunk-GBCYYDCI.js → chunk-MHSCCXVL.js} +1 -1
- package/static/{chunk-PY3BGNJN.js → chunk-OMRQYBXV.js} +1 -1
- package/static/chunk-P7CTJ5BG.js +27 -0
- package/static/{chunk-Y2CDUS4J.js → chunk-P7PX67IR.js} +4 -4
- package/static/{chunk-VMUOUCEI.js → chunk-PPO7DBVO.js} +1 -1
- package/static/{chunk-TTQ37MUV.js → chunk-RSS6GYNE.js} +1 -1
- package/static/{chunk-WWIC7UW3.js → chunk-SLGGINMR.js} +1 -1
- package/static/{chunk-KZQCFEPT.js → chunk-UHD5XD3G.js} +1 -1
- package/static/{chunk-TNW2CGK6.js → chunk-UPYYAJCJ.js} +1 -1
- package/static/{chunk-6F55D74O.js → chunk-VHYPQ3D4.js} +1 -1
- package/static/{chunk-DGVNNICG.js → chunk-YQSDS6BO.js} +1 -1
- package/static/{chunk-MTRNPGS4.js → chunk-ZC5NIT55.js} +1 -1
- package/static/index.html +1 -1
- package/static/main-FYD34UEC.js +7 -0
- package/static/chunk-RSNLYAN6.js +0 -560
- package/static/chunk-WHMS3PJ3.js +0 -24
- package/static/chunk-ZZ3LHYOY.js +0 -1
- package/static/main-7LDKYVXO.js +0 -10
|
@@ -6,19 +6,65 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", {
|
|
7
7
|
value: true
|
|
8
8
|
});
|
|
9
|
+
const _common = require("@nestjs/common");
|
|
9
10
|
const _testing = require("@nestjs/testing");
|
|
10
11
|
const _cacheservice = require("../../../infrastructure/cache/services/cache.service");
|
|
11
12
|
const _contextmanagerservice = require("../../../infrastructure/context/services/context-manager.service");
|
|
12
13
|
const _constants = require("../../../infrastructure/database/constants");
|
|
13
14
|
const _filesqueriesservice = require("../../files/services/files-queries.service");
|
|
15
|
+
const _files = require("../../files/utils/files");
|
|
14
16
|
const _notificationsmanagerservice = require("../../notifications/services/notifications-manager.service");
|
|
15
17
|
const _sharesqueriesservice = require("../../shares/services/shares-queries.service");
|
|
16
18
|
const _spacesqueriesservice = require("../../spaces/services/spaces-queries.service");
|
|
17
19
|
const _commentsmanagerservice = require("./comments-manager.service");
|
|
18
20
|
const _commentsqueriesservice = require("./comments-queries.service");
|
|
21
|
+
// Mocks of the file utilities used by the service
|
|
22
|
+
jest.mock('../../files/utils/files', ()=>({
|
|
23
|
+
isPathExists: jest.fn(),
|
|
24
|
+
getProps: jest.fn(),
|
|
25
|
+
dirName: jest.fn(),
|
|
26
|
+
fileName: jest.fn()
|
|
27
|
+
}));
|
|
19
28
|
describe(_commentsmanagerservice.CommentsManager.name, ()=>{
|
|
20
|
-
let
|
|
29
|
+
let commentsManager;
|
|
30
|
+
let contextManager;
|
|
31
|
+
let commentQueries;
|
|
32
|
+
let filesQueries;
|
|
33
|
+
let notificationsManager;
|
|
34
|
+
const user = {
|
|
35
|
+
id: 42,
|
|
36
|
+
email: 'john@doe.tld'
|
|
37
|
+
};
|
|
38
|
+
const makeSpace = (overrides = {})=>({
|
|
39
|
+
realPath: '/real/path',
|
|
40
|
+
url: '/space/folder/file.txt',
|
|
41
|
+
dbFile: {
|
|
42
|
+
path: 'folder',
|
|
43
|
+
ownerId: 42,
|
|
44
|
+
spaceExternalRootId: null,
|
|
45
|
+
shareExternalId: null
|
|
46
|
+
},
|
|
47
|
+
...overrides
|
|
48
|
+
});
|
|
21
49
|
beforeAll(async ()=>{
|
|
50
|
+
commentQueries = {
|
|
51
|
+
getComments: jest.fn(),
|
|
52
|
+
createComment: jest.fn(),
|
|
53
|
+
updateComment: jest.fn(),
|
|
54
|
+
deleteComment: jest.fn(),
|
|
55
|
+
getRecentsFromUser: jest.fn(),
|
|
56
|
+
membersToNotify: jest.fn()
|
|
57
|
+
};
|
|
58
|
+
filesQueries = {
|
|
59
|
+
getSpaceFileId: jest.fn(),
|
|
60
|
+
getOrCreateSpaceFile: jest.fn()
|
|
61
|
+
};
|
|
62
|
+
notificationsManager = {
|
|
63
|
+
create: jest.fn().mockResolvedValue(undefined)
|
|
64
|
+
};
|
|
65
|
+
contextManager = {
|
|
66
|
+
get: jest.fn().mockReturnValue('https://app.local/path')
|
|
67
|
+
};
|
|
22
68
|
const module = await _testing.Test.createTestingModule({
|
|
23
69
|
providers: [
|
|
24
70
|
{
|
|
@@ -31,20 +77,374 @@ describe(_commentsmanagerservice.CommentsManager.name, ()=>{
|
|
|
31
77
|
},
|
|
32
78
|
{
|
|
33
79
|
provide: _notificationsmanagerservice.NotificationsManager,
|
|
80
|
+
useValue: notificationsManager
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
provide: _contextmanagerservice.ContextManager,
|
|
84
|
+
useValue: contextManager
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
provide: _commentsmanagerservice.CommentsManager,
|
|
88
|
+
useClass: _commentsmanagerservice.CommentsManager
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
provide: _commentsqueriesservice.CommentsQueries,
|
|
92
|
+
useValue: commentQueries
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
provide: _filesqueriesservice.FilesQueries,
|
|
96
|
+
useValue: filesQueries
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
provide: _spacesqueriesservice.SpacesQueries,
|
|
34
100
|
useValue: {}
|
|
35
101
|
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
_spacesqueriesservice.SpacesQueries,
|
|
41
|
-
_sharesqueriesservice.SharesQueries
|
|
102
|
+
{
|
|
103
|
+
provide: _sharesqueriesservice.SharesQueries,
|
|
104
|
+
useValue: {}
|
|
105
|
+
}
|
|
42
106
|
]
|
|
43
107
|
}).compile();
|
|
44
|
-
|
|
108
|
+
commentsManager = module.get(_commentsmanagerservice.CommentsManager);
|
|
109
|
+
});
|
|
110
|
+
beforeEach(()=>{
|
|
111
|
+
jest.clearAllMocks();
|
|
112
|
+
_files.isPathExists.mockResolvedValue(true);
|
|
113
|
+
_files.getProps.mockResolvedValue({
|
|
114
|
+
name: 'file.txt',
|
|
115
|
+
path: 'folder'
|
|
116
|
+
});
|
|
117
|
+
_files.dirName.mockReturnValue('/space/folder');
|
|
118
|
+
_files.fileName.mockReturnValue('file.txt');
|
|
45
119
|
});
|
|
46
120
|
it('should be defined', ()=>{
|
|
47
|
-
expect(
|
|
121
|
+
expect(commentsManager).toBeDefined();
|
|
122
|
+
});
|
|
123
|
+
describe('getComments', ()=>{
|
|
124
|
+
it('returns [] if no fileId', async ()=>{
|
|
125
|
+
filesQueries.getSpaceFileId.mockResolvedValue(0);
|
|
126
|
+
const res = await commentsManager.getComments(user, makeSpace());
|
|
127
|
+
expect(res).toEqual([]);
|
|
128
|
+
expect(filesQueries.getSpaceFileId).toHaveBeenCalledTimes(1);
|
|
129
|
+
expect(commentQueries.getComments).not.toHaveBeenCalled();
|
|
130
|
+
});
|
|
131
|
+
it('returns comments if fileId is valid', async ()=>{
|
|
132
|
+
filesQueries.getSpaceFileId.mockResolvedValue(123);
|
|
133
|
+
const expected = [
|
|
134
|
+
{
|
|
135
|
+
id: 1
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: 2
|
|
139
|
+
}
|
|
140
|
+
];
|
|
141
|
+
commentQueries.getComments.mockResolvedValue(expected);
|
|
142
|
+
const res = await commentsManager.getComments(user, makeSpace());
|
|
143
|
+
expect(filesQueries.getSpaceFileId).toHaveBeenCalled();
|
|
144
|
+
expect(commentQueries.getComments).toHaveBeenCalledWith(42, true, 123);
|
|
145
|
+
expect(res).toBe(expected);
|
|
146
|
+
});
|
|
147
|
+
it('throws NOT_FOUND if path does not exist', async ()=>{
|
|
148
|
+
;
|
|
149
|
+
_files.isPathExists.mockResolvedValue(false);
|
|
150
|
+
await expect(commentsManager.getComments(user, makeSpace())).rejects.toThrow(_common.HttpException);
|
|
151
|
+
await expect(commentsManager.getComments(user, makeSpace())).rejects.toMatchObject({
|
|
152
|
+
status: _common.HttpStatus.NOT_FOUND
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
describe('createComment', ()=>{
|
|
157
|
+
it("rejects on external root/share at path '.'", async ()=>{
|
|
158
|
+
const space = makeSpace({
|
|
159
|
+
dbFile: {
|
|
160
|
+
path: '.',
|
|
161
|
+
ownerId: 42,
|
|
162
|
+
spaceExternalRootId: 'ext',
|
|
163
|
+
shareExternalId: null
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
await expect(commentsManager.createComment(user, space, {
|
|
167
|
+
fileId: 0,
|
|
168
|
+
content: 'Hi'
|
|
169
|
+
})).rejects.toMatchObject({
|
|
170
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
171
|
+
});
|
|
172
|
+
const space2 = makeSpace({
|
|
173
|
+
dbFile: {
|
|
174
|
+
path: '.',
|
|
175
|
+
ownerId: 42,
|
|
176
|
+
spaceExternalRootId: null,
|
|
177
|
+
shareExternalId: 'shr'
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
await expect(commentsManager.createComment(user, space2, {
|
|
181
|
+
fileId: 0,
|
|
182
|
+
content: 'Hi'
|
|
183
|
+
})).rejects.toMatchObject({
|
|
184
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
it('rejects BAD_REQUEST if provided fileId mismatches', async ()=>{
|
|
188
|
+
filesQueries.getSpaceFileId.mockResolvedValue(100);
|
|
189
|
+
await expect(commentsManager.createComment(user, makeSpace(), {
|
|
190
|
+
fileId: 101,
|
|
191
|
+
content: 'x'
|
|
192
|
+
})).rejects.toMatchObject({
|
|
193
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
it('uses getOrCreate when fileId < 0', async ()=>{
|
|
197
|
+
filesQueries.getOrCreateSpaceFile.mockResolvedValue(555);
|
|
198
|
+
commentQueries.createComment.mockResolvedValue(777);
|
|
199
|
+
commentQueries.getComments.mockResolvedValue([
|
|
200
|
+
{
|
|
201
|
+
id: 777,
|
|
202
|
+
fileId: 555,
|
|
203
|
+
content: 'hello'
|
|
204
|
+
}
|
|
205
|
+
]);
|
|
206
|
+
// Force a rejection in notify() to cover the catch attached to this.notify(...) in createComment
|
|
207
|
+
commentQueries.membersToNotify.mockRejectedValueOnce(new Error('members failed'));
|
|
208
|
+
const loggerSpy = jest.spyOn(commentsManager['logger'], 'error').mockImplementation(()=>undefined);
|
|
209
|
+
const res = await commentsManager.createComment(user, makeSpace(), {
|
|
210
|
+
fileId: -1,
|
|
211
|
+
content: 'hello'
|
|
212
|
+
});
|
|
213
|
+
// Let the microtask run the catch of createComment
|
|
214
|
+
await new Promise((r)=>setImmediate(r));
|
|
215
|
+
expect(filesQueries.getOrCreateSpaceFile).toHaveBeenCalled();
|
|
216
|
+
expect(filesQueries.getSpaceFileId).not.toHaveBeenCalled();
|
|
217
|
+
expect(commentQueries.createComment).toHaveBeenCalledWith(42, 555, 'hello');
|
|
218
|
+
expect(notificationsManager.create).not.toHaveBeenCalled();
|
|
219
|
+
expect(res).toEqual({
|
|
220
|
+
id: 777,
|
|
221
|
+
fileId: 555,
|
|
222
|
+
content: 'hello'
|
|
223
|
+
});
|
|
224
|
+
// Verify that the catch of createComment logged the error
|
|
225
|
+
expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('createComment'));
|
|
226
|
+
loggerSpy.mockRestore();
|
|
227
|
+
});
|
|
228
|
+
it('notifies members when present', async ()=>{
|
|
229
|
+
filesQueries.getSpaceFileId.mockResolvedValue(10);
|
|
230
|
+
commentQueries.createComment.mockResolvedValue(1);
|
|
231
|
+
commentQueries.getComments.mockResolvedValue([
|
|
232
|
+
{
|
|
233
|
+
id: 1,
|
|
234
|
+
fileId: 10,
|
|
235
|
+
content: 'c'
|
|
236
|
+
}
|
|
237
|
+
]);
|
|
238
|
+
commentQueries.membersToNotify.mockResolvedValue([
|
|
239
|
+
{
|
|
240
|
+
id: 2,
|
|
241
|
+
email: 'a@b.c'
|
|
242
|
+
}
|
|
243
|
+
]);
|
|
244
|
+
// Force rejection of notification creation to trigger the catch in notify()
|
|
245
|
+
notificationsManager.create.mockRejectedValueOnce(new Error('notify failed'));
|
|
246
|
+
const loggerSpy = jest.spyOn(commentsManager['logger'], 'error').mockImplementation(()=>undefined);
|
|
247
|
+
await commentsManager.createComment(user, makeSpace(), {
|
|
248
|
+
fileId: 10,
|
|
249
|
+
content: 'c'
|
|
250
|
+
});
|
|
251
|
+
// Let the microtask execute the internal catch of notify()
|
|
252
|
+
await new Promise((r)=>setImmediate(r));
|
|
253
|
+
expect(notificationsManager.create).toHaveBeenCalledTimes(1);
|
|
254
|
+
notificationsManager.create.mockClear();
|
|
255
|
+
expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('notify'));
|
|
256
|
+
loggerSpy.mockRestore();
|
|
257
|
+
const space = makeSpace();
|
|
258
|
+
await commentsManager.createComment(user, space, {
|
|
259
|
+
fileId: 10,
|
|
260
|
+
content: 'c'
|
|
261
|
+
});
|
|
262
|
+
expect(commentQueries.membersToNotify).toHaveBeenCalledWith(42, 10);
|
|
263
|
+
expect(notificationsManager.create).toHaveBeenCalledTimes(1);
|
|
264
|
+
const [members, notification, data] = notificationsManager.create.mock.calls[0];
|
|
265
|
+
expect(members).toEqual([
|
|
266
|
+
{
|
|
267
|
+
id: 2,
|
|
268
|
+
email: 'a@b.c'
|
|
269
|
+
}
|
|
270
|
+
]);
|
|
271
|
+
expect(notification).toMatchObject({
|
|
272
|
+
app: expect.anything(),
|
|
273
|
+
event: expect.anything(),
|
|
274
|
+
element: 'file.txt',
|
|
275
|
+
url: '/space/folder'
|
|
276
|
+
});
|
|
277
|
+
expect(_files.fileName).toHaveBeenCalledWith(space.url);
|
|
278
|
+
expect(_files.dirName).toHaveBeenCalledWith(space.url);
|
|
279
|
+
expect(data).toMatchObject({
|
|
280
|
+
author: user,
|
|
281
|
+
currentUrl: 'https://app.local/path',
|
|
282
|
+
content: 'c'
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
it('logs an error if notificationsManager.create rejects (covers catch in notify)', async ()=>{
|
|
286
|
+
filesQueries.getSpaceFileId.mockResolvedValue(10);
|
|
287
|
+
commentQueries.createComment.mockResolvedValue(1);
|
|
288
|
+
commentQueries.getComments.mockResolvedValue([
|
|
289
|
+
{
|
|
290
|
+
id: 1,
|
|
291
|
+
fileId: 10,
|
|
292
|
+
content: 'c'
|
|
293
|
+
}
|
|
294
|
+
]);
|
|
295
|
+
commentQueries.membersToNotify.mockResolvedValue([
|
|
296
|
+
{
|
|
297
|
+
id: 2,
|
|
298
|
+
email: 'a@b.c'
|
|
299
|
+
}
|
|
300
|
+
]);
|
|
301
|
+
// Force rejection to trigger the catch in notify()
|
|
302
|
+
notificationsManager.create.mockRejectedValueOnce(new Error('notify failed'));
|
|
303
|
+
const loggerSpy = jest.spyOn(commentsManager['logger'], 'error').mockImplementation(()=>undefined);
|
|
304
|
+
await commentsManager.createComment(user, makeSpace(), {
|
|
305
|
+
fileId: 10,
|
|
306
|
+
content: 'c'
|
|
307
|
+
});
|
|
308
|
+
// Allow the microtask to run the internal catch of notify()
|
|
309
|
+
await new Promise((r)=>setImmediate(r));
|
|
310
|
+
expect(notificationsManager.create).toHaveBeenCalledTimes(1);
|
|
311
|
+
expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('notify'));
|
|
312
|
+
loggerSpy.mockRestore();
|
|
313
|
+
});
|
|
314
|
+
it('does not notify if no members', async ()=>{
|
|
315
|
+
filesQueries.getSpaceFileId.mockResolvedValue(10);
|
|
316
|
+
commentQueries.createComment.mockResolvedValue(1);
|
|
317
|
+
commentQueries.getComments.mockResolvedValue([
|
|
318
|
+
{
|
|
319
|
+
id: 1
|
|
320
|
+
}
|
|
321
|
+
]);
|
|
322
|
+
commentQueries.membersToNotify.mockResolvedValue([]);
|
|
323
|
+
await commentsManager.createComment(user, makeSpace(), {
|
|
324
|
+
fileId: 10,
|
|
325
|
+
content: 'c'
|
|
326
|
+
});
|
|
327
|
+
expect(notificationsManager.create).not.toHaveBeenCalled();
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
describe('updateComment', ()=>{
|
|
331
|
+
it('rejects NOT_FOUND if target comment is not found', async ()=>{
|
|
332
|
+
commentQueries.getComments.mockResolvedValue([]);
|
|
333
|
+
await expect(commentsManager.updateComment(user, makeSpace(), {
|
|
334
|
+
commentId: 99,
|
|
335
|
+
fileId: 1,
|
|
336
|
+
content: 'z'
|
|
337
|
+
})).rejects.toMatchObject({
|
|
338
|
+
status: _common.HttpStatus.NOT_FOUND
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
it('rejects BAD_REQUEST if fileId mismatches', async ()=>{
|
|
342
|
+
commentQueries.getComments.mockResolvedValue([
|
|
343
|
+
{
|
|
344
|
+
id: 50,
|
|
345
|
+
fileId: 123
|
|
346
|
+
}
|
|
347
|
+
]);
|
|
348
|
+
filesQueries.getSpaceFileId.mockResolvedValue(999);
|
|
349
|
+
await expect(commentsManager.updateComment(user, makeSpace(), {
|
|
350
|
+
commentId: 50,
|
|
351
|
+
fileId: 123,
|
|
352
|
+
content: 'z'
|
|
353
|
+
})).rejects.toMatchObject({
|
|
354
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
it('rejects INTERNAL_SERVER_ERROR if update fails', async ()=>{
|
|
358
|
+
commentQueries.getComments.mockResolvedValueOnce([
|
|
359
|
+
{
|
|
360
|
+
id: 50,
|
|
361
|
+
fileId: 5
|
|
362
|
+
}
|
|
363
|
+
]);
|
|
364
|
+
filesQueries.getSpaceFileId.mockResolvedValue(5);
|
|
365
|
+
commentQueries.updateComment.mockResolvedValue(false);
|
|
366
|
+
await expect(commentsManager.updateComment(user, makeSpace(), {
|
|
367
|
+
commentId: 50,
|
|
368
|
+
fileId: 5,
|
|
369
|
+
content: 'z'
|
|
370
|
+
})).rejects.toMatchObject({
|
|
371
|
+
status: _common.HttpStatus.INTERNAL_SERVER_ERROR
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
it('returns the comment after update', async ()=>{
|
|
375
|
+
commentQueries.getComments.mockResolvedValueOnce([
|
|
376
|
+
{
|
|
377
|
+
id: 50,
|
|
378
|
+
fileId: 5
|
|
379
|
+
}
|
|
380
|
+
]) // initial fetch
|
|
381
|
+
.mockResolvedValueOnce([
|
|
382
|
+
{
|
|
383
|
+
id: 50,
|
|
384
|
+
fileId: 5,
|
|
385
|
+
content: 'updated'
|
|
386
|
+
}
|
|
387
|
+
]); // fetch after update -> include content
|
|
388
|
+
filesQueries.getSpaceFileId.mockResolvedValue(5);
|
|
389
|
+
commentQueries.updateComment.mockResolvedValue(true);
|
|
390
|
+
const res = await commentsManager.updateComment(user, makeSpace(), {
|
|
391
|
+
commentId: 50,
|
|
392
|
+
fileId: 5,
|
|
393
|
+
content: 'updated'
|
|
394
|
+
});
|
|
395
|
+
expect(commentQueries.updateComment).toHaveBeenCalledWith(42, 50, 5, 'updated');
|
|
396
|
+
// allow additional fields via toMatchObject
|
|
397
|
+
expect(res).toMatchObject({
|
|
398
|
+
id: 50,
|
|
399
|
+
fileId: 5,
|
|
400
|
+
content: 'updated'
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
describe('deleteComment', ()=>{
|
|
405
|
+
it('rejects BAD_REQUEST if fileId mismatches', async ()=>{
|
|
406
|
+
filesQueries.getSpaceFileId.mockResolvedValue(10);
|
|
407
|
+
await expect(commentsManager.deleteComment(user, makeSpace(), {
|
|
408
|
+
commentId: 1,
|
|
409
|
+
fileId: 11
|
|
410
|
+
})).rejects.toMatchObject({
|
|
411
|
+
status: _common.HttpStatus.BAD_REQUEST
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
it('rejects FORBIDDEN if deletion is denied', async ()=>{
|
|
415
|
+
filesQueries.getSpaceFileId.mockResolvedValue(10);
|
|
416
|
+
commentQueries.deleteComment.mockResolvedValue(false);
|
|
417
|
+
await expect(commentsManager.deleteComment(user, makeSpace(), {
|
|
418
|
+
commentId: 1,
|
|
419
|
+
fileId: 10
|
|
420
|
+
})).rejects.toMatchObject({
|
|
421
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
it('resolves when deletion succeeds', async ()=>{
|
|
425
|
+
filesQueries.getSpaceFileId.mockResolvedValue(10);
|
|
426
|
+
commentQueries.deleteComment.mockResolvedValue(true);
|
|
427
|
+
await expect(commentsManager.deleteComment(user, makeSpace(), {
|
|
428
|
+
commentId: 1,
|
|
429
|
+
fileId: 10
|
|
430
|
+
})).resolves.toBeUndefined();
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
describe('getRecents', ()=>{
|
|
434
|
+
it('delegates to commentQueries.getRecentsFromUser', async ()=>{
|
|
435
|
+
const recents = [
|
|
436
|
+
{
|
|
437
|
+
id: 1
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
id: 2
|
|
441
|
+
}
|
|
442
|
+
];
|
|
443
|
+
commentQueries.getRecentsFromUser.mockResolvedValue(recents);
|
|
444
|
+
const res = await commentsManager.getRecents(user, 5);
|
|
445
|
+
expect(commentQueries.getRecentsFromUser).toHaveBeenCalledWith(user, 5);
|
|
446
|
+
expect(res).toBe(recents);
|
|
447
|
+
});
|
|
48
448
|
});
|
|
49
449
|
});
|
|
50
450
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/comments/services/comments-manager.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { CommentsManager } from './comments-manager.service'\nimport { CommentsQueries } from './comments-queries.service'\n\ndescribe(CommentsManager.name, () => {\n let service: CommentsManager\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: DB_TOKEN_PROVIDER,\n useValue: {}\n },\n { provide: Cache, useValue: {} },\n { provide: NotificationsManager, useValue: {} },\n ContextManager,\n CommentsManager,\n CommentsQueries,\n FilesQueries,\n SpacesQueries,\n SharesQueries\n ]\n }).compile()\n\n service = module.get<CommentsManager>(CommentsManager)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n})\n"],"names":["describe","CommentsManager","name","service","beforeAll","module","Test","createTestingModule","providers","provide","DB_TOKEN_PROVIDER","useValue","Cache","NotificationsManager","ContextManager","CommentsQueries","FilesQueries","SpacesQueries","SharesQueries","compile","get","it","expect","toBeDefined"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;8BACd;uCACS;2BACG;qCACL;6CACQ;sCACP;sCACA;wCACE;wCACA;AAEhCA,SAASC,uCAAe,CAACC,IAAI,EAAE;IAC7B,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACT;oBACEC,SAASC,4BAAiB;oBAC1BC,UAAU,CAAC;gBACb;gBACA;oBAAEF,SAASG,mBAAK;oBAAED,UAAU,CAAC;gBAAE;gBAC/B;oBAAEF,SAASI,iDAAoB;oBAAEF,UAAU,CAAC;gBAAE;gBAC9CG,qCAAc;gBACdb,uCAAe;gBACfc,uCAAe;gBACfC,iCAAY;gBACZC,mCAAa;gBACbC,mCAAa;aACd;QACH,GAAGC,OAAO;QAEVhB,UAAUE,OAAOe,GAAG,CAAkBnB,uCAAe;IACvD;IAEAoB,GAAG,qBAAqB;QACtBC,OAAOnB,SAASoB,WAAW;IAC7B;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/comments/services/comments-manager.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { HttpException, HttpStatus } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { dirName, fileName, getProps, isPathExists } from '../../files/utils/files'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { CommentsManager } from './comments-manager.service'\nimport { CommentsQueries } from './comments-queries.service'\n\n// Mocks of the file utilities used by the service\njest.mock('../../files/utils/files', () => ({\n isPathExists: jest.fn(),\n getProps: jest.fn(),\n dirName: jest.fn(),\n fileName: jest.fn()\n}))\n\ndescribe(CommentsManager.name, () => {\n let commentsManager: CommentsManager\n let contextManager: { get: jest.Mock }\n let commentQueries: {\n getComments: jest.Mock\n createComment: jest.Mock\n updateComment: jest.Mock\n deleteComment: jest.Mock\n getRecentsFromUser: jest.Mock\n membersToNotify: jest.Mock\n }\n let filesQueries: {\n getSpaceFileId: jest.Mock\n getOrCreateSpaceFile: jest.Mock\n }\n let notificationsManager: { create: jest.Mock }\n\n const user = { id: 42, email: 'john@doe.tld' } as any\n\n const makeSpace = (overrides: Partial<any> = {}) =>\n ({\n realPath: '/real/path',\n url: '/space/folder/file.txt',\n dbFile: {\n path: 'folder',\n ownerId: 42,\n spaceExternalRootId: null,\n shareExternalId: null\n },\n ...overrides\n }) as any\n\n beforeAll(async () => {\n commentQueries = {\n getComments: jest.fn(),\n createComment: jest.fn(),\n updateComment: jest.fn(),\n deleteComment: jest.fn(),\n getRecentsFromUser: jest.fn(),\n membersToNotify: jest.fn()\n }\n filesQueries = {\n getSpaceFileId: jest.fn(),\n getOrCreateSpaceFile: jest.fn()\n }\n notificationsManager = {\n create: jest.fn().mockResolvedValue(undefined)\n }\n contextManager = {\n get: jest.fn().mockReturnValue('https://app.local/path')\n }\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: DB_TOKEN_PROVIDER,\n useValue: {}\n },\n { provide: Cache, useValue: {} },\n { provide: NotificationsManager, useValue: notificationsManager },\n { provide: ContextManager, useValue: contextManager },\n { provide: CommentsManager, useClass: CommentsManager },\n { provide: CommentsQueries, useValue: commentQueries },\n { provide: FilesQueries, useValue: filesQueries },\n { provide: SpacesQueries, useValue: {} },\n { provide: SharesQueries, useValue: {} }\n ]\n }).compile()\n\n commentsManager = module.get<CommentsManager>(CommentsManager)\n })\n\n beforeEach(() => {\n jest.clearAllMocks()\n ;(isPathExists as jest.Mock).mockResolvedValue(true)\n ;(getProps as jest.Mock).mockResolvedValue({ name: 'file.txt', path: 'folder' })\n ;(dirName as jest.Mock).mockReturnValue('/space/folder')\n ;(fileName as jest.Mock).mockReturnValue('file.txt')\n })\n\n it('should be defined', () => {\n expect(commentsManager).toBeDefined()\n })\n\n describe('getComments', () => {\n it('returns [] if no fileId', async () => {\n filesQueries.getSpaceFileId.mockResolvedValue(0)\n\n const res = await commentsManager.getComments(user, makeSpace())\n\n expect(res).toEqual([])\n expect(filesQueries.getSpaceFileId).toHaveBeenCalledTimes(1)\n expect(commentQueries.getComments).not.toHaveBeenCalled()\n })\n\n it('returns comments if fileId is valid', async () => {\n filesQueries.getSpaceFileId.mockResolvedValue(123)\n const expected = [{ id: 1 }, { id: 2 }]\n commentQueries.getComments.mockResolvedValue(expected)\n\n const res = await commentsManager.getComments(user, makeSpace())\n\n expect(filesQueries.getSpaceFileId).toHaveBeenCalled()\n expect(commentQueries.getComments).toHaveBeenCalledWith(42, true, 123)\n expect(res).toBe(expected)\n })\n\n it('throws NOT_FOUND if path does not exist', async () => {\n ;(isPathExists as jest.Mock).mockResolvedValue(false)\n\n await expect(commentsManager.getComments(user, makeSpace())).rejects.toThrow(HttpException)\n await expect(commentsManager.getComments(user, makeSpace())).rejects.toMatchObject({ status: HttpStatus.NOT_FOUND })\n })\n })\n\n describe('createComment', () => {\n it(\"rejects on external root/share at path '.'\", async () => {\n const space = makeSpace({\n dbFile: { path: '.', ownerId: 42, spaceExternalRootId: 'ext', shareExternalId: null }\n })\n await expect(commentsManager.createComment(user, space, { fileId: 0, content: 'Hi' } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST\n })\n\n const space2 = makeSpace({\n dbFile: { path: '.', ownerId: 42, spaceExternalRootId: null, shareExternalId: 'shr' }\n })\n await expect(commentsManager.createComment(user, space2, { fileId: 0, content: 'Hi' } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST\n })\n })\n\n it('rejects BAD_REQUEST if provided fileId mismatches', async () => {\n filesQueries.getSpaceFileId.mockResolvedValue(100)\n\n await expect(commentsManager.createComment(user, makeSpace(), { fileId: 101, content: 'x' } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST\n })\n })\n\n it('uses getOrCreate when fileId < 0', async () => {\n filesQueries.getOrCreateSpaceFile.mockResolvedValue(555)\n commentQueries.createComment.mockResolvedValue(777)\n commentQueries.getComments.mockResolvedValue([{ id: 777, fileId: 555, content: 'hello' }])\n // Force a rejection in notify() to cover the catch attached to this.notify(...) in createComment\n commentQueries.membersToNotify.mockRejectedValueOnce(new Error('members failed'))\n const loggerSpy = jest.spyOn(commentsManager['logger'], 'error').mockImplementation(() => undefined as any)\n\n const res = await commentsManager.createComment(user, makeSpace(), { fileId: -1, content: 'hello' } as any)\n // Let the microtask run the catch of createComment\n await new Promise((r) => setImmediate(r))\n\n expect(filesQueries.getOrCreateSpaceFile).toHaveBeenCalled()\n expect(filesQueries.getSpaceFileId).not.toHaveBeenCalled()\n expect(commentQueries.createComment).toHaveBeenCalledWith(42, 555, 'hello')\n expect(notificationsManager.create).not.toHaveBeenCalled()\n expect(res).toEqual({ id: 777, fileId: 555, content: 'hello' })\n // Verify that the catch of createComment logged the error\n expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('createComment'))\n loggerSpy.mockRestore()\n })\n\n it('notifies members when present', async () => {\n filesQueries.getSpaceFileId.mockResolvedValue(10)\n commentQueries.createComment.mockResolvedValue(1)\n commentQueries.getComments.mockResolvedValue([{ id: 1, fileId: 10, content: 'c' }])\n commentQueries.membersToNotify.mockResolvedValue([{ id: 2, email: 'a@b.c' }])\n // Force rejection of notification creation to trigger the catch in notify()\n notificationsManager.create.mockRejectedValueOnce(new Error('notify failed'))\n const loggerSpy = jest.spyOn(commentsManager['logger'], 'error').mockImplementation(() => undefined as any)\n\n await commentsManager.createComment(user, makeSpace(), { fileId: 10, content: 'c' } as any)\n // Let the microtask execute the internal catch of notify()\n await new Promise((r) => setImmediate(r))\n\n expect(notificationsManager.create).toHaveBeenCalledTimes(1)\n notificationsManager.create.mockClear()\n expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('notify'))\n loggerSpy.mockRestore()\n\n const space = makeSpace()\n await commentsManager.createComment(user, space, { fileId: 10, content: 'c' } as any)\n\n expect(commentQueries.membersToNotify).toHaveBeenCalledWith(42, 10)\n expect(notificationsManager.create).toHaveBeenCalledTimes(1)\n const [members, notification, data] = notificationsManager.create.mock.calls[0]\n expect(members).toEqual([{ id: 2, email: 'a@b.c' }])\n expect(notification).toMatchObject({\n app: expect.anything(),\n event: expect.anything(),\n element: 'file.txt',\n url: '/space/folder'\n })\n expect(fileName).toHaveBeenCalledWith(space.url)\n expect(dirName).toHaveBeenCalledWith(space.url)\n expect(data).toMatchObject({\n author: user,\n currentUrl: 'https://app.local/path',\n content: 'c'\n })\n })\n\n it('logs an error if notificationsManager.create rejects (covers catch in notify)', async () => {\n filesQueries.getSpaceFileId.mockResolvedValue(10)\n commentQueries.createComment.mockResolvedValue(1)\n commentQueries.getComments.mockResolvedValue([{ id: 1, fileId: 10, content: 'c' }])\n commentQueries.membersToNotify.mockResolvedValue([{ id: 2, email: 'a@b.c' }])\n // Force rejection to trigger the catch in notify()\n notificationsManager.create.mockRejectedValueOnce(new Error('notify failed'))\n const loggerSpy = jest.spyOn(commentsManager['logger'], 'error').mockImplementation(() => undefined as any)\n\n await commentsManager.createComment(user, makeSpace(), { fileId: 10, content: 'c' } as any)\n // Allow the microtask to run the internal catch of notify()\n await new Promise((r) => setImmediate(r))\n\n expect(notificationsManager.create).toHaveBeenCalledTimes(1)\n expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('notify'))\n loggerSpy.mockRestore()\n })\n\n it('does not notify if no members', async () => {\n filesQueries.getSpaceFileId.mockResolvedValue(10)\n commentQueries.createComment.mockResolvedValue(1)\n commentQueries.getComments.mockResolvedValue([{ id: 1 }])\n commentQueries.membersToNotify.mockResolvedValue([])\n\n await commentsManager.createComment(user, makeSpace(), { fileId: 10, content: 'c' } as any)\n\n expect(notificationsManager.create).not.toHaveBeenCalled()\n })\n })\n\n describe('updateComment', () => {\n it('rejects NOT_FOUND if target comment is not found', async () => {\n commentQueries.getComments.mockResolvedValue([])\n\n await expect(commentsManager.updateComment(user, makeSpace(), { commentId: 99, fileId: 1, content: 'z' } as any)).rejects.toMatchObject({\n status: HttpStatus.NOT_FOUND\n })\n })\n\n it('rejects BAD_REQUEST if fileId mismatches', async () => {\n commentQueries.getComments.mockResolvedValue([{ id: 50, fileId: 123 }])\n filesQueries.getSpaceFileId.mockResolvedValue(999)\n\n await expect(commentsManager.updateComment(user, makeSpace(), { commentId: 50, fileId: 123, content: 'z' } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST\n })\n })\n\n it('rejects INTERNAL_SERVER_ERROR if update fails', async () => {\n commentQueries.getComments.mockResolvedValueOnce([{ id: 50, fileId: 5 }])\n filesQueries.getSpaceFileId.mockResolvedValue(5)\n commentQueries.updateComment.mockResolvedValue(false)\n\n await expect(commentsManager.updateComment(user, makeSpace(), { commentId: 50, fileId: 5, content: 'z' } as any)).rejects.toMatchObject({\n status: HttpStatus.INTERNAL_SERVER_ERROR\n })\n })\n\n it('returns the comment after update', async () => {\n commentQueries.getComments\n .mockResolvedValueOnce([{ id: 50, fileId: 5 }]) // initial fetch\n .mockResolvedValueOnce([{ id: 50, fileId: 5, content: 'updated' }]) // fetch after update -> include content\n filesQueries.getSpaceFileId.mockResolvedValue(5)\n commentQueries.updateComment.mockResolvedValue(true)\n\n const res = await commentsManager.updateComment(user, makeSpace(), { commentId: 50, fileId: 5, content: 'updated' } as any)\n\n expect(commentQueries.updateComment).toHaveBeenCalledWith(42, 50, 5, 'updated')\n // allow additional fields via toMatchObject\n expect(res).toMatchObject({ id: 50, fileId: 5, content: 'updated' })\n })\n })\n\n describe('deleteComment', () => {\n it('rejects BAD_REQUEST if fileId mismatches', async () => {\n filesQueries.getSpaceFileId.mockResolvedValue(10)\n\n await expect(commentsManager.deleteComment(user, makeSpace(), { commentId: 1, fileId: 11 } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST\n })\n })\n\n it('rejects FORBIDDEN if deletion is denied', async () => {\n filesQueries.getSpaceFileId.mockResolvedValue(10)\n commentQueries.deleteComment.mockResolvedValue(false)\n\n await expect(commentsManager.deleteComment(user, makeSpace(), { commentId: 1, fileId: 10 } as any)).rejects.toMatchObject({\n status: HttpStatus.FORBIDDEN\n })\n })\n\n it('resolves when deletion succeeds', async () => {\n filesQueries.getSpaceFileId.mockResolvedValue(10)\n commentQueries.deleteComment.mockResolvedValue(true)\n\n await expect(commentsManager.deleteComment(user, makeSpace(), { commentId: 1, fileId: 10 } as any)).resolves.toBeUndefined()\n })\n })\n\n describe('getRecents', () => {\n it('delegates to commentQueries.getRecentsFromUser', async () => {\n const recents = [{ id: 1 }, { id: 2 }]\n commentQueries.getRecentsFromUser.mockResolvedValue(recents)\n\n const res = await commentsManager.getRecents(user, 5)\n\n expect(commentQueries.getRecentsFromUser).toHaveBeenCalledWith(user, 5)\n expect(res).toBe(recents)\n })\n })\n})\n"],"names":["jest","mock","isPathExists","fn","getProps","dirName","fileName","describe","CommentsManager","name","commentsManager","contextManager","commentQueries","filesQueries","notificationsManager","user","id","email","makeSpace","overrides","realPath","url","dbFile","path","ownerId","spaceExternalRootId","shareExternalId","beforeAll","getComments","createComment","updateComment","deleteComment","getRecentsFromUser","membersToNotify","getSpaceFileId","getOrCreateSpaceFile","create","mockResolvedValue","undefined","get","mockReturnValue","module","Test","createTestingModule","providers","provide","DB_TOKEN_PROVIDER","useValue","Cache","NotificationsManager","ContextManager","useClass","CommentsQueries","FilesQueries","SpacesQueries","SharesQueries","compile","beforeEach","clearAllMocks","it","expect","toBeDefined","res","toEqual","toHaveBeenCalledTimes","not","toHaveBeenCalled","expected","toHaveBeenCalledWith","toBe","rejects","toThrow","HttpException","toMatchObject","status","HttpStatus","NOT_FOUND","space","fileId","content","BAD_REQUEST","space2","mockRejectedValueOnce","Error","loggerSpy","spyOn","mockImplementation","Promise","r","setImmediate","stringContaining","mockRestore","mockClear","members","notification","data","calls","app","anything","event","element","author","currentUrl","commentId","mockResolvedValueOnce","INTERNAL_SERVER_ERROR","FORBIDDEN","resolves","toBeUndefined","recents","getRecents"],"mappings":"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"}
|