Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds Gmail/Microsoft E2E tests and helpers; removes rule/example/group example UI and related APIs; refactors EmailProvider (removes getMessagesByFields) and prior-communication search logic to use a centralized sender search term; adds Debug Rules UI/API and a bulk-toggle action; small mocks/UI/util tweaks; version bump. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as DebugRulesPage (client)
participant API as GET /api/user/debug/rules
participant Action as toggleAllRulesAction
participant DB as Prisma
UI->>API: GET debug rules
API->>DB: query rules with actions and group counts
DB-->>API: rules data
API-->>UI: JSON DebugRulesResponse
UI->>Action: invoke toggleAllRulesAction(enabled)
Action->>DB: updateMany rules set enabled
DB-->>Action: update result
Action-->>UI: { success: true }
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Update Outlook query handling and premium-rule test setup, add Outlook query parsing E2E, and adjust Gmail/Microsoft labeling tests with 30,000–60,000 ms timeoutsAdd Outlook query prefix stripping and domain KQL in 📍Where to StartStart with Outlook query changes in Macroscope summarized 3cb430e. |
| .top(options?.maxResults || 50) | ||
| .get(); | ||
|
|
||
| return response.value.map((msg) => convertMessage(msg)); |
There was a problem hiding this comment.
Suggestion: Guard response.value in getDrafts to avoid a runtime error if it’s undefined. Consider using the same (response.value || []) pattern used elsewhere in this class.
| return response.value.map((msg) => convertMessage(msg)); | |
| return (response.value || []).map((msg) => convertMessage(msg)); |
🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
| async getDrafts(options?: { maxResults?: number }): Promise<ParsedMessage[]> { | ||
| const response = await this.getMessagesWithPagination({ | ||
| query: "isDraft eq true", | ||
| maxResults: options?.maxResults || 50, | ||
| }); | ||
| return response.messages; | ||
| const response: { value: Message[] } = await this.client | ||
| .getClient() | ||
| .api("/me/mailFolders/drafts/messages") | ||
| .select(MESSAGE_SELECT_FIELDS) | ||
| .top(options?.maxResults || 50) | ||
| .get(); | ||
|
|
||
| return response.value.map((msg) => convertMessage(msg)); | ||
| } |
There was a problem hiding this comment.
convertMessage is called without folderIds, so labelIds won’t map correctly. Consider fetching folderIds via getFolderIds(this.client) and passing it to convertMessage.
| async getDrafts(options?: { maxResults?: number }): Promise<ParsedMessage[]> { | |
| const response = await this.getMessagesWithPagination({ | |
| query: "isDraft eq true", | |
| maxResults: options?.maxResults || 50, | |
| }); | |
| return response.messages; | |
| const response: { value: Message[] } = await this.client | |
| .getClient() | |
| .api("/me/mailFolders/drafts/messages") | |
| .select(MESSAGE_SELECT_FIELDS) | |
| .top(options?.maxResults || 50) | |
| .get(); | |
| return response.value.map((msg) => convertMessage(msg)); | |
| } | |
| async getDrafts(options?: { maxResults?: number }): Promise<ParsedMessage[]> { | |
| const response: { value: Message[] } = await this.client | |
| .getClient() | |
| .api("/me/mailFolders/drafts/messages") | |
| .select(MESSAGE_SELECT_FIELDS) | |
| .top(options?.maxResults || 50) | |
| .get(); | |
| const folderIds = await getFolderIds(this.client); | |
| return response.value.map((msg) => convertMessage(msg, folderIds)); | |
| } |
🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/ResultDisplay.tsx (1)
216-219: Considerbreak-wordsinstead ofbreak-allfor better readability.While
break-allprevents overflow, it breaks words at any character, which can reduce readability for fields likesubjectandcontent. Thebreak-wordsclass breaks long words only when necessary while preserving word boundaries when possible, providing a better user experience for mixed content types (emails, URLs, and regular text).Apply this diff to use
break-words:<div key={field.key} - className="whitespace-pre-wrap break-all" + className="whitespace-pre-wrap break-words" >apps/web/utils/email/google.ts (1)
946-958: Consider potential N+1 query pattern.The current implementation lists drafts and then fetches each draft's full message individually. For the default
maxResultsof 50, this results in 51 API calls. While parallel fetching withPromise.allhelps, consider whether batch operations could be more efficient if available in the Gmail API.apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts (1)
135-151: Consider usingtest.skipIffor clearer skip semantics.The early return works, but
test.skipIf(!companyDomain)would make the skip condition more explicit in test output and follow vitest conventions.- test("returns TRUE for colleague at same company domain", async () => { - if (!companyDomain) { - // No company domain in inbox - skip - return; - } + test.skipIf(!companyDomain)("returns TRUE for colleague at same company domain", async () => {Note: This would require lifting
companyDomainto module scope or using a different pattern sincetest.skipIfevaluates at test registration time. The current approach is acceptable ifcompanyDomainmust be determined at runtime.
| async getDrafts(options?: { maxResults?: number }): Promise<ParsedMessage[]> { | ||
| const response = await this.getMessagesWithPagination({ | ||
| query: "isDraft eq true", | ||
| maxResults: options?.maxResults || 50, | ||
| }); | ||
| return response.messages; | ||
| const response: { value: Message[] } = await this.client | ||
| .getClient() | ||
| .api("/me/mailFolders/drafts/messages") | ||
| .select(MESSAGE_SELECT_FIELDS) | ||
| .top(options?.maxResults || 50) | ||
| .get(); | ||
|
|
||
| return response.value.map((msg) => convertMessage(msg)); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Search for convertMessage function definition
rg -n "function convertMessage|const convertMessage|export.*convertMessage" apps/web --type ts --type tsx -A 3
# Also check for convertMessage type definition
rg -n "convertMessage\(" apps/web/utils/email/microsoft.ts -B 2 -A 2
# Find where folderIds is used in relation to convertMessage
rg -n "folderIds" apps/web/utils/email/microsoft.ts -B 3 -A 3Repository: elie222/inbox-zero
Length of output: 1815
🏁 Script executed:
# Search for convertMessage function definition more broadly
rg -n "convertMessage" apps/web/utils --type ts -B 2 -A 15 | head -100
# Also check the imports in microsoft.ts
rg -n "import.*convertMessage|export.*convertMessage" apps/web -type ts -A 2 -B 2Repository: elie222/inbox-zero
Length of output: 6806
🏁 Script executed:
# Find the convertMessage function definition in message.ts
cat apps/web/utils/outlook/message.ts | head -150Repository: elie222/inbox-zero
Length of output: 4484
🏁 Script executed:
# Continue reading to find convertMessage function
sed -n '140,280p' apps/web/utils/outlook/message.tsRepository: elie222/inbox-zero
Length of output: 4624
🏁 Script executed:
# Find the convertMessage function definition
rg -n "^export function convertMessage|^function convertMessage" apps/web/utils/outlook/message.ts -A 30Repository: elie222/inbox-zero
Length of output: 1204
🏁 Script executed:
# Check if there are other instances where convertMessage is called without folderIds
rg -n "convertMessage\(" apps/web --type ts -B 2 -A 1 | grep -E "convertMessage\(|apps/web"Repository: elie222/inbox-zero
Length of output: 2467
Pass folderIds to convertMessage for consistency with other message-fetching methods.
The convertMessage function has an optional folderIds parameter (defaults to {}). While this won't cause errors, omitting it disables folder-based label mapping. Other similar methods (getSentMessages, getInboxMessages) explicitly pass folderIds to ensure proper label mapping. Update line 979 to fetch and pass folderIds:
const folderIds = await getFolderIds(this.client);
return response.value.map((msg) => convertMessage(msg, folderIds));This maintains consistency and ensures drafts receive proper folder-related labels.
🤖 Prompt for AI Agents
In apps/web/utils/email/microsoft.ts around lines 971 to 980, the draft messages
are converted without passing folderIds which disables folder-based label
mapping; fetch folder IDs with getFolderIds(this.client) (await it) and pass the
resulting folderIds into convertMessage when mapping response.value so each
draft is converted as convertMessage(msg, folderIds).
There was a problem hiding this comment.
5 issues found across 35 files
Prompt for AI agents (all 5 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/app/(app)/[emailAccountId]/debug/rules/page.tsx">
<violation number="1" location="apps/web/app/(app)/[emailAccountId]/debug/rules/page.tsx:44">
P2: Clipboard write operation is not awaited and lacks error handling. If the clipboard operation fails, the UI will still show "Copied" and display the success toast.</violation>
</file>
<file name="apps/web/utils/email.ts">
<violation number="1" location="apps/web/utils/email.ts:141">
P2: When input is in "Name <email>" format and domain is public, this returns the entire string including the name instead of just the email address. Use `extractEmailAddress(email)` to ensure consistent return format as documented ("returns the full email address").</violation>
</file>
<file name="apps/web/__tests__/e2e/helpers.ts">
<violation number="1" location="apps/web/__tests__/e2e/helpers.ts:83">
P2: Including `enabled: true` in the query will cause duplicate rules to be created if the test rule exists but is disabled. Consider finding by name only, then enabling an existing disabled rule or creating new if not found.</violation>
</file>
<file name="apps/web/__tests__/e2e/outlook-query-parsing.test.ts">
<violation number="1" location="apps/web/__tests__/e2e/outlook-query-parsing.test.ts:26">
P2: Tests will fail with cryptic errors if `TEST_OUTLOOK_EMAIL` is not set because `provider` will be undefined. Include it in the skipIf condition to match the pattern used by other E2E tests in this codebase.</violation>
</file>
<file name="apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts">
<violation number="1" location="apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts:136">
P2: Test silently passes instead of properly skipping when `companyDomain` is undefined. The comment says "skip" but `return` makes the test pass, not skip. Consider using vitest's dynamic skip mechanism or updating the comment to reflect the actual behavior.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| const existingRule = await prisma.rule.findFirst({ | ||
| where: { | ||
| emailAccountId, | ||
| enabled: true, |
There was a problem hiding this comment.
P2: Including enabled: true in the query will cause duplicate rules to be created if the test rule exists but is disabled. Consider finding by name only, then enabling an existing disabled rule or creating new if not found.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/__tests__/e2e/helpers.ts, line 83:
<comment>Including `enabled: true` in the query will cause duplicate rules to be created if the test rule exists but is disabled. Consider finding by name only, then enabling an existing disabled rule or creating new if not found.</comment>
<file context>
@@ -26,3 +27,80 @@ export async function findOldMessage(
+ const existingRule = await prisma.rule.findFirst({
+ where: {
+ emailAccountId,
+ enabled: true,
+ name: "E2E Test Catch-All Rule",
+ },
</file context>
|
|
||
| vi.mock("server-only", () => ({})); | ||
|
|
||
| describe.skipIf(!RUN_E2E_TESTS)( |
There was a problem hiding this comment.
P2: Tests will fail with cryptic errors if TEST_OUTLOOK_EMAIL is not set because provider will be undefined. Include it in the skipIf condition to match the pattern used by other E2E tests in this codebase.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/__tests__/e2e/outlook-query-parsing.test.ts, line 26:
<comment>Tests will fail with cryptic errors if `TEST_OUTLOOK_EMAIL` is not set because `provider` will be undefined. Include it in the skipIf condition to match the pattern used by other E2E tests in this codebase.</comment>
<file context>
@@ -0,0 +1,174 @@
+
+vi.mock("server-only", () => ({}));
+
+describe.skipIf(!RUN_E2E_TESTS)(
+ "Outlook Query Parsing E2E",
+ { timeout: 15_000 },
</file context>
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
apps/web/__tests__/e2e/helpers.ts (1)
94-100: Duplicate rule creation when disabled rule exists.Including
enabled: truein the findFirst query means if a rule with name "E2E Test Catch-All Rule" exists but is disabled, the function will create a duplicate rule instead of enabling the existing one.Consider finding by name and emailAccountId only, then enable if disabled or create if not found:
const existingRule = await prisma.rule.findFirst({ where: { emailAccountId, - enabled: true, name: "E2E Test Catch-All Rule", }, }); if (!existingRule) { await prisma.rule.create({ data: { name: "E2E Test Catch-All Rule", emailAccountId, enabled: true, automate: true, instructions: "This is a test rule that should match all emails. Draft a brief acknowledgment reply.", actions: { create: { type: "DRAFT_EMAIL", content: "Test acknowledgment", }, }, }, }); + } else if (!existingRule.enabled) { + await prisma.rule.update({ + where: { id: existingRule.id }, + data: { enabled: true }, + }); }
🧹 Nitpick comments (2)
apps/web/utils/email.ts (1)
116-132: Consider expanding the list of public domains.The current list covers major providers. If you encounter other common public email providers in production (e.g.,
live.com,msn.com,mail.com,inbox.com), consider adding them to ensure consistent search behavior.apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts (1)
84-94: Consider storing the extracted email to avoid redundant calls.
extractEmailAddressis called twice on the same value: once in the find predicate (line 85) and again at line 92. You could store the result from the find logic to avoid the redundant call.Example optimization:
- const companyMessage = realMessages.find((m) => { - const from = extractEmailAddress(m.headers.from); - if (!from) return false; - const domain = extractDomainFromEmail(from); - return domain && !publicDomains.includes(domain.toLowerCase()); - }); - - if (companyMessage) { - const senderEmail = extractEmailAddress(companyMessage.headers.from)!; - companyDomain = extractDomainFromEmail(senderEmail) || undefined; - } + let companySenderEmail: string | undefined; + const companyMessage = realMessages.find((m) => { + const from = extractEmailAddress(m.headers.from); + if (!from) return false; + const domain = extractDomainFromEmail(from); + if (domain && !publicDomains.includes(domain.toLowerCase())) { + companySenderEmail = from; + return true; + } + return false; + }); + + if (companyMessage && companySenderEmail) { + companyDomain = extractDomainFromEmail(companySenderEmail) || undefined; + }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts(1 hunks)apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts(1 hunks)apps/web/__tests__/e2e/helpers.ts(2 hunks)apps/web/utils/email.ts(1 hunks)apps/web/utils/logger.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/tests/e2e/cold-email/microsoft-cold-email.test.ts
🧰 Additional context used
📓 Path-based instructions (15)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use@/path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type filesImport specific lodash functions rather than entire lodash library to minimize bundle size (e.g.,
import groupBy from 'lodash/groupBy')
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/utils/logger.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor error handling in async operations
**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
**/*.{ts,tsx}: For early access feature flags, create hooks using the naming conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g.,inbox-cleaner,pricing-options-2)
Always define types for A/B test variant flags (e.g.,type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting
**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the!postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/utils/logger.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
apps/web/{utils/ai,utils/llms,__tests__}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/llm.mdc)
LLM-related code must be organized in specific directories:
apps/web/utils/ai/for main implementations,apps/web/utils/llms/for core utilities and configurations, andapps/web/__tests__/for LLM-specific tests
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/utils/logger.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma'sselectoption. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. AllfindUnique/findFirstcalls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
AllfindManyqueries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g.,emailAccount: { id: emailAccountId }) to validate ownership
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/utils/logger.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
AI tests must be placed in the
__tests__directory and are not run by default (they use a real LLM)
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/utils/logger.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/*.{tsx,ts,css}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
Implement responsive design with Tailwind CSS using a mobile-first approach
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/utils/logger.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-hidden="true"on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like<marquee>or<blink>
Only use thescopeprop on<th>elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include atitleelement for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
AssigntabIndexto non-interactive HTML elements witharia-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/utils/logger.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
!(pages/_document).{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
Don't use the next/head module in pages/_document.js on Next.js projects
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/utils/logger.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)
**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g.,import groupBy from 'lodash/groupBy')
Files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/utils/logger.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/{server,api,actions,utils}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/{server,api,actions,utils}/**/*.ts: UsecreateScopedLoggerfrom "@/utils/logger" for logging in backend code
Add thecreateScopedLoggerinstantiation at the top of the file with an appropriate scope name
Use.with()method to attach context variables only within specific functions, not on global loggers
For large functions with reused variables, usecreateScopedLogger().with()to attach context once and reuse the logger without passing variables repeatedly
Files:
apps/web/utils/email.tsapps/web/utils/logger.ts
apps/web/__tests__/**/*.test.ts
📄 CodeRabbit inference engine (.cursor/rules/llm-test.mdc)
apps/web/__tests__/**/*.test.ts: Place all LLM-related tests inapps/web/__tests__/directory
Use vitest imports (describe,expect,test,vi,beforeEach) in LLM test files
Mock 'server-only' module with empty object in LLM test files:vi.mock("server-only", () => ({}))
Set timeout constantconst TIMEOUT = 15_000;for LLM tests
Usedescribe.runIf(isAiTest)with environment variableRUN_AI_TESTS === "true"to conditionally run LLM tests
Useconsole.debug()for outputting generated LLM content in tests, e.g.,console.debug("Generated content:\n", result.content);
Prefer using existing helpers from@/__tests__/helpers.ts(getEmailAccount,getEmail,getRule,getMockMessage,getMockExecutedRule) instead of creating custom test data helpers
Files:
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
**/*.test.{ts,tsx}: Usevitestfor testing the application
Tests should be colocated next to the tested file with.test.tsor.test.tsxextension (e.g.,dir/format.tsanddir/format.test.ts)
Mockserver-onlyusingvi.mock("server-only", () => ({}))
Mock Prisma usingvi.mock("@/utils/prisma")and import the mock from@/utils/__mocks__/prisma
Usevi.clearAllMocks()inbeforeEachto clean up mocks between tests
Each test should be independent
Use descriptive test names
Mock external dependencies in tests
Do not mock the Logger
Avoid testing implementation details
Use test helpersgetEmail,getEmailAccount, andgetRulefrom@/__tests__/helpersfor mocking emails, accounts, and rules
Files:
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests
Files:
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
🧠 Learnings (26)
📓 Common learnings
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Design Gmail wrapper functions to be provider-agnostic to support future email providers like Outlook and ProtonMail
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Always use wrapper functions from @/utils/gmail/ for Gmail API operations instead of direct provider API calls
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Keep Gmail provider-specific implementation details isolated within the apps/web/utils/gmail/ directory
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers
Applied to files:
apps/web/__tests__/e2e/helpers.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules
Applied to files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Applied to files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Applied to files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`
Applied to files:
apps/web/__tests__/e2e/helpers.ts
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`
Applied to files:
apps/web/__tests__/e2e/helpers.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Always use wrapper functions from @/utils/gmail/ for Gmail API operations instead of direct provider API calls
Applied to files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Keep Gmail provider-specific implementation details isolated within the apps/web/utils/gmail/ directory
Applied to files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.tsapps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
Applied to files:
apps/web/__tests__/e2e/helpers.tsapps/web/utils/email.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must import from `zod` for schema validation, use `createScopedLogger` from `@/utils/logger`, `chatCompletionObject` and `createGenerateObject` from `@/utils/llms`, and import `EmailAccountWithAI` type from `@/utils/llms/types`
Applied to files:
apps/web/__tests__/e2e/helpers.ts
📚 Learning: 2025-11-25T14:39:08.150Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-11-25T14:39:08.150Z
Learning: Applies to apps/web/app/api/**/*.{ts,tsx} : All database queries must include user scoping with `emailAccountId` or `userId` filtering in WHERE clauses
Applied to files:
apps/web/__tests__/e2e/helpers.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Mock Prisma using `vi.mock("@/utils/prisma")` and import the mock from `@/utils/__mocks__/prisma`
Applied to files:
apps/web/__tests__/e2e/helpers.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must follow a standard structure: accept options with `inputData` and `emailAccount` parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use `createGenerateObject` to execute the LLM call
Applied to files:
apps/web/__tests__/e2e/helpers.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Design Gmail wrapper functions to be provider-agnostic to support future email providers like Outlook and ProtonMail
Applied to files:
apps/web/utils/email.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages
Applied to files:
apps/web/utils/logger.ts
📚 Learning: 2025-11-25T14:38:08.183Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-11-25T14:38:08.183Z
Learning: Applies to **/{server,api,actions,utils}/**/*.ts : Add the `createScopedLogger` instantiation at the top of the file with an appropriate scope name
Applied to files:
apps/web/utils/logger.ts
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't hardcode sensitive data like API keys and tokens
Applied to files:
apps/web/utils/logger.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions
Applied to files:
apps/web/utils/logger.ts
📚 Learning: 2025-11-25T14:38:08.183Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-11-25T14:38:08.183Z
Learning: Applies to **/{server,api,actions,utils}/**/*.ts : For large functions with reused variables, use `createScopedLogger().with()` to attach context once and reuse the logger without passing variables repeatedly
Applied to files:
apps/web/utils/logger.ts
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/*.ts : Only return necessary fields in API responses using Prisma's `select` option. Never expose sensitive data such as password hashes, private keys, or system flags
Applied to files:
apps/web/utils/logger.ts
📚 Learning: 2025-11-25T14:38:08.183Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-11-25T14:38:08.183Z
Learning: Applies to **/{server,api,actions,utils}/**/*.ts : Use `createScopedLogger` from "@/utils/logger" for logging in backend code
Applied to files:
apps/web/utils/logger.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Use vitest imports (`describe`, `expect`, `test`, `vi`, `beforeEach`) in LLM test files
Applied to files:
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Use `describe.runIf(isAiTest)` with environment variable `RUN_AI_TESTS === "true"` to conditionally run LLM tests
Applied to files:
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/__tests__/**/*.{ts,tsx} : AI tests must be placed in the `__tests__` directory and are not run by default (they use a real LLM)
Applied to files:
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Avoid testing implementation details
Applied to files:
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts
🧬 Code graph analysis (2)
apps/web/utils/logger.ts (1)
apps/web/env.ts (1)
env(17-255)
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts (2)
apps/web/utils/email/provider.ts (1)
createEmailProvider(14-32)apps/web/utils/email.ts (2)
extractEmailAddress(19-52)extractDomainFromEmail(73-91)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: test
- GitHub Check: Review for correctness
🔇 Additional comments (8)
apps/web/utils/logger.ts (1)
255-259: LGTM! Formatting improvement enhances readability.The multi-line formatting of this conditional expression improves code readability without any behavioral changes. The split is consistent with the similar formatting pattern used in the subsequent else-if block at lines 263-268.
apps/web/utils/email.ts (1)
137-144: LGTM! Previous issues addressed.The implementation correctly extracts the email address for public domains (with proper fallback) and returns the domain for company emails. The logic handles edge cases appropriately and addresses the concerns from previous review comments.
apps/web/__tests__/e2e/cold-email/google-cold-email.test.ts (3)
1-30: LGTM! Well-structured E2E test setup.The test file follows E2E patterns correctly: proper vitest imports, server-only mocking, environment-based gating with
describe.skipIf, and appropriate timeout configuration for real API calls.
37-75: LGTM! Test setup logic is sound.The beforeAll hook properly initializes the provider with real account data and derives test inputs from actual inbox messages. Error handling ensures tests fail fast if prerequisites aren't met.
97-154: LGTM! Comprehensive test coverage.The four test cases provide thorough coverage of the
hasPreviousCommunicationsWithSenderOrDomainmethod: known sender (TRUE), unknown sender (FALSE), pre-email date (FALSE), and company domain colleague (TRUE with conditional skip). The use ofskip()for the company domain test when no suitable data exists is appropriate.apps/web/__tests__/e2e/helpers.ts (3)
5-5: LGTM! Correct prisma import.Using the centralized prisma wrapper as per project guidelines.
8-43: LGTM! Robust message selection logic.The enhanced
findOldMessagecorrectly prioritizes older messages to avoid interfering with recent activity, with a sensible fallback to the oldest available inbox message. Error handling ensures clear feedback when no suitable message exists.
45-83: LGTM! Proper premium setup for E2E tests.
ensureTestPremiumAccountcorrectly ensures premium status for AI feature testing. Database operations are properly scoped withuserId, and the logic handles both create and update scenarios cleanly.
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
| .top(5) | ||
| .select("id,sentDateTime") | ||
| .get() | ||
| .catch((error) => { | ||
| this.logger.error("Error checking sent messages (domain)", { | ||
| error, | ||
| }); | ||
| return { value: [] }; | ||
| }), | ||
|
|
||
| this.client | ||
| .getClient() | ||
| .api("/me/messages") |
There was a problem hiding this comment.
Domain search uses to:@domain/from:@domain, which Graph KQL doesn’t reliably match. This likely yields false negatives. Consider switching to participants:@domain for the domain-based search (and keep the date filtering).
- .search(`"to:@${escapedKqlDomain}"`)
+ .search(`participants:@${escapedKqlDomain}`)
- .search(`"from:@${escapedKqlDomain}"`)
+ .search(`participants:@${escapedKqlDomain}`)🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts (1)
27-36: Use the centralizedPUBLIC_EMAIL_DOMAINSconstant from@/utils/email.This test duplicates the public email domains list. Import and use
PUBLIC_EMAIL_DOMAINSfrom@/utils/emailinstead. Additionally, the domainslive.comandmsn.com(which this test includes) are not in the shared constant—consider adding them there if they represent a broader set of public providers.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use@/path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type filesImport specific lodash functions rather than entire lodash library to minimize bundle size (e.g.,
import groupBy from 'lodash/groupBy')
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor error handling in async operations
**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
**/*.{ts,tsx}: For early access feature flags, create hooks using the naming conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g.,inbox-cleaner,pricing-options-2)
Always define types for A/B test variant flags (e.g.,type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting
**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the!postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
apps/web/__tests__/**/*.test.ts
📄 CodeRabbit inference engine (.cursor/rules/llm-test.mdc)
apps/web/__tests__/**/*.test.ts: Place all LLM-related tests inapps/web/__tests__/directory
Use vitest imports (describe,expect,test,vi,beforeEach) in LLM test files
Mock 'server-only' module with empty object in LLM test files:vi.mock("server-only", () => ({}))
Set timeout constantconst TIMEOUT = 15_000;for LLM tests
Usedescribe.runIf(isAiTest)with environment variableRUN_AI_TESTS === "true"to conditionally run LLM tests
Useconsole.debug()for outputting generated LLM content in tests, e.g.,console.debug("Generated content:\n", result.content);
Prefer using existing helpers from@/__tests__/helpers.ts(getEmailAccount,getEmail,getRule,getMockMessage,getMockExecutedRule) instead of creating custom test data helpers
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
apps/web/{utils/ai,utils/llms,__tests__}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/llm.mdc)
LLM-related code must be organized in specific directories:
apps/web/utils/ai/for main implementations,apps/web/utils/llms/for core utilities and configurations, andapps/web/__tests__/for LLM-specific tests
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma'sselectoption. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. AllfindUnique/findFirstcalls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
AllfindManyqueries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g.,emailAccount: { id: emailAccountId }) to validate ownership
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
**/*.test.{ts,tsx}: Usevitestfor testing the application
Tests should be colocated next to the tested file with.test.tsor.test.tsxextension (e.g.,dir/format.tsanddir/format.test.ts)
Mockserver-onlyusingvi.mock("server-only", () => ({}))
Mock Prisma usingvi.mock("@/utils/prisma")and import the mock from@/utils/__mocks__/prisma
Usevi.clearAllMocks()inbeforeEachto clean up mocks between tests
Each test should be independent
Use descriptive test names
Mock external dependencies in tests
Do not mock the Logger
Avoid testing implementation details
Use test helpersgetEmail,getEmailAccount, andgetRulefrom@/__tests__/helpersfor mocking emails, accounts, and rules
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
AI tests must be placed in the
__tests__directory and are not run by default (they use a real LLM)
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/*.{tsx,ts,css}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
Implement responsive design with Tailwind CSS using a mobile-first approach
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-hidden="true"on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like<marquee>or<blink>
Only use thescopeprop on<th>elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include atitleelement for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
AssigntabIndexto non-interactive HTML elements witharia-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
!(pages/_document).{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
Don't use the next/head module in pages/_document.js on Next.js projects
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)
**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g.,import groupBy from 'lodash/groupBy')
Files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Design Gmail wrapper functions to be provider-agnostic to support future email providers like Outlook and ProtonMail
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Keep Gmail provider-specific implementation details isolated within the apps/web/utils/gmail/ directory
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers
Applied to files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules
Applied to files:
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts
🧬 Code graph analysis (1)
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts (2)
apps/web/utils/email/provider.ts (1)
createEmailProvider(14-32)apps/web/utils/email.ts (2)
extractEmailAddress(19-52)extractDomainFromEmail(73-91)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: test
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
apps/web/__tests__/e2e/cold-email/microsoft-cold-email.test.ts (1)
139-308: LGTM! Comprehensive E2E test coverage.The test suite provides excellent coverage of the
hasPreviousCommunicationsWithSenderOrDomainfunctionality for Microsoft Outlook:
- ✅ Properly uses
skipparameter from test context for dynamic skipping (addresses the previous review comment)- ✅ Tests both received and sent email detection
- ✅ Covers domain-based detection for company domains
- ✅ Includes edge cases (unknown senders, date boundaries)
- ✅ Clear console warnings when tests are skipped due to missing data
- ✅ Appropriate for E2E testing with real inbox data
Summary by CodeRabbit
New Features
Bug Fixes / Improvements
Removed
✏️ Tip: You can customize this high-level summary in your review settings.