@cakemail-org/cakemail-cli 1.7.0 → 2.0.0

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 (198) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/.env.example +40 -0
  3. package/.env.test.example +45 -0
  4. package/CHANGELOG.md +1031 -0
  5. package/README.md +41 -37
  6. package/audit-formats.js +128 -0
  7. package/cakemail.rb +20 -0
  8. package/dist/client.js +1 -1
  9. package/dist/client.js.map +1 -1
  10. package/dist/commands/account.js +1 -1
  11. package/dist/commands/account.js.map +1 -1
  12. package/dist/commands/attributes.js +1 -1
  13. package/dist/commands/attributes.js.map +1 -1
  14. package/dist/commands/campaigns.js +1 -1
  15. package/dist/commands/campaigns.js.map +1 -1
  16. package/dist/commands/contacts.js +1 -1
  17. package/dist/commands/contacts.js.map +1 -1
  18. package/dist/commands/emails.js +1 -1
  19. package/dist/commands/emails.js.map +1 -1
  20. package/dist/commands/interests.js +1 -1
  21. package/dist/commands/interests.js.map +1 -1
  22. package/dist/commands/lists.js +1 -1
  23. package/dist/commands/lists.js.map +1 -1
  24. package/dist/commands/logs.js +1 -1
  25. package/dist/commands/logs.js.map +1 -1
  26. package/dist/commands/reports.js +1 -1
  27. package/dist/commands/reports.js.map +1 -1
  28. package/dist/commands/segments.js +1 -1
  29. package/dist/commands/segments.js.map +1 -1
  30. package/dist/commands/senders.js +1 -1
  31. package/dist/commands/senders.js.map +1 -1
  32. package/dist/commands/suppressed.js +1 -1
  33. package/dist/commands/suppressed.js.map +1 -1
  34. package/dist/commands/tags.js +1 -1
  35. package/dist/commands/tags.js.map +1 -1
  36. package/dist/commands/templates.js +1 -1
  37. package/dist/commands/templates.js.map +1 -1
  38. package/dist/commands/transactional-templates.js +1 -1
  39. package/dist/commands/transactional-templates.js.map +1 -1
  40. package/dist/commands/webhooks.js +1 -1
  41. package/dist/commands/webhooks.js.map +1 -1
  42. package/dist/utils/config.js +2 -2
  43. package/dist/utils/config.js.map +1 -1
  44. package/dist/utils/errors.js +1 -1
  45. package/dist/utils/errors.js.map +1 -1
  46. package/dist/utils/progress.d.ts.map +1 -1
  47. package/dist/utils/progress.js +32 -4
  48. package/dist/utils/progress.js.map +1 -1
  49. package/dist/utils/spinner.d.ts +17 -0
  50. package/dist/utils/spinner.d.ts.map +1 -0
  51. package/dist/utils/spinner.js +43 -0
  52. package/dist/utils/spinner.js.map +1 -0
  53. package/docs/DOCUMENTATION-STANDARD.md +1068 -0
  54. package/docs/README.md +161 -0
  55. package/docs/developer/ARCHITECTURE.md +516 -0
  56. package/docs/developer/AUTH.md +204 -0
  57. package/docs/developer/CONTRIBUTING.md +227 -0
  58. package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
  59. package/docs/developer/PROJECT_INDEX.md +365 -0
  60. package/docs/planning/API_COVERAGE.md +1045 -0
  61. package/docs/planning/BACKLOG.md +1159 -0
  62. package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
  63. package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
  64. package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
  65. package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
  66. package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
  67. package/docs/planning/cakemail-profile-system-plan.md +1121 -0
  68. package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
  69. package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
  70. package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
  71. package/docs/user-manual/.obsidian/app.json +1 -0
  72. package/docs/user-manual/.obsidian/appearance.json +1 -0
  73. package/docs/user-manual/.obsidian/core-plugins.json +33 -0
  74. package/docs/user-manual/.obsidian/workspace.json +167 -0
  75. package/docs/user-manual/01-getting-started/01-installation.md +214 -0
  76. package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
  77. package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
  78. package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
  79. package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
  80. package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
  81. package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
  82. package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
  83. package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
  84. package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
  85. package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
  86. package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
  87. package/docs/user-manual/03-email-operations/01-senders.md +490 -0
  88. package/docs/user-manual/03-email-operations/02-templates.md +444 -0
  89. package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
  90. package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
  91. package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
  92. package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
  93. package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
  94. package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
  95. package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
  96. package/docs/user-manual/05-contact-management/01-lists.md +836 -0
  97. package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
  98. package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
  99. package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
  100. package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
  101. package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
  102. package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
  103. package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
  104. package/docs/user-manual/07-integrations/02-automation.md +326 -0
  105. package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
  106. package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
  107. package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
  108. package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
  109. package/docs/user-manual/09-command-reference/01-config.md +776 -0
  110. package/docs/user-manual/09-command-reference/02-account.md +652 -0
  111. package/docs/user-manual/09-command-reference/03-lists.md +958 -0
  112. package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
  113. package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
  114. package/docs/user-manual/09-command-reference/06-segments.md +894 -0
  115. package/docs/user-manual/09-command-reference/07-senders.md +803 -0
  116. package/docs/user-manual/09-command-reference/08-templates.md +818 -0
  117. package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
  118. package/docs/user-manual/09-command-reference/10-emails.md +807 -0
  119. package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
  120. package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
  121. package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
  122. package/docs/user-manual/09-command-reference/14-interests.md +630 -0
  123. package/docs/user-manual/09-command-reference/15-tags.md +584 -0
  124. package/docs/user-manual/09-command-reference/16-logs.md +656 -0
  125. package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
  126. package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
  127. package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
  128. package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
  129. package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
  130. package/docs/user-manual/11-appendix/04-faq.md +484 -0
  131. package/docs/user-manual/11-appendix/05-glossary.md +250 -0
  132. package/docs/user-manual/README.md +0 -0
  133. package/package.json +13 -61
  134. package/src/cli.ts +125 -0
  135. package/src/client.ts +16 -0
  136. package/src/commands/account.ts +267 -0
  137. package/src/commands/accounts.ts +78 -0
  138. package/src/commands/actions.ts +249 -0
  139. package/src/commands/attributes.ts +139 -0
  140. package/src/commands/campaign-blueprints.ts +106 -0
  141. package/src/commands/campaigns.ts +469 -0
  142. package/src/commands/config.ts +77 -0
  143. package/src/commands/contacts.ts +612 -0
  144. package/src/commands/custom-attributes.ts +127 -0
  145. package/src/commands/dkims.ts +117 -0
  146. package/src/commands/domains.ts +82 -0
  147. package/src/commands/email-apis.ts +569 -0
  148. package/src/commands/emails.ts +197 -0
  149. package/src/commands/forms.ts +283 -0
  150. package/src/commands/interests.ts +155 -0
  151. package/src/commands/links.ts +38 -0
  152. package/src/commands/lists.ts +406 -0
  153. package/src/commands/logos.ts +71 -0
  154. package/src/commands/logs.ts +386 -0
  155. package/src/commands/reports.ts +306 -0
  156. package/src/commands/segments.ts +158 -0
  157. package/src/commands/senders.ts +204 -0
  158. package/src/commands/sub-accounts.ts +271 -0
  159. package/src/commands/suppressed-emails.ts +234 -0
  160. package/src/commands/suppressed.ts +198 -0
  161. package/src/commands/system-emails.ts +85 -0
  162. package/src/commands/tags.ts +146 -0
  163. package/src/commands/tasks.ts +116 -0
  164. package/src/commands/templates.ts +189 -0
  165. package/src/commands/tokens.ts +83 -0
  166. package/src/commands/transactional-emails.ts +374 -0
  167. package/src/commands/transactional-templates.ts +385 -0
  168. package/src/commands/users.ts +506 -0
  169. package/src/commands/webhooks.ts +172 -0
  170. package/src/commands/workflow-blueprints.ts +123 -0
  171. package/src/commands/workflows.ts +265 -0
  172. package/src/types/profile.ts +93 -0
  173. package/src/utils/auth.ts +272 -0
  174. package/src/utils/config-file.ts +96 -0
  175. package/src/utils/config.ts +134 -0
  176. package/src/utils/confirm.ts +32 -0
  177. package/src/utils/defaults.ts +99 -0
  178. package/src/utils/errors.ts +116 -0
  179. package/src/utils/interactive.ts +91 -0
  180. package/src/utils/list-defaults.ts +74 -0
  181. package/src/utils/output.ts +190 -0
  182. package/src/utils/progress.ts +320 -0
  183. package/src/utils/spinner.ts +22 -0
  184. package/tests/IMPLEMENTATION_STATUS.md +258 -0
  185. package/tests/PTY_SETUP.md +118 -0
  186. package/tests/PTY_TESTING_GUIDE.md +507 -0
  187. package/tests/README.md +244 -0
  188. package/tests/fixtures/api-responses/campaigns.json +34 -0
  189. package/tests/fixtures/test-config.json +13 -0
  190. package/tests/helpers/cli-runner.ts +128 -0
  191. package/tests/helpers/mock-server.ts +301 -0
  192. package/tests/helpers/pty-runner.ts +181 -0
  193. package/tests/integration/campaigns-real-api.test.ts +196 -0
  194. package/tests/integration/setup-integration.ts +50 -0
  195. package/tests/pty/campaigns.test.ts +241 -0
  196. package/tests/setup.ts +34 -0
  197. package/tsconfig.json +15 -0
  198. package/vitest.config.ts +28 -0
@@ -0,0 +1,507 @@
1
+ # PTY Testing Guide: Simulating Real Users
2
+
3
+ ## What is PTY Testing?
4
+
5
+ **PTY (Pseudo-Terminal)** creates a **real terminal session** for your CLI, exactly like when a user runs your command.
6
+
7
+ ### What You Get:
8
+ - ✅ **Real terminal** - Just like `ssh` or Terminal.app
9
+ - ✅ **Colors** - ANSI escape codes work
10
+ - ✅ **Spinners** - Ora spinners animate
11
+ - ✅ **Interactive prompts** - Can respond to inquirer/prompts
12
+ - ✅ **Ctrl+C handling** - Test signal handling
13
+ - ✅ **Terminal size** - Responsive layouts
14
+
15
+ ### What Makes It Special:
16
+ Unlike `execa` (subprocess), PTY gives your CLI a **real TTY (teletypewriter)**, which means:
17
+ - `process.stdout.isTTY === true`
18
+ - Colors don't get stripped
19
+ - Progress bars and spinners work
20
+ - You can test exactly what users see
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install --save-dev node-pty express @types/express
28
+ ```
29
+
30
+ **Note**: `node-pty` requires build tools and has specific Node version requirements:
31
+ - **macOS**: Xcode Command Line Tools (`xcode-select --install`)
32
+ - **Linux**: `python3`, `make`, `g++`
33
+ - **Windows**: Visual Studio Build Tools
34
+ - **Node Version**: Currently supports Node 18.x and 20.x (Node 22+ may have compatibility issues)
35
+
36
+ **⚠️ If node-pty fails to build**: Use Node 18 LTS or Node 20 LTS. Node 24+ is too new and may not be supported yet.
37
+
38
+ ```bash
39
+ # Switch to Node 20 (recommended)
40
+ nvm install 20
41
+ nvm use 20
42
+ npm install
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Quick Start
48
+
49
+ ### 1. Files Already Created
50
+
51
+ ✅ `tests/helpers/mock-server.ts` - Mock API server
52
+ ✅ `tests/helpers/pty-runner.ts` - PTY helper functions
53
+ ✅ `tests/pty/campaigns.test.ts` - Example PTY test
54
+ ✅ `tests/pty-test-example.ts` - Interactive examples
55
+
56
+ ### 2. Run the Example
57
+
58
+ ```bash
59
+ # Build CLI first
60
+ npm run build
61
+
62
+ # Run PTY test
63
+ npx vitest tests/pty/campaigns.test.ts
64
+ ```
65
+
66
+ ---
67
+
68
+ ## How It Works
69
+
70
+ ### Architecture
71
+
72
+ ```
73
+ ┌─────────────────────────────────────────┐
74
+ │ Test Process (Vitest) │
75
+ │ │
76
+ │ ┌────────────────────────────────────┐ │
77
+ │ │ Mock HTTP Server │ │
78
+ │ │ http://localhost:RANDOM_PORT │ │
79
+ │ │ │ │
80
+ │ │ POST /token → Auth │ │
81
+ │ │ GET /campaigns → Mock data │ │
82
+ │ │ ... │ │
83
+ │ └────────────────────────────────────┘ │
84
+ │ │
85
+ │ ┌────────────────────────────────────┐ │
86
+ │ │ PTY (Real Terminal) │ │
87
+ │ │ │ │
88
+ │ │ $ node dist/cli.js campaigns list│ │
89
+ │ │ ↓ │ │
90
+ │ │ - Fetching campaigns... ⠋ │ │
91
+ │ │ ↓ │ │
92
+ │ │ ┌────┬─────────┬────────┐ │ │
93
+ │ │ │ ID │ Name │ Status │ │ │
94
+ │ │ ├────┼─────────┼────────┤ │ │
95
+ │ │ │ 1 │ Test │ draft │ │ │
96
+ │ │ └────┴─────────┴────────┘ │ │
97
+ │ │ │ │
98
+ │ │ (Makes HTTP requests to mock) │ │
99
+ │ └────────────────────────────────────┘ │
100
+ └─────────────────────────────────────────┘
101
+ ```
102
+
103
+ ### Key Differences from Current Tests
104
+
105
+ | Feature | Current (execa) | PTY Testing |
106
+ |---------|----------------|-------------|
107
+ | Terminal | ❌ No TTY | ✅ Real TTY |
108
+ | HTTP Mocks | ❌ Nock (doesn't work) | ✅ Real HTTP Server |
109
+ | Colors | ❌ Stripped | ✅ ANSI codes visible |
110
+ | Spinners | ❌ Don't work | ✅ Fully animated |
111
+ | Interactive | ❌ No | ✅ Yes |
112
+ | User Experience | ⚠️ Partial | ✅ Exact |
113
+
114
+ ---
115
+
116
+ ## Usage Examples
117
+
118
+ ### Basic Test
119
+
120
+ ```typescript
121
+ import { runPTYSuccess } from '../helpers/pty-runner';
122
+
123
+ it('should list campaigns', async () => {
124
+ const { output, exitCode } = await runPTYSuccess(
125
+ ['campaigns', 'list'],
126
+ { mockServerPort }
127
+ );
128
+
129
+ expect(exitCode).toBe(0);
130
+ expect(output).toContain('Test Campaign');
131
+ });
132
+ ```
133
+
134
+ ### Test JSON Output
135
+
136
+ ```typescript
137
+ it('should output JSON', async () => {
138
+ const { cleanOutput } = await runPTYSuccess(
139
+ ['-f', 'json', 'campaigns', 'list'],
140
+ { mockServerPort }
141
+ );
142
+
143
+ const data = JSON.parse(cleanOutput);
144
+ expect(data.data).toHaveLength(2);
145
+ });
146
+ ```
147
+
148
+ ### Test Colors
149
+
150
+ ```typescript
151
+ it('should show colored output', async () => {
152
+ const { output } = await runPTYSuccess(
153
+ ['campaigns', 'list'],
154
+ { mockServerPort, enableColors: true }
155
+ );
156
+
157
+ // Check for ANSI escape codes
158
+ expect(output).toMatch(/\u001b\[3\d+m/); // Color codes
159
+ });
160
+ ```
161
+
162
+ ### Test Spinners
163
+
164
+ ```typescript
165
+ it('should show spinner while loading', async () => {
166
+ const { output } = await runPTYSuccess(
167
+ ['campaigns', 'list'],
168
+ { mockServerPort }
169
+ );
170
+
171
+ // Check for loading message
172
+ expect(output).toContain('Fetching campaigns');
173
+ });
174
+ ```
175
+
176
+ ### Test Interactive Prompts
177
+
178
+ ```typescript
179
+ import { createInteraction } from '../helpers/pty-runner';
180
+
181
+ it('should handle interactive input', async () => {
182
+ const interaction = createInteraction([
183
+ { prompt: 'List name:', response: 'My List\r' },
184
+ { prompt: 'Language:', response: 'en\r' }
185
+ ]);
186
+
187
+ const { output } = await runPTYSuccess(
188
+ ['lists', 'create'],
189
+ {
190
+ mockServerPort,
191
+ interactive: true,
192
+ onData: interaction.handler
193
+ }
194
+ );
195
+
196
+ expect(output).toContain('My List');
197
+ expect(output).toContain('created');
198
+ });
199
+ ```
200
+
201
+ ### Test Error Handling
202
+
203
+ ```typescript
204
+ import { runPTYFailure } from '../helpers/pty-runner';
205
+
206
+ it('should handle not found errors', async () => {
207
+ const { output, exitCode } = await runPTYFailure(
208
+ ['campaigns', 'get', '999'],
209
+ { mockServerPort }
210
+ );
211
+
212
+ expect(exitCode).toBe(1);
213
+ expect(output).toMatch(/not found/i);
214
+ });
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Converting Existing Tests
220
+
221
+ ### Before (with execa and nock)
222
+
223
+ ```typescript
224
+ import { runCLISuccess } from '../helpers/cli-runner';
225
+ import { mockCampaignsList } from '../helpers/mock-api';
226
+ import nock from 'nock';
227
+
228
+ it('should list campaigns', async () => {
229
+ mockCampaignsList([/* data */]);
230
+
231
+ const result = await runCLISuccess(['campaigns', 'list']);
232
+ // ❌ This fails - nock doesn't work with subprocess
233
+ });
234
+ ```
235
+
236
+ ### After (with PTY and mock server)
237
+
238
+ ```typescript
239
+ import { runPTYSuccess } from '../helpers/pty-runner';
240
+
241
+ it('should list campaigns', async () => {
242
+ // Mock server already running in beforeAll
243
+ const result = await runPTYSuccess(
244
+ ['campaigns', 'list'],
245
+ { mockServerPort }
246
+ );
247
+ // ✅ Works! Real HTTP to mock server
248
+ });
249
+ ```
250
+
251
+ ### Migration Checklist
252
+
253
+ For each test file:
254
+ 1. ✅ Remove nock imports
255
+ 2. ✅ Remove mock setup (e.g., `mockCampaignsList()`)
256
+ 3. ✅ Import PTY helpers instead
257
+ 4. ✅ Use `mockServerPort` from `beforeAll`
258
+ 5. ✅ Update assertions to use `cleanOutput`
259
+
260
+ ---
261
+
262
+ ## Mock Server Customization
263
+
264
+ ### Adding New Endpoints
265
+
266
+ Edit `tests/helpers/mock-server.ts`:
267
+
268
+ ```typescript
269
+ export function createMockAPI(): Express {
270
+ const app = express();
271
+
272
+ // Your new endpoint
273
+ app.get('/my-endpoint', (req, res) => {
274
+ res.json({ data: 'your mock data' });
275
+ });
276
+
277
+ return app;
278
+ }
279
+ ```
280
+
281
+ ### Testing Error Scenarios
282
+
283
+ ```typescript
284
+ // In mock-server.ts
285
+ app.get('/campaigns/:id', (req, res) => {
286
+ const id = parseInt(req.params.id);
287
+
288
+ // Special IDs trigger errors
289
+ if (id === 999) {
290
+ return res.status(404).json({ error: 'Not found' });
291
+ }
292
+ if (id === 888) {
293
+ return res.status(500).json({ error: 'Server error' });
294
+ }
295
+
296
+ res.json({ id, name: `Campaign ${id}` });
297
+ });
298
+
299
+ // In test
300
+ it('should handle 404', async () => {
301
+ const { exitCode } = await runPTYFailure(
302
+ ['campaigns', 'get', '999'], // Magic ID triggers 404
303
+ { mockServerPort }
304
+ );
305
+
306
+ expect(exitCode).toBe(1);
307
+ });
308
+ ```
309
+
310
+ ### Dynamic Responses
311
+
312
+ ```typescript
313
+ // Track state in mock server
314
+ let campaignsData = [
315
+ { id: 1, name: 'Campaign 1' }
316
+ ];
317
+
318
+ app.post('/campaigns', (req, res) => {
319
+ const newCampaign = {
320
+ id: campaignsData.length + 1,
321
+ ...req.body
322
+ };
323
+ campaignsData.push(newCampaign);
324
+ res.status(201).json(newCampaign);
325
+ });
326
+
327
+ app.get('/campaigns', (req, res) => {
328
+ res.json({ data: campaignsData });
329
+ });
330
+ ```
331
+
332
+ ---
333
+
334
+ ## Tips & Best Practices
335
+
336
+ ### 1. Use `cleanOutput` for Assertions
337
+
338
+ ```typescript
339
+ // ❌ BAD: Raw output has ANSI codes
340
+ expect(result.output).toContain('Campaign');
341
+
342
+ // ✅ GOOD: Clean output strips ANSI
343
+ expect(result.cleanOutput).toContain('Campaign');
344
+ ```
345
+
346
+ ### 2. Test Colors Separately
347
+
348
+ ```typescript
349
+ // Test functionality
350
+ expect(result.cleanOutput).toContain('success');
351
+
352
+ // Test presentation
353
+ it('should show green for success', async () => {
354
+ const { output } = await runPTYSuccess(
355
+ ['campaigns', 'create', ...],
356
+ { enableColors: true }
357
+ );
358
+ expect(output).toMatch(/\u001b\[32m/); // Green
359
+ });
360
+ ```
361
+
362
+ ### 3. Set Reasonable Timeouts
363
+
364
+ ```typescript
365
+ const { output } = await runPTYSuccess(
366
+ ['campaigns', 'list'],
367
+ {
368
+ mockServerPort,
369
+ timeout: 5000 // 5 seconds (default is 10s)
370
+ }
371
+ );
372
+ ```
373
+
374
+ ### 4. Debug with onData
375
+
376
+ ```typescript
377
+ const { output } = await runPTYSuccess(
378
+ ['campaigns', 'list'],
379
+ {
380
+ mockServerPort,
381
+ onData: (data) => console.log('[PTY]', data) // Debug output
382
+ }
383
+ );
384
+ ```
385
+
386
+ ### 5. Clean Up PTY Processes
387
+
388
+ ```typescript
389
+ afterEach(() => {
390
+ // PTY helper already kills process
391
+ // But if you create custom PTY:
392
+ if (customPty) {
393
+ customPty.kill();
394
+ }
395
+ });
396
+ ```
397
+
398
+ ---
399
+
400
+ ## Common Issues
401
+
402
+ ### Issue: "Cannot find module 'node-pty'"
403
+
404
+ **Solution**: Install native dependencies
405
+ ```bash
406
+ # macOS
407
+ xcode-select --install
408
+ npm install node-pty
409
+
410
+ # Ubuntu/Debian
411
+ sudo apt-get install python3 make g++
412
+ npm install node-pty
413
+
414
+ # Windows
415
+ npm install --global windows-build-tools
416
+ npm install node-pty
417
+ ```
418
+
419
+ ### Issue: Tests timeout
420
+
421
+ **Solution**: Increase timeout or check mock server
422
+ ```typescript
423
+ const result = await runPTYSuccess(args, {
424
+ mockServerPort,
425
+ timeout: 30000 // 30 seconds
426
+ });
427
+ ```
428
+
429
+ ### Issue: Can't parse JSON output
430
+
431
+ **Solution**: Use `-f json` flag
432
+ ```typescript
433
+ const result = await runPTYSuccess(
434
+ ['-f', 'json', 'campaigns', 'list'], // Force JSON
435
+ { mockServerPort }
436
+ );
437
+ ```
438
+
439
+ ### Issue: Colors don't show
440
+
441
+ **Solution**: Enable colors explicitly
442
+ ```typescript
443
+ const result = await runPTYSuccess(args, {
444
+ mockServerPort,
445
+ enableColors: true // Enable ANSI colors
446
+ });
447
+ ```
448
+
449
+ ---
450
+
451
+ ## Performance
452
+
453
+ ### Speed Comparison
454
+
455
+ | Test Type | Speed | Tests/Second |
456
+ |-----------|-------|--------------|
457
+ | Direct Import + nock | 🚀 Very Fast | 50-100 |
458
+ | PTY + Mock Server | ⚡ Fast | 10-20 |
459
+ | Integration (Real API) | 🐌 Slow | 1-5 |
460
+
461
+ ### Optimization Tips
462
+
463
+ 1. **Reuse mock server** - Start once in `beforeAll`, not per test
464
+ 2. **Parallel tests** - Vitest runs tests in parallel by default
465
+ 3. **Disable colors** - Faster rendering without ANSI codes
466
+ 4. **Short timeouts** - Fail fast on broken tests
467
+
468
+ ---
469
+
470
+ ## Next Steps
471
+
472
+ ### Phase 1: Get One Test Working (30 min)
473
+ ```bash
474
+ npm install node-pty @types/node-pty express @types/express
475
+ npm run build
476
+ npx vitest tests/pty/campaigns.test.ts -t "should list campaigns"
477
+ ```
478
+
479
+ ### Phase 2: Convert High-Priority Tests (2-3 hours)
480
+ - Convert campaigns tests (25 tests)
481
+ - Convert lists tests (30 tests)
482
+ - Convert contacts tests (48 tests)
483
+
484
+ ### Phase 3: Convert Remaining Tests (3-4 hours)
485
+ - Convert senders tests (20 tests)
486
+ - Convert templates tests (24 tests)
487
+
488
+ ### Total Effort: 6-8 hours
489
+ ✅ **Result**: 147 tests simulating real user experience!
490
+
491
+ ---
492
+
493
+ ## Summary
494
+
495
+ **PTY Testing gives you**:
496
+ - ✅ Real terminal simulation
497
+ - ✅ HTTP mocks that work (real server)
498
+ - ✅ Test colors, spinners, interactivity
499
+ - ✅ Exact user experience verification
500
+
501
+ **Perfect for**:
502
+ - E2E testing CLI behavior
503
+ - Verifying user-facing features
504
+ - Testing error messages and formatting
505
+ - Ensuring professional UX
506
+
507
+ **Start with**: `tests/pty/campaigns.test.ts` example! 🚀