@ogcio/building-blocks-sdk 0.0.22 → 0.0.24
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/.github/CODEOWNERS +2 -0
- package/dist/__tests__/client/clients/featureFlags/index.test.js +17 -17
- package/dist/__tests__/client/clients/featureFlags/index.test.js.map +1 -1
- package/dist/__tests__/client/utils/client-utils.test.js +28 -31
- package/dist/__tests__/client/utils/client-utils.test.js.map +1 -1
- package/package.json +7 -9
- package/src/__tests__/client/clients/featureFlags/index.test.ts +30 -30
- package/src/__tests__/client/utils/client-utils.test.ts +29 -67
- package/vitest.config.mts +20 -0
- package/tap.yml +0 -14
- package/vitest.config.cts +0 -9
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as td from "testdouble";
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
2
|
import { FeatureFlags } from "../../../../client/clients/featureFlags/index.js";
|
|
4
3
|
const enabledOrNot = {
|
|
5
4
|
"not-enabled": false,
|
|
6
5
|
enabled: true,
|
|
7
6
|
};
|
|
8
|
-
|
|
9
|
-
initialize:
|
|
7
|
+
vi.mock("unleash-client", () => ({
|
|
8
|
+
initialize: vi.fn(),
|
|
10
9
|
startUnleash: () => ({
|
|
11
|
-
isEnabled: (name, _context, _functionToUse) => enabledOrNot[name],
|
|
10
|
+
isEnabled: vi.fn((name, _context, _functionToUse) => enabledOrNot[name]),
|
|
12
11
|
}),
|
|
13
|
-
InMemStorageProvider:
|
|
14
|
-
});
|
|
12
|
+
InMemStorageProvider: vi.fn(),
|
|
13
|
+
}));
|
|
15
14
|
let fetchResponse = {};
|
|
15
|
+
// Mock global fetch
|
|
16
16
|
global.fetch = async () => ({
|
|
17
17
|
ok: true,
|
|
18
18
|
status: 200,
|
|
19
19
|
json: async () => fetchResponse,
|
|
20
20
|
headers: new Headers(),
|
|
21
21
|
});
|
|
22
|
-
|
|
22
|
+
describe("FeatureFlags", () => {
|
|
23
23
|
const baseUrl = "http://fakehost";
|
|
24
24
|
const getTokenFn = () => "test-token";
|
|
25
25
|
let featureFlags;
|
|
26
|
-
|
|
26
|
+
beforeEach(async () => {
|
|
27
27
|
featureFlags = new FeatureFlags({ baseUrl, getTokenFn });
|
|
28
28
|
});
|
|
29
|
-
|
|
29
|
+
it("should return false if flag is not enabled", async () => {
|
|
30
30
|
const result = await featureFlags.isFlagEnabled("not-enabled");
|
|
31
|
-
|
|
31
|
+
expect(result).toBe(enabledOrNot["not-enabled"]);
|
|
32
32
|
});
|
|
33
|
-
|
|
33
|
+
it("should return true if flag is enabled", async () => {
|
|
34
34
|
const result = await featureFlags.isFlagEnabled("enabled");
|
|
35
|
-
|
|
35
|
+
expect(result).toBe(enabledOrNot.enabled);
|
|
36
36
|
});
|
|
37
|
-
|
|
37
|
+
it("should call GET method on client when getFeatureFlags is called", async () => {
|
|
38
38
|
fetchResponse = { data: { features: [] }, metadata: {} };
|
|
39
39
|
const result = await featureFlags.getFeatureFlags();
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
expect(result).toBeTruthy();
|
|
41
|
+
expect(result).toEqual({
|
|
42
42
|
data: [],
|
|
43
43
|
metadata: {},
|
|
44
|
-
error:
|
|
44
|
+
error: undefined,
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../../../src/__tests__/client/clients/featureFlags/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../../../src/__tests__/client/clients/featureFlags/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,kDAAkD,CAAC;AAEhF,MAAM,YAAY,GAAG;IACnB,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,IAAI;CACd,CAAC;AAEF,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/B,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;IACnB,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;QACnB,SAAS,EAAE,EAAE,CAAC,EAAE,CACd,CACE,IAA+B,EAC/B,QAAiB,EACjB,cAA6B,EAC7B,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CACxB;KACF,CAAC;IACF,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE;CAC9B,CAAC,CAAC,CAAC;AAEJ,IAAI,aAAa,GAAG,EAAE,CAAC;AAEvB,oBAAoB;AACpB,MAAM,CAAC,KAAK,GAAG,KAAK,IAAI,EAAE,CACxB,CAAC;IACC,EAAE,EAAE,IAAI;IACR,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,aAAa;IAC/B,OAAO,EAAE,IAAI,OAAO,EAAE;CACvB,CAAa,CAAC;AAEjB,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,MAAM,OAAO,GAAG,iBAAiB,CAAC;IAClC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC;IACtC,IAAI,YAA0B,CAAC;IAE/B,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,YAAY,GAAG,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAC3D,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,aAAa,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC;QAC5B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,IAAI,EAAE,EAAE;YACR,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,56 +1,53 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { describe, test } from "node:test";
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
3
2
|
import { formatError, formatResponse, preparePaginationParams, toStringOrUndefined, } from "./../../../client/utils/client-utils.js";
|
|
4
3
|
describe("toStringOrUndefined", () => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
it("should convert numbers and booleans to strings", () => {
|
|
5
|
+
expect(toStringOrUndefined(42)).toBe("42");
|
|
6
|
+
expect(toStringOrUndefined(true)).toBe("true");
|
|
7
|
+
expect(toStringOrUndefined(false)).toBe("false");
|
|
9
8
|
});
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
it("should return undefined if input is undefined", () => {
|
|
10
|
+
expect(toStringOrUndefined(undefined)).toBeUndefined();
|
|
12
11
|
});
|
|
13
|
-
|
|
12
|
+
it("should convert offset and limit to strings if provided", () => {
|
|
14
13
|
const params = { offset: 10, limit: 20 };
|
|
15
14
|
const result = preparePaginationParams(params);
|
|
16
|
-
|
|
15
|
+
expect(result).toEqual({ offset: "10", limit: "20" });
|
|
17
16
|
});
|
|
18
|
-
|
|
17
|
+
it("should handle string inputs for offset and limit", () => {
|
|
19
18
|
const params = { offset: "5", limit: "15" };
|
|
20
19
|
const result = preparePaginationParams(params);
|
|
21
|
-
|
|
20
|
+
expect(result).toEqual({ offset: "5", limit: "15" });
|
|
22
21
|
});
|
|
23
|
-
|
|
22
|
+
it("should return an empty object if no pagination parameters are provided", () => {
|
|
24
23
|
const result = preparePaginationParams();
|
|
25
|
-
|
|
24
|
+
expect(result).toEqual({});
|
|
26
25
|
});
|
|
27
26
|
});
|
|
28
27
|
describe("preparePaginationParams", () => {
|
|
29
|
-
|
|
28
|
+
it("should handle missing offset and limit individually", () => {
|
|
30
29
|
const offsetOnly = { offset: 30 };
|
|
31
30
|
const limitOnly = { limit: 50 };
|
|
32
31
|
const resultOffsetOnly = preparePaginationParams(offsetOnly);
|
|
33
|
-
|
|
32
|
+
expect(resultOffsetOnly).toEqual({ offset: "30" });
|
|
34
33
|
const resultLimitOnly = preparePaginationParams(limitOnly);
|
|
35
|
-
|
|
34
|
+
expect(resultLimitOnly).toEqual({ limit: "50" });
|
|
36
35
|
});
|
|
37
36
|
});
|
|
38
37
|
describe("formatResponse", () => {
|
|
39
|
-
|
|
40
|
-
// Create a properly typed success response
|
|
38
|
+
it("should handle response with plain data", () => {
|
|
41
39
|
const mockResponse = {
|
|
42
40
|
data: { value: "test" },
|
|
43
41
|
response: new Response(),
|
|
44
42
|
};
|
|
45
43
|
const result = formatResponse(mockResponse);
|
|
46
|
-
|
|
44
|
+
expect(result).toEqual({
|
|
47
45
|
data: { value: "test" },
|
|
48
46
|
metadata: undefined,
|
|
49
47
|
error: undefined,
|
|
50
48
|
});
|
|
51
49
|
});
|
|
52
|
-
|
|
53
|
-
// Create a properly typed nested success response
|
|
50
|
+
it("should handle response with nested data property", () => {
|
|
54
51
|
const mockResponse = {
|
|
55
52
|
data: {
|
|
56
53
|
data: {
|
|
@@ -62,7 +59,7 @@ describe("formatResponse", () => {
|
|
|
62
59
|
response: new Response(),
|
|
63
60
|
};
|
|
64
61
|
const result = formatResponse(mockResponse);
|
|
65
|
-
|
|
62
|
+
expect(result).toEqual({
|
|
66
63
|
data: {
|
|
67
64
|
nested: {
|
|
68
65
|
value: "test",
|
|
@@ -72,7 +69,7 @@ describe("formatResponse", () => {
|
|
|
72
69
|
error: undefined,
|
|
73
70
|
});
|
|
74
71
|
});
|
|
75
|
-
|
|
72
|
+
it("should format typed error correctly", () => {
|
|
76
73
|
const mockError = {
|
|
77
74
|
message: "Test error",
|
|
78
75
|
code: "500",
|
|
@@ -82,7 +79,7 @@ describe("formatResponse", () => {
|
|
|
82
79
|
response: new Response(),
|
|
83
80
|
};
|
|
84
81
|
const result = formatResponse(errorResponse);
|
|
85
|
-
|
|
82
|
+
expect(result).toEqual({
|
|
86
83
|
data: undefined,
|
|
87
84
|
metadata: undefined,
|
|
88
85
|
error: mockError,
|
|
@@ -90,24 +87,24 @@ describe("formatResponse", () => {
|
|
|
90
87
|
});
|
|
91
88
|
});
|
|
92
89
|
describe("formatError", () => {
|
|
93
|
-
|
|
90
|
+
it("should format error correctly", () => {
|
|
94
91
|
const error = new Error("Test error");
|
|
95
92
|
const result = formatError(error);
|
|
96
|
-
|
|
93
|
+
expect(result).toEqual({
|
|
97
94
|
error: error,
|
|
98
95
|
});
|
|
99
96
|
});
|
|
100
|
-
|
|
97
|
+
it("should handle non-error objects", () => {
|
|
101
98
|
const errorObj = { code: 500, message: "Server error" };
|
|
102
99
|
const result = formatError(errorObj);
|
|
103
|
-
|
|
100
|
+
expect(result).toEqual({
|
|
104
101
|
error: errorObj,
|
|
105
102
|
});
|
|
106
103
|
});
|
|
107
|
-
|
|
104
|
+
it("should handle primitive error values", () => {
|
|
108
105
|
const errorMessage = "Something went wrong";
|
|
109
106
|
const result = formatError(errorMessage);
|
|
110
|
-
|
|
107
|
+
expect(result).toEqual({
|
|
111
108
|
error: errorMessage,
|
|
112
109
|
});
|
|
113
110
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-utils.test.js","sourceRoot":"","sources":["../../../../src/__tests__/client/utils/client-utils.test.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"client-utils.test.js","sourceRoot":"","sources":["../../../../src/__tests__/client/utils/client-utils.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ogcio/building-blocks-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"test": "
|
|
9
|
-
"test:local": "TAP_RCFILE=tap.yml tap",
|
|
8
|
+
"test": "vitest run --coverage --reporter=junit --outputFile=results.xml",
|
|
10
9
|
"test:e2e": "cd ./e2e && bru run --env local",
|
|
11
|
-
"test:smoke:e2e": "echo \"Error: no test specified\" && exit 0",
|
|
12
10
|
"test:regression:e2e": "cd ./e2e && mkdir -p test-results && bru run --env dev --output ./test-results/results.xml --format junit",
|
|
13
11
|
"build": "rm -rf dist && tsc -p tsconfig.prod.json",
|
|
14
12
|
"clients:update": "node --import=tsx src/cli/index.ts clients:update -c src/clients-configurations/clients-configuration.json",
|
|
@@ -17,10 +15,11 @@
|
|
|
17
15
|
"fix:formatting": "biome format --write",
|
|
18
16
|
"check:linting": "biome lint",
|
|
19
17
|
"fix:linting": "biome lint --write",
|
|
18
|
+
"prepublishOnly": "npm i && npm run build && npm run test",
|
|
20
19
|
"prepare": "husky || true"
|
|
21
20
|
},
|
|
22
21
|
"dependencies": {
|
|
23
|
-
"@ogcio/analytics-sdk": "0.0
|
|
22
|
+
"@ogcio/analytics-sdk": "0.1.0-beta.4",
|
|
24
23
|
"@sinclair/typebox": "^0.33.17",
|
|
25
24
|
"commander": "^12.1.0",
|
|
26
25
|
"http-errors": "^2.0.0",
|
|
@@ -34,13 +33,12 @@
|
|
|
34
33
|
"@biomejs/biome": "1.9.4",
|
|
35
34
|
"@commitlint/config-conventional": "^19.5.0",
|
|
36
35
|
"@types/http-errors": "^2.0.4",
|
|
36
|
+
"@vitest/coverage-istanbul": "^2.1.4",
|
|
37
37
|
"commitlint": "^19.5.0",
|
|
38
38
|
"husky": "^9.1.6",
|
|
39
|
-
"tap": "^21.0.1",
|
|
40
|
-
"testdouble": "^3.20.2",
|
|
41
|
-
"vitest": "^2.1.4",
|
|
42
39
|
"tsx": "^4.19.2",
|
|
43
|
-
"typescript": "^5.6.3"
|
|
40
|
+
"typescript": "^5.6.3",
|
|
41
|
+
"vitest": "^2.1.4"
|
|
44
42
|
},
|
|
45
43
|
"peerDependencies": {
|
|
46
44
|
"@logto/node": "2.5.5",
|
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as td from "testdouble";
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
2
|
import { FeatureFlags } from "../../../../client/clients/featureFlags/index.js";
|
|
4
3
|
|
|
5
4
|
const enabledOrNot = {
|
|
6
5
|
"not-enabled": false,
|
|
7
6
|
enabled: true,
|
|
8
7
|
};
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
|
|
9
|
+
vi.mock("unleash-client", () => ({
|
|
10
|
+
initialize: vi.fn(),
|
|
11
11
|
startUnleash: () => ({
|
|
12
|
-
isEnabled: (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
isEnabled: vi.fn(
|
|
13
|
+
(
|
|
14
|
+
name: "enabled" | "not-enabled",
|
|
15
|
+
_context: unknown,
|
|
16
|
+
_functionToUse: () => boolean,
|
|
17
|
+
) => enabledOrNot[name],
|
|
18
|
+
),
|
|
17
19
|
}),
|
|
18
|
-
InMemStorageProvider:
|
|
19
|
-
});
|
|
20
|
+
InMemStorageProvider: vi.fn(),
|
|
21
|
+
}));
|
|
20
22
|
|
|
21
23
|
let fetchResponse = {};
|
|
22
24
|
|
|
25
|
+
// Mock global fetch
|
|
23
26
|
global.fetch = async () =>
|
|
24
27
|
({
|
|
25
28
|
ok: true,
|
|
@@ -28,36 +31,33 @@ global.fetch = async () =>
|
|
|
28
31
|
headers: new Headers(),
|
|
29
32
|
}) as Response;
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
describe("FeatureFlags", () => {
|
|
32
35
|
const baseUrl = "http://fakehost";
|
|
33
36
|
const getTokenFn = () => "test-token";
|
|
34
37
|
let featureFlags: FeatureFlags;
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
beforeEach(async () => {
|
|
37
40
|
featureFlags = new FeatureFlags({ baseUrl, getTokenFn });
|
|
38
41
|
});
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
it("should return false if flag is not enabled", async () => {
|
|
41
44
|
const result = await featureFlags.isFlagEnabled("not-enabled");
|
|
42
|
-
|
|
45
|
+
expect(result).toBe(enabledOrNot["not-enabled"]);
|
|
43
46
|
});
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
it("should return true if flag is enabled", async () => {
|
|
46
49
|
const result = await featureFlags.isFlagEnabled("enabled");
|
|
47
|
-
|
|
50
|
+
expect(result).toBe(enabledOrNot.enabled);
|
|
48
51
|
});
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
});
|
|
61
|
-
},
|
|
62
|
-
);
|
|
53
|
+
it("should call GET method on client when getFeatureFlags is called", async () => {
|
|
54
|
+
fetchResponse = { data: { features: [] }, metadata: {} };
|
|
55
|
+
const result = await featureFlags.getFeatureFlags();
|
|
56
|
+
expect(result).toBeTruthy();
|
|
57
|
+
expect(result).toEqual({
|
|
58
|
+
data: [],
|
|
59
|
+
metadata: {},
|
|
60
|
+
error: undefined,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
63
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { describe, test } from "node:test";
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
3
2
|
import {
|
|
4
3
|
type PaginationParams,
|
|
5
4
|
formatError,
|
|
@@ -14,87 +13,51 @@ import type {
|
|
|
14
13
|
TypedErrorResponse,
|
|
15
14
|
TypedSuccessResponse,
|
|
16
15
|
} from "./response-types.js";
|
|
16
|
+
|
|
17
17
|
describe("toStringOrUndefined", () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"Expected number to be converted to string",
|
|
23
|
-
);
|
|
24
|
-
assert.strictEqual(
|
|
25
|
-
toStringOrUndefined(true),
|
|
26
|
-
"true",
|
|
27
|
-
"Expected boolean true to be converted to string",
|
|
28
|
-
);
|
|
29
|
-
assert.strictEqual(
|
|
30
|
-
toStringOrUndefined(false),
|
|
31
|
-
"false",
|
|
32
|
-
"Expected boolean false to be converted to string",
|
|
33
|
-
);
|
|
18
|
+
it("should convert numbers and booleans to strings", () => {
|
|
19
|
+
expect(toStringOrUndefined(42)).toBe("42");
|
|
20
|
+
expect(toStringOrUndefined(true)).toBe("true");
|
|
21
|
+
expect(toStringOrUndefined(false)).toBe("false");
|
|
34
22
|
});
|
|
35
23
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
toStringOrUndefined(undefined),
|
|
39
|
-
undefined,
|
|
40
|
-
"Expected undefined input to return undefined",
|
|
41
|
-
);
|
|
24
|
+
it("should return undefined if input is undefined", () => {
|
|
25
|
+
expect(toStringOrUndefined(undefined)).toBeUndefined();
|
|
42
26
|
});
|
|
43
27
|
|
|
44
|
-
|
|
28
|
+
it("should convert offset and limit to strings if provided", () => {
|
|
45
29
|
const params: PaginationParams = { offset: 10, limit: 20 };
|
|
46
30
|
const result = preparePaginationParams(params);
|
|
47
|
-
|
|
48
|
-
result,
|
|
49
|
-
{ offset: "10", limit: "20" },
|
|
50
|
-
"Expected offset and limit to be converted to strings",
|
|
51
|
-
);
|
|
31
|
+
expect(result).toEqual({ offset: "10", limit: "20" });
|
|
52
32
|
});
|
|
53
33
|
|
|
54
|
-
|
|
34
|
+
it("should handle string inputs for offset and limit", () => {
|
|
55
35
|
const params: PaginationParams = { offset: "5", limit: "15" };
|
|
56
36
|
const result = preparePaginationParams(params);
|
|
57
|
-
|
|
58
|
-
result,
|
|
59
|
-
{ offset: "5", limit: "15" },
|
|
60
|
-
"Expected offset and limit to remain strings if already provided as strings",
|
|
61
|
-
);
|
|
37
|
+
expect(result).toEqual({ offset: "5", limit: "15" });
|
|
62
38
|
});
|
|
63
39
|
|
|
64
|
-
|
|
40
|
+
it("should return an empty object if no pagination parameters are provided", () => {
|
|
65
41
|
const result = preparePaginationParams();
|
|
66
|
-
|
|
67
|
-
result,
|
|
68
|
-
{},
|
|
69
|
-
"Expected empty object if no pagination parameters are provided",
|
|
70
|
-
);
|
|
42
|
+
expect(result).toEqual({});
|
|
71
43
|
});
|
|
72
44
|
});
|
|
73
45
|
|
|
74
46
|
describe("preparePaginationParams", () => {
|
|
75
|
-
|
|
47
|
+
it("should handle missing offset and limit individually", () => {
|
|
76
48
|
const offsetOnly: PaginationParams = { offset: 30 };
|
|
77
49
|
const limitOnly: PaginationParams = { limit: 50 };
|
|
78
50
|
|
|
79
51
|
const resultOffsetOnly = preparePaginationParams(offsetOnly);
|
|
80
|
-
|
|
81
|
-
resultOffsetOnly,
|
|
82
|
-
{ offset: "30" },
|
|
83
|
-
"Expected only offset to be set when limit is not provided",
|
|
84
|
-
);
|
|
52
|
+
expect(resultOffsetOnly).toEqual({ offset: "30" });
|
|
85
53
|
|
|
86
54
|
const resultLimitOnly = preparePaginationParams(limitOnly);
|
|
87
|
-
|
|
88
|
-
resultLimitOnly,
|
|
89
|
-
{ limit: "50" },
|
|
90
|
-
"Expected only limit to be set when offset is not provided",
|
|
91
|
-
);
|
|
55
|
+
expect(resultLimitOnly).toEqual({ limit: "50" });
|
|
92
56
|
});
|
|
93
57
|
});
|
|
94
58
|
|
|
95
59
|
describe("formatResponse", () => {
|
|
96
|
-
|
|
97
|
-
// Create a properly typed success response
|
|
60
|
+
it("should handle response with plain data", () => {
|
|
98
61
|
const mockResponse: TypedSuccessResponse<{ value: string }> = {
|
|
99
62
|
data: { value: "test" },
|
|
100
63
|
response: new Response(),
|
|
@@ -105,15 +68,14 @@ describe("formatResponse", () => {
|
|
|
105
68
|
Record<string, unknown>
|
|
106
69
|
>(mockResponse);
|
|
107
70
|
|
|
108
|
-
|
|
71
|
+
expect(result).toEqual({
|
|
109
72
|
data: { value: "test" },
|
|
110
73
|
metadata: undefined,
|
|
111
74
|
error: undefined,
|
|
112
75
|
});
|
|
113
76
|
});
|
|
114
77
|
|
|
115
|
-
|
|
116
|
-
// Create a properly typed nested success response
|
|
78
|
+
it("should handle response with nested data property", () => {
|
|
117
79
|
const mockResponse: TypedSuccessResponse<{
|
|
118
80
|
data: {
|
|
119
81
|
nested: {
|
|
@@ -136,7 +98,7 @@ describe("formatResponse", () => {
|
|
|
136
98
|
Record<string, unknown>
|
|
137
99
|
>(mockResponse);
|
|
138
100
|
|
|
139
|
-
|
|
101
|
+
expect(result).toEqual({
|
|
140
102
|
data: {
|
|
141
103
|
nested: {
|
|
142
104
|
value: "test",
|
|
@@ -147,7 +109,7 @@ describe("formatResponse", () => {
|
|
|
147
109
|
});
|
|
148
110
|
});
|
|
149
111
|
|
|
150
|
-
|
|
112
|
+
it("should format typed error correctly", () => {
|
|
151
113
|
const mockError: ApiError = {
|
|
152
114
|
message: "Test error",
|
|
153
115
|
code: "500",
|
|
@@ -163,7 +125,7 @@ describe("formatResponse", () => {
|
|
|
163
125
|
Record<string, unknown>
|
|
164
126
|
>(errorResponse);
|
|
165
127
|
|
|
166
|
-
|
|
128
|
+
expect(result).toEqual({
|
|
167
129
|
data: undefined,
|
|
168
130
|
metadata: undefined,
|
|
169
131
|
error: mockError,
|
|
@@ -172,26 +134,26 @@ describe("formatResponse", () => {
|
|
|
172
134
|
});
|
|
173
135
|
|
|
174
136
|
describe("formatError", () => {
|
|
175
|
-
|
|
137
|
+
it("should format error correctly", () => {
|
|
176
138
|
const error = new Error("Test error");
|
|
177
139
|
const result = formatError(error);
|
|
178
|
-
|
|
140
|
+
expect(result).toEqual({
|
|
179
141
|
error: error,
|
|
180
142
|
});
|
|
181
143
|
});
|
|
182
144
|
|
|
183
|
-
|
|
145
|
+
it("should handle non-error objects", () => {
|
|
184
146
|
const errorObj = { code: 500, message: "Server error" };
|
|
185
147
|
const result = formatError(errorObj);
|
|
186
|
-
|
|
148
|
+
expect(result).toEqual({
|
|
187
149
|
error: errorObj,
|
|
188
150
|
});
|
|
189
151
|
});
|
|
190
152
|
|
|
191
|
-
|
|
153
|
+
it("should handle primitive error values", () => {
|
|
192
154
|
const errorMessage = "Something went wrong";
|
|
193
155
|
const result = formatError(errorMessage);
|
|
194
|
-
|
|
156
|
+
expect(result).toEqual({
|
|
195
157
|
error: errorMessage,
|
|
196
158
|
});
|
|
197
159
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
reporters: "default",
|
|
6
|
+
coverage: {
|
|
7
|
+
reporter: ["text"],
|
|
8
|
+
provider: "istanbul",
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
include: [
|
|
12
|
+
"**/@(test?(s)|__test?(s)__)/**/*.test.@(js|cjs|mjs|tap|cts|jsx|mts|ts|tsx)",
|
|
13
|
+
"**/*.@(test?(s)|spec).@(js|cjs|mjs|tap|cts|jsx|mts|ts|tsx)",
|
|
14
|
+
"**/test?(s).@(js|cjs|mjs|tap|cts|jsx|mts|ts|tsx)",
|
|
15
|
+
],
|
|
16
|
+
exclude: ["**/@(fixture*(s)|dist|node_modules)/**"],
|
|
17
|
+
maxConcurrency: 1,
|
|
18
|
+
testTimeout: 30000, // Timeout in milliseconds (30 seconds)
|
|
19
|
+
},
|
|
20
|
+
});
|
package/tap.yml
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
color: true
|
|
2
|
-
coverage-report:
|
|
3
|
-
- text
|
|
4
|
-
exclude:
|
|
5
|
-
- "**/@(fixture*(s)|dist)/**"
|
|
6
|
-
include:
|
|
7
|
-
- "**/@(test?(s)|__test?(s)__)/**/*.test.@(js|cjs|mjs|tap|cts|jsx|mts|ts|tsx)"
|
|
8
|
-
- "**/*.@(test?(s)|spec).@(js|cjs|mjs|tap|cts|jsx|mts|ts|tsx)"
|
|
9
|
-
- "**/test?(s).@(js|cjs|mjs|tap|cts|jsx|mts|ts|tsx)"
|
|
10
|
-
jobs: 1
|
|
11
|
-
reporter: base
|
|
12
|
-
snapshot-clean-cwd: true
|
|
13
|
-
timeout: 30
|
|
14
|
-
allow-incomplete-coverage: true
|