[tests][auth] Tests for onAuthStateChange, onIdTokenChanged and onUserChanged

This commit is contained in:
Chris Bianca 2018-01-24 15:03:21 +00:00
parent 66a8ef6926
commit c3e5eb634e
2 changed files with 285 additions and 61 deletions

View File

@ -37,6 +37,7 @@ type ActionCodeInfo = {
const NATIVE_EVENTS = [ const NATIVE_EVENTS = [
'auth_state_changed', 'auth_state_changed',
'auth_id_token_changed',
'phone_auth_state_changed', 'phone_auth_state_changed',
]; ];
@ -63,37 +64,36 @@ export default class Auth extends ModuleBase {
// sub to internal native event - this fans out to // sub to internal native event - this fans out to
// public event name: onAuthStateChanged // public event name: onAuthStateChanged
getAppEventName(this, 'auth_state_changed'), getAppEventName(this, 'auth_state_changed'),
this._onInternalAuthStateChanged.bind(this), (state: AuthState) => {
this._setUser(state.user);
SharedEventEmitter.emit(getAppEventName(this, 'onAuthStateChanged'), this._user);
},
); );
SharedEventEmitter.addListener( SharedEventEmitter.addListener(
// sub to internal native event - this fans out to // sub to internal native event - this fans out to
// public events based on event.type // public events based on event.type
getAppEventName(this, 'phone_auth_state_changed'), getAppEventName(this, 'phone_auth_state_changed'),
this._onInternalPhoneAuthStateChanged.bind(this), (event: Object) => {
const eventKey = `phone:auth:${event.requestKey}:${event.type}`;
SharedEventEmitter.emit(eventKey, event.state);
},
); );
SharedEventEmitter.addListener( SharedEventEmitter.addListener(
// sub to internal native event - this fans out to // sub to internal native event - this fans out to
// public event name: onIdTokenChanged // public event name: onIdTokenChanged
getAppEventName(this, 'auth_id_token_changed'), getAppEventName(this, 'auth_id_token_changed'),
this._onInternalIdTokenChanged.bind(this), (auth: AuthState) => {
this._setUser(auth.user);
SharedEventEmitter.emit(getAppEventName(this, 'onIdTokenChanged'), this._user);
},
); );
getNativeModule(this).addAuthStateListener(); getNativeModule(this).addAuthStateListener();
getNativeModule(this).addIdTokenListener(); getNativeModule(this).addIdTokenListener();
} }
/**
* Route a phone state change event to the correct listeners
* @param event
* @private
*/
_onInternalPhoneAuthStateChanged(event: Object) {
const eventKey = `phone:auth:${event.requestKey}:${event.type}`;
SharedEventEmitter.emit(eventKey, event.state);
}
_setUser(user: ?NativeUser): ?User { _setUser(user: ?NativeUser): ?User {
this._authResult = true; this._authResult = true;
this._user = user ? new User(this, user) : null; this._user = user ? new User(this, user) : null;
@ -112,27 +112,6 @@ export default class Auth extends ModuleBase {
}; };
} }
/**
* Internal auth changed listener
* @param auth
* @private
*/
_onInternalAuthStateChanged(auth: AuthState) {
this._setUser(auth.user);
SharedEventEmitter.emit(getAppEventName(this, 'onAuthStateChanged'), this._user);
}
/**
* Internal auth changed listener
* @param auth
* @param emit
* @private
*/
_onInternalIdTokenChanged(auth: AuthState) {
this._setUser(auth.user);
SharedEventEmitter.emit(getAppEventName(this, 'onIdTokenChanged'), this._user);
}
/* /*
* WEB API * WEB API
*/ */
@ -145,16 +124,11 @@ export default class Auth extends ModuleBase {
getLogger(this).info('Creating onAuthStateChanged listener'); getLogger(this).info('Creating onAuthStateChanged listener');
SharedEventEmitter.addListener(getAppEventName(this, 'onAuthStateChanged'), listener); SharedEventEmitter.addListener(getAppEventName(this, 'onAuthStateChanged'), listener);
if (this._authResult) listener(this._user || null); if (this._authResult) listener(this._user || null);
return this._offAuthStateChanged.bind(this, listener);
}
/** return () => {
* Remove auth change listener
* @param listener
*/
_offAuthStateChanged(listener: Function) {
getLogger(this).info('Removing onAuthStateChanged listener'); getLogger(this).info('Removing onAuthStateChanged listener');
SharedEventEmitter.removeListener(getAppEventName(this, 'onAuthStateChanged'), listener); SharedEventEmitter.removeListener(getAppEventName(this, 'onAuthStateChanged'), listener);
};
} }
/** /**
@ -165,16 +139,11 @@ export default class Auth extends ModuleBase {
getLogger(this).info('Creating onIdTokenChanged listener'); getLogger(this).info('Creating onIdTokenChanged listener');
SharedEventEmitter.addListener(getAppEventName(this, 'onIdTokenChanged'), listener); SharedEventEmitter.addListener(getAppEventName(this, 'onIdTokenChanged'), listener);
if (this._authResult) listener(this._user || null); if (this._authResult) listener(this._user || null);
return this._offIdTokenChanged.bind(this, listener);
}
/** return () => {
* Remove id token change listener
* @param listener
*/
_offIdTokenChanged(listener: Function) {
getLogger(this).info('Removing onIdTokenChanged listener'); getLogger(this).info('Removing onIdTokenChanged listener');
SharedEventEmitter.removeListener(getAppEventName(this, 'onIdTokenChanged'), listener); SharedEventEmitter.removeListener(getAppEventName(this, 'onIdTokenChanged'), listener);
};
} }
/** /**
@ -185,16 +154,11 @@ export default class Auth extends ModuleBase {
getLogger(this).info('Creating onUserChanged listener'); getLogger(this).info('Creating onUserChanged listener');
SharedEventEmitter.addListener(getAppEventName(this, 'onUserChanged'), listener); SharedEventEmitter.addListener(getAppEventName(this, 'onUserChanged'), listener);
if (this._authResult) listener(this._user || null); if (this._authResult) listener(this._user || null);
return this._offUserChanged.bind(this, listener);
}
/** return () => {
* Remove user change listener
* @param listener
*/
_offUserChanged(listener: Function) {
getLogger(this).info('Removing onUserChanged listener'); getLogger(this).info('Removing onUserChanged listener');
SharedEventEmitter.removeListener(getAppEventName(this, 'onUserChanged'), listener); SharedEventEmitter.removeListener(getAppEventName(this, 'onUserChanged'), listener);
};
} }
/** /**

View File

@ -1,3 +1,5 @@
import sinon from 'sinon';
import 'should-sinon';
import should from 'should'; import should from 'should';
function randomString(length, chars) { function randomString(length, chars) {
@ -12,6 +14,264 @@ function randomString(length, chars) {
} }
function authTests({ tryCatch, describe, it, firebase }) { function authTests({ tryCatch, describe, it, firebase }) {
describe('onAuthStateChanged', () => {
it('calls callback with the current user and when auth state changes', async () => {
await firebase.native.auth().signInAnonymously();
// Test
const callback = sinon.spy();
let unsubscribe;
await new Promise((resolve) => {
unsubscribe = firebase.native.auth().onAuthStateChanged((user) => {
callback(user);
resolve();
});
});
callback.should.be.calledWith(firebase.native.auth().currentUser);
callback.should.be.calledOnce();
// Sign out
await firebase.native.auth().signOut();
await new Promise((resolve) => {
setTimeout(() => resolve(), 5);
});
// Assertions
callback.should.be.calledWith(null);
callback.should.be.calledTwice();
// Tear down
unsubscribe();
});
it('stops listening when unsubscribed', async () => {
await firebase.native.auth().signInAnonymously();
// Test
const callback = sinon.spy();
let unsubscribe;
await new Promise((resolve) => {
unsubscribe = firebase.native.auth().onAuthStateChanged((user) => {
callback(user);
resolve();
});
});
callback.should.be.calledWith(firebase.native.auth().currentUser);
callback.should.be.calledOnce();
// Sign out
await firebase.native.auth().signOut();
await new Promise((resolve) => {
setTimeout(() => resolve(), 5);
});
// Assertions
callback.should.be.calledWith(null);
callback.should.be.calledTwice();
// Unsubscribe
unsubscribe();
// Sign back in
await firebase.native.auth().signInAnonymously();
// Assertions
callback.should.be.calledTwice();
// Tear down
await firebase.native.auth().signOut();
});
});
describe('onIdTokenChanged', () => {
it('calls callback with the current user and when auth state changes', async () => {
await firebase.native.auth().signInAnonymously();
// Test
const callback = sinon.spy();
let unsubscribe;
await new Promise((resolve) => {
unsubscribe = firebase.native.auth().onIdTokenChanged((user) => {
callback(user);
resolve();
});
});
callback.should.be.calledWith(firebase.native.auth().currentUser);
callback.should.be.calledOnce();
// Sign out
await firebase.native.auth().signOut();
await new Promise((resolve) => {
setTimeout(() => resolve(), 5);
});
// Assertions
callback.should.be.calledWith(null);
callback.should.be.calledTwice();
// Tear down
unsubscribe();
});
it('stops listening when unsubscribed', async () => {
await firebase.native.auth().signInAnonymously();
// Test
const callback = sinon.spy();
let unsubscribe;
await new Promise((resolve) => {
unsubscribe = firebase.native.auth().onIdTokenChanged((user) => {
callback(user);
resolve();
});
});
callback.should.be.calledWith(firebase.native.auth().currentUser);
callback.should.be.calledOnce();
// Sign out
await firebase.native.auth().signOut();
await new Promise((resolve) => {
setTimeout(() => resolve(), 5);
});
// Assertions
callback.should.be.calledWith(null);
callback.should.be.calledTwice();
// Unsubscribe
unsubscribe();
// Sign back in
await firebase.native.auth().signInAnonymously();
// Assertions
callback.should.be.calledTwice();
// Tear down
await firebase.native.auth().signOut();
});
});
describe('onUserChanged', () => {
it('calls callback with the current user and when auth state changes', async () => {
await firebase.native.auth().signInAnonymously();
// Test
const callback = sinon.spy();
let unsubscribe;
await new Promise((resolve) => {
unsubscribe = firebase.native.auth().onUserChanged((user) => {
callback(user);
resolve();
});
});
callback.should.be.calledWith(firebase.native.auth().currentUser);
callback.should.be.calledOnce();
// Sign out
await firebase.native.auth().signOut();
await new Promise((resolve) => {
setTimeout(() => resolve(), 5);
});
// Assertions
callback.should.be.calledWith(null);
// Because of the way onUserChanged works, it will be called double
// - once for onAuthStateChanged
// - once for onIdTokenChanged
callback.should.have.callCount(4);
// Tear down
unsubscribe();
});
it('stops listening when unsubscribed', async () => {
await firebase.native.auth().signInAnonymously();
// Test
const callback = sinon.spy();
let unsubscribe;
await new Promise((resolve) => {
unsubscribe = firebase.native.auth().onUserChanged((user) => {
callback(user);
resolve();
});
});
callback.should.be.calledWith(firebase.native.auth().currentUser);
callback.should.be.calledOnce();
// Sign out
await firebase.native.auth().signOut();
await new Promise((resolve) => {
setTimeout(() => resolve(), 5);
});
// Assertions
callback.should.be.calledWith(null);
// Because of the way onUserChanged works, it will be called double
// - once for onAuthStateChanged
// - once for onIdTokenChanged
callback.should.have.callCount(4);
// Unsubscribe
unsubscribe();
// Sign back in
await firebase.native.auth().signInAnonymously();
// Assertions
callback.should.have.callCount(4);
// Tear down
await firebase.native.auth().signOut();
});
});
describe('signInAnonymously', () => { describe('signInAnonymously', () => {
it('it should sign in anonymously', () => { it('it should sign in anonymously', () => {
const successCb = (currentUser) => { const successCb = (currentUser) => {