> ## Documentation Index
> Fetch the complete documentation index at: https://docs.morphllm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# GitHub Actions

> AI-powered browser testing for preview deployments

<Warning>
  **Beta Feature** — Browser automation is currently in beta. Please report any issues to [founders@morphllm.com](mailto:founders@morphllm.com).
</Warning>

Automatically test your preview deployments with Morph's AI-powered browser automation. When a PR is opened, Morph tests your preview URL and posts results directly to the PR as a comment.

## Quick Start

```yaml theme={null}
- uses: morphllm/preview-test-action@v1
  with:
    api-key: ${{ secrets.MORPH_API_KEY }}
    preview-url: ${{ steps.deploy.outputs.url }}
    instructions: Test the checkout flow
```

<Tip>
  You can also tag `@morph` or `@glance` in a PR comment to trigger a test without any CI config.
</Tip>

## Setup

<Steps>
  <Step title="Install the Morph GitHub App">
    Go to [morphllm.com/dashboard/integrations/github](https://morphllm.com/dashboard/integrations/github) and install the app on your repository. This allows Morph to post test results as PR comments.
  </Step>

  <Step title="Get your API key">
    Get your API key from [morphllm.com/dashboard/api-keys](https://morphllm.com/dashboard/api-keys).
  </Step>

  <Step title="Add secrets to your repository">
    Go to your repository's **Settings → Secrets and variables → Actions** and add:

    * `MORPH_API_KEY` - Your Morph API key
    * Any test credentials your app needs (see [Testing with Credentials](#testing-with-credentials))
  </Step>
</Steps>

## Inputs & Outputs

### Inputs

| Input          | Required | Description                            |
| -------------- | -------- | -------------------------------------- |
| `api-key`      | Yes      | Your Morph API key                     |
| `preview-url`  | Yes      | Preview deployment URL to test         |
| `instructions` | No       | Custom testing instructions for the AI |

### Outputs

| Output    | Description                      |
| --------- | -------------------------------- |
| `test-id` | The ID of the triggered test     |
| `status`  | The status of the test (started) |

## Testing with Credentials

For apps that require login, pass credentials via GitHub secrets and reference them in your instructions using `x_user` and `x_pass` placeholders.

```yaml theme={null}
name: Preview Test
on: pull_request

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ steps.deploy.outputs.url }}
          instructions: |
            1. Go to the login page
            2. Log in with username x_user and password x_pass
            3. Verify the dashboard loads successfully
            4. Check that the user's profile shows the correct email
        env:
          TEST_USERNAME: ${{ secrets.TEST_USERNAME }}
          TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
```

<Warning>
  **Never hardcode credentials** in your workflow file. Always use GitHub secrets and environment variables.
</Warning>

### Setting Up Test Credentials

1. Go to **Settings → Secrets and variables → Actions**
2. Add repository secrets:
   * `TEST_USERNAME` - Test account email/username
   * `TEST_PASSWORD` - Test account password
   * `ADMIN_USERNAME` - Admin test account (if needed)
   * `ADMIN_PASSWORD` - Admin test password (if needed)

## Testing Multiple User Roles

Test different user types by running parallel jobs with different credentials:

```yaml theme={null}
name: Preview Tests - All User Roles
on: pull_request

jobs:
  test-regular-user:
    runs-on: ubuntu-latest
    steps:
      - name: Wait for Preview
        id: preview
        run: echo "url=${{ github.event.deployment.payload.web_url }}" >> $GITHUB_OUTPUT

      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ steps.preview.outputs.url }}
          instructions: |
            Test as a regular user:
            1. Log in with x_user / x_pass
            2. Verify you can view the dashboard
            3. Verify you CANNOT access /admin
            4. Create a new post and verify it appears
            5. Edit your profile settings
        env:
          TEST_USERNAME: ${{ secrets.USER_EMAIL }}
          TEST_PASSWORD: ${{ secrets.USER_PASSWORD }}

  test-admin-user:
    runs-on: ubuntu-latest
    steps:
      - name: Wait for Preview
        id: preview
        run: echo "url=${{ github.event.deployment.payload.web_url }}" >> $GITHUB_OUTPUT

      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ steps.preview.outputs.url }}
          instructions: |
            Test as an admin user:
            1. Log in with x_user / x_pass
            2. Verify you can access /admin
            3. Verify the user management table loads
            4. Verify you can view analytics dashboard
            5. Check that admin-only actions are visible
        env:
          TEST_USERNAME: ${{ secrets.ADMIN_EMAIL }}
          TEST_PASSWORD: ${{ secrets.ADMIN_PASSWORD }}

  test-guest-user:
    runs-on: ubuntu-latest
    steps:
      - name: Wait for Preview
        id: preview
        run: echo "url=${{ github.event.deployment.payload.web_url }}" >> $GITHUB_OUTPUT

      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ steps.preview.outputs.url }}
          instructions: |
            Test as a guest (not logged in):
            1. Verify the homepage loads
            2. Verify you can browse public content
            3. Verify /dashboard redirects to login
            4. Verify the signup flow works
```

## Testing Multiple Flows

Run comprehensive test suites by testing different user journeys:

```yaml theme={null}
name: Comprehensive Preview Tests
on: pull_request

jobs:
  test-auth-flows:
    runs-on: ubuntu-latest
    steps:
      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ needs.deploy.outputs.url }}
          instructions: |
            Test authentication flows:
            1. Test signup with a new email
            2. Verify email validation errors show for invalid emails
            3. Test login with valid credentials (x_user / x_pass)
            4. Test login with wrong password shows error
            5. Test password reset flow (enter email, verify confirmation message)
            6. Test logout and verify redirect to homepage
        env:
          TEST_USERNAME: ${{ secrets.TEST_EMAIL }}
          TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

  test-checkout-flow:
    runs-on: ubuntu-latest
    steps:
      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ needs.deploy.outputs.url }}
          instructions: |
            Test the complete checkout flow:
            1. Browse to /products
            2. Add the first product to cart
            3. Add a second product to cart
            4. Go to cart and verify both items appear
            5. Apply discount code "TEST10" and verify discount applied
            6. Proceed to checkout
            7. Fill shipping form with test data
            8. Verify order summary shows correct totals

  test-responsive-design:
    runs-on: ubuntu-latest
    steps:
      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ needs.deploy.outputs.url }}
          instructions: |
            Test responsive design:
            1. Resize to mobile (375x667)
            2. Verify hamburger menu appears
            3. Open mobile menu and verify all links work
            4. Resize to tablet (768x1024)
            5. Verify layout adjusts appropriately
            6. Resize back to desktop (1920x1080)
            7. Verify full navigation is visible
```

## Platform Integrations

### Vercel

```yaml theme={null}
name: Test Vercel Preview
on:
  pull_request:
  deployment_status:

jobs:
  test:
    runs-on: ubuntu-latest
    if: github.event_name == 'deployment_status' && github.event.deployment_status.state == 'success'
    steps:
      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ github.event.deployment_status.target_url }}
          instructions: |
            Verify the deployment:
            1. Check homepage loads without errors
            2. Verify navigation works
            3. Test the main CTA button
```

### Netlify

```yaml theme={null}
name: Test Netlify Preview
on: pull_request

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Wait for Netlify
        uses: jakepartusch/wait-for-netlify-action@v1.4
        id: netlify
        with:
          site_name: your-site-name
          max_timeout: 300

      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ steps.netlify.outputs.url }}
          instructions: Verify homepage and navigation work correctly
```

### Railway

```yaml theme={null}
name: Test Railway Preview
on: pull_request

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Get Railway Preview URL
        id: railway
        run: |
          # Railway preview URLs follow this pattern
          echo "url=https://your-app-pr-${{ github.event.pull_request.number }}.up.railway.app" >> $GITHUB_OUTPUT

      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ steps.railway.outputs.url }}
          instructions: Test the application works correctly
```

### Custom Infrastructure (EKS, GKE, Self-hosted)

```yaml theme={null}
name: Test Custom Preview
on: pull_request

jobs:
  deploy-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy Preview
        id: deploy
        run: |
          # Your deployment script here
          # Example: Deploy to Kubernetes with PR-specific namespace
          kubectl apply -f k8s/ -n preview-pr-${{ github.event.pull_request.number }}
          echo "url=https://pr-${{ github.event.pull_request.number }}.preview.yourdomain.com" >> $GITHUB_OUTPUT

      - name: Wait for deployment
        run: sleep 30  # Or use a proper health check

      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ steps.deploy.outputs.url }}
          instructions: |
            Verify the deployment is working:
            1. Homepage loads successfully
            2. API health check returns 200
            3. Login flow works with test credentials
```

## Handling Third-Party Auth (Clerk, Auth0, Supabase)

Third-party auth providers may block automated browsers. Solutions:

### Option 1: Add Preview URL to Allowed Origins

Configure your auth provider to accept requests from preview URLs:

* **Clerk**: Dashboard → API Keys → Allowed origins
* **Auth0**: Applications → Settings → Allowed Origins
* **Supabase**: Authentication → URL Configuration

Add a wildcard pattern like `https://*.vercel.app` or your specific preview URL pattern.

### Option 2: Use Test/Development Mode

Many auth providers have development modes that are more permissive:

```yaml theme={null}
- uses: morphllm/preview-test-action@v1
  with:
    api-key: ${{ secrets.MORPH_API_KEY }}
    preview-url: ${{ steps.deploy.outputs.url }}
    instructions: |
      Note: This preview uses development auth mode.
      1. Log in with test credentials x_user / x_pass
      2. Verify dashboard access
  env:
    TEST_USERNAME: ${{ secrets.DEV_TEST_EMAIL }}
    TEST_PASSWORD: ${{ secrets.DEV_TEST_PASSWORD }}
```

### Option 3: Test Public Pages Only

For previews, you may choose to only test unauthenticated flows:

```yaml theme={null}
- uses: morphllm/preview-test-action@v1
  with:
    api-key: ${{ secrets.MORPH_API_KEY }}
    preview-url: ${{ steps.deploy.outputs.url }}
    instructions: |
      Test public pages only (auth tested separately):
      1. Verify homepage loads
      2. Check pricing page displays all tiers
      3. Verify contact form appears
      4. Test that /login page loads correctly
```

## Writing Effective Test Instructions

### Good Instructions

Be specific and actionable:

```yaml theme={null}
instructions: |
  Test the user signup flow:
  1. Click "Sign Up" in the header
  2. Enter email "test@example.com" in the email field
  3. Enter password "TestPass123!" in the password field
  4. Click the "Create Account" button
  5. Verify a success message appears
  6. Verify the user is redirected to /dashboard
```

### Bad Instructions

Avoid vague descriptions:

```yaml theme={null}
# Too vague - don't do this
instructions: Test the app and make sure it works
```

### Tips for Better Tests

* **Number your steps** - Makes it easier to identify where failures occur
* **Be explicit about expected outcomes** - "Verify X appears" rather than "check X"
* **Use specific selectors when helpful** - "Click the green 'Submit' button"
* **Include negative tests** - "Verify error message appears for invalid input"

## Conditional Testing

### Only Test on Specific Files Changed

```yaml theme={null}
name: Smart Preview Tests
on: pull_request

jobs:
  detect-changes:
    runs-on: ubuntu-latest
    outputs:
      frontend: ${{ steps.changes.outputs.frontend }}
      checkout: ${{ steps.changes.outputs.checkout }}
    steps:
      - uses: dorny/paths-filter@v2
        id: changes
        with:
          filters: |
            frontend:
              - 'src/components/**'
              - 'src/pages/**'
            checkout:
              - 'src/checkout/**'
              - 'src/cart/**'

  test-frontend:
    needs: detect-changes
    if: needs.detect-changes.outputs.frontend == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ needs.deploy.outputs.url }}
          instructions: Test homepage and navigation components

  test-checkout:
    needs: detect-changes
    if: needs.detect-changes.outputs.checkout == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ needs.deploy.outputs.url }}
          instructions: Test complete checkout flow with cart
```

### Skip Tests for Draft PRs

```yaml theme={null}
jobs:
  test:
    if: github.event.pull_request.draft == false
    runs-on: ubuntu-latest
    steps:
      - uses: morphllm/preview-test-action@v1
        # ...
```

## Complete Production Example

A full workflow with all best practices:

```yaml theme={null}
name: Preview Deployment Tests
on:
  pull_request:
    types: [opened, synchronize, reopened]
  deployment_status:

concurrency:
  group: preview-test-${{ github.head_ref }}
  cancel-in-progress: true

jobs:
  # Only run when deployment succeeds
  test-preview:
    if: |
      github.event_name == 'deployment_status' &&
      github.event.deployment_status.state == 'success'
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - name: Run Core Flow Tests
        uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ github.event.deployment_status.target_url }}
          instructions: |
            Test core user flows:

            ## Homepage
            1. Verify homepage loads within 3 seconds
            2. Check hero section displays correctly
            3. Verify main CTA button is visible

            ## Navigation
            4. Click each main nav link and verify page loads
            5. Test mobile menu at 375px width

            ## Authentication
            6. Go to /login
            7. Log in with x_user / x_pass
            8. Verify dashboard loads
            9. Verify user email shows in header
            10. Log out and verify redirect to homepage
        env:
          TEST_USERNAME: ${{ secrets.TEST_USER_EMAIL }}
          TEST_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}

      - name: Run Admin Tests
        uses: morphllm/preview-test-action@v1
        with:
          api-key: ${{ secrets.MORPH_API_KEY }}
          preview-url: ${{ github.event.deployment_status.target_url }}
          instructions: |
            Test admin functionality:
            1. Log in with admin credentials x_user / x_pass
            2. Navigate to /admin
            3. Verify admin dashboard loads
            4. Check user management table displays
            5. Verify analytics charts render
        env:
          TEST_USERNAME: ${{ secrets.ADMIN_EMAIL }}
          TEST_PASSWORD: ${{ secrets.ADMIN_PASSWORD }}
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Test results not appearing on PR" icon="comment-slash">
    **Cause**: Morph GitHub App not installed or lacks permissions.

    **Fix**:

    1. Install the app at [morphllm.com/dashboard/integrations/github](https://morphllm.com/dashboard/integrations/github)
    2. Ensure it has access to your repository
    3. Check the app has "Pull requests: Read and write" permission
  </Accordion>

  <Accordion title="Authentication errors" icon="key">
    **Cause**: Invalid or missing API key.

    **Fix**:

    1. Verify `MORPH_API_KEY` is set in repository secrets
    2. Check the key is valid at [morphllm.com/dashboard/api-keys](https://morphllm.com/dashboard/api-keys)
    3. Ensure you have available credits
  </Accordion>

  <Accordion title="Preview URL not accessible" icon="globe">
    **Cause**: Preview not deployed yet or URL incorrect.

    **Fix**:

    1. Add a wait/health check step before running tests
    2. Verify the preview URL is publicly accessible
    3. Check deployment logs for errors

    ```yaml theme={null}
    - name: Wait for preview
      run: |
        for i in {1..30}; do
          if curl -s -o /dev/null -w "%{http_code}" "${{ steps.deploy.outputs.url }}" | grep -q "200"; then
            echo "Preview is ready"
            exit 0
          fi
          sleep 10
        done
        echo "Preview not ready after 5 minutes"
        exit 1
    ```
  </Accordion>

  <Accordion title="Login not working" icon="user-lock">
    **Cause**: Third-party auth blocking automated browsers.

    **Fix**:

    * Add preview URL pattern to auth provider's allowed origins
    * Use development/test mode credentials
    * Test only public pages in preview tests

    See [Handling Third-Party Auth](#handling-third-party-auth-clerk-auth0-supabase) for details.
  </Accordion>

  <Accordion title="Tests timing out" icon="clock">
    **Cause**: Complex tests exceeding default timeout.

    **Fix**:

    1. Break complex tests into smaller focused tests
    2. Run tests in parallel jobs
    3. Increase job timeout: `timeout-minutes: 15`
  </Accordion>
</AccordionGroup>

## How It Works

1. **Your CI/CD deploys** to your infrastructure (Vercel, Netlify, EKS, etc.)
2. **Action triggers** and sends the preview URL to Morph
3. **Morph's AI browser** executes your test instructions
4. **Results posted** directly to your PR as a comment

The action uses the same [browser automation](/sdk/components/automation/browser/direct) engine as the SDK, optimized for CI/CD workflows.

## Requirements

* **Morph GitHub App** installed on your repository
* **Valid Morph API key** with available credits
* **Publicly accessible preview URL** (cannot test localhost)

## See Also

* [Browser Automation SDK](/sdk/components/automation/browser/direct) - Direct SDK usage with full control
* [Browser as Agent Tool](/sdk/components/automation/browser/tool) - Use in AI agent workflows
* [browser-use Python](/guides/browser-use) - Python SDK integration
