mirror of
https://github.com/hanzoai/firebase-js-sdk.git
synced 2026-09-24 16:59:10 +00:00
607 lines
21 KiB
TypeScript
607 lines
21 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2022 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import { expect } from 'chai';
|
|
|
|
import {
|
|
apiDescribe,
|
|
toDataMap,
|
|
withTestCollection,
|
|
withTestDocAndInitialData
|
|
} from './util/helpers';
|
|
|
|
apiDescribe('GetOptions', (persistence: boolean) => {
|
|
it('get document while online with default get options', () => {
|
|
const initialData = { key: 'value' };
|
|
return withTestDocAndInitialData(persistence, initialData, docRef => {
|
|
return docRef.get().then(doc => {
|
|
expect(doc.exists).to.be.true;
|
|
expect(doc.metadata.fromCache).to.be.false;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
expect(doc.data()).to.deep.equal(initialData);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get collection while online with default get options', () => {
|
|
const initialDocs = {
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2' },
|
|
doc3: { key3: 'value3' }
|
|
};
|
|
return withTestCollection(persistence, initialDocs, colRef => {
|
|
return colRef.get().then(qrySnap => {
|
|
expect(qrySnap.metadata.fromCache).to.be.false;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.false;
|
|
expect(qrySnap.docChanges().length).to.equal(3);
|
|
expect(toDataMap(qrySnap)).to.deep.equal(initialDocs);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get document while offline with default get options', () => {
|
|
const initialData = { key: 'value' };
|
|
return withTestDocAndInitialData(persistence, initialData, docRef => {
|
|
// Register a snapshot to force the data to stay in the cache and not be
|
|
// garbage collected.
|
|
docRef.onSnapshot(() => {});
|
|
return docRef
|
|
.get()
|
|
.then(ignored => docRef.firestore.disableNetwork())
|
|
.then(() => docRef.get())
|
|
.then(doc => {
|
|
expect(doc.exists).to.be.true;
|
|
expect(doc.metadata.fromCache).to.be.true;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
expect(doc.data()).to.deep.equal(initialData);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get collection while offline with default get options', () => {
|
|
const initialDocs = {
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2' },
|
|
doc3: { key3: 'value3' }
|
|
};
|
|
return withTestCollection(persistence, initialDocs, colRef => {
|
|
// Register a snapshot to force the data to stay in the cache and not be
|
|
// garbage collected.
|
|
colRef.onSnapshot(() => {});
|
|
return colRef
|
|
.get()
|
|
.then(ignored => colRef.firestore.disableNetwork())
|
|
.then(() => {
|
|
// NB: since we're offline, the returned promises won't complete
|
|
/* eslint-disable @typescript-eslint/no-floating-promises */
|
|
colRef.doc('doc2').set({ key2b: 'value2b' }, { merge: true });
|
|
colRef.doc('doc3').set({ key3b: 'value3b' });
|
|
colRef.doc('doc4').set({ key4: 'value4' });
|
|
/* eslint-enable @typescript-eslint/no-floating-promises */
|
|
return colRef.get();
|
|
})
|
|
.then(qrySnap => {
|
|
expect(qrySnap.metadata.fromCache).to.be.true;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.true;
|
|
const docsData = toDataMap(qrySnap);
|
|
expect(qrySnap.docChanges().length).to.equal(4);
|
|
expect(docsData).to.deep.equal({
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2', key2b: 'value2b' },
|
|
doc3: { key3b: 'value3b' },
|
|
doc4: { key4: 'value4' }
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get document while online with source=cache', () => {
|
|
const initialData = { key: 'value' };
|
|
return withTestDocAndInitialData(persistence, initialData, docRef => {
|
|
// Register a snapshot to force the data to stay in the cache and not be
|
|
// garbage collected.
|
|
docRef.onSnapshot(() => {});
|
|
return docRef
|
|
.get()
|
|
.then(ignored => docRef.get({ source: 'cache' }))
|
|
.then(doc => {
|
|
expect(doc.exists).to.be.true;
|
|
expect(doc.metadata.fromCache).to.be.true;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
expect(doc.data()).to.deep.equal(initialData);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get collection while online with source=cache', () => {
|
|
const initialDocs = {
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2' },
|
|
doc3: { key3: 'value3' }
|
|
};
|
|
return withTestCollection(persistence, initialDocs, colRef => {
|
|
// Register a snapshot to force the data to stay in the cache and not be
|
|
// garbage collected.
|
|
colRef.onSnapshot(() => {});
|
|
return colRef
|
|
.get()
|
|
.then(ignored => colRef.get({ source: 'cache' }))
|
|
.then(qrySnap => {
|
|
expect(qrySnap.metadata.fromCache).to.be.true;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.false;
|
|
expect(qrySnap.docChanges().length).to.equal(3);
|
|
expect(toDataMap(qrySnap)).to.deep.equal(initialDocs);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get document while offline with source=cache', () => {
|
|
const initialData = { key: 'value' };
|
|
|
|
return withTestDocAndInitialData(persistence, initialData, docRef => {
|
|
// Register a snapshot to force the data to stay in the cache and not be
|
|
// garbage collected.
|
|
docRef.onSnapshot(() => {});
|
|
return docRef
|
|
.get()
|
|
.then(ignored => docRef.firestore.disableNetwork())
|
|
.then(() => docRef.get({ source: 'cache' }))
|
|
.then(doc => {
|
|
expect(doc.exists).to.be.true;
|
|
expect(doc.metadata.fromCache).to.be.true;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
expect(doc.data()).to.deep.equal(initialData);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get collection while offline with source=cache', () => {
|
|
const initialDocs = {
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2' },
|
|
doc3: { key3: 'value3' }
|
|
};
|
|
return withTestCollection(persistence, initialDocs, colRef => {
|
|
// Register a snapshot to force the data to stay in the cache and not be
|
|
// garbage collected.
|
|
colRef.onSnapshot(() => {});
|
|
return colRef
|
|
.get()
|
|
.then(ignored => colRef.firestore.disableNetwork())
|
|
.then(() => {
|
|
// NB: since we're offline, the returned promises won't complete
|
|
/* eslint-disable @typescript-eslint/no-floating-promises */
|
|
colRef.doc('doc2').set({ key2b: 'value2b' }, { merge: true });
|
|
colRef.doc('doc3').set({ key3b: 'value3b' });
|
|
colRef.doc('doc4').set({ key4: 'value4' });
|
|
/* eslint-enable @typescript-eslint/no-floating-promises */
|
|
|
|
return colRef.get({ source: 'cache' });
|
|
})
|
|
.then(qrySnap => {
|
|
expect(qrySnap.metadata.fromCache).to.be.true;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.true;
|
|
const docsData = toDataMap(qrySnap);
|
|
expect(qrySnap.docChanges().length).to.equal(4);
|
|
expect(docsData).to.deep.equal({
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2', key2b: 'value2b' },
|
|
doc3: { key3b: 'value3b' },
|
|
doc4: { key4: 'value4' }
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get document while online with source=server', () => {
|
|
const initialData = { key: 'value' };
|
|
return withTestDocAndInitialData(persistence, initialData, docRef => {
|
|
return docRef.get({ source: 'server' }).then(doc => {
|
|
expect(doc.exists).to.be.true;
|
|
expect(doc.metadata.fromCache).to.be.false;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
expect(doc.data()).to.deep.equal(initialData);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get collection while online with source=server', () => {
|
|
const initialDocs = {
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2' },
|
|
doc3: { key3: 'value3' }
|
|
};
|
|
return withTestCollection(persistence, initialDocs, colRef => {
|
|
return colRef.get({ source: 'server' }).then(qrySnap => {
|
|
expect(qrySnap.metadata.fromCache).to.be.false;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.false;
|
|
expect(qrySnap.docChanges().length).to.equal(3);
|
|
expect(toDataMap(qrySnap)).to.deep.equal(initialDocs);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get document while offline with source=server', () => {
|
|
const initialData = { key: 'value' };
|
|
return withTestDocAndInitialData(persistence, initialData, docRef => {
|
|
return docRef
|
|
.get({ source: 'server' })
|
|
.then(ignored => {})
|
|
.then(() => docRef.firestore.disableNetwork())
|
|
.then(() => docRef.get({ source: 'server' }))
|
|
.then(
|
|
doc => {
|
|
expect.fail();
|
|
},
|
|
expected => {}
|
|
);
|
|
});
|
|
});
|
|
|
|
it('get collection while offline with source=server', () => {
|
|
const initialDocs = {
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2' },
|
|
doc3: { key3: 'value3' }
|
|
};
|
|
return withTestCollection(persistence, initialDocs, colRef => {
|
|
// force local cache of these
|
|
return (
|
|
colRef
|
|
.get()
|
|
// now go offline. Note that if persistence is disabled, this will cause
|
|
// the initialDocs to be garbage collected.
|
|
.then(ignored => colRef.firestore.disableNetwork())
|
|
.then(() => colRef.get({ source: 'server' }))
|
|
.then(
|
|
qrySnap => {
|
|
expect.fail();
|
|
},
|
|
expected => {}
|
|
)
|
|
);
|
|
});
|
|
});
|
|
|
|
it('get document while offline with different get options', () => {
|
|
const initialData = { key: 'value' };
|
|
|
|
return withTestDocAndInitialData(persistence, initialData, docRef => {
|
|
// Register a snapshot to force the data to stay in the cache and not be
|
|
// garbage collected.
|
|
docRef.onSnapshot(() => {});
|
|
return docRef
|
|
.get()
|
|
.then(ignored => docRef.firestore.disableNetwork())
|
|
.then(() => {
|
|
// Create an initial listener for this query (to attempt to disrupt the
|
|
// gets below) and wait for the listener to deliver its initial
|
|
// snapshot before continuing.
|
|
return new Promise<void>((resolve, reject) => {
|
|
docRef.onSnapshot(
|
|
docSnap => {
|
|
resolve();
|
|
},
|
|
error => {
|
|
reject();
|
|
}
|
|
);
|
|
});
|
|
})
|
|
.then(() => docRef.get({ source: 'cache' }))
|
|
.then(doc => {
|
|
expect(doc.exists).to.be.true;
|
|
expect(doc.metadata.fromCache).to.be.true;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
expect(doc.data()).to.deep.equal(initialData);
|
|
return Promise.resolve();
|
|
})
|
|
.then(() => docRef.get())
|
|
.then(doc => {
|
|
expect(doc.exists).to.be.true;
|
|
expect(doc.metadata.fromCache).to.be.true;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
expect(doc.data()).to.deep.equal(initialData);
|
|
return Promise.resolve();
|
|
})
|
|
.then(() => docRef.get({ source: 'server' }))
|
|
.then(
|
|
doc => {
|
|
expect.fail();
|
|
},
|
|
expected => {}
|
|
);
|
|
});
|
|
});
|
|
|
|
it('get collection while offline with different get options', () => {
|
|
const initialDocs = {
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2' },
|
|
doc3: { key3: 'value3' }
|
|
};
|
|
return withTestCollection(persistence, initialDocs, colRef => {
|
|
// Register a snapshot to force the data to stay in the cache and not be
|
|
// garbage collected.
|
|
colRef.onSnapshot(() => {});
|
|
return (
|
|
colRef
|
|
.get()
|
|
// now go offline. Note that if persistence is disabled, this will cause
|
|
// the initialDocs to be garbage collected.
|
|
.then(ignored => colRef.firestore.disableNetwork())
|
|
.then(() => {
|
|
// NB: since we're offline, the returned promises won't complete
|
|
/* eslint-disable @typescript-eslint/no-floating-promises */
|
|
colRef.doc('doc2').set({ key2b: 'value2b' }, { merge: true });
|
|
colRef.doc('doc3').set({ key3b: 'value3b' });
|
|
colRef.doc('doc4').set({ key4: 'value4' });
|
|
/* eslint-enable @typescript-eslint/no-floating-promises */
|
|
|
|
// Create an initial listener for this query (to attempt to disrupt the
|
|
// gets below) and wait for the listener to deliver its initial
|
|
// snapshot before continuing.
|
|
return new Promise<void>((resolve, reject) => {
|
|
colRef.onSnapshot(
|
|
qrySnap => {
|
|
resolve();
|
|
},
|
|
error => {
|
|
reject();
|
|
}
|
|
);
|
|
});
|
|
})
|
|
.then(() => colRef.get({ source: 'cache' }))
|
|
.then(qrySnap => {
|
|
expect(qrySnap.metadata.fromCache).to.be.true;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.true;
|
|
const docsData = toDataMap(qrySnap);
|
|
expect(qrySnap.docChanges().length).to.equal(4);
|
|
expect(docsData).to.deep.equal({
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2', key2b: 'value2b' },
|
|
doc3: { key3b: 'value3b' },
|
|
doc4: { key4: 'value4' }
|
|
});
|
|
})
|
|
.then(() => colRef.get())
|
|
.then(qrySnap => {
|
|
expect(qrySnap.metadata.fromCache).to.be.true;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.true;
|
|
const docsData = toDataMap(qrySnap);
|
|
expect(qrySnap.docChanges().length).to.equal(4);
|
|
expect(docsData).to.deep.equal({
|
|
doc1: { key1: 'value1' },
|
|
doc2: { key2: 'value2', key2b: 'value2b' },
|
|
doc3: { key3b: 'value3b' },
|
|
doc4: { key4: 'value4' }
|
|
});
|
|
})
|
|
.then(() => colRef.get({ source: 'server' }))
|
|
.then(
|
|
qrySnap => {
|
|
expect.fail();
|
|
},
|
|
expected => {}
|
|
)
|
|
);
|
|
});
|
|
});
|
|
|
|
it('get nonexistent doc while online with default get options', () => {
|
|
return withTestDocAndInitialData(persistence, null, docRef => {
|
|
return docRef.get().then(doc => {
|
|
expect(doc.exists).to.be.false;
|
|
expect(doc.metadata.fromCache).to.be.false;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get nonexistent collection while online with default get options', () => {
|
|
return withTestCollection(persistence, {}, colRef => {
|
|
return colRef.get().then(qrySnap => {
|
|
//expect(qrySnap.count).to.equal(0);
|
|
expect(qrySnap.empty).to.be.true;
|
|
expect(qrySnap.docChanges().length).to.equal(0);
|
|
expect(qrySnap.metadata.fromCache).to.be.false;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get nonexistent doc while offline with default get options', () => {
|
|
return withTestDocAndInitialData(persistence, null, docRef => {
|
|
return (
|
|
docRef.firestore
|
|
.disableNetwork()
|
|
// Attempt to get doc. This will fail since there's nothing in cache.
|
|
.then(() => docRef.get())
|
|
.then(
|
|
doc => {
|
|
expect.fail();
|
|
},
|
|
expected => {}
|
|
)
|
|
);
|
|
});
|
|
});
|
|
|
|
// TODO(b/112267729): We should raise a fromCache=true event with a
|
|
// nonexistent snapshot, but because the default source goes through a normal
|
|
// listener, we do not.
|
|
// eslint-disable-next-line no-restricted-properties
|
|
it.skip('get deleted doc while offline with default get options', () => {
|
|
return withTestDocAndInitialData(persistence, null, docRef => {
|
|
return docRef
|
|
.delete()
|
|
.then(() => docRef.firestore.disableNetwork())
|
|
.then(() => docRef.get())
|
|
.then(doc => {
|
|
expect(doc.exists).to.be.false;
|
|
expect(doc.data()).to.be.undefined;
|
|
expect(doc.metadata.fromCache).to.be.true;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get nonexistent collection while offline with default get options', () => {
|
|
return withTestCollection(persistence, {}, colRef => {
|
|
return colRef.firestore
|
|
.disableNetwork()
|
|
.then(() => colRef.get())
|
|
.then(qrySnap => {
|
|
expect(qrySnap.empty).to.be.true;
|
|
expect(qrySnap.docChanges().length).to.equal(0);
|
|
expect(qrySnap.metadata.fromCache).to.be.true;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get nonexistent doc while online with source=cache', () => {
|
|
return withTestDocAndInitialData(persistence, null, docRef => {
|
|
// Attempt to get doc. This will fail since there's nothing in cache.
|
|
return docRef.get({ source: 'cache' }).then(
|
|
doc => {
|
|
expect.fail();
|
|
},
|
|
expected => {}
|
|
);
|
|
});
|
|
});
|
|
|
|
it('get nonexistent collection while online with source=cache', () => {
|
|
return withTestCollection(persistence, {}, colRef => {
|
|
return colRef.get({ source: 'cache' }).then(qrySnap => {
|
|
expect(qrySnap.empty).to.be.true;
|
|
expect(qrySnap.docChanges().length).to.equal(0);
|
|
expect(qrySnap.metadata.fromCache).to.be.true;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get nonexistent doc while offline with source=cache', () => {
|
|
return withTestDocAndInitialData(persistence, null, docRef => {
|
|
return (
|
|
docRef.firestore
|
|
.disableNetwork()
|
|
// Attempt to get doc. This will fail since there's nothing in cache.
|
|
.then(() => docRef.get({ source: 'cache' }))
|
|
.then(
|
|
doc => {
|
|
expect.fail();
|
|
},
|
|
expected => {}
|
|
)
|
|
);
|
|
});
|
|
});
|
|
|
|
// We need the deleted doc to stay in cache, so only run this with persistence.
|
|
// eslint-disable-next-line no-restricted-properties,
|
|
(persistence ? it : it.skip)(
|
|
'get deleted doc while offline with source=cache',
|
|
() => {
|
|
return withTestDocAndInitialData(persistence, null, docRef => {
|
|
return (
|
|
docRef
|
|
.delete()
|
|
.then(() => docRef.firestore.disableNetwork())
|
|
// Should get a document with exists=false, fromCache=true
|
|
.then(() => docRef.get({ source: 'cache' }))
|
|
.then(doc => {
|
|
expect(doc.exists).to.be.false;
|
|
expect(doc.data()).to.be.undefined;
|
|
expect(doc.metadata.fromCache).to.be.true;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
})
|
|
);
|
|
});
|
|
}
|
|
);
|
|
|
|
it('get nonexistent collection while offline with source=cache', () => {
|
|
return withTestCollection(persistence, {}, colRef => {
|
|
return colRef.firestore
|
|
.disableNetwork()
|
|
.then(() => colRef.get({ source: 'cache' }))
|
|
.then(qrySnap => {
|
|
expect(qrySnap.empty).to.be.true;
|
|
expect(qrySnap.docChanges().length).to.equal(0);
|
|
expect(qrySnap.metadata.fromCache).to.be.true;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get nonexistent doc while online with source=server', () => {
|
|
return withTestDocAndInitialData(persistence, null, docRef => {
|
|
return docRef.get({ source: 'server' }).then(doc => {
|
|
expect(doc.exists).to.be.false;
|
|
expect(doc.metadata.fromCache).to.be.false;
|
|
expect(doc.metadata.hasPendingWrites).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get nonexistent collection while online with source=server', () => {
|
|
return withTestCollection(persistence, {}, colRef => {
|
|
return colRef.get({ source: 'server' }).then(qrySnap => {
|
|
expect(qrySnap.empty).to.be.true;
|
|
expect(qrySnap.docChanges().length).to.equal(0);
|
|
expect(qrySnap.metadata.fromCache).to.be.false;
|
|
expect(qrySnap.metadata.hasPendingWrites).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
|
|
it('get nonexistent doc while offline with source=server', () => {
|
|
return withTestDocAndInitialData(persistence, null, docRef => {
|
|
return (
|
|
docRef.firestore
|
|
.disableNetwork()
|
|
// Attempt to get doc. This will fail since there's nothing in cache.
|
|
.then(() => docRef.get({ source: 'server' }))
|
|
.then(
|
|
doc => {
|
|
expect.fail();
|
|
},
|
|
expected => {}
|
|
)
|
|
);
|
|
});
|
|
});
|
|
|
|
it('get nonexistent collection while offline with source=server', () => {
|
|
return withTestCollection(persistence, {}, colRef => {
|
|
return colRef.firestore
|
|
.disableNetwork()
|
|
.then(() => colRef.get({ source: 'server' }))
|
|
.then(
|
|
qrySnap => {
|
|
expect.fail();
|
|
},
|
|
expected => {}
|
|
);
|
|
});
|
|
});
|
|
});
|