Skip to content

Commit

Permalink
Merge branch 'service_rewrite_2023' into diaryServices-rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
shankari authored Jan 20, 2024
2 parents aa8cbe4 + 8f85e05 commit dfbee1f
Show file tree
Hide file tree
Showing 26 changed files with 1,446 additions and 468 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: code coverage
on:
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review

jobs:
run-codecov:
if: github.event.pull_request.draft == false
runs-on: macos-latest
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2

- name: Setup the serve environment
shell: bash -l {0}
run: |
bash setup/setup_serve.sh
- name: Run Jest tests
shell: bash -l {0}
run: |
source setup/activate_serve.sh
npx jest
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
with:
files: ./coverage/coverage-final.json
flags: unit
fail_ci_if_error: ${{ github.repository == 'e-mission/e-mission-phone' }}

3 changes: 2 additions & 1 deletion .github/workflows/prettier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npx prettier --check www
- run: npx [email protected] --check www


12 changes: 0 additions & 12 deletions .github/workflows/serve-install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,6 @@ jobs:
echo "ionic version"
npx ionic --version
- name: Run Jest tests
shell: bash -l {0}
run: |
npx jest
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
with:
files: ./coverage/coverage-final.json
flags: unit
fail_ci_if_error: ${{ github.repository == 'e-mission/e-mission-phone' }}

# TODO: figure out how to check that a server started correctly
# - name: Try starting it
# run: npx run serve
Expand Down
24 changes: 21 additions & 3 deletions setup/setup_ios_native.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,32 @@ source setup/setup_shared.sh
OSX_MAJOR_VERSION=`sw_vers | grep ProductVersion | cut -d ':' -f 2 | cut -d '.' -f 1`
echo "Found OSX major version" $OSX_MAJOR_VERSION

# The Homebrew pac-man is installed in different locations, depending on whether the processor
# is an Intel or Apple Silicone chip. Intel uses x86_64, Apple chips are amd64, so we can
# check the chip type using these hardware platforms.
CHIP_ARC=`uname -m`
INTEL="x86_64"
APPLE_SILICONE="arm64"
WORKING_DIR=""

if [ $CHIP_ARC == $INTEL ]; then
echo "Found "$INTEL" chip"
WORKING_DIR="/usr/local/"
else
if [ $CHIP_ARC == $APPLE_SILICONE ]; then
echo "Found "$APPLE_SILICONE" chip"
WORKING_DIR="/opt/homebrew/"
fi
fi

CURR_RUBY_VERSION=`ruby --version | cut -d ' ' -f 2 | cut -d '.' -f 1-2`
echo "Found ruby version "$CURR_RUBY_VERSION

if [ $CURR_RUBY_VERSION == $RUBY_VERSION ]; then
echo "Found ruby version "$CURR_RUBY_VERSION" expected "$RUBY_VERSION" no need to upgrade"
else
if [ -x /usr/local/bin/brew ]; then
echo "Found brew installation with version" `/usr/local/bin/brew --version`
if [ -x "${WORKING_DIR}/bin/brew" ]; then
echo "Found brew installation with version" ` brew --version`
echo "Installing ruby version to brew" $RUBY_VERSION
brew install ruby@$RUBY_VERSION
else
Expand All @@ -32,6 +50,6 @@ echo "Adding $RUBY_PATH to the path before the install"
export PATH=$RUBY_PATH:$PATH

echo "Installing cocoapods"
/usr/local/opt/ruby@$RUBY_VERSION/bin/gem install --no-document --user-install cocoapods -v $COCOAPODS_VERSION
${WORKING_DIR}/opt/ruby@$RUBY_VERSION/bin/gem install --no-document --user-install cocoapods -v $COCOAPODS_VERSION

source setup/setup_shared_native.sh
24 changes: 22 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 All @@ -8,6 +7,16 @@ export const mockCordova = () => {
window['cordova'].plugins ||= {};
};

export const mockReminders = () => {
window['cordova'] ||= {};
window['cordova'].plugins ||= {};
window['cordova'].plugins.notification ||= {};
window['cordova'].plugins.notification.local ||= {};
window['cordova'].plugins.notification.local.getScheduled ||= () => [];
window['cordova'].plugins.notification.local.cancelAll ||= () => {};
window['cordova'].plugins.notification.local.schedule ||= () => {};
};

export const mockDevice = () => {
window['device'] ||= {};
window['device'].platform ||= 'ios';
Expand All @@ -29,6 +38,7 @@ export const mockFile = () => {
window['cordova'].file = {
dataDirectory: '../path/to/data/directory',
applicationStorageDirectory: '../path/to/app/storage/directory',
tempDirectory: '../path/to/temp/directory',
};
};

Expand Down Expand Up @@ -119,13 +129,23 @@ export const mockBEMUserCache = (config?) => {
}, 100),
);
// Used for getUnifiedDataForInterval
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
7 changes: 7 additions & 0 deletions www/__mocks__/fileSystemMocks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export const mockFileSystem = () => {
type MockFileWriter = {
onreadend: any;
onerror: (e: any) => void;
write: (obj: Blob) => void;
};
window['resolveLocalFileSystemURL'] = function (parentDir, handleFS) {
const fs = {
filesystem: {
Expand All @@ -9,6 +14,8 @@ export const mockFileSystem = () => {
let file = new File(['this is a mock'], 'loggerDB');
handleFile(file);
},
nativeURL: 'file:///Users/Jest/test/URL/',
isFile: true,
};
onSuccess(fileEntry);
},
Expand Down
6 changes: 6 additions & 0 deletions www/__mocks__/globalMocks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export const mockLogger = () => {
window['Logger'] = { log: console.log };
window.alert = (msg) => {
console.log(msg);
};
console.error = (msg) => {
console.log(msg);
};
};

let alerts = [];
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);
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

0 comments on commit dfbee1f

Please sign in to comment.