Skip to content

Commit bcb6151

Browse files
authored
Merge branch 'main' into hotfix/fix-users-url
2 parents 47b94af + a528b8f commit bcb6151

12 files changed

+2084
-1590
lines changed

jest.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ module.exports = {
99
collectCoverageFrom: ['<rootDir>/src/**/*.js'],
1010
coveragePathIgnorePatterns: ['/node_modules/'],
1111
coverageReporters: ['text'],
12-
testEnvironment: 'jsdom'
12+
testEnvironment: 'jsdom',
13+
restoreMocks: true
1314
//TODO: Uncomment and determine thresholds
1415
// Certain areas can have different thresholds
1516
// https://jestjs.io/docs/configuration#coveragethreshold-object

jest.setupAfterEnv.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
// clear the mock.calls and mock.instances prperties of all mocks
2-
// eslint-disable-next-line no-undef
3-
global.afterEach(() => jest.clearAllMocks())
42
global.beforeAll(() => {
53
// eslint-disable-next-line no-undef
64
const createObjectURL = jest.fn()

package-lock.json

Lines changed: 1837 additions & 1577 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"lint": "eslint .",
1313
"lint:fix": "eslint --fix --ext .js .",
1414
"precommit": "npm run lint",
15-
"prepare": "concurrently \"npm run husky:install\" \"npm run co:login\"",
15+
"prepare": "npm run husky:install",
1616
"test": "jest --silent"
1717
},
1818
"main": "lib/cb-api-helper.js",
@@ -31,13 +31,14 @@
3131
"@babel/plugin-transform-runtime": "^7.17.0",
3232
"@babel/preset-env": "^7.16.11",
3333
"@babel/preset-typescript": "^7.16.7",
34-
"babel-jest": "^27.5.1",
34+
"babel-jest": "^29.2.2",
3535
"babel-loader": "^8.2.3",
3636
"concurrently": "^7.0.0",
3737
"eslint": "^8.8.0",
3838
"eslint-config-prettier": "^8.3.0",
3939
"husky": "^7.0.4",
40-
"jest": "^27.5.1",
40+
"jest": "^29.2.2",
41+
"jest-environment-jsdom": "^29.2.2",
4142
"jsdoc": "~3.6.10",
4243
"prettier": "^2.5.1",
4344
"pretty-quick": "^3.1.3",

src/api/crudOperations.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ const getMultipleEntities = async (
117117

118118
//responsefield might be set to something like 'dashboard/groups' and we just want 'groups'
119119
if (responseField.includes('/')) {
120-
responseField = responseField.substring(responseField.lastIndexOf('/') + 1)
120+
// This will get `users` from `/users/` or `/users`
121+
responseField = responseField.split('/').filter(Boolean).slice(-1)[0]
121122
}
122123

123124
try {

src/api/crudOperations.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ describe('crud', () => {
298298
})
299299

300300
it('catches error and throws it by default', async () => {
301-
jest.spyOn(baseApi, 'patch').mockRejectedValue(simpleError)
301+
jest.spyOn(baseApi, 'put').mockRejectedValue(simpleError)
302302

303303
try {
304304
await crud.updateItemById(testEndpoint, testId, testPayload)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import crud from '../../../crudOperations'
2+
3+
const URL = 'v3/cmp/histories'
4+
5+
export default {
6+
/**
7+
* Retrieve a list of existing histories
8+
* @param options anything parsable by URLSearchParams. See useful options here https://docs.cloudbolt.io/articles/#!cloudbolt-latest-docs/api-conventions/a/h2__904191799
9+
* @returns {Promise} resolves with a list of all Histories
10+
*/
11+
list: (options) => crud.getItems(URL, options),
12+
13+
/**
14+
* Retrieve an existing history
15+
* @param {string} id or global_id
16+
* @param options anything parsable by URLSearchParams. See useful options here https://docs.cloudbolt.io/articles/#!cloudbolt-latest-docs/api-conventions/a/h2__904191799
17+
* @returns {Promise} resolves with a cloudbolt API Response object of the History object
18+
*/
19+
get: (id, options) => crud.getItemById(URL, id, options)
20+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import { baseApi } from '../../../baseApi'
2+
import HistoriesService from './HistoriesService'
3+
4+
const mockListResponse = {
5+
_links: {
6+
self: {
7+
href: '/api/v3/cmp/histories/?page=1&page_size=2',
8+
title: 'List of Histories - Page 1 of 111'
9+
},
10+
next: {
11+
href: '/api/v3/cmp/histories/?page=2&page_size=2',
12+
title: 'Next List Page'
13+
}
14+
},
15+
total: 221,
16+
count: 2,
17+
_embedded: {
18+
histories: [
19+
{
20+
_links: {
21+
self: {
22+
href: '/api/v3/cmp/histories/HIS-255ugi0f/',
23+
title: ''
24+
},
25+
owner: {},
26+
job: {},
27+
server: {},
28+
resourceAction: {},
29+
serverAction: {},
30+
environment: {},
31+
order: {}
32+
},
33+
id: 'HIS-255ugi0f',
34+
eventMessage: 'An alert has been requested to be sent',
35+
eventType: 'SENT',
36+
actionTime: '2022-11-04 23:39:10.866753',
37+
rateChange: null,
38+
historyType: 'alerthistory',
39+
jobId: null,
40+
serverId: null,
41+
resourceId: null,
42+
serverActionId: null,
43+
resourceActionId: null,
44+
environmentId: null,
45+
orderId: null,
46+
serverPowerStatus: null
47+
},
48+
{
49+
_links: {
50+
self: {
51+
href: '/api/v3/cmp/histories/HIS-iy5r0duf/',
52+
title: 'experience_eCIT_10'
53+
},
54+
owner: {},
55+
job: {
56+
href: '/api/v3/cmp/jobs/JOB-f62k4gru/',
57+
title: 'Synchronize VMs from vCenter Job 344'
58+
},
59+
server: {
60+
href: '/api/v3/cmp/servers/SVR-byvtcaee/',
61+
title: 'experience_eCIT_10'
62+
},
63+
resourceAction: {},
64+
serverAction: {},
65+
environment: {},
66+
order: {}
67+
},
68+
id: 'HIS-iy5r0duf',
69+
eventMessage:
70+
" Server record set to historical because its VM can no longer be found on resource handler 'VMware vCenter'",
71+
eventType: 'DECOMMISSION',
72+
actionTime: '2022-11-04 19:32:23.021371',
73+
rateChange: '0E-10',
74+
historyType: 'serverhistory',
75+
jobId: 'JOB-f62k4gru',
76+
serverId: 'SVR-byvtcaee',
77+
resourceId: null,
78+
serverActionId: null,
79+
resourceActionId: null,
80+
environmentId: null,
81+
orderId: null,
82+
serverPowerStatus: 'POWEROFF'
83+
}
84+
]
85+
}
86+
}
87+
88+
const mockGetResponse = {
89+
_links: {
90+
self: {
91+
href: '/api/v3/cmp/histories/HIS-iy5r0duf/',
92+
title: 'experience_eCIT_10'
93+
},
94+
owner: {},
95+
job: {
96+
href: '/api/v3/cmp/jobs/JOB-f62k4gru/',
97+
title: 'Synchronize VMs from vCenter Job 344'
98+
},
99+
server: {
100+
href: '/api/v3/cmp/servers/SVR-byvtcaee/',
101+
title: 'experience_eCIT_10'
102+
},
103+
resourceAction: {},
104+
serverAction: {},
105+
environment: {},
106+
order: {}
107+
},
108+
id: 'HIS-iy5r0duf',
109+
eventMessage:
110+
" Server record set to historical because its VM can no longer be found on resource handler 'VMware vCenter'",
111+
eventType: 'DECOMMISSION',
112+
actionTime: '2022-11-04 19:32:23.021371',
113+
rateChange: '0E-10',
114+
historyType: 'serverhistory',
115+
jobId: 'JOB-f62k4gru',
116+
serverId: 'SVR-byvtcaee',
117+
resourceId: null,
118+
serverActionId: null,
119+
resourceActionId: null,
120+
environmentId: null,
121+
orderId: null,
122+
serverPowerStatus: 'POWEROFF'
123+
}
124+
125+
test('list calls the correct endpoint', async () => {
126+
const mockFn = jest.spyOn(baseApi, 'get').mockResolvedValue({
127+
data: [{ hello: 'world' }]
128+
})
129+
await HistoriesService.list()
130+
expect(mockFn).toHaveBeenCalledWith('/v3/cmp/histories/')
131+
})
132+
133+
test('list parses data without issue', async () => {
134+
jest.spyOn(baseApi, 'get').mockResolvedValue({
135+
data: mockListResponse
136+
})
137+
const result = await HistoriesService.list()
138+
expect(result.items).toEqual(mockListResponse._embedded.histories)
139+
})
140+
141+
test('get calls the correct endpoint', async () => {
142+
const mockFn = jest.spyOn(baseApi, 'get').mockResolvedValue({
143+
data: { hello: 'world' }
144+
})
145+
await HistoriesService.get('history-id')
146+
expect(mockFn).toHaveBeenCalledWith('/v3/cmp/histories/history-id/')
147+
})
148+
149+
test('get parses data without issue', async () => {
150+
jest.spyOn(baseApi, 'get').mockResolvedValue({
151+
data: mockGetResponse
152+
})
153+
const result = await HistoriesService.get('history-id')
154+
expect(result).toEqual(mockGetResponse)
155+
})

src/api/services/v3/cmp/ResourcesStructuredService.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ const URL = 'v3/cmp/resourcesStructured'
55
export default {
66
/**
77
* Retrieve a list of existing Structured Resources
8-
* @param options anything parsable by URLSearchParams. See useful options here https://docs.cloudbolt.io/articles/#!cloudbolt-latest-docs/api-conventions/a/h2__904191799
8+
* @param {Object} options anything parsable by URLSearchParams. See useful options here https://docs.cloudbolt.io/articles/#!cloudbolt-latest-docs/api-conventions/a/h2__904191799
99
* @returns {Promise} resolves with a list of existing Structured Resources
1010
*/
1111
list: (options) => crud.getItems(URL, options),
1212

1313
/**
1414
* Retrieve an existing Structured Resource by idd
1515
* @param {string} id or global_id
16+
* @param {Object} options anything parsable by URLSearchParams. See useful options here https://docs.cloudbolt.io/articles/#!cloudbolt-latest-docs/api-conventions/a/h2__904191799
1617
* @returns {Promise} resolves with a cloudbolt API Response object of the Structured Resource object
1718
*/
18-
get: (id) => crud.getItemById(URL, id)
19+
get: (id, options) => crud.getItemById(URL, id, options)
1920
}

src/api/services/v3/cmp/UserService.test.js

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { baseApi } from '../../../baseApi'
12
import crud from '../../../crudOperations'
23
import UserService from './UserService'
34

@@ -6,15 +7,58 @@ const USER_URL = 'v3/cmp/user'
67
const WIDGETS_URL = 'v3/cmp/users/1/dashboardWidgets'
78
const DASHBOARD_URL = 'v3/cmp/users/1/cuiDashboard'
89

10+
const mockApiResponse = {
11+
_links: {
12+
self: {
13+
href: '/api/v3/cmp/users/?page=1',
14+
title: 'List of Users - Page 1 of 1'
15+
}
16+
},
17+
total: 1,
18+
count: 1,
19+
_embedded: {
20+
users: [
21+
{
22+
_links: {
23+
self: { href: '/api/v3/cmp/users/USR-i7nc49in/', title: 'admin' }
24+
},
25+
id: 'USR-i7nc49in',
26+
firstName: 'admin',
27+
lastName: 'admin',
28+
username: 'admin',
29+
email: 'admin@cloudbolt.io',
30+
isActive: true,
31+
source: null,
32+
superAdmin: true,
33+
devopsAdmin: false,
34+
apiAccess: true,
35+
globalViewer: false,
36+
lastActivityTime: '2022-10-31 16:54:06.045182',
37+
passwordResetQuestion: '1',
38+
hasActiveSession: true
39+
}
40+
]
41+
}
42+
}
43+
944
describe('UserService', () => {
10-
it('gets a list of users', async () => {
45+
it('calls the correct endpoint', async () => {
1146
const mockFn = jest.spyOn(crud, 'getItems').mockResolvedValue({
1247
data: { hello: 'world' }
1348
})
1449
await UserService.list({})
1550
expect(mockFn).toHaveBeenCalledWith(USERS_URL, {})
1651
})
1752

53+
it('parses the response correctly', async () => {
54+
jest.spyOn(baseApi, 'get').mockResolvedValue({ data: mockApiResponse })
55+
56+
const users = await UserService.list({})
57+
console.log(users)
58+
console.log(mockApiResponse)
59+
expect(users.items.length).toBe(1)
60+
})
61+
1862
it('getCurrentUser calls crud.getItemByEndpoint and returns result', async () => {
1963
jest.spyOn(crud, 'getItemByEndpoint').mockResolvedValue('dummyResponse')
2064

0 commit comments

Comments
 (0)