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

# GitLab pull request testing

> Review a GitLab merge request on a preview URL, after merge, or against a mobile build.

Use this when the change is a GitLab merge request. To run a test plan you already have, use [GitLab regression testing](/regression-testing/gitlab).

## Set it up

<CardGroup cols={2}>
  <Card title="Merge request review" icon="gitlab" href="#merge-request-review">
    Automatic on a GitLab deployment, a `@qa.tech` comment, CI, or the API.
  </Card>

  <Card title="After merge" icon="code-merge" href="#after-merge">
    No preview environment. Review the merged request after the deploy job.
  </Card>

  <Card title="Mobile build" icon="mobile" href="#mobile-build">
    Upload the build in the merge request pipeline and pin the review to it.
  </Card>
</CardGroup>

## What works on GitLab

| Capability                                   | GitLab                                                                                                                  |
| :------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------- |
| Review on a preview URL, before merge        | Yes. Native deployments, a `@qa.tech` comment that includes the URL, CI, or the API.                                    |
| Review after merge, with no preview URL      | Yes. CI can review the merged request against staging or production after the deploy job.                               |
| Review a mobile build for that merge request | Yes. Upload the binary and call the change review API. The GitLab integration has to be connected.                      |
| Run a regression test plan                   | Not from this guide. GitLab CI can call the Start Run API. See [GitLab regression testing](/regression-testing/gitlab). |
| Block the pipeline until the review finishes | No. The merge request review posts a note. It does not fail the pipeline.                                               |

## What this does not do

* GitLab has no equivalent of the GitHub post-merge agent. A post-merge GitLab review tests the merged code. It does not promote tests into a regression suite.
* The review does not fail the pipeline. To gate a deploy on a test plan, use [GitLab regression testing](/regression-testing/gitlab).
* Envoyer is not a GitLab pull request review. It only starts a test plan after a deploy.

## Merge request review

Connect the repository on the [GitLab setup page](/configuration/gitlab#set-up-gitlab-mr-reviews) first. What a review does on every CI is on [How a review works](/pr-testing/overview#how-a-review-works).

When enabled, QA.tech can:

* detect merge request activity from your connected repository
* post an introduction or progress comment on merge requests
* run exploratory and end-to-end testing against your merge request
* publish a final results-based review comment back on the merge request

### What QA.tech posts on GitLab MRs

QA.tech posts comments and review notes on merge requests when the integration is triggered.

| Operation                    | When                          | Description                                                                                                                  |
| :--------------------------- | :---------------------------- | :--------------------------------------------------------------------------------------------------------------------------- |
| **MR comment (in progress)** | When the agent starts testing | Comment with link to the QA.tech conversation and details (project, MR number, branch, event type). Lets you track progress. |
| **MR review note**           | After tests complete          | MR note with verdict (Approved, Changes Requested, or Comment), summary, test results table, and evaluation details.         |

<Note>
  QA.tech uses your connected GitLab OAuth integration to call GitLab APIs. That
  means MR comments and review updates are posted through your connected GitLab
  integration identity.
</Note>

<Note>
  Automatic MR review triggering requires native GitLab deployment and
  environment signals. If your flow does not publish those signals, use the
  manual or CI-assisted `@qa.tech` trigger path in [Triggering a merge request
  review](#triggering-a-merge-request-review).
</Note>

### Triggering a merge request review

#### Option A: Automatic trigger for native GitLab deployments

If **Auto-run on Merge Requests** is enabled, QA.tech can auto-trigger reviews when deployment data is ready from native GitLab deployments and environments.

High-level behavior:

1. MR is opened or updated.
2. QA.tech checks if the MR commit is the latest and deployment(s) for that commit are ready.
3. If deployments are ready, QA.tech starts the review flow automatically.
4. If deployments are not ready, QA.tech can post a waiting comment (based on your setting) and wait for deployment readiness or a manual `@qa.tech` trigger.

#### Option B: Manual trigger using a GitLab comment

Comment on the merge request and mention `@qa.tech`.

Include the preview deployment URL in the same comment. QA.tech parses URLs from MR comments and uses that URL as deployment context for the review run. In practice, this is required for reliable review targeting.

Example:

```text theme={null}
@qa.tech https://preview.example.com
```

#### Option C: CI-assisted manual trigger

If your deployment process is custom, have CI post an MR comment that mentions `@qa.tech` and includes the preview URL. This gives you a consistent trigger pattern without requiring developers to comment manually each time.

#### Option D: API trigger (no `@qa.tech` comment)

Trigger the same MR review directly from CI by calling the [Start change review chat API](/api-reference/chat/start-change-review-chat) with `mode: "pr"`. This runs the same review agent as Options A, B, and C and posts the same native MR review note, but you control exactly when it fires and which environment it targets, with no `@qa.tech` comment required.

This requires the repository to be connected in **Settings → Integrations → GitLab** so the agent can read the MR and post the review note.

```yaml theme={null}
qatech_mr_review:
  stage: test
  only:
    - merge_requests
  script: |
    MR_URL="${CI_MERGE_REQUEST_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}"
    curl -sSf -X POST "https://api.qa.tech/v1/chat/change-review" \
      -H "Authorization: Bearer ${QA_TECH_API_TOKEN}" \
      -H "Content-Type: application/json" \
      -d "{
        \"mode\": \"pr\",
        \"prUrl\": \"${MR_URL}\",
        \"vcsProviderId\": \"gitlab\",
        \"applicationOverrides\": [{
          \"applicationShortId\": \"${QATECH_APP_SHORT_ID}\",
          \"environment\": { \"url\": \"${PREVIEW_URL}\" }
        }]
      }"
```

The review runs asynchronously; poll [Get chat conversation](/api-reference/chat/get-chat-conversation) if you want CI to wait for the verdict. See [Start change review chat API](/api-reference/chat/start-change-review-chat) for the full request schema.

<Note>
  Use this same API for **post-merge** reviews when you do not have per-MR
  preview environments. See [After merge](#after-merge).
</Note>

### Troubleshooting

**No review starts after MR open**

* Verify the repository is selected in GitLab integration settings.
* Check whether **Auto-run on Merge Requests** is enabled.
* Confirm deployment status is successful for the latest MR commit, or manually trigger with `@qa.tech`.
* If you are not using native GitLab deployment/environment signals, use the manual `@qa.tech` trigger with a preview URL.

**Draft MRs are skipped**

* Enable **Include Draft Merge Requests** if you want draft MRs reviewed.

**Manual trigger did nothing**

* Make sure the comment is on the merge request and includes `@qa.tech` (case-insensitive).
* If you expect preview-aware testing, include the preview URL in that same comment.

## After merge

If you do not have preview environments for merge requests, you can run QA.tech change reviews **after** merging to your main branch. This tests the changes from each MR against your staging or production environment once they're deployed.

**How it works**

1. An MR is merged to `main`/`dev`/`staging`.
2. Your deploy job deploys to staging/production.
3. CI extracts the MR number from the merge commit message.
4. The agent fetches the MR details (diff, changed files, description).
5. Tests run against your deployed environment.
6. Results are posted back on the merged MR as a note.

```yaml theme={null}
stages:
  - deploy
  - review

deploy:
  stage: deploy
  only:
    - main
  script:
    - echo "Your deploy steps..."

change-review:
  stage: review
  needs: [deploy]
  only:
    - main
  script: |
    MR_IID=$(echo "$CI_COMMIT_MESSAGE" | grep -oE '![0-9]+' | tail -1 | tr -d '!')
    if [ -z "$MR_IID" ]; then
      echo "No MR number found in commit message, skipping"
      exit 0
    fi
    MR_URL="${CI_PROJECT_URL}/-/merge_requests/${MR_IID}"
    curl -sSf -X POST "https://api.qa.tech/v1/chat/change-review" \
      -H "Authorization: Bearer ${QA_TECH_API_TOKEN}" \
      -H "Content-Type: application/json" \
      -d "{
        \"mode\": \"pr\",
        \"prUrl\": \"${MR_URL}\",
        \"vcsProviderId\": \"gitlab\",
        \"applicationOverrides\": [{
          \"applicationShortId\": \"${QATECH_APP_SHORT_ID}\",
          \"environment\": { \"url\": \"${STAGING_URL}\" }
        }],
        \"context\": \"This MR has already been merged and deployed. Test the changes and report any issues found.\"
      }"
```

**Setup**

1. Add `QA_TECH_API_TOKEN`, `QATECH_APP_SHORT_ID`, and `STAGING_URL` as **CI/CD → Variables** (mark the token **Protected** and **Masked**).
2. Set `QATECH_APP_SHORT_ID` to your application's short ID (found in **Settings → Applications & Envs**, e.g. `app_gXeBl2`).
3. Set `STAGING_URL` to your staging/production URL.
4. Make sure the `change-review` job runs after your deploy job completes (`needs: [deploy]`).
5. Connect the repository in **Settings → Integrations → GitLab** so the agent can read the MR and post the review note.

**Notes**

* GitLab's default merge commit message ends with `See merge request namespace/project!123`. The script extracts the last `!<number>` token, so it assumes the MR reference is at the end of the message.
* If you use squash merges with a custom template, include `%{reference}` in the template so the MR reference is present in the commit message.
* We extract the MR number from the commit message because `CI_MERGE_REQUEST_IID` is only set in merge request pipelines, not on push-to-`main`.
* Direct pushes to `main` without an MR are skipped automatically.
* Results are posted back on the merged MR as a note, since the MR is already merged.

<Note>
  No MR reference in your commits? Use `mode: "rawChanges"` instead and pass a
  `changes` object with `changeDescription` and a git `diff` computed in CI. See
  the [Start Change Review Chat
  reference](/api-reference/chat/start-change-review-chat).
</Note>

## Mobile build

Store `QA_TECH_API_TOKEN` as a CI/CD variable. Upload the build, then start a change review. Change reviews need the repository connected under **Settings → Integrations → GitLab**.

```yaml theme={null}
qatech_mobile_mr:
  stage: test
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script: |
    APP_ID="app_gXeBl2"
    BUILD_FILE="app/build/outputs/apk/debug/app-debug.apk"
    FILE_NAME=$(basename "$BUILD_FILE")

    UPLOAD_RESPONSE=$(curl -sSf -X POST "https://api.qa.tech/v1/applications/$APP_ID/builds/upload-url" \
      -H "Authorization: Bearer $QA_TECH_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d "{\"fileName\": \"$FILE_NAME\"}")
    UPLOAD_URL=$(echo "$UPLOAD_RESPONSE" | jq -r '.uploadUrl')
    BUILD_TOKEN=$(echo "$UPLOAD_RESPONSE" | jq -r '.buildToken')
    curl -sSf -X PUT "$UPLOAD_URL" \
      --upload-file "$BUILD_FILE" \
      -H "Content-Type: application/octet-stream"
    BUILD_RESPONSE=$(curl -sSf -X POST "https://api.qa.tech/v1/applications/$APP_ID/builds" \
      -H "Authorization: Bearer $QA_TECH_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d "{\"platform\": \"android\", \"buildToken\": \"$BUILD_TOKEN\"}")
    BUILD_SHORT_ID=$(echo "$BUILD_RESPONSE" | jq -r '.applicationBuildShortId')

    MR_URL="${CI_MERGE_REQUEST_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}"
    curl -sSf -X POST "https://api.qa.tech/v1/chat/change-review" \
      -H "Authorization: Bearer $QA_TECH_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d "{
        \"mode\": \"pr\",
        \"prUrl\": \"$MR_URL\",
        \"vcsProviderId\": \"gitlab\",
        \"applicationOverrides\": [{
          \"applicationShortId\": \"$APP_ID\",
          \"environment\": { \"applicationBuildShortId\": \"$BUILD_SHORT_ID\" }
        }]
      }"
```

To run a fixed plan instead of a change review, call [Start Run](/api-reference/runs/start-test-run) with `testPlanShortId` and the same `applications` override. Poll [Get Run](/api-reference/runs/get-run) if the job should fail on test failure. See [Mobile regression testing](/regression-testing/agents/mobile).
