-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathMailinatorService.ts
More file actions
129 lines (105 loc) · 4.61 KB
/
MailinatorService.ts
File metadata and controls
129 lines (105 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { BrowserContext, Page, expect } from '@playwright/test';
import { EmailAddress, EmailContent, EmailHeader, EmailService } from './EmailService';
export class MailinatorService extends EmailService {
context: BrowserContext;
constructor(context: BrowserContext) {
super();
this.context = context;
}
generateEmailAddress(): EmailAddress {
const randomString = this.randomString(10)
return `test+${randomString}@mailinator.com`;
}
// Action functions
async getInbox(emailAddress: EmailAddress): Promise<EmailHeader[]> {
const mailinatorURL = this.buildMailinatorURLToInbox(emailAddress)
const mailinatorPage = await this.openNewPage(mailinatorURL)
// Wait for email rows to load
const rows = mailinatorPage.locator(this.SELECTORS.inbox.emailRow);
const rowCount = await rows.count();
console.log(`Found ${rowCount} email(s) in the inbox.`);
const fromSelector = this.SELECTORS.inbox.cells.from;
const subjectSelector = this.SELECTORS.inbox.cells.subject;
const inboxEntries: EmailHeader[] = await rows.evaluateAll(
(rows, { emailAddress, fromSelector, subjectSelector }) => {
const entries: EmailHeader[] = [];
for (const row of rows) {
const fullRowId = row.getAttribute("id") || ""; // e.g., 'row_test+2f4e8guu-1734141721-9052847012'
const extractedId = fullRowId.split("-").slice(-2).join("-"); // just the ID portion: 1734141721-9052847012
entries.push({
id: extractedId,
to: emailAddress,
from: row.querySelector(fromSelector)?.textContent?.trim() || "",
subject: row.querySelector(subjectSelector)?.textContent?.trim() || "",
});
}
return entries;
},
{ emailAddress, fromSelector, subjectSelector }
);
await mailinatorPage.close()
return inboxEntries;
}
async getEmailContent(emailHeader: EmailHeader): Promise<EmailContent> {
const directEmailURL = this.buildMailinatorURLToEmail(emailHeader)
const emailPage = await this.openNewPage(directEmailURL)
await emailPage.waitForSelector(this.SELECTORS.email.iframe);
const iframe = emailPage.frame({ name: this.SELECTORS.email.iframeName });
const text = await iframe?.textContent(this.SELECTORS.email.body) || '';
const html = await iframe?.evaluate(() => document.body.innerHTML) || '';
await emailPage.close()
return { text, html, emailHeader };
}
async waitForEmailWithSubject(emailAddress: EmailAddress, subjectSubstring: string): Promise<EmailContent> {
const mailinatorURL = this.buildMailinatorURLToInbox(emailAddress)
const mailinatorPage = await this.openNewPage(mailinatorURL)
const matchingEmail = mailinatorPage
.locator(this.SELECTORS.inbox.emailRowTR)
.filter({ hasText: subjectSubstring })
.first();
await matchingEmail.waitFor();
const idAttribute = await matchingEmail.getAttribute("id");
expect(idAttribute, "Email row missing required ID attribute").not.toBeNull();
const emailHeaderId = idAttribute!.split("-").slice(-2).join("-");
const emailHeader: EmailHeader = {
id: emailHeaderId,
to: emailAddress,
from: await matchingEmail.locator("td:nth-of-type(2)").innerText(),
subject: await matchingEmail.locator("td:nth-of-type(3)").innerText(),
};
return this.getEmailContent(emailHeader);
}
private static readonly MAILINATOR_BASE_URL = 'https://www.mailinator.com/v4/public/inboxes.jsp';
private readonly SELECTORS = {
inbox: {
emailRow: '[ng-repeat="email in emails"]',
emailRowTR: "tr[ng-repeat='email in emails']",
cells: {
from: 'td:nth-of-type(2)',
subject: 'td:nth-of-type(3)',
}
},
email: {
iframe: 'iframe[name="html_msg_body"]',
iframeName: 'html_msg_body',
body: 'body',
},
};
// Helpers
private buildMailinatorURLToEmail(emailHeader: EmailHeader): string {
const encodedEmailPrefix = this.getEncodedEmailPrefix(emailHeader.to);
return `${MailinatorService.MAILINATOR_BASE_URL}?msgid=${encodedEmailPrefix}-${emailHeader.id}`;
}
private buildMailinatorURLToInbox(emailAddress: string): string {
const encodedEmailPrefix = this.getEncodedEmailPrefix(emailAddress);
return `${MailinatorService.MAILINATOR_BASE_URL}?to=${encodedEmailPrefix}`;
}
private getEncodedEmailPrefix(emailAddress: string): string {
return encodeURIComponent(emailAddress.split('@')[0]);
}
private async openNewPage(url: string): Promise<Page> {
const page = await this.context.newPage();
await page.goto(url);
return page;
}
}