mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-04-24 04:24:52 +08:00
Refactor into monorepo for v6 (#1837)
> You can [learn more about this here](https://blog.invertase.io/react-native-firebase-2019-7e334ca9bcc6).
This commit is contained in:
@@ -1,193 +0,0 @@
|
||||
describe('analytics()', () => {
|
||||
describe('logEvent()', () => {
|
||||
it('errors on using a reserved name', () => {
|
||||
try {
|
||||
firebase.analytics().logEvent('session_start');
|
||||
} catch (e) {
|
||||
e.message.should.containEql('reserved event');
|
||||
}
|
||||
});
|
||||
|
||||
it('errors if name not alphanumeric', () => {
|
||||
try {
|
||||
firebase.analytics().logEvent('!@£$%^&*');
|
||||
} catch (e) {
|
||||
e.message.should.containEql('is invalid');
|
||||
}
|
||||
});
|
||||
|
||||
it('errors if more than 25 params provided', () => {
|
||||
try {
|
||||
firebase.analytics().logEvent('fooby', {
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 3,
|
||||
4: 4,
|
||||
5: 5,
|
||||
6: 6,
|
||||
7: 7,
|
||||
8: 8,
|
||||
9: 9,
|
||||
10: 10,
|
||||
11: 11,
|
||||
12: 12,
|
||||
13: 13,
|
||||
14: 14,
|
||||
15: 15,
|
||||
16: 16,
|
||||
17: 17,
|
||||
18: 18,
|
||||
19: 19,
|
||||
20: 20,
|
||||
21: 21,
|
||||
22: 22,
|
||||
23: 23,
|
||||
24: 24,
|
||||
25: 25,
|
||||
26: 26,
|
||||
});
|
||||
} catch (e) {
|
||||
e.message.should.containEql('Maximum number of parameters exceeded');
|
||||
}
|
||||
});
|
||||
|
||||
it('errors if name is not a string', () => {
|
||||
(() => {
|
||||
firebase.analytics().logEvent(123456);
|
||||
}).should.throw(
|
||||
`analytics.logEvent(): First argument 'name' is required and must be a string value.`
|
||||
);
|
||||
});
|
||||
|
||||
it('errors if params is not an object', () => {
|
||||
(() => {
|
||||
firebase.analytics().logEvent('test_event', 'this should be an object');
|
||||
}).should.throw(
|
||||
`analytics.logEvent(): Second optional argument 'params' must be an object if provided.`
|
||||
);
|
||||
});
|
||||
|
||||
it('log an event without parameters', () => {
|
||||
firebase.analytics().logEvent('test_event');
|
||||
});
|
||||
|
||||
it('log an event with parameters', () => {
|
||||
firebase.analytics().logEvent('test_event', {
|
||||
boolean: true,
|
||||
number: 1,
|
||||
string: 'string',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setAnalyticsCollectionEnabled()', () => {
|
||||
it('true', () => {
|
||||
firebase.analytics().setAnalyticsCollectionEnabled(true);
|
||||
});
|
||||
|
||||
it('false', () => {
|
||||
firebase.analytics().setAnalyticsCollectionEnabled(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setCurrentScreen()', () => {
|
||||
it('screenName only', () => {
|
||||
firebase.analytics().setCurrentScreen('test screen');
|
||||
});
|
||||
|
||||
it('screenName with screenClassOverride', () => {
|
||||
firebase
|
||||
.analytics()
|
||||
.setCurrentScreen('test screen', 'test class override');
|
||||
});
|
||||
|
||||
xit('errors if screenName not a string', () => {
|
||||
// TODO needs validations adding to lib
|
||||
});
|
||||
|
||||
xit('errors if screenClassOverride not a string', () => {
|
||||
// TODO needs validations adding to lib
|
||||
});
|
||||
});
|
||||
|
||||
describe('setMinimumSessionDuration()', () => {
|
||||
it('default duration', () => {
|
||||
firebase.analytics().setMinimumSessionDuration();
|
||||
});
|
||||
|
||||
it('custom duration', () => {
|
||||
firebase.analytics().setMinimumSessionDuration(10001);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSessionTimeoutDuration()', () => {
|
||||
it('default duration', () => {
|
||||
firebase.analytics().setSessionTimeoutDuration();
|
||||
});
|
||||
|
||||
it('custom duration', () => {
|
||||
firebase.analytics().setSessionTimeoutDuration(1800001);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setUserId()', () => {
|
||||
// nulls remove the field on firebase
|
||||
it('allows a null values to be set', () => {
|
||||
firebase.analytics().setUserId(null);
|
||||
});
|
||||
|
||||
it('accepts string values', () => {
|
||||
firebase.analytics().setUserId('test-id');
|
||||
});
|
||||
|
||||
it('rejects none string none null values', () => {
|
||||
try {
|
||||
firebase.analytics().setUserId(33.3333);
|
||||
} catch (e) {
|
||||
e.message.should.containEql('must be a string');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('setUserProperty()', () => {
|
||||
// nulls remove the field on firebase
|
||||
it('allows a null values to be set', () => {
|
||||
firebase.analytics().setUserProperty('fooby', null);
|
||||
});
|
||||
|
||||
it('accepts string values', () => {
|
||||
firebase.analytics().setUserProperty('fooby2', 'test-id');
|
||||
});
|
||||
|
||||
it('rejects none string none null values', () => {
|
||||
try {
|
||||
firebase.analytics().setUserProperty('fooby3', 33.3333);
|
||||
} catch (e) {
|
||||
e.message.should.containEql('must be a string');
|
||||
}
|
||||
});
|
||||
|
||||
xit('errors if property name not a string', () => {
|
||||
// TODO needs validations adding to lib
|
||||
});
|
||||
});
|
||||
|
||||
describe('setUserProperties()', () => {
|
||||
// nulls remove the field on firebase
|
||||
it('allows a null values to be set', () => {
|
||||
firebase.analytics().setUserProperties({ fooby: null });
|
||||
});
|
||||
|
||||
it('accepts string values', () => {
|
||||
firebase.analytics().setUserProperties({ fooby2: 'test-id' });
|
||||
});
|
||||
|
||||
it('rejects none string none null values', () => {
|
||||
try {
|
||||
firebase.analytics().setUserProperties({ fooby3: 33.3333 });
|
||||
} catch (e) {
|
||||
e.message.should.containEql('must be a string');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,62 +0,0 @@
|
||||
describe('auth() -> emailLink Provider', () => {
|
||||
beforeEach(async () => {
|
||||
if (firebase.auth().currentUser) {
|
||||
await firebase.auth().signOut();
|
||||
await sleep(50);
|
||||
}
|
||||
});
|
||||
|
||||
describe('sendSignInLinkToEmail', () => {
|
||||
it('should send email', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
// const email = 'MANUAL TEST EMAIL HERE';
|
||||
const actionCodeSettings = {
|
||||
url: 'http://localhost:1337/authLinkFoo?bar=1234',
|
||||
handleCodeInApp: true,
|
||||
iOS: {
|
||||
bundleId: 'com.testing',
|
||||
},
|
||||
android: {
|
||||
packageName: 'com.testing',
|
||||
installApp: true,
|
||||
minimumVersion: '12',
|
||||
},
|
||||
};
|
||||
await firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isSignInWithEmailLink', () => {
|
||||
it('should return true/false', async () => {
|
||||
const emailLink1 =
|
||||
'https://www.example.com/action?mode=signIn&oobCode=oobCode';
|
||||
const emailLink2 =
|
||||
'https://www.example.com/action?mode=verifyEmail&oobCode=oobCode';
|
||||
const emailLink3 = 'https://www.example.com/action?mode=signIn';
|
||||
const emailLink4 =
|
||||
'https://x59dg.app.goo.gl/?link=https://rnfirebase-b9ad4.firebaseapp.com/__/auth/action?apiKey%3Dfoo%26mode%3DsignIn%26oobCode%3Dbar';
|
||||
|
||||
should.equal(true, firebase.auth().isSignInWithEmailLink(emailLink1));
|
||||
should.equal(false, firebase.auth().isSignInWithEmailLink(emailLink2));
|
||||
should.equal(false, firebase.auth().isSignInWithEmailLink(emailLink3));
|
||||
should.equal(true, firebase.auth().isSignInWithEmailLink(emailLink4));
|
||||
});
|
||||
});
|
||||
|
||||
// FOR MANUAL TESTING ONLY
|
||||
xdescribe('signInWithEmailLink', () => {
|
||||
it('should signIn', async () => {
|
||||
const email = 'MANUAL TEST EMAIL HERE';
|
||||
const emailLink = 'MANUAL TEST CODE HERE';
|
||||
|
||||
const userCredential = await firebase
|
||||
.auth()
|
||||
.signInWithEmailLink(email, emailLink);
|
||||
|
||||
userCredential.user.email.should.equal(email);
|
||||
|
||||
await await firebase.auth().signOut();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,70 +0,0 @@
|
||||
const TEST_PHONE_A = '+447445123456';
|
||||
const TEST_CODE_A = '123456';
|
||||
|
||||
const TEST_PHONE_B = '+447445123457';
|
||||
const TEST_CODE_B = '654321';
|
||||
|
||||
describe('auth() => Phone', () => {
|
||||
before(async () => {
|
||||
// iOS
|
||||
firebase.auth().settings.appVerificationDisabledForTesting = true;
|
||||
|
||||
// android
|
||||
await firebase
|
||||
.auth()
|
||||
.settings.setAutoRetrievedSmsCodeForPhoneNumber(
|
||||
TEST_PHONE_A,
|
||||
TEST_CODE_A
|
||||
);
|
||||
|
||||
await sleep(50);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
if (firebase.auth().currentUser) {
|
||||
await firebase.auth().signOut();
|
||||
await sleep(50);
|
||||
}
|
||||
});
|
||||
|
||||
describe('signInWithPhoneNumber', () => {
|
||||
it('signs in with a valid code', async () => {
|
||||
const confirmResult = await firebase
|
||||
.auth()
|
||||
.signInWithPhoneNumber(TEST_PHONE_A);
|
||||
|
||||
confirmResult.verificationId.should.be.a.String();
|
||||
|
||||
should.ok(
|
||||
confirmResult.verificationId.length,
|
||||
'verificationId string should not be empty'
|
||||
);
|
||||
|
||||
confirmResult.confirm.should.be.a.Function();
|
||||
|
||||
const user = await confirmResult.confirm(TEST_CODE_A);
|
||||
|
||||
user.should.be.instanceOf(jet.require('src/modules/auth/User'));
|
||||
|
||||
user.phoneNumber.should.equal(TEST_PHONE_A);
|
||||
});
|
||||
|
||||
it('errors on invalid code', async () => {
|
||||
const confirmResult = await firebase
|
||||
.auth()
|
||||
.signInWithPhoneNumber(TEST_PHONE_A);
|
||||
|
||||
confirmResult.verificationId.should.be.a.String();
|
||||
|
||||
should.ok(
|
||||
confirmResult.verificationId.length,
|
||||
'verificationId string should not be empty'
|
||||
);
|
||||
|
||||
confirmResult.confirm.should.be.a.Function();
|
||||
|
||||
await confirmResult.confirm('666999').should.be.rejected();
|
||||
// TODO test error code and message
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,244 +0,0 @@
|
||||
describe('auth() -> Providers', () => {
|
||||
beforeEach(async () => {
|
||||
if (firebase.auth().currentUser) {
|
||||
await firebase.auth().signOut();
|
||||
await sleep(50);
|
||||
}
|
||||
});
|
||||
|
||||
describe('EmailAuthProvider', () => {
|
||||
describe('constructor', () => {
|
||||
it('should throw an unsupported error', () => {
|
||||
(() => new firebase.auth.EmailAuthProvider()).should.throw(
|
||||
'`new EmailAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credential', () => {
|
||||
it('should return a credential object', () => {
|
||||
const email = 'email@email.com';
|
||||
const password = 'password';
|
||||
const credential = firebase.auth.EmailAuthProvider.credential(
|
||||
email,
|
||||
password
|
||||
);
|
||||
credential.providerId.should.equal('password');
|
||||
credential.token.should.equal(email);
|
||||
credential.secret.should.equal(password);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credentialWithLink', () => {
|
||||
it('should return a credential object', () => {
|
||||
const email = 'email@email.com';
|
||||
const link = 'link';
|
||||
const credential = firebase.auth.EmailAuthProvider.credentialWithLink(
|
||||
email,
|
||||
link
|
||||
);
|
||||
credential.providerId.should.equal('emailLink');
|
||||
credential.token.should.equal(email);
|
||||
credential.secret.should.equal(link);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EMAIL_PASSWORD_SIGN_IN_METHOD', () => {
|
||||
it('should return password', () => {
|
||||
firebase.auth.EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD.should.equal(
|
||||
'password'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EMAIL_LINK_SIGN_IN_METHOD', () => {
|
||||
it('should return emailLink', () => {
|
||||
firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD.should.equal(
|
||||
'emailLink'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PROVIDER_ID', () => {
|
||||
it('should return password', () => {
|
||||
firebase.auth.EmailAuthProvider.PROVIDER_ID.should.equal('password');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('FacebookAuthProvider', () => {
|
||||
describe('constructor', () => {
|
||||
it('should throw an unsupported error', () => {
|
||||
(() => new firebase.auth.FacebookAuthProvider()).should.throw(
|
||||
'`new FacebookAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credential', () => {
|
||||
it('should return a credential object', () => {
|
||||
const token = '123456';
|
||||
const credential = firebase.auth.FacebookAuthProvider.credential(token);
|
||||
credential.providerId.should.equal('facebook.com');
|
||||
credential.token.should.equal(token);
|
||||
credential.secret.should.equal('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('PROVIDER_ID', () => {
|
||||
it('should return facebook.com', () => {
|
||||
firebase.auth.FacebookAuthProvider.PROVIDER_ID.should.equal(
|
||||
'facebook.com'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('GithubAuthProvider', () => {
|
||||
describe('constructor', () => {
|
||||
it('should throw an unsupported error', () => {
|
||||
(() => new firebase.auth.GithubAuthProvider()).should.throw(
|
||||
'`new GithubAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credential', () => {
|
||||
it('should return a credential object', () => {
|
||||
const token = '123456';
|
||||
const credential = firebase.auth.GithubAuthProvider.credential(token);
|
||||
credential.providerId.should.equal('github.com');
|
||||
credential.token.should.equal(token);
|
||||
credential.secret.should.equal('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('PROVIDER_ID', () => {
|
||||
it('should return github.com', () => {
|
||||
firebase.auth.GithubAuthProvider.PROVIDER_ID.should.equal('github.com');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('GoogleAuthProvider', () => {
|
||||
describe('constructor', () => {
|
||||
it('should throw an unsupported error', () => {
|
||||
(() => new firebase.auth.GoogleAuthProvider()).should.throw(
|
||||
'`new GoogleAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credential', () => {
|
||||
it('should return a credential object', () => {
|
||||
const token = '123456';
|
||||
const secret = '654321';
|
||||
const credential = firebase.auth.GoogleAuthProvider.credential(
|
||||
token,
|
||||
secret
|
||||
);
|
||||
credential.providerId.should.equal('google.com');
|
||||
credential.token.should.equal(token);
|
||||
credential.secret.should.equal(secret);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PROVIDER_ID', () => {
|
||||
it('should return google.com', () => {
|
||||
firebase.auth.GoogleAuthProvider.PROVIDER_ID.should.equal('google.com');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('OAuthProvider', () => {
|
||||
describe('constructor', () => {
|
||||
it('should throw an unsupported error', () => {
|
||||
(() => new firebase.auth.OAuthProvider()).should.throw(
|
||||
'`new OAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credential', () => {
|
||||
it('should return a credential object', () => {
|
||||
const idToken = '123456';
|
||||
const accessToken = '654321';
|
||||
const credential = firebase.auth.OAuthProvider.credential(
|
||||
idToken,
|
||||
accessToken
|
||||
);
|
||||
credential.providerId.should.equal('oauth');
|
||||
credential.token.should.equal(idToken);
|
||||
credential.secret.should.equal(accessToken);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PROVIDER_ID', () => {
|
||||
it('should return oauth', () => {
|
||||
firebase.auth.OAuthProvider.PROVIDER_ID.should.equal('oauth');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('PhoneAuthProvider', () => {
|
||||
describe('constructor', () => {
|
||||
it('should throw an unsupported error', () => {
|
||||
(() => new firebase.auth.PhoneAuthProvider()).should.throw(
|
||||
'`new PhoneAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credential', () => {
|
||||
it('should return a credential object', () => {
|
||||
const verificationId = '123456';
|
||||
const code = '654321';
|
||||
const credential = firebase.auth.PhoneAuthProvider.credential(
|
||||
verificationId,
|
||||
code
|
||||
);
|
||||
credential.providerId.should.equal('phone');
|
||||
credential.token.should.equal(verificationId);
|
||||
credential.secret.should.equal(code);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PROVIDER_ID', () => {
|
||||
it('should return phone', () => {
|
||||
firebase.auth.PhoneAuthProvider.PROVIDER_ID.should.equal('phone');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('TwitterAuthProvider', () => {
|
||||
describe('constructor', () => {
|
||||
it('should throw an unsupported error', () => {
|
||||
(() => new firebase.auth.TwitterAuthProvider()).should.throw(
|
||||
'`new TwitterAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credential', () => {
|
||||
it('should return a credential object', () => {
|
||||
const token = '123456';
|
||||
const secret = '654321';
|
||||
const credential = firebase.auth.TwitterAuthProvider.credential(
|
||||
token,
|
||||
secret
|
||||
);
|
||||
credential.providerId.should.equal('twitter.com');
|
||||
credential.token.should.equal(token);
|
||||
credential.secret.should.equal(secret);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PROVIDER_ID', () => {
|
||||
it('should return twitter.com', () => {
|
||||
firebase.auth.TwitterAuthProvider.PROVIDER_ID.should.equal(
|
||||
'twitter.com'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,68 +0,0 @@
|
||||
describe('auth()', () => {
|
||||
beforeEach(async () => {
|
||||
if (firebase.auth().currentUser) {
|
||||
await firebase.auth().signOut();
|
||||
await sleep(50);
|
||||
}
|
||||
});
|
||||
|
||||
describe('firebase.auth().currentUser', () => {
|
||||
it('exists after reload', async () => {
|
||||
let currentUser;
|
||||
// before reload
|
||||
await firebase.auth().signInAnonymously();
|
||||
|
||||
({ currentUser } = firebase.auth());
|
||||
currentUser.should.be.an.Object();
|
||||
currentUser.uid.should.be.a.String();
|
||||
currentUser.toJSON().should.be.an.Object();
|
||||
should.equal(currentUser.toJSON().email, null);
|
||||
currentUser.isAnonymous.should.equal(true);
|
||||
currentUser.providerId.should.equal('firebase');
|
||||
currentUser.should.equal(firebase.auth().currentUser);
|
||||
|
||||
// RELOAD
|
||||
await device.reloadReactNative();
|
||||
|
||||
// after reload
|
||||
({ currentUser } = firebase.auth());
|
||||
currentUser.should.be.an.Object();
|
||||
currentUser.uid.should.be.a.String();
|
||||
currentUser.toJSON().should.be.an.Object();
|
||||
should.equal(currentUser.toJSON().email, null);
|
||||
currentUser.isAnonymous.should.equal(true);
|
||||
currentUser.providerId.should.equal('firebase');
|
||||
currentUser.should.equal(firebase.auth().currentUser);
|
||||
|
||||
// test correct user is returned after signing
|
||||
// in with a different user then reloading
|
||||
await firebase.auth().signOut();
|
||||
|
||||
const email = 'test@test.com';
|
||||
const pass = 'test1234';
|
||||
await firebase.auth().signInWithEmailAndPassword(email, pass);
|
||||
|
||||
({ currentUser } = firebase.auth());
|
||||
currentUser.should.be.an.Object();
|
||||
currentUser.uid.should.be.a.String();
|
||||
currentUser.toJSON().should.be.an.Object();
|
||||
currentUser.toJSON().email.should.eql(email);
|
||||
currentUser.isAnonymous.should.equal(false);
|
||||
currentUser.providerId.should.equal('firebase');
|
||||
currentUser.should.equal(firebase.auth().currentUser);
|
||||
|
||||
// RELOAD
|
||||
await device.reloadReactNative();
|
||||
|
||||
// after reload
|
||||
({ currentUser } = firebase.auth());
|
||||
currentUser.should.be.an.Object();
|
||||
currentUser.uid.should.be.a.String();
|
||||
currentUser.toJSON().should.be.an.Object();
|
||||
currentUser.toJSON().email.should.eql(email);
|
||||
currentUser.isAnonymous.should.equal(false);
|
||||
currentUser.providerId.should.equal('firebase');
|
||||
currentUser.should.equal(firebase.auth().currentUser);
|
||||
}).timeout(15000);
|
||||
});
|
||||
});
|
||||
@@ -1,499 +0,0 @@
|
||||
describe('auth().currentUser', () => {
|
||||
beforeEach(async () => {
|
||||
if (firebase.auth().currentUser) {
|
||||
await firebase.auth().signOut();
|
||||
await sleep(50);
|
||||
}
|
||||
});
|
||||
|
||||
describe('getIdToken()', () => {
|
||||
it('should return a token', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
|
||||
const { user } = await firebase
|
||||
.auth()
|
||||
.createUserWithEmailAndPassword(email, random);
|
||||
|
||||
// Test
|
||||
const token = await user.getIdToken();
|
||||
|
||||
// Assertions
|
||||
token.should.be.a.String();
|
||||
token.length.should.be.greaterThan(24);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIdTokenResult()', () => {
|
||||
it('should return a valid IdTokenResult Object', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
|
||||
const { user } = await firebase
|
||||
.auth()
|
||||
.createUserWithEmailAndPassword(email, random);
|
||||
|
||||
// Test
|
||||
const tokenResult = await user.getIdTokenResult();
|
||||
|
||||
tokenResult.token.should.be.a.String();
|
||||
tokenResult.authTime.should.be.a.String();
|
||||
tokenResult.issuedAtTime.should.be.a.String();
|
||||
tokenResult.expirationTime.should.be.a.String();
|
||||
|
||||
new Date(tokenResult.authTime)
|
||||
.toString()
|
||||
.should.not.equal('Invalid Date');
|
||||
new Date(tokenResult.issuedAtTime)
|
||||
.toString()
|
||||
.should.not.equal('Invalid Date');
|
||||
new Date(tokenResult.expirationTime)
|
||||
.toString()
|
||||
.should.not.equal('Invalid Date');
|
||||
|
||||
tokenResult.claims.should.be.a.Object();
|
||||
tokenResult.claims.iat.should.be.a.Number();
|
||||
tokenResult.claims.iss.should.be.a.String();
|
||||
|
||||
tokenResult.signInProvider.should.equal('password');
|
||||
tokenResult.token.length.should.be.greaterThan(24);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
});
|
||||
|
||||
describe('linkWithCredential()', () => {
|
||||
it('should link anonymous account <-> email account', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
const pass = random;
|
||||
|
||||
await firebase.auth().signInAnonymously();
|
||||
const currentUser = firebase.auth().currentUser;
|
||||
|
||||
// Test
|
||||
const credential = firebase.auth.EmailAuthProvider.credential(
|
||||
email,
|
||||
pass
|
||||
);
|
||||
|
||||
const linkedUserCredential = await currentUser.linkWithCredential(
|
||||
credential
|
||||
);
|
||||
|
||||
// Assertions
|
||||
const linkedUser = linkedUserCredential.user;
|
||||
linkedUser.should.be.an.Object();
|
||||
linkedUser.should.equal(firebase.auth().currentUser);
|
||||
linkedUser.email.toLowerCase().should.equal(email.toLowerCase());
|
||||
linkedUser.isAnonymous.should.equal(false);
|
||||
linkedUser.providerId.should.equal('firebase');
|
||||
linkedUser.providerData.should.be.an.Array();
|
||||
linkedUser.providerData.length.should.equal(1);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
|
||||
it('should error on link anon <-> email if email already exists', async () => {
|
||||
const email = 'test@test.com';
|
||||
const pass = 'test1234';
|
||||
|
||||
await firebase.auth().signInAnonymously();
|
||||
const currentUser = firebase.auth().currentUser;
|
||||
|
||||
// Test
|
||||
try {
|
||||
const credential = firebase.auth.EmailAuthProvider.credential(
|
||||
email,
|
||||
pass
|
||||
);
|
||||
await currentUser.linkWithCredential(credential);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().signOut();
|
||||
|
||||
// Reject
|
||||
return Promise.reject(new Error('Did not error on link'));
|
||||
} catch (error) {
|
||||
// Assertions
|
||||
error.code.should.equal('auth/email-already-in-use');
|
||||
error.message.should.equal(
|
||||
'The email address is already in use by another account.'
|
||||
);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('linkAndRetrieveDataWithCredential()', () => {
|
||||
it('should link anonymous account <-> email account', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
const pass = random;
|
||||
|
||||
await firebase.auth().signInAnonymously();
|
||||
const currentUser = firebase.auth().currentUser;
|
||||
|
||||
// Test
|
||||
const credential = firebase.auth.EmailAuthProvider.credential(
|
||||
email,
|
||||
pass
|
||||
);
|
||||
|
||||
const linkedUserCredential = await currentUser.linkAndRetrieveDataWithCredential(
|
||||
credential
|
||||
);
|
||||
|
||||
// Assertions
|
||||
const linkedUser = linkedUserCredential.user;
|
||||
linkedUser.should.be.an.Object();
|
||||
linkedUser.should.equal(firebase.auth().currentUser);
|
||||
linkedUser.email.toLowerCase().should.equal(email.toLowerCase());
|
||||
linkedUser.isAnonymous.should.equal(false);
|
||||
linkedUser.providerId.should.equal('firebase');
|
||||
linkedUser.providerData.should.be.an.Array();
|
||||
linkedUser.providerData.length.should.equal(1);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
|
||||
it('should error on link anon <-> email if email already exists', async () => {
|
||||
const email = 'test@test.com';
|
||||
const pass = 'test1234';
|
||||
|
||||
await firebase.auth().signInAnonymously();
|
||||
const currentUser = firebase.auth().currentUser;
|
||||
|
||||
// Test
|
||||
try {
|
||||
const credential = firebase.auth.EmailAuthProvider.credential(
|
||||
email,
|
||||
pass
|
||||
);
|
||||
await currentUser.linkAndRetrieveDataWithCredential(credential);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().signOut();
|
||||
|
||||
// Reject
|
||||
return Promise.reject(new Error('Did not error on link'));
|
||||
} catch (error) {
|
||||
// Assertions
|
||||
error.code.should.equal('auth/email-already-in-use');
|
||||
error.message.should.equal(
|
||||
'The email address is already in use by another account.'
|
||||
);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('reauthenticateWithCredential()', () => {
|
||||
it('should reauthenticate correctly', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
const pass = random;
|
||||
|
||||
await firebase.auth().createUserWithEmailAndPassword(email, pass);
|
||||
|
||||
// Test
|
||||
const credential = firebase.auth.EmailAuthProvider.credential(
|
||||
email,
|
||||
pass
|
||||
);
|
||||
|
||||
await firebase
|
||||
.auth()
|
||||
.currentUser.reauthenticateWithCredential(credential);
|
||||
|
||||
// Assertions
|
||||
const currentUser = firebase.auth().currentUser;
|
||||
currentUser.email.should.equal(email.toLowerCase());
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reauthenticateAndRetrieveDataWithCredential()', () => {
|
||||
it('should reauthenticate correctly', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
const pass = random;
|
||||
|
||||
await firebase
|
||||
.auth()
|
||||
.createUserAndRetrieveDataWithEmailAndPassword(email, pass);
|
||||
|
||||
// Test
|
||||
const credential = firebase.auth.EmailAuthProvider.credential(
|
||||
email,
|
||||
pass
|
||||
);
|
||||
|
||||
await firebase
|
||||
.auth()
|
||||
.currentUser.reauthenticateAndRetrieveDataWithCredential(credential);
|
||||
|
||||
// Assertions
|
||||
const currentUser = firebase.auth().currentUser;
|
||||
currentUser.email.should.equal(email.toLowerCase());
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reload()', () => {
|
||||
it('should not error', async () => {
|
||||
await firebase.auth().signInAnonymously();
|
||||
|
||||
try {
|
||||
await firebase.auth().currentUser.reload();
|
||||
await firebase.auth().signOut();
|
||||
} catch (error) {
|
||||
// Reject
|
||||
await firebase.auth().signOut();
|
||||
return Promise.reject(new Error('reload() caused an error', error));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('sendEmailVerification()', () => {
|
||||
it('should not error', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
const pass = random;
|
||||
|
||||
await firebase
|
||||
.auth()
|
||||
.createUserAndRetrieveDataWithEmailAndPassword(email, pass);
|
||||
|
||||
try {
|
||||
await firebase.auth().currentUser.sendEmailVerification();
|
||||
await firebase.auth().currentUser.delete();
|
||||
} catch (error) {
|
||||
// Reject
|
||||
await firebase.auth().currentUser.delete();
|
||||
return Promise.reject(
|
||||
new Error('sendEmailVerification() caused an error', error)
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('unlink()', () => {
|
||||
it('should unlink the email address', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
const pass = random;
|
||||
|
||||
await firebase.auth().signInAnonymouslyAndRetrieveData();
|
||||
const currentUser = firebase.auth().currentUser;
|
||||
|
||||
const credential = firebase.auth.EmailAuthProvider.credential(
|
||||
email,
|
||||
pass
|
||||
);
|
||||
await currentUser.linkAndRetrieveDataWithCredential(credential);
|
||||
|
||||
// Test
|
||||
await currentUser.unlink(firebase.auth.EmailAuthProvider.PROVIDER_ID);
|
||||
|
||||
// Assertions
|
||||
const unlinkedUser = firebase.auth().currentUser;
|
||||
unlinkedUser.providerData.should.be.an.Array();
|
||||
unlinkedUser.providerData.length.should.equal(0);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateEmail()', () => {
|
||||
it('should update the email address', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const random2 = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
const email2 = `${random2}@${random2}.com`;
|
||||
const pass = random;
|
||||
|
||||
// Setup
|
||||
await firebase
|
||||
.auth()
|
||||
.createUserAndRetrieveDataWithEmailAndPassword(email, pass);
|
||||
firebase
|
||||
.auth()
|
||||
.currentUser.email.toLowerCase()
|
||||
.should.equal(email.toLowerCase());
|
||||
|
||||
// Update user email
|
||||
await firebase.auth().currentUser.updateEmail(email2);
|
||||
|
||||
// Assertions
|
||||
firebase
|
||||
.auth()
|
||||
.currentUser.email.toLowerCase()
|
||||
.should.equal(email2.toLowerCase());
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
});
|
||||
|
||||
describe('updatePassword()', () => {
|
||||
it('should update the password', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const random2 = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
const pass = random;
|
||||
const pass2 = random2;
|
||||
|
||||
// Setup
|
||||
await firebase
|
||||
.auth()
|
||||
.createUserAndRetrieveDataWithEmailAndPassword(email, pass);
|
||||
|
||||
// Update user password
|
||||
await firebase.auth().currentUser.updatePassword(pass2);
|
||||
|
||||
// Sign out
|
||||
await firebase.auth().signOut();
|
||||
|
||||
// Log in with the new password
|
||||
await firebase
|
||||
.auth()
|
||||
.signInAndRetrieveDataWithEmailAndPassword(email, pass2);
|
||||
|
||||
// Assertions
|
||||
firebase.auth().currentUser.should.be.an.Object();
|
||||
firebase.auth().currentUser.email.should.equal(email.toLowerCase());
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateProfile()', () => {
|
||||
it('should update the profile', async () => {
|
||||
const random = randomString(12, '#aA');
|
||||
const email = `${random}@${random}.com`;
|
||||
const pass = random;
|
||||
const displayName = random;
|
||||
const photoURL = `http://${random}.com/${random}.jpg`;
|
||||
|
||||
// Setup
|
||||
await firebase
|
||||
.auth()
|
||||
.createUserAndRetrieveDataWithEmailAndPassword(email, pass);
|
||||
|
||||
// Update user profile
|
||||
await firebase.auth().currentUser.updateProfile({
|
||||
displayName,
|
||||
photoURL,
|
||||
});
|
||||
|
||||
// Assertions
|
||||
const user = firebase.auth().currentUser;
|
||||
user.should.be.an.Object();
|
||||
user.email.should.equal(email.toLowerCase());
|
||||
user.displayName.should.equal(displayName);
|
||||
user.photoURL.should.equal(photoURL);
|
||||
|
||||
// Clean up
|
||||
await firebase.auth().currentUser.delete();
|
||||
});
|
||||
});
|
||||
|
||||
describe('linkWithPhoneNumber()', () => {
|
||||
it('should throw an unsupported error', async () => {
|
||||
await firebase.auth().signInAnonymouslyAndRetrieveData();
|
||||
(() => {
|
||||
firebase.auth().currentUser.linkWithPhoneNumber();
|
||||
}).should.throw(
|
||||
'User.linkWithPhoneNumber() is unsupported by the native Firebase SDKs.'
|
||||
);
|
||||
await firebase.auth().signOut();
|
||||
});
|
||||
});
|
||||
|
||||
describe('linkWithPopup()', () => {
|
||||
it('should throw an unsupported error', async () => {
|
||||
await firebase.auth().signInAnonymouslyAndRetrieveData();
|
||||
(() => {
|
||||
firebase.auth().currentUser.linkWithPopup();
|
||||
}).should.throw(
|
||||
'User.linkWithPopup() is unsupported by the native Firebase SDKs.'
|
||||
);
|
||||
await firebase.auth().signOut();
|
||||
});
|
||||
});
|
||||
|
||||
describe('linkWithRedirect()', () => {
|
||||
it('should throw an unsupported error', async () => {
|
||||
await firebase.auth().signInAnonymouslyAndRetrieveData();
|
||||
(() => {
|
||||
firebase.auth().currentUser.linkWithRedirect();
|
||||
}).should.throw(
|
||||
'User.linkWithRedirect() is unsupported by the native Firebase SDKs.'
|
||||
);
|
||||
await firebase.auth().signOut();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reauthenticateWithPhoneNumber()', () => {
|
||||
it('should throw an unsupported error', async () => {
|
||||
await firebase.auth().signInAnonymouslyAndRetrieveData();
|
||||
(() => {
|
||||
firebase.auth().currentUser.reauthenticateWithPhoneNumber();
|
||||
}).should.throw(
|
||||
'User.reauthenticateWithPhoneNumber() is unsupported by the native Firebase SDKs.'
|
||||
);
|
||||
await firebase.auth().signOut();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reauthenticateWithPopup()', () => {
|
||||
it('should throw an unsupported error', async () => {
|
||||
await firebase.auth().signInAnonymouslyAndRetrieveData();
|
||||
(() => {
|
||||
firebase.auth().currentUser.reauthenticateWithPopup();
|
||||
}).should.throw(
|
||||
'User.reauthenticateWithPopup() is unsupported by the native Firebase SDKs.'
|
||||
);
|
||||
await firebase.auth().signOut();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reauthenticateWithRedirect()', () => {
|
||||
it('should throw an unsupported error', async () => {
|
||||
await firebase.auth().signInAnonymouslyAndRetrieveData();
|
||||
(() => {
|
||||
firebase.auth().currentUser.reauthenticateWithRedirect();
|
||||
}).should.throw(
|
||||
'User.reauthenticateWithRedirect() is unsupported by the native Firebase SDKs.'
|
||||
);
|
||||
await firebase.auth().signOut();
|
||||
});
|
||||
});
|
||||
|
||||
describe('refreshToken', () => {
|
||||
it('should throw an unsupported error', async () => {
|
||||
await firebase.auth().signInAnonymouslyAndRetrieveData();
|
||||
(() => firebase.auth().currentUser.refreshToken).should.throw(
|
||||
'User.refreshToken is unsupported by the native Firebase SDKs.'
|
||||
);
|
||||
await firebase.auth().signOut();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,97 +0,0 @@
|
||||
describe('config()', () => {
|
||||
before(() => {
|
||||
firebase.config().enableDeveloperMode();
|
||||
firebase.config().setDefaults({
|
||||
foo: 'bar',
|
||||
bar: 'baz',
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetch()', () => {
|
||||
it('with expiration provided', () => firebase.config().fetch(0));
|
||||
it('without expiration provided', () => firebase.config().fetch());
|
||||
});
|
||||
|
||||
describe('activateFetched()', () => {
|
||||
it('with expiration provided', async () => {
|
||||
await firebase.config().fetch(0);
|
||||
const activated = await firebase.config().activateFetched();
|
||||
activated.should.be.a.Boolean();
|
||||
});
|
||||
|
||||
it('with expiration provided', async () => {
|
||||
await firebase.config().fetch();
|
||||
const activated = await firebase.config().activateFetched();
|
||||
activated.should.be.a.Boolean();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getValue()', () => {
|
||||
it('gets a single value by key', async () => {
|
||||
const config = await firebase.config().getValue('foo');
|
||||
config.should.be.a.Object();
|
||||
config.source.should.be.a.String();
|
||||
config.val.should.be.a.Function();
|
||||
config.val().should.be.equalOneOf('bar', true);
|
||||
});
|
||||
|
||||
xit('errors if no key provided or is not a string', async () => {
|
||||
// TODO needs input validation adding to lib
|
||||
});
|
||||
});
|
||||
|
||||
describe('getValues()', () => {
|
||||
it('get multiple values by an array of keys', async () => {
|
||||
const config = await firebase
|
||||
.config()
|
||||
.getValues(['foo', 'bar', 'foobar', 'numvalue']);
|
||||
config.should.be.a.Object();
|
||||
config.should.have.keys('foo', 'bar', 'foobar');
|
||||
const fooValue = config.foo.val();
|
||||
const barValue = config.bar.val();
|
||||
const foobarValue = config.foobar.val();
|
||||
const numvalueValue = config.numvalue.val();
|
||||
|
||||
fooValue.should.be.equal(true);
|
||||
barValue.should.be.equal('baz');
|
||||
foobarValue.should.be.equal('barbaz');
|
||||
numvalueValue.should.be.equal(0);
|
||||
});
|
||||
|
||||
xit('errors if any key is not a string', async () => {
|
||||
// TODO needs input validation adding to lib
|
||||
});
|
||||
});
|
||||
|
||||
describe('getKeysByPrefix()', () => {
|
||||
it('get keys beginning with the prefix provided', async () => {
|
||||
const keys = await firebase.config().getKeysByPrefix('num');
|
||||
keys.should.be.Array();
|
||||
should.equal(keys.length, 2);
|
||||
});
|
||||
|
||||
xit('get all keys as an array if no prefix provided', async () => {
|
||||
// TODO flakey on Android
|
||||
const keys = await firebase.config().getKeysByPrefix();
|
||||
keys.should.be.Array();
|
||||
should.equal(keys.length, 4);
|
||||
});
|
||||
|
||||
xit('errors if prefix is not a string', async () => {
|
||||
// TODO needs input validation adding to lib
|
||||
});
|
||||
});
|
||||
|
||||
describe('setDefaultsFromResource()', () => {
|
||||
it('accepts a resource id/name to read defaults from', async () => {
|
||||
if (device.getPlatform() === 'android')
|
||||
firebase.config().setDefaultsFromResource(6666);
|
||||
else firebase.config().setDefaultsFromResource();
|
||||
// todo add plist/xml on ios/android to test
|
||||
});
|
||||
|
||||
xit('errors if id not a integer for android or a string for ios', async () => {
|
||||
// TODO needs input validation adding to lib
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,115 +0,0 @@
|
||||
describe('Core', () => {
|
||||
describe('Firebase', () => {
|
||||
it('it should create js apps for natively initialized apps', () => {
|
||||
should.equal(firebase.app()._nativeInitialized, true);
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
it('natively initialized apps should have options available in js', () => {
|
||||
const platformAppConfig = TestHelpers.core.config();
|
||||
should.equal(firebase.app().options.apiKey, platformAppConfig.apiKey);
|
||||
should.equal(firebase.app().options.appId, platformAppConfig.appId);
|
||||
should.equal(
|
||||
firebase.app().options.databaseURL,
|
||||
platformAppConfig.databaseURL
|
||||
);
|
||||
should.equal(
|
||||
firebase.app().options.messagingSenderId,
|
||||
platformAppConfig.messagingSenderId
|
||||
);
|
||||
should.equal(
|
||||
firebase.app().options.projectId,
|
||||
platformAppConfig.projectId
|
||||
);
|
||||
should.equal(
|
||||
firebase.app().options.storageBucket,
|
||||
platformAppConfig.storageBucket
|
||||
);
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
it('it should resolve onReady for natively initialized apps', () =>
|
||||
firebase.app().onReady());
|
||||
|
||||
it('it should initialize dynamic apps', () => {
|
||||
const name = `testscoreapp${global.testRunId}`;
|
||||
const platformAppConfig = TestHelpers.core.config();
|
||||
return firebase
|
||||
.initializeApp(platformAppConfig, name)
|
||||
.onReady()
|
||||
.then(newApp => {
|
||||
newApp.name.should.equal(name.toUpperCase());
|
||||
newApp.toString().should.equal(name.toUpperCase());
|
||||
newApp.options.apiKey.should.equal(platformAppConfig.apiKey);
|
||||
return newApp.delete();
|
||||
});
|
||||
});
|
||||
|
||||
it('SDK_VERSION should return a string version', () => {
|
||||
firebase.SDK_VERSION.should.be.a.String();
|
||||
});
|
||||
});
|
||||
|
||||
describe('App', () => {
|
||||
it('apps should provide an array of apps', () => {
|
||||
should.equal(!!firebase.apps.length, true);
|
||||
should.equal(firebase.apps.includes(firebase.app('[DEFAULT]')), true);
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
it('can be deleted', async () => {
|
||||
const name = `testscoreapp${global.testRunId}`;
|
||||
const platformAppConfig = TestHelpers.core.config();
|
||||
const newApp = firebase.initializeApp(platformAppConfig, name);
|
||||
|
||||
await newApp.onReady();
|
||||
|
||||
newApp.name.should.equal(name.toUpperCase());
|
||||
newApp.toString().should.equal(name.toUpperCase());
|
||||
newApp.options.apiKey.should.equal(platformAppConfig.apiKey);
|
||||
|
||||
await newApp.delete();
|
||||
|
||||
(() => {
|
||||
firebase.app(name);
|
||||
}).should.throw(
|
||||
`The [${name.toUpperCase()}] firebase app has not been initialized!`
|
||||
);
|
||||
});
|
||||
|
||||
it('prevents the default app from being deleted', async () => {
|
||||
firebase
|
||||
.app()
|
||||
.delete()
|
||||
.should.be.rejectedWith(
|
||||
'Unable to delete the default native firebase app instance.'
|
||||
);
|
||||
});
|
||||
|
||||
it('extendApp should error if an object is not supplied', () => {
|
||||
(() => {
|
||||
firebase.app().extendApp('string');
|
||||
}).should.throw(
|
||||
"Missing required argument of type 'Object' for method 'extendApp()'."
|
||||
);
|
||||
});
|
||||
|
||||
it('extendApp should error if a protected property is supplied', () => {
|
||||
(() => {
|
||||
firebase.app().extendApp({
|
||||
database: {},
|
||||
});
|
||||
}).should.throw(
|
||||
"Property 'database' is protected and can not be overridden by extendApp."
|
||||
);
|
||||
});
|
||||
|
||||
it('extendApp should provide additional functionality', () => {
|
||||
const extension = {};
|
||||
firebase.app().extendApp({
|
||||
extension,
|
||||
});
|
||||
firebase.app().extension.should.equal(extension);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,84 +0,0 @@
|
||||
describe('crashlytics()', () => {
|
||||
// todo test is flakey due to a detox error occurring sometimes;
|
||||
// Error: the string "Error when sending event: websocketFailed with body:
|
||||
// {\n id = 0;\n message = \"The operation couldn\\U2019t be completed.
|
||||
// Connection refused\";\n}. Bridge is not set. This is probably because you've
|
||||
// explicitly synthesized the bridge in RCTWebSocketModule, even though it's
|
||||
// inherited from RCTEventEmitter.
|
||||
xdescribe('crash()', () => {
|
||||
it('should force an app crash', async () => {
|
||||
await firebase.crashlytics().crash();
|
||||
if (device.getPlatform() === 'ios') {
|
||||
// ios responds quicker after a fatal exception if we re-install
|
||||
await device.uninstallApp();
|
||||
await device.installApp();
|
||||
}
|
||||
|
||||
await device.launchApp({ newInstance: true });
|
||||
await firebase.crashlytics().log('app relaunched from a crash');
|
||||
});
|
||||
});
|
||||
|
||||
describe('log()', () => {
|
||||
it('should set a string value', async () => {
|
||||
await firebase.crashlytics().log('123abc');
|
||||
});
|
||||
|
||||
xit('should error on a non a string value', async () => {
|
||||
// TODO lib needs validations adding
|
||||
await firebase.crashlytics().log(123456);
|
||||
});
|
||||
});
|
||||
|
||||
describe('recordError()', () => {
|
||||
it('should record an error with a code and message', async () => {
|
||||
await firebase.crashlytics().recordError(1234, 'Test error');
|
||||
});
|
||||
|
||||
xit('should error on invalid args', async () => {
|
||||
// TODO lib needs validations adding - and this should technically take an instance of Error only
|
||||
await firebase.crashlytics().recordError({}, []);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setBoolValue()', () => {
|
||||
it('should set a boolean value', async () => {
|
||||
await firebase.crashlytics().setBoolValue('boolKey', true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setFloatValue()', () => {
|
||||
it('should set a float value', async () => {
|
||||
await firebase.crashlytics().setFloatValue('floatKey', 1.23);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setIntValue()', () => {
|
||||
it('should set a integer value', async () => {
|
||||
await firebase.crashlytics().setIntValue('intKey', 123);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setStringValue()', () => {
|
||||
it('should set a string value', async () => {
|
||||
await firebase.crashlytics().setStringValue('stringKey', 'test');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setUserIdentifier()', () => {
|
||||
it('should set a string value', async () => {
|
||||
await firebase.crashlytics().setUserIdentifier('123abc');
|
||||
});
|
||||
|
||||
xit('should error on a non a string value', async () => {
|
||||
// TODO lib needs validations adding
|
||||
await firebase.crashlytics().setUserIdentifier(123456);
|
||||
});
|
||||
});
|
||||
|
||||
describe('enableCrashlyticsCollection()', () => {
|
||||
it('should not throw', async () => {
|
||||
await firebase.crashlytics().enableCrashlyticsCollection();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,279 +0,0 @@
|
||||
const { CONTENTS, setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
beforeEach(() => setDatabaseContents());
|
||||
|
||||
describe('issue_100', () => {
|
||||
describe('array-like values should', () => {
|
||||
it('return null in returned array at positions where a key is missing', async () => {
|
||||
const ref = firebase.database().ref('tests/issues/100');
|
||||
|
||||
const snapshot = await ref.once('value');
|
||||
|
||||
snapshot
|
||||
.val()
|
||||
.should.eql(
|
||||
jet.contextify([
|
||||
null,
|
||||
jet.contextify(CONTENTS.ISSUES[100][1]),
|
||||
jet.contextify(CONTENTS.ISSUES[100][2]),
|
||||
jet.contextify(CONTENTS.ISSUES[100][3]),
|
||||
])
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('issue_108', () => {
|
||||
describe('filters using floats', () => {
|
||||
it('return correct results', async () => {
|
||||
const ref = firebase.database().ref('tests/issues/108');
|
||||
|
||||
const snapshot = await ref
|
||||
.orderByChild('latitude')
|
||||
.startAt(34.00867000999119)
|
||||
.endAt(34.17462960866099)
|
||||
.once('value');
|
||||
|
||||
const val = snapshot.val();
|
||||
|
||||
val.foobar.should.eql(jet.contextify(CONTENTS.ISSUES[108].foobar));
|
||||
should.equal(Object.keys(val).length, 1);
|
||||
});
|
||||
|
||||
it('return correct results when not using float values', async () => {
|
||||
const ref = firebase.database().ref('tests/issues/108');
|
||||
|
||||
const snapshot = await ref
|
||||
.orderByChild('latitude')
|
||||
.equalTo(37)
|
||||
.once('value');
|
||||
|
||||
const val = snapshot.val();
|
||||
|
||||
val.notAFloat.should.eql(
|
||||
jet.contextify(CONTENTS.ISSUES[108].notAFloat)
|
||||
);
|
||||
|
||||
should.equal(Object.keys(val).length, 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
xdescribe('issue_171', () => {
|
||||
describe('non array-like values should', () => {
|
||||
it('return as objects', async () => {
|
||||
const ref = firebase.database().ref('tests/issues/171');
|
||||
const snapshot = await ref.once('value');
|
||||
|
||||
snapshot.val().should.eql(jet.contextify(CONTENTS.ISSUES[171]));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('issue_489', () => {
|
||||
describe('long numbers should', () => {
|
||||
it('return as longs', async () => {
|
||||
const long1Ref = firebase.database().ref('tests/issues/489/long1');
|
||||
const long2Ref = firebase.database().ref('tests/issues/489/long2');
|
||||
const long2 = 1234567890123456;
|
||||
|
||||
let snapshot = await long1Ref.once('value');
|
||||
snapshot.val().should.eql(CONTENTS.ISSUES[489].long1);
|
||||
|
||||
await long2Ref.set(long2);
|
||||
snapshot = await long2Ref.once('value');
|
||||
snapshot.val().should.eql(long2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('issue_521', () => {
|
||||
describe('orderByChild (numerical field) and limitToLast', () => {
|
||||
it('once() returns correct results', async () => {
|
||||
const ref = firebase.database().ref('tests/issues/521');
|
||||
|
||||
const snapshot = await ref
|
||||
.orderByChild('number')
|
||||
.limitToLast(1)
|
||||
.once('value');
|
||||
|
||||
const val = snapshot.val();
|
||||
|
||||
val.key3.should.eql(jet.contextify(CONTENTS.ISSUES[521].key3));
|
||||
should.equal(Object.keys(val).length, 1);
|
||||
});
|
||||
|
||||
it('on() returns correct initial results', async () => {
|
||||
const ref = firebase
|
||||
.database()
|
||||
.ref('tests/issues/521')
|
||||
.orderByChild('number')
|
||||
.limitToLast(2);
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
await new Promise(resolve => {
|
||||
ref.on('value', snapshot => {
|
||||
callback(snapshot.val());
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith({
|
||||
key2: CONTENTS.ISSUES[521].key2,
|
||||
key3: CONTENTS.ISSUES[521].key3,
|
||||
});
|
||||
|
||||
callback.should.be.calledOnce();
|
||||
});
|
||||
|
||||
it('on() returns correct subsequent results', async () => {
|
||||
const ref = firebase
|
||||
.database()
|
||||
.ref('tests/issues/521')
|
||||
.orderByChild('number')
|
||||
.limitToLast(2);
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
await new Promise(resolve => {
|
||||
ref.on('value', snapshot => {
|
||||
callback(snapshot.val());
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith({
|
||||
key2: CONTENTS.ISSUES[521].key2,
|
||||
key3: CONTENTS.ISSUES[521].key3,
|
||||
});
|
||||
|
||||
callback.should.be.calledOnce();
|
||||
|
||||
const newDataValue = {
|
||||
name: 'Item 4',
|
||||
number: 4,
|
||||
string: 'item4',
|
||||
};
|
||||
|
||||
const newRef = firebase.database().ref('tests/issues/521/key4');
|
||||
|
||||
await newRef.set(newDataValue);
|
||||
await sleep(5);
|
||||
|
||||
callback.should.be.calledWith({
|
||||
key3: CONTENTS.ISSUES[521].key3,
|
||||
key4: newDataValue,
|
||||
});
|
||||
|
||||
callback.should.be.calledTwice();
|
||||
});
|
||||
});
|
||||
|
||||
describe('orderByChild (string field) and limitToLast', () => {
|
||||
it('once() returns correct results', async () => {
|
||||
const ref = firebase.database().ref('tests/issues/521');
|
||||
|
||||
const snapshot = await ref
|
||||
.orderByChild('string')
|
||||
.limitToLast(1)
|
||||
.once('value');
|
||||
|
||||
const val = snapshot.val();
|
||||
|
||||
val.key3.should.eql(jet.contextify(CONTENTS.ISSUES[521].key3));
|
||||
should.equal(Object.keys(val).length, 1);
|
||||
});
|
||||
|
||||
it('on() returns correct initial results', async () => {
|
||||
const ref = firebase
|
||||
.database()
|
||||
.ref('tests/issues/521')
|
||||
.orderByChild('string')
|
||||
.limitToLast(2);
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
await new Promise(resolve => {
|
||||
ref.on('value', snapshot => {
|
||||
callback(snapshot.val());
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith({
|
||||
key2: CONTENTS.ISSUES[521].key2,
|
||||
key3: CONTENTS.ISSUES[521].key3,
|
||||
});
|
||||
|
||||
callback.should.be.calledOnce();
|
||||
});
|
||||
|
||||
it('on() returns correct subsequent results', async () => {
|
||||
const ref = firebase
|
||||
.database()
|
||||
.ref('tests/issues/521')
|
||||
.orderByChild('string')
|
||||
.limitToLast(2);
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
await new Promise(resolve => {
|
||||
ref.on('value', snapshot => {
|
||||
callback(snapshot.val());
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith({
|
||||
key2: CONTENTS.ISSUES[521].key2,
|
||||
key3: CONTENTS.ISSUES[521].key3,
|
||||
});
|
||||
|
||||
callback.should.be.calledOnce();
|
||||
|
||||
const newDataValue = {
|
||||
name: 'Item 4',
|
||||
number: 4,
|
||||
string: 'item4',
|
||||
};
|
||||
|
||||
const newRef = firebase.database().ref('tests/issues/521/key4');
|
||||
await newRef.set(newDataValue);
|
||||
await sleep(5);
|
||||
|
||||
callback.should.be.calledWith({
|
||||
key3: CONTENTS.ISSUES[521].key3,
|
||||
key4: newDataValue,
|
||||
});
|
||||
|
||||
callback.should.be.calledTwice();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('issue_679', () => {
|
||||
describe('path from snapshot reference', () => {
|
||||
it('should match web SDK', async () => {
|
||||
const nativeRef = firebase.database().ref('tests/issues/679');
|
||||
const webRef = firebaseAdmin.database().ref('tests/issues/679');
|
||||
const nativeRef2 = firebase.database().ref('tests/issues/679/');
|
||||
const webRef2 = firebaseAdmin.database().ref('tests/issues/679/');
|
||||
|
||||
webRef.toString().should.equal(nativeRef.toString());
|
||||
webRef2.toString().should.equal(nativeRef2.toString());
|
||||
});
|
||||
|
||||
it('should be correct when returned from native', async () => {
|
||||
const nativeRef = firebase.database().ref('tests/issues/679/');
|
||||
const webRef = firebaseAdmin.database().ref('tests/issues/679/');
|
||||
|
||||
const nativeSnapshot = await nativeRef.once('value');
|
||||
const webSnapshot = await webRef.once('value');
|
||||
|
||||
webSnapshot.ref.toString().should.equal(nativeSnapshot.ref.toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,39 +0,0 @@
|
||||
const { setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
|
||||
describe('ref().child', () => {
|
||||
describe('when passed a shallow path', () => {
|
||||
it('returns correct child ref', () => {
|
||||
const ref = firebase.database().ref('tests');
|
||||
const childRef = ref.child('tests');
|
||||
childRef.key.should.eql('tests');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passed a nested path', () => {
|
||||
it('returns correct child ref', () => {
|
||||
const ref = firebase.database().ref('tests');
|
||||
const grandChildRef = ref.child('tests/number');
|
||||
grandChildRef.key.should.eql('number');
|
||||
});
|
||||
});
|
||||
|
||||
describe("when passed a path that doesn't exist", () => {
|
||||
it('creates a reference, anyway', () => {
|
||||
const ref = firebase.database().ref('tests');
|
||||
const grandChildRef = ref.child('doesnt/exist');
|
||||
grandChildRef.key.should.eql('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passed an invalid path', () => {
|
||||
it('creates a reference, anyway', () => {
|
||||
const ref = firebase.database().ref('tests');
|
||||
const grandChildRef = ref.child('does$&nt/exist');
|
||||
grandChildRef.key.should.eql('exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
const { CONTENTS, setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
|
||||
describe('ref()', () => {
|
||||
it('returns root reference when provided no path', () => {
|
||||
const ref = firebase.database().ref();
|
||||
(ref.key === null).should.be.true();
|
||||
(ref.parent === null).should.be.true();
|
||||
});
|
||||
|
||||
it('returns reference to data at path', async () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
|
||||
let valueAtRef;
|
||||
await ref.once('value', snapshot => {
|
||||
valueAtRef = snapshot.val();
|
||||
});
|
||||
|
||||
valueAtRef.should.eql(CONTENTS.DEFAULT.number);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
const { setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
|
||||
describe('ref().isEqual()', () => {
|
||||
before(() => {
|
||||
this.ref = firebase.database().ref('tests/types');
|
||||
});
|
||||
|
||||
it('returns true when the reference is for the same location', () => {
|
||||
const ref = firebase.database().ref();
|
||||
ref.ref.should.eql(ref);
|
||||
|
||||
const ref2 = firebase.database().ref('tests/types');
|
||||
this.ref.isEqual(ref2).should.eql(true);
|
||||
});
|
||||
|
||||
it('returns false when the reference is for a different location', () => {
|
||||
const ref2 = firebase.database().ref('tests/types/number');
|
||||
this.ref.isEqual(ref2).should.eql(false);
|
||||
});
|
||||
|
||||
it('returns false when the reference is null', () => {
|
||||
this.ref.isEqual(null).should.eql(false);
|
||||
});
|
||||
|
||||
it('returns false when the reference is not a Reference', () => {
|
||||
this.ref.isEqual(1).should.eql(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
describe('database()', () => {
|
||||
describe('ref().key', () => {
|
||||
it('returns null for root ref', () => {
|
||||
const ref = firebase.database().ref();
|
||||
(ref.key === null).should.be.true();
|
||||
});
|
||||
|
||||
it('returns correct key for path', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const arrayItemRef = firebase.database().ref('tests/types/array/1');
|
||||
|
||||
ref.key.should.eql('number');
|
||||
arrayItemRef.key.should.eql('1');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,89 +0,0 @@
|
||||
const { CONTENTS, setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
describe('ref().on("value")', () => {
|
||||
it('throws without second argument', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
(() => ref.on('value')).should.throw(
|
||||
'Query.on failed: Function called with 1 argument. Expects at least 2.'
|
||||
);
|
||||
});
|
||||
it('returns a function', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const unsub = ref.on('value', () => {});
|
||||
unsub.should.be.Function();
|
||||
unsub();
|
||||
});
|
||||
it('resolves with the correct value and key', async () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const nodeValue = await new Promise(resolve => {
|
||||
const unsub = ref.on('value', v => {
|
||||
if (!v) return;
|
||||
const nodeValue = v.val();
|
||||
unsub();
|
||||
nodeValue.should.be.Number();
|
||||
v.key.should.be.String();
|
||||
v.key.should.equal('number');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('is called again when the value changes', async () => {
|
||||
const callback = sinon.spy();
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const unsub = ref.on('value', callback);
|
||||
// To know how long to wait
|
||||
await ref.once('value');
|
||||
callback.should.be.calledOnce();
|
||||
await ref.set(CONTENTS.NEW.number);
|
||||
// To know how long to wait
|
||||
await ref.once('value');
|
||||
callback.should.be.calledTwice();
|
||||
unsub();
|
||||
});
|
||||
});
|
||||
describe('ref().on("child_added")', () => {
|
||||
it('returns a function', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const unsub = ref.on('child_added', () => {});
|
||||
unsub.should.be.Function();
|
||||
unsub();
|
||||
});
|
||||
});
|
||||
describe('ref().on("child_removed")', () => {
|
||||
it('returns a function', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const unsub = ref.on('child_removed', () => {});
|
||||
unsub.should.be.Function();
|
||||
unsub();
|
||||
});
|
||||
});
|
||||
describe('ref().on("child_moved")', () => {
|
||||
it('returns a function', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const unsub = ref.on('child_moved', () => {});
|
||||
unsub.should.be.Function();
|
||||
unsub();
|
||||
});
|
||||
});
|
||||
describe('ref().on("child_changed")', () => {
|
||||
it('returns a function', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const unsub = ref.on('child_changed', () => {});
|
||||
unsub.should.be.Function();
|
||||
unsub();
|
||||
});
|
||||
});
|
||||
describe('ref().on("INVALID_EVENT_NAME")', () => {
|
||||
it('throws', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
(() => {
|
||||
const unsub = ref.on('INVALID_EVENT_NAME', () => {});
|
||||
}).should.throw(
|
||||
'Query.on failed: First argument must be a valid string event type: "value, child_added, child_removed, child_changed, child_moved"'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
const { CONTENTS, setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
|
||||
describe('ref().once()', () => {
|
||||
it('returns a promise', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const returnValue = ref.once('value');
|
||||
returnValue.should.be.Promise();
|
||||
});
|
||||
|
||||
it('resolves with the correct value', async () => {
|
||||
await Promise.all(
|
||||
Object.keys(CONTENTS.DEFAULT).map(dataRef => {
|
||||
const dataTypeValue = CONTENTS.DEFAULT[dataRef];
|
||||
const ref = firebase.database().ref(`tests/types/${dataRef}`);
|
||||
return ref.once('value').then(snapshot => {
|
||||
snapshot.val().should.eql(jet.contextify(dataTypeValue));
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('is NOT called when the value is changed', async () => {
|
||||
const callback = sinon.spy();
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
ref.once('value').then(callback);
|
||||
await ref.set(CONTENTS.NEW.number);
|
||||
callback.should.be.calledOnce();
|
||||
});
|
||||
|
||||
it('errors if permission denied', async () => {
|
||||
const reference = firebase.database().ref('nope');
|
||||
|
||||
try {
|
||||
await reference.once('value');
|
||||
} catch (error) {
|
||||
error.code.includes('database/permission-denied').should.be.true();
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Error('No permission denied error');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
describe('database()', () => {
|
||||
describe('ref().parent', () => {
|
||||
describe('on the root ref', () => {
|
||||
it('returns null', () => {
|
||||
const ref = firebase.database().ref();
|
||||
(ref.parent === null).should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('on a non-root ref', () => {
|
||||
it('returns correct parent', () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const parentRef = firebase.database().ref('tests/types');
|
||||
|
||||
ref.parent.key.should.eql(parentRef.key);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
const { CONTENTS, setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
|
||||
describe('ref().priority', () => {
|
||||
it('setPriority() should correctly set a priority for all non-null values', async () => {
|
||||
await Promise.all(
|
||||
Object.keys(CONTENTS.DEFAULT).map(async dataRef => {
|
||||
const ref = firebase.database().ref(`tests/types/${dataRef}`);
|
||||
|
||||
await ref.setPriority(1);
|
||||
|
||||
await ref.once('value').then(snapshot => {
|
||||
if (snapshot.val() !== null) {
|
||||
snapshot.getPriority().should.eql(1);
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('setWithPriority() should correctly set the priority', async () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
|
||||
await ref.setWithPriority(CONTENTS.DEFAULT.number, '2');
|
||||
|
||||
await ref.once('value').then(snapshot => {
|
||||
snapshot.getPriority().should.eql('2');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,126 +0,0 @@
|
||||
const { CONTENTS, setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
|
||||
describe('ref().push()', () => {
|
||||
it('returns a ref that can be used to set value later', async () => {
|
||||
const ref = firebase.database().ref('tests/types/array');
|
||||
|
||||
let originalListValue;
|
||||
await ref.once('value', snapshot => {
|
||||
originalListValue = snapshot.val();
|
||||
});
|
||||
await sleep(5);
|
||||
|
||||
originalListValue.should.eql(jet.contextify(CONTENTS.DEFAULT.array));
|
||||
|
||||
const newItemRef = ref.push();
|
||||
const valueToAddToList = CONTENTS.NEW.number;
|
||||
await newItemRef.set(valueToAddToList);
|
||||
|
||||
let newItemValue;
|
||||
await newItemRef.once('value', snapshot => {
|
||||
newItemValue = snapshot.val();
|
||||
});
|
||||
await sleep(5);
|
||||
|
||||
newItemValue.should.eql(valueToAddToList);
|
||||
|
||||
let newListValue;
|
||||
await ref.once('value', snapshot => {
|
||||
newListValue = snapshot.val();
|
||||
});
|
||||
await sleep(5);
|
||||
|
||||
const originalListAsObject = {
|
||||
...originalListValue,
|
||||
[newItemRef.key]: valueToAddToList,
|
||||
};
|
||||
|
||||
newListValue.should.eql(jet.contextify(originalListAsObject));
|
||||
});
|
||||
|
||||
it('allows setting value immediately', async () => {
|
||||
let snapshot;
|
||||
|
||||
const ref = firebase.database().ref('tests/types/array');
|
||||
const valueToAddToList = CONTENTS.NEW.number;
|
||||
|
||||
snapshot = await ref.once('value');
|
||||
const originalListValue = snapshot.val();
|
||||
const newItemRef = ref.push(valueToAddToList);
|
||||
|
||||
snapshot = await newItemRef.once('value');
|
||||
const newItemValue = snapshot.val();
|
||||
newItemValue.should.eql(valueToAddToList);
|
||||
|
||||
snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/types/array')
|
||||
.once('value');
|
||||
const newListValue = snapshot.val();
|
||||
|
||||
const originalListAsObject = {
|
||||
...originalListValue,
|
||||
[newItemRef.key]: valueToAddToList,
|
||||
};
|
||||
|
||||
newListValue.should.eql(jet.contextify(originalListAsObject));
|
||||
});
|
||||
|
||||
// https://github.com/invertase/react-native-firebase/issues/893
|
||||
it('correctly returns the reference', async () => {
|
||||
let result;
|
||||
const path = 'tests/types/array';
|
||||
const valueToAddToList = CONTENTS.NEW.number;
|
||||
const Reference = jet.require('src/modules/database/Reference');
|
||||
|
||||
// 1
|
||||
const ref1 = firebase
|
||||
.database()
|
||||
.ref(path)
|
||||
.push();
|
||||
|
||||
should.exist(ref1, 'ref1 did not return a Reference instance');
|
||||
ref1.key.should.be.a.String();
|
||||
ref1.should.be.instanceOf(Reference);
|
||||
result = await ref1.set(valueToAddToList);
|
||||
should.not.exist(result);
|
||||
|
||||
// 2
|
||||
const ref2 = await firebase
|
||||
.database()
|
||||
.ref(path)
|
||||
.push(valueToAddToList);
|
||||
|
||||
should.exist(ref2, 'ref2 did not return a Reference instance');
|
||||
ref2.key.should.be.a.String();
|
||||
ref2.should.be.instanceOf(Reference);
|
||||
|
||||
// 3
|
||||
const ref3 = await firebase
|
||||
.database()
|
||||
.ref(path)
|
||||
.push();
|
||||
|
||||
should.exist(ref3, 'ref3 did not return a Reference instance');
|
||||
ref3.key.should.be.a.String();
|
||||
ref3.should.be.instanceOf(Reference);
|
||||
|
||||
result = await ref3.set(valueToAddToList);
|
||||
should.not.exist(result);
|
||||
});
|
||||
|
||||
it('calls an onComplete callback', async () => {
|
||||
const callback = sinon.spy();
|
||||
const ref = firebase.database().ref('tests/types/array');
|
||||
|
||||
const valueToAddToList = CONTENTS.NEW.number;
|
||||
const newItemRef = await ref.push(valueToAddToList, callback);
|
||||
|
||||
callback.should.be.calledWith(null);
|
||||
newItemRef.parent.path.should.equal('tests/types/array');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
const { CONTENTS, setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
|
||||
describe('ref() query', () => {
|
||||
it('orderByChild().equalTo()', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/query')
|
||||
.orderByChild('search')
|
||||
.equalTo('foo')
|
||||
.once('value');
|
||||
|
||||
const val = snapshot.val();
|
||||
CONTENTS.QUERY[0].should.eql({ ...val[0] });
|
||||
});
|
||||
|
||||
it('orderByKey()', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/query')
|
||||
.orderByKey()
|
||||
.once('value');
|
||||
|
||||
const val = snapshot.val();
|
||||
for (let i = 0; i < CONTENTS.QUERY.length; i += 1) {
|
||||
CONTENTS.QUERY[i].should.eql({ ...val[i] });
|
||||
}
|
||||
});
|
||||
|
||||
it('orderByKey().limitToFirst()', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/query')
|
||||
.orderByKey()
|
||||
.limitToFirst(1)
|
||||
.once('value');
|
||||
|
||||
const val = snapshot.val();
|
||||
CONTENTS.QUERY[0].should.eql({ ...val[0] });
|
||||
});
|
||||
it('orderByPriority()', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/query')
|
||||
.orderByPriority()
|
||||
.once('value');
|
||||
|
||||
const val = snapshot.val();
|
||||
for (let i = 0; i < CONTENTS.QUERY.length; i += 1) {
|
||||
CONTENTS.QUERY[i].should.eql({ ...val[i] });
|
||||
}
|
||||
});
|
||||
// TODO more query tests
|
||||
});
|
||||
});
|
||||
@@ -1,52 +0,0 @@
|
||||
const { setDatabaseContents, CONTENTS } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
beforeEach(() => setDatabaseContents());
|
||||
|
||||
describe('ref.set()', () => {
|
||||
it('returns a promise', async () => {
|
||||
const ref = firebase.database().ref('tests/types/number');
|
||||
const returnValue = ref.set(CONTENTS.DEFAULT.number);
|
||||
returnValue.should.be.Promise();
|
||||
|
||||
const value = await returnValue;
|
||||
(value === null).should.be.true();
|
||||
});
|
||||
|
||||
it('changes value', async () => {
|
||||
await Promise.all(
|
||||
Object.keys(CONTENTS.DEFAULT).map(async dataRef => {
|
||||
const previousValue = jet.contextify(CONTENTS.DEFAULT[dataRef]);
|
||||
|
||||
const ref = firebase.database().ref(`tests/types/${dataRef}`);
|
||||
|
||||
const snapshot = await ref.once('value');
|
||||
snapshot.val().should.eql(previousValue);
|
||||
|
||||
const newValue = jet.contextify(CONTENTS.NEW[dataRef]);
|
||||
|
||||
await ref.set(newValue);
|
||||
|
||||
const snapshot2 = await ref.once('value');
|
||||
snapshot2.val().should.eql(newValue);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('can unset values', async () => {
|
||||
await Promise.all(
|
||||
Object.keys(CONTENTS.DEFAULT).map(async dataRef => {
|
||||
const previousValue = jet.contextify(CONTENTS.DEFAULT[dataRef]);
|
||||
const ref = firebase.database().ref(`tests/types/${dataRef}`);
|
||||
|
||||
const snapshot = await ref.once('value');
|
||||
snapshot.val().should.eql(previousValue);
|
||||
|
||||
await ref.set(null);
|
||||
const snapshot2 = await ref.once('value');
|
||||
(snapshot2.val() === null).should.be.true();
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
const { setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
// TODO use testRunId in refs to prevent multiple test instances interfering with each other
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
describe('ref.transaction()', () => {
|
||||
it('increments a value', async () => {
|
||||
let valueBefore = 1;
|
||||
const ref = firebase.database().ref('tests/transaction');
|
||||
|
||||
const { committed, snapshot } = await ref.transaction(currentData => {
|
||||
if (currentData === null) {
|
||||
return valueBefore + 10;
|
||||
}
|
||||
valueBefore = currentData;
|
||||
return valueBefore + 10;
|
||||
}, true);
|
||||
|
||||
should.equal(committed, true, 'Transaction did not commit.');
|
||||
snapshot.val().should.equal(valueBefore + 10);
|
||||
});
|
||||
|
||||
it('aborts if undefined returned', async () => {
|
||||
const ref = firebase.database().ref('tests/transaction');
|
||||
|
||||
const { committed } = await ref.transaction(() => undefined, true);
|
||||
should.equal(
|
||||
committed,
|
||||
false,
|
||||
'Transaction committed and did not abort.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,97 +0,0 @@
|
||||
const { CONTENTS, setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
before(() => setDatabaseContents());
|
||||
|
||||
describe('ref().once()', () => {
|
||||
it('same reference path works after React Native reload', async () => {
|
||||
let ref;
|
||||
let snapshot;
|
||||
const path = 'tests/types/number';
|
||||
const dataTypeValue = CONTENTS.DEFAULT.number;
|
||||
|
||||
// before reload
|
||||
ref = firebase.database().ref(path);
|
||||
snapshot = await ref.once('value');
|
||||
snapshot.val().should.eql(dataTypeValue);
|
||||
|
||||
// RELOAD
|
||||
await device.reloadReactNative();
|
||||
|
||||
// after reload
|
||||
ref = firebase.database().ref(path);
|
||||
snapshot = await ref.once('value');
|
||||
snapshot.val().should.eql(dataTypeValue);
|
||||
}).timeout(15000);
|
||||
|
||||
it(':android: same reference path works after app backgrounded', async () => {
|
||||
let ref;
|
||||
let snapshot;
|
||||
const path = 'tests/types/number';
|
||||
const dataTypeValue = CONTENTS.DEFAULT.number;
|
||||
|
||||
// before
|
||||
ref = firebase.database().ref(path);
|
||||
snapshot = await ref.once('value');
|
||||
snapshot.val().should.eql(dataTypeValue);
|
||||
|
||||
await device.sendToHome();
|
||||
await sleep(250);
|
||||
await device.launchApp({ newInstance: false });
|
||||
await sleep(250);
|
||||
|
||||
// after
|
||||
ref = firebase.database().ref(path);
|
||||
snapshot = await ref.once('value');
|
||||
snapshot.val().should.eql(dataTypeValue);
|
||||
}).timeout(15000);
|
||||
});
|
||||
|
||||
describe('ref().on()', () => {
|
||||
it('same reference path works after React Native reload', async () => {
|
||||
let ref;
|
||||
let snapshot;
|
||||
const path = 'tests/types/number';
|
||||
const dataTypeValue = CONTENTS.DEFAULT.number;
|
||||
|
||||
// before reload
|
||||
ref = firebase.database().ref(path);
|
||||
snapshot = await new Promise(resolve => ref.on('value', resolve));
|
||||
snapshot.val().should.eql(dataTypeValue);
|
||||
|
||||
// RELOAD
|
||||
await device.reloadReactNative();
|
||||
|
||||
// after reload
|
||||
ref = firebase.database().ref(path);
|
||||
snapshot = await new Promise(resolve => ref.on('value', resolve));
|
||||
snapshot.val().should.eql(dataTypeValue);
|
||||
|
||||
firebase.utils().database.cleanup();
|
||||
}).timeout(15000);
|
||||
|
||||
it(':android: same reference path works after app backgrounded', async () => {
|
||||
let ref;
|
||||
let snapshot;
|
||||
const path = 'tests/types/number';
|
||||
const dataTypeValue = CONTENTS.DEFAULT.number;
|
||||
|
||||
// before background
|
||||
ref = firebase.database().ref(path);
|
||||
snapshot = await new Promise(resolve => ref.on('value', resolve));
|
||||
snapshot.val().should.eql(dataTypeValue);
|
||||
|
||||
await device.sendToHome();
|
||||
await sleep(250);
|
||||
await device.launchApp({ newInstance: false });
|
||||
await sleep(250);
|
||||
|
||||
// after background
|
||||
ref = firebase.database().ref(path);
|
||||
snapshot = await new Promise(resolve => ref.on('value', resolve));
|
||||
snapshot.val().should.eql(dataTypeValue);
|
||||
|
||||
firebase.utils().database.cleanup();
|
||||
}).timeout(15000);
|
||||
});
|
||||
});
|
||||
@@ -1,103 +0,0 @@
|
||||
const { setDatabaseContents } = TestHelpers.database;
|
||||
|
||||
describe('database()', () => {
|
||||
describe('Snapshot', () => {
|
||||
before(() => setDatabaseContents());
|
||||
|
||||
it('should provide a functioning val() method', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/types/array')
|
||||
.once('value');
|
||||
|
||||
snapshot.val.should.be.a.Function();
|
||||
snapshot.val().should.eql(jet.Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
|
||||
});
|
||||
|
||||
it('should provide a functioning child() method', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/types/array')
|
||||
.once('value');
|
||||
|
||||
snapshot.child('0').val.should.be.a.Function();
|
||||
snapshot
|
||||
.child('0')
|
||||
.val()
|
||||
.should.equal(0);
|
||||
snapshot.child('0').key.should.be.a.String();
|
||||
snapshot.child('0').key.should.equal('0');
|
||||
});
|
||||
|
||||
// TODO refactor
|
||||
it('should provide a functioning hasChild() method', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/types/object')
|
||||
.once('value');
|
||||
|
||||
snapshot.hasChild.should.be.a.Function();
|
||||
snapshot.hasChild('foo').should.equal(true);
|
||||
snapshot.hasChild('baz').should.equal(false);
|
||||
});
|
||||
|
||||
it('should provide a functioning hasChildren() method', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/types/object')
|
||||
.once('value');
|
||||
|
||||
snapshot.hasChildren.should.be.a.Function();
|
||||
snapshot.hasChildren().should.equal(true);
|
||||
snapshot
|
||||
.child('foo')
|
||||
.hasChildren()
|
||||
.should.equal(false);
|
||||
});
|
||||
|
||||
it('should provide a functioning exists() method', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/types/object/baz/daz')
|
||||
.once('value');
|
||||
|
||||
snapshot.exists.should.be.a.Function();
|
||||
snapshot.exists().should.equal(false);
|
||||
});
|
||||
|
||||
it('should provide a functioning getPriority() method', async () => {
|
||||
const ref = firebase.database().ref('tests/priority');
|
||||
const snapshot = await ref.once('value');
|
||||
snapshot.getPriority.should.be.a.Function();
|
||||
snapshot.getPriority().should.equal(666);
|
||||
snapshot.val().should.eql(jet.Object({ foo: 'bar' }));
|
||||
});
|
||||
|
||||
it('should provide a functioning forEach() method', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/types/array')
|
||||
.once('value');
|
||||
|
||||
let total = 0;
|
||||
snapshot.forEach.should.be.a.Function();
|
||||
snapshot.forEach(childSnapshot => {
|
||||
const val = childSnapshot.val();
|
||||
total += val;
|
||||
return val === 3; // stop iteration after key 3
|
||||
});
|
||||
|
||||
total.should.equal(6); // 0 + 1 + 2 + 3 = 6
|
||||
});
|
||||
|
||||
it('should provide a key property', async () => {
|
||||
const snapshot = await firebase
|
||||
.database()
|
||||
.ref('tests/types/array')
|
||||
.once('value');
|
||||
|
||||
snapshot.key.should.be.a.String();
|
||||
snapshot.key.should.equal('array');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,79 +0,0 @@
|
||||
const { testDocRef } = TestHelpers.firestore;
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('batch()', () => {
|
||||
it('should create / update / delete', async () => {
|
||||
const ayRef = testDocRef('AY');
|
||||
const lRef = testDocRef('LON');
|
||||
const nycRef = testDocRef('NYC');
|
||||
const sfRef = testDocRef('SF');
|
||||
const batch = firebase.firestore().batch();
|
||||
|
||||
batch.set(ayRef, { name: 'Aylesbury' });
|
||||
batch.set(lRef, { name: 'London' });
|
||||
batch.set(nycRef, { name: 'New York City' });
|
||||
batch.set(sfRef, { name: 'San Francisco' });
|
||||
|
||||
batch.update(nycRef, { population: 1000000 });
|
||||
batch.update(sfRef, 'name', 'San Fran');
|
||||
batch.update(
|
||||
sfRef,
|
||||
new firebase.firestore.FieldPath('name'),
|
||||
'San Fran FieldPath'
|
||||
);
|
||||
batch.update(
|
||||
sfRef,
|
||||
new firebase.firestore.FieldPath('nested', 'name'),
|
||||
'Nested Nme'
|
||||
);
|
||||
batch.update(
|
||||
sfRef,
|
||||
new firebase.firestore.FieldPath('nested', 'firstname'),
|
||||
'First Name',
|
||||
new firebase.firestore.FieldPath('nested', 'lastname'),
|
||||
'Last Name'
|
||||
);
|
||||
|
||||
batch.set(lRef, { population: 3000000 }, { merge: true });
|
||||
batch.delete(ayRef);
|
||||
|
||||
await batch.commit();
|
||||
|
||||
const ayDoc = await ayRef.get();
|
||||
should.equal(ayDoc.exists, false);
|
||||
|
||||
const lDoc = await lRef.get();
|
||||
lDoc.data().name.should.equal('London');
|
||||
lDoc.data().population.should.equal(3000000);
|
||||
|
||||
const nycDoc = await nycRef.get();
|
||||
nycDoc.data().name.should.equal('New York City');
|
||||
nycDoc.data().population.should.equal(1000000);
|
||||
|
||||
const sfDoc = await sfRef.get();
|
||||
sfDoc.data().name.should.equal('San Fran FieldPath');
|
||||
sfDoc.data().nested.firstname.should.equal('First Name');
|
||||
sfDoc.data().nested.lastname.should.equal('Last Name');
|
||||
});
|
||||
|
||||
it('errors when invalid parameters supplied', async () => {
|
||||
const ref = firebase.firestore().doc('collection/doc');
|
||||
const batch = firebase.firestore().batch();
|
||||
(() => {
|
||||
batch.update(ref, 'error');
|
||||
}).should.throw(
|
||||
'WriteBatch.update failed: If using a single update argument, it must be an object.'
|
||||
);
|
||||
(() => {
|
||||
batch.update(ref, 'error1', 'error2', 'error3');
|
||||
}).should.throw(
|
||||
'WriteBatch.update failed: The update arguments must be either a single object argument, or equal numbers of key/value pairs.'
|
||||
);
|
||||
(() => {
|
||||
batch.update(ref, 0, 'error');
|
||||
}).should.throw(
|
||||
'WriteBatch.update failed: Argument at index 0 must be a string or FieldPath'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,156 +0,0 @@
|
||||
const testObject = { hello: 'world', testRunId };
|
||||
const testString = JSON.stringify(testObject);
|
||||
const testBuffer = Buffer.from(testString);
|
||||
const testBase64 = testBuffer.toString('base64');
|
||||
|
||||
const testObjectLarge = new Array(5000).fill(testObject);
|
||||
const testStringLarge = JSON.stringify(testObjectLarge);
|
||||
const testBufferLarge = Buffer.from(testStringLarge);
|
||||
const testBase64Large = testBufferLarge.toString('base64');
|
||||
|
||||
/** ----------------
|
||||
* CLASS TESTS
|
||||
* -----------------*/
|
||||
describe('firestore', () => {
|
||||
it('should export Blob class on statics', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
should.exist(Blob);
|
||||
});
|
||||
|
||||
describe('Blob', () => {
|
||||
it('.constructor() -> returns new instance of Blob', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = new Blob(testStringLarge);
|
||||
myBlob.should.be.instanceOf(Blob);
|
||||
myBlob._binaryString.should.equal(testStringLarge);
|
||||
myBlob.toBase64().should.equal(testBase64Large);
|
||||
});
|
||||
|
||||
it('.fromBase64String() -> returns new instance of Blob', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = Blob.fromBase64String(testBase64);
|
||||
myBlob.should.be.instanceOf(Blob);
|
||||
myBlob._binaryString.should.equal(testString);
|
||||
should.deepEqual(
|
||||
JSON.parse(myBlob._binaryString),
|
||||
testObject,
|
||||
'Expected Blob _binaryString internals to serialize to json and match test object'
|
||||
);
|
||||
});
|
||||
|
||||
it('.fromBase64String() -> throws if arg not typeof string and length > 0', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = Blob.fromBase64String(testBase64);
|
||||
myBlob.should.be.instanceOf(Blob);
|
||||
(() => Blob.fromBase64String(1234)).should.throwError();
|
||||
(() => Blob.fromBase64String('')).should.throwError();
|
||||
});
|
||||
|
||||
it('.fromUint8Array() -> returns new instance of Blob', async () => {
|
||||
const testUInt8Array = new Uint8Array(testBuffer);
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = Blob.fromUint8Array(testUInt8Array);
|
||||
myBlob.should.be.instanceOf(Blob);
|
||||
const json = JSON.parse(myBlob._binaryString);
|
||||
json.hello.should.equal('world');
|
||||
});
|
||||
|
||||
it('.fromUint8Array() -> throws if arg not instanceof Uint8Array', async () => {
|
||||
const testUInt8Array = new Uint8Array(testBuffer);
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = Blob.fromUint8Array(testUInt8Array);
|
||||
myBlob.should.be.instanceOf(Blob);
|
||||
(() => Blob.fromUint8Array('derp')).should.throwError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Blob instance', () => {
|
||||
it('.toString() -> returns string representation of blob instance', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = Blob.fromBase64String(testBase64);
|
||||
myBlob.should.be.instanceOf(Blob);
|
||||
should.equal(
|
||||
myBlob.toString().includes(testBase64),
|
||||
true,
|
||||
'toString() should return a string that includes the base64'
|
||||
);
|
||||
});
|
||||
|
||||
it('.isEqual() -> returns true or false', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = Blob.fromBase64String(testBase64);
|
||||
const myBlob2 = Blob.fromBase64String(testBase64Large);
|
||||
myBlob.isEqual(myBlob).should.equal(true);
|
||||
myBlob2.isEqual(myBlob).should.equal(false);
|
||||
});
|
||||
|
||||
it('.isEqual() -> throws if arg not instanceof Blob', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = Blob.fromBase64String(testBase64);
|
||||
const myBlob2 = Blob.fromBase64String(testBase64Large);
|
||||
myBlob.isEqual(myBlob).should.equal(true);
|
||||
(() => myBlob2.isEqual('derp')).should.throwError();
|
||||
});
|
||||
|
||||
it('.toBase64() -> returns base64 string', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = Blob.fromBase64String(testBase64);
|
||||
myBlob.should.be.instanceOf(Blob);
|
||||
myBlob.toBase64().should.equal(testBase64);
|
||||
});
|
||||
|
||||
it('.toUint8Array() -> returns Uint8Array', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
const myBlob = Blob.fromBase64String(testBase64);
|
||||
const testUInt8Array = new Uint8Array(testBuffer);
|
||||
const testUInt8Array2 = new Uint8Array();
|
||||
|
||||
myBlob.should.be.instanceOf(Blob);
|
||||
should.deepEqual(myBlob.toUint8Array(), testUInt8Array);
|
||||
should.notDeepEqual(myBlob.toUint8Array(), testUInt8Array2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/** ----------------
|
||||
* USAGE TESTS
|
||||
* -----------------*/
|
||||
describe('firestore', () => {
|
||||
describe('Blob', () => {
|
||||
it('reads and writes small blobs', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
|
||||
await firebase
|
||||
.firestore()
|
||||
.doc('blob-tests/small')
|
||||
.set({ blobby: Blob.fromBase64String(testBase64) });
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.doc('blob-tests/small')
|
||||
.get();
|
||||
|
||||
const blob = snapshot.data().blobby;
|
||||
blob._binaryString.should.equal(testString);
|
||||
blob.toBase64().should.equal(testBase64);
|
||||
});
|
||||
|
||||
it('reads and writes large blobs', async () => {
|
||||
const { Blob } = firebase.firestore;
|
||||
|
||||
await firebase
|
||||
.firestore()
|
||||
.doc('blob-tests/large')
|
||||
.set({ blobby: Blob.fromBase64String(testBase64Large) });
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.doc('blob-tests/large')
|
||||
.get();
|
||||
|
||||
const blob = snapshot.data().blobby;
|
||||
blob._binaryString.should.equal(testStringLarge);
|
||||
blob.toBase64().should.equal(testBase64Large);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,532 +0,0 @@
|
||||
const {
|
||||
COL_DOC_1,
|
||||
cleanCollection,
|
||||
TEST_COLLECTION_NAME_DYNAMIC,
|
||||
} = TestHelpers.firestore;
|
||||
|
||||
describe('firestore()', () => {
|
||||
before(async () => {
|
||||
await cleanCollection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
const collection = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
await Promise.all([
|
||||
collection.doc('col1').set({ ...COL_DOC_1(), foo: 'bar0' }),
|
||||
collection.doc('col2').set({
|
||||
...COL_DOC_1(),
|
||||
foo: 'bar1',
|
||||
daz: 234,
|
||||
object: { daz: 234 },
|
||||
timestamp: new jet.context.window.Date(2017, 2, 11, 10, 0, 0),
|
||||
}),
|
||||
collection.doc('col3').set({
|
||||
...COL_DOC_1(),
|
||||
foo: 'bar2',
|
||||
daz: 345,
|
||||
object: { daz: 345 },
|
||||
timestamp: new jet.context.window.Date(2017, 2, 12, 10, 0, 0),
|
||||
}),
|
||||
collection.doc('col4').set({
|
||||
...COL_DOC_1(),
|
||||
foo: 'bar3',
|
||||
daz: 456,
|
||||
object: { daz: 456 },
|
||||
timestamp: new jet.context.window.Date(2017, 2, 13, 10, 0, 0),
|
||||
}),
|
||||
collection.doc('col5').set({
|
||||
...COL_DOC_1(),
|
||||
foo: 'bar4',
|
||||
daz: 567,
|
||||
object: { daz: 567 },
|
||||
timestamp: new jet.context.window.Date(2017, 2, 14, 10, 0, 0),
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
describe('CollectionReference', () => {
|
||||
describe('cursors', () => {
|
||||
describe('endAt', () => {
|
||||
it('handles dates', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('timestamp')
|
||||
.endAt(new jet.context.window.Date(2017, 2, 12, 10, 0, 0))
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
345,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles numbers', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('daz')
|
||||
.endAt(345)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
345,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles strings', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.endAt('bar2')
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
345,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles snapshots', async () => {
|
||||
const collectionSnapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.get();
|
||||
|
||||
return firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.endAt(collectionSnapshot.docs[2])
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
345,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with FieldPath', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy(new firebase.firestore.FieldPath('timestamp'))
|
||||
.endAt(new jet.context.window.Date(2017, 2, 12, 10, 0, 0))
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
345,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles snapshots with FieldPath', async () => {
|
||||
const collectionSnapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy(new firebase.firestore.FieldPath('foo'))
|
||||
.get();
|
||||
return firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.endAt(collectionSnapshot.docs[2])
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
345,
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('endBefore', () => {
|
||||
it('handles dates', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('timestamp')
|
||||
.endBefore(new jet.context.window.Date(2017, 2, 12, 10, 0, 0))
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles numbers', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('daz')
|
||||
.endBefore(345)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles strings', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.endBefore('bar2')
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles snapshots', async () => {
|
||||
const collectionSnapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.get();
|
||||
|
||||
return firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.endBefore(collectionSnapshot.docs[2])
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with FieldPath', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy(new firebase.firestore.FieldPath('timestamp'))
|
||||
.endBefore(new jet.context.window.Date(2017, 2, 12, 10, 0, 0))
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles snapshots with FieldPath', async () => {
|
||||
const collectionSnapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy(new firebase.firestore.FieldPath('foo'))
|
||||
.get();
|
||||
return firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.endBefore(collectionSnapshot.docs[2])
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
123,
|
||||
234,
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('startAt', () => {
|
||||
it('handles dates', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('timestamp')
|
||||
.startAt(new jet.context.window.Date(2017, 2, 12, 10, 0, 0))
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
345,
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles numbers', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('daz')
|
||||
.startAt(345)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
345,
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles strings', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.startAt('bar2')
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
345,
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles snapshots', async () => {
|
||||
const collectionSnapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.get();
|
||||
return firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.startAt(collectionSnapshot.docs[2])
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
345,
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with FieldPath', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy(new firebase.firestore.FieldPath('timestamp'))
|
||||
.startAt(new jet.context.window.Date(2017, 2, 12, 10, 0, 0))
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
345,
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles snapshots with FieldPath', async () => {
|
||||
const collectionSnapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy(new firebase.firestore.FieldPath('foo'))
|
||||
.get();
|
||||
return firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.startAt(collectionSnapshot.docs[2])
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
345,
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('startAfter', () => {
|
||||
it('handles dates', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('timestamp')
|
||||
.startAfter(new jet.context.window.Date(2017, 2, 12, 10, 0, 0))
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles numbers', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('daz')
|
||||
.startAfter(345)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles strings', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.startAfter('bar2')
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles snapshot', async () => {
|
||||
const collectionSnapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.get();
|
||||
return firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.startAfter(collectionSnapshot.docs[2])
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with FieldPath', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy(new firebase.firestore.FieldPath('timestamp'))
|
||||
.startAfter(new jet.context.window.Date(2017, 2, 12, 10, 0, 0))
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
}));
|
||||
|
||||
it('handles snapshots with FieldPath', async () => {
|
||||
const collectionSnapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy(new firebase.firestore.FieldPath('foo'))
|
||||
.get();
|
||||
|
||||
return firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.orderBy('foo')
|
||||
.startAfter(collectionSnapshot.docs[2])
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 2);
|
||||
should.deepEqual(querySnapshot.docs.map(doc => doc.data().daz), [
|
||||
456,
|
||||
567,
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('orderBy()', () => {
|
||||
it('errors if called after startAt', () => {
|
||||
(() => {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.startAt({})
|
||||
.orderBy('test');
|
||||
}).should.throw(
|
||||
'Cannot specify an orderBy() constraint after calling startAt(), startAfter(), endBefore() or endAt().'
|
||||
);
|
||||
});
|
||||
|
||||
it('errors if called after startAfter', () => {
|
||||
(() => {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.startAfter({})
|
||||
.orderBy('test');
|
||||
}).should.throw(
|
||||
'Cannot specify an orderBy() constraint after calling startAt(), startAfter(), endBefore() or endAt().'
|
||||
);
|
||||
});
|
||||
|
||||
it('errors if called after endBefore', () => {
|
||||
(() => {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.endBefore({})
|
||||
.orderBy('test');
|
||||
}).should.throw(
|
||||
'Cannot specify an orderBy() constraint after calling startAt(), startAfter(), endBefore() or endAt().'
|
||||
);
|
||||
});
|
||||
|
||||
it('errors if called after endAt', () => {
|
||||
(() => {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.endAt({})
|
||||
.orderBy('test');
|
||||
}).should.throw(
|
||||
'Cannot specify an orderBy() constraint after calling startAt(), startAfter(), endBefore() or endAt().'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,417 +0,0 @@
|
||||
const { TEST_COLLECTION_NAME_DYNAMIC } = TestHelpers.firestore;
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
function documents() {
|
||||
const out = [
|
||||
{
|
||||
index: -1,
|
||||
indexStr: '-1',
|
||||
// https://github.com/invertase/react-native-firebase/issues/1552
|
||||
timestamp: null,
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const date = new jet.context.window.Date(2017, i, i + 1, i, i * 3, i * 4);
|
||||
out.push({
|
||||
index: i,
|
||||
indexStr: i.toString(),
|
||||
timestamp: date,
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const date = new jet.context.window.Date(2018, i, i + 1, i, i * 3, i * 4);
|
||||
out.push({
|
||||
index: i + 12,
|
||||
indexStr: (i + 12).toString(),
|
||||
timestamp: date,
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const date = new jet.context.window.Date(
|
||||
new Date().getFullYear(),
|
||||
i,
|
||||
i + 1,
|
||||
i,
|
||||
i * 3,
|
||||
i * 4
|
||||
);
|
||||
|
||||
out.push({
|
||||
index: i + 24,
|
||||
indexStr: (i + 24).toString(),
|
||||
timestamp: date,
|
||||
});
|
||||
}
|
||||
|
||||
out.push({
|
||||
index: 1337,
|
||||
indexStr: '1337',
|
||||
// https://github.com/invertase/react-native-firebase/issues/1552
|
||||
timestamp: null,
|
||||
});
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('CollectionReference', () => {
|
||||
before(async () => {
|
||||
const firestore = firebaseAdmin.firestore();
|
||||
const collection = firestore.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
const docsToAdd = documents();
|
||||
const batch = firestore.batch();
|
||||
const docsToDelete = (await collection.get()).docs;
|
||||
|
||||
if (docsToDelete.length) {
|
||||
for (let i = 0, len = docsToDelete.length; i < len; i++) {
|
||||
const { ref } = docsToDelete[i];
|
||||
batch.delete(ref);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < docsToAdd.length; i++) {
|
||||
batch.set(collection.doc(), docsToAdd[i]);
|
||||
}
|
||||
|
||||
return batch.commit();
|
||||
});
|
||||
|
||||
describe('where() -> Date Filters', () => {
|
||||
it('==', async () => {
|
||||
// index4 - 2017-05-05T03:12:16.000Z
|
||||
const date2017 = new jet.context.window.Date(2017, 4, 5, 4, 12, 16);
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '==', date2017)
|
||||
.get();
|
||||
|
||||
const { docs } = snapshot;
|
||||
|
||||
should.equal(snapshot.size, 1);
|
||||
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
const { index, indexStr, timestamp } = docs[i].data();
|
||||
should.equal(timestamp.getTime() === date2017.getTime(), true);
|
||||
should.equal(i + 4, index);
|
||||
indexStr.should.equal(`${i + 4}`);
|
||||
}
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
|
||||
it('>=', async () => {
|
||||
// index4 - 2017-05-05T03:12:16.000Z
|
||||
const date2017 = new jet.context.window.Date(2017, 4, 5, 4, 12, 16);
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '>=', date2017)
|
||||
.orderBy('timestamp')
|
||||
.get();
|
||||
|
||||
const { docs } = snapshot;
|
||||
|
||||
// 3 years (36 months), skipping 4 months, 36 - 4 = 32;
|
||||
should.equal(snapshot.size, 32);
|
||||
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
const { index, indexStr, timestamp } = docs[i].data();
|
||||
// validate first snapshot date - it should be exactly the same date
|
||||
if (i === 0)
|
||||
should.equal(timestamp.getTime() === date2017.getTime(), true);
|
||||
|
||||
should.equal(timestamp.getTime() >= date2017.getTime(), true);
|
||||
should.equal(i + 4, index);
|
||||
indexStr.should.equal(`${i + 4}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('<=', async () => {
|
||||
// index4 - 2017-05-05T03:12:16.000Z
|
||||
const date2017 = new jet.context.window.Date(2017, 4, 5, 4, 12, 16);
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '<=', date2017)
|
||||
.orderBy('timestamp')
|
||||
.get();
|
||||
|
||||
const { docs } = snapshot;
|
||||
|
||||
should.equal(snapshot.size, 5);
|
||||
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
const { index, indexStr, timestamp } = docs[i].data();
|
||||
// validate last snapshot date - it should be exactly the same date
|
||||
if (docs.length - 1 === i) {
|
||||
should.equal(timestamp.getTime() === date2017.getTime(), true);
|
||||
}
|
||||
|
||||
should.equal(timestamp.getTime() <= date2017.getTime(), true);
|
||||
should.equal(i, index);
|
||||
indexStr.should.equal(`${i}`);
|
||||
}
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
|
||||
it('>= & <=', async () => {
|
||||
// index4 - 2017-05-05T03:12:16.000Z
|
||||
const date2017 = new jet.context.window.Date(2017, 4, 5, 4, 12, 16);
|
||||
// index4 - 2018-05-05T03:12:16.000Z
|
||||
const date2018 = new jet.context.window.Date(2018, 4, 5, 4, 12, 16);
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '>=', date2017)
|
||||
.where('timestamp', '<=', date2018)
|
||||
.orderBy('timestamp')
|
||||
.get();
|
||||
|
||||
const { docs } = snapshot;
|
||||
|
||||
should.equal(snapshot.size, 13);
|
||||
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
const { index, indexStr, timestamp } = docs[i].data();
|
||||
// validate first snapshot date - it should be exactly the same as date2017
|
||||
if (i === 0)
|
||||
should.equal(timestamp.getTime() === date2017.getTime(), true);
|
||||
// validate last snapshot date - it should be exactly the same as date2018
|
||||
if (i === docs.length - 1)
|
||||
should.equal(timestamp.getTime() === date2018.getTime(), true);
|
||||
|
||||
should.equal(timestamp.getTime() >= date2017.getTime(), true);
|
||||
should.equal(timestamp.getTime() <= date2018.getTime(), true);
|
||||
should.equal(i + 4, index);
|
||||
indexStr.should.equal(`${i + 4}`);
|
||||
}
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
|
||||
it('>', async () => {
|
||||
// index4 - 2017-05-05T03:12:16.000Z
|
||||
const date2017 = new jet.context.window.Date(2017, 4, 5, 4, 12, 16);
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '>', date2017)
|
||||
.orderBy('timestamp')
|
||||
.get();
|
||||
|
||||
const { docs } = snapshot;
|
||||
|
||||
// 3 years (36 months), skipping 4 months, 36 - 4 = 32;
|
||||
should.equal(snapshot.size, 31); // minus one as not including equality on date filter
|
||||
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
const { index, indexStr, timestamp } = docs[i].data();
|
||||
// validate first snapshot date - it should NOT be exactly the same date
|
||||
if (i === 0)
|
||||
should.equal(timestamp.getTime() !== date2017.getTime(), true);
|
||||
|
||||
should.equal(timestamp.getTime() > date2017.getTime(), true);
|
||||
should.equal(i + 5, index);
|
||||
indexStr.should.equal(`${i + 5}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('<', async () => {
|
||||
// index4 - 2017-05-05T03:12:16.000Z
|
||||
const date2017 = new jet.context.window.Date(2017, 4, 5, 4, 12, 16);
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '<', date2017)
|
||||
.orderBy('timestamp')
|
||||
.get();
|
||||
|
||||
const { docs } = snapshot;
|
||||
|
||||
should.equal(snapshot.size, 4); // minus one as not including equality on date filter
|
||||
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
const { index, indexStr, timestamp } = docs[i].data();
|
||||
// validate first snapshot date - it should NOT be exactly the same date
|
||||
if (i === 0)
|
||||
should.equal(timestamp.getTime() !== date2017.getTime(), true);
|
||||
|
||||
should.equal(timestamp.getTime() < date2017.getTime(), true);
|
||||
should.equal(i, index);
|
||||
indexStr.should.equal(`${i}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('> & <', async () => {
|
||||
// index4 - 2017-05-05T03:12:16.000Z
|
||||
const date2017 = new jet.context.window.Date(2017, 4, 5, 4, 12, 16);
|
||||
// index4 - 2018-05-05T03:12:16.000Z
|
||||
const date2018 = new jet.context.window.Date(2018, 4, 5, 4, 12, 16);
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '>', date2017)
|
||||
.where('timestamp', '<', date2018)
|
||||
.orderBy('timestamp')
|
||||
.get();
|
||||
|
||||
const { docs } = snapshot;
|
||||
|
||||
should.equal(snapshot.size, 11); // minus two as not including equality on date filters
|
||||
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
const { index, indexStr, timestamp } = docs[i].data();
|
||||
// validate first snapshot date - it should NOT be exactly the same as date2017
|
||||
if (i === 0)
|
||||
should.equal(timestamp.getTime() !== date2017.getTime(), true);
|
||||
// validate last snapshot date - it should NOT be exactly the same as date2018
|
||||
if (i === docs.length - 1)
|
||||
should.equal(timestamp.getTime() !== date2018.getTime(), true);
|
||||
|
||||
should.equal(timestamp.getTime() > date2017.getTime(), true);
|
||||
should.equal(timestamp.getTime() < date2018.getTime(), true);
|
||||
should.equal(i + 5, index);
|
||||
indexStr.should.equal(`${i + 5}`);
|
||||
}
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
// ------------------------------------------------------------
|
||||
|
||||
it('> & <=', async () => {
|
||||
// index4 - 2017-05-05T03:12:16.000Z
|
||||
const date2017 = new jet.context.window.Date(2017, 4, 5, 4, 12, 16);
|
||||
// index4 - 2018-05-05T03:12:16.000Z
|
||||
const date2018 = new jet.context.window.Date(2018, 4, 5, 4, 12, 16);
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '>', date2017)
|
||||
.where('timestamp', '<=', date2018)
|
||||
.orderBy('timestamp')
|
||||
.get();
|
||||
|
||||
const { docs } = snapshot;
|
||||
|
||||
should.equal(snapshot.size, 12); // minus one as not including equality on date2017 filter
|
||||
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
const { index, indexStr, timestamp } = docs[i].data();
|
||||
// validate first snapshot date - it should NOT be exactly the same as date2017
|
||||
if (i === 0)
|
||||
should.equal(timestamp.getTime() !== date2017.getTime(), true);
|
||||
// validate last snapshot date - it should be exactly the same as date2018
|
||||
if (i === docs.length - 1)
|
||||
should.equal(timestamp.getTime() === date2018.getTime(), true);
|
||||
|
||||
should.equal(timestamp.getTime() > date2017.getTime(), true);
|
||||
should.equal(timestamp.getTime() <= date2018.getTime(), true);
|
||||
should.equal(i + 5, index);
|
||||
indexStr.should.equal(`${i + 5}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('>= & <', async () => {
|
||||
// index4 - 2017-05-05T03:12:16.000Z
|
||||
const date2017 = new jet.context.window.Date(2017, 4, 5, 4, 12, 16);
|
||||
// index4 - 2018-05-05T03:12:16.000Z
|
||||
const date2018 = new jet.context.window.Date(2018, 4, 5, 4, 12, 16);
|
||||
|
||||
const snapshot = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '>=', date2017)
|
||||
.where('timestamp', '<', date2018)
|
||||
.orderBy('timestamp')
|
||||
.get();
|
||||
|
||||
const { docs } = snapshot;
|
||||
|
||||
should.equal(snapshot.size, 12); // minus one as not including equality on date2018 filters
|
||||
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
const { index, indexStr, timestamp } = docs[i].data();
|
||||
// validate first snapshot date - it should be exactly the same as date2017
|
||||
if (i === 0)
|
||||
should.equal(timestamp.getTime() === date2017.getTime(), true);
|
||||
// validate last snapshot date - it should NOT be exactly the same as date2018
|
||||
if (i === docs.length - 1)
|
||||
should.equal(timestamp.getTime() !== date2018.getTime(), true);
|
||||
|
||||
should.equal(timestamp.getTime() >= date2017.getTime(), true);
|
||||
should.equal(timestamp.getTime() < date2018.getTime(), true);
|
||||
should.equal(i + 4, index);
|
||||
indexStr.should.equal(`${i + 4}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,61 +0,0 @@
|
||||
const {
|
||||
COL_DOC_1,
|
||||
cleanCollection,
|
||||
TEST_COLLECTION_NAME_DYNAMIC,
|
||||
} = TestHelpers.firestore;
|
||||
|
||||
describe('firestore()', () => {
|
||||
before(async () => {
|
||||
await cleanCollection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
const collection = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
await Promise.all([
|
||||
collection.doc('col1').set(COL_DOC_1()),
|
||||
collection.doc('col2').set({ ...COL_DOC_1(), daz: 2 }),
|
||||
collection.doc('col3').set({ ...COL_DOC_1(), daz: 3 }),
|
||||
collection.doc('col4').set({ ...COL_DOC_1(), daz: 4 }),
|
||||
collection.doc('col5').set({ ...COL_DOC_1(), daz: 5 }),
|
||||
]);
|
||||
});
|
||||
|
||||
describe('CollectionReference', () => {
|
||||
describe('limit()', () => {
|
||||
it('correctly works with get()', async () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.limit(3)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 3);
|
||||
}));
|
||||
|
||||
it('correctly works with onSnapshot()', async () => {
|
||||
const collectionRef = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.limit(3);
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribe = collectionRef.onSnapshot(snapshot => {
|
||||
callback(snapshot.size);
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
// Assertions
|
||||
callback.should.be.calledWith(3);
|
||||
|
||||
// Tear down
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,553 +0,0 @@
|
||||
const {
|
||||
COL_DOC_1,
|
||||
DOC_2_PATH,
|
||||
COL_DOC_1_PATH,
|
||||
cleanCollection,
|
||||
resetTestCollectionDoc,
|
||||
TEST_COLLECTION_NAME_DYNAMIC,
|
||||
} = TestHelpers.firestore;
|
||||
|
||||
function getSnapshotErrorClass() {
|
||||
return jet.require('src/modules/firestore/SnapshotError');
|
||||
}
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('CollectionReference', () => {
|
||||
describe('onSnapshot()', () => {
|
||||
beforeEach(async () => {
|
||||
await sleep(50);
|
||||
await cleanCollection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
await sleep(50);
|
||||
});
|
||||
|
||||
it('QuerySnapshot has correct properties', async () => {
|
||||
const collection = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
const snapshot = await collection.get();
|
||||
snapshot.docChanges.should.be.an.Array();
|
||||
snapshot.empty.should.equal(true);
|
||||
snapshot.metadata.should.be.an.Object();
|
||||
snapshot.query.should.be.an.Object();
|
||||
});
|
||||
|
||||
it('DocumentChange has correct properties', async () => {
|
||||
const collection = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
await resetTestCollectionDoc();
|
||||
|
||||
// Test
|
||||
let changes;
|
||||
let unsubscribe;
|
||||
await new Promise(resolve => {
|
||||
unsubscribe = collection.onSnapshot(snapshot => {
|
||||
changes = snapshot.docChanges;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// Assertions
|
||||
changes.should.be.a.Array();
|
||||
changes[0].doc.should.be.an.Object();
|
||||
changes[0].newIndex.should.be.a.Number();
|
||||
changes[0].oldIndex.should.be.a.Number();
|
||||
changes[0].type.should.be.a.String();
|
||||
|
||||
// Tear down
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('calls callback with the initial data and then when document changes', async () => {
|
||||
const callback = sinon.spy();
|
||||
const collection = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
const newDocValue = { ...COL_DOC_1(), foo: 'updated' };
|
||||
|
||||
// Test
|
||||
let unsubscribe;
|
||||
let resolved = false;
|
||||
await new Promise(resolve => {
|
||||
unsubscribe = collection.onSnapshot(snapshot => {
|
||||
if (snapshot && snapshot.docs.length) {
|
||||
callback(snapshot.docs[0].data());
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
|
||||
if (!resolved) {
|
||||
resolved = true;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledOnce();
|
||||
|
||||
await firebase
|
||||
.firestore()
|
||||
.doc(COL_DOC_1_PATH)
|
||||
.set(newDocValue);
|
||||
|
||||
await sleep(25);
|
||||
|
||||
// Assertions
|
||||
callback.should.be.calledTwice();
|
||||
callback.getCall(1).args[0].foo.should.equal('updated');
|
||||
|
||||
// Tear down
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('calls callback with the initial data and then when document is added', async () => {
|
||||
const colDoc = await resetTestCollectionDoc();
|
||||
await sleep(50);
|
||||
|
||||
const collectionRef = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
const newDocValue = { foo: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribe = collectionRef.onSnapshot(snapshot => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(colDoc);
|
||||
|
||||
const docRef = firebase.firestore().doc(DOC_2_PATH);
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await sleep(25);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(colDoc);
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
callback.should.be.calledThrice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it("doesn't call callback when the ref is updated with the same value", async () => {
|
||||
const colDoc = await resetTestCollectionDoc();
|
||||
await sleep(50);
|
||||
|
||||
const collectionRef = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribe = collectionRef.onSnapshot(snapshot => {
|
||||
snapshot.forEach(doc => {
|
||||
callback(doc.data());
|
||||
});
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(colDoc);
|
||||
|
||||
const docRef = firebase.firestore().doc(COL_DOC_1_PATH);
|
||||
await docRef.set(colDoc);
|
||||
|
||||
await sleep(150);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledOnce(); // Callback is not called again
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('allows binding multiple callbacks to the same ref', async () => {
|
||||
const colDoc = await resetTestCollectionDoc();
|
||||
await sleep(50);
|
||||
|
||||
// Setup
|
||||
const collectionRef = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
const newDocValue = { ...colDoc, foo: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribeA = collectionRef.onSnapshot(snapshot => {
|
||||
snapshot.forEach(doc => callbackA(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribeB = collectionRef.onSnapshot(snapshot => {
|
||||
snapshot.forEach(doc => callbackB(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(colDoc);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(colDoc);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
const docRef = firebase.firestore().doc(COL_DOC_1_PATH);
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await sleep(25);
|
||||
|
||||
callbackA.should.be.calledWith(newDocValue);
|
||||
callbackB.should.be.calledWith(newDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
});
|
||||
|
||||
it('listener stops listening when unsubscribed', async () => {
|
||||
const colDoc = await resetTestCollectionDoc();
|
||||
await sleep(50);
|
||||
|
||||
// Setup
|
||||
const collectionRef = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
const newDocValue = { ...colDoc, foo: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribeA = collectionRef.onSnapshot(snapshot => {
|
||||
snapshot.forEach(doc => callbackA(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribeB = collectionRef.onSnapshot(snapshot => {
|
||||
snapshot.forEach(doc => callbackB(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(colDoc);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(colDoc);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
const docRef = firebase.firestore().doc(COL_DOC_1_PATH);
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await sleep(25);
|
||||
|
||||
callbackA.should.be.calledWith(newDocValue);
|
||||
callbackB.should.be.calledWith(newDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Unsubscribe A
|
||||
|
||||
unsubscribeA();
|
||||
|
||||
await docRef.set(colDoc);
|
||||
|
||||
await sleep(25);
|
||||
|
||||
callbackB.should.be.calledWith(colDoc);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
// Unsubscribe B
|
||||
|
||||
unsubscribeB();
|
||||
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await sleep(25);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
});
|
||||
|
||||
it('supports options and callback', async () => {
|
||||
const colDoc = await resetTestCollectionDoc();
|
||||
await sleep(50);
|
||||
|
||||
const collectionRef = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
const newDocValue = { ...colDoc, foo: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribe = collectionRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
snapshot => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(colDoc);
|
||||
|
||||
const docRef = firebase.firestore().doc(COL_DOC_1_PATH);
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await sleep(25);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('supports observer', async () => {
|
||||
const colDoc = await resetTestCollectionDoc();
|
||||
await sleep(50);
|
||||
|
||||
const collectionRef = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
const newDocValue = { ...colDoc, foo: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
const observer = {
|
||||
next: snapshot => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
},
|
||||
};
|
||||
unsubscribe = collectionRef.onSnapshot(observer);
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(colDoc);
|
||||
|
||||
const docRef = firebase.firestore().doc(COL_DOC_1_PATH);
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await sleep(25);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('supports options and observer', async () => {
|
||||
const colDoc = await resetTestCollectionDoc();
|
||||
await sleep(50);
|
||||
|
||||
const collectionRef = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
const newDocValue = { ...colDoc, foo: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
const observer = {
|
||||
next: snapshot => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
},
|
||||
error: () => {},
|
||||
};
|
||||
unsubscribe = collectionRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
observer
|
||||
);
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(colDoc);
|
||||
|
||||
const docRef = firebase.firestore().doc(COL_DOC_1_PATH);
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await sleep(25);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('snapshot error returns instance of SnapshotError', () => {
|
||||
let unsubscribe;
|
||||
const { reject, resolve, promise } = Promise.defer();
|
||||
const collection = firebase
|
||||
.firestore()
|
||||
.collection('blocked-collection');
|
||||
|
||||
const observer = {
|
||||
next: () => {
|
||||
unsubscribe();
|
||||
reject(new Error('Did not error!'));
|
||||
},
|
||||
error: snapshotError => {
|
||||
snapshotError.should.be.instanceOf(getSnapshotErrorClass());
|
||||
snapshotError.code.should.be.a.String();
|
||||
snapshotError.path.should.be.a.String();
|
||||
snapshotError.appName.should.be.a.String();
|
||||
snapshotError.message.should.be.a.String();
|
||||
snapshotError.nativeErrorMessage.should.be.a.String();
|
||||
snapshotError.appName.should.equal('[DEFAULT]');
|
||||
snapshotError.path.should.equal('blocked-collection');
|
||||
snapshotError.code.should.equal('firestore/permission-denied');
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
|
||||
unsubscribe = collection.onSnapshot(observer);
|
||||
return promise;
|
||||
});
|
||||
|
||||
it('errors when invalid parameters supplied', async () => {
|
||||
const colRef = firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
|
||||
(() => {
|
||||
colRef.onSnapshot(() => {}, 'error');
|
||||
}).should.throw(
|
||||
'Query.onSnapshot failed: Second argument must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
colRef.onSnapshot({
|
||||
next: () => {},
|
||||
error: 'error',
|
||||
});
|
||||
}).should.throw(
|
||||
'Query.onSnapshot failed: Observer.error must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
colRef.onSnapshot({
|
||||
next: 'error',
|
||||
});
|
||||
}).should.throw(
|
||||
'Query.onSnapshot failed: Observer.next must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
colRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
() => {},
|
||||
'error'
|
||||
);
|
||||
}).should.throw(
|
||||
'Query.onSnapshot failed: Third argument must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
colRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
{
|
||||
next: () => {},
|
||||
error: 'error',
|
||||
}
|
||||
);
|
||||
}).should.throw(
|
||||
'Query.onSnapshot failed: Observer.error must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
colRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
{
|
||||
next: 'error',
|
||||
}
|
||||
);
|
||||
}).should.throw(
|
||||
'Query.onSnapshot failed: Observer.next must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
colRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
'error'
|
||||
);
|
||||
}).should.throw(
|
||||
'Query.onSnapshot failed: Second argument must be a function or observer.'
|
||||
);
|
||||
(() => {
|
||||
colRef.onSnapshot({
|
||||
error: 'error',
|
||||
});
|
||||
}).should.throw(
|
||||
'Query.onSnapshot failed: First argument must be a function, observer or options.'
|
||||
);
|
||||
(() => {
|
||||
colRef.onSnapshot();
|
||||
}).should.throw(
|
||||
'Query.onSnapshot failed: Called with invalid arguments.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,171 +0,0 @@
|
||||
const {
|
||||
COL_DOC_1,
|
||||
COL_DOC_1_PATH,
|
||||
TEST_COLLECTION_NAME_DYNAMIC,
|
||||
resetTestCollectionDoc,
|
||||
} = TestHelpers.firestore;
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('CollectionReference', () => {
|
||||
before(() => resetTestCollectionDoc(COL_DOC_1_PATH, COL_DOC_1()));
|
||||
describe('where()', () => {
|
||||
it('`array-contains` a string value', async () => {
|
||||
const found = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('arrString', 'array-contains', 'a')
|
||||
.get();
|
||||
|
||||
should.equal(found.size, 1);
|
||||
found.forEach(documentSnapshot => {
|
||||
should.deepEqual(
|
||||
documentSnapshot.data().arrString,
|
||||
jet.contextify(['a', 'b', 'c', 'd'])
|
||||
);
|
||||
});
|
||||
|
||||
const notFound = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('arrString', 'array-contains', 'f')
|
||||
.get();
|
||||
|
||||
should.equal(notFound.size, 0);
|
||||
});
|
||||
|
||||
it('`array-contains` a number value', async () => {
|
||||
const found = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('arrNumber', 'array-contains', 1)
|
||||
.get();
|
||||
|
||||
should.equal(found.size, 1);
|
||||
found.forEach(documentSnapshot => {
|
||||
should.deepEqual(
|
||||
documentSnapshot.data().arrNumber,
|
||||
jet.contextify([1, 2, 3, 4])
|
||||
);
|
||||
});
|
||||
|
||||
const notFound = await firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('arrNumber', 'array-contains', 5)
|
||||
.get();
|
||||
|
||||
should.equal(notFound.size, 0);
|
||||
});
|
||||
|
||||
// TODO: below tests should also check the inverse to ensure working as
|
||||
// TODO: currently there is only one document in the collection so might be false positives in future
|
||||
it('== boolean value', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('baz', '==', true)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach(documentSnapshot => {
|
||||
should.equal(documentSnapshot.data().baz, true);
|
||||
});
|
||||
}));
|
||||
|
||||
it('== string value', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('foo', '==', 'bar')
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach(documentSnapshot => {
|
||||
should.equal(documentSnapshot.data().foo, 'bar');
|
||||
});
|
||||
}));
|
||||
|
||||
it('== null value', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('naz', '==', null)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach(documentSnapshot => {
|
||||
should.equal(documentSnapshot.data().naz, null);
|
||||
});
|
||||
}));
|
||||
|
||||
it('== date value', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('timestamp', '==', COL_DOC_1().timestamp)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
}));
|
||||
|
||||
it('== GeoPoint value', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('geopoint', '==', COL_DOC_1().geopoint)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
}));
|
||||
|
||||
it('>= number value', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('daz', '>=', 123)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach(documentSnapshot => {
|
||||
should.equal(documentSnapshot.data().daz, 123);
|
||||
});
|
||||
}));
|
||||
|
||||
it('>= GeoPoint value', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('geopoint', '>=', new firebase.firestore.GeoPoint(-1, -1))
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
}));
|
||||
|
||||
it('<= float value', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where('gaz', '<=', 12.1234666)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach(documentSnapshot => {
|
||||
should.equal(documentSnapshot.data().gaz, 12.1234567);
|
||||
});
|
||||
}));
|
||||
|
||||
it('FieldPath', () =>
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(TEST_COLLECTION_NAME_DYNAMIC)
|
||||
.where(new firebase.firestore.FieldPath('baz'), '==', true)
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach(documentSnapshot => {
|
||||
should.equal(documentSnapshot.data().baz, true);
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,174 +0,0 @@
|
||||
const {
|
||||
COL_DOC_1,
|
||||
DOC_2_PATH,
|
||||
COL_DOC_1_ID,
|
||||
COL_DOC_1_PATH,
|
||||
TEST_COLLECTION_NAME,
|
||||
TEST_COLLECTION_NAME_DYNAMIC,
|
||||
testCollection,
|
||||
cleanCollection,
|
||||
testCollectionDoc,
|
||||
resetTestCollectionDoc,
|
||||
} = TestHelpers.firestore;
|
||||
|
||||
function getCollectionReferenceClass() {
|
||||
return jet.require('src/modules/firestore/CollectionReference');
|
||||
}
|
||||
|
||||
function getDocumentReferenceClass() {
|
||||
return jet.require('src/modules/firestore/DocumentReference');
|
||||
}
|
||||
|
||||
function getDocumentSnapshotClass() {
|
||||
return jet.require('src/modules/firestore/DocumentSnapshot');
|
||||
}
|
||||
|
||||
function getPathClass() {
|
||||
return jet.require('src/modules/firestore/Path');
|
||||
}
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('CollectionReference', () => {
|
||||
before(() => resetTestCollectionDoc(COL_DOC_1_PATH, COL_DOC_1()));
|
||||
|
||||
it('get id()', () => {
|
||||
const Path = getPathClass();
|
||||
const firestore = firebase.firestore();
|
||||
const CollectionReference = getCollectionReferenceClass();
|
||||
|
||||
const reference = new CollectionReference(firestore, new Path(['tests']));
|
||||
reference.should.be.instanceOf(CollectionReference);
|
||||
reference.id.should.equal('tests');
|
||||
});
|
||||
|
||||
it('get firestore()', () => {
|
||||
const Path = getPathClass();
|
||||
const firestore = firebase.firestore();
|
||||
const CollectionReference = getCollectionReferenceClass();
|
||||
|
||||
const reference = new CollectionReference(firestore, new Path(['tests']));
|
||||
reference.should.be.instanceOf(CollectionReference);
|
||||
reference.firestore.should.equal(firestore);
|
||||
});
|
||||
|
||||
it('get parent()', () => {
|
||||
const Path = getPathClass();
|
||||
const firestore = firebase.firestore();
|
||||
const CollectionReference = getCollectionReferenceClass();
|
||||
const DocumentReference = getDocumentReferenceClass();
|
||||
|
||||
const reference = new CollectionReference(firestore, new Path(['tests']));
|
||||
reference.should.be.instanceOf(CollectionReference);
|
||||
should.equal(reference.parent, null);
|
||||
|
||||
const reference2 = new CollectionReference(
|
||||
firestore,
|
||||
new Path(['tests', 'someDoc', 'someChildCollection'])
|
||||
);
|
||||
reference2.should.be.instanceOf(CollectionReference);
|
||||
should.notEqual(reference2.parent, null);
|
||||
reference2.parent.should.be.an.instanceOf(DocumentReference);
|
||||
});
|
||||
|
||||
describe('add()', () => {
|
||||
it('should create a Document', async () => {
|
||||
const collection = testCollection(TEST_COLLECTION_NAME);
|
||||
|
||||
const docRef = await collection.add({
|
||||
first: 'Ada',
|
||||
last: 'Lovelace',
|
||||
born: 1815,
|
||||
});
|
||||
|
||||
const doc = await firebase
|
||||
.firestore()
|
||||
.doc(docRef.path)
|
||||
.get();
|
||||
|
||||
doc.data().first.should.equal('Ada');
|
||||
|
||||
await firebase
|
||||
.firestore()
|
||||
.doc(docRef.path)
|
||||
.delete();
|
||||
});
|
||||
});
|
||||
|
||||
describe('doc()', () => {
|
||||
it('should create DocumentReference with correct path', async () => {
|
||||
const docRef = await testCollectionDoc(COL_DOC_1_PATH);
|
||||
should.equal(docRef.path, COL_DOC_1_PATH);
|
||||
});
|
||||
|
||||
it('should error when supplied an incorrect path', () => {
|
||||
(() => {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection('collection')
|
||||
.doc('invalid/doc');
|
||||
}).should.throw('Argument "documentPath" must point to a document.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('get()', () => {
|
||||
it('should retrieve all documents on a collection', async () => {
|
||||
const collection = testCollection(TEST_COLLECTION_NAME);
|
||||
const DocumentSnapshot = getDocumentSnapshotClass();
|
||||
|
||||
const querySnapshot = await collection.get();
|
||||
|
||||
should.equal(querySnapshot.size >= 1, true);
|
||||
|
||||
querySnapshot.forEach(documentSnapshot => {
|
||||
documentSnapshot.should.be.instanceOf(DocumentSnapshot);
|
||||
});
|
||||
});
|
||||
|
||||
it('should support GetOptions source=`default`', async () => {
|
||||
const collection = testCollection(TEST_COLLECTION_NAME);
|
||||
const querySnapshot = await collection.get({ source: 'default' });
|
||||
should.equal(querySnapshot.size >= 1, true);
|
||||
querySnapshot.metadata.should.be.an.Object();
|
||||
should.equal(querySnapshot.metadata.fromCache, false);
|
||||
});
|
||||
|
||||
it('should support GetOptions source=`server`', async () => {
|
||||
const collection = testCollection(TEST_COLLECTION_NAME);
|
||||
const querySnapshot = await collection.get({ source: 'server' });
|
||||
should.equal(querySnapshot.size >= 1, true);
|
||||
querySnapshot.metadata.should.be.an.Object();
|
||||
should.equal(querySnapshot.metadata.fromCache, false);
|
||||
});
|
||||
|
||||
// TODO: Investigate why this isn't returning `fromCache=true`
|
||||
xit('should support GetOptions source=`cache`', async () => {
|
||||
const collection = testCollection(TEST_COLLECTION_NAME);
|
||||
const querySnapshot = await collection.get({ source: 'cache' });
|
||||
should.equal(querySnapshot.size >= 1, true);
|
||||
querySnapshot.metadata.should.be.an.Object();
|
||||
should.equal(querySnapshot.metadata.fromCache, true);
|
||||
});
|
||||
|
||||
it('should error with invalid GetOptions source option', async () => {
|
||||
const collectionRef = testCollection(TEST_COLLECTION_NAME);
|
||||
try {
|
||||
await collectionRef.get(() => {});
|
||||
return Promise.reject(
|
||||
new Error('get() did not reject with invalid argument.')
|
||||
);
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
try {
|
||||
await collectionRef.get({ source: 'invalid' });
|
||||
return Promise.reject(
|
||||
new Error('get() did not reject with invalid source property.')
|
||||
);
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,698 +0,0 @@
|
||||
const {
|
||||
test2DocRef,
|
||||
COL2_DOC_1,
|
||||
COL2_DOC_1_ID,
|
||||
cleanCollection,
|
||||
COL2_DOC_1_PATH,
|
||||
resetTestCollectionDoc,
|
||||
TEST_COLLECTION_NAME_DYNAMIC,
|
||||
} = TestHelpers.firestore;
|
||||
|
||||
function getSnapshotErrorClass() {
|
||||
return jet.require('src/modules/firestore/SnapshotError');
|
||||
}
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('DocumentReference', () => {
|
||||
before(async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, COL2_DOC_1());
|
||||
});
|
||||
|
||||
describe('class', () => {
|
||||
it('should return instance methods', () => {
|
||||
const document = test2DocRef(COL2_DOC_1_ID);
|
||||
document.should.have.property('firestore');
|
||||
// TODO: Remaining checks
|
||||
});
|
||||
});
|
||||
|
||||
describe('id', () => {
|
||||
it('should return document id', () => {
|
||||
const document = test2DocRef(COL2_DOC_1_ID);
|
||||
document.id.should.equal(COL2_DOC_1_ID);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parent', () => {
|
||||
it('should return parent collection', () => {
|
||||
const document = test2DocRef(COL2_DOC_1_ID);
|
||||
document.parent.id.should.equal(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
});
|
||||
});
|
||||
|
||||
describe('collection()', () => {
|
||||
it('should return a child collection', () => {
|
||||
const document = test2DocRef(COL2_DOC_1_ID);
|
||||
const collection = document.collection('pages');
|
||||
collection.id.should.equal('pages');
|
||||
});
|
||||
|
||||
it('should error if invalid collection path supplied', () => {
|
||||
(() => {
|
||||
test2DocRef(COL2_DOC_1_ID).collection('pages/page1');
|
||||
}).should.throw(
|
||||
'Argument "collectionPath" must point to a collection.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete()', () => {
|
||||
it('should delete Document', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, COL2_DOC_1());
|
||||
await test2DocRef(COL2_DOC_1_ID).delete();
|
||||
const doc = await test2DocRef(COL2_DOC_1_ID).get();
|
||||
should.equal(doc.exists, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('get()', () => {
|
||||
it('DocumentSnapshot should have correct properties', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, COL2_DOC_1());
|
||||
const snapshot = await test2DocRef(COL2_DOC_1_ID).get();
|
||||
snapshot.id.should.equal(COL2_DOC_1_ID);
|
||||
snapshot.metadata.should.be.an.Object();
|
||||
});
|
||||
|
||||
it('should support GetOptions source=`default`', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, COL2_DOC_1());
|
||||
const snapshot = await test2DocRef(COL2_DOC_1_ID).get({
|
||||
source: 'default',
|
||||
});
|
||||
snapshot.id.should.equal(COL2_DOC_1_ID);
|
||||
snapshot.metadata.should.be.an.Object();
|
||||
should.equal(snapshot.metadata.fromCache, false);
|
||||
});
|
||||
|
||||
it('should support GetOptions source=`server`', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, COL2_DOC_1());
|
||||
const snapshot = await test2DocRef(COL2_DOC_1_ID).get({
|
||||
source: 'server',
|
||||
});
|
||||
snapshot.id.should.equal(COL2_DOC_1_ID);
|
||||
snapshot.metadata.should.be.an.Object();
|
||||
should.equal(snapshot.metadata.fromCache, false);
|
||||
});
|
||||
|
||||
// TODO: For some reason when using `cache` it's not seeing the data as available, even if
|
||||
// first requesting it from the server, although interestingly it works fine in the old
|
||||
// tests app
|
||||
xit('should support GetOptions source=`cache`', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, COL2_DOC_1());
|
||||
const ref = test2DocRef(COL2_DOC_1_ID);
|
||||
// Make sure the reference data is populated in the cache
|
||||
await ref.get({ source: 'server' });
|
||||
// Retrieve the cached version
|
||||
const snapshot = await ref.get({ source: 'cache' });
|
||||
snapshot.id.should.equal(COL2_DOC_1_ID);
|
||||
snapshot.metadata.should.be.an.Object();
|
||||
should.equal(snapshot.metadata.fromCache, true);
|
||||
});
|
||||
|
||||
it('should error with invalid GetOptions source option', async () => {
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
try {
|
||||
await docRef.get(() => {});
|
||||
return Promise.reject(
|
||||
new Error('get() did not reject with invalid argument.')
|
||||
);
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
try {
|
||||
await docRef.get({ source: 'invalid' });
|
||||
return Promise.reject(
|
||||
new Error('get() did not reject with invalid source property.')
|
||||
);
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onSnapshot()', () => {
|
||||
beforeEach(async () => {
|
||||
await sleep(50);
|
||||
await cleanCollection(TEST_COLLECTION_NAME_DYNAMIC);
|
||||
await sleep(50);
|
||||
});
|
||||
|
||||
it('snapshot error returns instance of SnapshotError', () => {
|
||||
let unsubscribe;
|
||||
const { reject, resolve, promise } = Promise.defer();
|
||||
const collection = firebase.firestore().doc('blocked-collection/nope');
|
||||
|
||||
const observer = {
|
||||
next: () => {
|
||||
unsubscribe();
|
||||
reject(new Error('Did not error!'));
|
||||
},
|
||||
error: snapshotError => {
|
||||
snapshotError.should.be.instanceOf(getSnapshotErrorClass());
|
||||
snapshotError.code.should.be.a.String();
|
||||
snapshotError.path.should.be.a.String();
|
||||
snapshotError.appName.should.be.a.String();
|
||||
snapshotError.message.should.be.a.String();
|
||||
snapshotError.nativeErrorMessage.should.be.a.String();
|
||||
snapshotError.appName.should.equal('[DEFAULT]');
|
||||
snapshotError.path.should.equal('blocked-collection/nope');
|
||||
snapshotError.code.should.equal('firestore/permission-denied');
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
|
||||
unsubscribe = collection.onSnapshot(observer);
|
||||
return promise;
|
||||
});
|
||||
|
||||
it('calls callback with the initial data and then when value changes', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, { name: 'doc1' });
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribe = docRef.onSnapshot(snapshot => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
// Update the document
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it("doesn't call callback when the ref is updated with the same value", async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, { name: 'doc1' });
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribe = docRef.onSnapshot(snapshot => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
await docRef.set(currentDataValue);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledOnce(); // Callback is not called again
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('allows binding multiple callbacks to the same ref', async () => {
|
||||
// Setup
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, { name: 'doc1' });
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribeA = docRef.onSnapshot(snapshot => {
|
||||
callbackA(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribeB = docRef.onSnapshot(snapshot => {
|
||||
callbackB(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDataValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
callbackA.should.be.calledWith(newDataValue);
|
||||
callbackB.should.be.calledWith(newDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
});
|
||||
|
||||
// TODO Flakey
|
||||
xit('listener stops listening when unsubscribed', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, { name: 'doc1' });
|
||||
|
||||
// Setup
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribeA = docRef.onSnapshot(snapshot => {
|
||||
callbackA(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribeB = docRef.onSnapshot(snapshot => {
|
||||
callbackB(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDataValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
callbackA.should.be.calledWith(newDataValue);
|
||||
callbackB.should.be.calledWith(newDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Unsubscribe A
|
||||
|
||||
unsubscribeA();
|
||||
|
||||
await docRef.set(currentDataValue);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
// Unsubscribe B
|
||||
|
||||
unsubscribeB();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
});
|
||||
|
||||
it('supports options and callbacks', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, { name: 'doc1' });
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
unsubscribe = docRef.onSnapshot(
|
||||
{ includeMetadataChanges: true },
|
||||
snapshot => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
// Update the document
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('supports observer', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, { name: 'doc1' });
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
const observer = {
|
||||
next: snapshot => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
},
|
||||
};
|
||||
unsubscribe = docRef.onSnapshot(observer);
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
// Update the document
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('supports options and observer', async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, { name: 'doc1' });
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise(resolve2 => {
|
||||
const observer = {
|
||||
next: snapshot => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
},
|
||||
error: () => {},
|
||||
};
|
||||
unsubscribe = docRef.onSnapshot(
|
||||
{ includeMetadataChanges: true },
|
||||
observer
|
||||
);
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
// Update the document
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('errors when invalid parameters supplied', async () => {
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
(() => {
|
||||
docRef.onSnapshot(() => {}, 'error');
|
||||
}).should.throw(
|
||||
'DocumentReference.onSnapshot failed: Second argument must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
docRef.onSnapshot({
|
||||
next: () => {},
|
||||
error: 'error',
|
||||
});
|
||||
}).should.throw(
|
||||
'DocumentReference.onSnapshot failed: Observer.error must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
docRef.onSnapshot({
|
||||
next: 'error',
|
||||
});
|
||||
}).should.throw(
|
||||
'DocumentReference.onSnapshot failed: Observer.next must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
docRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
() => {},
|
||||
'error'
|
||||
);
|
||||
}).should.throw(
|
||||
'DocumentReference.onSnapshot failed: Third argument must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
docRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
{
|
||||
next: () => {},
|
||||
error: 'error',
|
||||
}
|
||||
);
|
||||
}).should.throw(
|
||||
'DocumentReference.onSnapshot failed: Observer.error must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
docRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
{
|
||||
next: 'error',
|
||||
}
|
||||
);
|
||||
}).should.throw(
|
||||
'DocumentReference.onSnapshot failed: Observer.next must be a valid function.'
|
||||
);
|
||||
(() => {
|
||||
docRef.onSnapshot(
|
||||
{
|
||||
includeMetadataChanges: true,
|
||||
},
|
||||
'error'
|
||||
);
|
||||
}).should.throw(
|
||||
'DocumentReference.onSnapshot failed: Second argument must be a function or observer.'
|
||||
);
|
||||
(() => {
|
||||
docRef.onSnapshot({
|
||||
error: 'error',
|
||||
});
|
||||
}).should.throw(
|
||||
'DocumentReference.onSnapshot failed: First argument must be a function, observer or options.'
|
||||
);
|
||||
(() => {
|
||||
docRef.onSnapshot();
|
||||
}).should.throw(
|
||||
'DocumentReference.onSnapshot failed: Called with invalid arguments.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('set()', () => {
|
||||
before(async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, { name: 'doc1' });
|
||||
});
|
||||
it('should create Document', async () => {
|
||||
await test2DocRef('doc2').set({ name: 'doc2', testArray: [] });
|
||||
const doc = await test2DocRef('doc2').get();
|
||||
doc.data().name.should.equal('doc2');
|
||||
});
|
||||
|
||||
it('should merge Document', async () => {
|
||||
await test2DocRef(COL2_DOC_1_ID).set(
|
||||
{ merge: 'merge' },
|
||||
{ merge: true }
|
||||
);
|
||||
|
||||
const doc = await test2DocRef(COL2_DOC_1_ID).get();
|
||||
doc.data().name.should.equal('doc1');
|
||||
doc.data().merge.should.equal('merge');
|
||||
});
|
||||
|
||||
it('should overwrite Document', async () => {
|
||||
await test2DocRef(COL2_DOC_1_ID).set({ name: 'overwritten' });
|
||||
const doc = await test2DocRef(COL2_DOC_1_ID).get();
|
||||
doc.data().name.should.equal('overwritten');
|
||||
});
|
||||
});
|
||||
|
||||
describe('update()', () => {
|
||||
beforeEach(async () => {
|
||||
await resetTestCollectionDoc(COL2_DOC_1_PATH, { name: 'doc1' });
|
||||
});
|
||||
|
||||
it('should update Document using object', async () => {
|
||||
await test2DocRef(COL2_DOC_1_ID).update({ name: 'updated' });
|
||||
const doc = await test2DocRef(COL2_DOC_1_ID).get();
|
||||
doc.data().name.should.equal('updated');
|
||||
});
|
||||
|
||||
it('should update Document using key/value pairs', async () => {
|
||||
await test2DocRef(COL2_DOC_1_ID).update('name', 'updated');
|
||||
const doc = await test2DocRef(COL2_DOC_1_ID).get();
|
||||
doc.data().name.should.equal('updated');
|
||||
});
|
||||
|
||||
it('should update Document using FieldPath/value pair', async () => {
|
||||
await test2DocRef(COL2_DOC_1_ID).update(
|
||||
new firebase.firestore.FieldPath('name'),
|
||||
'Name'
|
||||
);
|
||||
const doc = await test2DocRef(COL2_DOC_1_ID).get();
|
||||
doc.data().name.should.equal('Name');
|
||||
});
|
||||
|
||||
it('should update Document using nested FieldPath and value pair', async () => {
|
||||
await test2DocRef(COL2_DOC_1_ID).update(
|
||||
new firebase.firestore.FieldPath('nested', 'name'),
|
||||
'Nested Name'
|
||||
);
|
||||
const doc = await test2DocRef(COL2_DOC_1_ID).get();
|
||||
doc.data().nested.name.should.equal('Nested Name');
|
||||
});
|
||||
|
||||
it('should update Document using multiple FieldPath/value pairs', async () => {
|
||||
await test2DocRef(COL2_DOC_1_ID).update(
|
||||
new firebase.firestore.FieldPath('nested', 'firstname'),
|
||||
'First Name',
|
||||
new firebase.firestore.FieldPath('nested', 'lastname'),
|
||||
'Last Name'
|
||||
);
|
||||
const doc = await test2DocRef(COL2_DOC_1_ID).get();
|
||||
doc.data().nested.firstname.should.equal('First Name');
|
||||
doc.data().nested.lastname.should.equal('Last Name');
|
||||
});
|
||||
|
||||
it('errors when invalid parameters supplied', async () => {
|
||||
const docRef = test2DocRef(COL2_DOC_1_ID);
|
||||
(() => {
|
||||
docRef.update('error');
|
||||
}).should.throw(
|
||||
'DocumentReference.update failed: If using a single update argument, it must be an object.'
|
||||
);
|
||||
(() => {
|
||||
docRef.update('error1', 'error2', 'error3');
|
||||
}).should.throw(
|
||||
'DocumentReference.update failed: The update arguments must be either a single object argument, or equal numbers of key/value pairs.'
|
||||
);
|
||||
(() => {
|
||||
docRef.update(0, 'error');
|
||||
}).should.throw(
|
||||
'DocumentReference.update failed: Argument at index 0 must be a string or FieldPath'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('types', () => {
|
||||
it('should handle Boolean field', async () => {
|
||||
const docRef = test2DocRef('reference');
|
||||
await docRef.set({
|
||||
field: true,
|
||||
});
|
||||
|
||||
const doc = await docRef.get();
|
||||
should.equal(doc.data().field, true);
|
||||
});
|
||||
|
||||
it('should handle Date field', async () => {
|
||||
const date = new jet.context.window.Date();
|
||||
const docRef = test2DocRef('reference');
|
||||
await docRef.set({
|
||||
field: date,
|
||||
});
|
||||
|
||||
const doc = await docRef.get();
|
||||
doc.data().field.should.be.instanceof(jet.context.window.Date);
|
||||
should.equal(doc.data().field.toISOString(), date.toISOString());
|
||||
should.equal(doc.data().field.getTime(), date.getTime());
|
||||
});
|
||||
|
||||
it('should handle DocumentReference field', async () => {
|
||||
const docRef = test2DocRef('reference');
|
||||
await docRef.set({
|
||||
field: firebase.firestore().doc('test/field'),
|
||||
});
|
||||
|
||||
const doc = await docRef.get();
|
||||
should.equal(doc.data().field.path, 'test/field');
|
||||
});
|
||||
|
||||
it('should handle GeoPoint field', async () => {
|
||||
const docRef = test2DocRef('reference');
|
||||
await docRef.set({
|
||||
field: new firebase.firestore.GeoPoint(1.01, 1.02),
|
||||
});
|
||||
|
||||
const doc = await docRef.get();
|
||||
should.equal(doc.data().field.latitude, 1.01);
|
||||
should.equal(doc.data().field.longitude, 1.02);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,109 +0,0 @@
|
||||
const {
|
||||
COL_DOC_1,
|
||||
COL_DOC_1_ID,
|
||||
COL_DOC_1_PATH,
|
||||
testCollectionDoc,
|
||||
resetTestCollectionDoc,
|
||||
} = TestHelpers.firestore;
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('DocumentSnapshot', () => {
|
||||
before(async () => {
|
||||
await resetTestCollectionDoc(COL_DOC_1_PATH, COL_DOC_1());
|
||||
});
|
||||
|
||||
describe('id', () => {
|
||||
it('returns a string document id', async () => {
|
||||
const snapshot = await testCollectionDoc(COL_DOC_1_PATH).get();
|
||||
snapshot.id.should.be.a.String();
|
||||
snapshot.id.should.equal(COL_DOC_1_ID);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ref', () => {
|
||||
it('returns a DocumentReference', async () => {
|
||||
const snapshot = await testCollectionDoc(COL_DOC_1_PATH).get();
|
||||
const DocumentReference = jet.require(
|
||||
'src/modules/firestore/DocumentReference'
|
||||
);
|
||||
snapshot.ref.should.be.an.instanceOf(DocumentReference);
|
||||
});
|
||||
});
|
||||
|
||||
describe('metadata', () => {
|
||||
it('returns an object of meta data', async () => {
|
||||
const { metadata } = await testCollectionDoc(COL_DOC_1_PATH).get();
|
||||
metadata.should.be.an.Object();
|
||||
metadata.should.have.property('hasPendingWrites');
|
||||
metadata.should.have.property('fromCache');
|
||||
metadata.hasPendingWrites.should.be.a.Boolean();
|
||||
metadata.fromCache.should.be.a.Boolean();
|
||||
});
|
||||
});
|
||||
|
||||
describe('exists', () => {
|
||||
it('returns a boolean', async () => {
|
||||
const { exists } = await testCollectionDoc(COL_DOC_1_PATH).get();
|
||||
exists.should.be.a.Boolean();
|
||||
exists.should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('data()', () => {
|
||||
it('returns document data', async () => {
|
||||
// additionally tests context binding not lost during destructuring
|
||||
const snapshot = await testCollectionDoc(COL_DOC_1_PATH).get();
|
||||
const { data } = snapshot;
|
||||
|
||||
snapshot.data.should.be.a.Function();
|
||||
data.should.be.a.Function();
|
||||
|
||||
snapshot.data().should.be.a.Object();
|
||||
data().should.be.a.Object();
|
||||
|
||||
snapshot.data().baz.should.be.true();
|
||||
data().baz.should.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('get()', () => {
|
||||
it('using a dot notated path string', async () => {
|
||||
// additionally tests context binding not lost during destructuring
|
||||
const snapshot = await testCollectionDoc(COL_DOC_1_PATH).get();
|
||||
const { get } = snapshot;
|
||||
|
||||
should.equal(snapshot.get('foo'), 'bar');
|
||||
should.equal(get('foo'), 'bar');
|
||||
|
||||
should.equal(snapshot.get('object.daz'), 123);
|
||||
should.equal(get('object.daz'), 123);
|
||||
|
||||
should.equal(snapshot.get('nonexistent.object'), undefined);
|
||||
should.equal(get('nonexistent.object'), undefined);
|
||||
});
|
||||
|
||||
it('using a FieldPath instance', async () => {
|
||||
const snapshot = await testCollectionDoc(COL_DOC_1_PATH).get();
|
||||
|
||||
should.equal(snapshot.get('foo'), 'bar');
|
||||
|
||||
should.equal(
|
||||
snapshot.get(new firebase.firestore.FieldPath('foo')),
|
||||
'bar'
|
||||
);
|
||||
|
||||
should.equal(
|
||||
snapshot.get(new firebase.firestore.FieldPath('object', 'daz')),
|
||||
123
|
||||
);
|
||||
|
||||
should.equal(
|
||||
snapshot.get(
|
||||
new firebase.firestore.FieldPath('nonexistent', 'object')
|
||||
),
|
||||
undefined
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,40 +0,0 @@
|
||||
const {
|
||||
COL_DOC_1,
|
||||
COL_DOC_1_PATH,
|
||||
testCollectionDoc,
|
||||
resetTestCollectionDoc,
|
||||
} = TestHelpers.firestore;
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('FieldPath', () => {
|
||||
before(async () => {
|
||||
await resetTestCollectionDoc(COL_DOC_1_PATH, COL_DOC_1());
|
||||
});
|
||||
|
||||
it('documentId() should return a FieldPath', () => {
|
||||
const documentId = firebase.firestore.FieldPath.documentId();
|
||||
documentId.should.be.instanceof(firebase.firestore.FieldPath);
|
||||
});
|
||||
|
||||
it('should allow getting values via documentSnapshot.get(FieldPath)', async () => {
|
||||
const snapshot = await testCollectionDoc(COL_DOC_1_PATH).get();
|
||||
|
||||
should.equal(snapshot.get('foo'), 'bar');
|
||||
|
||||
should.equal(
|
||||
snapshot.get(new firebase.firestore.FieldPath('foo')),
|
||||
'bar'
|
||||
);
|
||||
|
||||
should.equal(
|
||||
snapshot.get(new firebase.firestore.FieldPath('object', 'daz')),
|
||||
123
|
||||
);
|
||||
|
||||
should.equal(
|
||||
snapshot.get(new firebase.firestore.FieldPath('nonexistent', 'object')),
|
||||
undefined
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,208 +0,0 @@
|
||||
const {
|
||||
DOC_2,
|
||||
DOC_2_PATH,
|
||||
testCollectionDoc,
|
||||
resetTestCollectionDoc,
|
||||
} = TestHelpers.firestore;
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('FieldValue', () => {
|
||||
beforeEach(async () => {
|
||||
await resetTestCollectionDoc(DOC_2_PATH, DOC_2);
|
||||
});
|
||||
|
||||
describe('delete()', () => {
|
||||
it('should delete a field', async () => {
|
||||
const { data } = await testCollectionDoc(DOC_2_PATH).get();
|
||||
should.equal(data().title, DOC_2.title);
|
||||
|
||||
await testCollectionDoc(DOC_2_PATH).update({
|
||||
title: firebase.firestore.FieldValue.delete(),
|
||||
});
|
||||
|
||||
const { data: dataAfterUpdate } = await testCollectionDoc(
|
||||
DOC_2_PATH
|
||||
).get();
|
||||
|
||||
should.equal(dataAfterUpdate().title, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('serverTimestamp()', () => {
|
||||
it('should set timestamp', async () => {
|
||||
const { data } = await testCollectionDoc(DOC_2_PATH).get();
|
||||
should.equal(data().creationDate, undefined);
|
||||
|
||||
await testCollectionDoc(DOC_2_PATH).update({
|
||||
creationDate: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
});
|
||||
|
||||
const { data: dataAfterUpdate } = await testCollectionDoc(
|
||||
DOC_2_PATH
|
||||
).get();
|
||||
|
||||
dataAfterUpdate().creationDate.should.be.instanceof(
|
||||
jet.context.window.Date
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayUnion()', () => {
|
||||
it('should add new values to array field', async () => {
|
||||
const { data } = await testCollectionDoc(DOC_2_PATH).get();
|
||||
should.equal(data().elements, undefined);
|
||||
|
||||
await testCollectionDoc(DOC_2_PATH).update({
|
||||
elements: firebase.firestore.FieldValue.arrayUnion('element 1'),
|
||||
elements2: firebase.firestore.FieldValue.arrayUnion('element 2'),
|
||||
});
|
||||
|
||||
const { data: dataAfterUpdate } = await testCollectionDoc(
|
||||
DOC_2_PATH
|
||||
).get();
|
||||
|
||||
dataAfterUpdate().elements.should.containDeep(['element 1']);
|
||||
dataAfterUpdate().elements2.should.containDeep(['element 2']);
|
||||
});
|
||||
|
||||
it('should adding references & objects', async () => {
|
||||
const { data } = await testCollectionDoc(DOC_2_PATH).get();
|
||||
should.equal(data().elements, undefined);
|
||||
|
||||
await testCollectionDoc(DOC_2_PATH).update({
|
||||
elements: firebase.firestore.FieldValue.arrayUnion(
|
||||
'element 1',
|
||||
firebase
|
||||
.firestore()
|
||||
.collection('bar')
|
||||
.doc('foo'),
|
||||
firebase
|
||||
.firestore()
|
||||
.collection('bar')
|
||||
.doc('baz'),
|
||||
{ foo: 'bar', baz: [1, 2, 3], daz: { f: 'f' } }
|
||||
),
|
||||
});
|
||||
|
||||
const { data: dataAfterUpdate } = await testCollectionDoc(
|
||||
DOC_2_PATH
|
||||
).get();
|
||||
|
||||
const { elements } = dataAfterUpdate();
|
||||
elements.length.should.equal(4);
|
||||
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
const element = elements[i];
|
||||
if (i === 0) element.should.equal('element 1');
|
||||
if (i === 1) {
|
||||
element.should.be.instanceOf(
|
||||
jet.require('src/modules/firestore/DocumentReference')
|
||||
);
|
||||
element.id.should.equal('foo');
|
||||
}
|
||||
if (i === 2) {
|
||||
element.should.be.instanceOf(
|
||||
jet.require('src/modules/firestore/DocumentReference')
|
||||
);
|
||||
element.id.should.equal('baz');
|
||||
}
|
||||
if (i === 3) {
|
||||
element.foo.should.equal('bar');
|
||||
element.baz[0].should.equal(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayRemove()', () => {
|
||||
it('should remove value from array', async () => {
|
||||
await testCollectionDoc(DOC_2_PATH).set({
|
||||
elements: ['element 1', 'element 2'],
|
||||
});
|
||||
const { data } = await testCollectionDoc(DOC_2_PATH).get();
|
||||
data().elements.should.containDeep(['element 1', 'element 2']);
|
||||
|
||||
await testCollectionDoc(DOC_2_PATH).update({
|
||||
elements: firebase.firestore.FieldValue.arrayRemove('element 2'),
|
||||
});
|
||||
|
||||
const { data: dataAfterUpdate } = await testCollectionDoc(
|
||||
DOC_2_PATH
|
||||
).get();
|
||||
|
||||
dataAfterUpdate().elements.should.not.containDeep(['element 2']);
|
||||
});
|
||||
|
||||
it('should allow removing references & objects', async () => {
|
||||
await testCollectionDoc(DOC_2_PATH).set({
|
||||
elements: firebase.firestore.FieldValue.arrayUnion(
|
||||
'element 1',
|
||||
firebase
|
||||
.firestore()
|
||||
.collection('bar')
|
||||
.doc('foo'),
|
||||
firebase
|
||||
.firestore()
|
||||
.collection('bar')
|
||||
.doc('baz'),
|
||||
{ foo: 'bar', baz: [1, 2, 3], daz: { f: 'f' } }
|
||||
),
|
||||
});
|
||||
|
||||
const { data } = await testCollectionDoc(DOC_2_PATH).get();
|
||||
const { elements } = data();
|
||||
elements.length.should.equal(4);
|
||||
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
const element = elements[i];
|
||||
if (i === 0) element.should.equal('element 1');
|
||||
if (i === 1) {
|
||||
element.should.be.instanceOf(
|
||||
jet.require('src/modules/firestore/DocumentReference')
|
||||
);
|
||||
element.id.should.equal('foo');
|
||||
}
|
||||
if (i === 2) {
|
||||
element.should.be.instanceOf(
|
||||
jet.require('src/modules/firestore/DocumentReference')
|
||||
);
|
||||
element.id.should.equal('baz');
|
||||
}
|
||||
if (i === 3) {
|
||||
element.foo.should.equal('bar');
|
||||
element.baz[0].should.equal(1);
|
||||
}
|
||||
}
|
||||
|
||||
// now remove the last 2 items with arrayRemove
|
||||
await testCollectionDoc(DOC_2_PATH).update({
|
||||
elements: firebase.firestore.FieldValue.arrayRemove(
|
||||
firebase
|
||||
.firestore()
|
||||
.collection('bar')
|
||||
.doc('baz'),
|
||||
{ foo: 'bar', baz: [1, 2, 3], daz: { f: 'f' } }
|
||||
),
|
||||
});
|
||||
|
||||
const { data: dataAfterUpdate } = await testCollectionDoc(
|
||||
DOC_2_PATH
|
||||
).get();
|
||||
|
||||
const { elements: elementsAfterUpdate } = dataAfterUpdate();
|
||||
elementsAfterUpdate.length.should.equal(2);
|
||||
|
||||
for (let i = 0; i < elementsAfterUpdate.length; i++) {
|
||||
const element = elementsAfterUpdate[i];
|
||||
if (i === 0) element.should.equal('element 1');
|
||||
if (i === 1) {
|
||||
element.should.be.instanceOf(
|
||||
jet.require('src/modules/firestore/DocumentReference')
|
||||
);
|
||||
element.id.should.equal('foo');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,123 +0,0 @@
|
||||
describe('firestore()', () => {
|
||||
describe('collection()', () => {
|
||||
it('should create CollectionReference with the right id', () => {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection('collection1/doc1/collection2')
|
||||
.id.should.equal('collection2');
|
||||
});
|
||||
|
||||
it('should error if invalid collection path supplied', () => {
|
||||
(() => {
|
||||
firebase.firestore().collection('collection1/doc1');
|
||||
}).should.throw('Argument "collectionPath" must point to a collection.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('doc()', () => {
|
||||
it('should create DocumentReference with correct path', () => {
|
||||
firebase
|
||||
.firestore()
|
||||
.doc('collection1/doc1/collection2/doc2')
|
||||
.path.should.equal('collection1/doc1/collection2/doc2');
|
||||
});
|
||||
|
||||
it('should error if invalid document path supplied', () => {
|
||||
(() => {
|
||||
firebase.firestore().doc('collection1');
|
||||
}).should.throw('Argument "documentPath" must point to a document.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('disable/enableNetwork()', () => {
|
||||
it('calls without error', async () => {
|
||||
await firebase.firestore().disableNetwork();
|
||||
await firebase.firestore().enableNetwork();
|
||||
});
|
||||
});
|
||||
|
||||
describe('enablePersistence()', () => {
|
||||
it('calls without error', async () => {
|
||||
await firebase.firestore().enablePersistence();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setLogLevel()', () => {
|
||||
it('should set level from string', () => {
|
||||
firebase.firestore.setLogLevel('debug');
|
||||
firebase.firestore.setLogLevel('error');
|
||||
firebase.firestore.setLogLevel('silent');
|
||||
// test deprecated method
|
||||
firebase.firestore.enableLogging(true);
|
||||
firebase.firestore.enableLogging(false);
|
||||
});
|
||||
|
||||
it('should throw an invalid parameter error', () => {
|
||||
(() => {
|
||||
firebase.firestore.setLogLevel('warn');
|
||||
}).should.throw(
|
||||
'Argument `logLevel` must be one of: `debug`, `error`, `silent`'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('settings()', () => {
|
||||
it('should reject invalid object', async () => {
|
||||
try {
|
||||
await firebase.firestore().settings('test');
|
||||
} catch (error) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject(new Error('Did not error on invalid object'));
|
||||
});
|
||||
|
||||
it('should reject invalid host setting', async () => {
|
||||
try {
|
||||
await firebase.firestore().settings({ host: true });
|
||||
} catch (error) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
new Error('Did not error on invalid `host` setting')
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid persistence setting', async () => {
|
||||
try {
|
||||
await firebase.firestore().settings({ persistence: 'fail' });
|
||||
} catch (error) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
new Error('Did not error on invalid `persistence` setting')
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid ssl setting', async () => {
|
||||
try {
|
||||
await firebase.firestore().settings({ ssl: 'fail' });
|
||||
} catch (error) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
new Error('Did not error on invalid `ssl` setting')
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid timestampsInSnapshots setting', async () => {
|
||||
try {
|
||||
await firebase.firestore().settings({ timestampsInSnapshots: 'fail' });
|
||||
} catch (error) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
new Error('Did not error on invalid `timestampsInSnapshots` setting')
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,119 +0,0 @@
|
||||
describe('firestore()', () => {
|
||||
describe('Path', () => {
|
||||
describe('id', () => {
|
||||
it('returns the document id', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('collection/documentId');
|
||||
path.id.should.be.equal('documentId');
|
||||
});
|
||||
|
||||
it('returns empty string if no path', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('');
|
||||
should.equal(path.id, '');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isDocument', () => {
|
||||
it('returns true if path is a document', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('collection/documentId');
|
||||
path.isDocument.should.be.equal(true);
|
||||
});
|
||||
|
||||
it('returns false if path is a collection', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('collection');
|
||||
path.isDocument.should.be.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isCollection', () => {
|
||||
it('returns true if path is a collection', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('collection');
|
||||
path.isCollection.should.be.equal(true);
|
||||
});
|
||||
|
||||
it('returns false if path is a document', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('collection/documentId');
|
||||
path.isCollection.should.be.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('relativeName', () => {
|
||||
it('returns original full path', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('collection');
|
||||
const path2 = Path.fromName('collection/documentId');
|
||||
path.relativeName.should.be.equal('collection');
|
||||
path2.relativeName.should.be.equal('collection/documentId');
|
||||
});
|
||||
});
|
||||
|
||||
describe('child()', () => {
|
||||
it('returns original path joined with the provided child path', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('collection');
|
||||
const path2 = path.child('documentId');
|
||||
path.relativeName.should.be.equal('collection');
|
||||
path2.relativeName.should.be.equal('collection/documentId');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parent()', () => {
|
||||
it('returns the parent of the current child path', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('collection/documentId');
|
||||
const path2 = path.parent();
|
||||
path.relativeName.should.be.equal('collection/documentId');
|
||||
path2.relativeName.should.be.equal('collection');
|
||||
});
|
||||
|
||||
it('returns null if no path', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('');
|
||||
const path2 = path.parent();
|
||||
path._parts.length.should.be.equal(0);
|
||||
should.equal(path2, null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('static fromName()', () => {
|
||||
it('returns a new instance from a / delimited path string', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('collection/document');
|
||||
path.should.be.instanceOf(Path);
|
||||
path._parts.length.should.be.equal(2);
|
||||
});
|
||||
|
||||
it('returns a new instance from an empty string', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName('');
|
||||
path.should.be.instanceOf(Path);
|
||||
path._parts.length.should.be.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a new instance with no args provided', async () => {
|
||||
const Path = jet.require('src/modules/firestore/Path');
|
||||
|
||||
const path = Path.fromName();
|
||||
path.should.be.instanceOf(Path);
|
||||
path._parts.length.should.be.equal(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,169 +0,0 @@
|
||||
const { testDocRef } = TestHelpers.firestore;
|
||||
|
||||
describe('firestore()', () => {
|
||||
describe('runTransaction()', () => {
|
||||
it('should set() values', async () => {
|
||||
const firestore = firebase.firestore();
|
||||
const docRef = testDocRef('tSet');
|
||||
|
||||
const updateFunction = async transaction => {
|
||||
let doc;
|
||||
// TODO test multiple gets
|
||||
doc = await transaction.get(docRef);
|
||||
if (!doc.exists) {
|
||||
transaction.set(docRef, { value: 1, somethingElse: 'set' });
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
const result = await firestore.runTransaction(updateFunction);
|
||||
should.equal(result, 1);
|
||||
const finalDoc = await docRef.get();
|
||||
finalDoc.data().value.should.equal(1);
|
||||
finalDoc.data().somethingElse.should.equal('set');
|
||||
});
|
||||
|
||||
it('should update() values', async () => {
|
||||
const firestore = firebase.firestore();
|
||||
const docRef = testDocRef('tUpdate');
|
||||
|
||||
await docRef.set({ value: 1 });
|
||||
|
||||
const updateFunction = async transaction => {
|
||||
const doc = await transaction.get(docRef);
|
||||
if (doc.exists) {
|
||||
transaction.update(docRef, {
|
||||
value: doc.data().value + 1,
|
||||
somethingElse: 'update',
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
const result = await firestore.runTransaction(updateFunction);
|
||||
should.equal(result, 1);
|
||||
|
||||
const finalDoc = await docRef.get();
|
||||
finalDoc.data().value.should.equal(2);
|
||||
finalDoc.data().somethingElse.should.equal('update');
|
||||
});
|
||||
|
||||
it('should delete() values', async () => {
|
||||
const firestore = firebase.firestore();
|
||||
const docRef = testDocRef('tDelete');
|
||||
await docRef.set({ value: 1, somethingElse: 'delete' });
|
||||
|
||||
const updateFunction = async transaction => {
|
||||
const doc = await transaction.get(docRef);
|
||||
if (doc.exists) {
|
||||
transaction.delete(docRef);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
const result = await firestore.runTransaction(updateFunction);
|
||||
should.equal(result, 1);
|
||||
|
||||
const finalDoc = await docRef.get();
|
||||
finalDoc.exists.should.equal(false);
|
||||
});
|
||||
|
||||
it('error if updateFn does return a promise', async () => {
|
||||
const firestore = firebase.firestore();
|
||||
|
||||
// test async functions - they always return a promise in JS
|
||||
let didReject = false;
|
||||
let updateFunction = async () => 1;
|
||||
try {
|
||||
await firestore.runTransaction(updateFunction);
|
||||
} catch (e) {
|
||||
didReject = true;
|
||||
}
|
||||
should.equal(didReject, false);
|
||||
|
||||
// should not error as a promise returned
|
||||
didReject = false;
|
||||
updateFunction = () => Promise.resolve();
|
||||
try {
|
||||
await firestore.runTransaction(updateFunction);
|
||||
} catch (e) {
|
||||
didReject = true;
|
||||
}
|
||||
should.equal(didReject, false);
|
||||
|
||||
// should error as no promise returned
|
||||
didReject = false;
|
||||
updateFunction = () => '123456';
|
||||
try {
|
||||
await firestore.runTransaction(updateFunction);
|
||||
} catch (e) {
|
||||
didReject = true;
|
||||
e.message.includes('must return a Promise');
|
||||
}
|
||||
should.equal(didReject, true);
|
||||
});
|
||||
|
||||
it('updateFn promise rejections / js exceptions handled', async () => {
|
||||
const firestore = firebase.firestore();
|
||||
|
||||
// rejections
|
||||
let didReject = false;
|
||||
// eslint-disable-next-line
|
||||
let updateFunction = () => Promise.reject('shoop');
|
||||
try {
|
||||
await firestore.runTransaction(updateFunction);
|
||||
} catch (e) {
|
||||
didReject = true;
|
||||
should.equal(e, 'shoop');
|
||||
}
|
||||
should.equal(didReject, true);
|
||||
|
||||
// exceptions
|
||||
didReject = false;
|
||||
updateFunction = () => {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw 'doop';
|
||||
};
|
||||
try {
|
||||
await firestore.runTransaction(updateFunction);
|
||||
} catch (e) {
|
||||
didReject = true;
|
||||
should.equal(e, 'doop');
|
||||
}
|
||||
should.equal(didReject, true);
|
||||
});
|
||||
|
||||
it('handle native exceptions', async () => {
|
||||
const firestore = firebase.firestore();
|
||||
const docRef = testDocRef('tSet');
|
||||
const blockedRef = firestore.doc('denied/foo');
|
||||
|
||||
const updateFunction = async transaction => {
|
||||
await transaction.get(docRef);
|
||||
transaction.set(blockedRef, { value: 1, somethingElse: 'set' });
|
||||
return 1;
|
||||
};
|
||||
|
||||
// rejections
|
||||
let didReject = false;
|
||||
try {
|
||||
await firestore.runTransaction(updateFunction);
|
||||
} catch (e) {
|
||||
// TODO sdks are giving different errors - standardise?
|
||||
if (device.getPlatform() === 'ios') {
|
||||
e.message.should.containEql('firestore/failed-precondition');
|
||||
} else {
|
||||
e.message.should.containEql('firestore/aborted');
|
||||
}
|
||||
didReject = true;
|
||||
}
|
||||
should.equal(didReject, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,251 +0,0 @@
|
||||
const TEST_DATA = TestHelpers.functions.data;
|
||||
|
||||
describe('functions()', () => {
|
||||
it('accepts passing in an FirebaseApp instance as first arg', async () => {
|
||||
const appName = `functionsApp${global.testRunId}1`;
|
||||
const platformAppConfig = TestHelpers.core.config();
|
||||
const app = await firebase
|
||||
.initializeApp(platformAppConfig, appName)
|
||||
.onReady();
|
||||
|
||||
const functionsForApp = firebase.functions(app);
|
||||
|
||||
functionsForApp.app.should.equal(app);
|
||||
functionsForApp.app.name.should.equal(app.name);
|
||||
|
||||
// check from an app
|
||||
app.functions().app.should.equal(app);
|
||||
app.functions().app.name.should.equal(app.name);
|
||||
});
|
||||
|
||||
it('accepts passing in a region string as first arg', async () => {
|
||||
const region = 'europe-west1';
|
||||
const functionsForRegion = firebase.functions(region);
|
||||
|
||||
// check internal region property
|
||||
functionsForRegion._customUrlOrRegion.should.equal(region);
|
||||
// app should be default app
|
||||
functionsForRegion.app.should.equal(firebase.app());
|
||||
functionsForRegion.app.name.should.equal(firebase.app().name);
|
||||
|
||||
firebase
|
||||
.app()
|
||||
.functions(region)
|
||||
.app.should.equal(firebase.app());
|
||||
|
||||
firebase
|
||||
.app()
|
||||
.functions(region)
|
||||
._customUrlOrRegion.should.equal(region);
|
||||
|
||||
const functionRunner = functionsForRegion.httpsCallable(
|
||||
'runTestWithRegion'
|
||||
);
|
||||
|
||||
const response = await functionRunner();
|
||||
// the function just sends back it's region as a string
|
||||
response.data.should.equal(region);
|
||||
});
|
||||
|
||||
// TODO app and region test both args
|
||||
// TODO app passed to existing app instance - should error?
|
||||
|
||||
describe('httpsCallable(fnName)(args)', () => {
|
||||
it('accepts primitive args: undefined', async () => {
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
const response = await functionRunner();
|
||||
response.data.should.equal('null');
|
||||
});
|
||||
|
||||
it('accepts primitive args: string', async () => {
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
const response = await functionRunner('hello');
|
||||
response.data.should.equal('string');
|
||||
});
|
||||
|
||||
it('accepts primitive args: number', async () => {
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
const response = await functionRunner(123);
|
||||
response.data.should.equal('number');
|
||||
});
|
||||
|
||||
it('accepts primitive args: boolean', async () => {
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
const response = await functionRunner(true);
|
||||
response.data.should.equal('boolean');
|
||||
});
|
||||
|
||||
it('accepts primitive args: null', async () => {
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
const response = await functionRunner(null);
|
||||
response.data.should.equal('null');
|
||||
});
|
||||
|
||||
it('accepts array args', async () => {
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
const response = await functionRunner([1, 2, 3, 4]);
|
||||
response.data.should.equal('array');
|
||||
});
|
||||
|
||||
it('accepts object args', async () => {
|
||||
const type = 'simpleObject';
|
||||
const inputData = TEST_DATA[type];
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
const { data: outputData } = await functionRunner({
|
||||
type,
|
||||
inputData,
|
||||
});
|
||||
should.deepEqual(outputData, inputData);
|
||||
});
|
||||
|
||||
it('accepts complex nested objects', async () => {
|
||||
const type = 'advancedObject';
|
||||
const inputData = TEST_DATA[type];
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
const { data: outputData } = await functionRunner({
|
||||
type,
|
||||
inputData,
|
||||
});
|
||||
should.deepEqual(outputData, inputData);
|
||||
});
|
||||
|
||||
it('accepts complex nested arrays', async () => {
|
||||
const type = 'advancedArray';
|
||||
const inputData = TEST_DATA[type];
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
const { data: outputData } = await functionRunner({
|
||||
type,
|
||||
inputData,
|
||||
});
|
||||
should.deepEqual(outputData, inputData);
|
||||
});
|
||||
});
|
||||
|
||||
describe('HttpsError', () => {
|
||||
it('errors return instance of HttpsError', async () => {
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
try {
|
||||
await functionRunner({});
|
||||
return Promise.reject(new Error('Function did not reject with error.'));
|
||||
} catch (e) {
|
||||
should.equal(e.details, null);
|
||||
e.code.should.equal('invalid-argument');
|
||||
e.message.should.equal('Invalid test requested.');
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
it('HttpsError.details -> allows returning complex data', async () => {
|
||||
let type = 'advancedObject';
|
||||
let inputData = TEST_DATA[type];
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
try {
|
||||
await functionRunner({
|
||||
type,
|
||||
inputData,
|
||||
asError: true,
|
||||
});
|
||||
return Promise.reject(new Error('Function did not reject with error.'));
|
||||
} catch (e) {
|
||||
should.deepEqual(e.details, inputData);
|
||||
e.code.should.equal('cancelled');
|
||||
e.message.should.equal(
|
||||
'Response data was requested to be sent as part of an Error payload, so here we are!'
|
||||
);
|
||||
}
|
||||
|
||||
type = 'advancedArray';
|
||||
inputData = TEST_DATA[type];
|
||||
try {
|
||||
await functionRunner({
|
||||
type,
|
||||
inputData,
|
||||
asError: true,
|
||||
});
|
||||
return Promise.reject(new Error('Function did not reject with error.'));
|
||||
} catch (e) {
|
||||
should.deepEqual(e.details, inputData);
|
||||
e.code.should.equal('cancelled');
|
||||
e.message.should.equal(
|
||||
'Response data was requested to be sent as part of an Error payload, so here we are!'
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
it('HttpsError.details -> allows returning primitives', async () => {
|
||||
let type = 'number';
|
||||
let inputData = TEST_DATA[type];
|
||||
const functionRunner = firebase.functions().httpsCallable('runTest');
|
||||
try {
|
||||
await functionRunner({
|
||||
type,
|
||||
inputData,
|
||||
asError: true,
|
||||
});
|
||||
return Promise.reject(new Error('Function did not reject with error.'));
|
||||
} catch (e) {
|
||||
e.code.should.equal('cancelled');
|
||||
e.message.should.equal(
|
||||
'Response data was requested to be sent as part of an Error payload, so here we are!'
|
||||
);
|
||||
should.deepEqual(e.details, inputData);
|
||||
}
|
||||
|
||||
type = 'string';
|
||||
inputData = TEST_DATA[type];
|
||||
try {
|
||||
await functionRunner({
|
||||
type,
|
||||
inputData,
|
||||
asError: true,
|
||||
});
|
||||
return Promise.reject(new Error('Function did not reject with error.'));
|
||||
} catch (e) {
|
||||
should.deepEqual(e.details, inputData);
|
||||
e.code.should.equal('cancelled');
|
||||
e.message.should.equal(
|
||||
'Response data was requested to be sent as part of an Error payload, so here we are!'
|
||||
);
|
||||
}
|
||||
|
||||
type = 'boolean';
|
||||
inputData = TEST_DATA[type];
|
||||
try {
|
||||
await functionRunner({
|
||||
type,
|
||||
inputData,
|
||||
asError: true,
|
||||
});
|
||||
return Promise.reject(new Error('Function did not reject with error.'));
|
||||
} catch (e) {
|
||||
should.deepEqual(e.details, inputData);
|
||||
e.code.should.equal('cancelled');
|
||||
e.message.should.equal(
|
||||
'Response data was requested to be sent as part of an Error payload, so here we are!'
|
||||
);
|
||||
}
|
||||
|
||||
type = 'null';
|
||||
inputData = TEST_DATA[type];
|
||||
try {
|
||||
await functionRunner({
|
||||
type,
|
||||
inputData,
|
||||
asError: true,
|
||||
});
|
||||
return Promise.reject(new Error('Function did not reject with error.'));
|
||||
} catch (e) {
|
||||
should.deepEqual(e.details, inputData);
|
||||
e.code.should.equal('cancelled');
|
||||
e.message.should.equal(
|
||||
'Response data was requested to be sent as part of an Error payload, so here we are!'
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
144
tests/e2e/helpers.js
Normal file
144
tests/e2e/helpers.js
Normal file
@@ -0,0 +1,144 @@
|
||||
const { resolve } = require('path');
|
||||
const { existsSync } = require('fs');
|
||||
const requireAll = require('require-all');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param packageName
|
||||
*/
|
||||
function requirePackageTests(packageName) {
|
||||
const e2eDir = `./../packages/${packageName}/e2e`;
|
||||
if (existsSync(e2eDir)) {
|
||||
console.log(`Loaded tests from ${e2eDir}/*`);
|
||||
requireAll({
|
||||
dirname: resolve(e2eDir),
|
||||
filter: /(.+e2e)\.js$/,
|
||||
excludeDirs: /^\.(git|svn)$/,
|
||||
recursive: true,
|
||||
});
|
||||
} else {
|
||||
console.log(`No tests directory found for ${e2eDir}/*`);
|
||||
}
|
||||
}
|
||||
|
||||
global.sleep = d => new Promise(r => setTimeout(r, d));
|
||||
|
||||
Object.defineProperty(global, 'firebase', {
|
||||
get() {
|
||||
return jet.module;
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(global, 'NativeModules', {
|
||||
get() {
|
||||
return jet.NativeModules;
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(global, 'NativeEventEmitter', {
|
||||
get() {
|
||||
return jet.NativeEventEmitter;
|
||||
},
|
||||
});
|
||||
|
||||
global.isAndroid = process.argv.join('').includes('android.emu');
|
||||
global.isIOS = process.argv.join('').includes('ios.emu');
|
||||
global.android = {
|
||||
describe(name, ctx) {
|
||||
if (isAndroid) {
|
||||
describe(name, ctx);
|
||||
} else {
|
||||
xdescribe('SKIP: ANDROID ONLY - ' + name, ctx);
|
||||
}
|
||||
},
|
||||
it(name, ctx) {
|
||||
if (isAndroid) {
|
||||
it(name, ctx);
|
||||
} else {
|
||||
xit('SKIP: ANDROID ONLY - ' + name, ctx);
|
||||
}
|
||||
},
|
||||
};
|
||||
global.ios = {
|
||||
describe(name, ctx) {
|
||||
if (isIOS) {
|
||||
describe(name, ctx);
|
||||
} else {
|
||||
xdescribe('SKIP: IOS ONLY - ' + name, ctx);
|
||||
}
|
||||
},
|
||||
it(name, ctx) {
|
||||
if (isIOS) {
|
||||
it(name, ctx);
|
||||
} else {
|
||||
xit('SKIP: IOS ONLY - ' + name, ctx);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Old style deferred promise shim - for niceness
|
||||
*
|
||||
* @returns {{resolve: null, reject: null}}
|
||||
*/
|
||||
Promise.defer = function defer() {
|
||||
const deferred = {
|
||||
resolve: null,
|
||||
reject: null,
|
||||
};
|
||||
|
||||
deferred.promise = new Promise((resolve, reject) => {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
module.exports.requirePackageTests = requirePackageTests;
|
||||
|
||||
const androidTestConfig = {
|
||||
// firebase android sdk completely ignores client id
|
||||
clientId: '305229645282-j8ij0jev9ut24odmlk9i215pas808ugn.apps.googleusercontent.com',
|
||||
appId: '1:305229645282:android:af36d4d29a83e04c',
|
||||
apiKey: 'AIzaSyCzbBYFyX8d6VdSu7T4s10IWYbPc-dguwM',
|
||||
databaseURL: 'https://rnfirebase-b9ad4.firebaseio.com',
|
||||
storageBucket: 'rnfirebase-b9ad4.appspot.com',
|
||||
messagingSenderId: '305229645282',
|
||||
projectId: 'rnfirebase-b9ad4',
|
||||
};
|
||||
|
||||
const iosTestConfig = {
|
||||
clientId: '305229645282-22imndi01abc2p6esgtu1i1m9mqrd0ib.apps.googleusercontent.com',
|
||||
androidClientId: androidTestConfig.clientId,
|
||||
appId: '1:305229645282:ios:af36d4d29a83e04c',
|
||||
apiKey: 'AIzaSyAcdVLG5dRzA1ck_fa_xd4Z0cY7cga7S5A',
|
||||
databaseURL: 'https://rnfirebase-b9ad4.firebaseio.com',
|
||||
storageBucket: 'rnfirebase-b9ad4.appspot.com',
|
||||
messagingSenderId: '305229645282',
|
||||
projectId: 'rnfirebase-b9ad4',
|
||||
};
|
||||
|
||||
global.randomString = (length, chars) => {
|
||||
let mask = '';
|
||||
if (chars.indexOf('a') > -1) mask += 'abcdefghijklmnopqrstuvwxyz';
|
||||
if (chars.indexOf('A') > -1) mask += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
if (chars.indexOf('#') > -1) mask += '0123456789';
|
||||
if (chars.indexOf('!') > -1) mask += '~`!@#$%^&*()_+-={}[]:";\'<>?,./|\\';
|
||||
let result = '';
|
||||
for (let i = length; i > 0; --i) {
|
||||
result += mask[Math.round(Math.random() * (mask.length - 1))];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
global.testRunId = randomString(4, 'aA#');
|
||||
|
||||
global.TestHelpers = {
|
||||
core: {
|
||||
config() {
|
||||
const config = device.getPlatform() === 'ios' ? iosTestConfig : androidTestConfig;
|
||||
return { ...config };
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
describe('iid()', () => {
|
||||
describe('get()', () => {
|
||||
it('returns instance id string', async () => {
|
||||
const iid = await firebase.iid().get();
|
||||
iid.should.be.a.String();
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete()', () => {
|
||||
it('deletes the current instance id', async () => {
|
||||
const iidBefore = await firebase.iid().get();
|
||||
iidBefore.should.be.a.String();
|
||||
await firebase.iid().delete();
|
||||
|
||||
const iidAfter = await firebase.iid().get();
|
||||
iidAfter.should.be.a.String();
|
||||
iidBefore.should.not.equal(iidAfter);
|
||||
await sleep(4000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToken()', () => {
|
||||
it('should return an FCM token from getToken with arguments', async () => {
|
||||
const authorizedEntity = firebase.iid().app.options.messagingSenderId;
|
||||
const token = await firebase.iid().getToken(authorizedEntity, '*');
|
||||
token.should.be.a.String();
|
||||
});
|
||||
|
||||
it('should return an FCM token from getToken without arguments', async () => {
|
||||
const token = await firebase.iid().getToken();
|
||||
token.should.be.a.String();
|
||||
});
|
||||
|
||||
it('should return an FCM token from getToken with 1 argument', async () => {
|
||||
const authorizedEntity = firebase.iid().app.options.messagingSenderId;
|
||||
|
||||
const token = await firebase.iid().getToken(authorizedEntity);
|
||||
token.should.be.a.String();
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteToken()', () => {
|
||||
it('should return nil from deleteToken with arguments', async () => {
|
||||
const authorizedEntity = firebase.iid().app.options.messagingSenderId;
|
||||
const token = await firebase.iid().deleteToken(authorizedEntity, '*');
|
||||
should.not.exist(token);
|
||||
});
|
||||
|
||||
it('should return nil from deleteToken without arguments', async () => {
|
||||
const token = await firebase.iid().deleteToken();
|
||||
should.not.exist(token);
|
||||
});
|
||||
|
||||
it('should return nil from deleteToken with 1 argument', async () => {
|
||||
const authorizedEntity = firebase.iid().app.options.messagingSenderId;
|
||||
const token = await firebase.iid().deleteToken(authorizedEntity);
|
||||
should.not.exist(token);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,28 @@
|
||||
const detox = require('detox');
|
||||
const config = require('../package.json').detox;
|
||||
const { requirePackageTests } = require('./helpers');
|
||||
const { detox: config } = require('../package.json');
|
||||
|
||||
const PACKAGES = [
|
||||
'app',
|
||||
'analytics',
|
||||
'functions',
|
||||
// 'auth',
|
||||
// 'config',
|
||||
// 'crashlytics',
|
||||
// 'firestore',
|
||||
// 'fiam',
|
||||
// 'links',
|
||||
// 'messaging',
|
||||
// 'storage',
|
||||
];
|
||||
|
||||
for (let i = 0; i < PACKAGES.length; i++) {
|
||||
requirePackageTests(PACKAGES[i]);
|
||||
}
|
||||
|
||||
before(async () => {
|
||||
await detox.init(config);
|
||||
// needs to be called before any usage of firestore
|
||||
// await firebase.firestore().settings({ persistence: true });
|
||||
// await firebase.firestore().settings({ persistence: false });
|
||||
await firebase.initializeApp(TestHelpers.core.config());
|
||||
});
|
||||
|
||||
beforeEach(async function beforeEach() {
|
||||
@@ -35,8 +52,10 @@ beforeEach(async function beforeEach() {
|
||||
|
||||
after(async () => {
|
||||
console.log('Cleaning up...');
|
||||
await TestHelpers.firestore.cleanup();
|
||||
// await TestHelpers.firestore.cleanup();
|
||||
console.log('Firestore cleaned up...');
|
||||
// await detox.cleanup(); // TODO hangs - most likely jet internals interfering
|
||||
console.log('Detox cleaned up...');
|
||||
|
||||
await device.terminateApp();
|
||||
});
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
describe('messaging()', () => {
|
||||
describe('requestPermission()', () => {
|
||||
it('returns fcm token', async () => {
|
||||
if (device.getPlatform() === 'android') {
|
||||
await firebase.messaging().requestPermission();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasPermission()', () => {
|
||||
it('returns fcm token', async () => {
|
||||
const bool = await firebase.messaging().hasPermission();
|
||||
bool.should.be.Boolean();
|
||||
if (device.getPlatform() === 'android') {
|
||||
should.equal(bool, true);
|
||||
} else {
|
||||
should.equal(bool, false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('RemoteMessage', () => {
|
||||
it('builds a remote message', async () => {
|
||||
const message = new firebase.messaging.RemoteMessage();
|
||||
message.messageId.should.be.a.String(); // default
|
||||
message.setMessageId('123');
|
||||
message.messageId.should.equal('123');
|
||||
|
||||
message.setData({ foo: 'bar' });
|
||||
message.data.should.be.a.Object();
|
||||
|
||||
should.equal(message.ttl, 3600); // default
|
||||
message.setTtl(666);
|
||||
should.equal(message.ttl, 666);
|
||||
|
||||
should.equal(message.to, undefined);
|
||||
message.setTo('some-topic');
|
||||
|
||||
message.build();
|
||||
});
|
||||
});
|
||||
|
||||
describe('sendMessage()', () => {
|
||||
it('sends a message', async () => {
|
||||
const message = new firebase.messaging.RemoteMessage();
|
||||
message.setData({ foo: 'bar' });
|
||||
message.setMessageType('data');
|
||||
message.setTo(
|
||||
`${firebase.app().options.messagingSenderId}@gcm.googleapis.com`
|
||||
);
|
||||
await firebase.messaging().sendMessage(message);
|
||||
// TODO test with new firebase admin testing api
|
||||
// const { promise, resolve, reject } = Promise.defer();
|
||||
// const unsubscribe = firebase.messaging().onMessage(msg => {
|
||||
// resolve();
|
||||
// });
|
||||
// await promise;
|
||||
// unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
describe('subscribeToTopic()', () => {
|
||||
it('subscribe without error', async () => {
|
||||
await firebase.messaging().subscribeToTopic('foo-bar-baz');
|
||||
// TODO test subscription with new firebase testing api
|
||||
});
|
||||
});
|
||||
|
||||
describe('unsubscribeFromTopic()', () => {
|
||||
it('unsubscribe without error', async () => {
|
||||
await firebase.messaging().unsubscribeFromTopic('foo-bar-baz');
|
||||
// TODO test unsub with new firebase testing api
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToken()', () => {
|
||||
it('returns fcm token', async () => {
|
||||
const token = await firebase.messaging().getToken();
|
||||
token.should.be.a.String();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onTokenRefresh()', () => {
|
||||
it('triggers when token changes', async () => {
|
||||
let refreshedToken = null;
|
||||
let unsubscribe = null;
|
||||
|
||||
const tokenBefore = await firebase.messaging().getToken();
|
||||
tokenBefore.should.be.a.String();
|
||||
|
||||
const { promise, resolve, reject } = Promise.defer();
|
||||
unsubscribe = firebase.messaging().onTokenRefresh(newToken => {
|
||||
unsubscribe();
|
||||
|
||||
try {
|
||||
newToken.should.be.a.String();
|
||||
tokenBefore.should.not.equal(newToken);
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
|
||||
refreshedToken = newToken;
|
||||
return resolve();
|
||||
});
|
||||
|
||||
await firebase.messaging().deleteToken();
|
||||
await sleep(250);
|
||||
await firebase.iid().delete();
|
||||
await sleep(250);
|
||||
await firebase.iid().get();
|
||||
await sleep(250);
|
||||
|
||||
const tokenAfter = await firebase.messaging().getToken();
|
||||
tokenAfter.should.be.a.String();
|
||||
tokenBefore.should.not.equal(tokenAfter);
|
||||
|
||||
// TODO ios triggers twice, on initial token and new
|
||||
if (device.getPlatform() === 'android') {
|
||||
tokenAfter.should.equal(refreshedToken);
|
||||
}
|
||||
|
||||
await promise;
|
||||
|
||||
await sleep(500);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteToken()', () => {
|
||||
it('deletes the current fcm token', async () => {
|
||||
const tokenBefore = await firebase.messaging().getToken();
|
||||
tokenBefore.should.be.a.String();
|
||||
await firebase.messaging().deleteToken();
|
||||
|
||||
const tokenAfter = await firebase.messaging().getToken();
|
||||
tokenAfter.should.be.a.String();
|
||||
tokenBefore.should.not.equal(tokenAfter);
|
||||
await sleep(500);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
--recursive
|
||||
--timeout 120000
|
||||
--reporter xunit
|
||||
--reporter-options output=~/reports/ios-tests.xml.
|
||||
--slow 1200
|
||||
--bail
|
||||
--exit
|
||||
--require jet/platform/node
|
||||
--require ./helpers
|
||||
@@ -1,9 +1,8 @@
|
||||
--recursive
|
||||
--timeout 120000
|
||||
--timeout 240000
|
||||
--reporter spec
|
||||
--slow 1000
|
||||
--retries 3
|
||||
--retries 0
|
||||
--bail
|
||||
--exit
|
||||
--require jet/platform/node
|
||||
--require ./helpers
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
const trigger = {
|
||||
type: 'push',
|
||||
};
|
||||
|
||||
const notification = {
|
||||
trigger,
|
||||
title: 'Foo',
|
||||
subtitle: 'Bar',
|
||||
body: 'World',
|
||||
// badge: 0,
|
||||
payload: {
|
||||
foo: 'world',
|
||||
},
|
||||
// category: '',
|
||||
// 'content-available': 0,
|
||||
// 'user-text': '',
|
||||
// 'action-identifier': '',
|
||||
};
|
||||
|
||||
describe('notifications() - iOS Only', () => {
|
||||
describe('getInitialNotification()', () => {
|
||||
it('should be provided ', async () => {
|
||||
if (device.getPlatform() === 'ios') {
|
||||
await device.relaunchApp({ userNotification: notification });
|
||||
const initialNotification = await firebase
|
||||
.notifications()
|
||||
.getInitialNotification();
|
||||
|
||||
initialNotification.action.should.equal(
|
||||
'com.apple.UNNotificationDefaultActionIdentifier'
|
||||
);
|
||||
|
||||
initialNotification.notification.should.be.an.instanceOf(
|
||||
jet.require('src/modules/notifications/Notification')
|
||||
);
|
||||
|
||||
initialNotification.notification.title.should.equal(notification.title);
|
||||
|
||||
initialNotification.notification.subtitle.should.equal(
|
||||
notification.subtitle
|
||||
);
|
||||
|
||||
initialNotification.notification.body.should.equal(notification.body);
|
||||
|
||||
initialNotification.notification.data.foo.should.equal(
|
||||
notification.payload.foo
|
||||
);
|
||||
|
||||
// TODO: Salakar: more validations
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,93 +0,0 @@
|
||||
describe('perf()', () => {
|
||||
describe('HttpMetric', () => {
|
||||
it('start() & stop()', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
await httpMetric.stop();
|
||||
});
|
||||
|
||||
it('removeAttribute()', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
await httpMetric.putAttribute('foo', 'bar');
|
||||
const value = await httpMetric.getAttribute('foo');
|
||||
should.equal(value, 'bar');
|
||||
await httpMetric.removeAttribute('foo');
|
||||
const value2 = await httpMetric.getAttribute('foo');
|
||||
should.equal(value2, null);
|
||||
await httpMetric.stop();
|
||||
});
|
||||
|
||||
it('getAttribute() should return null', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
const value = await httpMetric.getAttribute('foo');
|
||||
should.equal(value, null);
|
||||
await httpMetric.removeAttribute('foo');
|
||||
await httpMetric.stop();
|
||||
});
|
||||
|
||||
it('getAttribute() should return string value', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
await httpMetric.putAttribute('foo', 'bar');
|
||||
const value = await httpMetric.getAttribute('foo');
|
||||
should.equal(value, 'bar');
|
||||
await httpMetric.removeAttribute('foo');
|
||||
await httpMetric.stop();
|
||||
});
|
||||
|
||||
it('putAttribute()', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
await httpMetric.putAttribute('foo', 'bar');
|
||||
const value = await httpMetric.getAttribute('foo');
|
||||
value.should.equal('bar');
|
||||
await httpMetric.removeAttribute('foo');
|
||||
await httpMetric.stop();
|
||||
});
|
||||
|
||||
it('getAttributes()', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
await httpMetric.putAttribute('foo', 'bar');
|
||||
await httpMetric.putAttribute('bar', 'baz');
|
||||
const value = await httpMetric.getAttributes();
|
||||
value.should.deepEqual({
|
||||
foo: 'bar',
|
||||
bar: 'baz',
|
||||
});
|
||||
await httpMetric.removeAttribute('foo');
|
||||
await httpMetric.removeAttribute('bar');
|
||||
await httpMetric.stop();
|
||||
});
|
||||
|
||||
it('setHttpResponseCode()', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
await httpMetric.setHttpResponseCode(500);
|
||||
await httpMetric.stop();
|
||||
});
|
||||
|
||||
it('setRequestPayloadSize()', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
await httpMetric.setRequestPayloadSize(1234567);
|
||||
await httpMetric.stop();
|
||||
});
|
||||
|
||||
it('setResponseContentType()', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
await httpMetric.setResponseContentType('application/foobar');
|
||||
await httpMetric.stop();
|
||||
});
|
||||
|
||||
it('setResponsePayloadSize()', async () => {
|
||||
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
await httpMetric.start();
|
||||
await httpMetric.setResponsePayloadSize(123456789);
|
||||
await httpMetric.stop();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,52 +0,0 @@
|
||||
describe('perf()', () => {
|
||||
describe('setPerformanceCollectionEnabled()', () => {
|
||||
it('true', async () => {
|
||||
await firebase.perf().setPerformanceCollectionEnabled(true);
|
||||
await sleep(2000);
|
||||
});
|
||||
|
||||
it('false', async () => {
|
||||
await firebase.perf().setPerformanceCollectionEnabled(false);
|
||||
await sleep(2000);
|
||||
await firebase.perf().setPerformanceCollectionEnabled(true);
|
||||
await sleep(2000);
|
||||
await device.launchApp({ newInstance: true });
|
||||
});
|
||||
|
||||
it('errors if not boolean', async () => {
|
||||
(() => firebase.perf().setPerformanceCollectionEnabled()).should.throw(
|
||||
'firebase.perf().setPerformanceCollectionEnabled() requires a boolean value'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('newTrace()', () => {
|
||||
it('returns an instance of Trace', async () => {
|
||||
const trace = firebase.perf().newTrace('foo');
|
||||
trace.constructor.name.should.be.equal('Trace');
|
||||
});
|
||||
|
||||
it('errors if identifier not a string', async () => {
|
||||
(() => firebase.perf().newTrace([1, 2, 3, 4])).should.throw(
|
||||
'firebase.perf().newTrace() requires a string value'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('newHttpMetric()', () => {
|
||||
it('returns an instance of HttpMetric', async () => {
|
||||
const trace = firebase.perf().newHttpMetric('http://foo.com', 'GET');
|
||||
trace.constructor.name.should.be.equal('HttpMetric');
|
||||
});
|
||||
|
||||
it('errors if url/httpMethod not a string', async () => {
|
||||
(() => firebase.perf().newHttpMetric(123, [1, 2])).should.throw(
|
||||
'firebase.perf().newHttpMetric() requires url and httpMethod string values'
|
||||
);
|
||||
});
|
||||
|
||||
it('errors if httpMethod not a valid type', async () => {
|
||||
(() => firebase.perf().newHttpMetric('foo', 'FOO')).should.throw(); // TODO error
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,87 +0,0 @@
|
||||
describe('perf()', () => {
|
||||
describe('Trace', () => {
|
||||
it('start() & stop()', async () => {
|
||||
const trace = firebase.perf().newTrace('bar');
|
||||
await trace.start();
|
||||
await trace.stop();
|
||||
});
|
||||
|
||||
it('getAttribute() should return null', async () => {
|
||||
const trace = firebase.perf().newTrace('bar');
|
||||
await trace.start();
|
||||
const value = await trace.getAttribute('foo');
|
||||
should.equal(value, null);
|
||||
await trace.stop();
|
||||
});
|
||||
|
||||
it('getAttribute() should return string value', async () => {
|
||||
const trace = firebase.perf().newTrace('bar');
|
||||
await trace.start();
|
||||
await trace.putAttribute('foo', 'bar');
|
||||
const value = await trace.getAttribute('foo');
|
||||
should.equal(value, 'bar');
|
||||
await trace.stop();
|
||||
});
|
||||
|
||||
it('putAttribute()', async () => {
|
||||
const trace = firebase.perf().newTrace('bar');
|
||||
await trace.start();
|
||||
await trace.putAttribute('foo', 'bar');
|
||||
const value = await trace.getAttribute('foo');
|
||||
value.should.equal('bar');
|
||||
await trace.stop();
|
||||
});
|
||||
|
||||
it('getAttributes()', async () => {
|
||||
const trace = firebase.perf().newTrace('bar');
|
||||
await trace.start();
|
||||
await trace.putAttribute('foo', 'bar');
|
||||
await trace.putAttribute('bar', 'baz');
|
||||
const value = await trace.getAttributes();
|
||||
value.should.deepEqual({
|
||||
foo: 'bar',
|
||||
bar: 'baz',
|
||||
});
|
||||
await trace.stop();
|
||||
});
|
||||
|
||||
it('removeAttribute()', async () => {
|
||||
const trace = firebase.perf().newTrace('bar');
|
||||
await trace.start();
|
||||
await trace.putAttribute('foobar', 'bar');
|
||||
const value = await trace.getAttribute('foobar');
|
||||
value.should.equal('bar');
|
||||
await trace.removeAttribute('foobar');
|
||||
const removed = await trace.getAttribute('foobar');
|
||||
should.equal(removed, null);
|
||||
await trace.stop();
|
||||
});
|
||||
|
||||
it('getMetric()', async () => {
|
||||
const trace = firebase.perf().newTrace('bar');
|
||||
await trace.start();
|
||||
const metric = await trace.getMetric('foo');
|
||||
metric.should.equal(0);
|
||||
await trace.stop();
|
||||
});
|
||||
|
||||
it('putMetric()', async () => {
|
||||
const trace = firebase.perf().newTrace('bar');
|
||||
await trace.start();
|
||||
await trace.putMetric('baz', 1);
|
||||
const metric = await trace.getMetric('baz');
|
||||
metric.should.equal(1);
|
||||
await trace.stop();
|
||||
});
|
||||
|
||||
it('incrementMetric()', async () => {
|
||||
const trace = firebase.perf().newTrace('bar');
|
||||
await trace.start();
|
||||
await trace.putMetric('baz', 1);
|
||||
await trace.incrementMetric('baz', 2);
|
||||
const metric = await trace.getMetric('baz');
|
||||
metric.should.equal(3);
|
||||
await trace.stop();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,163 +0,0 @@
|
||||
describe('storage()', () => {
|
||||
describe('ref()', () => {
|
||||
describe('toString()', () => {
|
||||
it('returns the correct bucket path to the file', () => {
|
||||
const app = firebase.app();
|
||||
firebase
|
||||
.storage()
|
||||
.ref('/uploadNope.jpeg')
|
||||
.toString()
|
||||
.should.equal(`gs://${app.options.storageBucket}/uploadNope.jpeg`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('downloadFile()', () => {
|
||||
it('errors if permission denied', async () => {
|
||||
try {
|
||||
await firebase
|
||||
.storage()
|
||||
.ref('/not.jpg')
|
||||
.downloadFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/not.jpg`
|
||||
);
|
||||
return Promise.reject(new Error('No permission denied error'));
|
||||
} catch (error) {
|
||||
error.code.should.equal('storage/unauthorized');
|
||||
error.message.includes('not authorized').should.be.true();
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
it('downloads a file', async () => {
|
||||
const meta = await firebase
|
||||
.storage()
|
||||
.ref('/ok.jpeg')
|
||||
.downloadFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
|
||||
);
|
||||
|
||||
meta.state.should.eql(firebase.storage.TaskState.SUCCESS);
|
||||
meta.bytesTransferred.should.eql(meta.totalBytes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('putFile()', () => {
|
||||
before(async () => {
|
||||
await firebase
|
||||
.storage()
|
||||
.ref('/ok.jpeg')
|
||||
.downloadFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
|
||||
);
|
||||
await firebase
|
||||
.storage()
|
||||
.ref('/cat.gif')
|
||||
.downloadFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/cat.gif`
|
||||
);
|
||||
await firebase
|
||||
.storage()
|
||||
.ref('/hei.heic')
|
||||
.downloadFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/hei.heic`
|
||||
);
|
||||
});
|
||||
|
||||
it('errors if permission denied', async () => {
|
||||
try {
|
||||
await firebase
|
||||
.storage()
|
||||
.ref('/uploadNope.jpeg')
|
||||
.putFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
|
||||
);
|
||||
return Promise.reject(new Error('No permission denied error'));
|
||||
} catch (error) {
|
||||
error.code.should.equal('storage/unauthorized');
|
||||
error.message.includes('not authorized').should.be.true();
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
it('uploads a file', async () => {
|
||||
const uploadTaskSnapshot = await firebase
|
||||
.storage()
|
||||
.ref('/uploadOk.jpeg')
|
||||
.putFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
|
||||
);
|
||||
|
||||
await firebase
|
||||
.storage()
|
||||
.ref('/uploadCat.gif')
|
||||
.putFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/cat.gif`
|
||||
);
|
||||
|
||||
await firebase
|
||||
.storage()
|
||||
.ref('/uploadHei.heic')
|
||||
.putFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/hei.heic`
|
||||
);
|
||||
|
||||
uploadTaskSnapshot.state.should.eql(firebase.storage.TaskState.SUCCESS);
|
||||
uploadTaskSnapshot.bytesTransferred.should.eql(
|
||||
uploadTaskSnapshot.totalBytes
|
||||
);
|
||||
uploadTaskSnapshot.metadata.should.be.an.Object();
|
||||
uploadTaskSnapshot.downloadURL.should.be.a.String();
|
||||
});
|
||||
|
||||
it('uploads a file without read permission', async () => {
|
||||
const uploadTaskSnapshot = await firebase
|
||||
.storage()
|
||||
.ref('/writeOnly.jpeg')
|
||||
.putFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
|
||||
);
|
||||
|
||||
uploadTaskSnapshot.state.should.eql(firebase.storage.TaskState.SUCCESS);
|
||||
uploadTaskSnapshot.bytesTransferred.should.eql(
|
||||
uploadTaskSnapshot.totalBytes
|
||||
);
|
||||
uploadTaskSnapshot.metadata.should.be.an.Object();
|
||||
should.not.exist(uploadTaskSnapshot.downloadURL);
|
||||
});
|
||||
});
|
||||
|
||||
describe('on()', () => {
|
||||
before(async () => {
|
||||
await firebase
|
||||
.storage()
|
||||
.ref('/ok.jpeg')
|
||||
.downloadFile(
|
||||
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
|
||||
);
|
||||
});
|
||||
|
||||
it('listens to upload state', () => {
|
||||
const { resolve, reject, promise } = Promise.defer();
|
||||
const path = `${
|
||||
firebase.storage.Native.DOCUMENT_DIRECTORY_PATH
|
||||
}/ok.jpeg`;
|
||||
const ref = firebase.storage().ref('/uploadOk.jpeg');
|
||||
|
||||
const unsubscribe = ref.putFile(path).on(
|
||||
firebase.storage.TaskEvent.STATE_CHANGED,
|
||||
snapshot => {
|
||||
if (snapshot.state === firebase.storage.TaskState.SUCCESS) {
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
error => {
|
||||
unsubscribe();
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
return promise;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user