@bernierllc/email-testing-suite 0.1.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 Bernier LLC
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,347 @@
1
+ # @bernierllc/email-testing-suite
2
+
3
+ Complete email testing solution with opinionated defaults and best practices.
4
+
5
+ ## Features
6
+
7
+ - **One-Command Setup** - Start testing emails with minimal configuration
8
+ - **Opinionated Defaults** - Pre-configured validations and best practices
9
+ - **Comprehensive Validation** - Template, compliance, accessibility, performance, and security checks
10
+ - **Advanced Analytics** - Track trends, identify issues, generate reports
11
+ - **Best Practices Enforcement** - Automatic validation against email standards
12
+ - **Integration Ready** - Works with Jest, Mocha, Vitest, and other test frameworks
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @bernierllc/email-testing-suite
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### One-Line Testing
23
+
24
+ The simplest way to test an email:
25
+
26
+ ```typescript
27
+ import { testEmail } from '@bernierllc/email-testing-suite';
28
+
29
+ const result = await testEmail({
30
+ template: './templates/welcome.html',
31
+ data: { name: 'John Doe', product: 'Pro Plan' },
32
+ recipient: 'test@example.com'
33
+ });
34
+
35
+ expect(result.success).toBe(true);
36
+ expect(result.score).toBeGreaterThan(90);
37
+ ```
38
+
39
+ ### Full Suite Usage
40
+
41
+ For more control and advanced features:
42
+
43
+ ```typescript
44
+ import { EmailTestingSuite } from '@bernierllc/email-testing-suite';
45
+
46
+ const suite = new EmailTestingSuite({
47
+ smtp: { port: 2525 },
48
+ defaults: { compliance: 'US', timeout: 30000 }
49
+ });
50
+
51
+ await suite.start();
52
+
53
+ const result = await suite.testEmailTemplate({
54
+ name: 'Welcome Email',
55
+ template: './templates/welcome.html',
56
+ data: { name: 'Jane Doe' },
57
+ recipients: ['test@example.com'],
58
+ expectations: {
59
+ delivery: true,
60
+ templateCompletion: true,
61
+ compliance: 'US',
62
+ accessibility: true,
63
+ performance: { renderTime: 2000, size: '100kb' }
64
+ }
65
+ });
66
+
67
+ await suite.stop();
68
+ ```
69
+
70
+ ## Configuration
71
+
72
+ ### Suite Configuration
73
+
74
+ ```typescript
75
+ interface EmailTestingSuiteConfig {
76
+ smtp?: {
77
+ port: number; // Default: 2525
78
+ host: string; // Default: 'localhost'
79
+ auth?: { user: string; pass: string; };
80
+ };
81
+
82
+ defaults?: {
83
+ compliance: 'US' | 'EU' | 'GLOBAL'; // Default: 'US'
84
+ timeout: number; // Default: 30000
85
+ retries: number; // Default: 3
86
+ expectations?: Partial<EmailExpectations>;
87
+ };
88
+
89
+ validation?: {
90
+ enabledValidators?: ValidatorType[]; // All enabled by default
91
+ strictMode?: boolean; // Default: false
92
+ customRules?: ValidationRule[]; // Custom validation rules
93
+ };
94
+
95
+ reporting?: {
96
+ enableAnalytics?: boolean; // Default: true
97
+ generateTrendReports?: boolean; // Default: true
98
+ exportFormats?: ReportFormat[]; // Default: ['json', 'html']
99
+ retainHistory?: number; // Days, default: 30
100
+ };
101
+ }
102
+ ```
103
+
104
+ ### Expectations
105
+
106
+ ```typescript
107
+ interface EmailExpectations {
108
+ delivery: boolean; // Email should be delivered
109
+ templateCompletion: boolean; // All variables resolved
110
+ compliance: 'US' | 'EU' | 'GLOBAL'; // Compliance standard
111
+ accessibility: boolean; // Accessibility validation
112
+ performance: {
113
+ renderTime?: number; // Max render time (ms)
114
+ size?: string; // Max email size (e.g., '100kb')
115
+ deliveryTime?: number; // Max delivery time (ms)
116
+ };
117
+ }
118
+ ```
119
+
120
+ ## Test Patterns
121
+
122
+ Pre-configured test patterns for common scenarios:
123
+
124
+ ### Welcome Email
125
+
126
+ ```typescript
127
+ import { EmailTestPatterns } from '@bernierllc/email-testing-suite';
128
+
129
+ const result = await EmailTestPatterns.testWelcomeEmail(
130
+ './templates/welcome.html',
131
+ { name: 'John Doe', email: 'john@example.com' }
132
+ );
133
+ ```
134
+
135
+ ### Password Reset Email
136
+
137
+ ```typescript
138
+ const result = await EmailTestPatterns.testPasswordResetEmail(
139
+ './templates/reset.html',
140
+ { email: 'user@example.com', resetLink: 'https://example.com/reset?token=abc' }
141
+ );
142
+ ```
143
+
144
+ ### Newsletter Email
145
+
146
+ ```typescript
147
+ const result = await EmailTestPatterns.testNewsletterEmail(
148
+ './templates/newsletter.html',
149
+ { title: 'Monthly Update', articles: [...] },
150
+ 'subscriber@example.com'
151
+ );
152
+ ```
153
+
154
+ ### Transactional Email
155
+
156
+ ```typescript
157
+ const result = await EmailTestPatterns.testTransactionalEmail(
158
+ './templates/order-confirmation.html',
159
+ { orderNumber: '12345', total: '$99.99' },
160
+ 'customer@example.com'
161
+ );
162
+ ```
163
+
164
+ ## Email Flow Testing
165
+
166
+ Test multi-step email workflows:
167
+
168
+ ```typescript
169
+ const flowResult = await suite.testEmailFlow({
170
+ name: 'User Onboarding Flow',
171
+ steps: [
172
+ { trigger: 'user.signup', template: 'welcome', delay: 0 },
173
+ { trigger: 'user.verify', template: 'verification', delay: 300000 },
174
+ { trigger: 'user.complete', template: 'onboarding', delay: 86400000 }
175
+ ],
176
+ assertions: [
177
+ { step: 1, assertion: 'delivered' },
178
+ { step: 2, assertion: 'contains_verification_link' },
179
+ { step: 3, assertion: 'personalized_content' }
180
+ ]
181
+ });
182
+ ```
183
+
184
+ ## Analytics
185
+
186
+ Track and analyze email testing performance:
187
+
188
+ ```typescript
189
+ import { EmailTestAnalytics } from '@bernierllc/email-testing-suite';
190
+
191
+ const analytics = new EmailTestAnalytics();
192
+
193
+ // Add test results
194
+ analytics.addTestResult(result);
195
+
196
+ // Generate analytics
197
+ const data = analytics.generateAnalytics('last_30_days');
198
+ console.log(`Success Rate: ${data.successRate}%`);
199
+ console.log(`Average Score: ${data.performanceMetrics.averageRenderTime}ms`);
200
+
201
+ // Export analytics
202
+ const json = analytics.exportAsJSON();
203
+ const csv = analytics.exportAsCSV();
204
+ ```
205
+
206
+ ## Best Practices
207
+
208
+ Get best practice recommendations:
209
+
210
+ ```typescript
211
+ import { BestPracticesValidator } from '@bernierllc/email-testing-suite';
212
+
213
+ // Validate email
214
+ const validation = BestPracticesValidator.validateEmail(emailData);
215
+ console.log(`Score: ${validation.score}`);
216
+ console.log(`Recommendations: ${validation.recommendations.length}`);
217
+
218
+ // Get compliance checklist
219
+ const checklist = BestPracticesValidator.getComplianceChecklist('US');
220
+
221
+ // Get accessibility guidelines
222
+ const guidelines = BestPracticesValidator.getAccessibilityGuidelines();
223
+
224
+ // Get performance tips
225
+ const tips = BestPracticesValidator.getPerformanceOptimizationTips();
226
+
227
+ // Get recommended coverage
228
+ const coverage = BestPracticesValidator.getRecommendedCoverage('marketing');
229
+ ```
230
+
231
+ ## Test Suite Execution
232
+
233
+ Run multiple tests together:
234
+
235
+ ```typescript
236
+ const tests = [
237
+ {
238
+ name: 'Welcome Email',
239
+ template: 'welcome.html',
240
+ data: { name: 'User 1' },
241
+ recipients: ['test1@example.com']
242
+ },
243
+ {
244
+ name: 'Newsletter',
245
+ template: 'newsletter.html',
246
+ data: { content: '...' },
247
+ recipients: ['test2@example.com']
248
+ }
249
+ ];
250
+
251
+ const suiteResult = await suite.runTestSuite(tests);
252
+
253
+ console.log(`Total: ${suiteResult.totalTests}`);
254
+ console.log(`Passed: ${suiteResult.passedTests}`);
255
+ console.log(`Failed: ${suiteResult.failedTests}`);
256
+ console.log(`Average Score: ${suiteResult.summary.averageScore}`);
257
+ ```
258
+
259
+ ## Jest Integration
260
+
261
+ ```typescript
262
+ describe('Email Templates', () => {
263
+ let suite: EmailTestingSuite;
264
+
265
+ beforeAll(async () => {
266
+ suite = new EmailTestingSuite({
267
+ smtp: { port: process.env.SMTP_PORT || 2525 },
268
+ defaults: { compliance: 'US', timeout: 30000 }
269
+ });
270
+ await suite.start();
271
+ });
272
+
273
+ afterAll(async () => {
274
+ await suite.stop();
275
+ });
276
+
277
+ test('welcome email passes validation', async () => {
278
+ const result = await suite.testEmailTemplate({
279
+ name: 'Welcome Email',
280
+ template: './templates/welcome.html',
281
+ data: { name: 'Test User' },
282
+ recipients: ['test@example.com']
283
+ });
284
+
285
+ expect(result.success).toBe(true);
286
+ expect(result.score).toBeGreaterThan(90);
287
+ });
288
+ });
289
+ ```
290
+
291
+ ## Data Generation
292
+
293
+ Generate test data from a schema:
294
+
295
+ ```typescript
296
+ const schema = {
297
+ name: { type: 'string', required: true },
298
+ email: { type: 'email', required: true },
299
+ age: { type: 'number', min: 18, max: 100 },
300
+ joinDate: { type: 'date' },
301
+ website: { type: 'url' },
302
+ userId: { type: 'uuid' }
303
+ };
304
+
305
+ const testData = suite.generateTestData(schema);
306
+ // Returns: { name: 'test-name', email: 'test-email@example.com', age: 18, ... }
307
+ ```
308
+
309
+ ## API Reference
310
+
311
+ ### EmailTestingSuite
312
+
313
+ - `constructor(config?: EmailTestingSuiteConfig)` - Create new suite instance
314
+ - `async start()` - Start the testing environment
315
+ - `async stop()` - Stop the testing environment
316
+ - `async reset()` - Reset captured emails and state
317
+ - `async testEmailTemplate(spec: EmailTemplateTest)` - Test an email template
318
+ - `async testEmailFlow(flow: EmailFlowTest)` - Test an email flow
319
+ - `async runTestSuite(tests: EmailTest[])` - Run multiple tests
320
+ - `getTestingEnvironment()` - Get current environment state
321
+ - `generateTestData(schema: DataSchema)` - Generate test data
322
+ - `getTestHistory()` - Get all test results
323
+ - `clearTestHistory()` - Clear test history
324
+
325
+ ### EmailTestAnalytics
326
+
327
+ - `addTestResult(result: EmailTestResult)` - Add single result
328
+ - `addTestResults(results: EmailTestResult[])` - Add multiple results
329
+ - `generateAnalytics(period: string)` - Generate analytics report
330
+ - `exportAsJSON(period?: string)` - Export as JSON
331
+ - `exportAsCSV(period?: string)` - Export as CSV
332
+ - `getTestHistory()` - Get all results
333
+ - `clearHistory()` - Clear history
334
+
335
+ ### BestPracticesValidator
336
+
337
+ - `static validateEmail(email: EmailData)` - Validate email against best practices
338
+ - `static getRecommendedCoverage(emailType: string)` - Get recommended validators
339
+ - `static getComplianceChecklist(region: 'US' | 'EU' | 'GLOBAL')` - Get compliance checklist
340
+ - `static getAccessibilityGuidelines()` - Get accessibility guidelines
341
+ - `static getPerformanceOptimizationTips()` - Get performance tips
342
+
343
+ ## License
344
+
345
+ Copyright (c) 2025 Bernier LLC
346
+
347
+ This file is licensed to the client under a limited-use license.
@@ -0,0 +1,52 @@
1
+ import type { EmailTestResult, AnalyticsData } from './types';
2
+ /**
3
+ * Analytics engine for email testing data
4
+ */
5
+ export declare class EmailTestAnalytics {
6
+ private testHistory;
7
+ /**
8
+ * Add test result to analytics history
9
+ */
10
+ addTestResult(result: EmailTestResult): void;
11
+ /**
12
+ * Add multiple test results
13
+ */
14
+ addTestResults(results: EmailTestResult[]): void;
15
+ /**
16
+ * Generate analytics for a given period
17
+ */
18
+ generateAnalytics(period?: string): AnalyticsData;
19
+ /**
20
+ * Filter test results by period
21
+ */
22
+ private filterByPeriod;
23
+ /**
24
+ * Calculate trend data
25
+ */
26
+ private calculateTrends;
27
+ /**
28
+ * Identify top issues from test results
29
+ */
30
+ private identifyTopIssues;
31
+ /**
32
+ * Calculate performance metrics
33
+ */
34
+ private calculatePerformanceMetrics;
35
+ /**
36
+ * Get test history
37
+ */
38
+ getTestHistory(): EmailTestResult[];
39
+ /**
40
+ * Clear analytics history
41
+ */
42
+ clearHistory(): void;
43
+ /**
44
+ * Export analytics data as JSON
45
+ */
46
+ exportAsJSON(period?: string): string;
47
+ /**
48
+ * Export analytics data as CSV
49
+ */
50
+ exportAsCSV(period?: string): string;
51
+ }
52
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EAId,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAyB;IAE5C;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IAI5C;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI;IAIhD;;OAEG;IACH,iBAAiB,CAAC,MAAM,GAAE,MAAuB,GAAG,aAAa;IAqBjE;;OAEG;IACH,OAAO,CAAC,cAAc;IAwBtB;;OAEG;IACH,OAAO,CAAC,eAAe;IA2BvB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiDzB;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAuBnC;;OAEG;IACH,cAAc,IAAI,eAAe,EAAE;IAInC;;OAEG;IACH,YAAY,IAAI,IAAI;IAIpB;;OAEG;IACH,YAAY,CAAC,MAAM,GAAE,MAAuB,GAAG,MAAM;IAKrD;;OAEG;IACH,WAAW,CAAC,MAAM,GAAE,MAAuB,GAAG,MAAM;CAoCrD"}
@@ -0,0 +1,211 @@
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.EmailTestAnalytics = void 0;
11
+ /**
12
+ * Analytics engine for email testing data
13
+ */
14
+ class EmailTestAnalytics {
15
+ testHistory = [];
16
+ /**
17
+ * Add test result to analytics history
18
+ */
19
+ addTestResult(result) {
20
+ this.testHistory.push(result);
21
+ }
22
+ /**
23
+ * Add multiple test results
24
+ */
25
+ addTestResults(results) {
26
+ this.testHistory.push(...results);
27
+ }
28
+ /**
29
+ * Generate analytics for a given period
30
+ */
31
+ generateAnalytics(period = 'last_30_days') {
32
+ const filteredResults = this.filterByPeriod(period);
33
+ const testCount = filteredResults.length;
34
+ const successCount = filteredResults.filter((r) => r.success).length;
35
+ const successRate = testCount > 0 ? (successCount / testCount) * 100 : 0;
36
+ const trends = this.calculateTrends(filteredResults);
37
+ const topIssues = this.identifyTopIssues(filteredResults);
38
+ const performanceMetrics = this.calculatePerformanceMetrics(filteredResults);
39
+ return {
40
+ period,
41
+ testCount,
42
+ successRate,
43
+ trends,
44
+ topIssues,
45
+ performanceMetrics,
46
+ };
47
+ }
48
+ /**
49
+ * Filter test results by period
50
+ */
51
+ filterByPeriod(period) {
52
+ const now = new Date();
53
+ let cutoffDate;
54
+ switch (period) {
55
+ case 'last_7_days':
56
+ cutoffDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
57
+ break;
58
+ case 'last_30_days':
59
+ cutoffDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
60
+ break;
61
+ case 'last_90_days':
62
+ cutoffDate = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);
63
+ break;
64
+ default:
65
+ cutoffDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
66
+ }
67
+ return this.testHistory.filter((result) => {
68
+ const resultDate = new Date(result.timestamp);
69
+ return resultDate >= cutoffDate;
70
+ });
71
+ }
72
+ /**
73
+ * Calculate trend data
74
+ */
75
+ calculateTrends(results) {
76
+ const trendMap = new Map();
77
+ for (const result of results) {
78
+ const date = new Date(result.timestamp).toISOString().split('T')[0];
79
+ if (!trendMap.has(date)) {
80
+ trendMap.set(date, {
81
+ date,
82
+ successRate: 0,
83
+ testCount: 0,
84
+ averageScore: 0,
85
+ });
86
+ }
87
+ const trend = trendMap.get(date);
88
+ trend.testCount++;
89
+ trend.averageScore = (trend.averageScore * (trend.testCount - 1) + result.score) / trend.testCount;
90
+ if (result.success) {
91
+ trend.successRate = ((trend.successRate * (trend.testCount - 1)) / trend.testCount) * 100;
92
+ }
93
+ }
94
+ return Array.from(trendMap.values()).sort((a, b) => a.date.localeCompare(b.date));
95
+ }
96
+ /**
97
+ * Identify top issues from test results
98
+ */
99
+ identifyTopIssues(results) {
100
+ const issueMap = new Map();
101
+ for (const result of results) {
102
+ if (result.errors && result.errors.length > 0) {
103
+ for (const error of result.errors) {
104
+ const key = error.substring(0, 100); // Normalize error message
105
+ if (!issueMap.has(key)) {
106
+ issueMap.set(key, {
107
+ issue: key,
108
+ count: 0,
109
+ severity: 'error',
110
+ });
111
+ }
112
+ const issue = issueMap.get(key);
113
+ issue.count++;
114
+ }
115
+ }
116
+ // Check validation warnings
117
+ if (result.validations) {
118
+ for (const validation of result.validations) {
119
+ if (validation.warnings && validation.warnings.length > 0) {
120
+ for (const warning of validation.warnings) {
121
+ const key = warning.substring(0, 100);
122
+ if (!issueMap.has(key)) {
123
+ issueMap.set(key, {
124
+ issue: key,
125
+ count: 0,
126
+ severity: 'warning',
127
+ });
128
+ }
129
+ const issue = issueMap.get(key);
130
+ issue.count++;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ return Array.from(issueMap.values())
137
+ .sort((a, b) => b.count - a.count)
138
+ .slice(0, 10);
139
+ }
140
+ /**
141
+ * Calculate performance metrics
142
+ */
143
+ calculatePerformanceMetrics(results) {
144
+ if (results.length === 0) {
145
+ return {
146
+ averageRenderTime: 0,
147
+ averageDeliveryTime: 0,
148
+ averageSize: 0,
149
+ };
150
+ }
151
+ const totalDuration = results.reduce((sum, r) => sum + r.duration, 0);
152
+ const averageRenderTime = totalDuration / results.length;
153
+ // Mock delivery time and size calculations
154
+ const averageDeliveryTime = averageRenderTime * 1.5;
155
+ const averageSize = 50000; // Mock value
156
+ return {
157
+ averageRenderTime,
158
+ averageDeliveryTime,
159
+ averageSize,
160
+ };
161
+ }
162
+ /**
163
+ * Get test history
164
+ */
165
+ getTestHistory() {
166
+ return [...this.testHistory];
167
+ }
168
+ /**
169
+ * Clear analytics history
170
+ */
171
+ clearHistory() {
172
+ this.testHistory = [];
173
+ }
174
+ /**
175
+ * Export analytics data as JSON
176
+ */
177
+ exportAsJSON(period = 'last_30_days') {
178
+ const analytics = this.generateAnalytics(period);
179
+ return JSON.stringify(analytics, null, 2);
180
+ }
181
+ /**
182
+ * Export analytics data as CSV
183
+ */
184
+ exportAsCSV(period = 'last_30_days') {
185
+ const analytics = this.generateAnalytics(period);
186
+ const lines = [];
187
+ // Header
188
+ lines.push('Metric,Value');
189
+ // Summary metrics
190
+ lines.push(`Test Count,${analytics.testCount}`);
191
+ lines.push(`Success Rate,${analytics.successRate.toFixed(2)}%`);
192
+ lines.push(`Average Render Time,${analytics.performanceMetrics.averageRenderTime.toFixed(2)}ms`);
193
+ lines.push(`Average Delivery Time,${analytics.performanceMetrics.averageDeliveryTime.toFixed(2)}ms`);
194
+ lines.push(`Average Size,${analytics.performanceMetrics.averageSize} bytes`);
195
+ // Trends
196
+ lines.push('');
197
+ lines.push('Date,Test Count,Success Rate,Average Score');
198
+ for (const trend of analytics.trends) {
199
+ lines.push(`${trend.date},${trend.testCount},${trend.successRate.toFixed(2)}%,${trend.averageScore.toFixed(2)}`);
200
+ }
201
+ // Top Issues
202
+ lines.push('');
203
+ lines.push('Issue,Count,Severity');
204
+ for (const issue of analytics.topIssues) {
205
+ lines.push(`"${issue.issue}",${issue.count},${issue.severity}`);
206
+ }
207
+ return lines.join('\n');
208
+ }
209
+ }
210
+ exports.EmailTestAnalytics = EmailTestAnalytics;
211
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { EmailData, Recommendation } from './types';
2
+ /**
3
+ * Best practices validator for email testing
4
+ */
5
+ export declare class BestPracticesValidator {
6
+ /**
7
+ * Validate email against best practices
8
+ */
9
+ static validateEmail(email: EmailData): {
10
+ passed: boolean;
11
+ score: number;
12
+ recommendations: Recommendation[];
13
+ };
14
+ /**
15
+ * Get recommended test coverage for email type
16
+ */
17
+ static getRecommendedCoverage(emailType: string): {
18
+ validators: string[];
19
+ description: string;
20
+ };
21
+ /**
22
+ * Generate compliance checklist
23
+ */
24
+ static getComplianceChecklist(region: 'US' | 'EU' | 'GLOBAL'): string[];
25
+ /**
26
+ * Get accessibility guidelines
27
+ */
28
+ static getAccessibilityGuidelines(): Recommendation[];
29
+ /**
30
+ * Get performance optimization tips
31
+ */
32
+ static getPerformanceOptimizationTips(): Recommendation[];
33
+ }
34
+ //# sourceMappingURL=best-practices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"best-practices.d.ts","sourceRoot":"","sources":["../src/best-practices.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzD;;GAEG;AACH,qBAAa,sBAAsB;IACjC;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG;QACtC,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,eAAe,EAAE,cAAc,EAAE,CAAC;KACnC;IA4HD;;OAEG;IACH,MAAM,CAAC,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG;QAChD,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;KACrB;IA8BD;;OAEG;IACH,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,QAAQ,GAAG,MAAM,EAAE;IA4BvE;;OAEG;IACH,MAAM,CAAC,0BAA0B,IAAI,cAAc,EAAE;IAwCrD;;OAEG;IACH,MAAM,CAAC,8BAA8B,IAAI,cAAc,EAAE;CAuC1D"}