Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Fix AppConfig survey_info backwards compat + add tests for dynamicConfig #1115

14 changes: 12 additions & 2 deletions www/__mocks__/cordovaMocks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import packageJsonBuild from '../../package.cordovabuild.json';
import fakeConfig from './fakeConfig.json';

export const mockCordova = () => {
window['cordova'] ||= {};
Expand Down Expand Up @@ -101,12 +100,23 @@ export const mockBEMUserCache = (config?) => {
}, 100),
);
},
putRWDocument: (key: string, value: any) => {
if (key == 'config/app_ui_config') {
return new Promise<void>((rs, rj) =>
setTimeout(() => {
config = value;
rs();
}, 100),
);
}
},
getDocument: (key: string, withMetadata?: boolean) => {
//returns the config provided as a paramenter to this mock!
if (key == 'config/app_ui_config') {
return new Promise<any>((rs, rj) =>
setTimeout(() => {
rs(config || fakeConfig);
if (config) rs(config);
else rs({}); // return empty object if config is not set
}, 100),
);
} else {
Expand Down
3 changes: 2 additions & 1 deletion www/__tests__/customMetricsHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import {
import { mockBEMUserCache } from '../__mocks__/cordovaMocks';
import { mockLogger } from '../__mocks__/globalMocks';
import fakeLabels from '../__mocks__/fakeLabels.json';
import fakeConfig from '../__mocks__/fakeConfig.json';

mockBEMUserCache();
mockBEMUserCache(fakeConfig);
mockLogger();

global.fetch = (url: string) =>
Expand Down
134 changes: 134 additions & 0 deletions www/__tests__/dynamicConfig.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { mockBEMUserCache } from '../__mocks__/cordovaMocks';
import { mockAlert, mockLogger } from '../__mocks__/globalMocks';
import { getConfig, initByUser } from '../js/config/dynamicConfig';

import initializedI18next from '../js/i18nextInit';
import { storageClear } from '../js/plugin/storage';
window['i18next'] = initializedI18next;

mockLogger();
mockAlert();
mockBEMUserCache();

beforeEach(() => {
// clear all storage and the config document
storageClear({ local: true, native: true });
window['cordova'].plugins.BEMUserCache.putRWDocument('config/app_ui_config', {});
});

const nrelCommuteConfig = {
version: 1,
server: {
connectUrl: 'https://nrel-commute-openpath.nrel.gov/api/',
aggregate_call_auth: 'user_only',
},
// ...
};

const denverCasrConfig = {
version: 1,
server: {
connectUrl: 'https://denver-casr-openpath.nrel.gov/api/',
aggregate_call_auth: 'user_only',
},
opcode: {
autogen: true,
subgroups: [
'test',
'qualified-cargo',
'qualified-regular',
'standard-cargo',
'standard-regular',
],
},
// ...
};

global.fetch = (url: string) => {
return new Promise((rs, rj) => {
if (url.includes('nrel-commute.nrel-op.json')) {
rs({
ok: true,
json: () => new Promise((rs, rj) => rs(nrelCommuteConfig)),
});
} else if (url.includes('denver-casr.nrel-op.json')) {
rs({
ok: true,
json: () => new Promise((rs, rj) => rs(denverCasrConfig)),
});
} else {
rj(new Error('404 while fetching ' + url));
}
}) as any;
};

describe('dynamicConfig', () => {
const fakeStudyName = 'gotham-city-transit';
const validStudyNrelCommute = 'nrel-commute';
const validStudyDenverCasr = 'denver-casr';

describe('getConfig', () => {
it('should resolve with null since no config is set yet', async () => {
await expect(getConfig()).resolves.toBeNull();
});
it('should resolve with a valid config once initByUser is called for an nrel-commute token', async () => {
const validToken = `nrelop_${validStudyNrelCommute}_user1`;
await initByUser({ token: validToken });
const config = await getConfig();
expect(config.server.connectUrl).toBe('https://nrel-commute-openpath.nrel.gov/api/');
expect(config.joined).toEqual({
opcode: validToken,
study_name: validStudyNrelCommute,
subgroup: undefined,
});
});

it('should resolve with a valid config once initByUser is called for a denver-casr token', async () => {
const validToken = `nrelop_${validStudyDenverCasr}_test_user1`;
await initByUser({ token: validToken });
const config = await getConfig();
expect(config.server.connectUrl).toBe('https://denver-casr-openpath.nrel.gov/api/');
expect(config.joined).toEqual({
opcode: validToken,
study_name: validStudyDenverCasr,
subgroup: 'test',
});
});
});

describe('initByUser', () => {
// fake study (gotham-city-transit)
it('should error if the study is nonexistent', async () => {
const fakeBatmanToken = `nrelop_${fakeStudyName}_batman`;
await expect(initByUser({ token: fakeBatmanToken })).rejects.toThrow();
});

// real study without subgroups (nrel-commute)
it('should error if the study exists but the token is invalid format', async () => {
const badToken1 = validStudyNrelCommute; // doesn't start with nrelop_
await expect(initByUser({ token: badToken1 })).rejects.toThrow();
const badToken2 = `nrelop_${validStudyNrelCommute}`; // doesn't have enough _
await expect(initByUser({ token: badToken2 })).rejects.toThrow();
const badToken3 = `nrelop_${validStudyNrelCommute}_`; // doesn't have user code after last _
await expect(initByUser({ token: badToken3 })).rejects.toThrow();
});
it('should return true after successfully storing the config for a valid token', async () => {
const validToken = `nrelop_${validStudyNrelCommute}_user2`;
await expect(initByUser({ token: validToken })).resolves.toBe(true);
});

// real study with subgroups (denver-casr)
it('should error if the study uses subgroups but the token has no subgroup', async () => {
const tokenWithoutSubgroup = `nrelop_${validStudyDenverCasr}_user2`;
await expect(initByUser({ token: tokenWithoutSubgroup })).rejects.toThrow();
});
it('should error if the study uses subgroups and the token is invalid format', async () => {
const badToken1 = `nrelop_${validStudyDenverCasr}_test_`; // doesn't have user code after last _
await expect(initByUser({ token: badToken1 })).rejects.toThrow();
});
it('should return true after successfully storing the config for a valid token with subgroup', async () => {
const validToken = `nrelop_${validStudyDenverCasr}_test_user2`;
await expect(initByUser({ token: validToken })).resolves.toBe(true);
});
});
});
4 changes: 2 additions & 2 deletions www/__tests__/enketoHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '../js/survey/enketo/enketoHelper';
import { mockBEMUserCache } from '../__mocks__/cordovaMocks';
import { mockLogger } from '../__mocks__/globalMocks';
import { getConfig, resetStoredConfig } from '../../www/js/config/dynamicConfig';
import { getConfig, _test_resetStoredConfig } from '../../www/js/config/dynamicConfig';
import fakeConfig from '../__mocks__/fakeConfig.json';

import initializedI18next from '../js/i18nextInit';
Expand All @@ -21,7 +21,7 @@ global.URL = require('url').URL;
global.Blob = require('node:buffer').Blob;

beforeEach(() => {
resetStoredConfig();
_test_resetStoredConfig();
});

it('gets the survey config', async () => {
Expand Down
3 changes: 2 additions & 1 deletion www/__tests__/footprintHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { getConfig } from '../js/config/dynamicConfig';
import { mockBEMUserCache } from '../__mocks__/cordovaMocks';
import { mockLogger } from '../__mocks__/globalMocks';
import fakeLabels from '../__mocks__/fakeLabels.json';
import fakeConfig from '../__mocks__/fakeConfig.json';

mockBEMUserCache();
mockBEMUserCache(fakeConfig);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not your change, but I would like to understand this better. Why do we pass in the config instead of calling putRWDocument

mockLogger();

global.fetch = (url: string) =>
Expand Down
3 changes: 2 additions & 1 deletion www/__tests__/metHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { mockLogger } from '../__mocks__/globalMocks';
import fakeLabels from '../__mocks__/fakeLabels.json';
import { getConfig } from '../js/config/dynamicConfig';
import { initCustomDatasetHelper } from '../js/metrics/customMetricsHelper';
import fakeConfig from '../__mocks__/fakeConfig.json';

mockBEMUserCache();
mockBEMUserCache(fakeConfig);
mockLogger();

global.fetch = (url: string) =>
Expand Down
Loading
Loading