cozy-pouch-link 60.24.0 → 60.24.2
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/dist/PouchManager.spec.js +1 -1
- package/dist/files.js +8 -4
- package/dist/files.spec.js +25 -0
- package/dist/jsonapi.js +3 -3
- package/dist/jsonapi.spec.js +31 -0
- package/dist/replicateOnce.js +3 -1
- package/dist/replicateOnce.spec.js +104 -0
- package/package.json +2 -2
|
@@ -235,7 +235,7 @@ describe('PouchManager', () => {
|
|
|
235
235
|
manager.updateSyncInfo('io.cozy.todos')
|
|
236
236
|
await manager.replicateOnce()
|
|
237
237
|
expect(onSync).toHaveBeenCalledWith({
|
|
238
|
-
'
|
|
238
|
+
'io.cozy.todos': [
|
|
239
239
|
{
|
|
240
240
|
_id: '1',
|
|
241
241
|
name: 'Make replication work'
|
package/dist/files.js
CHANGED
|
@@ -23,19 +23,23 @@ exports.TYPE_FILE = TYPE_FILE;
|
|
|
23
23
|
|
|
24
24
|
var queryFileById = /*#__PURE__*/function () {
|
|
25
25
|
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(client, id) {
|
|
26
|
-
var
|
|
26
|
+
var definition, options;
|
|
27
27
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
28
28
|
while (1) {
|
|
29
29
|
switch (_context.prev = _context.next) {
|
|
30
30
|
case 0:
|
|
31
|
-
|
|
31
|
+
definition = (0, _cozyClient.Q)('io.cozy.files').getById(id);
|
|
32
|
+
options = {
|
|
32
33
|
as: "io.cozy.files/".concat(id),
|
|
33
34
|
fetchPolicy: defaultFetchPolicy,
|
|
34
35
|
singleDocData: true
|
|
35
36
|
};
|
|
36
|
-
return _context.abrupt("return", client.
|
|
37
|
+
return _context.abrupt("return", client.fetchQueryAndGetFromState({
|
|
38
|
+
definition: definition,
|
|
39
|
+
options: options
|
|
40
|
+
}));
|
|
37
41
|
|
|
38
|
-
case
|
|
42
|
+
case 3:
|
|
39
43
|
case "end":
|
|
40
44
|
return _context.stop();
|
|
41
45
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Q } from 'cozy-client'
|
|
2
|
+
|
|
3
|
+
import { queryFileById } from './files'
|
|
4
|
+
|
|
5
|
+
describe('queryFileById', () => {
|
|
6
|
+
it('should call client.fetchQueryAndGetFromState with the expected definition and options', async () => {
|
|
7
|
+
const expectedResult = { data: { _id: 'parent', path: '/parent' } }
|
|
8
|
+
const client = {
|
|
9
|
+
fetchQueryAndGetFromState: jest.fn().mockResolvedValue(expectedResult)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const res = await queryFileById(client, 'parent')
|
|
13
|
+
|
|
14
|
+
expect(res).toBe(expectedResult)
|
|
15
|
+
expect(client.fetchQueryAndGetFromState).toHaveBeenCalledTimes(1)
|
|
16
|
+
expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
|
|
17
|
+
definition: expect.objectContaining(Q('io.cozy.files').getById('parent')),
|
|
18
|
+
options: {
|
|
19
|
+
as: 'io.cozy.files/parent',
|
|
20
|
+
fetchPolicy: expect.any(Function),
|
|
21
|
+
singleDocData: true
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
})
|
package/dist/jsonapi.js
CHANGED
|
@@ -167,7 +167,7 @@ var buildPathWithName = function buildPathWithName(parentPath, fileName) {
|
|
|
167
167
|
|
|
168
168
|
var computeFileFullpath = /*#__PURE__*/function () {
|
|
169
169
|
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(client, file) {
|
|
170
|
-
var _file$path, newPath, filePath, parentPath, builtPath, path,
|
|
170
|
+
var _file$path, newPath, filePath, parentPath, builtPath, path, result, parentDir, _path;
|
|
171
171
|
|
|
172
172
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
173
173
|
while (1) {
|
|
@@ -246,8 +246,8 @@ var computeFileFullpath = /*#__PURE__*/function () {
|
|
|
246
246
|
return (0, _files.queryFileById)(client, file.dir_id);
|
|
247
247
|
|
|
248
248
|
case 27:
|
|
249
|
-
|
|
250
|
-
parentDir =
|
|
249
|
+
result = _context.sent;
|
|
250
|
+
parentDir = result === null || result === void 0 ? void 0 : result.data;
|
|
251
251
|
|
|
252
252
|
if (parentDir !== null && parentDir !== void 0 && parentDir.path) {
|
|
253
253
|
_path = buildPathWithName(parentDir.path, file.name);
|
package/dist/jsonapi.spec.js
CHANGED
|
@@ -719,4 +719,35 @@ describe('computeFileFullpath', () => {
|
|
|
719
719
|
const res2 = await computeFileFullpath(client, updFile)
|
|
720
720
|
expect(res2.path).toEqual('ROOT/MYDIR/file3.1')
|
|
721
721
|
})
|
|
722
|
+
|
|
723
|
+
it('should return the file unchanged when queryFileById resolves to undefined', async () => {
|
|
724
|
+
// This happens offline when the link chain returns nothing for the
|
|
725
|
+
// parent dir lookup. Before the fix, destructuring `.data` from
|
|
726
|
+
// `undefined` crashed with "Cannot read property 'data' of undefined".
|
|
727
|
+
queryFileById.mockResolvedValue(undefined)
|
|
728
|
+
const file = {
|
|
729
|
+
_id: 'offline-file-1',
|
|
730
|
+
_type: 'io.cozy.files',
|
|
731
|
+
type: 'file',
|
|
732
|
+
dir_id: 'unknown-dir',
|
|
733
|
+
name: 'offline.txt'
|
|
734
|
+
}
|
|
735
|
+
const res = await computeFileFullpath(client, file)
|
|
736
|
+
expect(res).toBe(file)
|
|
737
|
+
expect(res.path).toBeUndefined()
|
|
738
|
+
})
|
|
739
|
+
|
|
740
|
+
it('should return the file unchanged when queryFileById resolves with null data', async () => {
|
|
741
|
+
queryFileById.mockResolvedValue({ data: null })
|
|
742
|
+
const file = {
|
|
743
|
+
_id: 'offline-file-2',
|
|
744
|
+
_type: 'io.cozy.files',
|
|
745
|
+
type: 'file',
|
|
746
|
+
dir_id: 'unknown-dir',
|
|
747
|
+
name: 'offline2.txt'
|
|
748
|
+
}
|
|
749
|
+
const res = await computeFileFullpath(client, file)
|
|
750
|
+
expect(res).toBe(file)
|
|
751
|
+
expect(res.path).toBeUndefined()
|
|
752
|
+
})
|
|
722
753
|
})
|
package/dist/replicateOnce.js
CHANGED
|
@@ -176,7 +176,9 @@ var replicateOnce = /*#__PURE__*/function () {
|
|
|
176
176
|
};
|
|
177
177
|
}()); // Waiting on each replication
|
|
178
178
|
|
|
179
|
-
doctypes = Object.keys(pouchManager.pouches)
|
|
179
|
+
doctypes = Object.keys(pouchManager.pouches).map(function (dbName) {
|
|
180
|
+
return (0, _utils.getDoctypeFromDatabaseName)(dbName);
|
|
181
|
+
});
|
|
180
182
|
promises = Object.values(pouchManager.replications);
|
|
181
183
|
_context2.prev = 9;
|
|
182
184
|
_context2.next = 12;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* global jest */
|
|
2
|
+
|
|
3
|
+
jest.mock('./remote', () => ({
|
|
4
|
+
fetchRemoteLastSequence: jest.fn().mockResolvedValue('0'),
|
|
5
|
+
isDatabaseNotFoundError: jest.fn().mockReturnValue(false),
|
|
6
|
+
isDatabaseUnradableError: jest.fn().mockReturnValue(false)
|
|
7
|
+
}))
|
|
8
|
+
|
|
9
|
+
jest.mock('./startReplication', () => ({
|
|
10
|
+
startReplication: jest.fn()
|
|
11
|
+
}))
|
|
12
|
+
|
|
13
|
+
import { replicateOnce } from './replicateOnce'
|
|
14
|
+
import { startReplication } from './startReplication'
|
|
15
|
+
|
|
16
|
+
describe('replicateOnce', () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
jest.clearAllMocks()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should call onSync with clean doctype keys, not prefixed pouch dbNames', async () => {
|
|
22
|
+
const dbName = 'instance__doctype__io.cozy.todos'
|
|
23
|
+
const docs = [{ _id: 'doc-1', name: 'a' }]
|
|
24
|
+
|
|
25
|
+
startReplication.mockResolvedValue(docs)
|
|
26
|
+
|
|
27
|
+
const pouchManager = {
|
|
28
|
+
pouches: { [dbName]: { id: 'fake-pouch' } },
|
|
29
|
+
replications: {},
|
|
30
|
+
doctypesReplicationOptions: {},
|
|
31
|
+
options: {
|
|
32
|
+
onSync: jest.fn()
|
|
33
|
+
},
|
|
34
|
+
storage: {
|
|
35
|
+
persistDoctypeLastSequence: jest.fn().mockResolvedValue(),
|
|
36
|
+
getDoctypeLastSequence: jest.fn().mockResolvedValue(''),
|
|
37
|
+
destroyDoctypeLastSequence: jest.fn().mockResolvedValue()
|
|
38
|
+
},
|
|
39
|
+
client: {},
|
|
40
|
+
isOnline: jest.fn().mockResolvedValue(true),
|
|
41
|
+
getReplicationURL: jest.fn().mockReturnValue('http://example/db'),
|
|
42
|
+
getSyncStatus: jest.fn().mockReturnValue('synced'),
|
|
43
|
+
updateSyncInfo: jest.fn().mockResolvedValue(),
|
|
44
|
+
checkToWarmupDoctype: jest.fn(),
|
|
45
|
+
handleReplicationError: jest.fn(),
|
|
46
|
+
cancelCurrentReplications: jest.fn()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await replicateOnce(pouchManager)
|
|
50
|
+
|
|
51
|
+
expect(pouchManager.options.onSync).toHaveBeenCalledTimes(1)
|
|
52
|
+
const payload = pouchManager.options.onSync.mock.calls[0][0]
|
|
53
|
+
|
|
54
|
+
// The bug: payload was keyed by the full prefixed dbName
|
|
55
|
+
// The fix: payload must be keyed by the clean doctype
|
|
56
|
+
expect(Object.keys(payload)).toEqual(['io.cozy.todos'])
|
|
57
|
+
expect(Object.keys(payload)).not.toContain(dbName)
|
|
58
|
+
expect(payload['io.cozy.todos']).toEqual(docs)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('should preserve clean doctype keys for multiple pouches', async () => {
|
|
62
|
+
const dbNameA = 'instance__doctype__io.cozy.todos'
|
|
63
|
+
const dbNameB = 'instance__doctype__io.cozy.files'
|
|
64
|
+
const docsA = [{ _id: 'a1' }]
|
|
65
|
+
const docsB = [{ _id: 'b1' }]
|
|
66
|
+
|
|
67
|
+
startReplication.mockImplementation(pouch => {
|
|
68
|
+
if (pouch === 'pouchA') return Promise.resolve(docsA)
|
|
69
|
+
if (pouch === 'pouchB') return Promise.resolve(docsB)
|
|
70
|
+
return Promise.resolve([])
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const pouchManager = {
|
|
74
|
+
pouches: { [dbNameA]: 'pouchA', [dbNameB]: 'pouchB' },
|
|
75
|
+
replications: {},
|
|
76
|
+
doctypesReplicationOptions: {},
|
|
77
|
+
options: { onSync: jest.fn() },
|
|
78
|
+
storage: {
|
|
79
|
+
persistDoctypeLastSequence: jest.fn().mockResolvedValue(),
|
|
80
|
+
getDoctypeLastSequence: jest.fn().mockResolvedValue(''),
|
|
81
|
+
destroyDoctypeLastSequence: jest.fn().mockResolvedValue()
|
|
82
|
+
},
|
|
83
|
+
client: {},
|
|
84
|
+
isOnline: jest.fn().mockResolvedValue(true),
|
|
85
|
+
getReplicationURL: jest.fn().mockReturnValue('http://example/db'),
|
|
86
|
+
getSyncStatus: jest.fn().mockReturnValue('synced'),
|
|
87
|
+
updateSyncInfo: jest.fn().mockResolvedValue(),
|
|
88
|
+
checkToWarmupDoctype: jest.fn(),
|
|
89
|
+
handleReplicationError: jest.fn(),
|
|
90
|
+
cancelCurrentReplications: jest.fn()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
await replicateOnce(pouchManager)
|
|
94
|
+
|
|
95
|
+
expect(pouchManager.options.onSync).toHaveBeenCalledTimes(1)
|
|
96
|
+
const payload = pouchManager.options.onSync.mock.calls[0][0]
|
|
97
|
+
expect(Object.keys(payload).sort()).toEqual([
|
|
98
|
+
'io.cozy.files',
|
|
99
|
+
'io.cozy.todos'
|
|
100
|
+
])
|
|
101
|
+
expect(payload['io.cozy.todos']).toEqual(docsA)
|
|
102
|
+
expect(payload['io.cozy.files']).toEqual(docsB)
|
|
103
|
+
})
|
|
104
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-pouch-link",
|
|
3
|
-
"version": "60.24.
|
|
3
|
+
"version": "60.24.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"typecheck": "tsc -p tsconfig.json"
|
|
42
42
|
},
|
|
43
43
|
"sideEffects": false,
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "e621858d1b3d16f79d75bb79d3f183d204f2eabe"
|
|
45
45
|
}
|