Skip to content

Commit ba6acb0

Browse files
authored
Merge pull request #43 from raman-nbg/messaging
2 parents 744d6b0 + 891551e commit ba6acb0

File tree

7 files changed

+585
-2
lines changed

7 files changed

+585
-2
lines changed

API.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ Only `MockFirebase` methods are included here. For details on normal Firebase AP
1919
- [Server Timestamps](#server-timestamps)
2020
- [`setClock(fn)`](#firebasesetclockfn---undefined)
2121
- [`restoreClock()`](#firebasesetclockfn---undefined)
22+
- [Messaging](#messaging)
23+
- [`respondNext(methodName, result)`](#respondnextmethodname-result---undefined)
24+
- [`failNext(methodName, err)`](#failnextmethodname-err---undefined)
25+
- [`on(methodName, callback)`](#onmethodname-callback---undefined)
2226

2327
## Core
2428

@@ -242,3 +246,31 @@ Instead of using `Date.now()`, MockFirebase will call the `fn` you provide to ge
242246
##### `Firebase.restoreClock()` -> `undefined`
243247

244248
After calling `Firebase.setClock`, calling `Firebase.restoreClock` will restore the default timestamp behavior.
249+
250+
## Messaging
251+
252+
API reference of `MockMessaging`.
253+
254+
##### `respondNext(methodName, result)` -> `undefined`
255+
256+
When `methodName` is next invoked, the `Promise` (that is returned from the `methodName`) will be resolved with the specified `result`. This is useful for testing specific results of firebase messaging (e. g. partial success of sending messaging). The result will be triggered with the next `flush`.
257+
258+
If no result is specified, `methodName` will resolve a default response.
259+
260+
`result` must not be undefined.
261+
262+
<hr>
263+
264+
##### `failNext(methodName, err)` -> `undefined`
265+
266+
When `methodName` is next invoked, the `Promise` will be rejected with the specified `err`. This is useful for simulating validation or any other errors. The error will be triggered with the next `flush`.
267+
268+
`err` must be a proper `Error` object and not a string or any other primitive.
269+
270+
<hr>
271+
272+
##### `on(methodName, callback)` -> `undefined`
273+
274+
When `methodName` is next invoked, the `callback` will be triggered. The callback gets an array as argument. The array contains all arguments, that were passed on invoking `methodName`. This is useful to assert the input arguments of `methodName`.
275+
276+
See [docs.js](/test/unit/docs.js) for an example.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## [Unreleased]
88
### Added
99
- Changelog
10+
- Support for Firebase Messaging (Admin API)
1011

1112
### Changed
1213
- `MockStorageFile.download()` now allows omitting the destination arg;

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Firebase Mock supports the client-side [JavaScript API](https://firebase.google.
3535
* Authentication
3636
* [Basic](tutorials/admin/authentication.md)
3737
* [JWT Tokens](tutorials/admin/tokens.md)
38+
* [Messaging](tutorials/admin/messaging.md)
3839
* [Realtime Database](tutorials/admin/rtdb.md)
3940
* [Firestore](tutorials/admin/firestore.md)
4041
* [Storage](tutorials/admin/storage.md)

src/messaging.js

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,141 @@
1+
/*
2+
Mock for admin.messaging.Messaging
3+
https://firebase.google.com/docs/reference/admin/node/admin.messaging
4+
*/
15
'use strict';
6+
var _ = require('./lodash');
7+
var assert = require('assert');
8+
var Promise = require('rsvp').Promise;
9+
var autoId = require('firebase-auto-ids');
10+
var Queue = require('./queue').Queue;
211

312
function MockMessaging() {
13+
this.results = {};
14+
this.callbacks = {};
15+
this.queue = new Queue();
16+
this.flushDelay = false;
417
}
518

19+
// https://firebase.google.com/docs/reference/admin/node/admin.messaging.Messaging.html#send
20+
MockMessaging.prototype.send = function(message, dryRun) {
21+
assert(!_.isUndefined(message), 'message must not be undefined');
22+
return this._send(_.toArray(arguments), 'send', function() {
23+
var messageId = autoId(new Date().getTime());
24+
return messageId;
25+
});
26+
};
27+
28+
// https://firebase.google.com/docs/reference/admin/node/admin.messaging.Messaging.html#send-all
29+
MockMessaging.prototype.sendAll = function(messages, dryRun) {
30+
assert(Array.isArray(messages), 'messages must be an "Array"');
31+
var self = this;
32+
return this._send(_.toArray(arguments), 'sendAll', function() {
33+
return self._mapMessagesToBatchResponse(messages);
34+
});
35+
};
36+
37+
// https://firebase.google.com/docs/reference/admin/node/admin.messaging.Messaging.html#send-multicast
38+
MockMessaging.prototype.sendMulticast = function(multicastMessage, dryRun) {
39+
assert(!_.isUndefined(multicastMessage), 'multicastMessage must not be undefined');
40+
assert(Array.isArray(multicastMessage.tokens));
41+
var self = this;
42+
return this._send(_.toArray(arguments), 'sendMulticast', function() {
43+
return self._mapMessagesToBatchResponse(multicastMessage.tokens);
44+
});
45+
};
46+
47+
MockMessaging.prototype.flush = function(delay) {
48+
this.queue.flush(delay);
49+
return this;
50+
};
51+
52+
MockMessaging.prototype.autoFlush = function (delay) {
53+
if (_.isUndefined(delay)) {
54+
delay = true;
55+
}
56+
57+
this.flushDelay = delay;
58+
59+
return this;
60+
};
61+
62+
MockMessaging.prototype.failNext = function(methodName, err) {
63+
assert(_.isString(methodName), 'methodName must be a string');
64+
assert(err instanceof Error, 'err must be an "Error" object');
65+
this.results[methodName] = err;
66+
};
67+
68+
MockMessaging.prototype.respondNext = function(methodName, result) {
69+
assert(_.isString(methodName), 'methodName must be a string');
70+
assert(!_.isUndefined(result), 'result must not be undefined');
71+
assert(!(result instanceof Error), 'result must not be an "Error" object');
72+
this.results[methodName] = result;
73+
};
74+
75+
MockMessaging.prototype.on = function(methodName, callback) {
76+
assert(_.isString(methodName), 'methodName must be a string');
77+
assert(_.isFunction(callback), 'callback must be a function');
78+
this.callbacks[methodName] = callback;
79+
};
80+
81+
MockMessaging.prototype._send = function(args, methodName, defaultResultFn) {
82+
var result = this._nextResult(methodName);
83+
var self = this;
84+
return new Promise(function (resolve, reject) {
85+
self._defer(methodName, args, function () {
86+
self._invokeOn(methodName, args);
87+
88+
if (result === null) {
89+
resolve(defaultResultFn());
90+
} else if (result instanceof Error) {
91+
reject(result);
92+
} else {
93+
resolve(result);
94+
}
95+
});
96+
});
97+
};
98+
99+
MockMessaging.prototype._invokeOn = function(methodName, args) {
100+
var callback = this.callbacks[methodName];
101+
if (callback) {
102+
callback(args);
103+
}
104+
};
105+
106+
MockMessaging.prototype._nextResult = function(type) {
107+
var result = this.results[type];
108+
delete this.results[type];
109+
return result || null;
110+
};
111+
112+
MockMessaging.prototype._defer = function(sourceMethod, sourceArgs, callback) {
113+
this.queue.push({
114+
fn: callback,
115+
context: this,
116+
sourceData: {
117+
ref: this,
118+
method: sourceMethod,
119+
args: sourceArgs
120+
}
121+
});
122+
if (this.flushDelay !== false) {
123+
this.flush(this.flushDelay);
124+
}
125+
};
126+
127+
MockMessaging.prototype._mapMessagesToBatchResponse = function(messages) {
128+
return {
129+
failureCount: 0,
130+
successCount: messages.length,
131+
responses: messages.map(function(message) {
132+
return {
133+
error: undefined,
134+
messageId: autoId(new Date().getTime()),
135+
success: true,
136+
};
137+
})
138+
};
139+
};
140+
6141
module.exports = MockMessaging;

test/unit/docs.js

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
const MockUser = require('../../src/user');
1+
'use strict';
2+
3+
/* jshint browser:true */
4+
/* globals expect:false */
25

36
describe('API.md', () => {
47
describe('Auth example for changeAuthState', () => {
58

69
let ref;
710
beforeEach(() => {
8-
const Authentication = require('../../').MockAuthentication;
11+
const Authentication = require('../../src').MockAuthentication;
912
ref = new Authentication();
1013
});
1114

1215
it('works as described', () => {
16+
const MockUser = require('../../src/user');
1317
ref.changeAuthState(new MockUser(ref, {
1418
uid: 'theUid',
1519
@@ -37,4 +41,78 @@ describe('API.md', () => {
3741
console.assert(ref.getAuth().displayName === 'Mr. Meeseeks', 'Auth name is correct');
3842
});
3943
});
44+
45+
describe('Messaging examples', () => {
46+
let mockMessaging;
47+
48+
beforeEach(() => {
49+
const Messaging = require('../../').MockMessaging;
50+
mockMessaging = new Messaging();
51+
});
52+
53+
it('send messages', () => {
54+
var message = {
55+
notification: {
56+
title: 'message title',
57+
body: 'foobar'
58+
}
59+
};
60+
var result = mockMessaging.send(message);
61+
mockMessaging.flush();
62+
result.then(function (messageId) {
63+
console.assert(messageId !== '', 'message id is ' + messageId);
64+
});
65+
});
66+
67+
it('returns custom message responses', () => {
68+
var messages = [
69+
{
70+
notification: {
71+
title: 'message title',
72+
body: 'foobar'
73+
}
74+
},
75+
{
76+
notification: {
77+
title: 'message title',
78+
body: 'second message'
79+
}
80+
}
81+
];
82+
var batchResponse = {
83+
failureCount: 1,
84+
responses: [
85+
{
86+
error: "something went wrong",
87+
success: false,
88+
},
89+
{
90+
messageId: "12345",
91+
success: true,
92+
},
93+
],
94+
successCount: 1,
95+
};
96+
mockMessaging.respondNext('sendAll', batchResponse);
97+
var result = mockMessaging.sendAll(messages);
98+
mockMessaging.flush();
99+
result.then(function (response) {
100+
console.assert(response === batchResponse, 'custom batch response is returned');
101+
});
102+
});
103+
104+
it('callback on sending messages', () => {
105+
var message = {
106+
notification: {
107+
title: 'message title',
108+
body: 'foobar'
109+
}
110+
};
111+
mockMessaging.on('send', function(args) {
112+
console.assert(args[0] === message, 'message argument is correct');
113+
});
114+
mockMessaging.send(message);
115+
mockMessaging.flush();
116+
});
117+
});
40118
});

0 commit comments

Comments
 (0)