Test Runner
Unit tests & end-to-end flow tests
Unit Tests: 1 failed
293 passed, 1 failed, 294 total ยท Click to jump to first failure
City match: host in same city matches
City match: host in different city does not match
Guest capacity: host with enough space matches
Guest capacity: host with too few spaces does not match
Sleeping needed: full_shabbat host matches
Sleeping needed: both type host matches
Sleeping needed: meals_only host does not match
Sleeping not needed: meals_only host matches
English level: host with "any" matches all requests
English level: fluent host matches intermediate request
English level: basic host does not match fluent request
English level: intermediate host matches intermediate request
Religious level: matching observance matches
Religious level: non-matching observance does not match
Religious level: "any" request matches all hosts
Religious level: empty request matches all hosts
Neighborhood: matching neighborhood matches
Neighborhood: host with no neighborhood matches any request
Neighborhood: fallback when no neighborhood matches
Multiple cities: matches hosts in all requested cities
Combined filters: all conditions must be met
Guest capacity: exactly equal (max_guests === guest_count)
Guest capacity: one over capacity does not match
Guest capacity: undefined max_guests falls back to 4
English level: basic host exactly matches basic request (level 1)
English level: host with null english_level matches all requests
Religious level: host with null religious_observance matches all requests
English proficiency: integer host level 3 matches intermediate request
English proficiency: integer host level 1 does not match fluent request
English proficiency: integer host level 3 matches fluent request
Saturday: cutoff is today at 16:00
Saturday evening: cutoff is today at 16:00
Sunday: cutoff is previous Saturday at 16:00
Friday: cutoff is previous Saturday at 16:00
Monday: cutoff is 2 days ago (Saturday) at 16:00
isRequestExpired: open request before cutoff is expired
isRequestExpired: open request after cutoff is not expired
isRequestExpired: claimed request is never expired
isRequestExpired: fulfilled request is never expired
isRequestExpired: uses current time when no cutoff provided
isRequestExpired: request exactly at cutoff is not expired
isRequestExpired: request one second before cutoff is expired
isRequestExpired: request one second after cutoff is not expired
Thursday: cutoff is previous Saturday at 16:00
getRequestSummary: no meals, no sleeping
getRequestSummary: one meal
getRequestSummary: all meals
getRequestSummary: meals + sleeping
getRequestDisplay: returns meals array and sleeping flag
getRequestDisplay: no meals, no sleeping
validateStudentRequest: valid request returns null
validateStudentRequest: missing name
validateStudentRequest: missing email
validateStudentRequest: invalid email
validateStudentRequest: missing city
validateStudentRequest: missing meals
validateStudentRequest: guest_count 0 is invalid
validateStudentRequest: multiple missing fields
validateStudentRequest: guest_count = 1 is valid
validateStudentRequest: negative guest_count is invalid
validateStudentRequest: email with multiple @ signs is invalid
getRequestSummary: only sleeping, no meals
Host notification email: contains host family name
Host notification email: contains student name in greeting
Host notification email: contains city
Host notification email: contains meal summary
Host notification email: contains sleeping note
Host notification email: contains institution name
Host notification email: contains student name
Host notification email: contains guest count
Host notification email: contains dashboard link
Host notification email: includes profile photo when present
Host notification email: excludes profile photo section when absent
Student claimed email: contains student name
Student claimed email: contains host family name
Student claimed email: contains host city
Student claimed email: contains gift tip
WhatsApp message: encoded and contains host name
WhatsApp message: contains meal summary
WhatsApp message: contains dashboard URL
WhatsApp link: generates valid wa.me link
WhatsApp link: returns null when no whatsapp number
createPageUrl: Home โ /Home
createPageUrl: StudentDashboard โ /StudentDashboard
createPageUrl: HostDashboard โ /HostDashboard
createPageUrl: replaces spaces with dashes
createPageUrl: always starts with /
createPageUrl: handles empty string
createPageUrl: single character
createPageUrl: alphanumeric characters
deriveHostFromApplication: maps all fields correctly
deriveHostFromApplication: defaults empty neighborhood to empty string
deriveHostFromApplication: defaults empty whatsapp to empty string
deriveHostFromApplication: defaults empty profile_photo to empty string
getWelcomeEmailSubject: returns correct subject
getWelcomeEmailHtml: contains family name
getWelcomeEmailHtml: contains city
getWelcomeEmailHtml: contains dashboard link
getAdminNotificationEmailHtml: contains family name
getAdminNotificationEmailHtml: contains email
getAdminNotificationEmailHtml: contains city
getAdminNotificationEmailHtml: includes phone when present
getAdminNotificationEmailHtml: excludes phone when absent
validateHostApplicationForm: valid form returns null
validateHostApplicationForm: missing family name
validateHostApplicationForm: missing email
validateHostApplicationForm: invalid email format
validateHostApplicationForm: missing city
validateHostApplicationForm: missing whatsapp
validateHostApplicationForm: missing religious observance
validateHostApplicationForm: missing how_heard_about_us
validateHostApplicationForm: how_heard_about_us too short
getWelcomeEmailTrackingPayload: correct structure
getAdminNotificationEmailTrackingPayload: correct structure
parseEmailRecipients: splits comma-separated emails
parseEmailRecipients: splits newline-separated emails
parseEmailRecipients: handles mixed comma and newline
parseEmailRecipients: trims whitespace
parseEmailRecipients: filters empty entries
parseEmailRecipients: empty string returns empty array
parseEmailRecipients: null returns empty array
getHostRegistrationLink: contains ref__=host param
getManageHostsRegistrationLink: returns hardcoded URL
getHostWelcomeTemplate: returns subject and body
getHostWelcomeTemplate: body contains registration link
getHostNotificationTemplate: returns subject with CITY placeholder
getHostNotificationTemplate: body contains dashboard link
getStudentClaimedTemplate: returns subject with matched
getStudentClaimedTemplate: body contains placeholders
getCustomEmailTrackingPayload: correct structure
validateCustomEmail: valid input returns null
validateCustomEmail: missing email list
validateCustomEmail: missing subject
validateCustomEmail: missing body
getStudentEmails: filters students and both types
getHostEmails: extracts all host emails
getAllUserEmails: extracts all user emails
validateSupportForm: valid form returns null
validateSupportForm: missing name
validateSupportForm: missing email
validateSupportForm: invalid email format
validateSupportForm: missing subject
validateSupportForm: missing message
createSupportEmailBody: contains sender name
createSupportEmailBody: contains sender email
createSupportEmailBody: contains subject
createSupportEmailBody: contains message
getSupportEmailSubject: prefixes with [Support]
getSupportRequestPayload: correct structure with status new
getNextSupportStatus: new can go to in_progress or resolved
getNextSupportStatus: in_progress can go to resolved
getNextSupportStatus: resolved has no transitions
isValidSupportStatusTransition: new โ in_progress is valid
isValidSupportStatusTransition: new โ resolved is valid
isValidSupportStatusTransition: in_progress โ resolved is valid
isValidSupportStatusTransition: resolved โ new is invalid
isValidSupportStatusTransition: in_progress โ new is invalid
escapeCsvValue: plain value returns as-is
escapeCsvValue: value with comma is quoted
escapeCsvValue: value with quote is escaped and quoted
escapeCsvValue: value with newline is quoted
escapeCsvValue: null returns empty string
escapeCsvValue: undefined returns empty string
escapeCsvValue: number is converted to string
objectsToCsv: empty array returns empty string
objectsToCsv: generates header row
objectsToCsv: generates data rows
objectsToCsv: escapes values with commas
mapHostToCsvRow: maps all fields
mapHostToCsvRow: defaults empty neighborhood
generateHostsCsv: produces valid CSV with headers
generateHostsCsv: handles values with commas
mapEmailToCsvRow: maps all fields
generateEmailTrackingCsv: produces valid CSV with headers
getUnclaimPayload: returns open status with nulls
getCancelPayload: returns expired status
getMarkCompletedPayload: returns fulfilled status
getCancelConfirmMessage: claimed status mentions host family
getCancelConfirmMessage: open status mentions cannot be undone
getUnclaimConfirmMessage: mentions available for other families
getMarkCompletedConfirmMessage: mentions completed
getHostingTypeDisplay: all meals + sleeping
getHostingTypeDisplay: no meals selected
getHostingTypeDisplay: only sleeping
getHostingTypeDisplay: only one meal
filterMyRequests: returns only requests for given email
filterMyRequests: returns empty for non-matching email
isExpiredOrCanceled: true for expired status
isExpiredOrCanceled: false for claimed status
isExpiredOrCanceled: false for fulfilled status
isUpcomingRequest: true for claimed with future date
isUpcomingRequest: false for fulfilled
isUpcomingRequest: false for expired
isUpcomingRequest: false for past date
isUpcomingRequest: true for open with future date
isUpcomingRequest: no date + recent created โ upcoming
Expected true
isUpcomingRequest: no date + old created โ not upcoming
partitionRequests: splits upcoming and previous
filterHideExpired: hides expired when toggle on
filterHideExpired: shows all when toggle off
validateStudentRegistrationForm: valid form returns null
validateStudentRegistrationForm: missing code
validateStudentRegistrationForm: missing phone
validateStudentRegistrationForm: missing gender
computeStudentUserType: with hosts returns "both"
computeStudentUserType: without hosts returns "student"
getStudentRegistrationPayload: correct structure
validateEditProfileForm: valid form returns null
validateEditProfileForm: missing phone
getEditProfilePayload: correct structure
validatePhotoFile: null returns error
validatePhotoFile: non-image type returns error
validatePhotoFile: too large returns error
validatePhotoFile: valid image returns null
filterStudentsBySearch: matches name (case-insensitive)
filterStudentsBySearch: matches email
filterStudentsBySearch: empty search returns all
filterStudentsBySearch: null search returns all
filterStudentsBySearch: no match returns empty
filterStudentsByInstitution: filters by institution ID
filterStudentsByInstitution: empty ID returns all
filterStudentsByInstitution: null ID returns all
applyStudentFilters: combines search and institution
applyStudentFilters: only search filter
applyStudentFilters: only institution filter
applyStudentFilters: no filters returns all
getRegisteredStudents: filters users with institution_id
Outbound: rejects missing to field
Outbound: rejects empty to field
Outbound: rejects to without whatsapp: prefix
Outbound: accepts valid whatsapp: prefixed number
Outbound: rejects empty body
Outbound: rejects null body
Outbound: accepts non-empty body
Phone extraction: strips whatsapp: prefix and non-digits
Phone extraction: handles plain number with dashes
Phone extraction: handles number with spaces
Phone extraction: returns empty for null
Phone extraction: returns empty for empty string
Phone matching: matches when record contains exact digits
Phone matching: matches with spaces in record number
Phone matching: matches with leading zeros in record number
Phone matching: does not match different number
Phone matching: returns false for empty digits
Phone matching: returns false for empty record phone
Phone matching: returns false for null record phone
Reminders: fulfilled request gets no host reminder
Reminders: fulfilled request gets no student reminder
Reminders: expired request gets no host reminder
Reminders: expired request gets no student reminder
Reminders: open request gets no host reminder
Reminders: open request gets no student reminder
Reminders: claimed in window, not reached out โ host reminder
Reminders: claimed in window, not reached out โ student reminder
Reminders: host_reached_out=true โ no host reminder
Reminders: host_reached_out=true โ student reminder still sent
Reminders: past date โ no host reminder
Reminders: past date โ no student reminder
Reminders: future date beyond window โ no host reminder
Reminders: future date beyond window โ no student reminder
Reminders: no requested_date โ no host reminder
Reminders: no requested_date โ no student reminder
Reminders: requested_date == today โ host reminder
Reminders: requested_date == end โ student reminder
Reminders: null request โ no host reminder
Reminders: null request โ no student reminder
isHebrewText detects Hebrew
isHebrewText detects English as non-Hebrew
isHebrewText handles empty string
isHebrewText handles null
isHebrewText handles mixed text
getCityDisplayName returns Hebrew for Jerusalem when showHebrew=true
getCityDisplayName returns English for ืืจืืฉืืื when showHebrew=false
getCityDisplayName returns English for Jerusalem when showHebrew=false
getCityDisplayName returns Hebrew for ืืจืืฉืืื when showHebrew=true
getCityDisplayName is case-insensitive for English
getCityDisplayName returns original for unknown city
getCityDisplayName handles empty string
getCityDisplayName uses extraTranslations
findMissingTranslations finds unknown cities
findMissingTranslations excludes Chiggsland
findMissingTranslations returns empty for all-known cities
findMissingTranslations detects Hebrew input
findMissingTranslations handles empty array
findMissingTranslations uses extraTranslations
hasFullTranslation returns true for Jerusalem
hasFullTranslation returns true for Hebrew input
hasFullTranslation returns false for unknown city
getCityCoordinates returns coordinates for Jerusalem
getCityCoordinates returns null for unknown city
getCityCoordinates works with Hebrew input
cityTranslations has at least 50 entries
cityTranslations entries have both english and hebrew
cityTranslations entries have coordinates
