Skip to main content
Beta Feature — Browser automation is currently in beta. Please report any issues to founders@morphllm.com.
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

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

Setup

1

Install the Morph GitHub App

Go to morphllm.com/dashboard/integrations/github and install the app on your repository. This allows Morph to post test results as PR comments.
2

Get your API key

Get your API key from morphllm.com/dashboard/api-keys.
3

Add secrets to your repository

Go to your repository’s Settings → Secrets and variables → Actions and add:

Inputs & Outputs

Inputs

InputRequiredDescription
api-keyYesYour Morph API key
preview-urlYesPreview deployment URL to test
instructionsNoCustom testing instructions for the AI

Outputs

OutputDescription
test-idThe ID of the triggered test
statusThe 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.
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 }}
Never hardcode credentials in your workflow file. Always use GitHub secrets and environment variables.

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:
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:
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

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

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

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)

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:
- 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:
- 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:
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:
# 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

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

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:
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

Cause: Morph GitHub App not installed or lacks permissions.Fix:
  1. Install the app at morphllm.com/dashboard/integrations/github
  2. Ensure it has access to your repository
  3. Check the app has “Pull requests: Read and write” permission
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
  3. Ensure you have available credits
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
- 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
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 for details.
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

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 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