@easyflow/javascript-sdk 2.1.8 → 2.1.9

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.
Files changed (94) hide show
  1. package/README.md +71 -7
  2. package/dist/index.d.ts +421 -0
  3. package/package.json +19 -6
  4. package/.babelrc +0 -5
  5. package/.github/workflows/deploy-sdk-cf.yml +0 -49
  6. package/.github/workflows/release-sdk-cdn.yml +0 -144
  7. package/.github/workflows/release-sdk.yml +0 -112
  8. package/.prettierrc +0 -6
  9. package/CDN-DEPLOYMENT.md +0 -175
  10. package/DEMO.md +0 -258
  11. package/DEPLOYMENT.md +0 -224
  12. package/INTEGRATION-GUIDE.md +0 -521
  13. package/coverage/base.css +0 -224
  14. package/coverage/block-navigation.js +0 -87
  15. package/coverage/easyflow-javascript-sdk/index.html +0 -116
  16. package/coverage/easyflow-javascript-sdk/libs/constants.mjs.html +0 -268
  17. package/coverage/easyflow-javascript-sdk/libs/errors.mjs.html +0 -271
  18. package/coverage/easyflow-javascript-sdk/libs/exception-handler.mjs.html +0 -148
  19. package/coverage/easyflow-javascript-sdk/libs/fingerprint.mjs.html +0 -895
  20. package/coverage/easyflow-javascript-sdk/libs/http.mjs.html +0 -502
  21. package/coverage/easyflow-javascript-sdk/libs/index.html +0 -266
  22. package/coverage/easyflow-javascript-sdk/libs/logger.mjs.html +0 -568
  23. package/coverage/easyflow-javascript-sdk/libs/sanitizer.mjs.html +0 -1099
  24. package/coverage/easyflow-javascript-sdk/libs/security.mjs.html +0 -733
  25. package/coverage/easyflow-javascript-sdk/libs/types.mjs.html +0 -508
  26. package/coverage/easyflow-javascript-sdk/libs/utils.mjs.html +0 -379
  27. package/coverage/easyflow-javascript-sdk/libs/validator.mjs.html +0 -2623
  28. package/coverage/easyflow-javascript-sdk/sdk.mjs.html +0 -2434
  29. package/coverage/favicon.png +0 -0
  30. package/coverage/index.html +0 -131
  31. package/coverage/lcov-report/base.css +0 -224
  32. package/coverage/lcov-report/block-navigation.js +0 -87
  33. package/coverage/lcov-report/easyflow-javascript-sdk/index.html +0 -116
  34. package/coverage/lcov-report/easyflow-javascript-sdk/libs/constants.mjs.html +0 -268
  35. package/coverage/lcov-report/easyflow-javascript-sdk/libs/errors.mjs.html +0 -271
  36. package/coverage/lcov-report/easyflow-javascript-sdk/libs/exception-handler.mjs.html +0 -148
  37. package/coverage/lcov-report/easyflow-javascript-sdk/libs/fingerprint.mjs.html +0 -895
  38. package/coverage/lcov-report/easyflow-javascript-sdk/libs/http.mjs.html +0 -502
  39. package/coverage/lcov-report/easyflow-javascript-sdk/libs/index.html +0 -266
  40. package/coverage/lcov-report/easyflow-javascript-sdk/libs/logger.mjs.html +0 -568
  41. package/coverage/lcov-report/easyflow-javascript-sdk/libs/sanitizer.mjs.html +0 -1099
  42. package/coverage/lcov-report/easyflow-javascript-sdk/libs/security.mjs.html +0 -733
  43. package/coverage/lcov-report/easyflow-javascript-sdk/libs/types.mjs.html +0 -508
  44. package/coverage/lcov-report/easyflow-javascript-sdk/libs/utils.mjs.html +0 -379
  45. package/coverage/lcov-report/easyflow-javascript-sdk/libs/validator.mjs.html +0 -2623
  46. package/coverage/lcov-report/easyflow-javascript-sdk/sdk.mjs.html +0 -2434
  47. package/coverage/lcov-report/favicon.png +0 -0
  48. package/coverage/lcov-report/index.html +0 -131
  49. package/coverage/lcov-report/prettify.css +0 -1
  50. package/coverage/lcov-report/prettify.js +0 -2
  51. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  52. package/coverage/lcov-report/sorter.js +0 -196
  53. package/coverage/lcov.info +0 -1429
  54. package/coverage/prettify.css +0 -1
  55. package/coverage/prettify.js +0 -2
  56. package/coverage/sort-arrow-sprite.png +0 -0
  57. package/coverage/sorter.js +0 -196
  58. package/dist/435.easyflow-sdk.min.js +0 -1
  59. package/dist/easyflow-sdk.min.js +0 -1
  60. package/dist/easyflow-sdk.min.js.LICENSE.txt +0 -1
  61. package/dist/index.html +0 -756
  62. package/docs/index.html +0 -775
  63. package/examples/lovable-integration.html +0 -410
  64. package/index.html +0 -981
  65. package/jest.config.js +0 -37
  66. package/jsdoc.json +0 -42
  67. package/libs/auto-integration.mjs +0 -333
  68. package/libs/constants.mjs +0 -61
  69. package/libs/constants.spec.js +0 -198
  70. package/libs/errors.mjs +0 -62
  71. package/libs/errors.spec.js +0 -178
  72. package/libs/exception-handler.mjs +0 -21
  73. package/libs/exception-handler.spec.js +0 -237
  74. package/libs/fingerprint.mjs +0 -270
  75. package/libs/http.mjs +0 -163
  76. package/libs/http.spec.js +0 -427
  77. package/libs/integration-wrapper.mjs +0 -285
  78. package/libs/logger.mjs +0 -161
  79. package/libs/logger.spec.js +0 -389
  80. package/libs/sanitizer.mjs +0 -340
  81. package/libs/sanitizer.spec.js +0 -583
  82. package/libs/security.mjs +0 -217
  83. package/libs/types.mjs +0 -141
  84. package/libs/utils.mjs +0 -368
  85. package/libs/utils.spec.js +0 -231
  86. package/libs/validator.mjs +0 -952
  87. package/libs/validator.spec.js +0 -615
  88. package/mocks/offer.mock.js +0 -77
  89. package/scripts/publish-npm.sh +0 -82
  90. package/sdk.mjs +0 -945
  91. package/sdk.spec.js +0 -796
  92. package/test-setup.cjs +0 -211
  93. package/test.html +0 -154
  94. package/webpack.config.cjs +0 -41
package/libs/utils.mjs DELETED
@@ -1,368 +0,0 @@
1
- /**
2
- * Utility functions for Easyflow SDK
3
- */
4
-
5
- import { PAYMENT_METHODS } from '../sdk.mjs'
6
-
7
- /**
8
- * Deep clone an object using JSON serialization
9
- * @param {*} data - Data to clone
10
- * @returns {*} Cloned data
11
- */
12
- export function deepClone(data) {
13
- return JSON.parse(JSON.stringify(data))
14
- }
15
-
16
- /**
17
- * Prepare order data by mapping payments
18
- * @param {Object} data - Order data
19
- * @returns {Object} Prepared order data
20
- */
21
- export function mapCreditCardIfNeeded(data) {
22
- const clonedData = deepClone(data)
23
- clonedData.payments = clonedData.payments.map((payment) => {
24
- if (payment.method === PAYMENT_METHODS.CREDIT_CARD) {
25
- return {
26
- ...payment,
27
- rawCreditCard: payment.creditCard,
28
- }
29
- }
30
- return payment
31
- })
32
- return clonedData
33
- }
34
-
35
- /**
36
- * Find payment by method in order data
37
- * @param {Object} order - Order data
38
- * @param {string} method - Payment method to find
39
- * @param {Function} validator - Validation function for the payment data
40
- * @returns {Object|null} Payment data or null if not found
41
- */
42
- export function findPaymentByMethod(order, method, validator) {
43
- if (!order?.payments?.length) {
44
- return null
45
- }
46
-
47
- const payment = order.payments.find(
48
- (payment) => payment.method === method && validator(payment)
49
- )
50
-
51
- return payment || null
52
- }
53
-
54
- /**
55
- * Validate PIX payment data
56
- * @param {Object} payment - Payment object
57
- * @returns {boolean} True if valid PIX payment
58
- */
59
- export function isValidPixPayment(payment) {
60
- return payment.pix && (payment.pix.qrCode || payment.pix.copyAndPasteCode)
61
- }
62
-
63
- /**
64
- * Validate bank billet payment data
65
- * @param {Object} payment - Payment object
66
- * @returns {boolean} True if valid bank billet payment
67
- */
68
- export function isValidBankBilletPayment(payment) {
69
- return (
70
- payment.bankBillet &&
71
- (payment.bankBillet.link ||
72
- payment.bankBillet.line ||
73
- payment.bankBillet.barCode)
74
- )
75
- }
76
-
77
- /**
78
- * Merge headers with default headers
79
- * @param {Object} defaultHeaders - Default headers
80
- * @param {Object} additionalHeaders - Additional headers
81
- * @returns {Object} Merged headers
82
- */
83
- export function mergeHeaders(defaultHeaders = {}, additionalHeaders = {}) {
84
- return { ...defaultHeaders, ...additionalHeaders }
85
- }
86
-
87
- /**
88
- * Build API URL with target and parameters
89
- * @param {string} baseUrl - Base URL
90
- * @param {string} target - API target
91
- * @param {Object} params - URL parameters
92
- * @returns {string} Complete API URL
93
- */
94
- export function buildApiUrl(baseUrl, target, params = {}) {
95
- const url = new URL(`/api/proxy?target=${target}`, baseUrl).toString()
96
- const queryParams = new URLSearchParams(params).toString()
97
- return queryParams ? `${url}&${queryParams}` : url
98
- }
99
-
100
- /**
101
- * Generate browser fingerprint for security and tracking
102
- * @param {Object} options - Fingerprint options
103
- * @param {boolean} options.hardwareOnly - Only use hardware-based data
104
- * @param {boolean} options.enableWebgl - Enable WebGL fingerprinting
105
- * @param {boolean} options.debug - Enable debug logging
106
- * @returns {string} Fingerprint hash
107
- */
108
- export function getBrowserFingerprint({ hardwareOnly = false, enableWebgl = false, debug = false } = {}) {
109
- const {
110
- cookieEnabled,
111
- deviceMemory,
112
- doNotTrack,
113
- hardwareConcurrency,
114
- language,
115
- languages,
116
- maxTouchPoints,
117
- platform,
118
- userAgent,
119
- vendor
120
- } = window.navigator
121
-
122
- let { width, height, colorDepth, pixelDepth } = window.screen
123
- width = 1000
124
- height = 1000
125
-
126
- const timezoneOffset = (new Date()).getTimezoneOffset()
127
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
128
- const touchSupport = 'ontouchstart' in window
129
- const devicePixelRatio = window.devicePixelRatio
130
- const canvas = getCanvasID(debug)
131
- const webgl = enableWebgl ? getWebglID(debug) : undefined
132
- const webglInfo = enableWebgl ? getWebglInfo(debug) : undefined
133
-
134
- const fingerprintData = hardwareOnly
135
- ? JSON.stringify({
136
- canvas,
137
- colorDepth,
138
- deviceMemory,
139
- devicePixelRatio,
140
- hardwareConcurrency,
141
- height,
142
- maxTouchPoints,
143
- pixelDepth,
144
- platform,
145
- touchSupport,
146
- webgl,
147
- webglInfo,
148
- width
149
- })
150
- : JSON.stringify({
151
- canvas,
152
- colorDepth,
153
- cookieEnabled,
154
- deviceMemory,
155
- devicePixelRatio,
156
- doNotTrack,
157
- hardwareConcurrency,
158
- height,
159
- language,
160
- languages,
161
- maxTouchPoints,
162
- pixelDepth,
163
- platform,
164
- timezone,
165
- timezoneOffset,
166
- touchSupport,
167
- userAgent,
168
- vendor,
169
- webgl,
170
- webglInfo,
171
- width
172
- })
173
-
174
- const fingerprintJson = JSON.stringify(fingerprintData, null, 4)
175
-
176
- if (debug) {
177
- console.log('fingerprint data', fingerprintJson)
178
- }
179
-
180
- return murmurhash3_32_gc(fingerprintJson)
181
- }
182
-
183
- /**
184
- * Generate canvas fingerprint ID
185
- * @param {boolean} debug - Enable debug mode
186
- * @returns {string|null} Canvas fingerprint hash
187
- */
188
- function getCanvasID(debug = false) {
189
- try {
190
- const canvas = document.createElement('canvas')
191
- const ctx = canvas.getContext('2d')
192
- const text = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}|;:\',<.>/?'
193
-
194
- ctx.textBaseline = 'top'
195
- ctx.font = '14px \'Arial\''
196
- ctx.textBaseline = 'alphabetic'
197
- ctx.fillStyle = '#f60'
198
- ctx.fillRect(125, 1, 62, 20)
199
- ctx.fillStyle = '#069'
200
- ctx.fillText(text, 2, 15)
201
- ctx.fillStyle = 'rgba(102, 204, 0, 0.7)'
202
- ctx.fillText(text, 4, 17)
203
-
204
- const dataURL = canvas.toDataURL()
205
-
206
- if (debug) {
207
- document.body.appendChild(canvas)
208
- } else {
209
- ctx.clearRect(0, 0, canvas.width, canvas.height)
210
- }
211
-
212
- return murmurhash3_32_gc(dataURL)
213
- } catch {
214
- return null
215
- }
216
- }
217
-
218
- /**
219
- * Generate WebGL fingerprint ID
220
- * @param {boolean} debug - Enable debug mode
221
- * @returns {string|null} WebGL fingerprint hash
222
- */
223
- function getWebglID(debug = false) {
224
- try {
225
- const canvas = document.createElement('canvas')
226
- const gl = canvas.getContext('webgl')
227
-
228
- canvas.width = 256
229
- canvas.height = 128
230
-
231
- const vertexShaderSource = `
232
- attribute vec2 attrVertex;
233
- varying vec2 varyinTexCoordinate;
234
- uniform vec2 uniformOffset;
235
- void main() {
236
- varyinTexCoordinate = attrVertex + uniformOffset;
237
- gl_Position = vec4(attrVertex, 0, 1);
238
- }
239
- `
240
-
241
- const fragmentShaderSource = `
242
- precision mediump float;
243
- varying vec2 varyinTexCoordinate;
244
- void main() {
245
- gl_FragColor = vec4(varyinTexCoordinate, 0, 1);
246
- }
247
- `
248
-
249
- const buffer = gl.createBuffer()
250
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
251
-
252
- const vertices = new Float32Array([-0.2, -0.9, 0, 0.4, -0.26, 0, 0, 0.7321, 0])
253
- gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
254
- buffer.itemSize = 3
255
- buffer.numItems = 3
256
-
257
- const program = gl.createProgram()
258
- const vertexShader = gl.createShader(gl.VERTEX_SHADER)
259
- gl.shaderSource(vertexShader, vertexShaderSource)
260
- gl.compileShader(vertexShader)
261
-
262
- const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
263
- gl.shaderSource(fragmentShader, fragmentShaderSource)
264
- gl.compileShader(fragmentShader)
265
-
266
- gl.attachShader(program, vertexShader)
267
- gl.attachShader(program, fragmentShader)
268
- gl.linkProgram(program)
269
- gl.useProgram(program)
270
-
271
- program.vertexPosAttrib = gl.getAttribLocation(program, 'attrVertex')
272
- program.offsetUniform = gl.getUniformLocation(program, 'uniformOffset')
273
-
274
- gl.enableVertexAttribArray(program.vertexPosAttrib)
275
- gl.vertexAttribPointer(program.vertexPosAttrib, buffer.itemSize, gl.FLOAT, false, 0, 0)
276
- gl.uniform2f(program.offsetUniform, 1, 1)
277
- gl.drawArrays(gl.TRIANGLE_STRIP, 0, buffer.numItems)
278
-
279
- const pixels = new Uint8Array(canvas.width * canvas.height * 4)
280
- gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
281
-
282
- const pixelsString = JSON.stringify(pixels).replace(/,?"[0-9]+":/g, '')
283
-
284
- if (debug) {
285
- document.body.appendChild(canvas)
286
- } else {
287
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
288
- }
289
-
290
- return murmurhash3_32_gc(pixelsString)
291
- } catch {
292
- return null
293
- }
294
- }
295
-
296
- /**
297
- * Get WebGL information
298
- * @param {boolean} debug - Enable debug mode
299
- * @returns {Object|null} WebGL information
300
- */
301
- function getWebglInfo(debug = false) {
302
- try {
303
- const canvas = document.createElement('canvas')
304
- const gl = canvas.getContext('webgl')
305
-
306
- return {
307
- VERSION: gl.getParameter(gl.VERSION),
308
- SHADING_LANGUAGE_VERSION: gl.getParameter(gl.SHADING_LANGUAGE_VERSION),
309
- VENDOR: gl.getParameter(gl.VENDOR),
310
- SUPORTED_EXTENSIONS: gl.getSupportedExtensions()
311
- }
312
- } catch {
313
- return null
314
- }
315
- }
316
-
317
- /**
318
- * MurmurHash3 implementation for fingerprint generation
319
- * @param {string} str - String to hash
320
- * @returns {string} Hash result
321
- */
322
- function murmurhash3_32_gc(str) {
323
- const c1 = 0xcc9e2d51
324
- const c2 = 0x1b873593
325
- const r1 = 15
326
- const r2 = 13
327
- const m = 5
328
- const n = 0xe6546b64
329
-
330
- let h = 0xdeadbeef
331
- let k
332
-
333
- for (let i = 0; i < str.length; i += 4) {
334
- k = str.charCodeAt(i) |
335
- (str.charCodeAt(i + 1) << 8) |
336
- (str.charCodeAt(i + 2) << 16) |
337
- (str.charCodeAt(i + 3) << 24)
338
-
339
- k = Math.imul(k, c1)
340
- k = (k << r1) | (k >>> (32 - r1))
341
- k = Math.imul(k, c2)
342
-
343
- h ^= k
344
- h = (h << r2) | (h >>> (32 - r2))
345
- h = Math.imul(h, m) + n
346
- }
347
-
348
- const remaining = str.length % 4
349
- if (remaining > 0) {
350
- let k = 0
351
- for (let i = str.length - remaining; i < str.length; i++) {
352
- k |= str.charCodeAt(i) << ((i - (str.length - remaining)) * 8)
353
- }
354
- k = Math.imul(k, c1)
355
- k = (k << r1) | (k >>> (32 - r1))
356
- k = Math.imul(k, c2)
357
- h ^= k
358
- }
359
-
360
- h ^= str.length
361
- h ^= h >>> 16
362
- h = Math.imul(h, 0x85ebca6b)
363
- h ^= h >>> 13
364
- h = Math.imul(h, 0xc2b2ae35)
365
- h ^= h >>> 16
366
-
367
- return (h >>> 0).toString(16)
368
- }
@@ -1,231 +0,0 @@
1
- import { jest, describe, it, expect, beforeEach } from '@jest/globals'
2
-
3
- // Mock PAYMENT_METHODS para evitar import do SDK completo
4
- await jest.unstable_mockModule('../sdk.mjs', () => ({
5
- PAYMENT_METHODS: {
6
- CREDIT_CARD: 'credit-card',
7
- PIX: 'pix',
8
- BANK_BILLET: 'bank-billet',
9
- },
10
- }))
11
-
12
- const {
13
- deepClone,
14
- mapCreditCardIfNeeded,
15
- findPaymentByMethod,
16
- isValidPixPayment,
17
- isValidBankBilletPayment,
18
- mergeHeaders,
19
- buildApiUrl,
20
- } = await import('./utils.mjs')
21
-
22
- describe('Utils', () => {
23
- describe('deepClone', () => {
24
- it('should clone simple object', () => {
25
- const obj = { a: 1, b: 'x' }
26
- const cloned = deepClone(obj)
27
- expect(cloned).toEqual(obj)
28
- expect(cloned).not.toBe(obj)
29
- })
30
-
31
- it('should clone nested object', () => {
32
- const obj = { a: { b: { c: 1 } } }
33
- const cloned = deepClone(obj)
34
- expect(cloned).toEqual(obj)
35
- expect(cloned.a).not.toBe(obj.a)
36
- })
37
-
38
- it('should clone array', () => {
39
- const arr = [1, { a: 2 }, [3]]
40
- const cloned = deepClone(arr)
41
- expect(cloned).toEqual(arr)
42
- expect(cloned).not.toBe(arr)
43
- })
44
-
45
- it('should handle primitive values', () => {
46
- expect(deepClone(1)).toBe(1)
47
- expect(deepClone('x')).toBe('x')
48
- expect(deepClone(true)).toBe(true)
49
- })
50
-
51
- it('should handle empty objects and arrays', () => {
52
- expect(deepClone({})).toEqual({})
53
- expect(deepClone([])).toEqual([])
54
- })
55
- })
56
-
57
- describe('mapCreditCardIfNeeded', () => {
58
- it('should map credit card payment correctly', () => {
59
- const data = {
60
- payments: [
61
- { method: 'credit-card', creditCard: { token: 't', n: 1 } },
62
- ],
63
- }
64
- const result = mapCreditCardIfNeeded(data)
65
- expect(result).not.toBe(data)
66
- expect(result.payments[0].rawCreditCard).toEqual({
67
- token: 't',
68
- n: 1,
69
- })
70
- // não deve remover creditCard original
71
- expect(result.payments[0].creditCard).toEqual({ token: 't', n: 1 })
72
- })
73
-
74
- it('should not modify non-credit-card payments', () => {
75
- const data = {
76
- payments: [{ method: 'pix' }, { method: 'bank-billet' }],
77
- }
78
- const result = mapCreditCardIfNeeded(data)
79
- expect(result.payments).toEqual(data.payments)
80
- })
81
-
82
- it('should handle mixed payment methods', () => {
83
- const data = {
84
- payments: [
85
- { method: 'pix' },
86
- { method: 'credit-card', creditCard: { token: 'abc' } },
87
- ],
88
- }
89
- const result = mapCreditCardIfNeeded(data)
90
- expect(result.payments[1].rawCreditCard).toEqual({ token: 'abc' })
91
- })
92
-
93
- it('should return deep clone of original data', () => {
94
- const data = {
95
- payments: [{ method: 'credit-card', creditCard: { t: 'x' } }],
96
- }
97
- const result = mapCreditCardIfNeeded(data)
98
- expect(result).toEqual({
99
- payments: [
100
- {
101
- method: 'credit-card',
102
- creditCard: { t: 'x' },
103
- rawCreditCard: { t: 'x' },
104
- },
105
- ],
106
- })
107
- expect(result).not.toBe(data)
108
- })
109
- })
110
-
111
- describe('findPaymentByMethod', () => {
112
- it('should find payment by method when validator returns true', () => {
113
- const order = {
114
- payments: [{ method: 'pix', pix: { qrCode: 'q' } }],
115
- }
116
- const validator = (p) => !!p.pix?.qrCode
117
- const found = findPaymentByMethod(order, 'pix', validator)
118
- expect(found).toEqual(order.payments[0])
119
- })
120
-
121
- it('should return null when validator returns false', () => {
122
- const order = { payments: [{ method: 'pix', pix: {} }] }
123
- const validator = (p) => !!p.pix?.qrCode
124
- expect(findPaymentByMethod(order, 'pix', validator)).toBeNull()
125
- })
126
-
127
- it('should return null when payment method not found', () => {
128
- expect(
129
- findPaymentByMethod({ payments: [] }, 'pix', () => true)
130
- ).toBeNull()
131
- })
132
-
133
- it('should return null when order has no payments', () => {
134
- expect(findPaymentByMethod({}, 'pix', () => true)).toBeNull()
135
- expect(findPaymentByMethod(null, 'pix', () => true)).toBeNull()
136
- })
137
- })
138
-
139
- describe('isValidPixPayment', () => {
140
- it('should return true for valid PIX payment with qrCode', () => {
141
- expect(!!isValidPixPayment({ pix: { qrCode: 'x' } })).toBe(true)
142
- })
143
- it('should return true for valid PIX payment with copyAndPasteCode', () => {
144
- expect(
145
- !!isValidPixPayment({ pix: { copyAndPasteCode: 'y' } })
146
- ).toBe(true)
147
- })
148
- it('should return false for invalid pix object', () => {
149
- expect(!!isValidPixPayment({})).toBe(false)
150
- expect(!!isValidPixPayment({ pix: {} })).toBe(false)
151
- expect(!!isValidPixPayment({ pix: null })).toBe(false)
152
- })
153
- })
154
-
155
- describe('isValidBankBilletPayment', () => {
156
- it('should return true for valid bank billet with link', () => {
157
- expect(
158
- !!isValidBankBilletPayment({ bankBillet: { link: 'l' } })
159
- ).toBe(true)
160
- })
161
- it('should return true for valid bank billet with line', () => {
162
- expect(
163
- !!isValidBankBilletPayment({ bankBillet: { line: 'ln' } })
164
- ).toBe(true)
165
- })
166
- it('should return true for valid bank billet with barCode', () => {
167
- expect(
168
- !!isValidBankBilletPayment({ bankBillet: { barCode: 'bc' } })
169
- ).toBe(true)
170
- })
171
- it('should return false for invalid bank billet object', () => {
172
- expect(!!isValidBankBilletPayment({})).toBe(false)
173
- expect(!!isValidBankBilletPayment({ bankBillet: {} })).toBe(false)
174
- expect(!!isValidBankBilletPayment({ bankBillet: null })).toBe(false)
175
- })
176
- })
177
-
178
- describe('mergeHeaders', () => {
179
- it('should merge headers correctly and override defaults', () => {
180
- const defaults = { A: '1', B: '2' }
181
- const add = { B: '3', C: '4' }
182
- expect(mergeHeaders(defaults, add)).toEqual({
183
- A: '1',
184
- B: '3',
185
- C: '4',
186
- })
187
- })
188
-
189
- it('should handle empty and undefined headers', () => {
190
- expect(mergeHeaders({}, {})).toEqual({})
191
- expect(mergeHeaders(undefined, { A: '1' })).toEqual({ A: '1' })
192
- expect(mergeHeaders({ A: '1' }, undefined)).toEqual({ A: '1' })
193
- })
194
- })
195
-
196
- describe('buildApiUrl', () => {
197
- const baseUrl = 'https://api.example.com'
198
-
199
- it('should build URL with target only', () => {
200
- const url = buildApiUrl(baseUrl, 'get-offer')
201
- // accept with or without origin
202
- expect(url).toMatch(
203
- /(https:\/\/api\.example\.com)?\/api\/proxy\?target=get-offer/
204
- )
205
- })
206
-
207
- it('should build URL with target and parameters', () => {
208
- const url = buildApiUrl(baseUrl, 'get-order', { orderId: '123' })
209
- expect(url).toMatch(
210
- /(https:\/\/api\.example\.com)?\/api\/proxy\?target=get-order&orderId=123/
211
- )
212
- })
213
-
214
- it('should handle empty and undefined params', () => {
215
- expect(buildApiUrl(baseUrl, 'x', {})).toMatch(
216
- /(https:\/\/api\.example\.com)?\/api\/proxy\?target=x/
217
- )
218
- expect(buildApiUrl(baseUrl, 'y')).toMatch(
219
- /(https:\/\/api\.example\.com)?\/api\/proxy\?target=y/
220
- )
221
- })
222
-
223
- it('should encode URL parameters correctly', () => {
224
- const url = buildApiUrl(baseUrl, 'search', { q: 'a b+c' })
225
- // allow + or %20 for space encoding
226
- expect(url).toMatch(
227
- /(https:\/\/api\.example\.com)?\/api\/proxy\?target=search&q=a(\+|%20)b%2Bc/
228
- )
229
- })
230
- })
231
- })