diff --git a/packages-exp/auth-exp/.eslintrc.js b/packages-exp/auth-exp/.eslintrc.js index 674937d0c30..6cfe90711fc 100644 --- a/packages-exp/auth-exp/.eslintrc.js +++ b/packages-exp/auth-exp/.eslintrc.js @@ -17,7 +17,7 @@ module.exports = { extends: '../../config/.eslintrc.js', - ignorePatterns: ['demo/'], + ignorePatterns: ['demo/', 'scripts/'], parserOptions: { project: 'tsconfig.json', // to make vscode-eslint work with monorepo diff --git a/packages-exp/auth-exp/karma.conf.js b/packages-exp/auth-exp/karma.conf.js index 6b96b877eea..3b6355af507 100644 --- a/packages-exp/auth-exp/karma.conf.js +++ b/packages-exp/auth-exp/karma.conf.js @@ -24,7 +24,9 @@ module.exports = function (config) { files: getTestFiles(argv), // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['mocha'] + frameworks: ['mocha'], + + client: Object.assign({}, karmaBase.client, getClientConfig(argv)) }); config.set(karmaConfig); @@ -48,4 +50,19 @@ function getTestFiles(argv) { } } +function getClientConfig(argv) { + if (!argv.local) { + return {}; + } + + return { + authAppConfig: { + apiKey: 'local-api-key', + projectId: 'test-emulator', + authDomain: 'local-auth-domain' + }, + authEmulatorPort: '9099' + }; +} + module.exports.files = getTestFiles(argv); diff --git a/packages-exp/auth-exp/package.json b/packages-exp/auth-exp/package.json index c0a3a0baeaa..0248a8f4e84 100644 --- a/packages-exp/auth-exp/package.json +++ b/packages-exp/auth-exp/package.json @@ -20,6 +20,7 @@ "build": "rollup -c && yarn api-report", "build:deps": "lerna run --scope @firebase/auth-exp --include-dependencies build", "build:release": "rollup -c rollup.config.release.js && yarn api-report && yarn typings:public", + "build:scripts": "tsc -moduleResolution node --module commonjs scripts/*.ts && ls scripts/*.js | xargs -I % sh -c 'terser % -o %'", "dev": "rollup -c -w", "test": "run-p lint test:all", "test:all": "run-p test:browser test:node", @@ -27,13 +28,15 @@ "test:browser": "karma start --single-run", "test:browser:unit": "karma start --single-run --unit", "test:browser:integration": "karma start --single-run --integration", + "test:browser:integration:local": "karma start --single-run --integration --local --auto-watch", "test:browser:debug": "karma start --auto-watch", "test:browser:unit:debug": "karma start --auto-watch --unit", "test:cordova": "karma start --single-run --cordova", "test:cordova:debug": "karma start --auto-watch --cordova", "test:node": "run-s test:node:unit test:node:integration", - "test:node:unit": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'src/!(platform_browser|platform_react_native|platform_cordova)/**/*.test.ts' --file index.node.ts --config ../../config/mocharc.node.js", - "test:node:integration": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'test/integration/flows/{email,anonymous}.test.ts' --config ../../config/mocharc.node.js", + "test:node:unit": "node ./scripts/run-node-tests.js", + "test:node:integration": "node ./scripts/run-node-tests.js --integration", + "test:node:integration:local": "node ./scripts/run-node-tests.js --integration --local", "api-report": "api-extractor run --local --verbose", "predoc": "node ../../scripts/exp/remove-exp.js temp", "doc": "api-documenter markdown --input temp --output docs", diff --git a/packages-exp/auth-exp/scripts/run-node-tests.js b/packages-exp/auth-exp/scripts/run-node-tests.js new file mode 100644 index 00000000000..c83ddee1a20 --- /dev/null +++ b/packages-exp/auth-exp/scripts/run-node-tests.js @@ -0,0 +1,69 @@ +/** + * @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. + */ + +'use strict'; +var __spreadArrays = + (this && this.__spreadArrays) || + function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) + s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; + }; +exports.__esModule = true; +var path_1 = require('path'); +var child_process_promise_1 = require('child-process-promise'); +var yargs = require('yargs'); +var argv = yargs.options({ + local: { type: 'boolean' }, + integration: { type: 'boolean' } +}).argv; +var nyc = path_1.resolve(__dirname, '../../../node_modules/.bin/nyc'); +var mocha = path_1.resolve(__dirname, '../../../node_modules/.bin/mocha'); +process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs"}'; +var testConfig = [ + 'src/!(platform_browser|platform_react_native|platform_cordova)/**/*.test.ts', + '--file', + 'index.node.ts' +]; +if (argv.integration) { + testConfig = ['test/integration/flows/{email,anonymous}.test.ts']; +} +var args = __spreadArrays(['--reporter', 'lcovonly', mocha], testConfig, [ + '--config', + '../../config/mocharc.node.js' +]); +if (argv.local) { + process.env.AUTH_EMULATOR_PORT = '9099'; + process.env.AUTH_EMULATOR_PROJECT_ID = 'test-emulator'; +} +args = args.concat(argv._); +var childProcess = child_process_promise_1.spawn(nyc, args, { + stdio: 'inherit', + cwd: process.cwd() +}).childProcess; +process.once('exit', function () { + return childProcess.kill(); +}); +process.once('SIGINT', function () { + return childProcess.kill('SIGINT'); +}); +process.once('SIGTERM', function () { + return childProcess.kill('SIGTERM'); +}); diff --git a/packages-exp/auth-exp/scripts/run-node-tests.ts b/packages-exp/auth-exp/scripts/run-node-tests.ts new file mode 100644 index 00000000000..f3a5eba5a3c --- /dev/null +++ b/packages-exp/auth-exp/scripts/run-node-tests.ts @@ -0,0 +1,70 @@ +/** + * @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({ + local: { + type: 'boolean' + }, + integration: { + 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"}'; + +let testConfig = [ + 'src/!(platform_browser|platform_react_native|platform_cordova)/**/*.test.ts', + '--file', + 'index.node.ts' +]; + +if (argv.integration) { + testConfig = ['test/integration/flows/{email,anonymous}.test.ts']; +} + +let args = [ + '--reporter', + 'lcovonly', + mocha, + ...testConfig, + '--config', + '../../config/mocharc.node.js' +]; + +if (argv.local) { + process.env.AUTH_EMULATOR_PORT = '9099'; + process.env.AUTH_EMULATOR_PROJECT_ID = 'test-emulator'; +} + +args = args.concat(argv._ as string[]); + +const childProcess = spawn(nyc, args, { + stdio: 'inherit', + cwd: process.cwd() +}).childProcess; + +process.once('exit', () => childProcess.kill()); +process.once('SIGINT', () => childProcess.kill('SIGINT')); +process.once('SIGTERM', () => childProcess.kill('SIGTERM')); diff --git a/packages-exp/auth-exp/test/helpers/integration/helpers.ts b/packages-exp/auth-exp/test/helpers/integration/helpers.ts index 508b3239384..831179c58b5 100644 --- a/packages-exp/auth-exp/test/helpers/integration/helpers.ts +++ b/packages-exp/auth-exp/test/helpers/integration/helpers.ts @@ -18,15 +18,9 @@ import { deleteApp, initializeApp } from '@firebase/app-exp'; import { Auth, User } from '../../../src/model/public_types'; -import { getAuth } from '../../../'; // Use browser OR node dist entrypoint depending on test env. +import { getAuth, useAuthEmulator } from '../../../'; // Use browser OR node dist entrypoint depending on test env. import { _generateEventId } from '../../../src/core/util/event_id'; - -// eslint-disable-next-line @typescript-eslint/no-require-imports -const PROJECT_CONFIG = require('../../../../../config/project.json'); - -export const PROJECT_ID = PROJECT_CONFIG.projectId; -export const AUTH_DOMAIN = PROJECT_CONFIG.authDomain; -export const API_KEY = PROJECT_CONFIG.apiKey; +import { getAppConfig, getEmulatorUrl } from './settings'; interface IntegrationTestAuth extends Auth { cleanUp(): Promise; @@ -37,15 +31,16 @@ export function randomEmail(): string { } export function getTestInstance(): Auth { - const app = initializeApp({ - apiKey: API_KEY, - projectId: PROJECT_ID, - authDomain: AUTH_DOMAIN - }); + const app = initializeApp(getAppConfig()); const createdUsers: User[] = []; const auth = getAuth(app) as IntegrationTestAuth; auth.settings.appVerificationDisabledForTesting = true; + const emulatorUrl = getEmulatorUrl(); + + if (emulatorUrl) { + useAuthEmulator(auth, emulatorUrl, { disableWarnings: true }); + } auth.onAuthStateChanged(user => { if (user) { diff --git a/packages-exp/auth-exp/test/helpers/integration/settings.ts b/packages-exp/auth-exp/test/helpers/integration/settings.ts new file mode 100644 index 00000000000..f42421e534d --- /dev/null +++ b/packages-exp/auth-exp/test/helpers/integration/settings.ts @@ -0,0 +1,65 @@ +/** + * @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 { FirebaseOptions } from '@firebase/app-exp'; + +// __karma__ is an untyped global +// eslint-disable-next-line @typescript-eslint/no-explicit-any +declare const __karma__: any; + +// eslint-disable-next-line @typescript-eslint/no-require-imports +const PROJECT_CONFIG = require('../../../../../config/project.json'); + +const EMULATOR_PORT = process.env.AUTH_EMULATOR_PORT; +const EMULATOR_PROJECT_ID = process.env.AUTH_EMULATOR_PROJECT_ID; + +export const USE_EMULATOR = !!EMULATOR_PORT; + +export const PROJECT_ID = USE_EMULATOR + ? EMULATOR_PROJECT_ID + : PROJECT_CONFIG.projectId; +export const AUTH_DOMAIN = USE_EMULATOR + ? 'emulator-auth-domain' + : PROJECT_CONFIG.authDomain; +export const API_KEY = USE_EMULATOR + ? 'emulator-api-key' + : PROJECT_CONFIG.apiKey; + +export function getAppConfig(): FirebaseOptions { + // Prefer the karma config, then fallback on node process.env stuff + return ( + getKarma()?.config?.authAppConfig || { + apiKey: API_KEY, + projectId: PROJECT_ID, + authDomain: AUTH_DOMAIN + } + ); +} + +export function getEmulatorUrl(): string | null { + // Check karma first, then fallback on node process + const emulatorPort: string | null = + getKarma()?.config?.authEmulatorPort || + (USE_EMULATOR ? EMULATOR_PORT : null); + + return emulatorPort ? `http://localhost:${emulatorPort}` : null; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function getKarma(): any { + return typeof __karma__ !== 'undefined' ? __karma__ : undefined; +}