Skip to content

Commit 0182a8a

Browse files
authored
Implement firebase-functions-test wrapV2 (#131)
* Implement firebase-functions-test wrapV2 * Minor updates (per pr comments.) This commit makes some minor updates to resolve pr comments. I still need to go back and clean up the createCloudEvent usecase. Stay tuned! * Implement createMockCloudEvent for v2 wrap This commit implements the createMockCloudEvent. This simplifies the story of testing the wrapped V2 function. * Fix how V2 CloudEventSource gets populated * Fix CloudEvent.subject and CloudEvent.source * Bumped semver to 1.0.0 * Added support for eventarc custom events * Fix follow ups from PR feedback * Handle V2 function behavior within the main.ts#wrap call * Decouple wrapV1 logic from main.ts#wrap This cl decouples the implementation logic from wrapping V1 functions and places it into a separate directory. I went back and re-exported the same exports from v1 back out to main.ts to reduce disruption from existing usage. * Add in Partial Typing instead of CloudEventOverride * Fix issue with broken typing (CloudBaseEvent isn't exported) * Follow up items from PR feedback CloudEvent stuff is being decoupled shortly, stay tuned!™ * Create and Implement MockCloudEvent This commit introduces MockCloudEvent. Its very apparent the switch-case shenanigans are too brittle to handle the growing number of CloudEvents. So Instead, I'm introducing a wrapper that contains most of the implementation within `src/mock-cloud-event-partial-definitions.ts`. The wrapper uses a `match` function to see which implementation of MockCloudEventPartial to use, and then uses a `generatePartial` to get the expected Partial<CloudEvent>. This is not particularly DRY, but it seemed more useful to keep the building blocks basic rather than being too clever. I'm happy to be convinced otherwise though. I'll be breaking / updating other unit tests momentarily. * Refactor V2 wrap function This commit refactors the V2 wrap function, removing the need for the end-user to generate a mock event to pass into the function. The spec tests are still mostly useless, and we are still missing data. I wanted to finish this refactor before implementing the data potion, otherwise it would be more work to clean up. * Implemented StorageObjectData and improved typing * Introduce DeepPartial Because Partials' don't Partial down recursively. * Wire up deep merge * Implement data generation for Alerts * Fix Types for AppDistributionEvent, BillingEvent, and CrashlyticsEvent * Split the cloudevent partial definitions to different files This is a quality-of-life improvement that splits up the giant `src/mock-cloud-event-partial-definitions.ts` by event type. `src/mock-cloud-event-partial-definitions.ts` is now just `partials.ts`, and it returns a list of partials that are all definined in different files. Its not the DRYest thing in thr world... but its much more readable. * Implement mock MessagePublishedData for pubsub * Update EventArc sample CloudEvent * Updated Unit tests for PubSub data.message generation * Update returned type for `Alert.OnAlertPublished` partial * Remove `param` from default CloudEvent generation * Fix all the imports (from /lib/v2/providers -> /v2) * Fix redundant typing `<FunctionType, EventType>` -> `<EventType>` * DRY cleanup * Patch Minor lint issues * Removed hardcoded json from pubsub partial generator Removing the hardcoded json from the partial. There needs to be a better pattern. Stay tuned ™
1 parent c1dd82b commit 0182a8a

30 files changed

+9906
-351
lines changed

package-lock.json

Lines changed: 8370 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "firebase-functions-test",
3-
"version": "0.3.3",
3+
"version": "1.0.0",
44
"description": "A testing companion to firebase-functions.",
55
"main": "lib/index.js",
66
"scripts": {
@@ -39,14 +39,15 @@
3939
"homepage": "https://github.com/firebase/firebase-functions-test#readme",
4040
"dependencies": {
4141
"@types/lodash": "^4.14.104",
42-
"lodash": "^4.17.5"
42+
"lodash": "^4.17.5",
43+
"ts-deepmerge": "^2.0.1"
4344
},
4445
"devDependencies": {
4546
"@types/chai": "~4.2.4",
4647
"@types/mocha": "^5.2.7",
4748
"chai": "^4.2.0",
4849
"firebase-admin": "~8.9.0",
49-
"firebase-functions": "^3.3.0",
50+
"firebase-functions": "^3.20.1",
5051
"firebase-tools": "^8.9.2",
5152
"mocha": "^6.2.2",
5253
"prettier": "^1.19.1",
@@ -55,8 +56,8 @@
5556
"typescript": "^3.6.4"
5657
},
5758
"peerDependencies": {
58-
"firebase-functions": ">=2.0.0",
59-
"firebase-admin": ">=6.0.0"
59+
"firebase-admin": ">=6.0.0",
60+
"firebase-functions": ">=3.20.1"
6061
},
6162
"engines": {
6263
"node": ">=8.0.0"

spec/cloudevent/generate.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2018 Firebase
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
import {expect} from 'chai';
24+
25+
import {alerts, storage} from 'firebase-functions/v2';
26+
import {generateMockCloudEvent} from '../../src/cloudevent/generate';
27+
28+
describe('generate (CloudEvent)', () => {
29+
describe('#generateMockCloudEvent', () => {
30+
describe('alerts.billing.onPlanAutomatedUpdatePublished()', () => {
31+
it('should create CloudEvent with appropriate fields', () => {
32+
const cloudFn = alerts.billing.onPlanAutomatedUpdatePublished(() => {
33+
});
34+
const cloudEvent =
35+
generateMockCloudEvent(cloudFn);
36+
37+
expect(cloudEvent.type).equal(
38+
'google.firebase.firebasealerts.alerts.v1.published');
39+
expect(cloudEvent.source).equal(
40+
'//firebasealerts.googleapis.com/projects/42');
41+
expect(cloudEvent.subject).equal(undefined);
42+
});
43+
});
44+
describe('storage.onObjectArchived', () => {
45+
it('should create CloudEvent with appropriate fields', () => {
46+
const bucketName = 'bucket_name';
47+
const cloudFn = storage.onObjectArchived(bucketName, () => {
48+
});
49+
const cloudEvent =
50+
generateMockCloudEvent(cloudFn);
51+
52+
expect(cloudEvent.type).equal(
53+
'google.cloud.storage.object.v1.archived');
54+
expect(cloudEvent.source).equal(
55+
`//storage.googleapis.com/projects/_/buckets/${bucketName}`);
56+
expect(cloudEvent.subject).equal('objects/file_name');
57+
});
58+
});
59+
});
60+
});

spec/index.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ describe('index', () => {
6767

6868
import './lifecycle.spec';
6969
import './main.spec';
70+
import './v2.spec';
71+
import './cloudevent/generate';
7072
import './app.spec';
7173
import './providers/https.spec';
7274
import './providers/firestore.spec';

spec/main.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import {
3333
} from '../src/main';
3434
import { features } from '../src/features';
3535
import { FirebaseFunctionsTest } from '../src/lifecycle';
36+
import {alerts} from 'firebase-functions/v2';
37+
import {wrapV2} from '../src/v2';
3638

3739
describe('main', () => {
3840
describe('#wrap', () => {
@@ -226,6 +228,17 @@ describe('main', () => {
226228
});
227229
});
228230

231+
describe('v2 functions', () => {
232+
it('should invoke wrapV2 wrapper', () => {
233+
const handler = (cloudEvent) => ({cloudEvent});
234+
const cloudFn = alerts.billing.onPlanAutomatedUpdatePublished(handler);
235+
const cloudFnWrap = wrapV2(cloudFn);
236+
237+
const expectedType = 'google.firebase.firebasealerts.alerts.v1.published';
238+
expect(cloudFnWrap().cloudEvent).to.include({type: expectedType});
239+
});
240+
});
241+
229242
describe('callable functions', () => {
230243
let wrappedCF;
231244

0 commit comments

Comments
 (0)