@softwear/latestcollectioncore 1.0.151 → 1.0.153
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/dist/articleStatus.js +11 -4
- package/dist/buildPropertyMappingFn.js +3 -3
- package/dist/cryptography.d.ts +1 -1
- package/dist/cryptography.js +8 -8
- package/dist/imageBinder.js +10 -10
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -1
- package/dist/lcAxios.d.ts +51 -0
- package/dist/lcAxios.js +330 -0
- package/dist/types.d.ts +1 -1
- package/package.json +33 -34
- package/src/articleStatus.ts +9 -2
- package/src/buildPropertyMappingFn.ts +3 -3
- package/src/cryptography.ts +2 -2
- package/src/imageBinder.ts +23 -26
- package/src/index.ts +16 -0
- package/src/lcAxios.ts +349 -0
- package/src/types.ts +1 -1
- package/test/lcAxios.spec.ts +172 -0
- package/vitest.config.ts +1 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { lcAxios as axios, axiosRetry, type AxiosError } from '../src/lcAxios'
|
|
3
|
+
|
|
4
|
+
function jsonResponse(body: unknown, status = 200) {
|
|
5
|
+
const s = typeof body === 'string' ? body : JSON.stringify(body)
|
|
6
|
+
return new Response(s, {
|
|
7
|
+
status,
|
|
8
|
+
statusText: status === 200 ? 'OK' : 'Error',
|
|
9
|
+
headers: { 'Content-Type': 'application/json' },
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('lcAxios', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.stubGlobal(
|
|
16
|
+
'fetch',
|
|
17
|
+
vi.fn().mockImplementation(() => Promise.resolve(jsonResponse({ ok: true })))
|
|
18
|
+
)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
vi.unstubAllGlobals()
|
|
23
|
+
vi.restoreAllMocks()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('GET sends method GET, URL, and no body', async () => {
|
|
27
|
+
const client = axios.create()
|
|
28
|
+
await client.get('https://api.example.com/v1/items', { params: { a: '1', b: '2' } })
|
|
29
|
+
|
|
30
|
+
expect(fetch).toHaveBeenCalledTimes(1)
|
|
31
|
+
const [url, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
32
|
+
expect(url).toBe('https://api.example.com/v1/items?a=1&b=2')
|
|
33
|
+
expect(init?.method).toBe('GET')
|
|
34
|
+
expect(init?.body).toBeUndefined()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('GET with decompress: true (axios compat) still works; option not passed to fetch', async () => {
|
|
38
|
+
const client = axios.create()
|
|
39
|
+
await client.get('https://api.example.com/x', { decompress: true })
|
|
40
|
+
|
|
41
|
+
const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
42
|
+
expect(init).toBeDefined()
|
|
43
|
+
expect((init as RequestInit).decompress).toBeUndefined()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('POST JSON object stringifies body and sets Content-Type', async () => {
|
|
47
|
+
const client = axios.create()
|
|
48
|
+
await client.post('https://api.example.com/data', { foo: 'bar' })
|
|
49
|
+
|
|
50
|
+
const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
51
|
+
expect(init?.method).toBe('POST')
|
|
52
|
+
const headers = init?.headers as Record<string, string>
|
|
53
|
+
expect(headers['Content-Type'] || (headers as any)['content-type']).toMatch(/application\/json/i)
|
|
54
|
+
expect(init?.body).toBe('{"foo":"bar"}')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('POST string body passes through unchanged', async () => {
|
|
58
|
+
const client = axios.create()
|
|
59
|
+
const raw = '{"x":1}'
|
|
60
|
+
await client.post('https://api.example.com/raw', raw)
|
|
61
|
+
|
|
62
|
+
const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
63
|
+
expect(init?.body).toBe(raw)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('POST Uint8Array is not JSON.stringified (binary pass-through)', async () => {
|
|
67
|
+
const client = axios.create()
|
|
68
|
+
const bin = new Uint8Array([0x1f, 0x8b, 0x08, 0x00])
|
|
69
|
+
await client.post('https://api.example.com/bin', bin)
|
|
70
|
+
|
|
71
|
+
const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
72
|
+
expect(init?.body).toBeInstanceOf(Uint8Array)
|
|
73
|
+
const body = init?.body as Uint8Array
|
|
74
|
+
expect([...body]).toEqual([...bin])
|
|
75
|
+
expect(typeof init?.body).not.toBe('string')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('PATCH with baseURL joins path', async () => {
|
|
79
|
+
const client = axios.create({ baseURL: 'https://api.example.com' })
|
|
80
|
+
await client.patch('/tenant/sku', [{ id: '1' }])
|
|
81
|
+
|
|
82
|
+
const [url] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
83
|
+
expect(url).toBe('https://api.example.com/tenant/sku')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('callable axios(config) merges method and url', async () => {
|
|
87
|
+
await axios({
|
|
88
|
+
method: 'put',
|
|
89
|
+
url: 'https://api.example.com/x',
|
|
90
|
+
data: { a: 1 },
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
94
|
+
expect(init?.method).toBe('PUT')
|
|
95
|
+
expect(init?.body).toBe('{"a":1}')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('async transformRequest runs after default JSON stringify', async () => {
|
|
99
|
+
const client = axios.create({
|
|
100
|
+
transformRequest: [
|
|
101
|
+
async (data, _headers) => {
|
|
102
|
+
if (typeof data === 'string' && data.includes('"n":1')) return 'replaced-by-async'
|
|
103
|
+
return data
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
})
|
|
107
|
+
await client.post('https://api.example.com/t', { n: 1 })
|
|
108
|
+
|
|
109
|
+
const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
110
|
+
expect(init?.body).toBe('replaced-by-async')
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('validateStatus: rejects non-2xx by default with AxiosError and response', async () => {
|
|
114
|
+
vi.mocked(fetch).mockResolvedValueOnce(jsonResponse({ err: true }, 400))
|
|
115
|
+
|
|
116
|
+
const client = axios.create()
|
|
117
|
+
await expect(client.get('https://api.example.com/fail')).rejects.toMatchObject({
|
|
118
|
+
isAxiosError: true,
|
|
119
|
+
response: { status: 400, data: { err: true } },
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('validateStatus accepts custom success when it returns true for 404', async () => {
|
|
124
|
+
vi.mocked(fetch).mockResolvedValueOnce(jsonResponse({ missing: true }, 404))
|
|
125
|
+
|
|
126
|
+
const client = axios.create()
|
|
127
|
+
const res = await client.get('https://api.example.com/maybe', {
|
|
128
|
+
validateStatus: (s) => s === 404,
|
|
129
|
+
})
|
|
130
|
+
expect(res.status).toBe(404)
|
|
131
|
+
expect(res.data).toEqual({ missing: true })
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('axiosRetry retries when retryCondition passes and fetch then succeeds', async () => {
|
|
135
|
+
vi.mocked(fetch).mockReset()
|
|
136
|
+
vi.mocked(fetch).mockRejectedValueOnce(new TypeError('Failed to fetch'))
|
|
137
|
+
vi.mocked(fetch).mockResolvedValueOnce(jsonResponse({ ok: true }))
|
|
138
|
+
|
|
139
|
+
const client = axios.create()
|
|
140
|
+
axiosRetry(client, {
|
|
141
|
+
retries: 3,
|
|
142
|
+
retryDelay: () => 0,
|
|
143
|
+
retryCondition: () => true,
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
const res = await client.get('https://api.example.com/retry')
|
|
147
|
+
expect(res.data).toEqual({ ok: true })
|
|
148
|
+
expect(fetch).toHaveBeenCalledTimes(2)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('withCredentials sets fetch credentials include', async () => {
|
|
152
|
+
const client = axios.create({ withCredentials: true })
|
|
153
|
+
await client.get('https://api.example.com/cookie')
|
|
154
|
+
|
|
155
|
+
const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0]
|
|
156
|
+
expect(init?.credentials).toBe('include')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('network failure sets isAxiosError and message Network Error', async () => {
|
|
160
|
+
vi.mocked(fetch).mockRejectedValueOnce(new TypeError('Failed to fetch'))
|
|
161
|
+
|
|
162
|
+
const client = axios.create()
|
|
163
|
+
try {
|
|
164
|
+
await client.get('https://api.example.com/down')
|
|
165
|
+
expect.fail('should throw')
|
|
166
|
+
} catch (e) {
|
|
167
|
+
const err = e as AxiosError
|
|
168
|
+
expect(err.isAxiosError).toBe(true)
|
|
169
|
+
expect(err.message).toBe('Network Error')
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
})
|
package/vitest.config.ts
CHANGED
|
@@ -7,7 +7,7 @@ export default defineConfig({
|
|
|
7
7
|
// Timeout for each test (5 minutes for long-running tests like imageBinder)
|
|
8
8
|
testTimeout: 300000,
|
|
9
9
|
// Include test files
|
|
10
|
-
include: ['test/**/*.spec.js'],
|
|
10
|
+
include: ['test/**/*.spec.js', 'test/**/*.spec.ts'],
|
|
11
11
|
// Coverage configuration (optional)
|
|
12
12
|
coverage: {
|
|
13
13
|
provider: 'v8',
|