2222
2323import { has , merge , random , get } from 'lodash' ;
2424
25- import { CloudFunction , EventContext , Change } from 'firebase-functions' ;
25+ import { CloudFunction , EventContext , Change , https } from 'firebase-functions' ;
2626
2727/** Fields of the event context that can be overridden/customized. */
2828export type EventContextOptions = {
@@ -33,7 +33,7 @@ export type EventContextOptions = {
3333 /** The values for the wildcards in the reference path that a database or Firestore function is listening to.
3434 * If omitted, random values will be generated.
3535 */
36- params ?: { [ option : string ] : any } ;
36+ params ?: { [ option : string ] : any } ;
3737 /** (Only for database functions and https.onCall.) Firebase auth variable representing the user that triggered
3838 * the function. Defaults to null.
3939 */
@@ -55,6 +55,11 @@ export type CallableContextOptions = {
5555 * An unverified token for a Firebase Instance ID.
5656 */
5757 instanceIdToken ?: string ;
58+
59+ /**
60+ * The raw HTTP request object.
61+ */
62+ rawRequest ?: https . Request ;
5863} ;
5964
6065/* Fields for both Event and Callable contexts, checked at runtime */
@@ -63,73 +68,90 @@ export type ContextOptions = EventContextOptions | CallableContextOptions;
6368/** A function that can be called with test data and optional override values for the event context.
6469 * It will subsequently invoke the cloud function it wraps with the provided test data and a generated event context.
6570 */
66- export type WrappedFunction = ( data : any , options ?: ContextOptions ) => any | Promise < any > ;
71+ export type WrappedFunction = (
72+ data : any ,
73+ options ?: ContextOptions ,
74+ ) => any | Promise < any > ;
6775
6876/** Takes a cloud function to be tested, and returns a WrappedFunction which can be called in test code. */
6977export function wrap < T > ( cloudFunction : CloudFunction < T > ) : WrappedFunction {
7078 if ( ! has ( cloudFunction , '__trigger' ) ) {
71- throw new Error ( 'Wrap can only be called on functions written with the firebase-functions SDK.' ) ;
79+ throw new Error (
80+ 'Wrap can only be called on functions written with the firebase-functions SDK.' ,
81+ ) ;
7282 }
7383
74- if ( has ( cloudFunction , '__trigger.httpsTrigger' ) &&
75- ( get ( cloudFunction , '__trigger.labels.deployment-callable' ) !== 'true' ) ) {
76- throw new Error ( 'Wrap function is only available for `onCall` HTTP functions, not `onRequest`.' ) ;
84+ if (
85+ has ( cloudFunction , '__trigger.httpsTrigger' ) &&
86+ get ( cloudFunction , '__trigger.labels.deployment-callable' ) !== 'true'
87+ ) {
88+ throw new Error (
89+ 'Wrap function is only available for `onCall` HTTP functions, not `onRequest`.' ,
90+ ) ;
7791 }
7892
7993 if ( ! has ( cloudFunction , 'run' ) ) {
80- throw new Error ( 'This library can only be used with functions written with firebase-functions v1.0.0 and above' ) ;
94+ throw new Error (
95+ 'This library can only be used with functions written with firebase-functions v1.0.0 and above' ,
96+ ) ;
8197 }
8298
83- const isCallableFunction = get ( cloudFunction , '__trigger.labels.deployment-callable' ) === 'true' ;
99+ const isCallableFunction =
100+ get ( cloudFunction , '__trigger.labels.deployment-callable' ) === 'true' ;
84101
85102 let wrapped : WrappedFunction = ( data : T , options : ContextOptions ) => {
86103 // Although in Typescript we require `options` some of our JS samples do not pass it.
87104 options = options || { } ;
88105 let context ;
89106
90107 if ( isCallableFunction ) {
91- _checkOptionValidity ( [ 'auth' , 'instanceIdToken' ] , options ) ;
108+ _checkOptionValidity ( [ 'auth' , 'instanceIdToken' , 'rawRequest' ] , options ) ;
92109 let callableContextOptions = options as CallableContextOptions ;
93110 context = {
94- ...callableContextOptions ,
95- rawRequest : 'rawRequest is not supported in firebase-functions-test' ,
111+ ...callableContextOptions ,
96112 } ;
97113 } else {
98- _checkOptionValidity ( [ 'eventId' , 'timestamp' , 'params' , 'auth' , 'authType' ] , options ) ;
114+ _checkOptionValidity (
115+ [ 'eventId' , 'timestamp' , 'params' , 'auth' , 'authType' ] ,
116+ options ,
117+ ) ;
99118 let eventContextOptions = options as EventContextOptions ;
100119 const defaultContext : EventContext = {
101- eventId : _makeEventId ( ) ,
102- resource : cloudFunction . __trigger . eventTrigger && {
103- service : cloudFunction . __trigger . eventTrigger . service ,
104- name : _makeResourceName (
105- cloudFunction . __trigger . eventTrigger . resource ,
106- has ( eventContextOptions , 'params' ) && eventContextOptions . params ,
107- ) ,
108- } ,
109- eventType : get ( cloudFunction , '__trigger.eventTrigger.eventType' ) ,
110- timestamp : ( new Date ( ) ) . toISOString ( ) ,
111- params : { } ,
120+ eventId : _makeEventId ( ) ,
121+ resource : cloudFunction . __trigger . eventTrigger && {
122+ service : cloudFunction . __trigger . eventTrigger . service ,
123+ name : _makeResourceName (
124+ cloudFunction . __trigger . eventTrigger . resource ,
125+ has ( eventContextOptions , 'params' ) && eventContextOptions . params ,
126+ ) ,
127+ } ,
128+ eventType : get ( cloudFunction , '__trigger.eventTrigger.eventType' ) ,
129+ timestamp : new Date ( ) . toISOString ( ) ,
130+ params : { } ,
112131 } ;
113132
114- if ( has ( defaultContext , 'eventType' ) && defaultContext . eventType !== undefined &&
115- defaultContext . eventType . match ( / f i r e b a s e .d a t a b a s e / ) ) {
133+ if (
134+ has ( defaultContext , 'eventType' ) &&
135+ defaultContext . eventType !== undefined &&
136+ defaultContext . eventType . match ( / f i r e b a s e .d a t a b a s e / )
137+ ) {
116138 defaultContext . authType = 'UNAUTHENTICATED' ;
117139 defaultContext . auth = null ;
118140 }
119141 context = merge ( { } , defaultContext , eventContextOptions ) ;
120142 }
121143
122- return cloudFunction . run (
123- data ,
124- context ,
125- ) ;
144+ return cloudFunction . run ( data , context ) ;
126145 } ;
127146
128147 return wrapped ;
129148}
130149
131150/** @internal */
132- export function _makeResourceName ( triggerResource : string , params = { } ) : string {
151+ export function _makeResourceName (
152+ triggerResource : string ,
153+ params = { } ,
154+ ) : string {
133155 const wildcardRegex = new RegExp ( '{[^/{}]*}' , 'g' ) ;
134156 let resourceName = triggerResource . replace ( wildcardRegex , ( wildcard ) => {
135157 let wildcardNoBraces = wildcard . slice ( 1 , - 1 ) ; // .slice removes '{' and '}' from wildcard
@@ -140,15 +162,27 @@ export function _makeResourceName(triggerResource: string, params = {}): string
140162}
141163
142164function _makeEventId ( ) : string {
143- return Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 ) + Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 ) ;
165+ return (
166+ Math . random ( )
167+ . toString ( 36 )
168+ . substring ( 2 , 15 ) +
169+ Math . random ( )
170+ . toString ( 36 )
171+ . substring ( 2 , 15 )
172+ ) ;
144173}
145174
146- function _checkOptionValidity ( validFields : string [ ] , options : { [ s : string ] : any } ) {
147- Object . keys ( options ) . forEach ( ( key ) => {
148- if ( validFields . indexOf ( key ) === - 1 ) {
149- throw new Error ( `Options object ${ JSON . stringify ( options ) } has invalid key "${ key } "` ) ;
150- }
151- } ) ;
175+ function _checkOptionValidity (
176+ validFields : string [ ] ,
177+ options : { [ s : string ] : any } ,
178+ ) {
179+ Object . keys ( options ) . forEach ( ( key ) => {
180+ if ( validFields . indexOf ( key ) === - 1 ) {
181+ throw new Error (
182+ `Options object ${ JSON . stringify ( options ) } has invalid key "${ key } "` ,
183+ ) ;
184+ }
185+ } ) ;
152186}
153187
154188/** Make a Change object to be used as test data for Firestore and real time database onWrite and onUpdate functions. */
0 commit comments