Skip to content

Commit dd365b4

Browse files
committed
test(remote-config): re-enable onConfigUpdated tests
they should handle multiple parallel e2e test runs without blowing up now, so we can hammer on the e2e suite without having to disable these
1 parent b891b54 commit dd365b4

File tree

1 file changed

+93
-73
lines changed

1 file changed

+93
-73
lines changed

packages/remote-config/e2e/config.e2e.js

Lines changed: 93 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ describe('remoteConfig()', function () {
8181
});
8282

8383
describe('setConfigSettings()', function () {
84-
// TODO: flakey in jet e2e tests
8584
xit('minimumFetchIntervalMillis sets correctly', async function () {
8685
await firebase.remoteConfig().setConfigSettings({ minimumFetchIntervalMillis: 3000 });
8786

@@ -430,8 +429,7 @@ describe('remoteConfig()', function () {
430429
});
431430

432431
describe('setConfigSettings()', function () {
433-
// TODO flakey in jet e2e tests
434-
xit('minimumFetchIntervalMillis sets correctly', async function () {
432+
it('minimumFetchIntervalMillis sets correctly', async function () {
435433
const { getRemoteConfig, setConfigSettings } = remoteConfigModular;
436434
const remoteConfig = getRemoteConfig();
437435
await setConfigSettings(remoteConfig, { minimumFetchIntervalMillis: 3000 });
@@ -734,56 +732,89 @@ describe('remoteConfig()', function () {
734732
});
735733
});
736734

737-
xdescribe('onConfigUpdated on supported platforms', function () {
735+
describe('onConfigUpdated on supported platforms', function () {
738736
if (Platform.other) {
739737
// Not supported on Web
740738
return;
741739
}
742740

743741
let unsubscribers = [];
742+
const timestamp = '_pls_rm_if_day_old_' + Date.now();
743+
744+
// We may get more than one callback if other e2e suites run parallel.
745+
// But we have a specific parameter values, and we should only get one callback
746+
// where the updatedKeys have a given parameter value.
747+
// This verifier factory checks for that specific param name in updatedKeys, not a call count.
748+
const getVerifier = function (paramName) {
749+
return spy => {
750+
if (!spy.called) return false;
751+
for (let i = 0; i < spy.callCount; i++) {
752+
const callbackEvent = spy.getCall(i).args[0];
753+
if (callbackEvent.updatedKeys && callbackEvent.updatedKeys.includes(paramName)) {
754+
return true;
755+
}
756+
}
757+
758+
return false;
759+
};
760+
};
744761

745762
before(async function () {
746763
// configure a listener so any new templates are fetched and cached locally
747-
const { fetchAndActivate, getRemoteConfig, onConfigUpdated } = remoteConfigModular;
764+
const { fetchAndActivate, getAll, getRemoteConfig, onConfigUpdated } = remoteConfigModular;
748765
const unsubscribe = onConfigUpdated(getRemoteConfig(), () => {});
749766

750-
// clear out old test data
751-
const response = await updateTemplate({
752-
operations: {
753-
delete: ['rttest_param1', 'rttest_param2', 'rttest_param3'],
754-
},
755-
});
756-
should(response.result !== undefined).equal(true, 'response result not defined');
757-
// console.error('before updateTemplate version: ' + response.result.templateVersion);
758-
759767
// activate to make sure all values are in effect,
760768
// thus realtime updates only shows our testing work
769+
await fetchAndActivate(getRemoteConfig());
770+
771+
// Check for any test param > 1hr old from busted test runs
772+
const originalValues = getAll(getRemoteConfig());
773+
const staleDeletes = [];
774+
Object.keys(originalValues).forEach(param => {
775+
if (param.includes('_pls_rm_if_day_old_')) {
776+
let paramMillis = Number.parseInt(param.slice(param.lastIndexOf('_') + 1), 10);
777+
if (paramMillis < Date.now() - 1000 * 60 * 60) {
778+
staleDeletes.push(param);
779+
}
780+
}
781+
});
782+
783+
// If there is orphaned data, delete it on the server and let that settle
784+
if (staleDeletes.length > 0) {
785+
const response = await updateTemplate({
786+
operations: {
787+
delete: staleDeletes,
788+
},
789+
});
790+
should(response.result !== undefined).equal(true, 'response result not defined');
791+
await Utils.sleep(1000);
792+
}
793+
761794
await fetchAndActivate(getRemoteConfig());
762795
unsubscribe();
763796
});
764797

765798
after(async function () {
799+
// clean up our own test data after the whole suite runs
766800
const response = await updateTemplate({
767801
operations: {
768-
delete: ['rttest_param1', 'rttest_param2', 'rttest_param3'],
802+
delete: ['rttest1' + timestamp, 'rttest2' + timestamp, 'rttest3' + timestamp],
769803
},
770804
});
771805
should(response.result !== undefined).equal(true, 'response result not defined');
772806
// console.error('after updateTemplate version: ' + response.result.templateVersion);
773807
});
774808

775809
afterEach(async function () {
810+
// make sure all our callbacks are unsubscribed after each test - convenient
776811
for (let i = 0; i < unsubscribers.length; i++) {
777812
unsubscribers[i]();
778813
}
779814
unsubscribers = [];
780815
});
781816

782-
// TODO:
783-
// native listener emits, so verifying native listener count is same as counting callback events
784-
// - so main idea is to focus on callback counts and make sure they are exactly as expected
785-
// TODO: flakey in Jet e2e
786-
xit('adds a listener and receives updates', async function () {
817+
it('adds a listener and receives updates', async function () {
787818
// Configure our listener
788819
const { fetchAndActivate, getRemoteConfig, onConfigUpdated } = remoteConfigModular;
789820
const config = getRemoteConfig();
@@ -794,28 +825,21 @@ describe('remoteConfig()', function () {
794825
// Update the template using our cloud function, so our listeners are called
795826
let response = await updateTemplate({
796827
operations: {
797-
add: [{ name: 'rttest_param1', value: Date.now() + '' }],
828+
add: [{ name: 'rttest1' + timestamp, value: timestamp }],
798829
},
799830
});
800831
should(response.result !== undefined).equal(true, 'response result not defined');
801832

802833
// Assert: we were called exactly once with expected update event contents
803-
await Utils.spyToBeCalledTimesAsync(callback, 1, 60000);
804-
should(callback.callCount).equal(1);
805-
let callbackError = callback.getCall(0).args[1];
806-
should(callbackError).equal(undefined, 'error ' + JSON.stringify(callbackError));
807-
let callbackEvent = callback.getCall(0).args[0];
808-
should(callbackEvent.updatedKeys.includes('rttest_param1')).equal(
809-
true,
810-
'updated param not in callback updated keys set',
834+
await Utils.spyToBeCalledWithVerifierAsync(
835+
callback,
836+
getVerifier('rttest1' + timestamp),
837+
60000,
811838
);
812839
unsubscribe();
813840
});
814841

815-
// TODO: flakey in Jet e2e, are we not clearing out old listeners properly?
816-
// AssertionError: expected 16 to be 2 at:
817-
// should(callbackEvent.updatedKeys.length).equal(2);
818-
xit('manages multiple listeners', async function () {
842+
it('manages multiple listeners', async function () {
819843
const { fetchAndActivate, getRemoteConfig, onConfigUpdated } = remoteConfigModular;
820844
const config = getRemoteConfig();
821845

@@ -836,77 +860,73 @@ describe('remoteConfig()', function () {
836860
// Trigger an update that should call them all
837861
let response = await updateTemplate({
838862
operations: {
839-
add: [{ name: 'rttest_param1', value: Date.now() + '' }],
863+
add: [{ name: 'rttest1' + timestamp, value: Date.now() + '' }],
840864
},
841865
});
842866
should(response.result !== undefined).equal(true, 'response result not defined');
843867

844868
// Assert all were called with expected values
845-
await Utils.spyToBeCalledTimesAsync(callback1, 1, 60000);
846-
await Utils.spyToBeCalledTimesAsync(callback2, 1, 60000);
847-
await Utils.spyToBeCalledTimesAsync(callback3, 1, 60000);
848-
[callback1, callback2, callback3].forEach(callback => {
849-
should(callback.callCount).equal(1);
850-
should(callback.getCall(0).args[1]).equal(
851-
undefined,
852-
'error ' + JSON.stringify(callback.getCall(0).args[1]),
853-
);
854-
let callbackEvent = callback.getCall(0).args[0];
855-
should(callbackEvent.updatedKeys.length).equal(1);
856-
should(callbackEvent.updatedKeys.includes('rttest_param1')).equal(
857-
true,
858-
'updated param not in callback updated keys set',
859-
);
860-
});
869+
await Utils.spyToBeCalledWithVerifierAsync(
870+
callback1,
871+
getVerifier('rttest1' + timestamp),
872+
60000,
873+
);
874+
await Utils.spyToBeCalledWithVerifierAsync(
875+
callback2,
876+
getVerifier('rttest1' + timestamp),
877+
60000,
878+
);
879+
await Utils.spyToBeCalledWithVerifierAsync(
880+
callback3,
881+
getVerifier('rttest1' + timestamp),
882+
60000,
883+
);
861884

862885
// Unsubscribe second listener and repeat, this time expecting no call on second listener
863886
unsubscribe2();
887+
const callback2Count = callback2.callCount;
864888

865-
// Trigger update that should call listener 1 and 3
889+
// Trigger update that should call listener 1 and 3 for these values
866890
response = await updateTemplate({
867891
operations: {
868-
add: [{ name: 'rttest_param2', value: Date.now() + '' }],
892+
add: [{ name: 'rttest2' + timestamp, value: Date.now() + '' }],
869893
},
870894
});
871895
should(response.result !== undefined).equal(true, 'response result not defined');
872896

873897
// Assert first and third were called with expected values
874-
await Utils.spyToBeCalledTimesAsync(callback1, 2, 60000);
875-
await Utils.spyToBeCalledTimesAsync(callback3, 2, 60000);
898+
await Utils.spyToBeCalledWithVerifierAsync(
899+
callback1,
900+
getVerifier('rttest2' + timestamp),
901+
60000,
902+
);
903+
await Utils.spyToBeCalledWithVerifierAsync(
904+
callback3,
905+
getVerifier('rttest2' + timestamp),
906+
60000,
907+
);
876908

877909
// callback2 should not have been called again - same call count expected
878-
should(callback2.callCount).equal(1);
879-
880-
// assert callback 1 and 3 have new information
881-
[callback1, callback3].forEach(callback => {
882-
should(callback.callCount).equal(2);
883-
should(callback.getCall(1).args[1]).equal(
884-
undefined,
885-
'error ' + JSON.stringify(callback.getCall(1).args[1]),
886-
);
887-
let callbackEvent = callback.getCall(1).args[0];
888-
should(callbackEvent.updatedKeys.length).equal(2);
889-
should(callbackEvent.updatedKeys.includes('rttest_param2')).equal(
890-
true,
891-
'updated param not in callback updated keys set',
892-
);
893-
});
910+
should(callback2.callCount).equal(callback2Count);
894911

895912
// Unsubscribe remaining listeners
896913
unsubscribe1();
897914
unsubscribe3();
915+
const callback1Count = callback1.callCount;
916+
const callback3Count = callback3.callCount;
898917

899918
// Trigger an update that should call no listeners
900919
response = await updateTemplate({
901920
operations: {
902-
add: [{ name: 'rttest_param3', value: Date.now() + '' }],
921+
add: [{ name: 'rttest3' + timestamp, value: Date.now() + '' }],
903922
},
904923
});
905924
should(response.result !== undefined).equal(true, 'response result not defined');
906925
// Give the servers plenty of time to call us
907926
await Utils.sleep(20000);
908-
should(callback1.callCount).equal(2);
909-
should(callback3.callCount).equal(2);
927+
should(callback1.callCount).equal(callback1Count);
928+
should(callback2.callCount).equal(callback2Count);
929+
should(callback3.callCount).equal(callback3Count);
910930
});
911931

912932
// - react-native reload

0 commit comments

Comments
 (0)