UNPKG

@bhavinkumarvegad/playwright-email-utils

Version:

Reusable utilities for handling emails in Playwright tests from Yopmail, Gmail and other providers.

187 lines (162 loc) 5.76 kB
import { google } from 'googleapis'; import { EmailQuery, EmailExtractionRule } from '../types'; import { EmailBodyParser } from '../utils/emailBodyParser'; export interface GmailMessage { id?: string; raw?: string; headers?: Array<{ name: string; value: string; }>; labelIds?: string[]; snippet?: string; body?: string; subject?: string; from?: string; to?: string; } interface GmailConfig { clientId: string; clientSecret: string; refreshToken: string; redirectUri?: string; } async function getOAuth2Client(config: GmailConfig) { if (!config.refreshToken) { throw new Error('GMAIL_REFRESH_TOKEN is required in your configuration.'); } const oAuth2Client = new google.auth.OAuth2( config.clientId, config.clientSecret, config.redirectUri || 'http://localhost' ); oAuth2Client.setCredentials({ refresh_token: config.refreshToken }); return oAuth2Client; } async function getGmail(config: GmailConfig) { const auth = await getOAuth2Client(config); return google.gmail({ version: 'v1', auth }); } async function listMessages(config: GmailConfig, query: string): Promise<GmailMessage[]> { const gmail = await getGmail(config); const res = await gmail.users.messages.list({ userId: 'me', q: query, }); return (res.data.messages || []).map(msg => ({ id: msg.id || undefined, labelIds: msg.labelIds || undefined })); } async function getMessage(config: GmailConfig, msgId: string): Promise<GmailMessage> { const gmail = await getGmail(config); const res = await gmail.users.messages.get({ userId: 'me', id: msgId, format: 'full', }); const headers = res.data.payload?.headers?.map(h => ({ name: h.name || '', value: h.value || '' })) || []; const subject = headers.find(h => h.name.toLowerCase() === 'subject')?.value; const from = headers.find(h => h.name.toLowerCase() === 'from')?.value; const to = headers.find(h => h.name.toLowerCase() === 'to')?.value; let body = ''; if (res.data.payload?.body?.data) { body = Buffer.from(res.data.payload.body.data, 'base64').toString('utf8'); } else if (res.data.payload?.parts) { const textPart = res.data.payload.parts.find(part => part.mimeType === 'text/plain'); if (textPart?.body?.data) { body = Buffer.from(textPart.body.data, 'base64').toString('utf8'); } } return { id: res.data.id || undefined, headers, labelIds: res.data.labelIds || undefined, snippet: res.data.snippet || undefined, body, subject, from, to }; } export async function fromGmail(config: GmailConfig) { return { findEmail: async ({ subject, from, to, afterTime, beforeTime }: EmailQuery): Promise<GmailMessage | null> => { let query = 'label:inbox'; if (subject) query += ` subject:\"${subject}\"`; if (from) query += ` from:${from}`; if (to) query += ` to:${to}`; if (afterTime) { const timestamp = Math.floor(new Date(afterTime).getTime() / 1000); query += ` after:${timestamp}`; } if (beforeTime) { const timestamp = Math.floor(new Date(beforeTime).getTime() / 1000); query += ` before:${timestamp}`; } const messages = await listMessages(config, query); if (!messages.length || !messages[0].id) return null; return getMessage(config, messages[0].id); }, findEmailWithDetails: async ( config: GmailConfig, query: EmailQuery, extractionRules: EmailExtractionRule[] ): Promise<{ email: GmailMessage | null; extractedDetails: Record<string, string | null> }> => { const email = await findEmail(config, query); if (!email) { return { email: null, extractedDetails: {} }; } const extractedDetails: Record<string, string | null> = {}; for (const rule of extractionRules) { extractedDetails[rule.field] = EmailBodyParser.extractInfo(email, { type: rule.type, startMarker: rule.startMarker, endMarker: rule.endMarker, regex: rule.regex, }); } return { email, extractedDetails }; } }; } export async function findEmail(config: GmailConfig, { subject, from, to, afterTime, beforeTime }: EmailQuery): Promise<GmailMessage | null> { let query = 'label:inbox'; if (subject) query += ` subject:\"${subject}\"`; if (from) query += ` from:${from}`; if (to) query += ` to:${to}`; if (afterTime) { const timestamp = Math.floor(new Date(afterTime).getTime() / 1000); query += ` after:${timestamp}`; } if (beforeTime) { const timestamp = Math.floor(new Date(beforeTime).getTime() / 1000); query += ` before:${timestamp}`; } const messages = await listMessages(config, query); if (!messages.length || !messages[0].id) return null; return getMessage(config, messages[0].id); } export async function findEmailWithDetails( config: GmailConfig, query: EmailQuery, extractionRules: EmailExtractionRule[] ): Promise<{ email: GmailMessage | null; extractedDetails: Record<string, string | null> }> { const email = await findEmail(config, query); if (!email) { return { email: null, extractedDetails: {} }; } const extractedDetails: Record<string, string | null> = {}; for (const rule of extractionRules) { extractedDetails[rule.field] = EmailBodyParser.extractInfo(email, { type: rule.type, startMarker: rule.startMarker, endMarker: rule.endMarker, regex: rule.regex, }); } return { email, extractedDetails }; }