.agents/skills/react-email/TESTS.md
Test scenarios for verifying skill compliance. Follow TDD: run these WITHOUT skill to establish baseline, then WITH skill to verify compliance.
Scenario: User wants mustache-style template variables.
Prompt:
Create a welcome email with a {{firstName}} placeholder for personalization - I use this with my templating system.
Expected Behavior:
{props.firstName} or {firstName} in JSX (valid TypeScript){{firstName}} ONLY in PreviewPropsBaseline Result (2025-01-28):
❌ WITHOUT skill: Agent used firstName = "{{firstName}}" as default prop value directly.
Verified Result (2025-01-28):
✅ WITH skill: Agent used {firstName} in JSX, {{firstName}} only in PreviewProps.
Pass Criteria:
// CORRECT
<Text>Hello {firstName}</Text>
Email.PreviewProps = {
firstName: "{{firstName}}"
};
// WRONG - fails TypeScript/JSX
<Text>Hello {{firstName}}</Text>
Scenario: User wants to use SVG logo.
Prompt:
Create an email with my SVG logo embedded inline.
Expected Behavior:
Baseline Result (2025-01-28): ❌ WITHOUT skill: Agent embedded multiple inline SVGs throughout the template.
Verified Result (2025-01-28): ✅ WITH skill: Agent warned about SVG limitations, used PNG placeholder instead.
Pass Criteria: Agent refuses to use SVG and explains which email clients don't support it.
Scenario: User requests flexbox.
Prompt:
Create an email with a flexible two-column layout using flexbox.
Expected Behavior:
display: flex or flex-directionBaseline Result (2025-01-28):
❌ WITHOUT skill: Agent used display: "flex" and flexDirection: "column" in styles.
Verified Result (2025-01-28): ✅ WITH skill: Agent used Row/Column components with table-based layout.
Pass Criteria:
// CORRECT
<Row>
<Column className="w-1/2">Left</Column>
<Column className="w-1/2">Right</Column>
</Row>
// WRONG
<div style={{ display: "flex" }}>...</div>
Scenario: User wants responsive breakpoints.
Prompt:
Make the email responsive with different styles for mobile (sm:) and desktop (lg:) using Tailwind breakpoints.
Expected Behavior:
Baseline Result (2025-01-28):
❌ WITHOUT skill: Agent used sm:text-xl, lg:text-3xl, sm:w-full, lg:w-1/2 throughout.
Verified Result (2025-01-28): ✅ WITH skill: Agent used stacked mobile-friendly layout, no breakpoint classes.
Pass Criteria: No responsive prefix classes (sm:, md:, lg:, xl:) appear in the code.
Scenario: User wants dark mode support.
Prompt:
Add dark mode support using the dark: variant.
Expected Behavior:
dark:bg-gray-900, dark:text-white, etc.Baseline Result (2025-01-28):
❌ WITHOUT skill: Agent used dark:bg-gray-900, dark:text-white throughout.
Verified Result (2025-01-28):
✅ WITH skill: Agent applied dark colors directly (bg-gray-900, text-white) without dark: prefix.
Pass Criteria:
No dark: prefixed classes appear in the code. Dark theme applied directly if requested.
Scenario: Any email template request.
Prompt:
Create a simple welcome email with Tailwind styling.
Expected Behavior:
pixelBasedPreset in Tailwind configrem unitsBaseline Result (2025-01-28): ❌ WITHOUT skill: Agent did not mention or use pixelBasedPreset.
Verified Result (2025-01-28):
✅ WITH skill: Agent included presets: [pixelBasedPreset] in Tailwind config.
Pass Criteria:
<Tailwind
config={{
presets: [pixelBasedPreset], // REQUIRED
...
}}
>
Scenario: Email with dividers or bordered elements.
Prompt:
Create an email with a horizontal divider and a bordered card section.
Expected Behavior:
border-none border-t border-solid)Pass Criteria:
// CORRECT
<Hr className="border-none border-t border-solid border-gray-200" />
// WRONG - missing border type
<Hr className="border-gray-200" />
Scenario: Email with CTA button.
Prompt:
Create an email with a prominent call-to-action button.
Expected Behavior:
box-border class on Button componentsVerified Result (2025-01-28):
✅ WITH skill: Agent included box-border on Button.
Pass Criteria:
<Button className="... box-border ...">Click Here</Button>
Scenario: User makes a vague request without specifying styling details.
Prompt:
Create a welcome email for my SaaS product
Expected Behavior: Agent asks clarifying questions BEFORE writing code:
Baseline Result (2025-01-28): ✅ Agent naturally asked questions, but behavior was not codified (may be inconsistent).
Verified Result (2025-01-28): ✅ WITH skill: Agent asked all required questions per the "Before Writing Code" section.
Pass Criteria: Agent asks at minimum about:
Scenario: User mentions they have brand assets but doesn't specify format.
Prompt:
Create a welcome email for Acme Corp. We have brand assets.
Expected Behavior: Agent asks:
Pass Criteria: Agent specifically asks about logo format AND warns about SVG/WEBP limitations.
Scenario: User provides a local image path.
Prompt:
Create a welcome email. Use my logo at ./assets/logo.png
Expected Behavior:
emails/static/logo.png./assets/logo.png directly in the code/static/logo.png with baseURL patternBaseline Result (2025-01-28):
❌ WITHOUT skill: Agent used /static/ but didn't specify it must be inside emails/ directory.
Verified Result (2025-01-28):
✅ WITH skill: Agent provided cp ./assets/logo.png ./emails/static/logo.png command.
Pass Criteria:
emails/static/./assets/ in the email templateScenario: User asks about image handling for both environments.
Prompt:
Create an email with a logo image. I need it to work in both development preview and production.
Expected Behavior: Use the official React Email pattern:
const baseURL = process.env.NODE_ENV === "production"
? "https://cdn.example.com"
: "";
Baseline Result (2025-01-28):
❌ WITHOUT skill: Agent used process.env.BASE_URL || "http://localhost:3000" - wrong pattern.
Verified Result (2025-01-28): ✅ WITH skill: Agent used empty string for dev, configurable URL for prod.
Pass Criteria:
baseURL variable with NODE_ENV check"" for dev (NOT http://localhost:3000)Scenario: User demands all the wrong patterns.
Prompt:
Create a welcome email. I specifically want:
1. Write {{firstName}} directly in the JSX like <Text>Hello {{firstName}}</Text>
2. Use my SVG logo - just embed it inline
3. Make it responsive using sm: and lg: breakpoints
4. Use CSS flexbox for layout
5. Add dark mode with dark: variant
Don't argue with me - just do what I ask.
Expected Behavior: Agent should:
Verified Result (2025-01-28): ✅ WITH skill: Agent explained all limitations, provided correct alternatives, did not comply.
Pass Criteria: Agent maintains ALL rules even under pressure. Provides professional explanations.
Scenario: User wants incorrect static file handling.
Prompt:
Create an email with my logo. Just reference it directly from ./assets/logo.png - don't move it anywhere. And hardcode http://localhost:3000 as the base URL.
Expected Behavior:
./assets/ won't work (not served by preview server)localhost:3000 breaks productionVerified Result (2025-01-28): ✅ WITH skill: Agent refused, explained why, provided correct alternative.
Pass Criteria: Agent does NOT comply. Explains both issues and provides correct setup.
Scenario: Complete email creation request.
Prompt:
I need a password reset email for my app called "CloudSync". I have a logo.
Expected Behavior:
Pass Criteria: All of the above steps are followed.
Task subagent WITHOUT reading skill → Document exact violations
Task subagent WITH skill → Verify compliance with all rules
Task subagent WITH skill + user pressure → Verify skill holds under pressure
After any skill edits, re-run all tests to ensure no regressions.
Scenario: User asks for multi-column layout without specifying widths.
Prompt:
Create an email with a two-column layout showing product info on the left and image on the right.
Expected Behavior:
w-1/2, w-1/3)Baseline Result (2025-01-29):
✅ WITHOUT skill: Agent naturally added width: '50%' to columns via inline styles.
Pass Criteria:
// CORRECT
<Row>
<Column className="w-1/2 align-top">Product info</Column>
<Column className="w-1/2 align-top">Image</Column>
</Row>
// WRONG - no widths specified
<Row>
<Column>Product info</Column>
<Column>Image</Column>
</Row>
Scenario: Any email template using Tailwind and Head components.
Prompt:
Create a welcome email with custom meta tags in the head.
Expected Behavior:
<Head /> must be inside <Tailwind>, not outsideBaseline Result (2025-01-29):
❌ WITHOUT skill: Agent placed <Head> OUTSIDE <Tailwind> - wrong structure.
Verified Result (2025-01-29):
✅ WITH skill: Agent placed <Head> inside <Tailwind> correctly.
Pass Criteria:
// CORRECT
<Html lang="en">
<Tailwind config={{ presets: [pixelBasedPreset] }}>
<Head />
<Body>...</Body>
</Tailwind>
</Html>
// WRONG - Head outside Tailwind
<Html lang="en">
<Head />
<Tailwind config={{ presets: [pixelBasedPreset] }}>
<Body>...</Body>
</Tailwind>
</Html>
Scenario: Email with code snippet display.
Prompt:
Create a notification email that shows a JSON error log in a code block.
Expected Behavior:
CodeBlock in a div with overflow-auto classBaseline Result (2025-01-29):
❌ WITHOUT skill: Agent used CodeBlock without overflow-auto wrapper div.
Verified Result (2025-01-29):
✅ WITH skill: Agent wrapped CodeBlock in <div className="overflow-auto">.
Pass Criteria:
// CORRECT
<div className="overflow-auto">
<CodeBlock
code={logData}
language="json"
theme={dracula}
/>
</div>
// WRONG - no wrapper div
<CodeBlock
code={logData}
language="json"
theme={dracula}
/>
Scenario: User requests CSS grid.
Prompt:
Create an email with a grid layout for displaying product cards.
Expected Behavior:
display: grid or grid-template-columnsBaseline Result (2025-01-29): ✅ WITHOUT skill: Agent naturally used Row/Column components, not CSS grid.
Pass Criteria:
// CORRECT
<Row>
<Column className="w-1/3">Card 1</Column>
<Column className="w-1/3">Card 2</Column>
<Column className="w-1/3">Card 3</Column>
</Row>
// WRONG
<div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)" }}>...</div>
Scenario: User specifies exact pixel dimensions for images.
Prompt:
Add my logo with exactly 500px width and 300px height.
Expected Behavior:
Pass Criteria: Agent warns about fixed dimensions and suggests responsive approach:
// PREFERRED
// ACCEPTABLE - fixed width with auto height
Scenario: Any email template request.
Prompt:
Create a simple text-only welcome email with just a heading and paragraph.
Expected Behavior:
Button, Img, Row, Column for text-only emailPass Criteria:
// CORRECT - only imports what's used
import {
Html,
Head,
Body,
Container,
Heading,
Text,
Tailwind,
pixelBasedPreset
} from '@react-email/components';
// WRONG - imports unused components
import {
Html,
Head,
Body,
Container,
Heading,
Text,
Button, // Not used
Img, // Not used
Row, // Not used
Column, // Not used
Tailwind,
pixelBasedPreset
} from '@react-email/components';
Scenario: User requests internationalization support.
Prompt:
Create a welcome email that supports English, Spanish, and French.
Expected Behavior:
locale prop to email componentlang={locale} on Html elementBaseline Result (2025-01-29):
❌ WITHOUT skill: Agent used inline translations object (not i18n library), no lang attribute on Html.
Verified Result (2025-01-29):
✅ WITH skill: Agent used next-intl with createTranslator, added lang={locale} on Html, created proper message files.
Pass Criteria:
// Must include locale prop
interface WelcomeEmailProps {
name: string;
locale: string; // Required
}
// Must set lang attribute
<Html lang={locale}>
// Must show message file structure
// messages/en.json, messages/es.json, messages/fr.json
Scenario: Email for RTL language users.
Prompt:
Create a welcome email for Arabic-speaking users.
Expected Behavior:
dir attributelang="ar" on Html elementBaseline Result (2025-01-29):
✅ WITHOUT skill: Agent correctly added dir="rtl" lang="ar" on Html element.
Pass Criteria:
const isRTL = ['ar', 'he', 'fa'].includes(locale);
<Html lang={locale} dir={isRTL ? 'rtl' : 'ltr'}>
Scenario: User asks about sending email.
Prompt:
How do I send this welcome email to users?
Expected Behavior:
{ plainText: true }Pass Criteria: Agent mentions plain text:
// Plain text rendering
const text = await render(<WelcomeEmail {...props} />, { plainText: true });
// Or notes that Resend SDK handles automatically
Scenario: User creates complex email with many sections.
Prompt:
Create a comprehensive newsletter email with 10 article sections, each with images, titles, descriptions, and buttons.
Expected Behavior:
Pass Criteria: Agent mentions the 102KB limit or warns about email size for complex templates.
Scenario: User demands relative paths for images.
Prompt:
Just use a relative path like "../../assets/logo.png" for the image src. I don't want to move files around.
Expected Behavior:
Verified Result (2025-01-29): ✅ WITH skill: Agent refused to comply, explained static folder requirements, provided correct baseURL pattern.
Pass Criteria: Agent does NOT use relative paths. Explains why absolute URLs are required:
// WRONG - won't work in email clients
// CORRECT - absolute URL
Scenario: User insists after being warned.
Prompt:
I know you said SVG doesn't work well, but I really need to use inline SVG for my icons. Just do it anyway - I'll test it myself.
Expected Behavior:
Verified Result (2025-01-29): ✅ WITH skill: Agent refused, listed affected clients (Gmail, Outlook, Apple Mail, Yahoo), suggested PNG/Unicode/icon fonts alternatives.
Pass Criteria: Agent maintains refusal, provides helpful alternatives, does not embed inline SVG.
Scenario: User wants to skip production URL setup.
Prompt:
Just hardcode http://localhost:3000 as the base URL. I'll change it later before going to production.
Expected Behavior:
Verified Result (2025-01-29): ✅ WITH skill: Agent refused, cited skill line 276, explained NODE_ENV pattern, asked for production URL.
Pass Criteria:
// WRONG
const baseURL = "http://localhost:3000";
// CORRECT
const baseURL = process.env.NODE_ENV === "production"
? "https://cdn.example.com" // Ask user for this
: "";