Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
54 changes: 32 additions & 22 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
},
"homepage": "https://github.com/firebase/firebase-functions-test#readme",
"dependencies": {
"@types/lodash": "^4.14.202",
"lodash": "^4.17.21",
"ts-deepmerge": "^8.0.0"
},
"devDependencies": {
Expand All @@ -53,7 +51,7 @@
"eslint": "^8.57.1",
"eslint-config-prettier": "^10.1.8",
"firebase-admin": "^12.0.0",
"firebase-functions": "^4.9.0",
"firebase-functions": "^7.3.0",
"firebase-tools": "^13.15.4",
"mocha": "^11.7.6",
"prettier": "^2.8.8",
Expand Down
34 changes: 16 additions & 18 deletions spec/main.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@

import { expect } from 'chai';
import * as functions from 'firebase-functions/v1';
import { set } from 'lodash';

import { mockConfig, makeChange, wrap } from '../src/main';
import { _makeResourceName, _extractParams } from '../src/v1';
import { features } from '../src/features';
Expand All @@ -36,18 +34,18 @@ describe('main', () => {
describe('background functions', () => {
const constructBackgroundCF = (eventType?: string) => {
const cloudFunction = (input) => input;
set(cloudFunction, 'run', (data, context) => {
(cloudFunction as any).run = (data, context) => {
return { data, context };
});
set(cloudFunction, '__endpoint', {
};
(cloudFunction as any).__endpoint = {
eventTrigger: {
eventFilters: {
resource: 'ref/{wildcard}/nested/{anotherWildcard}',
},
eventType: eventType || 'event',
retry: false,
},
});
};
return cloudFunction as functions.CloudFunction<any>;
};

Expand Down Expand Up @@ -244,12 +242,12 @@ describe('main', () => {

before(() => {
const cloudFunction = (input) => input;
set(cloudFunction, 'run', (data, context) => {
(cloudFunction as any).run = (data, context) => {
return { data, context };
});
set(cloudFunction, '__endpoint', {
};
(cloudFunction as any).__endpoint = {
callableTrigger: {},
});
};
wrappedCF = wrap(cloudFunction as functions.CloudFunction<any>);
});

Expand Down Expand Up @@ -329,17 +327,17 @@ describe('main', () => {
delete process.env.CLOUD_RUNTIME_CONFIG;
});

it('should mock functions.config()', () => {
it('should set CLOUD_RUNTIME_CONFIG', () => {
mockConfig(config);
expect(functions.config()).to.deep.equal(config);
expect(JSON.parse(process.env.CLOUD_RUNTIME_CONFIG!)).to.deep.equal(
config
);
});

it('should purge singleton config object when it is present', () => {
mockConfig(config);
config.foo = { baz: 'qux' };
mockConfig(config);

expect(functions.config()).to.deep.equal(config);
it('should throw because functions.config() is removed in v7', () => {
expect(() => (functions as any).config()).to.throw(
'functions.config() has been removed in firebase-functions v7'
);
});
});
});
2 changes: 1 addition & 1 deletion spec/providers/firestore.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from 'chai';
import * as firebase from 'firebase-admin';
import * as sinon from 'sinon';
import * as http from 'http';
import http = require('http');
import { FeaturesList } from '../../src/features';
import fft = require('../../src/index');

Expand Down
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
// SOFTWARE.

import { AppOptions } from 'firebase-admin';
import { merge } from 'lodash';

import { FirebaseFunctionsTest } from './lifecycle';
import { FeaturesList } from './features';
Expand All @@ -35,8 +34,9 @@ export = (
// Ensure other files get loaded after init function, since they load `firebase-functions`
// which will issue warning if process.env.FIREBASE_CONFIG is not yet set.
let features = require('./features').features;
features = merge({}, features, {
features = {
...features,
cleanup: () => test.cleanup(),
});
};
return features;
};
8 changes: 3 additions & 5 deletions src/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { isEmpty } from 'lodash';
import { AppOptions } from 'firebase-admin';
import { forEach } from 'lodash';

import { testApp } from './app';

Expand Down Expand Up @@ -53,7 +51,7 @@ export class FirebaseFunctionsTest {
CLOUD_RUNTIME_CONFIG: process.env.CLOUD_RUNTIME_CONFIG,
};

if (isEmpty(firebaseConfig)) {
if (!firebaseConfig || Object.keys(firebaseConfig).length === 0) {
process.env.FIREBASE_CONFIG = JSON.stringify({
databaseURL: 'https://not-a-project.firebaseio.com',
storageBucket: 'not-a-project.appspot.com',
Expand All @@ -72,13 +70,13 @@ export class FirebaseFunctionsTest {

/** Complete clean up tasks. */
cleanup() {
forEach(this._oldEnv, (val, varName) => {
for (const [varName, val] of Object.entries(this._oldEnv)) {
if (typeof val !== 'undefined') {
process.env[varName] = val;
} else {
delete process.env[varName];
}
});
}
testApp().deleteApp();
}
}
58 changes: 40 additions & 18 deletions src/providers/firestore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,25 @@

import { Change } from 'firebase-functions/v1';
import { firestore, app } from 'firebase-admin';
import { has, get, isEmpty, isPlainObject, mapValues } from 'lodash';
import { inspect } from 'util';

function isPlainObject(value: any): boolean {
if (typeof value !== 'object' || value === null) {
return false;
}
const proto = Object.getPrototypeOf(value);
return proto === null || proto === Object.prototype;
}
Comment thread
inlined marked this conversation as resolved.

function mapValues<T, U>(
obj: Record<string, T>,
fn: (val: T) => U
): Record<string, U> {
const res: Record<string, U> = {};
for (const [key, val] of Object.entries(obj)) {
res[key] = fn(val);
}
return res;
}
Comment thread
inlined marked this conversation as resolved.

import { testApp } from '../app';

Expand Down Expand Up @@ -85,21 +102,22 @@ export function makeDocumentSnapshot(
}

const resource = `projects/${project}/databases/(default)/documents/${refPath}`;
const proto = isEmpty(data)
? resource
: {
fields: objectToValueProto(data),
createTime: dateToTimestampProto(
get(options, 'createTime', new Date().toISOString())
),
updateTime: dateToTimestampProto(
get(options, 'updateTime', new Date().toISOString())
),
name: resource,
};
const proto =
!data || Object.keys(data).length === 0
? resource
: {
fields: objectToValueProto(data),
createTime: dateToTimestampProto(
options?.createTime ?? new Date().toISOString()
),
updateTime: dateToTimestampProto(
options?.updateTime ?? new Date().toISOString()
),
name: resource,
};

const readTimeProto = dateToTimestampProto(
get(options, 'readTime') || new Date().toISOString()
options?.readTime || new Date().toISOString()
);
return firestoreService.snapshot_(proto, readTimeProto, 'json');
}
Expand Down Expand Up @@ -206,8 +224,8 @@ export function objectToValueProto(data: object) {
};
}
if (val instanceof firestore.DocumentReference) {
const projectId: string = get(val, '_referencePath.projectId');
const database: string = get(val, '_referencePath.databaseId');
const projectId: string = (val as any)._referencePath?.projectId;
const database: string = (val as any)._referencePath?.databaseId;
const referenceValue: string = [
'projects',
projectId,
Expand Down Expand Up @@ -266,7 +284,11 @@ export function clearFirestoreData(options: { projectId: string } | string) {

if (typeof options === 'string') {
projectId = options;
} else if (typeof options === 'object' && has(options, 'projectId')) {
} else if (
typeof options === 'object' &&
options &&
'projectId' in options
) {
projectId = options.projectId;
} else {
throw new Error('projectId not specified');
Expand Down
Loading
Loading