diff --git a/.changeset/funny-weeks-attack.md b/.changeset/funny-weeks-attack.md new file mode 100644 index 00000000000..54e26f5c749 --- /dev/null +++ b/.changeset/funny-weeks-attack.md @@ -0,0 +1,5 @@ +--- +"@firebase/data-connect": patch +--- + +Fixed issue where multiple calls to connectDataConnectEmulator caused an exception diff --git a/packages/data-connect/src/api/DataConnect.ts b/packages/data-connect/src/api/DataConnect.ts index 27ab83660fd..30ec344f3ef 100644 --- a/packages/data-connect/src/api/DataConnect.ts +++ b/packages/data-connect/src/api/DataConnect.ts @@ -179,7 +179,10 @@ export class DataConnect { // @internal enableEmulator(transportOptions: TransportOptions): void { - if (this._initialized) { + if ( + this._initialized && + !areTransportOptionsEqual(this._transportOptions, transportOptions) + ) { logError('enableEmulator called after initialization'); throw new DataConnectError( Code.ALREADY_INITIALIZED, @@ -191,6 +194,23 @@ export class DataConnect { } } +/** + * @internal + * @param transportOptions1 + * @param transportOptions2 + * @returns + */ +export function areTransportOptionsEqual( + transportOptions1: TransportOptions, + transportOptions2: TransportOptions +): boolean { + return ( + transportOptions1.host === transportOptions2.host && + transportOptions1.port === transportOptions2.port && + transportOptions1.sslEnabled === transportOptions2.sslEnabled + ); +} + /** * Connect to the DataConnect Emulator * @param dc Data Connect instance diff --git a/packages/data-connect/test/unit/transportoptions.test.ts b/packages/data-connect/test/unit/transportoptions.test.ts new file mode 100644 index 00000000000..91e090e6a54 --- /dev/null +++ b/packages/data-connect/test/unit/transportoptions.test.ts @@ -0,0 +1,80 @@ +/** + * @license + * Copyright 2024 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 { + TransportOptions, + areTransportOptionsEqual, + connectDataConnectEmulator, + getDataConnect +} from '../../src/api/DataConnect'; +import { app } from '../util'; +import { queryRef } from '../../src'; +describe('Transport Options', () => { + it('should return false if transport options are not equal', () => { + const transportOptions1: TransportOptions = { + host: 'h', + port: 1, + sslEnabled: false + }; + const transportOptions2: TransportOptions = { + host: 'h2', + port: 2, + sslEnabled: false + }; + expect( + areTransportOptionsEqual(transportOptions1, transportOptions2) + ).to.eq(false); + }); + it('should return true if transport options are equal', () => { + const transportOptions1: TransportOptions = { + host: 'h', + port: 1, + sslEnabled: false + }; + const transportOptions2: TransportOptions = { + port: 1, + host: 'h', + sslEnabled: false + }; + expect( + areTransportOptionsEqual(transportOptions1, transportOptions2) + ).to.eq(true); + }); + it('should throw if emulator is connected to with new transport options', () => { + const dc = getDataConnect(app, { + connector: 'c', + location: 'l', + service: 's' + }); + expect(() => connectDataConnectEmulator(dc, 'h', 80, false)).to.not.throw(); + queryRef(dc, 'query'); + expect(() => connectDataConnectEmulator(dc, 'h2', 80, false)).to.throw( + 'DataConnect instance already initialized!' + ); + }); + it('should not throw if emulator is connected to with the same transport options', () => { + const dc = getDataConnect(app, { + connector: 'c', + location: 'l', + service: 's' + }); + expect(() => connectDataConnectEmulator(dc, 'h', 80, false)).to.not.throw(); + queryRef(dc, 'query'); + expect(() => connectDataConnectEmulator(dc, 'h', 80, false)).to.not.throw(); + }); +});