Skip to content

Conversation

@shige
Copy link
Member

@shige shige commented Oct 14, 2025

User description

Summary

Enforce admin role and Pro plan for team invitations.

Related Issue

None.

Changes

Add validation checks to sendInvitationsAction:

  • Verify current user has admin role before sending invitations
  • Verify current team is on Pro plan before allowing invitations

Testing

Other Information


PR Type

Enhancement


Description

  • Add admin role validation before sending team invitations

  • Add Pro plan requirement check for team invitation feature

  • Reorder user and team fetching logic for early validation


Diagram Walkthrough

flowchart LR
  A["sendInvitationsAction"] --> B["Check admin role"]
  B --> C["Verify Pro plan"]
  C --> D["Fetch current user"]
  D --> E["Send invitations"]
Loading

File Walkthrough

Relevant files
Enhancement
actions.ts
Add role and plan validation to invitation action               

apps/studio.giselles.ai/app/(main)/settings/team/actions.ts

  • Add getCurrentUserRole() check to verify admin permissions before
    sending invitations
  • Add isProPlan() validation to ensure team has Pro plan subscription
  • Reorder code to fetch current user after validation checks
  • Throw descriptive errors for unauthorized access and plan restrictions
+13/-1   

Note

Gate sendInvitationsAction behind admin role and Pro plan checks, throwing errors if unmet.

  • Team invitations:
    • Enforce admin-only access using getCurrentUserRole() in apps/studio.giselles.ai/app/(main)/settings/team/actions.ts.
    • Require Pro plan via isProPlan(currentTeam) before creating invitations.
    • Minor refactor: fetch currentUser after permission/plan checks.

Written by Cursor Bugbot for commit 0c10ab2. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features
    • Team invitations are now restricted to admins only.
    • Sending invitations requires the team to be on a Pro plan.
    • Earlier validation provides quicker feedback when permissions or plan requirements aren’t met.
    • Invitation creation and email delivery remain unchanged for eligible users.

Add validation checks to sendInvitationsAction:
- Verify current user has admin role before sending invitations
- Verify current team is on Pro plan before allowing invitations
@shige shige self-assigned this Oct 14, 2025
Copilot AI review requested due to automatic review settings October 14, 2025 14:18
@changeset-bot
Copy link

changeset-bot bot commented Oct 14, 2025

⚠️ No Changeset found

Latest commit: 0c10ab2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

💥 An error occurred when fetching the changed packages and changesets in this PR
Some errors occurred when validating the changesets config:
The package or glob expression "giselle-sdk" is specified in the `ignore` option but it is not found in the project. You may have misspelled the package name or provided an invalid glob expression. Note that glob expressions must be defined according to https://www.npmjs.com/package/micromatch.

@vercel
Copy link

vercel bot commented Oct 14, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
giselle Ready Ready Preview Comment Oct 14, 2025 2:23pm
ui Ready Ready Preview Comment Oct 14, 2025 2:23pm

@giselles-ai
Copy link

giselles-ai bot commented Oct 14, 2025

Finished running flow.

Step Status Updated(UTC)
1 Oct 14, 2025 2:18pm
2 Oct 14, 2025 2:21pm
3 Oct 14, 2025 2:24pm
4 Oct 14, 2025 2:24pm

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds access control and plan validation to team invitations by restricting invitation sending to admin users on Pro plans only.

  • Validates that the current user has admin role before allowing invitations
  • Ensures the team is on a Pro plan before permitting invitation functionality
  • Reorganizes the function flow to perform validations before proceeding with invitation logic

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.


const currentTeam = await fetchCurrentTeam();
if (!isProPlan(currentTeam)) {
throw new Error("Team invitations require a Pro plan");
Copy link

Copilot AI Oct 14, 2025

Choose a reason for hiding this comment

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

The error message should be more descriptive and include guidance on how to upgrade. Consider: 'Team invitations are only available on Pro plans. Please upgrade your plan to send invitations.'

Suggested change
throw new Error("Team invitations require a Pro plan");
throw new Error("Team invitations are only available on Pro plans. Please upgrade your plan to send invitations.");

Copilot uses AI. Check for mistakes.
!currentUserRoleResult.success ||
currentUserRoleResult.data !== "admin"
) {
throw new Error("Only admin users can send invitations");
Copy link

Copilot AI Oct 14, 2025

Choose a reason for hiding this comment

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

The error message should be more user-friendly and descriptive. Consider: 'You must be a team admin to send invitations. Please contact your team admin for assistance.'

Suggested change
throw new Error("Only admin users can send invitations");
throw new Error("You must be a team admin to send invitations. Please contact your team admin for assistance.");

Copilot uses AI. Check for mistakes.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 14, 2025

Walkthrough

Adds admin-role authorization and Pro plan checks to sendInvitationsAction before fetching the current user. On failure, the action throws early. If checks pass, it proceeds with the existing per-email invitation creation, email dispatch, and error aggregation logic.

Changes

Cohort / File(s) Summary
Permissions and plan gating for invitations
apps/studio.giselles.ai/app/(main)/settings/team/actions.ts
Inserted admin check via getCurrentUserRole; added Pro plan enforcement for current team; reordered current user retrieval to follow new gates; preserved invitation creation/sending and result aggregation behavior.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant A as sendInvitationsAction
  participant R as getCurrentUserRole
  participant P as getCurrentTeamPlan
  participant C as getCurrentUser
  participant I as createInvitation
  participant E as sendEmail

  U->>A: invoke with email list
  A->>R: fetch current user role
  R-->>A: role
  alt Not Admin
    A-->>U: throw "not authorized"
  else Admin
    A->>P: fetch team plan
    P-->>A: plan (Pro/Other)
    alt Not Pro
      A-->>U: throw "plan not eligible"
    else Pro
      A->>C: get current user
      C-->>A: user
      loop for each email
        A->>I: create invitation
        I-->>A: invitation|error
        alt created
          A->>E: send invitation email
          E-->>A: sent|error
        end
      end
      A-->>U: aggregated results
    end
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested labels

Review effort 4/5

Suggested reviewers

  • satococoa

Poem

A bunny with badges, ears held high,
Checks roles and plans before invites fly.
If you’re Pro and admin—hoppity go!
Else, thump-thump: a courteous “no.”
Emails dispatched, tails a-twirl—
Governance snug as a carrot curl. 🌟🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description includes the required headings but leaves the Testing and Other Information sections as empty placeholders and contains additional headings not defined in the template, resulting in incomplete coverage of required information. Please fill in the Testing section with actual steps and results, provide relevant details under Other Information, and remove or integrate any non-template headings to match the required description template.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly states the primary change by describing the enforcement of an admin role and a Pro plan for sending team invitations, uses conventional commit style, and is concise and specific to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/enforce-admin-and-pro-plan-for-team-invitations

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-merge-for-open-source
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Information disclosure

Description: Throwing generic Error messages with specific authorization details could expose role/plan
constraints to clients if surfaced directly; ensure these messages are not leaked to end
users or mapped to safe responses.
actions.ts [623-634]

Referred Code
const currentUserRoleResult = await getCurrentUserRole();
if (
	!currentUserRoleResult.success ||
	currentUserRoleResult.data !== "admin"
) {
	throw new Error("Only admin users can send invitations");
}

const currentTeam = await fetchCurrentTeam();
if (!isProPlan(currentTeam)) {
	throw new Error("Team invitations require a Pro plan");
}
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
No custom compliance provided

Follow the guide to enable custom compliance check.

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-merge-for-open-source
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Avoid redundant calls to fetch team data

To improve performance, refactor sendInvitationsAction to call
fetchCurrentTeam() only once. Pass the resulting currentTeam object as an
argument to getCurrentUserRole() to avoid a redundant data fetch.

apps/studio.giselles.ai/app/(main)/settings/team/actions.ts [619-645]

 export async function sendInvitationsAction(
 	emails: string[],
 	role: TeamRole,
 ): Promise<SendInvitationsResult> {
-	const currentUserRoleResult = await getCurrentUserRole();
+	const currentTeam = await fetchCurrentTeam();
+
+	const currentUserRoleResult = await getCurrentUserRole(currentTeam);
 	if (
 		!currentUserRoleResult.success ||
 		currentUserRoleResult.data !== "admin"
 	) {
 		throw new Error("Only admin users can send invitations");
 	}
 
-	const currentTeam = await fetchCurrentTeam();
 	if (!isProPlan(currentTeam)) {
 		throw new Error("Team invitations require a Pro plan");
 	}
 
 	const currentUser = await fetchCurrentUser();
-	const currentTeam = await fetchCurrentTeam();
 
 	const invitationPromises = emails.map(
 		async (email): Promise<InvitationResult> => {
 			let invitation: Invitation | null = null;
 			try {
 				invitation = await createInvitation(
 					email,
 					role,
 					currentTeam,
 ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a performance inefficiency where fetchCurrentTeam() is called redundantly, once in getCurrentUserRole() and again in sendInvitationsAction. The proposed refactoring to fetch the team data once and pass it as an argument is a valid optimization.

Low
Learned
best practice
Replace throws with structured failures

Avoid throwing generic errors in server actions; return a structured failure
result so the UI can render proper states and avoid hard errors.

apps/studio.giselles.ai/app/(main)/settings/team/actions.ts [623-634]

 const currentUserRoleResult = await getCurrentUserRole();
-if (
-	!currentUserRoleResult.success ||
-	currentUserRoleResult.data !== "admin"
-) {
-	throw new Error("Only admin users can send invitations");
+if (!currentUserRoleResult.success || currentUserRoleResult.data !== "admin") {
+  return { success: false, invited: [], failed: emails.map((e) => ({ email: e, error: "Only admin users can send invitations" })) };
 }
 
 const currentTeam = await fetchCurrentTeam();
 if (!isProPlan(currentTeam)) {
-	throw new Error("Team invitations require a Pro plan");
+  return { success: false, invited: [], failed: emails.map((e) => ({ email: e, error: "Team invitations require a Pro plan" })) };
 }
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Use framework-appropriate error/empty-state fallbacks instead of throwing during server action flows; prefer guard clauses that return structured results over throwing generic errors.

Low
  • More

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b0f9ab and 0c10ab2.

📒 Files selected for processing (1)
  • apps/studio.giselles.ai/app/(main)/settings/team/actions.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development-guide.mdc)

**/*.{ts,tsx}: Use Biome for formatting with tab indentation and double quotes
Follow organized imports pattern (enabled in biome.json)
Use TypeScript for type safety; avoid any types
Use Next.js patterns for web applications
Use async/await for asynchronous code rather than promises
Error handling: use try/catch blocks and propagate errors appropriately
Use kebab-case for all filenames (e.g., user-profile.ts)
Use camelCase for variables, functions, and methods (e.g., userEmail)
Use prefixes like is, has, can, should for boolean variables and functions for clarity
Use verbs or verb phrases that clearly indicate purpose for function naming (e.g., calculateTotalPrice(), not process())

If breaking changes are introduced in new AI SDK versions, update code to accommodate those changes

**/*.{ts,tsx}: Avoid using the any type in TypeScript
Use async/await for asynchronous code and include proper error handling
Variables and functions should be camelCase
Boolean variables and functions should use is/has/can/should prefixes where appropriate
Function names should clearly indicate their purpose

Files:

  • apps/studio.giselles.ai/app/(main)/settings/team/actions.ts
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-guide.mdc)

All filenames should use kebab-case (lowercase with hyphens)

Files:

  • apps/studio.giselles.ai/app/(main)/settings/team/actions.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-guide.mdc)

**/*.{js,jsx,ts,tsx}: React components and classes should use PascalCase
Variables, functions, and methods should use camelCase
Use verbs or verb phrases for function names; names should clearly indicate what the function does; avoid ambiguous names that could lead to misuse
Use nouns or noun phrases for variable names; names should describe what the variable represents; avoid single-letter variables except in very short scopes
Use prefixes like 'is', 'has', 'can', 'should' for both variables and functions returning boolean values; make the true/false meaning clear

Files:

  • apps/studio.giselles.ai/app/(main)/settings/team/actions.ts
⏰ 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). (1)
  • GitHub Check: check
🔇 Additional comments (2)
apps/studio.giselles.ai/app/(main)/settings/team/actions.ts (2)

636-636: Efficient optimization by deferring user fetch.

Moving fetchCurrentUser after the authorization checks avoids an unnecessary database call when permission checks fail. The user data is still correctly passed to createInvitation on line 646.


623-629: Add missing Pro plan check to resendInvitationAction
invite-member-dialog handles thrown errors from sendInvitationsAction. resendInvitationAction currently only enforces admin role—mirror the Pro plan check from sendInvitationsAction for consistency.

Comment on lines 631 to +634
const currentTeam = await fetchCurrentTeam();
if (!isProPlan(currentTeam)) {
throw new Error("Team invitations require a Pro plan");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Pro plan validation is correct, but resendInvitationAction lacks the same check.

The Pro plan check appropriately restricts team invitations to Pro plan teams, consistent with the PR objective.

However, resendInvitationAction (lines 732-773) creates a new invitation (line 757) without validating the Pro plan. This inconsistency allows non-Pro teams to bypass the restriction by resending existing invitations.

Add the Pro plan check to resendInvitationAction after the admin check:

export async function resendInvitationAction(
	_prevState: ActionResult | undefined,
	formData: FormData,
): Promise<ActionResult> {
	const token = formData.get("token") as string;
	try {
		// Check if current user is admin
		const currentUserRoleResult = await getCurrentUserRole();
		if (
			!currentUserRoleResult.success ||
			currentUserRoleResult.data !== "admin"
		) {
			throw new Error("Only admin users can resend invitations");
		}

		const invitations = await listInvitations();
		const invitation = invitations.find((inv) => inv.token === token);
		if (!invitation) {
			throw new Error("Invitation not found");
		}
		// 1. revoke existing invitation
		await revokeInvitation(token);
		// 2. create new invitation
		const currentTeam = await fetchCurrentTeam();
+		if (!isProPlan(currentTeam)) {
+			throw new Error("Team invitations require a Pro plan");
+		}
		const currentUser = await fetchCurrentUser();
		const newInvitation = await createInvitation(
			invitation.email,
			invitation.role,
			currentTeam,
			currentUser,
		);
		// 3. send invitation email
		await sendInvitationEmail(newInvitation);
		revalidatePath("/settings/team/members");
		return { success: true };
	} catch (e: unknown) {
		return {
			success: false,
			error: e instanceof Error ? e.message : "Unknown error",
		};
	}
}

@giselles-ai
Copy link

giselles-ai bot commented Oct 14, 2025

🔍 QA Testing Assistant by Giselle

📋 Manual QA Checklist

Based on the changes in this PR, here are the key areas to test manually:

  • [Authentication/Authorization]: Verify that a user with the admin role on a Pro plan can successfully send a team invitation. (Steps: Log in as admin on Pro, navigate to team settings, enter email, click send. Expected: Success message, invitation sent.)
  • [Access Control - Role]: Verify that a user with a non-admin role (e.g., Member) on a Pro plan is blocked from sending team invitations. (Steps: Log in as member on Pro, navigate to team settings, attempt to send invitation. Expected: Error message "Only admin users can send invitations", invitation not sent.)
  • [Access Control - Plan]: Verify that a user with the admin role on a non-Pro plan (e.g., Free plan) is blocked from sending team invitations. (Steps: Log in as admin on Free, navigate to team settings, attempt to send invitation. Expected: Error message "Team invitations require a Pro plan", invitation not sent.)
  • [UI/UX]: Ensure that error messages displayed for blocked invitations are clear, concise, and informative, guiding the user on why the action failed.
  • [UI/UX]: Check if any UI elements related to sending invitations (e.g., the "Send Invitation" button) are appropriately disabled or hidden for users who should not have access, if applicable.

✨ Prompt for AI Agents

Use the following prompts with Cursor or Claude Code to automate E2E testing:

📝 E2E Test Generation Prompt
## **To: AI Coding Assistant**
## **From: Expert QA Engineer**
## **Subject: Generate E2E Tests for Team Invitation Access Control**

You are an expert QA engineer tasked with writing automated end-to-end tests using Playwright and Playwright MCP. The goal is to validate new business logic that restricts the team invitation feature based on user role and subscription plan.

Please analyze the following context and instructions to generate a comprehensive, CI-ready Playwright test suite.

---

## **Prompt to Generate E2E Tests**

### 1. Context Summary

The pull request introduces backend validation to the "Send Team Invitations" feature. This change enforces two new rules:

1.  Only users with the `admin` role can send invitations.
2.  The team must be on a `Pro plan` to use the invitation feature.

These checks are performed in the `sendInvitationsAction` server action. Your tests must trigger this action from the user interface and verify that the application behaves correctly under different conditions.

*   **Key User Flow:** `Go to Team Settings page -> Enter one or more email addresses into the invitation form -> Click "Send Invitations" button.`
*   **Critical Path:** The submission of the invitation form and the subsequent UI feedback (success or error notification).

### 2. Test Scenarios

Create a new Playwright test file to cover the following scenarios. Each scenario must simulate a different user context (role and plan).

**Happy Path:**

*   **Scenario 1: Admin on a Pro Plan**
    *   **Given** a user is logged in as an `admin`.
    *   **And** the current team is on a `Pro plan`.
    *   **When** the user navigates to the team settings page and submits a valid email for invitation.
    *   **Then** the invitation should be sent successfully, and a success notification should be displayed.

**Edge Cases & Negative Paths:**

*   **Scenario 2: Admin on a Free Plan**
    *   **Given** a user is logged in as an `admin`.
    *   **And** the current team is on a `Free plan`.
    *   **When** the user attempts to send an invitation.
    *   **Then** the action should fail, and an error message like `"Team invitations require a Pro plan"` should be displayed.
    *   **Bonus:** Assert that the "Send Invitations" button is disabled if the UI reflects this state change.

*   **Scenario 3: Non-Admin (Member) on a Pro Plan**
    *   **Given** a user is logged in as a `member` (non-admin).
    *   **And** the current team is on a `Pro plan`.
    *   **When** the user attempts to send an invitation.
    *   **Then** the action should fail, and an error message like `"Only admin users can send invitations"` should be displayed.
    *   **Bonus:** Assert that the "Send Invitations" button is disabled.

*   **Scenario 4: Non-Admin (Member) on a Free Plan**
    *   **Given** a user is logged in as a `member` (non-admin).
    *   **And** the current team is on a `Free plan`.
    *   **When** the user attempts to send an invitation.
    *   **Then** the action should fail, and an appropriate error message (likely the role-based one, `"Only admin users can send invitations"`) should be displayed.

### 3. Playwright Implementation Instructions

Use the following guidelines to implement the tests.

*   **Setup:** Use `test.beforeEach` to navigate to the team settings page (`/settings/team`) and set up API mocks for each test case.
*   **Mocking:** The backend logic is in a server action. The easiest way to test this is by mocking the API calls that fetch user and team data.
    *   Mock the response for `getCurrentUserRole()` to return `{ success: true, data: 'admin' }` or `{ success: true, data: 'member' }`.
    *   Mock the response for `fetchCurrentTeam()` to return a team object where `isProPlan()` evaluates to `true` or `false`.
*   **Selectors:** Use `data-testid` attributes for robust selectors. If they don't exist, recommend their addition.
    *   Invitation Email Input: `page.getByTestId('team-settings-invite-input')`
    *   Send Button: `page.getByTestId('team-settings-send-invitations-button')`
    *   Success Notification/Toast: `page.getByTestId('toast-success-message')`
    *   Error Notification/Toast: `page.getByTestId('toast-error-message')`
*   **Interactions:**
    *   Use `page.goto('/settings/team')` for navigation.
    *   Use `page.getByTestId(...).fill('[email protected]')` to enter an email.
    *   Use `page.getByTestId(...).click()` to submit the form.
*   **Assertions:** Use `expect` to verify outcomes.
    *   `await expect(page.getByTestId('toast-success-message')).toBeVisible();`
    *   `await expect(page.getByTestId('toast-error-message')).toContainText('Team invitations require a Pro plan');`
    *   `await expect(page.getByTestId('toast-error-message')).toContainText('Only admin users can send invitations');`
    *   `await expect(page.getByTestId('team-settings-send-invitations-button')).toBeDisabled();` (for bonus checks)

### 4. MCP Integration Guidelines

Structure the tests to be compatible with Playwright MCP for handling API mocks.

*   **Mock Configuration:** Define mocks in a separate file (e.g., `mcp-mocks.ts`) that can be loaded by MCP.

    ```typescript
    // Example: mcp-mocks.ts
    import { Mock } from '@playwright/mcp';

    export const adminUserMock: Mock = {
        url: '/api/user/role', // Use the actual API endpoint
        method: 'GET',
        response: {
            body: { success: true, data: 'admin' },
        },
    };

    export const memberUserMock: Mock = {
        url: '/api/user/role',
        method: 'GET',
        response: {
            body: { success: true, data: 'member' },
        },
    };

    export const proPlanTeamMock: Mock = {
        url: '/api/team/current', // Use the actual API endpoint
        method: 'GET',
        response: {
            // Include whatever structure makes isProPlan() return true
            body: { id: 'team-1', plan: 'pro' },
        },
    };

    export const freePlanTeamMock: Mock = {
        url: '/api/team/current',
        method: 'GET',
        response: {
            body: { id: 'team-2', plan: 'free' },
        },
    };
    ```

*   **Test Implementation with MCP:** Within your test file, use MCP's `mcp` fixture to apply mocks for each scenario.

    ```typescript
    // Example: team-invitations.spec.ts
    import { test, expect } from '@playwright/test';
    import { mcp } from '@playwright/mcp';
    import { adminUserMock, proPlanTeamMock, freePlanTeamMock, memberUserMock } from './mcp-mocks';

    test.describe('Team Invitations Access Control', () => {
        test('should allow admin on Pro plan to send invitations', async ({ page }) => {
            mcp.addMocks([adminUserMock, proPlanTeamMock]);
            // ... test implementation
        });

        test('should prevent admin on Free plan from sending invitations', async ({ page }) => {
            mcp.addMocks([adminUserMock, freePlanTeamMock]);
            // ... test implementation
        });
    });
    ```

### 5. CI-Ready Code Requirements

Ensure the generated code is clean, maintainable, and ready for a CI/CD pipeline.

*   **File Structure:** Create a new test file at `tests/e2e/settings/team-invitations.spec.ts`.
*   **Test Organization:**
    *   Use `test.describe('Team Invitations Access Control', () => { ... });` to group all related tests.
    *   Use `test.beforeEach` for common setup logic like navigation.
*   **Naming Conventions:** Use descriptive test names that clearly state the intent, e.g., `test('should display error for non-admin user on a Pro plan')`.
*   **Atomicity:** Each test must be independent. State changes in one test should not affect another. Using `mcp.addMocks()` at the beginning of each test ensures this.
*   **Parallelization:** Because the tests are atomic and use specific mocks, they are safe to be run in parallel by the Playwright test runner. No special configuration is needed other than following the atomic design pattern.

Please proceed with generating the Playwright test code based on these instructions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants