Files
6434c30541 Repo refactoring (#5345)
* Split storage and storage-compat (#5271)

* separate storage-compat from storage

* commit

* fix tests

* wat?

* build storage-compat

* save

* fixing some compat tests

* format

* update import path

* format

* get compat tests to work

* format

* update package json

* cleanup

* format

* address comments

* Update packages/storage-compat/test/unit/service.test.ts

Co-authored-by: Christina Holland <[email protected]>

* add missing dev dep

* Update packages/storage-compat/package.json

* Update packages/storage-compat/package.json

* Update deps after v8 release

* update compat version

* Split database and database-compat (#5276)

* compile database

* pass database tests

* compile and test database-compat

* pass all tests

* prettier

* cleanup

* fix lint

* address comments

* what is going on with ci

* use correct case in import path

* uppercase

* rename

* fix component name

* Repo refactoring for v9 (#5325)

* rename folders

* rename folders

* migrate app and app-compat

* migrate installations and analytics

* migrate app check

* migrate auth

* migrate functions

* migrate messaging

* migrate performance

* migrate remoteconfig

* remove v8 code

* update versions

* migrate firebase

* fix merge issues

* save

* fix firebase builds

* update changeset config

* update build scripts

* update release script

* fix functions typings

* remove redundant typings

* update path

* treat external dependencies correctly

* fix lint

* remove firestore-compat references

* fix build issues

* update build scripts

* update pkg json

* fix test

* fix some tests

* fix some tests

* fix integration tests

* fixes

* fix dep

* update ci tests

* resolve todos

* remove exp references

* docgen build

* export FirebaseError (#5349)

* firebase packaging update (#5348)

* Fei v9 main firestore (#5319)

* compile firestore

* update typings path

* compile firestore compat

* lint compat

* make test work

* get most tests work

* build

* remove special paths

* update firestore-compat pkg json

* fix merge issues

* Simplify bundles

* Prettier

* Fix Bundle compile

* Fix build

* address comments

* console build

* Fix all tests

* Prettier

* fix merge issues

* fix typo

* update paths

* app-exp

* fix lint

* correct path

* fix

* fix compat lint

* fix firestore integration

* fix workflow

* update dep

* Always block on Auth (#5340)

* Always block on Auth

* Don't block on token if already recevied

* fix lint

* build firestore

* remove memory only tests

* fix firebase integration tests

* enable more build and tests

* add firestore-compat to firebase dep

* fix auth compat class

* enable auth test

* auth package doc

* Update API reports

Co-authored-by: Sebastian Schmidt <[email protected]>
Co-authored-by: Feiyang1 <[email protected]>

* rebasing

* Create registerMessagingCompat.ts

* Add changeset for v9 (#5350)

* add changeset

* publish messaging interop

* add firestore bumps

* update changeset

* Revert "Create registerMessagingCompat.ts"

This reverts commit 0b95a5167e403ffc0dbcd9dd7dcb7cda754e510d.

* Revert "rebasing"

This reverts commit a8bf697157aaa29e8450acb626aae81ad5b542e1.

* Update index.d.ts (#5355)

* Fix Context Check in `Messaging-Compat` (#5353)

* Add Rules Unit Testing v2 skeleton for v9 release (#5352)

* Reset package for next major version.

* Switch emulator script to node-fetch.

* Migrate the other request call to fetch.

* Update packages/rules-unit-testing/package.json

Co-authored-by: Feiyang <[email protected]>

* Create stale-ducks-live.md

* Revert version change.

Co-authored-by: Feiyang <[email protected]>

* fix import path (#5356)

* Add new types and function stubs for RUT vNext. (#5316)

* Add new types and function stubs.

* Fix types for testEnv.emulators.

* Add util functions.

* Add withFunctionTriggersDisabled overloads.

* Improve typing for EmulatorConfig.

* Fix tests.

* Rename test_environment.ts to initialize.ts.

* Add a dummy test to make CI pass.

* Implement emulators discovery in RUTv2. (#5334)

* Add new types and function stubs.

* Fix types for testEnv.emulators.

* Add util functions.

* Add withFunctionTriggersDisabled overloads.

* Improve typing for EmulatorConfig.

* Fix tests.

* Rename test_environment.ts to initialize.ts.

* Add a dummy test to make CI pass.

* Implement emulators discovery.

* Use URL object from global.

* Fix unreachable  error code.

* Implement most of RUTv2 features. (#5343)

* Implement most of RUTv2 features.

* Switch to compat instances.

* Remove legacy code.

* Use public typings for release (#5358)

* use public typings for storage

* use public typings for database

* Implement rest of RUTv2 features. (#5360)

* Implement loading rules and withFunctionTriggersDisabled.

* Implement clearFirestore and storage.

* Add missing await.

* Add default bucketUrl.

* Use alternative method to clear bucket.

* Use default param (review feedback).

* Storage typing updates (#5359)

* rename to StorageError

* more type safety

* Update API reports

* update api report

Co-authored-by: Feiyang1 <[email protected]>

* correct component name

* fix installtions-compat typing

* remove rules-unit-testing from ignore list

* reenable things

* support mjs files

* correct matching pattern

* transform only @firebase/util

* use public types for database doc

* transform all but compat packages

Co-authored-by: Sebastian Schmidt <[email protected]>
Co-authored-by: Feiyang1 <[email protected]>
Co-authored-by: kai <[email protected]>
Co-authored-by: Yuchen Shi <[email protected]>
Co-authored-by: Kai Wu <[email protected]>
2021-08-24 13:56:01 -07:00

531 lines
13 KiB
TypeScript

/**
* @license
* Copyright 2017 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 { EventAccumulatorFactory } from '../../database/test/helpers/EventAccumulator';
import { Reference } from '../src/api/Reference';
import { getRandomNode } from './helpers/util';
describe('.orderBy tests', () => {
// TODO: setup spy on console.warn
const clearRef = getRandomNode() as Reference;
it('Snapshots are iterated in order', () => {
const ref = getRandomNode() as Reference;
const initial = {
alex: { nuggets: 60 },
rob: { nuggets: 56 },
vassili: { nuggets: 55.5 },
tony: { nuggets: 52 },
greg: { nuggets: 52 }
};
const expectedOrder = ['greg', 'tony', 'vassili', 'rob', 'alex'];
const expectedPrevNames = [null, 'greg', 'tony', 'vassili', 'rob'];
const valueOrder = [];
const addedOrder = [];
const addedPrevNames = [];
const orderedRef = ref.orderByChild('nuggets');
orderedRef.on('value', snap => {
snap.forEach(childSnap => {
valueOrder.push(childSnap.key);
});
});
orderedRef.on('child_added', (snap, prevName) => {
addedOrder.push(snap.key);
addedPrevNames.push(prevName);
});
ref.set(initial);
expect(addedOrder).to.deep.equal(expectedOrder);
expect(valueOrder).to.deep.equal(expectedOrder);
expect(addedPrevNames).to.deep.equal(expectedPrevNames);
});
it('Snapshots are iterated in order for value', () => {
const ref = getRandomNode() as Reference;
const initial = {
alex: 60,
rob: 56,
vassili: 55.5,
tony: 52,
greg: 52
};
const expectedOrder = ['greg', 'tony', 'vassili', 'rob', 'alex'];
const expectedPrevNames = [null, 'greg', 'tony', 'vassili', 'rob'];
const valueOrder = [];
const addedOrder = [];
const addedPrevNames = [];
const orderedRef = ref.orderByValue();
orderedRef.on('value', snap => {
snap.forEach(childSnap => {
valueOrder.push(childSnap.key);
});
});
orderedRef.on('child_added', (snap, prevName) => {
addedOrder.push(snap.key);
addedPrevNames.push(prevName);
});
ref.set(initial);
expect(addedOrder).to.deep.equal(expectedOrder);
expect(valueOrder).to.deep.equal(expectedOrder);
expect(addedPrevNames).to.deep.equal(expectedPrevNames);
});
it('Fires child_moved events', () => {
const ref = getRandomNode() as Reference;
const initial = {
alex: { nuggets: 60 },
rob: { nuggets: 56 },
vassili: { nuggets: 55.5 },
tony: { nuggets: 52 },
greg: { nuggets: 52 }
};
const orderedRef = ref.orderByChild('nuggets');
let moved = false;
orderedRef.on('child_moved', (snap, prevName) => {
moved = true;
expect(snap.key).to.equal('greg');
expect(prevName).to.equal('rob');
expect(snap.val()).to.deep.equal({ nuggets: 57 });
});
ref.set(initial);
ref.child('greg/nuggets').set(57);
expect(moved).to.equal(true);
});
it('Callback removal works', async () => {
const ref = getRandomNode() as Reference;
let reads = 0;
const ea = EventAccumulatorFactory.waitsForCount(4);
const fooCb = ref.orderByChild('foo').on('value', () => {
reads++;
ea.addEvent();
});
const barCb = ref.orderByChild('bar').on('value', () => {
reads++;
ea.addEvent();
});
const bazCb = ref.orderByChild('baz').on('value', () => {
reads++;
ea.addEvent();
});
ref.on('value', () => {
reads++;
ea.addEvent();
});
ref.set(1);
await ea.promise;
ref.off('value', fooCb);
ref.set(2);
expect(reads).to.equal(7);
// Should be a no-op, resulting in 3 more reads
ref.orderByChild('foo').off('value', bazCb);
ref.set(3);
expect(reads).to.equal(10);
ref.orderByChild('bar').off('value');
ref.set(4);
expect(reads).to.equal(12);
// Now, remove everything
ref.off();
ref.set(5);
expect(reads).to.equal(12);
});
it('child_added events are in the correct order', () => {
const ref = getRandomNode() as Reference;
const initial = {
a: { value: 5 },
c: { value: 3 }
};
const added = [];
ref.orderByChild('value').on('child_added', snap => {
added.push(snap.key);
});
ref.set(initial);
expect(added).to.deep.equal(['c', 'a']);
ref.update({
b: { value: 4 },
d: { value: 2 }
});
expect(added).to.deep.equal(['c', 'a', 'd', 'b']);
});
it('Can use key index', async () => {
const ref = getRandomNode() as Reference;
const data = {
a: { '.priority': 10, '.value': 'a' },
b: { '.priority': 5, '.value': 'b' },
c: { '.priority': 20, '.value': 'c' },
d: { '.priority': 7, '.value': 'd' },
e: { '.priority': 30, '.value': 'e' },
f: { '.priority': 8, '.value': 'f' }
};
await ref.set(data);
const snap = await ref.orderByKey().startAt('c').once('value');
let keys = [];
snap.forEach(child => {
keys.push(child.key);
});
expect(keys).to.deep.equal(['c', 'd', 'e', 'f']);
const ea = EventAccumulatorFactory.waitsForCount(5);
keys = [];
ref
.orderByKey()
.limitToLast(5)
.on('child_added', child => {
keys.push(child.key);
ea.addEvent();
});
await ea.promise;
ref.orderByKey().off();
expect(keys).to.deep.equal(['b', 'c', 'd', 'e', 'f']);
});
it('Queries work on leaf nodes', done => {
const ref = getRandomNode() as Reference;
ref.set('leaf-node', () => {
ref
.orderByChild('foo')
.limitToLast(1)
.on('value', snap => {
expect(snap.val()).to.be.null;
done();
});
});
});
it('Updates for unindexed queries work', done => {
const refs = getRandomNode(2) as Reference[];
const reader = refs[0];
const writer = refs[1];
const value = {
one: { index: 1, value: 'one' },
two: { index: 2, value: 'two' },
three: { index: 3, value: 'three' }
};
let count = 0;
writer.set(value, () => {
reader
.orderByChild('index')
.limitToLast(2)
.on('value', snap => {
if (count === 0) {
expect(snap.val()).to.deep.equal({
two: { index: 2, value: 'two' },
three: { index: 3, value: 'three' }
});
// update child which should trigger value event
writer.child('one/index').set(4);
} else if (count === 1) {
expect(snap.val()).to.deep.equal({
three: { index: 3, value: 'three' },
one: { index: 4, value: 'one' }
});
done();
}
count++;
});
});
});
it('Server respects KeyIndex', done => {
const refs = getRandomNode(2) as Reference[];
const reader = refs[0];
const writer = refs[1];
const initial = {
a: 1,
b: 2,
c: 3
};
const expected = ['b', 'c'];
const actual = [];
const orderedRef = reader.orderByKey().startAt('b').limitToFirst(2);
writer.set(initial, () => {
orderedRef.on('value', snap => {
snap.forEach(childSnap => {
actual.push(childSnap.key);
});
expect(actual).to.deep.equal(expected);
done();
});
});
});
it('startAt/endAt works on value index', () => {
const ref = getRandomNode() as Reference;
const initial = {
alex: 60,
rob: 56,
vassili: 55.5,
tony: 52,
greg: 52
};
const expectedOrder = ['tony', 'vassili', 'rob'];
const expectedPrevNames = [null, 'tony', 'vassili'];
const valueOrder = [];
const addedOrder = [];
const addedPrevNames = [];
const orderedRef = ref.orderByValue().startAt(52, 'tony').endAt(59);
orderedRef.on('value', snap => {
snap.forEach(childSnap => {
valueOrder.push(childSnap.key);
});
});
orderedRef.on('child_added', (snap, prevName) => {
addedOrder.push(snap.key);
addedPrevNames.push(prevName);
});
ref.set(initial);
expect(addedOrder).to.deep.equal(expectedOrder);
expect(valueOrder).to.deep.equal(expectedOrder);
expect(addedPrevNames).to.deep.equal(expectedPrevNames);
});
it('startAfter / endAt works on value index', () => {
const ref = getRandomNode() as Reference;
const initial = {
alex: 60,
rob: 56,
vassili: 55.5,
tony: 52,
greg: 52
};
const expectedOrder = ['vassili', 'rob'];
const expectedPrevNames = [null, 'vassili'];
const valueOrder = [];
const addedOrder = [];
const addedPrevNames = [];
const orderedRef = ref.orderByValue().startAfter(52, 'tony').endAt(59);
orderedRef.on('value', snap => {
snap.forEach(childSnap => {
valueOrder.push(childSnap.key);
});
});
orderedRef.on('child_added', (snap, prevName) => {
addedOrder.push(snap.key);
addedPrevNames.push(prevName);
});
ref.set(initial);
expect(addedOrder).to.deep.equal(expectedOrder);
expect(valueOrder).to.deep.equal(expectedOrder);
expect(addedPrevNames).to.deep.equal(expectedPrevNames);
});
it('startAt / endBefore works on value index', () => {
const ref = getRandomNode() as Reference;
const initial = {
alex: 60,
rob: 56,
vassili: 55.5,
tony: 52,
greg: 52
};
const expectedOrder = ['tony', 'vassili', 'rob'];
const expectedPrevNames = [null, 'tony', 'vassili'];
const valueOrder = [];
const addedOrder = [];
const addedPrevNames = [];
const orderedRef = ref.orderByValue().startAt(52, 'tony').endBefore(60);
orderedRef.on('value', snap => {
snap.forEach(childSnap => {
valueOrder.push(childSnap.key);
});
});
orderedRef.on('child_added', (snap, prevName) => {
addedOrder.push(snap.key);
addedPrevNames.push(prevName);
});
ref.set(initial);
expect(addedOrder).to.deep.equal(expectedOrder);
expect(valueOrder).to.deep.equal(expectedOrder);
expect(addedPrevNames).to.deep.equal(expectedPrevNames);
});
it('startAfter / endBefore works on value index', () => {
const ref = getRandomNode() as Reference;
const initial = {
alex: 60,
rob: 56,
vassili: 55.5,
tony: 52,
greg: 52
};
const expectedOrder = ['vassili', 'rob'];
const expectedPrevNames = [null, 'vassili'];
const valueOrder = [];
const addedOrder = [];
const addedPrevNames = [];
const orderedRef = ref.orderByValue().startAfter(52, 'tony').endBefore(60);
orderedRef.on('value', snap => {
snap.forEach(childSnap => {
valueOrder.push(childSnap.key);
});
});
orderedRef.on('child_added', (snap, prevName) => {
addedOrder.push(snap.key);
addedPrevNames.push(prevName);
});
ref.set(initial);
expect(addedOrder).to.deep.equal(expectedOrder);
expect(valueOrder).to.deep.equal(expectedOrder);
expect(addedPrevNames).to.deep.equal(expectedPrevNames);
});
it('Removing default listener removes non-default listener that loads all data', done => {
const ref = getRandomNode() as Reference;
const initial = { key: 'value' };
ref.set(initial, err => {
expect(err).to.be.null;
ref.orderByKey().on('value', () => {});
ref.on('value', () => {});
// Should remove both listener and should remove the listen sent to the server
ref.off();
// This used to crash because a listener for ref.orderByKey() existed already
ref.orderByKey().once('value', snap => {
expect(snap.val()).to.deep.equal(initial);
done();
});
});
});
it('Can define and use an deep index', done => {
const ref = getRandomNode() as Reference;
const initial = {
alex: { deep: { nuggets: 60 } },
rob: { deep: { nuggets: 56 } },
vassili: { deep: { nuggets: 55.5 } },
tony: { deep: { nuggets: 52 } },
greg: { deep: { nuggets: 52 } }
};
const expectedOrder = ['greg', 'tony', 'vassili'];
const expectedPrevNames = [null, 'greg', 'tony'];
const valueOrder = [];
const addedOrder = [];
const addedPrevNames = [];
const orderedRef = ref.orderByChild('deep/nuggets').limitToFirst(3);
// come before value event
orderedRef.on('child_added', (snap, prevName) => {
addedOrder.push(snap.key);
addedPrevNames.push(prevName);
});
orderedRef.once('value', snap => {
snap.forEach(childSnap => {
valueOrder.push(childSnap.key);
});
});
ref.set(initial, err => {
expect(err).to.be.null;
expect(addedOrder).to.deep.equal(expectedOrder);
expect(valueOrder).to.deep.equal(expectedOrder);
expect(addedPrevNames).to.deep.equal(expectedPrevNames);
done();
});
});
});