Skip to content

Commit 16535a4

Browse files
authored
fix: Saving a new Parse.Object with an unsaved Parse.File fails (#1662)
1 parent 528ef08 commit 16535a4

File tree

4 files changed

+71
-7
lines changed

4 files changed

+71
-7
lines changed

integration/test/ParseFileTest.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,23 @@ describe('Parse.File', () => {
120120
assert.equal(e.code, Parse.Error.FILE_DELETE_ERROR);
121121
}
122122
});
123+
124+
it('can save file to localDatastore', async () => {
125+
Parse.enableLocalDatastore();
126+
const file = new Parse.File('parse-js-sdk', [61, 170, 236, 120]);
127+
const object = new Parse.Object('TestObject');
128+
await object.pin();
129+
130+
object.set('file', file);
131+
await object.save();
132+
133+
const query = new Parse.Query(TestObject);
134+
query.fromLocalDatastore();
135+
const results = await query.find();
136+
137+
const url = results[0].get('file').url();
138+
assert.equal(results.length, 1);
139+
assert.notEqual(url, undefined);
140+
assert.equal(url, file.url());
141+
});
123142
});

src/ParseObject.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,8 +2499,11 @@ const DefaultController = {
24992499
return Promise.reject(objectError);
25002500
}
25012501
for (const object of target) {
2502-
await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object);
2503-
await localDatastore._updateObjectIfPinned(object);
2502+
// Make sure that it is a ParseObject before updating it into the localDataStore
2503+
if (object instanceof ParseObject) {
2504+
await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object);
2505+
await localDatastore._updateObjectIfPinned(object);
2506+
}
25042507
}
25052508
return Promise.resolve(target);
25062509
});

src/__tests__/ParseFile-test.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,21 @@ const mockHttp = require('http');
1616
const mockHttps = require('https');
1717

1818
const mockLocalDatastore = {
19-
_updateLocalIdForObject: jest.fn(),
19+
_updateLocalIdForObject: jest.fn((localId, /** @type {ParseObject}*/ object) => {
20+
if (!mockLocalDatastore.isEnabled) {
21+
return;
22+
}
23+
/* eslint-disable no-unused-vars */
24+
// (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject
25+
const objectKey = mockLocalDatastore.getKeyForObject(object);
26+
}),
2027
_updateObjectIfPinned: jest.fn(),
28+
getKeyForObject: jest.fn((object) => {
29+
// (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject
30+
const OBJECT_PREFIX = 'Parse_LDS_';
31+
const objectId = object.objectId || object._getId();
32+
return `${OBJECT_PREFIX}${object.className}_${objectId}`;
33+
}),
2134
};
2235
jest.setMock('../LocalDatastore', mockLocalDatastore);
2336

@@ -37,6 +50,8 @@ const defaultController = CoreManager.getFileController();
3750

3851
describe('ParseFile', () => {
3952
beforeEach(() => {
53+
ParseObject.enableSingleInstance();
54+
jest.clearAllMocks();
4055
CoreManager.setFileController({
4156
saveFile: generateSaveMock('http://files.parsetfss.com/a/'),
4257
saveBase64: generateSaveMock('http://files.parsetfss.com/a/'),
@@ -945,4 +960,20 @@ describe('FileController', () => {
945960
}
946961
global.FileReader = fileReader;
947962
});
963+
964+
it('can save unsaved Parse.File property when localDataStore is enabled.', async () => {
965+
mockLocalDatastore.isEnabled = true;
966+
const obj = new ParseObject('Item');
967+
const aFile = new ParseFile('myFileName', [0, 0, 0, 0, 2, 3, 4, 5]);
968+
obj.set('myName', 'helloworld');
969+
obj.set('myFile', aFile);
970+
let error = undefined;
971+
try {
972+
await obj.save();
973+
} catch (e) {
974+
error = e;
975+
}
976+
expect(error).toBeUndefined();
977+
expect(obj.get('myFile').name()).toBe('myFileName');
978+
});
948979
});

src/__tests__/ParseObject-test.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,23 @@ const mockLocalDatastore = {
115115
_serializeObjectsFromPinName: jest.fn(),
116116
_serializeObject: jest.fn(),
117117
_transverseSerializeObject: jest.fn(),
118-
_updateObjectIfPinned: jest.fn(),
119118
_destroyObjectIfPinned: jest.fn(),
120-
_updateLocalIdForObject: jest.fn(),
121-
updateFromServer: jest.fn(),
119+
_updateLocalIdForObject: jest.fn((localId, /** @type {ParseObject}*/ object) => {
120+
if (!mockLocalDatastore.isEnabled) {
121+
return;
122+
}
123+
/* eslint-disable no-unused-vars */
124+
// (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject
125+
const objectKey = mockLocalDatastore.getKeyForObject(object);
126+
}),
127+
_updateObjectIfPinned: jest.fn(),
128+
getKeyForObject: jest.fn((object) => {
129+
// (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject
130+
const objectId = object.objectId || object._getId();
131+
const OBJECT_PREFIX = 'Parse_LDS_';
132+
return `${OBJECT_PREFIX}${object.className}_${objectId}`;
133+
}), updateFromServer: jest.fn(),
122134
_clear: jest.fn(),
123-
getKeyForObject: jest.fn(),
124135
checkIfEnabled: jest.fn(() => {
125136
if (!mockLocalDatastore.isEnabled) {
126137
console.error('Parse.enableLocalDatastore() must be called first');

0 commit comments

Comments
 (0)