voluptasmollitia
Version:
Monorepo for the Firebase JavaScript SDK
223 lines (196 loc) • 6.91 kB
text/typescript
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { expect } from 'chai';
import * as sinon from 'sinon';
import { FirebaseApp } from '@firebase/app-exp';
import { FunctionsErrorCode } from './public-types';
import {
Provider,
ComponentContainer,
Component,
ComponentType
} from '@firebase/component';
import {
FirebaseMessaging,
FirebaseMessagingName
} from '@firebase/messaging-types';
import {
FirebaseAuthInternal,
FirebaseAuthInternalName
} from '@firebase/auth-interop-types';
import { makeFakeApp, createTestService } from '../test/utils';
import { httpsCallable } from './service';
import { FUNCTIONS_TYPE } from './constants';
// eslint-disable-next-line @typescript-eslint/no-require-imports
export const TEST_PROJECT = require('../../../config/project.json');
// Chai doesn't handle Error comparisons in a useful way.
// https://github.com/chaijs/chai/issues/608
async function expectError(
promise: Promise<any>,
code: FunctionsErrorCode,
message: string,
details?: any
): Promise<void> {
let failed = false;
try {
await promise;
} catch (e) {
failed = true;
expect(e.code).to.equal(`${FUNCTIONS_TYPE}/${code}`);
expect(e.message).to.equal(message);
expect(e.details).to.deep.equal(details);
}
if (!failed) {
expect(false, 'Promise should have failed.').to.be.true;
}
}
describe('Firebase Functions > Call', () => {
let app: FirebaseApp;
const region = 'us-central1';
before(() => {
const useEmulator = !!process.env.FIREBASE_FUNCTIONS_EMULATOR_ORIGIN;
const projectId = useEmulator
? 'functions-integration-test'
: TEST_PROJECT.projectId;
const messagingSenderId = 'messaging-sender-id';
app = makeFakeApp({ projectId, messagingSenderId });
});
it('simple data', async () => {
const functions = createTestService(app, region);
// TODO(klimt): Should we add an API to create a "long" in JS?
const data = {
bool: true,
int: 2,
str: 'four',
array: [5, 6],
null: null
};
const func = httpsCallable<
Record<string, any>,
{ message: string; code: number; long: number }
>(functions, 'dataTest');
const result = await func(data);
expect(result.data).to.deep.equal({
message: 'stub response',
code: 42,
long: 420
});
});
it('scalars', async () => {
const functions = createTestService(app, region);
const func = httpsCallable<number, number>(functions, 'scalarTest');
const result = await func(17);
expect(result.data).to.equal(76);
});
it('token', async () => {
// mock auth-internal service
const authMock: FirebaseAuthInternal = ({
getToken: async () => ({ accessToken: 'token' })
} as unknown) as FirebaseAuthInternal;
const authProvider = new Provider<FirebaseAuthInternalName>(
'auth-internal',
new ComponentContainer('test')
);
authProvider.setComponent(
new Component('auth-internal', () => authMock, ComponentType.PRIVATE)
);
const functions = createTestService(app, region, authProvider);
// Stub out the internals to get an auth token.
const stub = sinon.stub(authMock, 'getToken').callThrough();
const func = httpsCallable(functions, 'tokenTest');
const result = await func({});
expect(result.data).to.deep.equal({});
expect(stub.callCount).to.equal(1);
stub.restore();
});
it('instance id', async () => {
// Should effectively skip this test in environments where messaging doesn't work.
// (Node, IE)
if (process || !('Notification' in self)) {
console.log('No Notification API: skipping instance id test.');
return;
}
// mock firebase messaging
const messagingMock: FirebaseMessaging = ({
getToken: async () => 'iid'
} as unknown) as FirebaseMessaging;
const messagingProvider = new Provider<FirebaseMessagingName>(
'messaging',
new ComponentContainer('test')
);
messagingProvider.setComponent(
new Component('messaging', () => messagingMock, ComponentType.PRIVATE)
);
const functions = createTestService(
app,
region,
undefined,
messagingProvider
);
// Stub out the messaging method get an instance id token.
const stub = sinon.stub(messagingMock, 'getToken').callThrough();
sinon.stub(Notification, 'permission').value('granted');
const func = httpsCallable(functions, 'instanceIdTest');
const result = await func({});
expect(result.data).to.deep.equal({});
expect(stub.callCount).to.equal(1);
stub.restore();
});
it('null', async () => {
const functions = createTestService(app, region);
const func = httpsCallable(functions, 'nullTest');
let result = await func(null);
expect(result.data).to.be.null;
// Test with void arguments version.
result = await func();
expect(result.data).to.be.null;
});
it('missing result', async () => {
const functions = createTestService(app, region);
const func = httpsCallable(functions, 'missingResultTest');
await expectError(func(), 'internal', 'Response is missing data field.');
});
it('unhandled error', async () => {
const functions = createTestService(app, region);
const func = httpsCallable(functions, 'unhandledErrorTest');
await expectError(func(), 'internal', 'internal');
});
it('unknown error', async () => {
const functions = createTestService(app, region);
const func = httpsCallable(functions, 'unknownErrorTest');
await expectError(func(), 'internal', 'internal');
});
it('explicit error', async () => {
const functions = createTestService(app, region);
const func = httpsCallable(functions, 'explicitErrorTest');
await expectError(func(), 'out-of-range', 'explicit nope', {
start: 10,
end: 20,
long: 30
});
});
it('http error', async () => {
const functions = createTestService(app, region);
const func = httpsCallable(functions, 'httpErrorTest');
await expectError(func(), 'invalid-argument', 'invalid-argument');
});
it('timeout', async () => {
const functions = createTestService(app, region);
const func = httpsCallable(functions, 'timeoutTest', { timeout: 10 });
await expectError(func(), 'deadline-exceeded', 'deadline-exceeded');
});
});