Skip to content

Commit

Permalink
Implement and type auth.emulatorConfig. (#4481)
Browse files Browse the repository at this point in the history
* Add emulator methods to auth-types.

* Implement and type auth.emulatorConfig.

* Create itchy-grapes-drum.md
  • Loading branch information
yuchenshi committed Feb 17, 2021
1 parent b3f2eef commit 4ab5a9c
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/itchy-grapes-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@firebase/auth-types": patch
---

Add emulator methods to auth-types.
4 changes: 4 additions & 0 deletions packages-exp/auth-compat-exp/src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ export class Auth
);
}

get emulatorConfig(): compat.EmulatorConfig | null {
return this.auth.emulatorConfig;
}

get currentUser(): compat.User | null {
if (!this.auth.currentUser) {
return null;
Expand Down
2 changes: 1 addition & 1 deletion packages-exp/auth-exp/src/api/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ describe('api/_performApiRequest', () => {

it('works properly with an emulated environment', () => {
(auth.config as ConfigInternal).emulator = {
url: 'http://localhost:5000'
url: 'http://localhost:5000/'
};
expect(_getFinalTarget(auth, 'host', '/path', 'query=test')).to.eq(
'http://localhost:5000/host/path?query=test'
Expand Down
1 change: 1 addition & 0 deletions packages-exp/auth-exp/src/core/auth/auth_impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const enum DefaultConfig {

export class AuthImpl implements Auth, _FirebaseService {
currentUser: externs.User | null = null;
emulatorConfig: externs.EmulatorConfig | null = null;
private operations = Promise.resolve();
private persistenceManager?: PersistenceUserManager;
private redirectPersistenceManager?: PersistenceUserManager;
Expand Down
37 changes: 37 additions & 0 deletions packages-exp/auth-exp/src/core/auth/emulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ describe('core/auth/emulator', () => {
expect(emulatorEndpoint.calls.length).to.eq(1);
});

it('updates the endpoint appropriately with trailing slash', async () => {
useAuthEmulator(auth, 'http://localhost:2020/');
await user.delete();
expect(normalEndpoint.calls.length).to.eq(0);
expect(emulatorEndpoint.calls.length).to.eq(1);
});

it('checks the scheme properly', () => {
expect(() => useAuthEmulator(auth, 'http://localhost:2020')).not.to.throw;
delete auth.config.emulator;
Expand Down Expand Up @@ -134,6 +141,36 @@ describe('core/auth/emulator', () => {
expect(document.querySelector('.firebase-emulator-warning')).to.be.null;
}
});

it('sets emulatorConfig on the Auth object', async () => {
useAuthEmulator(auth, 'http://localhost:2020');
expect(auth.emulatorConfig).to.eql({
protocol: 'http',
host: 'localhost',
port: 2020,
options: { disableWarnings: false }
});
});

it('sets disableWarnings in emulatorConfig accordingly', async () => {
useAuthEmulator(auth, 'https://127.0.0.1', { disableWarnings: true });
expect(auth.emulatorConfig).to.eql({
protocol: 'https',
host: '127.0.0.1',
port: null,
options: { disableWarnings: true }
});
});

it('quotes IPv6 address in emulatorConfig', async () => {
useAuthEmulator(auth, 'http://[::1]:2020/');
expect(auth.emulatorConfig).to.eql({
protocol: 'http',
host: '[::1]',
port: 2020,
options: { disableWarnings: false }
});
});
});

context('toJSON', () => {
Expand Down
15 changes: 13 additions & 2 deletions packages-exp/auth-exp/src/core/auth/emulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,20 @@ export function useAuthEmulator(
AuthErrorCode.INVALID_EMULATOR_SCHEME
);

authInternal.config.emulator = { url };
const parsedUrl = new URL(url);
const disableWarnings = !!options?.disableWarnings;

// Store the normalized URL whose path is always nonempty (i.e. containing at least a single '/').
authInternal.config.emulator = { url: parsedUrl.toString() };
authInternal.settings.appVerificationDisabledForTesting = true;
emitEmulatorWarning(!!options?.disableWarnings);
authInternal.emulatorConfig = Object.freeze({
host: parsedUrl.hostname,
port: parsedUrl.port ? Number(parsedUrl.port) : null,
protocol: parsedUrl.protocol.replace(':', ''),
options: Object.freeze({ disableWarnings })
});

emitEmulatorWarning(disableWarnings);
}

function emitEmulatorWarning(disableBanner: boolean): void {
Expand Down
2 changes: 1 addition & 1 deletion packages-exp/auth-exp/src/core/util/emulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { _emulatorUrl } from './emulator';
describe('core/util/emulator', () => {
const config: ConfigInternal = {
emulator: {
url: 'http://localhost:4000'
url: 'http://localhost:4000/'
}
} as ConfigInternal;

Expand Down
5 changes: 2 additions & 3 deletions packages-exp/auth-exp/src/core/util/emulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ import { debugAssert } from './assert';
export function _emulatorUrl(config: ConfigInternal, path?: string): string {
debugAssert(config.emulator, 'Emulator should always be set here');
const { url } = config.emulator;
const emulatorHost = new URL(url).toString();

if (!path) {
return emulatorHost;
return url;
}

return `${emulatorHost}${path.startsWith('/') ? path.slice(1) : path}`;
return `${url}${path.startsWith('/') ? path.slice(1) : path}`;
}
1 change: 1 addition & 0 deletions packages-exp/auth-exp/src/model/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface ConfigInternal extends externs.Config {

export interface Auth extends externs.Auth {
currentUser: externs.User | null;
emulatorConfig: externs.EmulatorConfig | null;
_canInitEmulator: boolean;
_isInitialized: boolean;
_initializationPromise: Promise<void> | null;
Expand Down
30 changes: 30 additions & 0 deletions packages-exp/auth-types-exp/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ export interface Auth {
): Unsubscribe;
/** The currently signed-in user (or null). */
readonly currentUser: User | null;
/** The current emulator configuration (or null). */
readonly emulatorConfig: EmulatorConfig | null;
/**
* Asynchronously sets the provided user as {@link Auth.currentUser} on the {@link Auth} instance.
*
Expand Down Expand Up @@ -1511,6 +1513,34 @@ declare module '@firebase/component' {
}
}

/**
* Configuration of Firebase Authentication Emulator.
*/
export interface EmulatorConfig {
/**
* The protocol used to communicate with the emulator ("http"/"https").
*/
readonly protocol: string;
/**
* The hostname of the emulator, which may be a domain ("localhost"), IPv4 address ("127.0.0.1")
* or quoted IPv6 address ("[::1]").
*/
readonly host: string;
/**
* The port of the emulator, or null if port isn't specified (i.e. protocol default).
*/
readonly port: number | null;
/**
* The emulator-specific options.
*/
readonly options: {
/**
* Whether the warning banner attached to the DOM was disabled.
*/
readonly disableWarnings: boolean;
};
}

/**
* A mapping of error codes to error messages.
*
Expand Down
11 changes: 11 additions & 0 deletions packages/auth-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,15 @@ export class PhoneMultiFactorGenerator {
): PhoneMultiFactorAssertion;
}

export interface EmulatorConfig {
readonly protocol: string;
readonly host: string;
readonly port: number | null;
readonly options: {
readonly disableWarnings: boolean;
};
}

export class FirebaseAuth {
private constructor();

Expand All @@ -407,6 +416,7 @@ export class FirebaseAuth {
password: string
): Promise<UserCredential>;
currentUser: User | null;
readonly emulatorConfig: EmulatorConfig | null;
fetchSignInMethodsForEmail(email: string): Promise<Array<string>>;
isSignInWithEmailLink(emailLink: string): boolean;
getRedirectResult(): Promise<UserCredential>;
Expand Down Expand Up @@ -455,6 +465,7 @@ export class FirebaseAuth {
tenantId: string | null;
updateCurrentUser(user: User | null): Promise<void>;
useDeviceLanguage(): void;
useEmulator(url: string, options?: { disableWarnings?: boolean }): void;
verifyPasswordResetCode(code: string): Promise<string>;
}

Expand Down

0 comments on commit 4ab5a9c

Please sign in to comment.