Metadata-Version: 2.4
Name: squish-qatouch
Version: 1.1.0
Summary: QA Touch reporter for Squish (Froglogic/Qt) and pytest - uploads Squish XML, Squish JUnit or pytest --junitxml results to QA Touch, linking by case ID or title and auto-creating cases and test runs.
Author: UjjwalaMeena
License: ISC
Project-URL: Homepage, https://github.com/ujjwala91/squish-qatouch-py
Project-URL: Repository, https://github.com/ujjwala91/squish-qatouch-py
Project-URL: Issues, https://github.com/ujjwala91/squish-qatouch-py/issues
Keywords: squish,froglogic,qt,pytest,junit,qatouch,reporter,test-management,qa
Classifier: Programming Language :: Python :: 3
Classifier: Framework :: Pytest
Classifier: License :: OSI Approved :: ISC License (ISCL)
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.10
Description-Content-Type: text/markdown

﻿# squish-qatouch

> QA Touch reporter for **Squish** (Froglogic / Qt Group) and **pytest** — pure Python, zero dependencies.
> Reads your result file and uploads it to QA Touch: links each result to its case by case ID or title,
> creates missing modules, test cases, milestones and test runs, or updates an existing run.

## Supported result formats

| Format | How to generate | Detected as |
|--------|----------------|-------------|
| **Squish native XML** | `squishrunner --reportgen xml,results.xml` | Squish |
| **Squish JUnit XML** | `squish2junit results/ junit.xml` | Squish |
| **pytest JUnit XML** | `pytest --junitxml=junit.xml` | pytest |

Auto-detected at runtime — just point `--results` at the file. pytest is recognised by
`<testsuite name="pytest">`; force either with `--framework squish|pytest`.

Squish: works with all script languages (Python, JavaScript, Perl, Ruby, Tcl) — `squishrunner`
always produces the same XML format.

## Installation

```bash
pip install squish-qatouch
```

Requires **Python >= 3.10**. No third-party dependencies.

Installs two commands — the same tool with different defaults:

| Command | Use for |
|---|---|
| `squish-qatouch` | Squish results (pytest results are auto-detected too) |
| `pytest-qatouch-upload` | pytest `--junitxml` results |

## Usage — Squish

```bash
# after squishrunner writes results.xml
squish-qatouch \
  --results   ./results/squish.xml \
  --domain    mycompany \
  --token     $QATOUCH_TOKEN \
  --project   PROJ \
  --assign    user-key \
  --milestone-name "Sprint 12"
```

## Usage — pytest

```bash
pytest --junitxml=junit.xml
pytest-qatouch-upload \
  --results   junit.xml \
  --domain    mycompany \
  --token     $QATOUCH_TOKEN \
  --project   PROJ \
  --assign    user-key
```

Tests are grouped into QA Touch modules by their pytest `classname` (e.g. `tests.test_login`,
`tests.test_cart.TestCart`).

Or via `python -m`:

```bash
python -m squish_qatouch --results results.xml --domain mycompany \
  --token $QATOUCH_TOKEN --project PROJ --assign user-key
```

## Usage — Python API

```python
from squish_qatouch import SquishQATouchReporter

reporter = SquishQATouchReporter(
    domain="mycompany",
    api_token="YOUR_TOKEN",
    project_key="PROJ",
    assign_to="user-key",
    results_file="./results/squish.xml",   # or a pytest junit.xml
    milestone_name="Sprint 12",            # created automatically if missing
)
reporter.run()
```

## Linking tests to cases by ID

Give a test the QA Touch case ID (the `TR0015`-style code shown in test runs) and its result goes to
that case, whatever the test's name. No case is ever created for an ID.

**Squish** — put the ID in the test case name: `tst_TR0015_login`.

**pytest** — use the marker (registered automatically when the package is installed):

```python
import pytest

@pytest.mark.qatouch("TR0015")
def test_login():
    ...

@pytest.mark.qatouch("TR0016", "TR0017")   # one test, several cases
def test_checkout():
    ...
```

or `record_property("qatouch", "TR0015")`, or the ID in the test name: `test_TR0015_login`.

Rules:

- The ID wins: a test with an ID goes to that case even if its name matches another case.
- In a name, the ID is `TR` plus at least 4 digits standing on its own (`tst_TR0015_login`,
  `test_x[TR0015]`); `TR4Calibration` is not an ID and `TR00150` is not `TR0015`.
- Several results for one ID (e.g. parametrized tests `test_TR0014_lang[de]`, `test_TR0014_lang[en]`)
  are merged: the worst status wins (failed > blocked > passed) and the failure messages are combined.
- An ID that matches no case is reported and skipped.
- Tests without an ID are matched by title and created as before.

## Uploading into an existing run

`--run-id <run-key>` (`test_run_key=` in Python) uploads into an existing test run instead of creating
a milestone and a new run — e.g. to put retest results into the original run.

- Results are matched to the run's cases by case ID, otherwise by title.
- Results whose case is not in the run are reported and skipped; nothing is created.
- `--assign`, `--milestone-*` and `--tag` are not needed.

```bash
squish-qatouch --results results.xml ... --assign user-key --run-key-file run_key.txt
squish-qatouch --results retest.xml --domain mycompany --token $QATOUCH_TOKEN --project PROJ \
  --run-id "$(cat run_key.txt)"
```

## All options

| Option | CLI flag | Default | Description |
|--------|----------|---------|-------------|
| `domain` | `--domain` | — | QA Touch domain |
| `api_token` | `--token` | — | QA Touch API token |
| `project_key` | `--project` | — | QA Touch project key |
| `assign_to` | `--assign` | — | User key to assign the run to (required unless `--run-id`) |
| `results_file` | `--results` | — | Path to Squish XML or JUnit XML (Squish or pytest) |
| `testsuite_id` | `--testsuite` | — | Pin all cases to one module key |
| `milestone_name` | `--milestone-name` | `"Squish Automation"` / `"Pytest Automation"` | Milestone name |
| `milestone_key` | `--milestone-key` | — | Use existing milestone key directly |
| `create_cases` | `--no-create-cases` | `True` | Auto-create missing test cases (tests without an ID) |
| `tag` | `--tag` | `"squish"` / `"pytest"` | Tag on the test run |
| `framework` | `--framework` | auto-detect | `squish` or `pytest` |
| `test_run_key` | `--run-id` | — | Upload into this existing run |
| `run_key_file` | `--run-key-file` | — | Write the key of the run the results went into |

Per framework, new runs are named `Squish Run <timestamp>` / `Pytest Run <timestamp>`, and new cases
get Squish- or pytest-specific descriptions and steps.

## CI example (GitHub Actions)

```yaml
- name: Run Squish tests
  run: |
    squishrunner --testsuite suite_MyApp --reportgen xml,results/squish.xml

- name: Set up Python
  uses: actions/setup-python@v5
  with:
    python-version: "3.12"

- name: Upload to QA Touch
  run: |
    pip install squish-qatouch
    squish-qatouch --results results/squish.xml \
      --domain mycompany --token ${{ secrets.QATOUCH_TOKEN }} \
      --project PROJ --assign user-key
```

For pytest, replace the test step with `pytest --junitxml=junit.xml` and upload with
`pytest-qatouch-upload --results junit.xml ...`.

## Development

```bash
pip install pytest
python -m pytest tests
```

## Changelog

### 1.1.0

- **New:** pytest support — `pytest --junitxml` results are auto-detected, grouped by `classname`,
  and get pytest defaults (`Pytest Run`, `Pytest Automation`, tag `pytest`). New `pytest-qatouch-upload` command.
- **New:** link tests to QA Touch cases by case ID: `TR0015` in the test name, or
  `@pytest.mark.qatouch("TR0015")` / `record_property`. Unknown IDs are skipped, never created.
- **New:** `--run-id` / `test_run_key` uploads into an existing test run; `--assign` is then optional.
- **New:** `--run-key-file` / `run_key_file` writes the key of the run the results went into.
- **New:** `--framework squish|pytest` to override detection.
- **Fix:** a JUnit `<failure/>` or `<error/>` without child elements (every pytest failure) was uploaded
  as passed; a Squish `FAIL` message without text likewise. Both are now failed.
- **Fix:** milestones are now read across all pages (10 per page). Before, a milestone beyond the first
  10 was not found and a duplicate was created on every upload.
- Unchanged for Squish: milestone and tag defaults, run naming (`Squish Run <timestamp>`), case texts,
  and title matching/creation for tests without an ID.

### 1.0.2

- **Fix:** `get_test_cases()` pagination now uses deduplication instead of `per_page`-based stop condition. The API returns variable item counts per page, which caused pagination to stop at page 1 even when more pages existed.
- **Fix:** `module_key` query parameter is silently ignored by the `/getAllTestCases` API. Filtering by module is now done client-side using `item["module_key"]`.

## License

ISC
