///
/**
* Test Pattern: Email Pattern Launcher
*
* Tests the EmailPatternLauncher pattern behavior:
* - Initial state (empty matches, count 0)
* - Email pattern matching logic
* - Gmail query construction
* - Output structure
*
* Note: Since this pattern depends on Gmail API calls and pattern compilation,
* we focus on testing the helper functions and initial state.
*
* Run: deno task ct test packages/patterns/google/extractors/email-pattern-launcher.test.tsx --root packages/patterns/google --verbose
*/
import { computed, pattern } from "commontools";
// =============================================================================
// HELPER FUNCTIONS (duplicated for testing - same as in main pattern)
// =============================================================================
/**
* Check if an email address matches a glob pattern.
* Supports wildcards: "*@domain.com" matches any email at that domain.
*/
function matchesEmailPattern(email: string, patternStr: string): boolean {
if (!email || !patternStr) return false;
const emailLower = email.toLowerCase();
const patternLower = patternStr.toLowerCase();
// Convert glob pattern to regex
// * matches anything before @, and @ and . are literal
const regexPattern = patternLower
.replace(/[.+^${}()|[\]\\]/g, "\\$&") // Escape special regex chars except *
.replace(/\*/g, ".*"); // Convert * to .*
const regex = new RegExp(`^${regexPattern}$`, "i");
return regex.test(emailLower);
}
interface RegistryEntry {
patternUri: string;
emailPatterns: string[];
}
/**
* Build Gmail query from email patterns.
* Converts ["*@usps.com", "*@library.org"] to "from:@usps.com OR from:@library.org"
*/
function buildGmailQuery(entries: RegistryEntry[]): string {
const domains = new Set();
for (const entry of entries) {
for (const emailPattern of entry.emailPatterns) {
// Extract domain from pattern like "*@domain.com"
const atIndex = emailPattern.indexOf("@");
if (atIndex !== -1) {
const domain = emailPattern.substring(atIndex); // includes @
domains.add(domain);
}
}
}
if (domains.size === 0) return "in:INBOX";
// Build "from:@domain1 OR from:@domain2 ..." query
const parts = Array.from(domains).map((domain) => `from:${domain}`);
return parts.join(" OR ");
}
// =============================================================================
// TEST PATTERN
// =============================================================================
export default pattern(() => {
// ==========================================================================
// Email Pattern Matching Tests
// ==========================================================================
// Test: wildcard pattern matches any email at domain
const assert_wildcard_matches_domain = computed(() => {
return matchesEmailPattern(
"notices@library.berkeleypubliclibrary.org",
"*@library.berkeleypubliclibrary.org",
);
});
// Test: wildcard pattern matches different usernames
const assert_wildcard_matches_different_user = computed(() => {
return matchesEmailPattern(
"info@library.berkeleypubliclibrary.org",
"*@library.berkeleypubliclibrary.org",
);
});
// Test: pattern should not match different domain
const assert_no_match_different_domain = computed(() => {
return !matchesEmailPattern(
"notices@library.sfpl.org",
"*@library.berkeleypubliclibrary.org",
);
});
// Test: USPS pattern matching
const assert_usps_pattern_matches = computed(() => {
return matchesEmailPattern(
"USPSInformeddelivery@email.informeddelivery.usps.com",
"*@email.informeddelivery.usps.com",
);
});
// Test: case insensitive matching
const assert_case_insensitive = computed(() => {
return matchesEmailPattern(
"NOTICES@LIBRARY.BERKELEYPUBLICLIBRARY.ORG",
"*@library.berkeleypubliclibrary.org",
);
});
// Test: empty email returns false
const assert_empty_email_false = computed(() => {
return !matchesEmailPattern("", "*@domain.com");
});
// Test: empty pattern returns false
const assert_empty_pattern_false = computed(() => {
return !matchesEmailPattern("user@domain.com", "");
});
// ==========================================================================
// Gmail Query Construction Tests
// ==========================================================================
// Test: build query from single entry
const assert_single_entry_query = computed(() => {
const entries: RegistryEntry[] = [
{
patternUri: "google/test.tsx",
emailPatterns: ["*@example.com"],
},
];
const query = buildGmailQuery(entries);
return query === "from:@example.com";
});
// Test: build query from multiple entries
const assert_multiple_entries_query = computed(() => {
const entries: RegistryEntry[] = [
{
patternUri: "google/usps.tsx",
emailPatterns: ["*@usps.com", "*@informeddelivery.usps.com"],
},
{
patternUri: "google/library.tsx",
emailPatterns: ["*@library.berkeleypubliclibrary.org"],
},
];
const query = buildGmailQuery(entries);
// Should contain all domains with OR
return query.includes("from:@usps.com") &&
query.includes("from:@informeddelivery.usps.com") &&
query.includes("from:@library.berkeleypubliclibrary.org") &&
query.includes(" OR ");
});
// Test: empty entries returns default query
const assert_empty_entries_default = computed(() => {
const query = buildGmailQuery([]);
return query === "in:INBOX";
});
// Test: deduplicates domains
const assert_deduplicates_domains = computed(() => {
const entries: RegistryEntry[] = [
{
patternUri: "google/pattern1.tsx",
emailPatterns: ["*@example.com"],
},
{
patternUri: "google/pattern2.tsx",
emailPatterns: ["*@example.com"], // Same domain
},
];
const query = buildGmailQuery(entries);
// Should only have one @example.com
const matches = query.match(/@example\.com/g);
return matches?.length === 1;
});
// ==========================================================================
// Test Sequence
// ==========================================================================
return {
tests: [
// === Email pattern matching ===
{ assertion: assert_wildcard_matches_domain },
{ assertion: assert_wildcard_matches_different_user },
{ assertion: assert_no_match_different_domain },
{ assertion: assert_usps_pattern_matches },
{ assertion: assert_case_insensitive },
{ assertion: assert_empty_email_false },
{ assertion: assert_empty_pattern_false },
// === Gmail query construction ===
{ assertion: assert_single_entry_query },
{ assertion: assert_multiple_entries_query },
{ assertion: assert_empty_entries_default },
{ assertion: assert_deduplicates_domains },
],
};
});