@vulog/aima-vehicle 1.2.5 → 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/getModelVehicles.test.ts +193 -0
- package/src/getModelVehicles.ts +52 -0
- package/src/index.ts +1 -0
- package/src/types.ts +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vulog/aima-vehicle",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"author": "Vulog",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@vulog/aima-client": "1.2.
|
|
23
|
-
"@vulog/aima-core": "1.2.
|
|
22
|
+
"@vulog/aima-client": "1.2.7",
|
|
23
|
+
"@vulog/aima-core": "1.2.7"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"zod": "^3.25.76"
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { getModelVehicles } from './getModelVehicles';
|
|
4
|
+
import { ModelVehicle } from './types';
|
|
5
|
+
|
|
6
|
+
describe('getModelVehicles', () => {
|
|
7
|
+
const getMock = vi.fn();
|
|
8
|
+
const client = {
|
|
9
|
+
get: getMock,
|
|
10
|
+
clientOptions: {
|
|
11
|
+
fleetId: 'FLEET_ID',
|
|
12
|
+
},
|
|
13
|
+
} as unknown as Client;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('should return model vehicles with default options', async () => {
|
|
20
|
+
const mockData: ModelVehicle[] = [
|
|
21
|
+
{
|
|
22
|
+
serviceId: 'service-1',
|
|
23
|
+
serviceVisibility: 'PUBLIC',
|
|
24
|
+
modelId: 1,
|
|
25
|
+
vehicles: ['vehicle-1', 'vehicle-2'],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
serviceId: 'service-2',
|
|
29
|
+
serviceVisibility: 'PRIVATE',
|
|
30
|
+
modelId: 2,
|
|
31
|
+
vehicles: ['vehicle-3'],
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const mockHeaders = {
|
|
36
|
+
number: 0,
|
|
37
|
+
size: 100,
|
|
38
|
+
totalelements: 2,
|
|
39
|
+
totalpages: 1,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
getMock.mockResolvedValueOnce({
|
|
43
|
+
data: mockData,
|
|
44
|
+
headers: mockHeaders,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const result = await getModelVehicles(client);
|
|
48
|
+
|
|
49
|
+
expect(result).toEqual({
|
|
50
|
+
data: mockData,
|
|
51
|
+
page: 0,
|
|
52
|
+
pageSize: 100,
|
|
53
|
+
total: 2,
|
|
54
|
+
totalPages: 1,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
58
|
+
expect.stringContaining('boapi/proxy/user/vehicle/fleets/FLEET_ID/vehicles/models/modelvehicles')
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const calledUrl = getMock.mock.calls[0][0];
|
|
62
|
+
const url = new URL(calledUrl, 'http://example.com');
|
|
63
|
+
expect(url.searchParams.get('page')).toBe('0');
|
|
64
|
+
expect(url.searchParams.get('pageSize')).toBe('100');
|
|
65
|
+
// sort is not provided in default options, so it should not be in URL
|
|
66
|
+
expect(url.searchParams.get('sort')).toBe(null);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('should return model vehicles with custom options', async () => {
|
|
70
|
+
const mockData: ModelVehicle[] = [
|
|
71
|
+
{
|
|
72
|
+
serviceId: 'service-1',
|
|
73
|
+
serviceVisibility: 'PUBLIC',
|
|
74
|
+
modelId: 1,
|
|
75
|
+
vehicles: ['vehicle-1'],
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const mockHeaders = {
|
|
80
|
+
number: 1,
|
|
81
|
+
size: 50,
|
|
82
|
+
totalelements: 10,
|
|
83
|
+
totalpages: 1,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
getMock.mockResolvedValueOnce({
|
|
87
|
+
data: mockData,
|
|
88
|
+
headers: mockHeaders,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const options = {
|
|
92
|
+
page: 1,
|
|
93
|
+
pageSize: 50,
|
|
94
|
+
sort: 'modelId',
|
|
95
|
+
sortDirection: 'DESC' as const,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const result = await getModelVehicles(client, options);
|
|
99
|
+
|
|
100
|
+
expect(result).toEqual({
|
|
101
|
+
data: mockData,
|
|
102
|
+
page: 1,
|
|
103
|
+
pageSize: 50,
|
|
104
|
+
total: 10,
|
|
105
|
+
totalPages: 1,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const calledUrl = getMock.mock.calls[0][0];
|
|
109
|
+
const url = new URL(calledUrl, 'http://example.com');
|
|
110
|
+
expect(url.searchParams.get('page')).toBe('1');
|
|
111
|
+
expect(url.searchParams.get('pageSize')).toBe('50');
|
|
112
|
+
expect(url.searchParams.get('sort')).toBe('modelId,DESC');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('should handle default filters as empty object', async () => {
|
|
116
|
+
const mockData: ModelVehicle[] = [];
|
|
117
|
+
const mockHeaders = {
|
|
118
|
+
number: 0,
|
|
119
|
+
size: 100,
|
|
120
|
+
totalelements: 0,
|
|
121
|
+
totalpages: 0,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
getMock.mockResolvedValueOnce({
|
|
125
|
+
data: mockData,
|
|
126
|
+
headers: mockHeaders,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const result = await getModelVehicles(client);
|
|
130
|
+
|
|
131
|
+
expect(result).toEqual({
|
|
132
|
+
data: mockData,
|
|
133
|
+
page: 0,
|
|
134
|
+
pageSize: 100,
|
|
135
|
+
total: 0,
|
|
136
|
+
totalPages: 0,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const calledUrl = getMock.mock.calls[0][0];
|
|
140
|
+
const url = new URL(calledUrl, 'http://example.com');
|
|
141
|
+
// Should only have page and pageSize parameters since sort and filters are not provided
|
|
142
|
+
expect(url.searchParams.toString()).toBe('page=0&pageSize=100');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('should throw error for invalid page number', async () => {
|
|
146
|
+
const options = {
|
|
147
|
+
page: -1, // Invalid: negative page number
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
await expect(getModelVehicles(client, options)).rejects.toThrow('Invalid options');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('should throw error for invalid page size', async () => {
|
|
154
|
+
const options = {
|
|
155
|
+
pageSize: 0, // Invalid: page size must be positive
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
await expect(getModelVehicles(client, options)).rejects.toThrow('Invalid options');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('should throw error for invalid sort direction', async () => {
|
|
162
|
+
const options = {
|
|
163
|
+
sortDirection: 'INVALID' as any, // Invalid: not ASC or DESC
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
await expect(getModelVehicles(client, options)).rejects.toThrow('Invalid options');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('should handle empty response', async () => {
|
|
170
|
+
const mockData: ModelVehicle[] = [];
|
|
171
|
+
const mockHeaders = {
|
|
172
|
+
number: 0,
|
|
173
|
+
size: 100,
|
|
174
|
+
totalelements: 0,
|
|
175
|
+
totalpages: 0,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
getMock.mockResolvedValueOnce({
|
|
179
|
+
data: mockData,
|
|
180
|
+
headers: mockHeaders,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const result = await getModelVehicles(client);
|
|
184
|
+
|
|
185
|
+
expect(result).toEqual({
|
|
186
|
+
data: [],
|
|
187
|
+
page: 0,
|
|
188
|
+
pageSize: 100,
|
|
189
|
+
total: 0,
|
|
190
|
+
totalPages: 0,
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { PaginableOptions, PaginableResponse, createPaginableOptionsSchema } from '@vulog/aima-core';
|
|
3
|
+
|
|
4
|
+
import { ModelVehicle } from './types';
|
|
5
|
+
|
|
6
|
+
export const getModelVehicles = async (
|
|
7
|
+
client: Client,
|
|
8
|
+
options?: PaginableOptions
|
|
9
|
+
): Promise<PaginableResponse<ModelVehicle>> => {
|
|
10
|
+
const PaginableOptionsSchema = createPaginableOptionsSchema().default({});
|
|
11
|
+
|
|
12
|
+
const resultOptions = PaginableOptionsSchema.safeParse(options);
|
|
13
|
+
if (!resultOptions.success) {
|
|
14
|
+
throw new TypeError('Invalid options', {
|
|
15
|
+
cause: resultOptions.error.issues,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const finalOptions = resultOptions.data;
|
|
20
|
+
|
|
21
|
+
const searchParams = new URLSearchParams();
|
|
22
|
+
searchParams.append('page', finalOptions.page!.toString());
|
|
23
|
+
searchParams.append('pageSize', finalOptions.pageSize!.toString());
|
|
24
|
+
|
|
25
|
+
// Handle optional sort parameter
|
|
26
|
+
if (finalOptions.sort) {
|
|
27
|
+
searchParams.append('sort', `${finalOptions.sort.toString()},${finalOptions.sortDirection!.toString()}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Handle optional filters parameter
|
|
31
|
+
if (finalOptions.filters) {
|
|
32
|
+
Object.entries(finalOptions.filters).forEach(([key, value]) => {
|
|
33
|
+
if (value === undefined) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
searchParams.append(key, value as string);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const basePath = `boapi/proxy/user/vehicle/fleets/${client.clientOptions.fleetId}/vehicles/models/modelvehicles`;
|
|
41
|
+
const urlWithParams = `${basePath}?${searchParams.toString()}`;
|
|
42
|
+
|
|
43
|
+
return client.get<ModelVehicle[]>(urlWithParams).then(({ data, headers }) => {
|
|
44
|
+
return {
|
|
45
|
+
data,
|
|
46
|
+
page: headers.number,
|
|
47
|
+
pageSize: headers.size,
|
|
48
|
+
total: headers.totalelements,
|
|
49
|
+
totalPages: headers.totalpages,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
};
|
package/src/index.ts
CHANGED