@tempyemail/e2e-testing 1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 TempyEmail
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,695 @@
1
+ # @tempyemail/e2e-testing
2
+
3
+ > JavaScript/TypeScript client for [tempy.email](https://tempy.email) - Temporary email addresses for automated E2E testing
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@tempyemail/e2e-testing.svg)](https://www.npmjs.com/package/@tempyemail/e2e-testing)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ **Perfect for testing:**
9
+ - Email verification flows (signup, 2FA, password reset)
10
+ - OTP/verification code extraction
11
+ - Magic link authentication
12
+ - Email-triggered workflows
13
+ - Notification systems
14
+
15
+ **No authentication required** - fully public API with automatic cleanup.
16
+
17
+ ---
18
+
19
+ ## 📦 Installation
20
+
21
+ ```bash
22
+ npm install @tempyemail/e2e-testing
23
+ ```
24
+
25
+ Or with other package managers:
26
+
27
+ ```bash
28
+ yarn add @tempyemail/e2e-testing
29
+ pnpm add @tempyemail/e2e-testing
30
+ ```
31
+
32
+ ---
33
+
34
+ ## 🚀 Quick Start
35
+
36
+ ```typescript
37
+ import { TempyEmail } from '@tempyemail/e2e-testing';
38
+
39
+ // Create client
40
+ const client = new TempyEmail();
41
+
42
+ // Create a temporary mailbox
43
+ const mailbox = await client.createMailbox();
44
+ console.log(`Email: ${mailbox.address}`);
45
+
46
+ // Wait for an email
47
+ const email = await mailbox.waitForEmail({ timeout: 30000 });
48
+ console.log(`Received: ${email.subject}`);
49
+
50
+ // Extract OTP code
51
+ const otp = await mailbox.waitForOTP({ timeout: 30000 });
52
+ console.log(`OTP: ${otp}`);
53
+
54
+ // Cleanup
55
+ await mailbox.delete();
56
+ ```
57
+
58
+ ---
59
+
60
+ ## 📚 API Reference
61
+
62
+ ### TempyEmail
63
+
64
+ Main client class for interacting with the API.
65
+
66
+ #### Constructor
67
+
68
+ ```typescript
69
+ new TempyEmail(config?: {
70
+ baseUrl?: string; // Default: 'https://tempy.email/api/v1'
71
+ timeout?: number; // Default: 30000 (30 seconds)
72
+ })
73
+ ```
74
+
75
+ #### Methods
76
+
77
+ ##### `createMailbox(options?)`
78
+
79
+ Create a new temporary mailbox.
80
+
81
+ ```typescript
82
+ const mailbox = await client.createMailbox({
83
+ webhookUrl?: string; // Optional webhook URL
84
+ webhookFormat?: 'json' | 'xml'; // Default: 'json'
85
+ });
86
+ ```
87
+
88
+ **Returns:** `Promise<Mailbox>`
89
+
90
+ ##### `getMailbox(address)`
91
+
92
+ Get an existing mailbox by email address.
93
+
94
+ ```typescript
95
+ const mailbox = await client.getMailbox('abc123@tempy.email');
96
+ ```
97
+
98
+ **Returns:** `Promise<Mailbox>`
99
+
100
+ ---
101
+
102
+ ### Mailbox
103
+
104
+ Represents a temporary email inbox with helper methods.
105
+
106
+ #### Properties
107
+
108
+ - `address: string` - The email address
109
+ - `expiresAt: Date` - When the mailbox expires
110
+ - `webhookUrl?: string` - Webhook URL if configured
111
+
112
+ #### Methods
113
+
114
+ ##### `getMessages()`
115
+
116
+ Get all messages in the mailbox.
117
+
118
+ ```typescript
119
+ const messages = await mailbox.getMessages();
120
+ ```
121
+
122
+ **Returns:** `Promise<Email[]>`
123
+
124
+ ##### `waitForEmail(options?)`
125
+
126
+ Wait for a new email matching the specified criteria.
127
+
128
+ ```typescript
129
+ const email = await mailbox.waitForEmail({
130
+ timeout?: number; // Default: 30000ms
131
+ subject?: string | RegExp; // Filter by subject
132
+ from?: string | RegExp; // Filter by sender
133
+ pollInterval?: number; // Default: 1000ms
134
+ });
135
+ ```
136
+
137
+ **Returns:** `Promise<Email>`
138
+
139
+ **Example:**
140
+
141
+ ```typescript
142
+ // Wait for any email
143
+ const email = await mailbox.waitForEmail();
144
+
145
+ // Wait for email from specific sender
146
+ const email = await mailbox.waitForEmail({
147
+ from: /noreply@example\.com/
148
+ });
149
+
150
+ // Wait for email with specific subject
151
+ const email = await mailbox.waitForEmail({
152
+ subject: 'Welcome',
153
+ timeout: 60000
154
+ });
155
+ ```
156
+
157
+ ##### `waitForOTP(options?)`
158
+
159
+ Wait for an email and extract an OTP code.
160
+
161
+ ```typescript
162
+ const otp = await mailbox.waitForOTP({
163
+ timeout?: number; // Default: 30000ms
164
+ pattern?: RegExp; // Custom OTP pattern
165
+ from?: string | RegExp; // Filter by sender
166
+ });
167
+ ```
168
+
169
+ **Returns:** `Promise<string>`
170
+
171
+ **Automatically extracts:**
172
+ - 6-digit codes (e.g., `123456`)
173
+ - 4-8 digit codes
174
+ - Alphanumeric codes (e.g., `ABC123`)
175
+ - UUID tokens
176
+
177
+ **Example:**
178
+
179
+ ```typescript
180
+ // Extract any common OTP format
181
+ const otp = await mailbox.waitForOTP({ timeout: 30000 });
182
+
183
+ // Custom pattern
184
+ const otp = await mailbox.waitForOTP({
185
+ pattern: /PIN:\s*(\d{4})/
186
+ });
187
+ ```
188
+
189
+ ##### `waitForLink(options?)`
190
+
191
+ Wait for an email and extract a verification/magic link.
192
+
193
+ ```typescript
194
+ const link = await mailbox.waitForLink({
195
+ timeout?: number; // Default: 30000ms
196
+ pattern?: RegExp; // Custom link pattern
197
+ from?: string | RegExp; // Filter by sender
198
+ });
199
+ ```
200
+
201
+ **Returns:** `Promise<string>`
202
+
203
+ **Example:**
204
+
205
+ ```typescript
206
+ // Extract verification link
207
+ const link = await mailbox.waitForLink({
208
+ pattern: /verify/i
209
+ });
210
+
211
+ // Extract password reset link
212
+ const resetLink = await mailbox.waitForLink({
213
+ pattern: /reset-password/,
214
+ from: /security@/
215
+ });
216
+ ```
217
+
218
+ ##### `markAsRead(emailIds)`
219
+
220
+ Mark emails as read.
221
+
222
+ ```typescript
223
+ await mailbox.markAsRead(['email-id-1', 'email-id-2']);
224
+ ```
225
+
226
+ ##### `delete()`
227
+
228
+ Delete the mailbox.
229
+
230
+ ```typescript
231
+ await mailbox.delete();
232
+ ```
233
+
234
+ ##### `getStatus()`
235
+
236
+ Get mailbox status.
237
+
238
+ ```typescript
239
+ const status = await mailbox.getStatus();
240
+ console.log(`Expires: ${status.expiresAt}`);
241
+ console.log(`Time remaining: ${status.secondsRemaining}s`);
242
+ ```
243
+
244
+ ##### `isExpired()`
245
+
246
+ Check if mailbox has expired.
247
+
248
+ ```typescript
249
+ if (mailbox.isExpired()) {
250
+ console.log('Mailbox expired');
251
+ }
252
+ ```
253
+
254
+ ##### `secondsRemaining()`
255
+
256
+ Get seconds remaining until expiration.
257
+
258
+ ```typescript
259
+ const remaining = mailbox.secondsRemaining();
260
+ console.log(`${remaining}s remaining`);
261
+ ```
262
+
263
+ ---
264
+
265
+ ## 🎭 Framework Integration
266
+
267
+ ### Playwright
268
+
269
+ ```typescript
270
+ import { test, expect } from '@playwright/test';
271
+ import { TempyEmail } from '@tempyemail/e2e-testing';
272
+
273
+ test('user signup with verification', async ({ page }) => {
274
+ const client = new TempyEmail();
275
+ const mailbox = await client.createMailbox();
276
+
277
+ // Fill signup form
278
+ await page.goto('https://example.com/signup');
279
+ await page.fill('[name="email"]', mailbox.address);
280
+ await page.fill('[name="password"]', 'Password123!');
281
+ await page.click('button[type="submit"]');
282
+
283
+ // Wait for OTP
284
+ const otp = await mailbox.waitForOTP({ timeout: 30000 });
285
+
286
+ // Enter OTP
287
+ await page.fill('[name="code"]', otp);
288
+ await page.click('button[type="submit"]');
289
+
290
+ // Verify success
291
+ await expect(page.locator('.success')).toBeVisible();
292
+
293
+ await mailbox.delete();
294
+ });
295
+ ```
296
+
297
+ ### Cypress
298
+
299
+ ```typescript
300
+ import { TempyEmail } from '@tempyemail/e2e-testing';
301
+
302
+ describe('Signup', () => {
303
+ it('completes email verification', () => {
304
+ const client = new TempyEmail();
305
+
306
+ cy.wrap(client.createMailbox()).then((mailbox) => {
307
+ cy.visit('/signup');
308
+ cy.get('[name="email"]').type(mailbox.address);
309
+ cy.get('[name="password"]').type('Password123!');
310
+ cy.get('button[type="submit"]').click();
311
+
312
+ // Wait for OTP
313
+ cy.wrap(mailbox.waitForOTP({ timeout: 30000 })).then((otp) => {
314
+ cy.get('[name="code"]').type(otp);
315
+ cy.get('button[type="submit"]').click();
316
+ cy.get('.success').should('be.visible');
317
+ });
318
+
319
+ cy.wrap(mailbox.delete());
320
+ });
321
+ });
322
+ });
323
+ ```
324
+
325
+ ### Jest
326
+
327
+ ```typescript
328
+ import { TempyEmail } from '@tempyemail/e2e-testing';
329
+
330
+ describe('Email Integration', () => {
331
+ let client: TempyEmail;
332
+ let mailbox: Mailbox;
333
+
334
+ beforeAll(() => {
335
+ client = new TempyEmail();
336
+ });
337
+
338
+ beforeEach(async () => {
339
+ mailbox = await client.createMailbox();
340
+ });
341
+
342
+ afterEach(async () => {
343
+ await mailbox.delete();
344
+ });
345
+
346
+ it('receives welcome email', async () => {
347
+ // Trigger email in your app
348
+ await yourApp.sendWelcomeEmail(mailbox.address);
349
+
350
+ const email = await mailbox.waitForEmail({
351
+ subject: /welcome/i,
352
+ timeout: 30000
353
+ });
354
+
355
+ expect(email.subject).toContain('Welcome');
356
+ });
357
+ });
358
+ ```
359
+
360
+ ### Vitest
361
+
362
+ ```typescript
363
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
364
+ import { TempyEmail, Mailbox } from '@tempyemail/e2e-testing';
365
+
366
+ describe('Password Reset', () => {
367
+ let mailbox: Mailbox;
368
+
369
+ beforeEach(async () => {
370
+ const client = new TempyEmail();
371
+ mailbox = await client.createMailbox();
372
+ });
373
+
374
+ afterEach(async () => {
375
+ await mailbox.delete();
376
+ });
377
+
378
+ it('sends reset link', async () => {
379
+ await yourApp.requestPasswordReset(mailbox.address);
380
+
381
+ const link = await mailbox.waitForLink({
382
+ pattern: /reset-password/,
383
+ timeout: 30000
384
+ });
385
+
386
+ expect(link).toMatch(/^https:\/\//);
387
+ });
388
+ });
389
+ ```
390
+
391
+ ---
392
+
393
+ ## 🔍 Extracting OTP Codes
394
+
395
+ The library automatically extracts common OTP formats:
396
+
397
+ ```typescript
398
+ // 6-digit codes
399
+ "Your code is 123456" → "123456"
400
+
401
+ // Codes with formatting
402
+ "Code: 987-654" → "987654"
403
+
404
+ // Alphanumeric codes
405
+ "Token: ABC123" → "ABC123"
406
+
407
+ // UUID tokens
408
+ "Token: 550e8400-e29b-41d4-a716-446655440000" → "550e8400-..."
409
+ ```
410
+
411
+ ### Custom OTP Patterns
412
+
413
+ ```typescript
414
+ // Extract 4-digit PIN
415
+ const pin = await mailbox.waitForOTP({
416
+ pattern: /PIN:\s*(\d{4})/
417
+ });
418
+
419
+ // Extract specific format
420
+ const code = await mailbox.waitForOTP({
421
+ pattern: /CODE:\s*([A-Z0-9]{8})/
422
+ });
423
+ ```
424
+
425
+ ### Manual Extraction
426
+
427
+ ```typescript
428
+ import {
429
+ extract6DigitOTP,
430
+ extractNumericOTP,
431
+ extractAlphanumericOTP,
432
+ extractUUID,
433
+ extractByPattern
434
+ } from '@tempyemail/e2e-testing';
435
+
436
+ // From email text
437
+ const email = await mailbox.waitForEmail();
438
+ const otp = extract6DigitOTP(email.bodyText);
439
+ ```
440
+
441
+ ---
442
+
443
+ ## 🔗 Extracting Links
444
+
445
+ Extract verification and magic links from emails:
446
+
447
+ ```typescript
448
+ // Wait for verification link
449
+ const link = await mailbox.waitForLink();
450
+
451
+ // Custom pattern
452
+ const magicLink = await mailbox.waitForLink({
453
+ pattern: /magic-link/
454
+ });
455
+
456
+ // From specific sender
457
+ const resetLink = await mailbox.waitForLink({
458
+ pattern: /reset/,
459
+ from: /security@example\.com/
460
+ });
461
+ ```
462
+
463
+ ### Manual Link Extraction
464
+
465
+ ```typescript
466
+ import {
467
+ extractLinks,
468
+ extractVerificationLink,
469
+ extractLinksByDomain,
470
+ extractFirstLink
471
+ } from '@tempyemail/e2e-testing';
472
+
473
+ const email = await mailbox.waitForEmail();
474
+
475
+ // All links
476
+ const allLinks = extractLinks(email.bodyHtml);
477
+
478
+ // Verification links only
479
+ const verifyLink = extractVerificationLink(email.bodyHtml);
480
+
481
+ // Links from specific domain
482
+ const appLinks = extractLinksByDomain(email.bodyHtml, 'example.com');
483
+
484
+ // First link
485
+ const firstLink = extractFirstLink(email.bodyText);
486
+ ```
487
+
488
+ ---
489
+
490
+ ## 🪝 Using Webhooks
491
+
492
+ Receive real-time notifications when emails arrive:
493
+
494
+ ```typescript
495
+ const mailbox = await client.createMailbox({
496
+ webhookUrl: 'https://your-server.com/webhook',
497
+ webhookFormat: 'json'
498
+ });
499
+
500
+ console.log(`Webhook configured: ${mailbox.webhookUrl}`);
501
+ ```
502
+
503
+ **Webhook payload:**
504
+
505
+ ```json
506
+ {
507
+ "id": "msg_abc123",
508
+ "from": "sender@example.com",
509
+ "to": "abc123@tempy.email",
510
+ "subject": "Verification Code",
511
+ "bodyText": "Your code is 123456",
512
+ "bodyHtml": "<p>Your code is <b>123456</b></p>",
513
+ "receivedAt": "2025-01-15T10:30:00Z",
514
+ "direction": "inbound",
515
+ "isRead": false,
516
+ "allowReply": true
517
+ }
518
+ ```
519
+
520
+ **Testing webhooks locally:**
521
+
522
+ ```bash
523
+ # Expose local server with ngrok
524
+ npx ngrok http 3000
525
+
526
+ # Use ngrok URL as webhook
527
+ const mailbox = await client.createMailbox({
528
+ webhookUrl: 'https://abc123.ngrok.io/webhook'
529
+ });
530
+ ```
531
+
532
+ ---
533
+
534
+ ## 💡 Best Practices
535
+
536
+ ### 1. Always Clean Up
537
+
538
+ ```typescript
539
+ let mailbox: Mailbox;
540
+
541
+ try {
542
+ mailbox = await client.createMailbox();
543
+ // ... your test ...
544
+ } finally {
545
+ if (mailbox) {
546
+ await mailbox.delete();
547
+ }
548
+ }
549
+ ```
550
+
551
+ ### 2. Use Appropriate Timeouts
552
+
553
+ ```typescript
554
+ // Quick operations
555
+ const email = await mailbox.waitForEmail({ timeout: 10000 });
556
+
557
+ // Slower email services
558
+ const email = await mailbox.waitForEmail({ timeout: 60000 });
559
+ ```
560
+
561
+ ### 3. Filter by Sender
562
+
563
+ ```typescript
564
+ // Only accept emails from your app
565
+ const otp = await mailbox.waitForOTP({
566
+ from: /noreply@yourapp\.com/
567
+ });
568
+ ```
569
+
570
+ ### 4. Handle Timeouts Gracefully
571
+
572
+ ```typescript
573
+ try {
574
+ const otp = await mailbox.waitForOTP({ timeout: 30000 });
575
+ } catch (error) {
576
+ if (error.message.includes('timeout')) {
577
+ console.log('Email not received - check email service');
578
+ }
579
+ throw error;
580
+ }
581
+ ```
582
+
583
+ ### 5. Reuse Mailboxes When Possible
584
+
585
+ ```typescript
586
+ // Good: One mailbox for entire test
587
+ const mailbox = await client.createMailbox();
588
+ await testSignup(mailbox);
589
+ await testVerification(mailbox);
590
+ await mailbox.delete();
591
+
592
+ // Avoid: Creating multiple mailboxes unnecessarily
593
+ ```
594
+
595
+ ---
596
+
597
+ ## ⚡ Rate Limits
598
+
599
+ The tempy.email API has the following limits:
600
+
601
+ - **Mailbox creation:** Unlimited
602
+ - **API requests:** 100 per minute per IP
603
+ - **Mailbox lifetime:** 1 hour (automatic cleanup)
604
+ - **Message retention:** Deleted when mailbox expires
605
+
606
+ No authentication required - fully public API.
607
+
608
+ ---
609
+
610
+ ## 🐛 Troubleshooting
611
+
612
+ ### "Polling timeout" error
613
+
614
+ ```typescript
615
+ // Increase timeout
616
+ const email = await mailbox.waitForEmail({ timeout: 60000 });
617
+
618
+ // Check if email was actually sent
619
+ const messages = await mailbox.getMessages();
620
+ console.log(`${messages.length} messages in mailbox`);
621
+ ```
622
+
623
+ ### "No OTP code found" error
624
+
625
+ ```typescript
626
+ // Use custom pattern
627
+ const otp = await mailbox.waitForOTP({
628
+ pattern: /code:\s*(\d+)/i
629
+ });
630
+
631
+ // Or extract manually
632
+ const email = await mailbox.waitForEmail();
633
+ console.log('Email body:', email.bodyText);
634
+ ```
635
+
636
+ ### "Failed to create mailbox" error
637
+
638
+ - Check your internet connection
639
+ - Verify tempy.email is accessible
640
+ - Check for rate limiting (100 requests/minute)
641
+
642
+ ### Emails not arriving
643
+
644
+ - Wait longer (increase timeout)
645
+ - Check spam/junk folder in your email service
646
+ - Verify the email was actually sent from your app
647
+ - Check mailbox hasn't expired (`mailbox.isExpired()`)
648
+
649
+ ---
650
+
651
+ ## 📖 Examples
652
+
653
+ Complete working examples are available in the [`examples/`](./examples) directory:
654
+
655
+ - **[Basic](./examples/basic/)** - Simple Node.js examples
656
+ - **[Playwright](./examples/playwright/)** - Browser testing with Playwright
657
+ - **[Cypress](./examples/cypress/)** - E2E testing with Cypress
658
+ - **[Jest](./examples/jest/)** - Unit/integration testing with Jest
659
+ - **[Vitest](./examples/vitest/)** - Testing with Vitest
660
+
661
+ ---
662
+
663
+ ## 🤝 Contributing
664
+
665
+ Contributions are welcome! Please open an issue or submit a pull request on [GitHub](https://github.com/TempyEmail/e2e-testing).
666
+
667
+ ---
668
+
669
+ ## 📄 License
670
+
671
+ MIT © TempyEmail
672
+
673
+ ---
674
+
675
+ ## 🔗 Links
676
+
677
+ - **Website:** https://tempy.email
678
+ - **GitHub:** https://github.com/TempyEmail/e2e-testing
679
+ - **npm:** https://www.npmjs.com/package/@tempyemail/e2e-testing
680
+ - **Issues:** https://github.com/TempyEmail/e2e-testing/issues
681
+
682
+ ---
683
+
684
+ ## 🌟 Why tempy.email?
685
+
686
+ - ✅ **No authentication** - Just create and use
687
+ - ✅ **Automatic cleanup** - Mailboxes expire after 1 hour
688
+ - ✅ **Real emails** - Full SMTP support, not mocked
689
+ - ✅ **Webhook support** - Real-time notifications
690
+ - ✅ **Smart parsing** - Automatic OTP and link extraction
691
+ - ✅ **Framework agnostic** - Works with any testing framework
692
+ - ✅ **TypeScript native** - Full type safety
693
+ - ✅ **Zero configuration** - Works out of the box
694
+
695
+ Perfect for CI/CD pipelines, automated testing, and development workflows.