@@ -23,11 +23,17 @@ import * as scrypt from 'scrypt';
2323import firebase from '@firebase/app' ;
2424import '@firebase/auth' ;
2525import { clone } from 'lodash' ;
26- import { generateRandomString , projectId , apiKey , noServiceAccountApp } from './setup' ;
26+ import {
27+ generateRandomString , projectId , apiKey , noServiceAccountApp , cmdArgs ,
28+ } from './setup' ;
2729import url = require( 'url' ) ;
2830import * as mocks from '../resources/mocks' ;
2931import { AuthProviderConfig } from '../../src/auth/auth-config' ;
30- import { deepExtend } from '../../src/utils/deep-copy' ;
32+ import { deepExtend , deepCopy } from '../../src/utils/deep-copy' ;
33+
34+ /* tslint:disable:no-var-requires */
35+ const chalk = require ( 'chalk' ) ;
36+ /* tslint:enable:no-var-requires */
3137
3238chai . should ( ) ;
3339chai . use ( chaiAsPromised ) ;
@@ -428,6 +434,153 @@ describe('admin.auth', () => {
428434 } ) ;
429435 } ) ;
430436
437+ describe ( 'Tenant management operations' , ( ) => {
438+ // TODO: Add basic user management tests for multi-tenancy when Auth client SDK starts supporting it.
439+ let createdTenantId : string ;
440+ const createdTenants : string [ ] = [ ] ;
441+ const tenantOptions : admin . auth . CreateTenantRequest = {
442+ displayName : 'testTenant1' ,
443+ type : 'lightweight' ,
444+ emailSignInConfig : {
445+ enabled : true ,
446+ passwordRequired : true ,
447+ } ,
448+ } ;
449+ const expectedCreatedTenant : any = {
450+ displayName : 'testTenant1' ,
451+ emailSignInConfig : {
452+ enabled : true ,
453+ passwordRequired : true ,
454+ } ,
455+ type : 'lightweight' ,
456+ } ;
457+ const expectedUpdatedTenant : any = {
458+ displayName : 'testTenantUpdated' ,
459+ emailSignInConfig : {
460+ enabled : false ,
461+ passwordRequired : true ,
462+ } ,
463+ type : 'lightweight' ,
464+ } ;
465+ const expectedUpdatedTenant2 : any = {
466+ displayName : 'testTenantUpdated' ,
467+ emailSignInConfig : {
468+ enabled : true ,
469+ passwordRequired : false ,
470+ } ,
471+ type : 'lightweight' ,
472+ } ;
473+
474+ // https://mochajs.org/
475+ // Passing arrow functions (aka "lambdas") to Mocha is discouraged.
476+ // Lambdas lexically bind this and cannot access the Mocha context.
477+ before ( function ( ) {
478+ /* tslint:disable:no-console */
479+ if ( ! cmdArgs . testMultiTenancy ) {
480+ // To enable, run: npm run test:integration -- --testMultiTenancy
481+ // By default we skip multi-tenancy as it is a Google Cloud Identity Platform
482+ // feature only and requires to be enabled via the Cloud Console.
483+ console . log ( chalk . yellow ( ' Skipping multi-tenancy tests.' ) ) ;
484+ this . skip ( ) ;
485+ }
486+ /* tslint:enable:no-console */
487+ } ) ;
488+
489+ // Delete test tenants at the end of test suite.
490+ after ( ( ) => {
491+ const promises : Array < Promise < any > > = [ ] ;
492+ createdTenants . forEach ( ( tenantId ) => {
493+ promises . push (
494+ admin . auth ( ) . deleteTenant ( tenantId ) . catch ( ( error ) => { /** Ignore. */ } ) ) ;
495+ } ) ;
496+ return Promise . all ( promises ) ;
497+ } ) ;
498+
499+ it ( 'createTenant() should resolve with a new tenant' , ( ) => {
500+ return admin . auth ( ) . createTenant ( tenantOptions )
501+ . then ( ( actualTenant ) => {
502+ createdTenantId = actualTenant . tenantId ;
503+ createdTenants . push ( createdTenantId ) ;
504+ expectedCreatedTenant . tenantId = createdTenantId ;
505+ expect ( actualTenant . toJSON ( ) ) . to . deep . equal ( expectedCreatedTenant ) ;
506+ } ) ;
507+ } ) ;
508+
509+ it ( 'getTenant() should resolve with expected tenant' , ( ) => {
510+ return admin . auth ( ) . getTenant ( createdTenantId )
511+ . then ( ( actualTenant ) => {
512+ expect ( actualTenant . toJSON ( ) ) . to . deep . equal ( expectedCreatedTenant ) ;
513+ } ) ;
514+ } ) ;
515+
516+ it ( 'updateTenant() should resolve with the updated tenant' , ( ) => {
517+ expectedUpdatedTenant . tenantId = createdTenantId ;
518+ expectedUpdatedTenant2 . tenantId = createdTenantId ;
519+ const updatedOptions : admin . auth . UpdateTenantRequest = {
520+ displayName : expectedUpdatedTenant . displayName ,
521+ emailSignInConfig : {
522+ enabled : false ,
523+ } ,
524+ } ;
525+ const updatedOptions2 : admin . auth . UpdateTenantRequest = {
526+ emailSignInConfig : {
527+ enabled : true ,
528+ passwordRequired : false ,
529+ } ,
530+ } ;
531+ return admin . auth ( ) . updateTenant ( createdTenantId , updatedOptions )
532+ . then ( ( actualTenant ) => {
533+ expect ( actualTenant . toJSON ( ) ) . to . deep . equal ( expectedUpdatedTenant ) ;
534+ return admin . auth ( ) . updateTenant ( createdTenantId , updatedOptions2 ) ;
535+ } )
536+ . then ( ( actualTenant ) => {
537+ expect ( actualTenant . toJSON ( ) ) . to . deep . equal ( expectedUpdatedTenant2 ) ;
538+ } ) ;
539+ } ) ;
540+
541+ it ( 'listTenants() should resolve with expected number of tenants' , ( ) => {
542+ const allTenantIds : string [ ] = [ ] ;
543+ const tenantOptions2 = deepCopy ( tenantOptions ) ;
544+ tenantOptions2 . displayName = 'testTenant2' ;
545+ const listAllTenantIds = ( tenantIds : string [ ] , nextPageToken ?: string ) : Promise < void > => {
546+ return admin . auth ( ) . listTenants ( 100 , nextPageToken )
547+ . then ( ( result ) => {
548+ result . tenants . forEach ( ( tenant ) => {
549+ tenantIds . push ( tenant . tenantId ) ;
550+ } ) ;
551+ if ( result . pageToken ) {
552+ return listAllTenantIds ( tenantIds , result . pageToken ) ;
553+ }
554+ } ) ;
555+ } ;
556+ return admin . auth ( ) . createTenant ( tenantOptions2 )
557+ . then ( ( actualTenant ) => {
558+ createdTenants . push ( actualTenant . tenantId ) ;
559+ // Test listTenants returns the expected tenants.
560+ return listAllTenantIds ( allTenantIds ) ;
561+ } )
562+ . then ( ( ) => {
563+ // All created tenants should be in the list of tenants.
564+ createdTenants . forEach ( ( tenantId ) => {
565+ expect ( allTenantIds ) . to . contain ( tenantId ) ;
566+ } ) ;
567+ } ) ;
568+ } ) ;
569+
570+ it ( 'deleteTenant() should successfully delete the provided tenant' , ( ) => {
571+ return admin . auth ( ) . deleteTenant ( createdTenantId )
572+ . then ( ( ) => {
573+ return admin . auth ( ) . getTenant ( createdTenantId ) ;
574+ } )
575+ . then ( ( result ) => {
576+ throw new Error ( 'unexpected success' ) ;
577+ } )
578+ . catch ( ( error ) => {
579+ expect ( error . code ) . to . equal ( 'auth/tenant-not-found' ) ;
580+ } ) ;
581+ } ) ;
582+ } ) ;
583+
431584 describe ( 'SAML configuration operations' , ( ) => {
432585 const authProviderConfig1 = {
433586 providerId : 'saml.' + generateRandomString ( 5 ) ,
0 commit comments