Skip to content
This repository was archived by the owner on Oct 9, 2025. It is now read-only.

Commit e3c4ad6

Browse files
committed
add more test coverage
1 parent 7262657 commit e3c4ad6

File tree

5 files changed

+385
-111
lines changed

5 files changed

+385
-111
lines changed

test/errors.test.ts

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import {
2+
StorageError,
3+
StorageApiError,
4+
StorageUnknownError,
5+
isStorageError,
6+
} from '../src/lib/errors'
7+
8+
describe('Storage Errors', () => {
9+
describe('StorageError', () => {
10+
test('creates StorageError with message', () => {
11+
const error = new StorageError('Test error')
12+
expect(error.message).toBe('Test error')
13+
expect(error.name).toBe('StorageError')
14+
expect(error).toBeInstanceOf(Error)
15+
expect(error).toBeInstanceOf(StorageError)
16+
})
17+
18+
test('has __isStorageError property', () => {
19+
const error = new StorageError('Test error')
20+
// @ts-ignore - accessing private property for test
21+
expect(error.__isStorageError).toBe(true)
22+
})
23+
})
24+
25+
describe('StorageApiError', () => {
26+
test('creates StorageApiError with all parameters', () => {
27+
const error = new StorageApiError('API error', 404, 'NOT_FOUND')
28+
expect(error.message).toBe('API error')
29+
expect(error.name).toBe('StorageApiError')
30+
expect(error.status).toBe(404)
31+
expect(error.statusCode).toBe('NOT_FOUND')
32+
expect(error).toBeInstanceOf(Error)
33+
expect(error).toBeInstanceOf(StorageError)
34+
expect(error).toBeInstanceOf(StorageApiError)
35+
})
36+
37+
test('toJSON returns correct format', () => {
38+
const error = new StorageApiError('API error', 500, 'INTERNAL_ERROR')
39+
const json = error.toJSON()
40+
expect(json).toEqual({
41+
name: 'StorageApiError',
42+
message: 'API error',
43+
status: 500,
44+
statusCode: 'INTERNAL_ERROR',
45+
})
46+
})
47+
})
48+
49+
describe('StorageUnknownError', () => {
50+
test('creates StorageUnknownError with original error', () => {
51+
const originalError = new Error('Original error')
52+
const error = new StorageUnknownError('Unknown error occurred', originalError)
53+
54+
expect(error.message).toBe('Unknown error occurred')
55+
expect(error.name).toBe('StorageUnknownError')
56+
expect(error.originalError).toBe(originalError)
57+
expect(error).toBeInstanceOf(Error)
58+
expect(error).toBeInstanceOf(StorageError)
59+
expect(error).toBeInstanceOf(StorageUnknownError)
60+
})
61+
62+
test('preserves original error of any type', () => {
63+
const originalError = { custom: 'error object' }
64+
const error = new StorageUnknownError('Unknown error', originalError)
65+
expect(error.originalError).toBe(originalError)
66+
})
67+
})
68+
69+
describe('isStorageError', () => {
70+
test('returns true for StorageError instances', () => {
71+
const error = new StorageError('Test error')
72+
expect(isStorageError(error)).toBe(true)
73+
})
74+
75+
test('returns true for StorageApiError instances', () => {
76+
const error = new StorageApiError('API error', 404, 'NOT_FOUND')
77+
expect(isStorageError(error)).toBe(true)
78+
})
79+
80+
test('returns true for StorageUnknownError instances', () => {
81+
const error = new StorageUnknownError('Unknown error', new Error())
82+
expect(isStorageError(error)).toBe(true)
83+
})
84+
85+
test('returns false for regular Error', () => {
86+
const error = new Error('Regular error')
87+
expect(isStorageError(error)).toBe(false)
88+
})
89+
90+
test('returns false for non-objects', () => {
91+
expect(isStorageError('string')).toBe(false)
92+
expect(isStorageError(123)).toBe(false)
93+
expect(isStorageError(null)).toBe(false)
94+
expect(isStorageError(undefined)).toBe(false)
95+
})
96+
97+
test('returns false for objects without __isStorageError', () => {
98+
const obj = { name: 'Error', message: 'test' }
99+
expect(isStorageError(obj)).toBe(false)
100+
})
101+
})
102+
})

test/exports.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
describe('Module Exports', () => {
2+
test('can import main module successfully', () => {
3+
const mainExports = require('../src/index')
4+
expect(mainExports.StorageClient).toBeDefined()
5+
expect(typeof mainExports).toBe('object')
6+
})
7+
8+
test('can import lib module successfully', () => {
9+
const libExports = require('../src/lib/index')
10+
expect(typeof libExports).toBe('object')
11+
})
12+
13+
test('constants are accessible', () => {
14+
const constants = require('../src/lib/constants')
15+
expect(constants.DEFAULT_HEADERS).toBeDefined()
16+
})
17+
})

test/helpers.test.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import { resolveFetch, resolveResponse, recursiveToCamel, isPlainObject } from '../src/lib/helpers'
2+
3+
describe('Helpers', () => {
4+
describe('resolveFetch', () => {
5+
test('returns wrapper function with custom fetch', () => {
6+
const customFetch = jest.fn()
7+
const result = resolveFetch(customFetch)
8+
expect(typeof result).toBe('function')
9+
})
10+
11+
test('returns wrapper function with global fetch', () => {
12+
const originalFetch = global.fetch
13+
const mockFetch = jest.fn()
14+
global.fetch = mockFetch
15+
16+
const result = resolveFetch()
17+
expect(typeof result).toBe('function')
18+
19+
global.fetch = originalFetch
20+
})
21+
22+
test('returns dynamic import when fetch is undefined', async () => {
23+
const originalFetch = global.fetch
24+
// @ts-ignore
25+
global.fetch = undefined
26+
27+
const result = resolveFetch()
28+
expect(typeof result).toBe('function')
29+
30+
global.fetch = originalFetch
31+
})
32+
})
33+
34+
describe('resolveResponse', () => {
35+
test('returns Response constructor when available', async () => {
36+
// In Node.js, Response might not be globally available
37+
const originalResponse = global.Response
38+
// @ts-ignore
39+
global.Response = class MockResponse {}
40+
41+
const result = await resolveResponse()
42+
expect(typeof result).toBe('function')
43+
44+
global.Response = originalResponse
45+
})
46+
47+
test('returns dynamic import when Response is undefined', async () => {
48+
const originalResponse = global.Response
49+
// @ts-ignore
50+
global.Response = undefined
51+
52+
const result = await resolveResponse()
53+
expect(typeof result).toBe('function')
54+
55+
global.Response = originalResponse
56+
})
57+
})
58+
59+
describe('recursiveToCamel', () => {
60+
test('converts snake_case to camelCase', () => {
61+
const input = { snake_case: 'value', another_key: 'test' }
62+
const result = recursiveToCamel(input)
63+
expect(result).toEqual({ snakeCase: 'value', anotherKey: 'test' })
64+
})
65+
66+
test('converts kebab-case to camelCase', () => {
67+
const input = { 'kebab-case': 'value' }
68+
const result = recursiveToCamel(input)
69+
expect(result).toEqual({ kebabCase: 'value' })
70+
})
71+
72+
test('handles nested objects', () => {
73+
const input = { outer_key: { inner_key: 'value' } }
74+
const result = recursiveToCamel(input)
75+
expect(result).toEqual({ outerKey: { innerKey: 'value' } })
76+
})
77+
78+
test('handles arrays', () => {
79+
const input = [{ snake_case: 'value1' }, { another_key: 'value2' }]
80+
const result = recursiveToCamel(input)
81+
expect(result).toEqual([{ snakeCase: 'value1' }, { anotherKey: 'value2' }])
82+
})
83+
84+
test('returns functions unchanged', () => {
85+
const func = () => {}
86+
const result = recursiveToCamel(func)
87+
expect(result).toBe(func)
88+
})
89+
90+
test('returns non-objects unchanged', () => {
91+
expect(recursiveToCamel('string' as any)).toBe('string')
92+
expect(recursiveToCamel(123 as any)).toBe(123)
93+
expect(recursiveToCamel(null as any)).toBe(null)
94+
})
95+
})
96+
97+
describe('isPlainObject', () => {
98+
test('returns true for plain objects', () => {
99+
expect(isPlainObject({})).toBe(true)
100+
expect(isPlainObject(new Object())).toBe(true)
101+
expect(isPlainObject(Object.create(null))).toBe(true)
102+
expect(isPlainObject({ key: 'value' })).toBe(true)
103+
})
104+
105+
test('returns false for non-objects', () => {
106+
expect(isPlainObject('string' as any)).toBe(false)
107+
expect(isPlainObject(123 as any)).toBe(false)
108+
expect(isPlainObject(null as any)).toBe(false)
109+
expect(isPlainObject(undefined as any)).toBe(false)
110+
})
111+
112+
test('returns false for arrays', () => {
113+
expect(isPlainObject([])).toBe(false)
114+
expect(isPlainObject([1, 2, 3])).toBe(false)
115+
})
116+
117+
test('returns false for functions', () => {
118+
expect(isPlainObject(() => {})).toBe(false)
119+
expect(isPlainObject(function () {})).toBe(false)
120+
})
121+
122+
test('returns false for class instances', () => {
123+
class TestClass {}
124+
expect(isPlainObject(new TestClass())).toBe(false)
125+
expect(isPlainObject(new Date())).toBe(false)
126+
expect(isPlainObject(new Error())).toBe(false)
127+
})
128+
129+
test('returns false for objects with toStringTag', () => {
130+
const obj = {}
131+
Object.defineProperty(obj, Symbol.toStringTag, { value: 'CustomObject' })
132+
expect(isPlainObject(obj)).toBe(false)
133+
})
134+
135+
test('returns false for iterables', () => {
136+
const obj = {}
137+
Object.defineProperty(obj, Symbol.iterator, { value: function* () {} })
138+
expect(isPlainObject(obj)).toBe(false)
139+
})
140+
})
141+
})

0 commit comments

Comments
 (0)