Skip to content

Commit a01ce37

Browse files
committed
Try to extract context.params from triggered data
1 parent 84a50c2 commit a01ce37

File tree

2 files changed

+267
-113
lines changed

2 files changed

+267
-113
lines changed

spec/main.spec.ts

Lines changed: 172 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -24,140 +24,192 @@ import { expect } from 'chai';
2424
import * as functions from 'firebase-functions';
2525
import { set } from 'lodash';
2626

27-
import { mockConfig, makeChange, _makeResourceName, wrap } from '../src/main';
27+
import {
28+
mockConfig,
29+
makeChange,
30+
_makeResourceName,
31+
_extractParams,
32+
wrap,
33+
} from '../src/main';
34+
import { features } from '../src/features';
35+
import { FirebaseFunctionsTest } from '../src/lifecycle';
2836

2937
describe('main', () => {
3038
describe('#wrap', () => {
31-
describe('background functions', () => {
32-
const constructBackgroundCF = (eventType?: string) => {
33-
const cloudFunction = (input) => input;
34-
set(cloudFunction, 'run', (data, context) => {
35-
return { data, context };
36-
});
37-
set(cloudFunction, '__trigger', {
38-
eventTrigger: {
39-
resource: 'ref/{wildcard}/nested/{anotherWildcard}',
40-
eventType: eventType || 'event',
41-
service: 'service',
42-
},
43-
});
44-
return cloudFunction as functions.CloudFunction<any>;
45-
};
46-
47-
it('should invoke the function with the supplied data', () => {
48-
const wrapped = wrap(constructBackgroundCF());
49-
expect(wrapped('data').data).to.equal('data');
39+
const constructCF = (eventType?: string) => {
40+
const cloudFunction = (input) => input;
41+
set(cloudFunction, 'run', (data, context) => {
42+
return { data, context };
43+
});
44+
set(cloudFunction, '__trigger', {
45+
eventTrigger: {
46+
resource: 'ref/{wildcard}/nested/{anotherWildcard}',
47+
eventType: eventType || 'event',
48+
service: 'service',
49+
},
5050
});
51+
return cloudFunction as functions.CloudFunction<any>;
52+
};
53+
54+
it('should invoke the function with the supplied data', () => {
55+
const wrapped = wrap(constructCF());
56+
expect(wrapped('data').data).to.equal('data');
57+
});
58+
59+
it('should generate the appropriate context if no fields specified', () => {
60+
const context = wrap(constructCF())('data').context;
61+
expect(typeof context.eventId).to.equal('string');
62+
expect(context.resource.service).to.equal('service');
63+
expect(
64+
/ref\/wildcard[1-9]\/nested\/anotherWildcard[1-9]/.test(
65+
context.resource.name
66+
)
67+
).to.be.true;
68+
expect(context.eventType).to.equal('event');
69+
expect(Date.parse(context.timestamp)).to.be.greaterThan(0);
70+
expect(context.params).to.deep.equal({});
71+
expect(context.auth).to.be.undefined;
72+
expect(context.authType).to.be.undefined;
73+
});
74+
75+
it('should allow specification of context fields', () => {
76+
const wrapped = wrap(constructCF());
77+
const context = wrapped('data', {
78+
eventId: '111',
79+
timestamp: '2018-03-28T18:58:50.370Z',
80+
}).context;
81+
expect(context.eventId).to.equal('111');
82+
expect(context.timestamp).to.equal('2018-03-28T18:58:50.370Z');
83+
});
84+
85+
describe('database functions', () => {
86+
let test;
87+
let change;
5188

52-
it('should generate the appropriate context if no fields specified', () => {
53-
const context = wrap(constructBackgroundCF())('data').context;
54-
expect(typeof context.eventId).to.equal('string');
55-
expect(context.resource.service).to.equal('service');
56-
expect(
57-
/ref\/wildcard[1-9]\/nested\/anotherWildcard[1-9]/.test(
58-
context.resource.name
59-
)
60-
).to.be.true;
61-
expect(context.eventType).to.equal('event');
62-
expect(Date.parse(context.timestamp)).to.be.greaterThan(0);
63-
expect(context.params).to.deep.equal({});
64-
expect(context.auth).to.be.undefined;
65-
expect(context.authType).to.be.undefined;
89+
beforeEach(() => {
90+
test = new FirebaseFunctionsTest();
91+
test.init();
92+
change = features.database.exampleDataSnapshotChange();
6693
});
6794

68-
it('should allow specification of context fields', () => {
69-
const wrapped = wrap(constructBackgroundCF());
70-
const context = wrapped('data', {
71-
eventId: '111',
72-
timestamp: '2018-03-28T18:58:50.370Z',
73-
}).context;
74-
expect(context.eventId).to.equal('111');
75-
expect(context.timestamp).to.equal('2018-03-28T18:58:50.370Z');
95+
afterEach(() => {
96+
test.cleanup();
7697
});
7798

78-
it('should generate auth and authType for database functions', () => {
79-
const context = wrap(constructBackgroundCF('google.firebase.database.ref.write'))(
80-
'data'
81-
).context;
99+
it('should generate auth and authType', () => {
100+
const wrapped = wrap(constructCF('google.firebase.database.ref.write'));
101+
const context = wrapped(change).context;
82102
expect(context.auth).to.equal(null);
83103
expect(context.authType).to.equal('UNAUTHENTICATED');
84104
});
85105

86-
it('should allow auth and authType to be specified for database functions', () => {
87-
const wrapped = wrap(constructBackgroundCF('google.firebase.database.ref.write'));
88-
const context = wrapped('data', {
106+
it('should allow auth and authType to be specified', () => {
107+
const wrapped = wrap(constructCF('google.firebase.database.ref.write'));
108+
const context = wrapped(change, {
89109
auth: { uid: 'abc' },
90110
authType: 'USER',
91111
}).context;
92112
expect(context.auth).to.deep.equal({ uid: 'abc' });
93113
expect(context.authType).to.equal('USER');
94114
});
115+
});
95116

96-
it('should throw when passed invalid options', () => {
97-
const wrapped = wrap(constructBackgroundCF());
98-
expect(() =>
99-
wrapped('data', {
100-
auth: { uid: 'abc' },
101-
isInvalid: true,
102-
} as any)
103-
).to.throw();
104-
});
117+
it('should throw when passed invalid options', () => {
118+
const wrapped = wrap(constructCF());
119+
expect(() =>
120+
wrapped('data', {
121+
auth: { uid: 'abc' },
122+
isInvalid: true,
123+
} as any)
124+
).to.throw();
125+
});
105126

106-
it('should generate the appropriate resource based on params', () => {
107-
const params = {
108-
wildcard: 'a',
109-
anotherWildcard: 'b',
110-
};
111-
const wrapped = wrap(constructBackgroundCF());
112-
const context = wrapped('data', { params }).context;
113-
expect(context.params).to.deep.equal(params);
114-
expect(context.resource.name).to.equal('ref/a/nested/b');
115-
});
127+
it('should generate the appropriate resource based on params', () => {
128+
const params = {
129+
wildcard: 'a',
130+
anotherWildcard: 'b',
131+
};
132+
const wrapped = wrap(constructCF());
133+
const context = wrapped('data', { params }).context;
134+
expect(context.params).to.deep.equal(params);
135+
expect(context.resource.name).to.equal('ref/a/nested/b');
116136
});
117137

118-
describe('callable functions', () => {
119-
let wrappedCF;
138+
describe('Params extraction', () => {
139+
let test;
120140

121-
before(() => {
122-
const cloudFunction = (input) => input;
123-
set(cloudFunction, 'run', (data, context) => {
124-
return { data, context };
125-
});
126-
set(cloudFunction, '__trigger', {
127-
labels: {
128-
'deployment-callable': 'true',
129-
},
130-
httpsTrigger: {},
131-
});
132-
wrappedCF = wrap(cloudFunction as functions.CloudFunction<any>);
141+
beforeEach(() => {
142+
test = new FirebaseFunctionsTest();
143+
test.init();
133144
});
134145

135-
it('should invoke the function with the supplied data', () => {
136-
expect(wrappedCF('data').data).to.equal('data');
146+
afterEach(() => {
147+
test.cleanup();
137148
});
138149

139-
it('should allow specification of context fields', () => {
140-
const context = wrappedCF('data', {
141-
auth: { uid: 'abc' },
142-
app: { appId: 'efg' },
143-
instanceIdToken: '123',
144-
rawRequest: { body: 'hello' }
145-
}).context;
146-
expect(context.auth).to.deep.equal({ uid: 'abc' });
147-
expect(context.app).to.deep.equal({ appId: 'efg' });
148-
expect(context.instanceIdToken).to.equal('123');
149-
expect(context.rawRequest).to.deep.equal({ body: 'hello'});
150+
it('should extract the appropriate params for database function trigger', () => {
151+
const cf = constructCF('google.firebase.database.ref.create');
152+
cf.__trigger.eventTrigger.resource = 'companies/{company}/users/{user}';
153+
const wrapped = wrap(cf);
154+
const context = wrapped(
155+
features.database.makeDataSnapshot(
156+
{ foo: 'bar' },
157+
'companies/Google/users/Lauren'
158+
)
159+
).context;
160+
expect(context.params).to.deep.equal({
161+
company: 'Google',
162+
user: 'Lauren',
163+
});
164+
expect(context.resource.name).to.equal('companies/Google/users/Lauren');
150165
});
151166

152-
it('should throw when passed invalid options', () => {
153-
expect(() =>
154-
wrappedCF('data', {
155-
auth: { uid: 'abc' },
156-
isInvalid: true,
157-
} as any)
158-
).to.throw();
167+
it('should extract the appropriate params for Firestore function trigger', () => {
168+
const cf = constructCF('google.firestore.document.create');
169+
cf.__trigger.eventTrigger.resource =
170+
'databases/(default)/documents/companies/{company}/users/{user}';
171+
const wrapped = wrap(cf);
172+
const context = wrapped(
173+
features.firestore.makeDocumentSnapshot(
174+
{ foo: 'bar' },
175+
'companies/Google/users/Lauren'
176+
)
177+
).context;
178+
expect(context.params).to.deep.equal({
179+
company: 'Google',
180+
user: 'Lauren',
181+
});
182+
expect(context.resource.name).to.equal(
183+
'databases/(default)/documents/companies/Google/users/Lauren'
184+
);
159185
});
160186

187+
it('should prefer provided context.params over the extracted params', () => {
188+
const cf = constructCF('google.firebase.database.ref.create');
189+
cf.__trigger.eventTrigger.resource = 'companies/{company}/users/{user}';
190+
const wrapped = wrap(cf);
191+
const context = wrapped(
192+
features.database.makeDataSnapshot(
193+
{ foo: 'bar' },
194+
'companies/Google/users/Lauren'
195+
),
196+
{
197+
params: {
198+
company: 'Alphabet',
199+
user: 'Lauren',
200+
foo: 'bar',
201+
},
202+
}
203+
).context;
204+
expect(context.params).to.deep.equal({
205+
company: 'Alphabet',
206+
user: 'Lauren',
207+
foo: 'bar',
208+
});
209+
expect(context.resource.name).to.equal(
210+
'companies/Alphabet/users/Lauren'
211+
);
212+
});
161213
});
162214
});
163215

@@ -171,6 +223,24 @@ describe('main', () => {
171223
});
172224
});
173225

226+
describe('#_extractParams', () => {
227+
it('should not extract any params', () => {
228+
const params = _extractParams('users/foo', 'users/foo');
229+
expect(params).to.deep.equal({});
230+
});
231+
232+
it('should extract params', () => {
233+
const params = _extractParams(
234+
'companies/{company}/users/{user}',
235+
'companies/Google/users/Lauren'
236+
);
237+
expect(params).to.deep.equal({
238+
company: 'Google',
239+
user: 'Lauren',
240+
});
241+
});
242+
});
243+
174244
describe('#makeChange', () => {
175245
it('should make a Change object with the correct before and after', () => {
176246
const change = makeChange('before', 'after');

0 commit comments

Comments
 (0)