Skip to content

Commit eeeaffd

Browse files
author
Lauren Long
committed
Edit example and add necessary snippets
Change-Id: I06416465bcaafd58d942ac150da0444479a71386
1 parent 6e64e34 commit eeeaffd

File tree

4 files changed

+41
-46
lines changed

4 files changed

+41
-46
lines changed

quickstarts/uppercase/README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ This sample app does two things:
99
- Create messages in the Firebase Realtime Database using a simple HTTPS request which is handled by an HTTPS Firebase Function. Writing to the Realtime Database is done using the Firebase Admin SDK.
1010
- When a message gets added in the Realtime Database, a Firebase Function triggers and automatically makes these messages all uppercase.
1111

12-
## Deploy and test
12+
## Deploy and try out
1313

14-
To deploy and test the sample:
14+
To deploy and try out the sample:
1515

1616
- Create a Firebase project on the [Firebase Console](https://console.firebase.google.com)
1717
- Install the required dependencies by running `npm install` in the `functions` directory
@@ -20,8 +20,20 @@ To deploy and test the sample:
2020

2121
The function executes and redirects the browser to the Firebase console at the database location where the text string was stored. You should see your text value displayed in the console and uppercase.
2222

23+
## Run unit tests
2324

25+
The test folder has unit tests written with `firebase-functions-test`. There are 2 sets of tests: online and offline.
2426

27+
To run the offline tests: run `npm test` inside the functions folder.
28+
29+
To run the online tests:
30+
- Replace the `projectConfig` variable in `test/test.online.js` with configuration values from your project.
31+
- Download a service account key by following these instructions:
32+
..* Open the Service Accounts pane of the Google Cloud Console.
33+
..* Select the App Engine default service account, and use the options menu at right to select Create key.
34+
..* When prompted, select JSON for the key type, and click Create.
35+
- Save the file in the test folder, and name it `service-account-key.json`
36+
- Run `npm run test-online` inside the functions folder.
2537

2638
## Contributing
2739

quickstarts/uppercase/functions/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
},
1616
"scripts": {
1717
"ci-test": "npm install && npm run test",
18-
"test-online": "./node_modules/.bin/mocha --reporter spec test/test.online.js --exit",
19-
"test-offline": "./node_modules/.bin/mocha --reporter spec test/test.offline.js --exit",
18+
"test": "npm run test-offline",
19+
"test-online": "mocha --reporter spec test/test.online.js --exit",
20+
"test-offline": "mocha --reporter spec test/test.offline.js --exit",
2021
"serve": "firebase serve --only functions",
2122
"shell": "firebase experimental:functions:shell",
2223
"start": "npm run shell",

quickstarts/uppercase/functions/test/test.offline.js

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@
2020
const chai = require('chai');
2121
const assert = chai.assert;
2222

23-
// Chai As Promised extends Chai so that a test function can be asynchronous with promises instead
24-
// of using callbacks. It is recommended when testing Cloud Functions for Firebase due to its heavy
25-
// use of Promises.
26-
const chaiAsPromised = require("chai-as-promised");
27-
chai.use(chaiAsPromised);
28-
2923
// Sinon is a library used for mocking or verifying function calls in JavaScript.
3024
const sinon = require('sinon');
3125

@@ -40,37 +34,37 @@ describe('Cloud Functions', () => {
4034
var myFunctions, adminInitStub;
4135

4236
before(() => {
43-
// Since index.js calls admin.initializeApp at the top of the file,
37+
// [START stubAdminInit]
38+
// If index.js calls admin.initializeApp at the top of the file,
4439
// we need to stub it out before requiring index.js. This is because the
4540
// functions will be executed as a part of the require process.
4641
// Here we stub admin.initializeApp to be a dummy function that doesn't do anything.
4742
adminInitStub = sinon.stub(admin, 'initializeApp');
4843
// Now we can require index.js and save the exports inside a namespace called myFunctions.
49-
// This includes our cloud functions, which can now be accessed at myFunctions.makeUppercase
50-
// and myFunctions.addMessage
5144
myFunctions = require('../index');
45+
// [END stubAdminInit]
5246
});
5347

5448
after(() => {
5549
// Restore admin.initializeApp() to its original method.
5650
adminInitStub.restore();
5751
// Do other cleanup tasks.
58-
test.cleanUp();
52+
test.cleanup();
5953
});
6054

6155
describe('makeUpperCase', () => {
62-
// Test Case: setting messages/11111/original to 'input' should cause 'INPUT' to be written to
63-
// messages/11111/uppercase
56+
// Test Case: setting messages/{pushId}/original to 'input' should cause 'INPUT' to be written to
57+
// messages/{pushId}/uppercase
6458
it('should upper case input and write it to /uppercase', () => {
65-
66-
// [START stubDataRef]
59+
// [START assertOffline]
6760
const childParam = 'uppercase';
6861
const setParam = 'INPUT';
6962
// Stubs are objects that fake and/or record function calls.
7063
// These are excellent for verifying that functions have been called and to validate the
7164
// parameters passed to those functions.
7265
const childStub = sinon.stub();
7366
const setStub = sinon.stub();
67+
// [START fakeSnap]
7468
// The following lines creates a fake snapshot, 'snap', which returns 'input' when snap.val() is called,
7569
// and returns true when snap.ref.parent.child('uppercase').set('INPUT') is called.
7670
const snap = {
@@ -83,15 +77,13 @@ describe('Cloud Functions', () => {
8377
};
8478
childStub.withArgs(childParam).returns( { set: setStub });
8579
setStub.withArgs(setParam).returns(true);
86-
// [END stubDataRef]
87-
88-
// [START verifyDataWrite]
89-
// TODO
80+
// [END fakeSnap]
81+
// Wrap the makeUppercase function.
9082
const wrapped = test.wrap(myFunctions.makeUppercase);
9183
// Since we've stubbed snap.ref.parent.child(childParam).set(setParam) to return true if it was
9284
// called with the parameters we expect, we assert that it indeed returned true.
9385
return assert.equal(wrapped(snap), true);
94-
// [END verifyDataWrite]
86+
// [END assertOffline]
9587
})
9688
});
9789

@@ -108,15 +100,13 @@ describe('Cloud Functions', () => {
108100
});
109101

110102
it('should return a 303 redirect', (done) => {
111-
112-
// [START stubAdminDatabase]
113103
const refParam = '/messages';
114104
const pushParam = { original: 'input' };
115105
const databaseStub = sinon.stub();
116106
const refStub = sinon.stub();
117107
const pushStub = sinon.stub();
118108

119-
// The following 4 lines override the behavior of admin.database().ref('/messages')
109+
// The following lines override the behavior of admin.database().ref('/messages')
120110
// .push({ original: 'input' }) to return a promise that resolves with { ref: 'new_ref' }.
121111
// This mimics the behavior of a push to the database, which returns an object containing a
122112
// ref property representing the URL of the newly pushed item.
@@ -126,9 +116,7 @@ describe('Cloud Functions', () => {
126116
refStub.withArgs(refParam).returns({ push: pushStub });
127117
pushStub.withArgs(pushParam).returns(Promise.resolve({ ref: 'new_ref' }));
128118

129-
// [END stubAdminDatabase]
130-
131-
// [START invokeHTTPS]
119+
// [START assertHTTP]
132120
// A fake request object, with req.query.text set to 'input'
133121
const req = { query: {text: 'input'} };
134122
// A fake response object, with a stubbed redirect function which asserts that it is called
@@ -144,7 +132,7 @@ describe('Cloud Functions', () => {
144132
// Invoke addMessage with our fake request and response objects. This will cause the
145133
// assertions in the response object to be evaluated.
146134
myFunctions.addMessage(req, res);
147-
// [END invokeHTTPS]
135+
// [END assertHTTP]
148136
});
149137
});
150138
})

quickstarts/uppercase/functions/test/test.online.js

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,23 @@
1414
* limitations under the License.
1515
*/
1616

17-
// You can run these unit tests by running "npm test" inside the uppercase/functions directory.
17+
// Follow the instructions in uppercase/README.md for running these tests
1818

1919
// Chai is a commonly used library for creating unit test suites. It is easily extended with plugins.
2020
const chai = require('chai');
2121
const assert = chai.assert;
2222

23-
// Chai As Promised extends Chai so that a test function can be asynchronous with promises instead
24-
// of using callbacks. It is recommended when testing Cloud Functions for Firebase due to its heavy
25-
// use of Promises.
26-
const chaiAsPromised = require("chai-as-promised");
27-
chai.use(chaiAsPromised);
28-
2923
// Sinon is a library used for mocking or verifying function calls in JavaScript.
3024
const sinon = require('sinon');
3125

3226
const admin = require('firebase-admin');
33-
// Require and initialize firebase-functions-test with your project's credentials and service account key.
34-
const test = require('firebase-functions-test')({
27+
// Require and initialize firebase-functions-test in "online mode" with your project's
28+
// credentials and service account key.
29+
const projectConfig = {
3530
projectId: 'my-project',
3631
databaseURL: 'https://my-project.firebaseio.com'
37-
}, './service-account-key.json');
32+
};
33+
const test = require('firebase-functions-test')(projectConfig, './service-account-key.json');
3834

3935
describe('Cloud Functions', () => {
4036
var myFunctions;
@@ -48,7 +44,7 @@ describe('Cloud Functions', () => {
4844

4945
after(() => {
5046
// Do cleanup tasks.
51-
test.cleanUp();
47+
test.cleanup();
5248
// Reset the database.
5349
admin.database().ref('messages').remove();
5450
});
@@ -57,10 +53,10 @@ describe('Cloud Functions', () => {
5753
// Test Case: setting messages/11111/original to 'input' should cause 'INPUT' to be written to
5854
// messages/11111/uppercase
5955
it('should upper case input and write it to /uppercase', () => {
56+
// [START assertOnline]
6057
// Create a DataSnapshot with the value 'input' and the reference path 'messages/11111/original'.
6158
const snap = test.database.makeDataSnapshot('input', 'messages/11111/original');
6259

63-
// [START verifyDataWrite]
6460
// Wrap the makeUppercase function
6561
const wrapped = test.wrap(myFunctions.makeUppercase);
6662
// Call the wrapped function with the snapshot you constructed.
@@ -73,13 +69,12 @@ describe('Cloud Functions', () => {
7369
assert.equal(createdSnap.val(), 'INPUT');
7470
});
7571
});
76-
// [END verifyDataWrite]
72+
// [END assertOnline]
7773
})
7874
});
7975

8076
describe('addMessage', () => {
8177
it('should return a 303 redirect', (done) => {
82-
// [START invokeHTTPS]
8378
// A fake request object, with req.query.text set to 'input'
8479
const req = { query: {text: 'input'} };
8580
// A fake response object, with a stubbed redirect function which does some assertions
@@ -88,7 +83,7 @@ describe('Cloud Functions', () => {
8883
// Assert code is 303
8984
assert.equal(code, 303);
9085
// If the database push is successful, then the URL sent back will have the following format:
91-
var expectedRef = new RegExp('https://ll-firestore-dev.firebaseio.com/messages/');
86+
var expectedRef = new RegExp(projectConfig.databaseURL + '/messages/');
9287
assert.isTrue(expectedRef.test(url));
9388
done();
9489
}
@@ -97,7 +92,6 @@ describe('Cloud Functions', () => {
9792
// Invoke addMessage with our fake request and response objects. This will cause the
9893
// assertions in the response object to be evaluated.
9994
myFunctions.addMessage(req, res);
100-
// [END invokeHTTPS]
10195
});
10296
});
10397
})

0 commit comments

Comments
 (0)