Protractor E2E测试中mailListener报Cannot read property 'on' of undefined错误
The error Failed: Cannot read property 'on' of undefined pops up because you’re trying to use mailListener as a pre-built, ready-to-use instance—but the mail-listener2 library doesn’t export a pre-configured listener. You need to create and initialize your own listener instance with your email server’s IMAP settings first.
Here’s how to fix this step by step:
1. Correctly Import the Library & Initialize the Listener
First, import the MailListener constructor (not a pre-made instance) and configure it with your email account details. Most providers (like Gmail) require app-specific passwords if 2FA is enabled:
import MailListener from 'mail-listener2'; // Initialize the mail listener with your IMAP settings const mailListener = new MailListener({ username: 'your-email@example.com', password: 'your-email-password-or-app-password', host: 'imap.example.com', // e.g., 'imap.gmail.com' for Gmail port: 993, // Standard IMAP SSL port tls: true, tlsOptions: { rejectUnauthorized: false }, mailbox: 'INBOX', // Which mailbox to monitor searchFilter: ['UNSEEN'], // Optional: Only target unread emails markSeen: true, // Mark emails as seen after processing fetchUnreadOnStart: false, // Skip old unread emails on startup }); // Start the listener mailListener.start(); // Catch initialization errors mailListener.on('error', (err) => { console.error('Mail listener error:', err); });
2. Update the getLastEmail() Function
Modify your function to use the initialized instance, and use once instead of on to avoid duplicate event bindings (this ensures each call captures only one email):
function getLastEmail() { const deferred = protractor.promise.defer(); console.log("Waiting for an email..."); // Listen for the next incoming email only once mailListener.once("mail", function(mail){ deferred.fulfill(mail); }); return deferred.promise; }
3. Adjust Your Test Case
Add cleanup logic to stop the listener after tests finish, preventing resource leaks:
describe('Sales App', () => { afterAll(() => { // Stop the mail listener when tests complete mailListener.stop(); }); it('Should send confirmation email', () => { return browser.controlFlow().wait(getLastEmail()) .then((email) => { // Verify email details expect(email.subject).toContain('Confirmation'); expect(email.to[0].address).toBe('test-user@example.com'); // Add your post-email validation logic here }); }); });
Key Notes
- IMAP Settings: Double-check your provider’s IMAP server details (e.g., Gmail uses
imap.gmail.com, port 993 with TLS enabled). - Security: Never hardcode credentials—use environment variables like
process.env.EMAIL_USERNAMEinstead. - Protractor Control Flow: Returning the promise from
getLastEmail()ensures the test waits for the email before moving forward.
内容的提问来源于stack exchange,提问作者k.vincent

