Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions packages/private/test-utils/src/__mocks__/ky.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const i18nextInstanceMock: any = {
language: 'en',
changeLanguage: jest.fn(() => Promise.resolve(undefined)),
on: jest.fn(),
use: jest.fn(() => i18nextInstanceMock),
init: jest.fn(() => Promise.resolve(undefined)),
};

function createMockKyRequestFn() {
return jest.fn(() =>
Promise.resolve({
status: 200,
json: jest.fn(() => Promise.resolve({})),
}),
);
}

export = {
/* Actual exports */

/* Mocks */
get: createMockKyRequestFn(),
};
20 changes: 12 additions & 8 deletions packages/public/network/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"packageManager": "yarn@3.2.4",
"description": "MonkJs core package used to communicate with the API",
"author": "monkvision",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"files": [
"package.json",
"README.md",
Expand All @@ -24,6 +24,15 @@
"lint": "yarn run prettier && yarn run eslint",
"lint:fix": "yarn run prettier:fix && yarn run eslint:fix"
},
"dependencies": {
"jsonwebtoken": "^9.0.2",
"jwt-decode": "^4.0.0",
"ky": "^1.2.0"
},
"peerDependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@monkvision/common": "4.0.0",
"@monkvision/eslint-config-base": "4.0.0",
Expand Down Expand Up @@ -66,10 +75,5 @@
"bugs": {
"url": "https://github.com/monkvision/monkjs/issues"
},
"homepage": "https://github.com/monkvision/monkjs",
"dependencies": {
"axios": "^1.6.2",
"jsonwebtoken": "^9.0.2",
"jwt-decode": "^4.0.0"
}
"homepage": "https://github.com/monkvision/monkjs"
}
10 changes: 7 additions & 3 deletions packages/public/network/src/api/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { AxiosRequestConfig } from 'axios';
import packageJson from '../../package.json';

export const sdkVersion = packageJson.version;
Expand All @@ -17,15 +16,20 @@ export interface MonkAPIConfig {
authToken: string;
}

export function getBaseAxiosConfig(config: MonkAPIConfig): AxiosRequestConfig {
export interface KyConfig {
baseUrl: string;
headers: Record<string, string>;
}

export function getKyConfig(config: MonkAPIConfig): KyConfig {
const apiDomain = config.apiDomain.endsWith('/')
? config.apiDomain.substring(0, config.apiDomain.length - 1)
: config.apiDomain;
const authorizationHeader = config.authToken.startsWith('Bearer ')
? config.authToken
: `Bearer ${config.authToken}`;
return {
baseURL: `https://${apiDomain}`,
baseUrl: `https://${apiDomain}`,
headers: {
'Access-Control-Allow-Origin': '*',
'Authorization': authorizationHeader,
Expand Down
8 changes: 6 additions & 2 deletions packages/public/network/src/api/react.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { useMonkState } from '@monkvision/common';
import {
useMonkState,
MonkAction,
MonkActionType,
MonkUpdateStateAction,
} from '@monkvision/common';
import { Dispatch } from 'react';
import { MonkAction, MonkActionType, MonkUpdateStateAction } from '@monkvision/common/src';
import { MonkAPIConfig } from './config';
import { MonkAPIRequest, MonkAPIResponse } from './requests/types';
import { MonkApi } from './requests';
Expand Down
17 changes: 9 additions & 8 deletions packages/public/network/src/api/requests/inspections/requests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios from 'axios';
import { getBaseAxiosConfig, MonkAPIConfig } from '../../config';
import ky from 'ky';
import { getKyConfig, MonkAPIConfig } from '../../config';
import { MonkAPIRequest } from '../types';
import { ApiInspectionGet } from '../../apiModels';
import { mapGetInspectionResponse } from './mappers';
Expand All @@ -11,15 +11,16 @@ export const getInspection: MonkAPIRequest<[id: string], ApiInspectionGet> = asy
id: string,
config: MonkAPIConfig,
) => {
const axiosResponse = await axios.request<ApiInspectionGet>({
...getBaseAxiosConfig(config),
method: 'get',
url: `/inspections/${id}`,
const { baseUrl, headers } = getKyConfig(config);
const response = await ky.get(`${baseUrl}/inspections/${id}`, {
headers,
});
const body = await response.json<ApiInspectionGet>();
return {
payload: {
entities: mapGetInspectionResponse(axiosResponse.data),
entities: mapGetInspectionResponse(body),
},
axiosResponse,
response,
body,
};
};
9 changes: 6 additions & 3 deletions packages/public/network/src/api/requests/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { AxiosResponse } from 'axios';
import { MonkUpdateStatePayload } from '@monkvision/common';
import { MonkAPIConfig } from '../config';

Expand All @@ -11,9 +10,13 @@ export interface MonkAPIResponse<T> {
*/
payload: MonkUpdateStatePayload;
/**
* The raw response object obtained from Axios when making the request.
* The raw response object obtained from the fetch method when making the request.
*/
axiosResponse: AxiosResponse<T>;
response: Response;
/**
* The body of the response.
*/
body: T;
}

/**
Expand Down
20 changes: 10 additions & 10 deletions packages/public/network/test/api/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import packageJson from '../../package.json';
import { getBaseAxiosConfig, MonkAPIConfig, sdkVersion } from '../../src/api/config';
import { getKyConfig, MonkAPIConfig, sdkVersion } from '../../src/api/config';

describe('Network package API global config utils', () => {
describe('sdkVersion global constant', () => {
Expand All @@ -8,30 +8,30 @@ describe('Network package API global config utils', () => {
});
});

describe('getBaseAxiosConfig function', () => {
describe('getKyConfig function', () => {
const baseConfig: MonkAPIConfig = {
apiDomain: 'testapidomain',
authToken: 'Bearer testtoken',
};

it('should set the baseURL property', () => {
expect(getBaseAxiosConfig(baseConfig)).toEqual(
expect(getKyConfig(baseConfig)).toEqual(
expect.objectContaining({
baseURL: `https://${baseConfig.apiDomain}`,
baseUrl: `https://${baseConfig.apiDomain}`,
}),
);
});

it('should remove the ending slash from the baseURL property', () => {
expect(getBaseAxiosConfig({ ...baseConfig, apiDomain: `${baseConfig.apiDomain}/` })).toEqual(
expect(getKyConfig({ ...baseConfig, apiDomain: `${baseConfig.apiDomain}/` })).toEqual(
expect.objectContaining({
baseURL: `https://${baseConfig.apiDomain}`,
baseUrl: `https://${baseConfig.apiDomain}`,
}),
);
});

it('should set the Access-Control-Allow-Origin header', () => {
expect(getBaseAxiosConfig(baseConfig)).toEqual(
expect(getKyConfig(baseConfig)).toEqual(
expect.objectContaining({
headers: expect.objectContaining({
'Access-Control-Allow-Origin': '*',
Expand All @@ -41,7 +41,7 @@ describe('Network package API global config utils', () => {
});

it('should set the Authorization header', () => {
expect(getBaseAxiosConfig(baseConfig)).toEqual(
expect(getKyConfig(baseConfig)).toEqual(
expect.objectContaining({
headers: expect.objectContaining({
Authorization: baseConfig.authToken,
Expand All @@ -52,7 +52,7 @@ describe('Network package API global config utils', () => {

it('should add the "Bearer " prefix to the token if it is missing', () => {
const authToken = 'testtokentest';
expect(getBaseAxiosConfig({ ...baseConfig, authToken })).toEqual(
expect(getKyConfig({ ...baseConfig, authToken })).toEqual(
expect.objectContaining({
headers: expect.objectContaining({
Authorization: `Bearer ${authToken}`,
Expand All @@ -62,7 +62,7 @@ describe('Network package API global config utils', () => {
});

it('should set the X-Monk-SDK-Version header', () => {
expect(getBaseAxiosConfig(baseConfig)).toEqual(
expect(getKyConfig(baseConfig)).toEqual(
expect.objectContaining({
headers: expect.objectContaining({
'X-Monk-SDK-Version': packageJson.version,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,56 @@
jest.mock('axios', () => ({
request: jest.fn(() => Promise.resolve({ data: { test: 'hello' } })),
}));
import ky, { ResponsePromise } from 'ky';
import { mapGetInspectionResponse } from '../../../../src/api/requests/inspections/mappers';
import { getKyConfig, MonkAPIConfig } from '../../../../src/api/config';
import { getInspection } from '../../../../src/api/requests/inspections';

jest.mock('../../../../src/api/config', () => ({
getBaseAxiosConfig: jest.fn(() => ({ baseUrl: 'test' })),
getKyConfig: jest.fn(() => ({ baseUrl: 'test', headers: { test: 'hello' } })),
}));
jest.mock('../../../../src/api/requests/inspections/mappers', () => ({
mapGetInspectionResponse: jest.fn(() => ({ inspections: [{ id: 'test' }] })),
}));

import axios from 'axios';
import { mapGetInspectionResponse } from '../../../../src/api/requests/inspections/mappers';
import { getBaseAxiosConfig, MonkAPIConfig } from '../../../../src/api/config';
import { getInspection } from '../../../../src/api/requests/inspections';

describe('Inspection requests', () => {
afterEach(() => {
jest.clearAllMocks();
});

describe('getInspection function', () => {
it('should pass the proper params to the axios request', async () => {
it('should pass the proper params to the ky request', async () => {
const id = 'inspection-id-test';
const config: MonkAPIConfig = { apiDomain: 'test', authToken: 'wow' };
await getInspection(id, config);

expect(getBaseAxiosConfig).toHaveBeenCalledWith(config);
expect(axios.request).toHaveBeenCalledWith({
...getBaseAxiosConfig(config),
method: 'get',
url: `/inspections/${id}`,
});
expect(getKyConfig).toHaveBeenCalledWith(config);
expect(ky.get).toHaveBeenCalledWith(
`${getKyConfig({} as MonkAPIConfig).baseUrl}/inspections/${id}`,
{ headers: getKyConfig(config).headers },
);
});

it('should return the ky response', async () => {
const status = 404;
jest.spyOn(ky, 'get').mockImplementationOnce(
() =>
Promise.resolve({
status,
json: () => Promise.resolve({}),
}) as ResponsePromise,
);
const result = await getInspection('test', {} as MonkAPIConfig);
expect(result.response).toEqual(expect.objectContaining({ status }));
});

it('should return the axiosResponse', async () => {
it('should return the response body', async () => {
const body = { hello: 'world' };
jest.spyOn(ky, 'get').mockImplementationOnce(
() =>
Promise.resolve({
json: () => Promise.resolve(body),
}) as ResponsePromise,
);
const result = await getInspection('test', {} as MonkAPIConfig);
expect(result.axiosResponse).toEqual(await (axios.request as jest.Mock)());
expect(result.body).toEqual(body);
});

it('should return the mapped entities', async () => {
Expand Down
26 changes: 13 additions & 13 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3721,7 +3721,7 @@ __metadata:
languageName: unknown
linkType: soft

"@monkvision/network@workspace:packages/public/network":
"@monkvision/network@4.0.0, @monkvision/network@workspace:packages/public/network":
version: 0.0.0-use.local
resolution: "@monkvision/network@workspace:packages/public/network"
dependencies:
Expand All @@ -3737,7 +3737,6 @@ __metadata:
"@types/node": ^18.11.9
"@typescript-eslint/eslint-plugin": ^5.43.0
"@typescript-eslint/parser": ^5.43.0
axios: ^1.6.2
eslint: ^8.29.0
eslint-config-airbnb-base: ^15.0.0
eslint-config-prettier: ^8.5.0
Expand All @@ -3751,12 +3750,16 @@ __metadata:
jest: ^29.3.1
jsonwebtoken: ^9.0.2
jwt-decode: ^4.0.0
ky: ^1.2.0
mkdirp: ^1.0.4
prettier: ^2.7.1
regexpp: ^3.2.0
rimraf: ^3.0.2
ts-jest: ^29.0.3
typescript: ^4.8.4
peerDependencies:
react: ^17.0.2
react-dom: ^17.0.2
languageName: unknown
linkType: soft

Expand Down Expand Up @@ -6713,17 +6716,6 @@ __metadata:
languageName: node
linkType: hard

"axios@npm:^1.6.2":
version: 1.6.2
resolution: "axios@npm:1.6.2"
dependencies:
follow-redirects: ^1.15.0
form-data: ^4.0.0
proxy-from-env: ^1.1.0
checksum: 4a7429e2b784be0f2902ca2680964391eae7236faa3967715f30ea45464b98ae3f1c6f631303b13dfe721b17126b01f486c7644b9ef276bfc63112db9fd379f8
languageName: node
linkType: hard

"axobject-query@npm:^3.1.1":
version: 3.2.1
resolution: "axobject-query@npm:3.2.1"
Expand Down Expand Up @@ -14134,6 +14126,13 @@ __metadata:
languageName: node
linkType: hard

"ky@npm:^1.2.0":
version: 1.2.0
resolution: "ky@npm:1.2.0"
checksum: 10d436364d3e49e0c702adf90dfd0494812ba12853dfc4c1552a13150d769dfe0af339cd105f1076861f35ce1fb242e875858a2adb4fce62de0a5b5c7e9739fa
languageName: node
linkType: hard

"language-subtag-registry@npm:~0.3.2":
version: 0.3.22
resolution: "language-subtag-registry@npm:0.3.22"
Expand Down Expand Up @@ -15216,6 +15215,7 @@ __metadata:
"@monkvision/common-ui-web": 4.0.0
"@monkvision/inspection-capture-web": 4.0.0
"@monkvision/monitoring": 4.0.0
"@monkvision/network": 4.0.0
"@monkvision/sentry": 4.0.0
"@monkvision/sights": 4.0.0
"@monkvision/types": 4.0.0
Expand Down