Skip to content

[Auth] Add integration test framework to compatibility layer. #4642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 16, 2021
Merged
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
1 change: 1 addition & 0 deletions packages-exp/auth-compat-exp/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

module.exports = {
extends: '../../config/.eslintrc.js',
ignorePatterns: ['scripts/'],
parserOptions: {
project: 'tsconfig.json',
// to make vscode-eslint work with monorepo
Expand Down
8 changes: 8 additions & 0 deletions packages-exp/auth-compat-exp/index.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,11 @@
* just use index.ts
*/
export * from './index';
import { FetchProvider } from '@firebase/auth-exp/internal';
import * as fetchImpl from 'node-fetch';

FetchProvider.initialize(
(fetchImpl.default as unknown) as typeof fetch,
(fetchImpl.Headers as unknown) as typeof Headers,
(fetchImpl.Response as unknown) as typeof Response
);
49 changes: 44 additions & 5 deletions packages-exp/auth-compat-exp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* limitations under the License.
*/

/* eslint-disable camelcase */

import firebase, { _FirebaseNamespace } from '@firebase/app-compat';
import * as impl from '@firebase/auth-exp/internal';
import * as externs from '@firebase/auth-exp';
Expand All @@ -24,13 +26,32 @@ import {
InstantiationMode
} from '@firebase/component';

import { FirebaseAuth } from '@firebase/auth-types';
import {
EmailAuthProvider,
EmailAuthProvider_Instance,
FacebookAuthProvider,
FacebookAuthProvider_Instance,
FirebaseAuth,
GithubAuthProvider,
GithubAuthProvider_Instance,
GoogleAuthProvider,
GoogleAuthProvider_Instance,
OAuthProvider,
PhoneAuthProvider,
PhoneAuthProvider_Instance,
PhoneMultiFactorGenerator,
RecaptchaVerifier,
RecaptchaVerifier_Instance,
SAMLAuthProvider,
TwitterAuthProvider,
TwitterAuthProvider_Instance
} from '@firebase/auth-types';
import { version } from './package.json';
import { Auth } from './src/auth';
import { Persistence } from './src/persistence';
import { PhoneAuthProvider } from './src/phone_auth_provider';
import { PhoneAuthProvider as CompatAuthProvider } from './src/phone_auth_provider';
import { _getClientPlatform } from './src/platform';
import { RecaptchaVerifier } from './src/recaptcha_verifier';
import { RecaptchaVerifier as CompatRecaptchaVerifier } from './src/recaptcha_verifier';

const AUTH_TYPE = 'auth';

Expand All @@ -44,6 +65,24 @@ declare module '@firebase/app-compat' {
interface FirebaseNamespace {
auth: {
(app?: FirebaseApp): FirebaseAuth;
Auth: typeof FirebaseAuth;
EmailAuthProvider: typeof EmailAuthProvider;
EmailAuthProvider_Instance: typeof EmailAuthProvider_Instance;
FacebookAuthProvider: typeof FacebookAuthProvider;
FacebookAuthProvider_Instance: typeof FacebookAuthProvider_Instance;
GithubAuthProvider: typeof GithubAuthProvider;
GithubAuthProvider_Instance: typeof GithubAuthProvider_Instance;
GoogleAuthProvider: typeof GoogleAuthProvider;
GoogleAuthProvider_Instance: typeof GoogleAuthProvider_Instance;
OAuthProvider: typeof OAuthProvider;
SAMLAuthProvider: typeof SAMLAuthProvider;
PhoneAuthProvider: typeof PhoneAuthProvider;
PhoneAuthProvider_Instance: typeof PhoneAuthProvider_Instance;
PhoneMultiFactorGenerator: typeof PhoneMultiFactorGenerator;
RecaptchaVerifier: typeof RecaptchaVerifier;
RecaptchaVerifier_Instance: typeof RecaptchaVerifier_Instance;
TwitterAuthProvider: typeof TwitterAuthProvider;
TwitterAuthProvider_Instance: typeof TwitterAuthProvider_Instance;
};
}
interface FirebaseApp {
Expand Down Expand Up @@ -84,9 +123,9 @@ function registerAuthCompat(instance: _FirebaseNamespace): void {
GoogleAuthProvider: impl.GoogleAuthProvider,
OAuthProvider: impl.OAuthProvider,
// SAMLAuthProvider,
PhoneAuthProvider,
PhoneAuthProvider: CompatAuthProvider,
PhoneMultiFactorGenerator: impl.PhoneMultiFactorGenerator,
RecaptchaVerifier,
RecaptchaVerifier: CompatRecaptchaVerifier,
TwitterAuthProvider: impl.TwitterAuthProvider,
Auth: {
Persistence
Expand Down
41 changes: 38 additions & 3 deletions packages-exp/auth-compat-exp/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,55 @@
*/

const karmaBase = require('../../config/karma.base');
const { argv } = require('yargs');

const files = ['src/**/*.test.ts'];

module.exports = function (config) {
const karmaConfig = Object.assign({}, karmaBase, {
// files to load into karma
files: files,
files: getTestFiles(),
preprocessors: { '**/*.ts': ['webpack', 'sourcemap'] },
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['mocha']
frameworks: ['mocha'],

client: Object.assign({}, karmaBase.client, getClientConfig())
});

config.set(karmaConfig);
};

module.exports.files = files;
function getTestFiles() {
if (argv.integration) {
return ['test/**/*.test.ts'];
} else {
return ['src/**/*.test.ts'];
}
}

function getClientConfig() {
if (!argv.integration) {
return {};
}

if (!process.env.GCLOUD_PROJECT || !process.env.FIREBASE_AUTH_EMULATOR_HOST) {
console.error(
'Local testing against emulator requested, but ' +
'GCLOUD_PROJECT and FIREBASE_AUTH_EMULATOR_HOST env variables ' +
'are missing'
);
process.exit(1);
}

return {
authAppConfig: {
apiKey: 'local-api-key',
projectId: process.env.GCLOUD_PROJECT,
authDomain: 'local-auth-domain'
},
authEmulatorHost: process.env.FIREBASE_AUTH_EMULATOR_HOST
};
}

module.exports.files = getTestFiles();
6 changes: 5 additions & 1 deletion packages-exp/auth-compat-exp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
"test:all": "run-p test:browser test:node",
"test:ci": "node ../../scripts/run_tests_in_ci.js -s test:all",
"test:browser": "karma start --single-run",
"test:node": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha src/**/*.test.* --file ../auth-exp/src/platform_browser/iframe/gapi.iframes.ts --config ../../config/mocharc.node.js"
"test:browser:integration": "karma start --single-run --integration",
"test:node": "ts-node -O '{\"module\": \"commonjs\", \"target\": \"es6\"}' scripts/run_node_tests.ts",
"test:node:integration": "ts-node -O '{\"module\": \"commonjs\", \"target\": \"es6\"}' scripts/run_node_tests.ts --integration",
"test:integration": "run-s test:browser:integration test:node:integration"
},
"peerDependencies": {
"@firebase/app-compat": "0.x"
Expand All @@ -32,6 +35,7 @@
"@firebase/auth-exp": "0.0.900",
"@firebase/component": "0.2.1",
"@firebase/util": "0.4.0",
"node-fetch": "2.6.1",
"tslib": "^2.0.0"
},
"license": "Apache-2.0",
Expand Down
83 changes: 83 additions & 0 deletions packages-exp/auth-compat-exp/scripts/run_node_tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* @license
* Copyright 2020 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 { resolve } from 'path';

import { spawn } from 'child-process-promise';
import * as yargs from 'yargs';

const argv = yargs.options({
integration: {
type: 'boolean'
},
webdriver: {
type: 'boolean'
}
}).argv;

const nyc = resolve(__dirname, '../../../node_modules/.bin/nyc');
const mocha = resolve(__dirname, '../../../node_modules/.bin/mocha');

process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs", "target": "es6"}';

let testConfig = ['src/**/*.test.ts'];

if (argv.integration) {
testConfig = ['test/integration/flows/**.test.ts'];
} else if (argv.webdriver) {
testConfig = ['test/integration/webdriver/**.test.ts', '--delay'];
}

let args = [
'--reporter',
'lcovonly',
mocha,
...testConfig,
'--file',
'../auth-exp/src/platform_browser/iframe/gapi.iframes.ts',
'--config',
'../../config/mocharc.node.js'
];

// Make sure that the environment variables are present for local test
if (argv.integration || argv.webdriver) {
if (!process.env.GCLOUD_PROJECT || !process.env.FIREBASE_AUTH_EMULATOR_HOST) {
console.error(
'Local testing against emulator requested, but ' +
'GCLOUD_PROJECT and FIREBASE_AUTH_EMULATOR_HOST env variables ' +
'are missing'
);
process.exit(1);
}
}

args = args.concat(argv._ as string[]);

const spawned = spawn(nyc, args, {
stdio: 'inherit',
cwd: process.cwd()
});

const childProcess = spawned.childProcess;
spawned.catch(() => {
childProcess.kill();
process.exit(1);
});

process.once('exit', () => childProcess.kill());
process.once('SIGINT', () => childProcess.kill('SIGINT'));
process.once('SIGTERM', () => childProcess.kill('SIGTERM'));
9 changes: 5 additions & 4 deletions packages-exp/auth-compat-exp/src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,14 @@ export class Auth

this.auth._updateErrorMap(exp.debugErrorMap);

// Only use a popup/redirect resolver in browser environments
const resolver =
typeof window !== 'undefined' ? CompatPopupRedirectResolver : undefined;

// This promise is intended to float; auth initialization happens in the
// background, meanwhile the auth object may be used by the app.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.auth._initializeWithPersistence(
hierarchy,
CompatPopupRedirectResolver
);
this.auth._initializeWithPersistence(hierarchy, resolver);
}

get emulatorConfig(): compat.EmulatorConfig | null {
Expand Down
58 changes: 58 additions & 0 deletions packages-exp/auth-compat-exp/test/helpers/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* @license
* Copyright 2020 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 * as sinon from 'sinon';
import firebase from '@firebase/app-compat';
import '../..';

import * as exp from '@firebase/auth-exp/internal';
import {
getAppConfig,
getEmulatorUrl
} from '../../../auth-exp/test/helpers/integration/settings';
import { resetEmulator } from '../../../auth-exp/test/helpers/integration/emulator_rest_helpers';

export function initializeTestInstance(): void {
firebase.initializeApp(getAppConfig());
const stub = stubConsoleToSilenceEmulatorWarnings();
firebase.auth().useEmulator(getEmulatorUrl()!);
stub.restore();
}

export async function cleanUpTestInstance(): Promise<void> {
for (const app of firebase.apps) {
await app.delete();
}
await resetEmulator();
}

export function randomEmail(): string {
return `${exp._generateEventId('test.email.')}@integration.test`;
}

function stubConsoleToSilenceEmulatorWarnings(): sinon.SinonStub {
const originalConsoleInfo = console.info.bind(console);
return sinon.stub(console, 'info').callsFake((...args: unknown[]) => {
if (
!JSON.stringify(args[0]).includes(
'WARNING: You are using the Auth Emulator'
)
) {
originalConsoleInfo(...args);
}
});
}
Loading