@redseat/api 0.0.1
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/README.md +132 -0
- package/agents.md +275 -0
- package/client.md +288 -0
- package/dist/auth.d.ts +5 -0
- package/dist/auth.js +10 -0
- package/dist/client.d.ts +32 -0
- package/dist/client.js +157 -0
- package/dist/crypto.d.ts +36 -0
- package/dist/crypto.js +164 -0
- package/dist/encryption.d.ts +73 -0
- package/dist/encryption.js +238 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/interfaces.d.ts +311 -0
- package/dist/interfaces.js +38 -0
- package/dist/library.d.ts +231 -0
- package/dist/library.js +589 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +33 -0
- package/dist/upload.d.ts +16 -0
- package/dist/upload.js +28 -0
- package/encryption.md +533 -0
- package/libraries.md +1652 -0
- package/package.json +50 -0
- package/server.md +196 -0
- package/test.md +291 -0
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@redseat/api",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "TypeScript API client library for interacting with Redseat servers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/**/*",
|
|
17
|
+
"README.md",
|
|
18
|
+
"*.md"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"redseat",
|
|
22
|
+
"api",
|
|
23
|
+
"client",
|
|
24
|
+
"typescript"
|
|
25
|
+
],
|
|
26
|
+
"author": "Arnaud JEZEQUEL <arnaud.jezequel@gmail.com>",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/yourusername/redseat-svelte.git",
|
|
31
|
+
"directory": "packages/api"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"test:watch": "vitest"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"axios": "^1.11.0",
|
|
40
|
+
"rxjs": "^7.8.2"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"typescript": "^5.8.3",
|
|
44
|
+
"vite": "^7.3.0",
|
|
45
|
+
"vitest": "^4.0.16"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/server.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# ServerApi
|
|
2
|
+
|
|
3
|
+
The `ServerApi` class provides server-level operations for managing libraries, settings, plugins, and credentials.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`ServerApi` handles operations that are not specific to a single library, such as:
|
|
8
|
+
- Listing and creating libraries
|
|
9
|
+
- Getting current user information
|
|
10
|
+
- Managing server settings
|
|
11
|
+
- Listing plugins and credentials
|
|
12
|
+
- Adding credentials to libraries
|
|
13
|
+
|
|
14
|
+
## Constructor
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
new ServerApi(client: RedseatClient)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Parameters:**
|
|
21
|
+
- `client`: An initialized `RedseatClient` instance
|
|
22
|
+
|
|
23
|
+
**Example:**
|
|
24
|
+
```typescript
|
|
25
|
+
import { RedseatClient, ServerApi } from '@redseat/api';
|
|
26
|
+
|
|
27
|
+
const client = new RedseatClient({ /* ... */ });
|
|
28
|
+
const serverApi = new ServerApi(client);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Methods
|
|
32
|
+
|
|
33
|
+
### `getLibraries(): Promise<ILibrary[]>`
|
|
34
|
+
|
|
35
|
+
Retrieves all libraries available to the current user.
|
|
36
|
+
|
|
37
|
+
**Returns:** Promise resolving to an array of `ILibrary` objects
|
|
38
|
+
|
|
39
|
+
**Example:**
|
|
40
|
+
```typescript
|
|
41
|
+
const libraries = await serverApi.getLibraries();
|
|
42
|
+
libraries.forEach(library => {
|
|
43
|
+
console.log(`Library: ${library.name} (${library.type})`);
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### `getMe(): Promise<any>`
|
|
48
|
+
|
|
49
|
+
Gets information about the current authenticated user.
|
|
50
|
+
|
|
51
|
+
**Returns:** Promise resolving to user information object
|
|
52
|
+
|
|
53
|
+
**Example:**
|
|
54
|
+
```typescript
|
|
55
|
+
const user = await serverApi.getMe();
|
|
56
|
+
console.log(`Logged in as: ${user.name}`);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### `addLibrary(library: Partial<ILibrary>): Promise<ILibrary>`
|
|
60
|
+
|
|
61
|
+
Creates a new library.
|
|
62
|
+
|
|
63
|
+
**Parameters:**
|
|
64
|
+
- `library`: Partial library object with required fields:
|
|
65
|
+
- `name`: Library name (required)
|
|
66
|
+
- `type`: Library type - `'photos'`, `'shows'`, `'movies'`, or `'iptv'` (required)
|
|
67
|
+
- `source`: Optional source type
|
|
68
|
+
- `crypt`: Optional boolean to enable encryption
|
|
69
|
+
- `hidden`: Optional boolean to hide library
|
|
70
|
+
|
|
71
|
+
**Returns:** Promise resolving to the created `ILibrary` object with generated `id`
|
|
72
|
+
|
|
73
|
+
**Example:**
|
|
74
|
+
```typescript
|
|
75
|
+
const newLibrary = await serverApi.addLibrary({
|
|
76
|
+
name: 'My Photos',
|
|
77
|
+
type: 'photos',
|
|
78
|
+
crypt: true // Enable encryption
|
|
79
|
+
});
|
|
80
|
+
console.log(`Created library with ID: ${newLibrary.id}`);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `getSetting(key: string): Promise<string>`
|
|
84
|
+
|
|
85
|
+
Retrieves a server setting value by key.
|
|
86
|
+
|
|
87
|
+
**Parameters:**
|
|
88
|
+
- `key`: The setting key to retrieve
|
|
89
|
+
|
|
90
|
+
**Returns:** Promise resolving to the setting value as a string
|
|
91
|
+
|
|
92
|
+
**Example:**
|
|
93
|
+
```typescript
|
|
94
|
+
const maxUploadSize = await serverApi.getSetting('max_upload_size');
|
|
95
|
+
console.log(`Max upload size: ${maxUploadSize}`);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `getPlugins(): Promise<any[]>`
|
|
99
|
+
|
|
100
|
+
Retrieves all available plugins on the server.
|
|
101
|
+
|
|
102
|
+
**Returns:** Promise resolving to an array of plugin objects
|
|
103
|
+
|
|
104
|
+
**Example:**
|
|
105
|
+
```typescript
|
|
106
|
+
const plugins = await serverApi.getPlugins();
|
|
107
|
+
plugins.forEach(plugin => {
|
|
108
|
+
console.log(`Plugin: ${plugin.name} - ${plugin.description}`);
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `getCredentials(): Promise<any[]>`
|
|
113
|
+
|
|
114
|
+
Retrieves all available credentials configured on the server.
|
|
115
|
+
|
|
116
|
+
**Returns:** Promise resolving to an array of credential objects
|
|
117
|
+
|
|
118
|
+
**Example:**
|
|
119
|
+
```typescript
|
|
120
|
+
const credentials = await serverApi.getCredentials();
|
|
121
|
+
credentials.forEach(cred => {
|
|
122
|
+
console.log(`Credential: ${cred.name} (${cred.type})`);
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### `addLibraryCredential(credential: any): Promise<ILibrary>`
|
|
127
|
+
|
|
128
|
+
Adds a credential to a library. This is used to configure external service access for libraries.
|
|
129
|
+
|
|
130
|
+
**Parameters:**
|
|
131
|
+
- `credential`: Credential configuration object (structure depends on credential type)
|
|
132
|
+
|
|
133
|
+
**Returns:** Promise resolving to the updated `ILibrary` object
|
|
134
|
+
|
|
135
|
+
**Example:**
|
|
136
|
+
```typescript
|
|
137
|
+
const library = await serverApi.addLibraryCredential({
|
|
138
|
+
libraryId: 'library-123',
|
|
139
|
+
credentialId: 'credential-456',
|
|
140
|
+
// Additional credential-specific configuration
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Usage Examples
|
|
145
|
+
|
|
146
|
+
### Complete Workflow: Create Library and Get Info
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import { RedseatClient, ServerApi } from '@redseat/api';
|
|
150
|
+
|
|
151
|
+
// Initialize
|
|
152
|
+
const client = new RedseatClient({ /* ... */ });
|
|
153
|
+
const serverApi = new ServerApi(client);
|
|
154
|
+
|
|
155
|
+
// Get current user
|
|
156
|
+
const user = await serverApi.getMe();
|
|
157
|
+
console.log(`User: ${user.name}`);
|
|
158
|
+
|
|
159
|
+
// List existing libraries
|
|
160
|
+
const libraries = await serverApi.getLibraries();
|
|
161
|
+
console.log(`Found ${libraries.length} libraries`);
|
|
162
|
+
|
|
163
|
+
// Create a new encrypted photo library
|
|
164
|
+
const newLibrary = await serverApi.addLibrary({
|
|
165
|
+
name: 'Encrypted Photos',
|
|
166
|
+
type: 'photos',
|
|
167
|
+
crypt: true
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Get server settings
|
|
171
|
+
const maxUpload = await serverApi.getSetting('max_upload_size');
|
|
172
|
+
console.log(`Max upload size: ${maxUpload}`);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Error Handling
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
try {
|
|
179
|
+
const libraries = await serverApi.getLibraries();
|
|
180
|
+
} catch (error) {
|
|
181
|
+
if (error.response?.status === 401) {
|
|
182
|
+
console.error('Authentication failed');
|
|
183
|
+
} else if (error.response?.status === 403) {
|
|
184
|
+
console.error('Insufficient permissions');
|
|
185
|
+
} else {
|
|
186
|
+
console.error('Failed to get libraries:', error.message);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Related Documentation
|
|
192
|
+
|
|
193
|
+
- [RedseatClient Documentation](client.md) - HTTP client used by ServerApi
|
|
194
|
+
- [LibraryApi Documentation](libraries.md) - Library-specific operations
|
|
195
|
+
- [README](README.md) - Package overview
|
|
196
|
+
|
package/test.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Testing Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to run tests for the `@redseat/api` package and what each test file covers.
|
|
4
|
+
|
|
5
|
+
## Running Tests
|
|
6
|
+
|
|
7
|
+
### Run All Tests
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm test
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This runs all tests once and exits.
|
|
14
|
+
|
|
15
|
+
### Run Tests in Watch Mode
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run test:watch
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This runs tests in watch mode, automatically re-running tests when files change.
|
|
22
|
+
|
|
23
|
+
### Run Specific Test File
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx vitest run src/encryption.test.ts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Run Tests with Coverage
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx vitest run --coverage
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Test Framework
|
|
36
|
+
|
|
37
|
+
The package uses [Vitest](https://vitest.dev/) as the test framework. Vitest is a fast unit test framework powered by Vite, designed to be compatible with Jest.
|
|
38
|
+
|
|
39
|
+
### Configuration
|
|
40
|
+
|
|
41
|
+
Test configuration is in `vitest.config.ts`:
|
|
42
|
+
- Environment: Node.js
|
|
43
|
+
- Globals: Enabled (no need to import `describe`, `it`, `expect`)
|
|
44
|
+
|
|
45
|
+
## Test Files
|
|
46
|
+
|
|
47
|
+
### `src/encryption.test.ts`
|
|
48
|
+
|
|
49
|
+
Tests for the encryption module (`src/encryption.ts`).
|
|
50
|
+
|
|
51
|
+
**What it tests:**
|
|
52
|
+
- **Key Derivation (`deriveKey`)**
|
|
53
|
+
- Derives text keys from passphrases
|
|
54
|
+
- Derives file keys from passphrases
|
|
55
|
+
- Verifies text and file keys are different (different salts)
|
|
56
|
+
- Verifies same passphrase produces same key
|
|
57
|
+
|
|
58
|
+
- **IV Generation (`getRandomIV`)**
|
|
59
|
+
- Generates 16-byte IVs
|
|
60
|
+
- Generates different IVs on each call
|
|
61
|
+
|
|
62
|
+
- **Text Encryption/Decryption (`encryptText` / `decryptText`)**
|
|
63
|
+
- Encrypts and decrypts text correctly
|
|
64
|
+
- Produces different encrypted output for same text (due to random IV)
|
|
65
|
+
- Handles empty strings
|
|
66
|
+
- Handles special characters and unicode
|
|
67
|
+
- Verifies encrypted format: `${IV}.${encryptedData}` (base64url)
|
|
68
|
+
|
|
69
|
+
- **Buffer Encryption/Decryption (`encryptBuffer` / `decryptBuffer`)**
|
|
70
|
+
- Encrypts and decrypts binary data correctly
|
|
71
|
+
- Requires correct IV for decryption
|
|
72
|
+
- Handles empty buffers
|
|
73
|
+
- Handles large buffers
|
|
74
|
+
|
|
75
|
+
- **File Encryption (`encryptFile`)**
|
|
76
|
+
- Encrypts files with thumbnails
|
|
77
|
+
- Encrypts files without thumbnails
|
|
78
|
+
- Includes correct MIME types in encrypted structure
|
|
79
|
+
- Returns correct IV and thumbnail size
|
|
80
|
+
|
|
81
|
+
- **File Decryption (`decryptFile` / `decryptFileThumb`)**
|
|
82
|
+
- Decrypts file data from encrypted structure
|
|
83
|
+
- Decrypts thumbnail data from encrypted structure
|
|
84
|
+
- Handles files without thumbnails
|
|
85
|
+
- Verifies file format structure (IV, sizes, MIME types, data)
|
|
86
|
+
|
|
87
|
+
- **Filename Encryption (`encryptFilename`)**
|
|
88
|
+
- Encrypts filenames with given IV
|
|
89
|
+
- Returns base64url encoded encrypted filename
|
|
90
|
+
|
|
91
|
+
- **Endianness Compatibility**
|
|
92
|
+
- Handles both big-endian and little-endian size fields
|
|
93
|
+
- Backward compatibility with old file formats
|
|
94
|
+
|
|
95
|
+
**Example test:**
|
|
96
|
+
```typescript
|
|
97
|
+
it('should encrypt and decrypt text correctly', async () => {
|
|
98
|
+
const key = await deriveKey('password', 'text');
|
|
99
|
+
const encrypted = await encryptText(key, 'Hello World');
|
|
100
|
+
const decrypted = await decryptText(key, encrypted);
|
|
101
|
+
expect(decrypted).toBe('Hello World');
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### `src/crypto.test.ts`
|
|
108
|
+
|
|
109
|
+
Tests for crypto utility functions (`src/crypto.ts`).
|
|
110
|
+
|
|
111
|
+
**What it tests:**
|
|
112
|
+
- **Platform Detection (`getCryptoSubtle` / `getCryptoRandomValues`)**
|
|
113
|
+
- Returns SubtleCrypto instance
|
|
114
|
+
- Returns random number generator function
|
|
115
|
+
- Works in Node.js environment
|
|
116
|
+
|
|
117
|
+
- **Base64 Encoding/Decoding**
|
|
118
|
+
- `uint8ArrayFromBase64`: Converts base64 to Uint8Array
|
|
119
|
+
- `uint8ArrayFromBase64Url`: Converts base64url to Uint8Array
|
|
120
|
+
- `arrayBufferToBase64`: Converts ArrayBuffer to base64
|
|
121
|
+
- Handles padding correctly
|
|
122
|
+
- Handles base64url format (dashes and underscores)
|
|
123
|
+
|
|
124
|
+
- **Base64 URL Conversion**
|
|
125
|
+
- `base64ToBase64Url`: Converts standard base64 to base64url
|
|
126
|
+
- `base64UrlToBase64`: Converts base64url to standard base64
|
|
127
|
+
- Handles character substitution (`+`/`-`, `/`/`_`)
|
|
128
|
+
- Handles padding removal/addition
|
|
129
|
+
|
|
130
|
+
- **String Padding (`padRight`)**
|
|
131
|
+
- Pads strings to specified length
|
|
132
|
+
- Handles strings longer than target length
|
|
133
|
+
- Handles empty strings
|
|
134
|
+
- Uses correct padding character
|
|
135
|
+
|
|
136
|
+
**Example test:**
|
|
137
|
+
```typescript
|
|
138
|
+
it('should convert base64 string to Uint8Array', () => {
|
|
139
|
+
const base64 = 'SGVsbG8gV29ybGQ='; // "Hello World"
|
|
140
|
+
const result = uint8ArrayFromBase64(base64);
|
|
141
|
+
expect(result).toBeInstanceOf(Uint8Array);
|
|
142
|
+
expect(String.fromCharCode(...result)).toBe('Hello World');
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### `src/library-upload.test.ts`
|
|
149
|
+
|
|
150
|
+
Tests for `LibraryApi.uploadMedia()` method.
|
|
151
|
+
|
|
152
|
+
**What it tests:**
|
|
153
|
+
- **Encrypted Library Uploads**
|
|
154
|
+
- Throws error if encryption key is not set
|
|
155
|
+
- Encrypts data when key is set via `setKey()`
|
|
156
|
+
- Encrypts filename using text encryption
|
|
157
|
+
- Includes IV and thumbnail size in metadata
|
|
158
|
+
- Handles thumbnail encryption
|
|
159
|
+
- Validates thumbnail can only be specified for encrypted libraries
|
|
160
|
+
|
|
161
|
+
- **Non-Encrypted Library Uploads**
|
|
162
|
+
- Uploads without encryption
|
|
163
|
+
- Uses original filename
|
|
164
|
+
- Does not require encryption key
|
|
165
|
+
|
|
166
|
+
- **Input Validation**
|
|
167
|
+
- Handles ArrayBuffer input
|
|
168
|
+
- Handles Uint8Array input
|
|
169
|
+
- Normalizes different buffer types correctly
|
|
170
|
+
- Validates metadata structure
|
|
171
|
+
|
|
172
|
+
- **FormData Structure**
|
|
173
|
+
- Creates FormData with correct structure
|
|
174
|
+
- Info field is first, file field is last
|
|
175
|
+
- Includes correct metadata in info field
|
|
176
|
+
- Uses correct filename in file field
|
|
177
|
+
|
|
178
|
+
- **Progress Callback**
|
|
179
|
+
- Calls progress callback during upload
|
|
180
|
+
- Provides correct loaded/total values
|
|
181
|
+
|
|
182
|
+
- **Error Handling**
|
|
183
|
+
- Throws appropriate errors for missing keys
|
|
184
|
+
- Throws errors for invalid configurations
|
|
185
|
+
- Handles network errors gracefully
|
|
186
|
+
|
|
187
|
+
**Example test:**
|
|
188
|
+
```typescript
|
|
189
|
+
it('should throw error if key is not set', async () => {
|
|
190
|
+
libraryApi = new LibraryApi(client, 'lib1', encryptedLibrary);
|
|
191
|
+
await expect(
|
|
192
|
+
libraryApi.uploadMedia(data, {
|
|
193
|
+
metadata: {},
|
|
194
|
+
fileMime: 'image/jpeg'
|
|
195
|
+
})
|
|
196
|
+
).rejects.toThrow('Encryption key not set');
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Test Structure
|
|
203
|
+
|
|
204
|
+
All test files follow this structure:
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { describe, it, expect } from 'vitest';
|
|
208
|
+
import { /* functions to test */ } from './module';
|
|
209
|
+
|
|
210
|
+
describe('Module Name', () => {
|
|
211
|
+
describe('Function Group', () => {
|
|
212
|
+
it('should do something', () => {
|
|
213
|
+
// Test implementation
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Writing New Tests
|
|
220
|
+
|
|
221
|
+
When adding new functionality:
|
|
222
|
+
|
|
223
|
+
1. **Add tests to existing file** if testing existing module
|
|
224
|
+
2. **Create new test file** if testing new module (follow naming: `module-name.test.ts`)
|
|
225
|
+
3. **Test both success and error cases**
|
|
226
|
+
4. **Test edge cases** (empty inputs, null values, etc.)
|
|
227
|
+
5. **Use descriptive test names** that explain what is being tested
|
|
228
|
+
|
|
229
|
+
### Example: Adding Test for New Function
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// In appropriate test file
|
|
233
|
+
describe('newFunction', () => {
|
|
234
|
+
it('should handle normal case', () => {
|
|
235
|
+
const result = newFunction('input');
|
|
236
|
+
expect(result).toBe('expected');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should handle edge case', () => {
|
|
240
|
+
const result = newFunction('');
|
|
241
|
+
expect(result).toBe('');
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should throw error for invalid input', () => {
|
|
245
|
+
expect(() => newFunction(null)).toThrow();
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Continuous Integration
|
|
251
|
+
|
|
252
|
+
Tests should be run:
|
|
253
|
+
- Before committing code
|
|
254
|
+
- In CI/CD pipeline
|
|
255
|
+
- Before releasing new versions
|
|
256
|
+
|
|
257
|
+
## Coverage Goals
|
|
258
|
+
|
|
259
|
+
Aim for:
|
|
260
|
+
- **High coverage** on core functionality (encryption, API methods)
|
|
261
|
+
- **Edge case coverage** for error handling
|
|
262
|
+
- **Integration tests** for complex workflows
|
|
263
|
+
|
|
264
|
+
## Debugging Tests
|
|
265
|
+
|
|
266
|
+
### Run Single Test
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
npx vitest run -t "test name"
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Debug Mode
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
node --inspect-brk node_modules/.bin/vitest run
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Then attach debugger in VS Code or Chrome DevTools.
|
|
279
|
+
|
|
280
|
+
### Verbose Output
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
npx vitest run --reporter=verbose
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Related Documentation
|
|
287
|
+
|
|
288
|
+
- [Vitest Documentation](https://vitest.dev/)
|
|
289
|
+
- [Encryption Documentation](encryption.md) - Details on encryption functions being tested
|
|
290
|
+
- [README](README.md) - Package overview
|
|
291
|
+
|