Skip to content

Commit 4eea726

Browse files
author
kjelko
committed
Initial pass at adding some tests
1 parent 6d14604 commit 4eea726

File tree

2 files changed

+188
-50
lines changed

2 files changed

+188
-50
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { expect } from 'chai';
2+
import { ensureInitialized, fetchAndActivate, getRemoteConfig, getString } from '../src/index';
3+
import '../test/setup';
4+
import { deleteApp, FirebaseApp, initializeApp, _addOrOverwriteComponent } from '@firebase/app';
5+
import * as sinon from 'sinon';
6+
import { FetchResponse } from '../src/client/remote_config_fetch_client';
7+
import {
8+
Component,
9+
ComponentType
10+
} from '@firebase/component';
11+
import { FirebaseInstallations } from '@firebase/installations-types';
12+
import {
13+
openDatabase,
14+
APP_NAMESPACE_STORE,
15+
} from '../src/storage/storage';
16+
17+
const fakeFirebaseConfig = {
18+
apiKey: 'api-key',
19+
authDomain: 'project-id.firebaseapp.com',
20+
databaseURL: 'https://project-id.firebaseio.com',
21+
projectId: 'project-id',
22+
storageBucket: 'project-id.appspot.com',
23+
messagingSenderId: 'sender-id',
24+
appId: '1:111:web:a1234'
25+
};
26+
27+
async function clearDatabase(): Promise<void> {
28+
const db = await openDatabase();
29+
db.transaction([APP_NAMESPACE_STORE], 'readwrite')
30+
.objectStore(APP_NAMESPACE_STORE)
31+
.clear();
32+
}
33+
34+
describe('Remote Config API', () => {
35+
let app: FirebaseApp;
36+
const STUB_FETCH_RESPONSE: FetchResponse = {
37+
status: 200,
38+
eTag: 'asdf',
39+
config: { 'foobar': 'hello world' },
40+
};
41+
let fetchStub: sinon.SinonStub;
42+
43+
beforeEach(() => {
44+
fetchStub = sinon.stub(window, 'fetch');
45+
app = initializeApp(fakeFirebaseConfig);
46+
_addOrOverwriteComponent(
47+
app,
48+
new Component(
49+
'installations-internal',
50+
() => {
51+
return {
52+
getId: () => Promise.resolve('fis-id'),
53+
getToken: () => Promise.resolve('fis-token'),
54+
} as any as FirebaseInstallations;
55+
},
56+
ComponentType.PUBLIC
57+
) as any,
58+
);
59+
});
60+
61+
afterEach(async () => {
62+
fetchStub.restore();
63+
await clearDatabase();
64+
await deleteApp(app);
65+
});
66+
67+
function setFetchResponse(response: FetchResponse = { status: 200 }): void {
68+
fetchStub.returns(Promise.resolve({
69+
ok: response.status === 200,
70+
status: response.status,
71+
headers: new Headers({ ETag: response.eTag || '' }),
72+
json: () =>
73+
Promise.resolve({
74+
entries: response.config,
75+
state: 'OK'
76+
})
77+
} as Response));
78+
}
79+
80+
it('allows multiple initializations if options are same', () => {
81+
const rc = getRemoteConfig(app, { templateId: 'altTemplate' });
82+
const rc2 = getRemoteConfig(app, { templateId: 'altTemplate' });
83+
expect(rc).to.equal(rc2);
84+
});
85+
86+
it('throws an error if options are different', () => {
87+
getRemoteConfig(app);
88+
expect(() => {
89+
getRemoteConfig(app, { templateId: 'altTemplate' });
90+
}).to.throw(/Remote Config already initialized/);
91+
});
92+
93+
it('makes a fetch call', async () => {
94+
const rc = getRemoteConfig(app);
95+
setFetchResponse(STUB_FETCH_RESPONSE);
96+
await fetchAndActivate(rc);
97+
await ensureInitialized(rc);
98+
expect(getString(rc, 'foobar')).to.equal('hello world');
99+
});
100+
101+
it('calls fetch with default templateId', async () => {
102+
const rc = getRemoteConfig(app);
103+
setFetchResponse();
104+
await fetchAndActivate(rc);
105+
await ensureInitialized(rc);
106+
expect(fetchStub).to.be.calledOnceWith(
107+
'https://firebaseremoteconfig.googleapis.com/v1/projects/project-id/namespaces/firebase:fetch?key=api-key',
108+
sinon.match.object
109+
);
110+
});
111+
112+
it('calls fetch with alternate templateId', async () => {
113+
const rc = getRemoteConfig(app, { templateId: 'altTemplate' });
114+
setFetchResponse();
115+
await fetchAndActivate(rc);
116+
expect(fetchStub).to.be.calledOnceWith(
117+
'https://firebaseremoteconfig.googleapis.com/v1/projects/project-id/namespaces/altTemplate:fetch?key=api-key',
118+
sinon.match.object);
119+
});
120+
121+
it('hydrates with initialFetchResponse', async () => {
122+
const rc = getRemoteConfig(app, { initialFetchResponse: STUB_FETCH_RESPONSE });
123+
await ensureInitialized(rc);
124+
expect(getString(rc, 'foobar')).to.equal('hello world');
125+
});
126+
});

packages/remote-config/test/storage/storage.test.ts

Lines changed: 62 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
import '../setup';
1919
import { expect } from 'chai';
2020
import {
21-
Storage,
2221
ThrottleMetadata,
2322
openDatabase,
24-
APP_NAMESPACE_STORE
23+
APP_NAMESPACE_STORE,
24+
IndexedDbStorage,
25+
InMemoryStorage
2526
} from '../../src/storage/storage';
2627
import { FetchResponse } from '../../src/client/remote_config_fetch_client';
2728

@@ -33,88 +34,99 @@ async function clearDatabase(): Promise<void> {
3334
.clear();
3435
}
3536

36-
describe('Storage', () => {
37-
const storage = new Storage('appId', 'appName', 'namespace');
37+
describe('IndexedDbStorage', () => {
38+
39+
const indexedDbTestCase = {
40+
storage: new IndexedDbStorage('appId', 'appName', 'namespace'),
41+
name: 'IndexedDbStorage',
42+
};
43+
44+
const inMemoryStorage = {
45+
storage: new InMemoryStorage(),
46+
name: 'InMemoryStorage',
47+
};
3848

3949
beforeEach(async () => {
4050
await clearDatabase();
4151
});
4252

43-
it('constructs a composite key', async () => {
53+
it(`${indexedDbTestCase.name} constructs a composite key`, async () => {
4454
// This is defensive, but the cost of accidentally changing the key composition is high.
45-
expect(storage.createCompositeKey('throttle_metadata')).to.eq(
55+
expect(indexedDbTestCase.storage.createCompositeKey('throttle_metadata')).to.eq(
4656
'appId,appName,namespace,throttle_metadata'
4757
);
4858
});
4959

50-
it('sets and gets last fetch attempt status', async () => {
51-
const expectedStatus = 'success';
60+
for (const { name, storage } of [indexedDbTestCase, inMemoryStorage]) {
61+
it(`${name} sets and gets last fetch attempt status`, async () => {
62+
const expectedStatus = 'success';
5263

53-
await storage.setLastFetchStatus(expectedStatus);
64+
await storage.setLastFetchStatus(expectedStatus);
5465

55-
const actualStatus = await storage.getLastFetchStatus();
66+
const actualStatus = await storage.getLastFetchStatus();
5667

57-
expect(actualStatus).to.deep.eq(expectedStatus);
58-
});
68+
expect(actualStatus).to.deep.eq(expectedStatus);
69+
});
5970

60-
it('sets and gets last fetch success timestamp', async () => {
61-
const lastSuccessfulFetchTimestampMillis = 123;
71+
it(`${name} sets and gets last fetch success timestamp`, async () => {
72+
const lastSuccessfulFetchTimestampMillis = 123;
6273

63-
await storage.setLastSuccessfulFetchTimestampMillis(
64-
lastSuccessfulFetchTimestampMillis
65-
);
74+
await storage.setLastSuccessfulFetchTimestampMillis(
75+
lastSuccessfulFetchTimestampMillis
76+
);
6677

67-
const actualMetadata =
68-
await storage.getLastSuccessfulFetchTimestampMillis();
78+
const actualMetadata =
79+
await storage.getLastSuccessfulFetchTimestampMillis();
6980

70-
expect(actualMetadata).to.deep.eq(lastSuccessfulFetchTimestampMillis);
71-
});
81+
expect(actualMetadata).to.deep.eq(lastSuccessfulFetchTimestampMillis);
82+
});
7283

73-
it('sets and gets last successful fetch response', async () => {
74-
const lastSuccessfulFetchResponse = { status: 200 } as FetchResponse;
84+
it(`${name} sets and gets last successful fetch response`, async () => {
85+
const lastSuccessfulFetchResponse = { status: 200 } as FetchResponse;
7586

76-
await storage.setLastSuccessfulFetchResponse(lastSuccessfulFetchResponse);
87+
await storage.setLastSuccessfulFetchResponse(lastSuccessfulFetchResponse);
7788

78-
const actualConfig = await storage.getLastSuccessfulFetchResponse();
89+
const actualConfig = await storage.getLastSuccessfulFetchResponse();
7990

80-
expect(actualConfig).to.deep.eq(lastSuccessfulFetchResponse);
81-
});
91+
expect(actualConfig).to.deep.eq(lastSuccessfulFetchResponse);
92+
});
8293

83-
it('sets and gets active config', async () => {
84-
const expectedConfig = { key: 'value' };
94+
it(`${name} sets and gets active config`, async () => {
95+
const expectedConfig = { key: 'value' };
8596

86-
await storage.setActiveConfig(expectedConfig);
97+
await storage.setActiveConfig(expectedConfig);
8798

88-
const storedConfig = await storage.getActiveConfig();
99+
const storedConfig = await storage.getActiveConfig();
89100

90-
expect(storedConfig).to.deep.eq(expectedConfig);
91-
});
101+
expect(storedConfig).to.deep.eq(expectedConfig);
102+
});
92103

93-
it('sets and gets active config etag', async () => {
94-
const expectedEtag = 'etag';
104+
it(`${name} sets and gets active config etag`, async () => {
105+
const expectedEtag = 'etag';
95106

96-
await storage.setActiveConfigEtag(expectedEtag);
107+
await storage.setActiveConfigEtag(expectedEtag);
97108

98-
const storedConfigEtag = await storage.getActiveConfigEtag();
109+
const storedConfigEtag = await storage.getActiveConfigEtag();
99110

100-
expect(storedConfigEtag).to.deep.eq(expectedEtag);
101-
});
111+
expect(storedConfigEtag).to.deep.eq(expectedEtag);
112+
});
102113

103-
it('sets, gets and deletes throttle metadata', async () => {
104-
const expectedMetadata = {
105-
throttleEndTimeMillis: 1
106-
} as ThrottleMetadata;
114+
it(`${name} sets, gets and deletes throttle metadata`, async () => {
115+
const expectedMetadata = {
116+
throttleEndTimeMillis: 1
117+
} as ThrottleMetadata;
107118

108-
await storage.setThrottleMetadata(expectedMetadata);
119+
await storage.setThrottleMetadata(expectedMetadata);
109120

110-
let actualMetadata = await storage.getThrottleMetadata();
121+
let actualMetadata = await storage.getThrottleMetadata();
111122

112-
expect(actualMetadata).to.deep.eq(expectedMetadata);
123+
expect(actualMetadata).to.deep.eq(expectedMetadata);
113124

114-
await storage.deleteThrottleMetadata();
125+
await storage.deleteThrottleMetadata();
115126

116-
actualMetadata = await storage.getThrottleMetadata();
127+
actualMetadata = await storage.getThrottleMetadata();
117128

118-
expect(actualMetadata).to.be.undefined;
119-
});
129+
expect(actualMetadata).to.be.undefined;
130+
});
131+
}
120132
});

0 commit comments

Comments
 (0)