Skip to content

Commit

Permalink
reorg ts lib as classes, webpack bundle updates, http-client-wrapper (#…
Browse files Browse the repository at this point in the history
…986)

* reorg ts lib as classes, webpack bundle updates, http-client-wrapper

* remove console.logs

* add import change to mocks

* add logic to catch if custom httpClient option utilized in non-lite bundle, also removed some unused bits

* update uuid import and correct usage for clientsessionId, updated specs

* use concurrently and break up build types scripts

* 5.1 version update (#984)

* 5.1 version update

* remove comment

* update Scheduler to webpack 5, node 18 (#990)

* fix for jumbled sorting of exp list for lower and upper case exp names (#991)

* remove auto-merge workflow (#992)

* add smarter response types

* add smarter response types

* fix error handling on bad requests or end of retries

* remove async await from most ApiService calls, can just pass Promise straight through no problem

* get api version from package json and inject via webpack

* add api_version to jest config

* clean up lib tester code, pull in correct versions

* fixed payload type error (#1007) (#1008)

Co-authored-by: Yagnik Hingrajiya <[email protected]>

* try using workflow branch input as commit target in release flow (#1009)

* remove no-assignment logic

---------

Co-authored-by: Ben Blanchard <[email protected]>
Co-authored-by: Pratik Prajapati <[email protected]>
Co-authored-by: Yagnik Hingrajiya <[email protected]>
  • Loading branch information
4 people authored Sep 18, 2023
1 parent ab68afe commit 00b3114
Show file tree
Hide file tree
Showing 45 changed files with 3,411 additions and 2,139 deletions.
1 change: 1 addition & 0 deletions clientlibs/js/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ java/.project
java/.settings
java/target

coverage/
4 changes: 4 additions & 0 deletions clientlibs/js/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ const config: Config.InitialOptions = {
isolatedModules: true,
diagnostics: false,
},
USE_CUSTOM_HTTP_CLIENT: true,
IS_BROWSER: true,
API_VERSION: 5,
},
moduleNameMapper: {
upgrade_types: '<rootDir>/../../types',
},
coverageReporters: ['html'],
};
export default config;
385 changes: 315 additions & 70 deletions clientlibs/js/package-lock.json

Large diffs are not rendered by default.

18 changes: 11 additions & 7 deletions clientlibs/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
],
"scripts": {
"build:bundler": "webpack",
"build:types": "./node_modules/.bin/dts-bundle-generator -o dist/browser/index.d.ts src/index.ts && ./node_modules/.bin/dts-bundle-generator -o dist/node/index.d.ts src/index.ts",
"build:types": "concurrently \"npm:build:types-*\"",
"build:types-browser": "./node_modules/.bin/dts-bundle-generator -o dist/browser/index.d.ts src/index.ts",
"build:types-node": "./node_modules/.bin/dts-bundle-generator -o dist/node/index.d.ts src/index.ts",
"build:types-browser-lite": "./node_modules/.bin/dts-bundle-generator -o dist/browser-lite/index.d.ts src/index.ts",
"build:types-node-lite": "./node_modules/.bin/dts-bundle-generator -o dist/node-lite/index.d.ts src/index.ts",
"build": "npm run clean && npm run build:bundler && npm run build:types",
"build:watch": "tsc -w",
"clean": "rm -rf dist",
Expand All @@ -16,33 +20,33 @@
"prettier:write": "prettier --config ../../.prettierrc './{src, test}/**/*.ts' --write",
"prettier:check": "prettier --config ../../.prettierrc './{src, test}/**/*.ts' --check",
"docs:markdown": "typedoc --options typedoc.json",
"test": "jest"
"test": "jest",
"test:coverage": "jest --coverage"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/isomorphic-fetch": "^0.0.36",
"@types/jest": "^29.2.1",
"@types/node": "^18.11.9",
"@types/uuid": "^9.0.1",
"concurrently": "^8.2.1",
"dts-bundle-generator": "^8.0.1",
"eslint-plugin-tsdoc": "^0.2.17",
"jest": "^29.2.2",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.1",
"ts-node": "^10.9.1",
"tslib": "^2.4.1",
"typedoc": "^0.24.8",
"typedoc-plugin-markdown": "^3.15.4",
"typedoc-plugin-rename-defaults": "^0.6.5",
"typescript": "^4.8.4",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
},
"dependencies": {
"axios": "^1.4.0",
"es6-promise": "^4.2.8",
"eslint-plugin-tsdoc": "^0.2.17",
"typedoc": "^0.24.8",
"typedoc-plugin-markdown": "^3.15.3",
"uuid": "^8.3.2"
}
}
285 changes: 285 additions & 0 deletions clientlibs/js/src/ApiService/ApiService.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
import { CaliperEnvelope } from 'upgrade_types';
import ApiService from './ApiService';
import { UpGradeClientInterfaces } from './../types/Interfaces';
import { UpGradeClientRequests } from './../types/requests';

const MockDataService = {
findExperimentAssignmentBySiteAndTarget: jest.fn(),
rotateAssignmentList: jest.fn(),
};

const mockHttpClient = {
doGet: jest.fn(),
doPost: jest.fn(),
doPatch: jest.fn(),
};

const defaultConfig: UpGradeClientInterfaces.IConfig = {
hostURL: 'test.com',
userId: 'abc123',
context: 'context',
apiVersion: 'v5',
clientSessionId: 'testClientSessionId',
token: 'testToken',
httpClient: mockHttpClient,
};

describe('ApiService', () => {
let apiService: ApiService;

beforeEach(() => {
apiService = new ApiService(defaultConfig, MockDataService as any);
});

// these tests internally call through private methods sendRequest and createOptions...
// the assertion will be that the request body will get mapped to the correct params
// for the http client provided, which is itself mocked and can be spied

describe('#init', () => {
const expectedUrl = `${defaultConfig.hostURL}/api/${defaultConfig.apiVersion}/init`;
const expectedOptions = {
headers: {
'Client-source': 'browser',
'Content-Type': 'application/json',
'Session-Id': 'testClientSessionId',
URL: expectedUrl,
Authorization: 'Bearer testToken',
},
withCredentials: false,
};

it('should call sendRequest with just id', async () => {
const requestBody: UpGradeClientInterfaces.IExperimentUser = {
id: defaultConfig.userId,
};

await apiService.init();

expect(mockHttpClient.doPost).toHaveBeenCalledWith(expectedUrl, requestBody, expectedOptions);
});

it('should call sendRequest with id and group', async () => {
const mockGroup: UpGradeClientInterfaces.IExperimentUserGroup = {
school: ['testGroupSchool'],
};
const requestBody: UpGradeClientInterfaces.IExperimentUser = {
id: defaultConfig.userId,
group: mockGroup,
};

await apiService.init(mockGroup);

expect(mockHttpClient.doPost).toHaveBeenCalledWith(expectedUrl, requestBody, expectedOptions);
});

it('should call sendRequest with id and workingGroup', async () => {
const mockWorkingGroup: UpGradeClientInterfaces.IExperimentUserWorkingGroup = {
school: 'testWorkingGroupSchool',
};
const requestBody: UpGradeClientInterfaces.IExperimentUser = {
id: defaultConfig.userId,
workingGroup: mockWorkingGroup,
};

await apiService.init(undefined, mockWorkingGroup);

expect(mockHttpClient.doPost).toHaveBeenCalledWith(expectedUrl, requestBody, expectedOptions);
});

it('should call sendRequest with id, group, and workingGroup', async () => {
const mockGroup: UpGradeClientInterfaces.IExperimentUserGroup = {
school: ['testGroupSchool'],
};
const mockWorkingGroup: UpGradeClientInterfaces.IExperimentUserWorkingGroup = {
school: 'testWorkingGroupSchool',
};
const requestBody: UpGradeClientInterfaces.IExperimentUser = {
id: defaultConfig.userId,
group: mockGroup,
workingGroup: mockWorkingGroup,
};

await apiService.init(mockGroup, mockWorkingGroup);

expect(mockHttpClient.doPost).toHaveBeenCalledWith(expectedUrl, requestBody, expectedOptions);
});
});

describe('#setGroupMembership', () => {
const expectedUrl = `${defaultConfig.hostURL}/api/${defaultConfig.apiVersion}/groupmembership`;
const expectedOptions = {
headers: {
'Client-source': 'browser',
'Content-Type': 'application/json',
'Session-Id': 'testClientSessionId',
URL: expectedUrl,
Authorization: 'Bearer testToken',
},
withCredentials: false,
};

it('should call sendRequest with id and group', async () => {
const mockGroup: UpGradeClientInterfaces.IExperimentUserGroup = {
school: ['testGroupSchool'],
};
const requestBody: UpGradeClientInterfaces.IExperimentUser = {
id: defaultConfig.userId,
group: mockGroup,
};

await apiService.setGroupMembership(mockGroup);

expect(mockHttpClient.doPatch).toHaveBeenCalledWith(expectedUrl, requestBody, expectedOptions);
});
});

describe('#setWorkingGroup', () => {
//mimic setGroupMembership tests
const expectedUrl = `${defaultConfig.hostURL}/api/${defaultConfig.apiVersion}/workinggroup`;
const expectedOptions = {
headers: {
'Client-source': 'browser',
'Content-Type': 'application/json',
'Session-Id': 'testClientSessionId',
URL: expectedUrl,
Authorization: 'Bearer testToken',
},
withCredentials: false,
};

it('should call sendRequest with id and workingGroup', async () => {
const mockWorkingGroup: UpGradeClientInterfaces.IExperimentUserWorkingGroup = {
school: 'testWorkingGroupSchool',
};
const requestBody: UpGradeClientInterfaces.IExperimentUser = {
id: defaultConfig.userId,
workingGroup: mockWorkingGroup,
};

await apiService.setWorkingGroup(mockWorkingGroup);

expect(mockHttpClient.doPatch).toHaveBeenCalledWith(expectedUrl, requestBody, expectedOptions);
});
});

describe('#setAltUserIds', () => {
const expectedUrl = `${defaultConfig.hostURL}/api/${defaultConfig.apiVersion}/useraliases`;
const expectedOptions = {
headers: {
'Client-source': 'browser',
'Content-Type': 'application/json',
'Session-Id': 'testClientSessionId',
URL: expectedUrl,
Authorization: 'Bearer testToken',
},
withCredentials: false,
};

it('should call sendRequest with id and altUserIds', async () => {
const mockAliases = ['asdf', '1234'];
const requestBody: UpGradeClientRequests.ISetAltIdsRequestBody = {
userId: defaultConfig.userId,
aliases: mockAliases,
};

await apiService.setAltUserIds(mockAliases);

expect(mockHttpClient.doPatch).toHaveBeenCalledWith(expectedUrl, requestBody, expectedOptions);
});
});

describe('#getAllExperimentConditions', () => {
const expectedUrl = `${defaultConfig.hostURL}/api/${defaultConfig.apiVersion}/assign`;
const expectedOptions = {
headers: {
'Client-source': 'browser',
'Content-Type': 'application/json',
'Session-Id': 'testClientSessionId',
URL: expectedUrl,
Authorization: 'Bearer testToken',
},
withCredentials: false,
};

it('should call sendRequest with id and context', async () => {
const requestBody: UpGradeClientRequests.IGetAllExperimentConditionsRequestBody = {
userId: defaultConfig.userId,
context: defaultConfig.context,
};

await apiService.getAllExperimentConditions();

expect(mockHttpClient.doPost).toHaveBeenCalledWith(expectedUrl, requestBody, expectedOptions);
});
});

describe('#log', () => {
const expectedUrl = `${defaultConfig.hostURL}/api/${defaultConfig.apiVersion}/log`;
const expectedOptions = {
headers: {
'Client-source': 'browser',
'Content-Type': 'application/json',
'Session-Id': 'testClientSessionId',
URL: expectedUrl,
Authorization: 'Bearer testToken',
},
withCredentials: false,
};

it('should call sendRequest with userId and logDataInput value', async () => {
const mockLogData = [
{
timestamp: '1234',
metrics: {
attributes: {
testAttribute: 'testValue',
},
groupedMetrics: [
{
groupClass: 'workspaces',
groupKey: 'abc',
groupUniquifier: 'abc123',
attributes: [] as any,
},
],
},
},
];
const mockLogDataInput: UpGradeClientRequests.ILogRequestBody = {
userId: defaultConfig.userId,
value: mockLogData,
};

await apiService.log(mockLogData);

expect(mockHttpClient.doPost).toHaveBeenCalledWith(expectedUrl, mockLogDataInput, expectedOptions);
});
});

describe('#logCaliper', () => {
const expectedUrl = `${defaultConfig.hostURL}/api/${defaultConfig.apiVersion}/log/caliper`;
const expectedOptions = {
headers: {
'Client-source': 'browser',
'Content-Type': 'application/json',
'Session-Id': 'testClientSessionId',
URL: expectedUrl,
Authorization: 'Bearer testToken',
},
withCredentials: false,
};

it('should call sendRequest with caliper envelope value', async () => {
const mockLogData: CaliperEnvelope = {
sensor: 'test',
sendTime: '12345678',
dataVersion: '1',
data: [],
};

await apiService.logCaliper(mockLogData);

expect(mockHttpClient.doPost).toHaveBeenCalledWith(expectedUrl, mockLogData, expectedOptions);
});
});
});
Loading

0 comments on commit 00b3114

Please sign in to comment.