Skip to content

Commit dfa20ff

Browse files
authored
[Auth] Add integration test framework to compatibility layer. (#4642)
* Add integration testing framework to auth compat, plus the auth test ported over * Formatting, license * Fix linter issues * Fix broken node * Formatting * Update rest helpers
1 parent 6d6aa3e commit dfa20ff

File tree

11 files changed

+381
-32
lines changed

11 files changed

+381
-32
lines changed

packages-exp/auth-compat-exp/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
module.exports = {
1919
extends: '../../config/.eslintrc.js',
20+
ignorePatterns: ['scripts/'],
2021
parserOptions: {
2122
project: 'tsconfig.json',
2223
// to make vscode-eslint work with monorepo

packages-exp/auth-compat-exp/index.node.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,11 @@
2222
* just use index.ts
2323
*/
2424
export * from './index';
25+
import { FetchProvider } from '@firebase/auth-exp/internal';
26+
import * as fetchImpl from 'node-fetch';
27+
28+
FetchProvider.initialize(
29+
(fetchImpl.default as unknown) as typeof fetch,
30+
(fetchImpl.Headers as unknown) as typeof Headers,
31+
(fetchImpl.Response as unknown) as typeof Response
32+
);

packages-exp/auth-compat-exp/index.ts

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* limitations under the License.
1616
*/
1717

18+
/* eslint-disable camelcase */
19+
1820
import firebase, { _FirebaseNamespace } from '@firebase/app-compat';
1921
import * as impl from '@firebase/auth-exp/internal';
2022
import * as externs from '@firebase/auth-exp';
@@ -24,13 +26,32 @@ import {
2426
InstantiationMode
2527
} from '@firebase/component';
2628

27-
import { FirebaseAuth } from '@firebase/auth-types';
29+
import {
30+
EmailAuthProvider,
31+
EmailAuthProvider_Instance,
32+
FacebookAuthProvider,
33+
FacebookAuthProvider_Instance,
34+
FirebaseAuth,
35+
GithubAuthProvider,
36+
GithubAuthProvider_Instance,
37+
GoogleAuthProvider,
38+
GoogleAuthProvider_Instance,
39+
OAuthProvider,
40+
PhoneAuthProvider,
41+
PhoneAuthProvider_Instance,
42+
PhoneMultiFactorGenerator,
43+
RecaptchaVerifier,
44+
RecaptchaVerifier_Instance,
45+
SAMLAuthProvider,
46+
TwitterAuthProvider,
47+
TwitterAuthProvider_Instance
48+
} from '@firebase/auth-types';
2849
import { version } from './package.json';
2950
import { Auth } from './src/auth';
3051
import { Persistence } from './src/persistence';
31-
import { PhoneAuthProvider } from './src/phone_auth_provider';
52+
import { PhoneAuthProvider as CompatAuthProvider } from './src/phone_auth_provider';
3253
import { _getClientPlatform } from './src/platform';
33-
import { RecaptchaVerifier } from './src/recaptcha_verifier';
54+
import { RecaptchaVerifier as CompatRecaptchaVerifier } from './src/recaptcha_verifier';
3455

3556
const AUTH_TYPE = 'auth';
3657

@@ -44,6 +65,24 @@ declare module '@firebase/app-compat' {
4465
interface FirebaseNamespace {
4566
auth: {
4667
(app?: FirebaseApp): FirebaseAuth;
68+
Auth: typeof FirebaseAuth;
69+
EmailAuthProvider: typeof EmailAuthProvider;
70+
EmailAuthProvider_Instance: typeof EmailAuthProvider_Instance;
71+
FacebookAuthProvider: typeof FacebookAuthProvider;
72+
FacebookAuthProvider_Instance: typeof FacebookAuthProvider_Instance;
73+
GithubAuthProvider: typeof GithubAuthProvider;
74+
GithubAuthProvider_Instance: typeof GithubAuthProvider_Instance;
75+
GoogleAuthProvider: typeof GoogleAuthProvider;
76+
GoogleAuthProvider_Instance: typeof GoogleAuthProvider_Instance;
77+
OAuthProvider: typeof OAuthProvider;
78+
SAMLAuthProvider: typeof SAMLAuthProvider;
79+
PhoneAuthProvider: typeof PhoneAuthProvider;
80+
PhoneAuthProvider_Instance: typeof PhoneAuthProvider_Instance;
81+
PhoneMultiFactorGenerator: typeof PhoneMultiFactorGenerator;
82+
RecaptchaVerifier: typeof RecaptchaVerifier;
83+
RecaptchaVerifier_Instance: typeof RecaptchaVerifier_Instance;
84+
TwitterAuthProvider: typeof TwitterAuthProvider;
85+
TwitterAuthProvider_Instance: typeof TwitterAuthProvider_Instance;
4786
};
4887
}
4988
interface FirebaseApp {
@@ -84,9 +123,9 @@ function registerAuthCompat(instance: _FirebaseNamespace): void {
84123
GoogleAuthProvider: impl.GoogleAuthProvider,
85124
OAuthProvider: impl.OAuthProvider,
86125
// SAMLAuthProvider,
87-
PhoneAuthProvider,
126+
PhoneAuthProvider: CompatAuthProvider,
88127
PhoneMultiFactorGenerator: impl.PhoneMultiFactorGenerator,
89-
RecaptchaVerifier,
128+
RecaptchaVerifier: CompatRecaptchaVerifier,
90129
TwitterAuthProvider: impl.TwitterAuthProvider,
91130
Auth: {
92131
Persistence

packages-exp/auth-compat-exp/karma.conf.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,55 @@
1616
*/
1717

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

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

2223
module.exports = function (config) {
2324
const karmaConfig = Object.assign({}, karmaBase, {
2425
// files to load into karma
25-
files: files,
26+
files: getTestFiles(),
2627
preprocessors: { '**/*.ts': ['webpack', 'sourcemap'] },
2728
// frameworks to use
2829
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
29-
frameworks: ['mocha']
30+
frameworks: ['mocha'],
31+
32+
client: Object.assign({}, karmaBase.client, getClientConfig())
3033
});
3134

3235
config.set(karmaConfig);
3336
};
3437

35-
module.exports.files = files;
38+
function getTestFiles() {
39+
if (argv.integration) {
40+
return ['test/**/*.test.ts'];
41+
} else {
42+
return ['src/**/*.test.ts'];
43+
}
44+
}
45+
46+
function getClientConfig() {
47+
if (!argv.integration) {
48+
return {};
49+
}
50+
51+
if (!process.env.GCLOUD_PROJECT || !process.env.FIREBASE_AUTH_EMULATOR_HOST) {
52+
console.error(
53+
'Local testing against emulator requested, but ' +
54+
'GCLOUD_PROJECT and FIREBASE_AUTH_EMULATOR_HOST env variables ' +
55+
'are missing'
56+
);
57+
process.exit(1);
58+
}
59+
60+
return {
61+
authAppConfig: {
62+
apiKey: 'local-api-key',
63+
projectId: process.env.GCLOUD_PROJECT,
64+
authDomain: 'local-auth-domain'
65+
},
66+
authEmulatorHost: process.env.FIREBASE_AUTH_EMULATOR_HOST
67+
};
68+
}
69+
70+
module.exports.files = getTestFiles();

packages-exp/auth-compat-exp/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
"test:all": "run-p test:browser test:node",
2323
"test:ci": "node ../../scripts/run_tests_in_ci.js -s test:all",
2424
"test:browser": "karma start --single-run",
25-
"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"
25+
"test:browser:integration": "karma start --single-run --integration",
26+
"test:node": "ts-node -O '{\"module\": \"commonjs\", \"target\": \"es6\"}' scripts/run_node_tests.ts",
27+
"test:node:integration": "ts-node -O '{\"module\": \"commonjs\", \"target\": \"es6\"}' scripts/run_node_tests.ts --integration",
28+
"test:integration": "run-s test:browser:integration test:node:integration"
2629
},
2730
"peerDependencies": {
2831
"@firebase/app-compat": "0.x"
@@ -32,6 +35,7 @@
3235
"@firebase/auth-exp": "0.0.900",
3336
"@firebase/component": "0.2.1",
3437
"@firebase/util": "0.4.0",
38+
"node-fetch": "2.6.1",
3539
"tslib": "^2.0.0"
3640
},
3741
"license": "Apache-2.0",
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { resolve } from 'path';
19+
20+
import { spawn } from 'child-process-promise';
21+
import * as yargs from 'yargs';
22+
23+
const argv = yargs.options({
24+
integration: {
25+
type: 'boolean'
26+
},
27+
webdriver: {
28+
type: 'boolean'
29+
}
30+
}).argv;
31+
32+
const nyc = resolve(__dirname, '../../../node_modules/.bin/nyc');
33+
const mocha = resolve(__dirname, '../../../node_modules/.bin/mocha');
34+
35+
process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs", "target": "es6"}';
36+
37+
let testConfig = ['src/**/*.test.ts'];
38+
39+
if (argv.integration) {
40+
testConfig = ['test/integration/flows/**.test.ts'];
41+
} else if (argv.webdriver) {
42+
testConfig = ['test/integration/webdriver/**.test.ts', '--delay'];
43+
}
44+
45+
let args = [
46+
'--reporter',
47+
'lcovonly',
48+
mocha,
49+
...testConfig,
50+
'--file',
51+
'../auth-exp/src/platform_browser/iframe/gapi.iframes.ts',
52+
'--config',
53+
'../../config/mocharc.node.js'
54+
];
55+
56+
// Make sure that the environment variables are present for local test
57+
if (argv.integration || argv.webdriver) {
58+
if (!process.env.GCLOUD_PROJECT || !process.env.FIREBASE_AUTH_EMULATOR_HOST) {
59+
console.error(
60+
'Local testing against emulator requested, but ' +
61+
'GCLOUD_PROJECT and FIREBASE_AUTH_EMULATOR_HOST env variables ' +
62+
'are missing'
63+
);
64+
process.exit(1);
65+
}
66+
}
67+
68+
args = args.concat(argv._ as string[]);
69+
70+
const spawned = spawn(nyc, args, {
71+
stdio: 'inherit',
72+
cwd: process.cwd()
73+
});
74+
75+
const childProcess = spawned.childProcess;
76+
spawned.catch(() => {
77+
childProcess.kill();
78+
process.exit(1);
79+
});
80+
81+
process.once('exit', () => childProcess.kill());
82+
process.once('SIGINT', () => childProcess.kill('SIGINT'));
83+
process.once('SIGTERM', () => childProcess.kill('SIGTERM'));

packages-exp/auth-compat-exp/src/auth.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,14 @@ export class Auth
7171

7272
this.auth._updateErrorMap(exp.debugErrorMap);
7373

74+
// Only use a popup/redirect resolver in browser environments
75+
const resolver =
76+
typeof window !== 'undefined' ? CompatPopupRedirectResolver : undefined;
77+
7478
// This promise is intended to float; auth initialization happens in the
7579
// background, meanwhile the auth object may be used by the app.
7680
// eslint-disable-next-line @typescript-eslint/no-floating-promises
77-
this.auth._initializeWithPersistence(
78-
hierarchy,
79-
CompatPopupRedirectResolver
80-
);
81+
this.auth._initializeWithPersistence(hierarchy, resolver);
8182
}
8283

8384
get emulatorConfig(): compat.EmulatorConfig | null {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import * as sinon from 'sinon';
19+
import firebase from '@firebase/app-compat';
20+
import '../..';
21+
22+
import * as exp from '@firebase/auth-exp/internal';
23+
import {
24+
getAppConfig,
25+
getEmulatorUrl
26+
} from '../../../auth-exp/test/helpers/integration/settings';
27+
import { resetEmulator } from '../../../auth-exp/test/helpers/integration/emulator_rest_helpers';
28+
29+
export function initializeTestInstance(): void {
30+
firebase.initializeApp(getAppConfig());
31+
const stub = stubConsoleToSilenceEmulatorWarnings();
32+
firebase.auth().useEmulator(getEmulatorUrl()!);
33+
stub.restore();
34+
}
35+
36+
export async function cleanUpTestInstance(): Promise<void> {
37+
for (const app of firebase.apps) {
38+
await app.delete();
39+
}
40+
await resetEmulator();
41+
}
42+
43+
export function randomEmail(): string {
44+
return `${exp._generateEventId('test.email.')}@integration.test`;
45+
}
46+
47+
function stubConsoleToSilenceEmulatorWarnings(): sinon.SinonStub {
48+
const originalConsoleInfo = console.info.bind(console);
49+
return sinon.stub(console, 'info').callsFake((...args: unknown[]) => {
50+
if (
51+
!JSON.stringify(args[0]).includes(
52+
'WARNING: You are using the Auth Emulator'
53+
)
54+
) {
55+
originalConsoleInfo(...args);
56+
}
57+
});
58+
}

0 commit comments

Comments
 (0)