@bernierllc/email-testing-suite 0.3.0 → 0.4.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.
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Test helper utilities for email feature packages.
3
+ *
4
+ * Provides mock factories, assertion helpers, and validation utilities
5
+ * for calendar events, batch sending, subscriptions, headers, and attachments.
6
+ *
7
+ * These helpers are designed for consumers of the email suite to use in their
8
+ * own test suites when building on top of @bernierllc email packages.
9
+ */
10
+ import type { EmailData } from './types';
11
+ /**
12
+ * Represents a calendar event for email invitations.
13
+ * Aligns with the planned @bernierllc/email-calendar package interface.
14
+ */
15
+ export interface CalendarEvent {
16
+ uid: string;
17
+ summary: string;
18
+ description?: string;
19
+ location?: string;
20
+ dtstart: Date;
21
+ dtend: Date;
22
+ organizer: {
23
+ name: string;
24
+ email: string;
25
+ };
26
+ attendees?: Array<{
27
+ name: string;
28
+ email: string;
29
+ rsvp?: boolean;
30
+ role?: 'REQ-PARTICIPANT' | 'OPT-PARTICIPANT' | 'CHAIR';
31
+ status?: 'NEEDS-ACTION' | 'ACCEPTED' | 'DECLINED' | 'TENTATIVE';
32
+ }>;
33
+ method?: 'REQUEST' | 'REPLY' | 'CANCEL' | 'PUBLISH';
34
+ sequence?: number;
35
+ status?: 'CONFIRMED' | 'TENTATIVE' | 'CANCELLED';
36
+ rrule?: string;
37
+ }
38
+ /**
39
+ * Input for a single email in a batch send operation.
40
+ * Aligns with the planned @bernierllc/email-batch-sender package interface.
41
+ */
42
+ export interface BatchEmailInput {
43
+ to: string;
44
+ subject: string;
45
+ html?: string;
46
+ text?: string;
47
+ from?: string;
48
+ headers?: Record<string, string>;
49
+ tags?: string[];
50
+ metadata?: Record<string, string>;
51
+ }
52
+ /**
53
+ * Result of a batch email send operation.
54
+ */
55
+ export interface BatchResult {
56
+ total: number;
57
+ succeeded: number;
58
+ failed: number;
59
+ errors: Array<{
60
+ index: number;
61
+ email: string;
62
+ error: string;
63
+ }>;
64
+ duration: number;
65
+ }
66
+ /**
67
+ * Represents a subscription list.
68
+ * Aligns with the planned @bernierllc/email-subscription package interface.
69
+ */
70
+ export interface SubscriberList {
71
+ id: string;
72
+ name: string;
73
+ description?: string;
74
+ subscribers: Subscriber[];
75
+ createdAt: string;
76
+ updatedAt: string;
77
+ }
78
+ /**
79
+ * Represents a subscriber within a list.
80
+ */
81
+ export interface Subscriber {
82
+ id: string;
83
+ email: string;
84
+ name?: string;
85
+ status: 'active' | 'unsubscribed' | 'bounced' | 'complained';
86
+ subscribedAt: string;
87
+ unsubscribedAt?: string;
88
+ metadata?: Record<string, string>;
89
+ tags?: string[];
90
+ }
91
+ /**
92
+ * Represents a suppression entry.
93
+ */
94
+ export interface Suppression {
95
+ email: string;
96
+ reason: 'bounce' | 'complaint' | 'unsubscribe' | 'manual';
97
+ createdAt: string;
98
+ source?: string;
99
+ }
100
+ /**
101
+ * Represents an email attachment.
102
+ * Aligns with the planned @bernierllc/email-attachments package interface.
103
+ */
104
+ export interface Attachment {
105
+ filename: string;
106
+ content: Buffer | string;
107
+ contentType: string;
108
+ encoding?: 'base64' | 'binary' | 'utf-8';
109
+ contentDisposition?: 'attachment' | 'inline';
110
+ contentId?: string;
111
+ size?: number;
112
+ }
113
+ /**
114
+ * Creates a mock CalendarEvent with sensible defaults.
115
+ * Override any field by passing partial overrides.
116
+ */
117
+ export declare function createMockCalendarEvent(overrides?: Partial<CalendarEvent>): CalendarEvent;
118
+ /**
119
+ * Asserts that a string contains valid ICS (iCalendar) content.
120
+ * Validates required ICS properties and structure.
121
+ *
122
+ * @throws Error if the ICS content is invalid
123
+ */
124
+ export declare function assertValidIcsContent(icsString: string): void;
125
+ /**
126
+ * Asserts that an EmailData object represents a valid calendar invite email.
127
+ * Checks for a text/calendar attachment.
128
+ *
129
+ * @throws Error if the email is not a valid calendar invite
130
+ */
131
+ export declare function assertCalendarInviteEmail(email: EmailData): void;
132
+ /**
133
+ * Creates an array of mock batch email inputs.
134
+ *
135
+ * @param count - Number of mock emails to create
136
+ * @param overrides - Partial overrides applied to each email
137
+ */
138
+ export declare function createMockBatchEmails(count: number, overrides?: Partial<BatchEmailInput>): BatchEmailInput[];
139
+ /**
140
+ * Asserts that a BatchResult matches the given expectations.
141
+ *
142
+ * @throws Error if the result does not meet expectations
143
+ */
144
+ export declare function assertBatchResult(result: BatchResult, expectations: {
145
+ minSucceeded?: number;
146
+ maxFailed?: number;
147
+ }): void;
148
+ /**
149
+ * Creates a mock SubscriberList with sensible defaults.
150
+ */
151
+ export declare function createMockSubscriberList(overrides?: Partial<SubscriberList>): SubscriberList;
152
+ /**
153
+ * Creates a mock Subscriber with sensible defaults.
154
+ */
155
+ export declare function createMockSubscriber(overrides?: Partial<Subscriber>): Subscriber;
156
+ /**
157
+ * Asserts that a subscriber has an active subscription.
158
+ *
159
+ * @throws Error if the subscriber is not active
160
+ */
161
+ export declare function assertSubscriptionActive(subscriber: Subscriber): void;
162
+ /**
163
+ * Asserts that a suppression entry is valid.
164
+ *
165
+ * @throws Error if the suppression is invalid
166
+ */
167
+ export declare function assertSuppressed(suppression: Suppression): void;
168
+ /**
169
+ * Asserts that headers contain email threading headers
170
+ * (In-Reply-To and/or References).
171
+ *
172
+ * @throws Error if threading headers are missing
173
+ */
174
+ export declare function assertHasThreadingHeaders(headers: Record<string, string>): void;
175
+ /**
176
+ * Asserts that headers contain List-Unsubscribe header(s).
177
+ * Validates both List-Unsubscribe and optionally List-Unsubscribe-Post (RFC 8058).
178
+ *
179
+ * @throws Error if List-Unsubscribe header is missing
180
+ */
181
+ export declare function assertHasListUnsubscribeHeaders(headers: Record<string, string>): void;
182
+ /**
183
+ * Asserts that headers contain a Disposition-Notification-To header (MDN request).
184
+ *
185
+ * @throws Error if MDN request header is missing
186
+ */
187
+ export declare function assertHasMdnRequestHeader(headers: Record<string, string>): void;
188
+ /**
189
+ * Creates a mock Attachment with sensible defaults.
190
+ */
191
+ export declare function createMockAttachment(overrides?: Partial<Attachment>): Attachment;
192
+ /**
193
+ * Asserts that an attachment has all required fields and valid values.
194
+ *
195
+ * @throws Error if the attachment is invalid
196
+ */
197
+ export declare function assertValidAttachment(attachment: Attachment): void;
198
+ /**
199
+ * Asserts that an attachment does not exceed the specified size in bytes.
200
+ *
201
+ * @throws Error if the attachment exceeds maxBytes
202
+ */
203
+ export declare function assertAttachmentSize(attachment: Attachment, maxBytes: number): void;
204
+ //# sourceMappingURL=feature-test-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-test-helpers.d.ts","sourceRoot":"","sources":["../src/feature-test-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,375 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (c) 2025 Bernier LLC
4
+
5
+ This file is licensed to the client under a limited-use license.
6
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
7
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.createMockCalendarEvent = createMockCalendarEvent;
11
+ exports.assertValidIcsContent = assertValidIcsContent;
12
+ exports.assertCalendarInviteEmail = assertCalendarInviteEmail;
13
+ exports.createMockBatchEmails = createMockBatchEmails;
14
+ exports.assertBatchResult = assertBatchResult;
15
+ exports.createMockSubscriberList = createMockSubscriberList;
16
+ exports.createMockSubscriber = createMockSubscriber;
17
+ exports.assertSubscriptionActive = assertSubscriptionActive;
18
+ exports.assertSuppressed = assertSuppressed;
19
+ exports.assertHasThreadingHeaders = assertHasThreadingHeaders;
20
+ exports.assertHasListUnsubscribeHeaders = assertHasListUnsubscribeHeaders;
21
+ exports.assertHasMdnRequestHeader = assertHasMdnRequestHeader;
22
+ exports.createMockAttachment = createMockAttachment;
23
+ exports.assertValidAttachment = assertValidAttachment;
24
+ exports.assertAttachmentSize = assertAttachmentSize;
25
+ // ============================================================================
26
+ // Calendar Helpers
27
+ // ============================================================================
28
+ /**
29
+ * Creates a mock CalendarEvent with sensible defaults.
30
+ * Override any field by passing partial overrides.
31
+ */
32
+ function createMockCalendarEvent(overrides) {
33
+ const now = new Date();
34
+ const oneHourLater = new Date(now.getTime() + 60 * 60 * 1000);
35
+ return {
36
+ uid: `mock-event-${Date.now()}@example.com`,
37
+ summary: 'Mock Calendar Event',
38
+ description: 'This is a mock calendar event for testing',
39
+ location: 'Virtual Meeting Room',
40
+ dtstart: now,
41
+ dtend: oneHourLater,
42
+ organizer: {
43
+ name: 'Test Organizer',
44
+ email: 'organizer@example.com',
45
+ },
46
+ attendees: [
47
+ {
48
+ name: 'Test Attendee',
49
+ email: 'attendee@example.com',
50
+ rsvp: true,
51
+ role: 'REQ-PARTICIPANT',
52
+ status: 'NEEDS-ACTION',
53
+ },
54
+ ],
55
+ method: 'REQUEST',
56
+ sequence: 0,
57
+ status: 'CONFIRMED',
58
+ ...overrides,
59
+ };
60
+ }
61
+ /**
62
+ * Asserts that a string contains valid ICS (iCalendar) content.
63
+ * Validates required ICS properties and structure.
64
+ *
65
+ * @throws Error if the ICS content is invalid
66
+ */
67
+ function assertValidIcsContent(icsString) {
68
+ if (!icsString || typeof icsString !== 'string') {
69
+ throw new Error('ICS content must be a non-empty string');
70
+ }
71
+ const trimmed = icsString.trim();
72
+ if (!trimmed.startsWith('BEGIN:VCALENDAR')) {
73
+ throw new Error('ICS content must start with BEGIN:VCALENDAR');
74
+ }
75
+ if (!trimmed.endsWith('END:VCALENDAR')) {
76
+ throw new Error('ICS content must end with END:VCALENDAR');
77
+ }
78
+ if (!trimmed.includes('BEGIN:VEVENT')) {
79
+ throw new Error('ICS content must contain at least one VEVENT');
80
+ }
81
+ if (!trimmed.includes('END:VEVENT')) {
82
+ throw new Error('ICS content must contain END:VEVENT');
83
+ }
84
+ const requiredProperties = ['DTSTART', 'DTEND', 'SUMMARY'];
85
+ for (const prop of requiredProperties) {
86
+ if (!trimmed.includes(prop)) {
87
+ throw new Error(`ICS content must contain ${prop} property`);
88
+ }
89
+ }
90
+ if (!trimmed.includes('VERSION:2.0')) {
91
+ throw new Error('ICS content must specify VERSION:2.0');
92
+ }
93
+ }
94
+ /**
95
+ * Asserts that an EmailData object represents a valid calendar invite email.
96
+ * Checks for a text/calendar attachment.
97
+ *
98
+ * @throws Error if the email is not a valid calendar invite
99
+ */
100
+ function assertCalendarInviteEmail(email) {
101
+ if (!email) {
102
+ throw new Error('Email data is required');
103
+ }
104
+ if (!email.attachments || email.attachments.length === 0) {
105
+ throw new Error('Calendar invite email must have at least one attachment');
106
+ }
107
+ const calendarAttachment = email.attachments.find((att) => att.contentType === 'text/calendar' ||
108
+ att.contentType === 'application/ics' ||
109
+ (att.filename && att.filename.endsWith('.ics')));
110
+ if (!calendarAttachment) {
111
+ throw new Error('Calendar invite email must have a text/calendar or .ics attachment');
112
+ }
113
+ }
114
+ // ============================================================================
115
+ // Batch Helpers
116
+ // ============================================================================
117
+ /**
118
+ * Creates an array of mock batch email inputs.
119
+ *
120
+ * @param count - Number of mock emails to create
121
+ * @param overrides - Partial overrides applied to each email
122
+ */
123
+ function createMockBatchEmails(count, overrides) {
124
+ if (count < 0) {
125
+ throw new Error('Count must be a non-negative number');
126
+ }
127
+ return Array.from({ length: count }, (_, i) => ({
128
+ to: `recipient-${i + 1}@example.com`,
129
+ subject: `Batch Email #${i + 1}`,
130
+ html: `<p>Batch email content ${i + 1}</p>`,
131
+ text: `Batch email content ${i + 1}`,
132
+ from: 'sender@example.com',
133
+ ...overrides,
134
+ }));
135
+ }
136
+ /**
137
+ * Asserts that a BatchResult matches the given expectations.
138
+ *
139
+ * @throws Error if the result does not meet expectations
140
+ */
141
+ function assertBatchResult(result, expectations) {
142
+ if (!result) {
143
+ throw new Error('Batch result is required');
144
+ }
145
+ if (expectations.minSucceeded !== undefined &&
146
+ result.succeeded < expectations.minSucceeded) {
147
+ throw new Error(`Expected at least ${expectations.minSucceeded} succeeded, but got ${result.succeeded}`);
148
+ }
149
+ if (expectations.maxFailed !== undefined &&
150
+ result.failed > expectations.maxFailed) {
151
+ throw new Error(`Expected at most ${expectations.maxFailed} failed, but got ${result.failed}`);
152
+ }
153
+ if (result.succeeded + result.failed !== result.total) {
154
+ throw new Error(`Batch result inconsistency: succeeded (${result.succeeded}) + failed (${result.failed}) !== total (${result.total})`);
155
+ }
156
+ }
157
+ // ============================================================================
158
+ // Subscription Helpers
159
+ // ============================================================================
160
+ /**
161
+ * Creates a mock SubscriberList with sensible defaults.
162
+ */
163
+ function createMockSubscriberList(overrides) {
164
+ const now = new Date().toISOString();
165
+ return {
166
+ id: `list-${Date.now()}`,
167
+ name: 'Mock Subscriber List',
168
+ description: 'A mock subscriber list for testing',
169
+ subscribers: [
170
+ createMockSubscriber({ email: 'subscriber-1@example.com' }),
171
+ createMockSubscriber({ email: 'subscriber-2@example.com' }),
172
+ ],
173
+ createdAt: now,
174
+ updatedAt: now,
175
+ ...overrides,
176
+ };
177
+ }
178
+ /**
179
+ * Creates a mock Subscriber with sensible defaults.
180
+ */
181
+ function createMockSubscriber(overrides) {
182
+ const now = new Date().toISOString();
183
+ return {
184
+ id: `sub-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
185
+ email: 'mock-subscriber@example.com',
186
+ name: 'Mock Subscriber',
187
+ status: 'active',
188
+ subscribedAt: now,
189
+ metadata: {},
190
+ tags: [],
191
+ ...overrides,
192
+ };
193
+ }
194
+ /**
195
+ * Asserts that a subscriber has an active subscription.
196
+ *
197
+ * @throws Error if the subscriber is not active
198
+ */
199
+ function assertSubscriptionActive(subscriber) {
200
+ if (!subscriber) {
201
+ throw new Error('Subscriber is required');
202
+ }
203
+ if (subscriber.status !== 'active') {
204
+ throw new Error(`Expected subscriber status to be 'active', but got '${subscriber.status}'`);
205
+ }
206
+ if (!subscriber.subscribedAt) {
207
+ throw new Error('Active subscriber must have a subscribedAt date');
208
+ }
209
+ if (subscriber.unsubscribedAt) {
210
+ throw new Error('Active subscriber should not have an unsubscribedAt date');
211
+ }
212
+ }
213
+ /**
214
+ * Asserts that a suppression entry is valid.
215
+ *
216
+ * @throws Error if the suppression is invalid
217
+ */
218
+ function assertSuppressed(suppression) {
219
+ if (!suppression) {
220
+ throw new Error('Suppression is required');
221
+ }
222
+ if (!suppression.email || !suppression.email.includes('@')) {
223
+ throw new Error('Suppression must have a valid email address');
224
+ }
225
+ const validReasons = [
226
+ 'bounce',
227
+ 'complaint',
228
+ 'unsubscribe',
229
+ 'manual',
230
+ ];
231
+ if (!validReasons.includes(suppression.reason)) {
232
+ throw new Error(`Suppression reason must be one of: ${validReasons.join(', ')}`);
233
+ }
234
+ if (!suppression.createdAt) {
235
+ throw new Error('Suppression must have a createdAt date');
236
+ }
237
+ }
238
+ // ============================================================================
239
+ // Header Helpers
240
+ // ============================================================================
241
+ /**
242
+ * Asserts that headers contain email threading headers
243
+ * (In-Reply-To and/or References).
244
+ *
245
+ * @throws Error if threading headers are missing
246
+ */
247
+ function assertHasThreadingHeaders(headers) {
248
+ if (!headers) {
249
+ throw new Error('Headers object is required');
250
+ }
251
+ const hasInReplyTo = 'In-Reply-To' in headers || 'in-reply-to' in headers;
252
+ const hasReferences = 'References' in headers || 'references' in headers;
253
+ if (!hasInReplyTo && !hasReferences) {
254
+ throw new Error('Threading headers require at least In-Reply-To or References header');
255
+ }
256
+ }
257
+ /**
258
+ * Asserts that headers contain List-Unsubscribe header(s).
259
+ * Validates both List-Unsubscribe and optionally List-Unsubscribe-Post (RFC 8058).
260
+ *
261
+ * @throws Error if List-Unsubscribe header is missing
262
+ */
263
+ function assertHasListUnsubscribeHeaders(headers) {
264
+ if (!headers) {
265
+ throw new Error('Headers object is required');
266
+ }
267
+ const hasListUnsub = 'List-Unsubscribe' in headers || 'list-unsubscribe' in headers;
268
+ if (!hasListUnsub) {
269
+ throw new Error('Headers must contain a List-Unsubscribe header');
270
+ }
271
+ const unsubValue = headers['List-Unsubscribe'] || headers['list-unsubscribe'];
272
+ if (!unsubValue || unsubValue.trim().length === 0) {
273
+ throw new Error('List-Unsubscribe header must not be empty');
274
+ }
275
+ }
276
+ /**
277
+ * Asserts that headers contain a Disposition-Notification-To header (MDN request).
278
+ *
279
+ * @throws Error if MDN request header is missing
280
+ */
281
+ function assertHasMdnRequestHeader(headers) {
282
+ if (!headers) {
283
+ throw new Error('Headers object is required');
284
+ }
285
+ const hasMdn = 'Disposition-Notification-To' in headers ||
286
+ 'disposition-notification-to' in headers;
287
+ if (!hasMdn) {
288
+ throw new Error('Headers must contain a Disposition-Notification-To header for MDN requests');
289
+ }
290
+ const mdnValue = headers['Disposition-Notification-To'] ||
291
+ headers['disposition-notification-to'];
292
+ if (!mdnValue || !mdnValue.includes('@')) {
293
+ throw new Error('Disposition-Notification-To header must contain a valid email address');
294
+ }
295
+ }
296
+ // ============================================================================
297
+ // Attachment Helpers
298
+ // ============================================================================
299
+ /**
300
+ * Creates a mock Attachment with sensible defaults.
301
+ */
302
+ function createMockAttachment(overrides) {
303
+ const defaultContent = Buffer.from('Mock attachment content for testing');
304
+ return {
305
+ filename: 'test-document.pdf',
306
+ content: defaultContent,
307
+ contentType: 'application/pdf',
308
+ encoding: 'base64',
309
+ contentDisposition: 'attachment',
310
+ size: defaultContent.length,
311
+ ...overrides,
312
+ };
313
+ }
314
+ /**
315
+ * Asserts that an attachment has all required fields and valid values.
316
+ *
317
+ * @throws Error if the attachment is invalid
318
+ */
319
+ function assertValidAttachment(attachment) {
320
+ if (!attachment) {
321
+ throw new Error('Attachment is required');
322
+ }
323
+ if (!attachment.filename || attachment.filename.trim().length === 0) {
324
+ throw new Error('Attachment must have a non-empty filename');
325
+ }
326
+ if (attachment.content === undefined || attachment.content === null) {
327
+ throw new Error('Attachment must have content');
328
+ }
329
+ if (typeof attachment.content === 'string' &&
330
+ attachment.content.length === 0) {
331
+ throw new Error('Attachment content must not be empty');
332
+ }
333
+ if (Buffer.isBuffer(attachment.content) &&
334
+ attachment.content.length === 0) {
335
+ throw new Error('Attachment content must not be empty');
336
+ }
337
+ if (!attachment.contentType ||
338
+ attachment.contentType.trim().length === 0) {
339
+ throw new Error('Attachment must have a non-empty contentType');
340
+ }
341
+ // Validate contentType format (should contain a slash)
342
+ if (!attachment.contentType.includes('/')) {
343
+ throw new Error(`Attachment contentType '${attachment.contentType}' is not a valid MIME type`);
344
+ }
345
+ }
346
+ /**
347
+ * Asserts that an attachment does not exceed the specified size in bytes.
348
+ *
349
+ * @throws Error if the attachment exceeds maxBytes
350
+ */
351
+ function assertAttachmentSize(attachment, maxBytes) {
352
+ if (!attachment) {
353
+ throw new Error('Attachment is required');
354
+ }
355
+ if (maxBytes < 0) {
356
+ throw new Error('maxBytes must be a non-negative number');
357
+ }
358
+ let actualSize;
359
+ if (attachment.size !== undefined) {
360
+ actualSize = attachment.size;
361
+ }
362
+ else if (Buffer.isBuffer(attachment.content)) {
363
+ actualSize = attachment.content.length;
364
+ }
365
+ else if (typeof attachment.content === 'string') {
366
+ actualSize = Buffer.byteLength(attachment.content, 'utf-8');
367
+ }
368
+ else {
369
+ throw new Error('Cannot determine attachment size');
370
+ }
371
+ if (actualSize > maxBytes) {
372
+ throw new Error(`Attachment size (${actualSize} bytes) exceeds maximum allowed size (${maxBytes} bytes)`);
373
+ }
374
+ }
375
+ //# sourceMappingURL=feature-test-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-test-helpers.js","sourceRoot":"","sources":["../src/feature-test-helpers.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -7,5 +7,7 @@ export { EmailTestingSuite } from './email-testing-suite';
7
7
  export { testEmail, EmailTestPatterns } from './test-patterns';
8
8
  export { EmailTestAnalytics } from './analytics';
9
9
  export { BestPracticesValidator } from './best-practices';
10
+ export { createMockCalendarEvent, assertValidIcsContent, assertCalendarInviteEmail, createMockBatchEmails, assertBatchResult, createMockSubscriberList, createMockSubscriber, assertSubscriptionActive, assertSuppressed, assertHasThreadingHeaders, assertHasListUnsubscribeHeaders, assertHasMdnRequestHeader, createMockAttachment, assertValidAttachment, assertAttachmentSize, } from './feature-test-helpers';
11
+ export type { CalendarEvent, BatchEmailInput, BatchResult, SubscriberList, Subscriber, Suppression, Attachment, } from './feature-test-helpers';
10
12
  export type { EmailTestingSuiteConfig, SMTPConfig, SMTPAuth, DefaultsConfig, ValidationConfig, ValidatorType, ValidationRule, ReportingConfig, ReportFormat, IntegrationsConfig, TestFramework, WebhookConfig, NotificationConfig, EmailTemplateTest, TemplateSource, EmailExpectations, PerformanceThresholds, EmailFlowTest, EmailFlowStep, FlowAssertion, EmailTest, SimpleEmailTest, EmailTestResult, ValidationResult, EmailFlowResult, StepResult, AssertionResult, EmailSuiteResult, TestSummary, PerformanceMetrics, IssueCount, EmailData, EmailAttachment, TestingEnvironment, DataSchema, SchemaField, AnalyticsData, TrendData, ReportOptions, Report, Recommendation, ExportOptions, } from './types';
11
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,YAAY,EACV,uBAAuB,EACvB,UAAU,EACV,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,aAAa,EACb,aAAa,EACb,SAAS,EACT,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,EACb,MAAM,EACN,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,EAEL,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EAEzB,qBAAqB,EACrB,iBAAiB,EAEjB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,gBAAgB,EAEhB,yBAAyB,EACzB,+BAA+B,EAC/B,yBAAyB,EAEzB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAGhC,YAAY,EACV,aAAa,EACb,eAAe,EACf,WAAW,EACX,cAAc,EACd,UAAU,EACV,WAAW,EACX,UAAU,GACX,MAAM,wBAAwB,CAAC;AAGhC,YAAY,EACV,uBAAuB,EACvB,UAAU,EACV,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,aAAa,EACb,aAAa,EACb,SAAS,EACT,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,EACb,MAAM,EACN,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ The client may use and modify this code *only within the scope of the project it
7
7
  Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.BestPracticesValidator = exports.EmailTestAnalytics = exports.EmailTestPatterns = exports.testEmail = exports.EmailTestingSuite = void 0;
10
+ exports.assertAttachmentSize = exports.assertValidAttachment = exports.createMockAttachment = exports.assertHasMdnRequestHeader = exports.assertHasListUnsubscribeHeaders = exports.assertHasThreadingHeaders = exports.assertSuppressed = exports.assertSubscriptionActive = exports.createMockSubscriber = exports.createMockSubscriberList = exports.assertBatchResult = exports.createMockBatchEmails = exports.assertCalendarInviteEmail = exports.assertValidIcsContent = exports.createMockCalendarEvent = exports.BestPracticesValidator = exports.EmailTestAnalytics = exports.EmailTestPatterns = exports.testEmail = exports.EmailTestingSuite = void 0;
11
11
  /**
12
12
  * @bernierllc/email-testing-suite
13
13
  *
@@ -22,4 +22,26 @@ var analytics_1 = require("./analytics");
22
22
  Object.defineProperty(exports, "EmailTestAnalytics", { enumerable: true, get: function () { return analytics_1.EmailTestAnalytics; } });
23
23
  var best_practices_1 = require("./best-practices");
24
24
  Object.defineProperty(exports, "BestPracticesValidator", { enumerable: true, get: function () { return best_practices_1.BestPracticesValidator; } });
25
+ // Feature test helpers for calendar, batch, subscription, headers, attachments
26
+ var feature_test_helpers_1 = require("./feature-test-helpers");
27
+ // Calendar helpers
28
+ Object.defineProperty(exports, "createMockCalendarEvent", { enumerable: true, get: function () { return feature_test_helpers_1.createMockCalendarEvent; } });
29
+ Object.defineProperty(exports, "assertValidIcsContent", { enumerable: true, get: function () { return feature_test_helpers_1.assertValidIcsContent; } });
30
+ Object.defineProperty(exports, "assertCalendarInviteEmail", { enumerable: true, get: function () { return feature_test_helpers_1.assertCalendarInviteEmail; } });
31
+ // Batch helpers
32
+ Object.defineProperty(exports, "createMockBatchEmails", { enumerable: true, get: function () { return feature_test_helpers_1.createMockBatchEmails; } });
33
+ Object.defineProperty(exports, "assertBatchResult", { enumerable: true, get: function () { return feature_test_helpers_1.assertBatchResult; } });
34
+ // Subscription helpers
35
+ Object.defineProperty(exports, "createMockSubscriberList", { enumerable: true, get: function () { return feature_test_helpers_1.createMockSubscriberList; } });
36
+ Object.defineProperty(exports, "createMockSubscriber", { enumerable: true, get: function () { return feature_test_helpers_1.createMockSubscriber; } });
37
+ Object.defineProperty(exports, "assertSubscriptionActive", { enumerable: true, get: function () { return feature_test_helpers_1.assertSubscriptionActive; } });
38
+ Object.defineProperty(exports, "assertSuppressed", { enumerable: true, get: function () { return feature_test_helpers_1.assertSuppressed; } });
39
+ // Header helpers
40
+ Object.defineProperty(exports, "assertHasThreadingHeaders", { enumerable: true, get: function () { return feature_test_helpers_1.assertHasThreadingHeaders; } });
41
+ Object.defineProperty(exports, "assertHasListUnsubscribeHeaders", { enumerable: true, get: function () { return feature_test_helpers_1.assertHasListUnsubscribeHeaders; } });
42
+ Object.defineProperty(exports, "assertHasMdnRequestHeader", { enumerable: true, get: function () { return feature_test_helpers_1.assertHasMdnRequestHeader; } });
43
+ // Attachment helpers
44
+ Object.defineProperty(exports, "createMockAttachment", { enumerable: true, get: function () { return feature_test_helpers_1.createMockAttachment; } });
45
+ Object.defineProperty(exports, "assertValidAttachment", { enumerable: true, get: function () { return feature_test_helpers_1.assertValidAttachment; } });
46
+ Object.defineProperty(exports, "assertAttachmentSize", { enumerable: true, get: function () { return feature_test_helpers_1.assertAttachmentSize; } });
25
47
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;EAME;;;AAEF;;;;GAIG;AAEH,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,iDAA+D;AAAtD,0GAAA,SAAS,OAAA;AAAE,kHAAA,iBAAiB,OAAA;AACrC,yCAAiD;AAAxC,+GAAA,kBAAkB,OAAA;AAC3B,mDAA0D;AAAjD,wHAAA,sBAAsB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;EAME;;;AAEF;;;;GAIG;AAEH,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,iDAA+D;AAAtD,0GAAA,SAAS,OAAA;AAAE,kHAAA,iBAAiB,OAAA;AACrC,yCAAiD;AAAxC,+GAAA,kBAAkB,OAAA;AAC3B,mDAA0D;AAAjD,wHAAA,sBAAsB,OAAA;AAE/B,+EAA+E;AAC/E,+DAqBgC;AApB9B,mBAAmB;AACnB,+HAAA,uBAAuB,OAAA;AACvB,6HAAA,qBAAqB,OAAA;AACrB,iIAAA,yBAAyB,OAAA;AACzB,gBAAgB;AAChB,6HAAA,qBAAqB,OAAA;AACrB,yHAAA,iBAAiB,OAAA;AACjB,uBAAuB;AACvB,gIAAA,wBAAwB,OAAA;AACxB,4HAAA,oBAAoB,OAAA;AACpB,gIAAA,wBAAwB,OAAA;AACxB,wHAAA,gBAAgB,OAAA;AAChB,iBAAiB;AACjB,iIAAA,yBAAyB,OAAA;AACzB,uIAAA,+BAA+B,OAAA;AAC/B,iIAAA,yBAAyB,OAAA;AACzB,qBAAqB;AACrB,4HAAA,oBAAoB,OAAA;AACpB,6HAAA,qBAAqB,OAAA;AACrB,4HAAA,oBAAoB,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bernierllc/email-testing-suite",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Complete email testing solution with opinionated defaults, pre-configured test patterns, integrated mock server, and comprehensive reporting",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,16 +9,6 @@
9
9
  "README.md",
10
10
  "LICENSE"
11
11
  ],
12
- "scripts": {
13
- "build": "tsc",
14
- "dev": "tsc --watch",
15
- "test": "jest",
16
- "test:watch": "jest --watch",
17
- "test:coverage": "jest --coverage",
18
- "test:run": "jest --passWithNoTests",
19
- "lint": "eslint src/**/*.ts",
20
- "clean": "rimraf dist"
21
- },
22
12
  "keywords": [
23
13
  "email",
24
14
  "testing",
@@ -39,18 +29,18 @@
39
29
  "directory": "packages/suite/email-testing-suite"
40
30
  },
41
31
  "dependencies": {
42
- "@bernierllc/email-capture": "1.0.3",
43
- "@bernierllc/email-parser": "0.3.0",
44
- "@bernierllc/email-sender": "5.0.0",
45
- "@bernierllc/email-test-assertions": "1.2.0",
46
- "@bernierllc/email-test-orchestrator": "0.3.0",
47
- "@bernierllc/email-validator": "3.0.0",
48
- "@bernierllc/logger": "1.3.0",
49
- "@bernierllc/mock-smtp-server": "1.2.0",
50
- "@bernierllc/retry-policy": "0.3.0",
51
- "@bernierllc/smtp-analyzer": "0.3.0",
52
- "@bernierllc/template-engine": "0.4.0",
53
- "@bernierllc/template-validator": "1.2.0"
32
+ "@bernierllc/email-capture": "1.0.5",
33
+ "@bernierllc/email-parser": "0.4.1",
34
+ "@bernierllc/email-sender": "5.2.0",
35
+ "@bernierllc/email-test-assertions": "1.2.2",
36
+ "@bernierllc/email-test-orchestrator": "0.3.2",
37
+ "@bernierllc/email-validator": "3.0.2",
38
+ "@bernierllc/logger": "1.3.2",
39
+ "@bernierllc/mock-smtp-server": "1.2.2",
40
+ "@bernierllc/retry-policy": "0.3.2",
41
+ "@bernierllc/template-engine": "0.4.2",
42
+ "@bernierllc/template-validator": "1.2.2",
43
+ "@bernierllc/smtp-analyzer": "0.3.2"
54
44
  },
55
45
  "devDependencies": {
56
46
  "@types/jest": "^29.5.5",
@@ -68,5 +58,14 @@
68
58
  "access": "public",
69
59
  "registry": "https://registry.npmjs.org/"
70
60
  },
71
- "gitHead": "af7e74b3715d56d3a193e1bb6743b337c2b0df6d"
72
- }
61
+ "scripts": {
62
+ "build": "tsc",
63
+ "dev": "tsc --watch",
64
+ "test": "jest",
65
+ "test:watch": "jest --watch",
66
+ "test:coverage": "jest --coverage",
67
+ "test:run": "jest --passWithNoTests",
68
+ "lint": "eslint src/**/*.ts",
69
+ "clean": "rimraf dist"
70
+ }
71
+ }