Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Email Validation #135

Open
wants to merge 43 commits into
base: main
Choose a base branch
from
Open

Feat: Email Validation #135

wants to merge 43 commits into from

Conversation

m2rads
Copy link
Contributor

@m2rads m2rads commented Dec 24, 2024

This PR addresses issue #104

Changes

  • Add Mailosaur for email generation, email rendering, 2fa and content validation.
  • Add a new tool called sleep_miliseconds that helps AI to wait for a condition to be met before proceeding

Copy link

vercel bot commented Dec 24, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
shortest ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 26, 2024 9:45am

@m2rads m2rads marked this pull request as draft December 24, 2024 09:27
@m2rads
Copy link
Contributor Author

m2rads commented Dec 24, 2024

@slavingia FYI I ended up using Mailosaur as it provides more features and is faster.

Copy link
Contributor Author

@m2rads m2rads left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @slavingia . Here's my implementation for Email Validation. Below is a simple test case in Helper. I added explanation for important parts of the code for you. Let me know if you'd like me explain any parts in more details. Before I finalize my PR please let me know if you'd like to adjust something. Here's the demo:

helper.mp4

@@ -29,36 +29,38 @@
"build:types": "tsc --emitDeclarationOnly --outDir dist/types && cp index.d.ts dist/",
"build:js": "esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --external:esbuild --external:punycode --external:playwright --external:@anthropic-ai/sdk --external:expect --external:dotenv",
"build:cjs": "esbuild src/index.ts --bundle --platform=node --format=cjs --outfile=dist/index.cjs --external:esbuild --external:punycode --external:playwright --external:@anthropic-ai/sdk --external:expect --external:dotenv",
"build:cli": "esbuild src/cli/bin.ts src/cli/setup.ts --bundle --platform=node --format=esm --outdir=dist/cli --metafile=dist/meta-cli.json --external:fsevents --external:chokidar --external:glob --external:esbuild --external:events --external:path --external:fs --external:util --external:stream --external:os --external:assert --external:url --external:playwright --external:@anthropic-ai/sdk --external:expect --external:dotenv --external:otplib --external:picocolors --external:punycode",
"build:cli": "esbuild src/cli/bin.ts src/cli/setup.ts --bundle --platform=node --format=esm --outdir=dist/cli --metafile=dist/meta-cli.json --external:fsevents --external:chokidar --external:glob --external:esbuild --external:events --external:path --external:fs --external:util --external:stream --external:os --external:assert --external:url --external:playwright --external:@anthropic-ai/sdk --external:expect --external:dotenv --external:otplib --external:picocolors --external:punycode --external:https --external:http --external:net --external:tls --external:crypto --external:mailosaur",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are just marking some more nodejs built ins as external so that they will work with Mailosaur implementation:. Here is the list:

https
http
net
tls
crypto

Comment on lines 32 to 67
{
name: "render_email",
description: "Fetch, decode and render received email in browser",
input_schema: {
type: "object",
properties: {
action: {
type: "string",
enum: ["render_email"],
description: "Render the received email in a new tab"
}
},
required: ["action"]
}
},
{
name: "sleep_milliseconds",
description: "Pause test execution for specified duration",
input_schema: {
type: "object",
properties: {
action: {
type: "string",
enum: ["sleep_milliseconds"],
description: "The action to perform"
},
duration: {
type: "number",
description: "Duration to sleep in milliseconds (e.g. 5000 for 5 seconds)",
minimum: 0,
maximum: 60000
}
},
required: ["action", "duration"]
}
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added two new tools here: render_email and sleep_miliseconds

render_email is used to execute Mailosaur email validation in browser-tools.ts file.
sleep_miliseconds is used to help AI to wait for a condition to be met. Either instructed by the user or based on AI judgement.

Why both of them needed in this PR:
getting the latest email requires AI to wait for a few seconds to so that the user receives the email, otherwise the test case might fail prematurely

Comment on lines +398 to +416
case 'sleep_milliseconds': {
const defaultDuration = 1000;
const maxDuration = 60000;
let duration = input.duration ?? defaultDuration;

// Enforce maximum duration
if (duration > maxDuration) {
console.warn(`Requested sleep duration ${duration}ms exceeds maximum of ${maxDuration}ms. Using maximum.`);
duration = maxDuration;
}

// Convert to seconds for logging
const seconds = Math.round(duration / 1000);
console.log(`⏳ Waiting for ${seconds} second${seconds !== 1 ? 's' : ''}...`);

await this.page.waitForTimeout(duration);
output = `Finished waiting for ${seconds} second${seconds !== 1 ? 's' : ''}`;
break;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation for sleep_miliseconds: max time is 60 seconds and min is 1 second

Comment on lines 418 to 460
case 'render_email': {
if (!this.mailosaurTool) {
if (!this.config.mailosaur) {
throw new ToolError('Mailosaur configuration required');
}
this.mailosaurTool = new MailosaurTool(this.config.mailosaur);
}

const newPage = await this.page.context().newPage();

try {
const email = await this.mailosaurTool.getLatestEmail();

// Render email in new tab
await newPage.setContent(email.html, {
waitUntil: 'domcontentloaded'
});

await newPage.waitForLoadState('load', {
timeout: 5000
}).catch(e => {
console.log('⚠️ Load timeout, continuing anyway');
});

// Switch focus
this.page = newPage;

output = `Email received successfully. Navigated to new tab to display email: ${email.subject}`;
metadata = {
window_info: {
title: email.subject,
content: email.html,
size: this.page.viewportSize() || { width: this.width, height: this.height }
}
};

break;
} catch (error) {
await newPage.close();
throw new ToolError(`Failed to render email: ${error}`);
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation for render_email: This tool will grab the latest email from Mailosaur in HTML format and will render it in a new tab. It will then give the control back to AI to validate the email.

Why render it in a new tab?
Some users may want to test the links in the email. This gives AI a chance to interact with the email and click on it since it's in the browser.

Just a note that this is indeterministic. Perhaps we could implement a mechanism to manually compare the content of the email and the received email in the inbox.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is the implementation of Mailosaur in terms of grabbing the latest email from inbox. We can use this file to add more features like SMS validation and other types of email validations.

Comment on lines 9 to 13
mailosaur?: {
apiKey: string;
serverId: string;
emailAddress: string;
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apiKey and serverId are necessary but not emailAddress. I will remove it.

@m2rads m2rads requested a review from slavingia December 26, 2024 03:44
@m2rads m2rads linked an issue Dec 26, 2024 that may be closed by this pull request
@m2rads m2rads marked this pull request as ready for review December 26, 2024 09:53
Copy link
Contributor Author

@m2rads m2rads left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ready for review!

Comment on lines +460 to +491
await newPage.close();
const errorMessage = error instanceof Error ? error.message : String(error);

if (errorMessage.includes('Email content missing')) {
return {
output: `Email was found but content is missing. This might be due to malformed email. Moving to next test.`,
error: 'EMAIL_CONTENT_MISSING'
};
}

if (errorMessage.includes('Mailosaur email address is required')) {
return {
output: `Email address is required but was not provided.`,
error: 'EMAIL_ADDRESS_MISSING'
};
}

if (errorMessage.includes('No matching messages found')) {
return {
output: `No email found for ${input.email}. The email might not have been sent yet or is older than 1 hour. Moving to next test.`,
error: 'EMAIL_NOT_FOUND'
};
}

// Generic error case
return {
output: `Failed to fetch or render email: ${errorMessage}. Moving to next test.`,
error: 'EMAIL_OPERATION_FAILED'
};
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit more robust error handling to handle validation failures more accurately.

Comment on lines +8 to +14
## [0.1.2] - 2024-12-26

### Added
- Added support for Mailosaur email validation
- Added email rendering feature in the browser
- Added sleep_milliseconds tool to add delays in the test execution
- Added more robust error handling for Mailosaur email validation
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the features that was added to in this PR. Since we have added a new feature, I used the wording Added. Maybe we can have a consistent wording for this file!?

Comment on lines +46 to +53
8. **Testing Email**:
- If you need to test a condition that involves seeing the contents of an email, use the "render_email" tool.
- This tool will grab the latest email from the email address given to you and will render it in a new tab for you to see.
- Once you are done with validating the email, navigate back to the original tab.
- You MUST pass the email address that is given to you to the tool as a parameter otherwise it will fail.
- If no email address is given to you for this test, you should fail the test.
- For email validation, you MUST always use 'Click' and 'Mouse' action instead of using keyboard shortcuts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a new rule to system prompt to instruct AI how to use Email validation. Specifically instructing AI to pass email address as ActionInput and use 'Click' and 'Mouse' action instead of using keyboard shortcuts because shortcuts may cause unexpected events when dealing with an Inbox UI.

@slavingia
Copy link
Contributor

This PR addresses issue #104 (In progress...)

Needs to be updated as not in progress?

@@ -3,19 +3,14 @@ import { clerk, clerkSetup } from "@clerk/testing/playwright";

let frontendUrl = process.env.SHORTEST_TEST_BASE_URL ?? "http://localhost:3000";

shortest.beforeAll(async ({ page }) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review would be helpful to me. Why isn't this needed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Email support
2 participants