Zephyr Scale Integration
TestIntel integrates with Zephyr Scale for Jira Cloud to sync test cases and results.
Setup
1. Generate API token
Go to https://id.atlassian.com/manage-profile/security/api-tokens and create a new token. This is a separate JWT token from your Jira API token.
2. Set environment variables
$env:ZEPHYR_API_TOKEN="your-zephyr-jwt-token"
3. Configure config.yaml
zephyr:
api_token_env_var: ZEPHYR_API_TOKEN
base_url: https://api.zephyrscale.smartbear.com/v2
project_key: HR
For the EU region, use https://eu.api.zephyrscale.smartbear.com/v2 as the base_url.
4. Run schema discovery
testintel discover
This scans your Zephyr instance for test case statuses, execution statuses, and priorities. All Zephyr operations use these discovered mappings.
Usage
Zephyr sync is available via the Web UI Sync bar (Inventory tab) and API endpoints.
Web UI
- Go to the Inventory tab
- The Sync bar appears automatically when Zephyr is configured
- Use the ⬇ Zephyr Pull, ⬆ Zephyr Push, and ⬇ Zephyr Results buttons
- Push operations show real-time progress via SSE streaming
- Select specific tests with checkboxes before pushing to push only those tests
API
# Pull tests into inventory
curl -X POST http://localhost:8000/sync/zephyr/pull -H "x-api-key: your-key"
# Push inventory to Zephyr
curl -X POST http://localhost:8000/sync/zephyr/push -H "x-api-key: your-key"
# Push specific tests
curl -X POST "http://localhost:8000/sync/zephyr/push?test_ids=TC-0001,TC-0002" -H "x-api-key: your-key"
# Push local EDITS of already-synced tests back to Zephyr (two-way sync)
curl -X POST http://localhost:8000/sync/zephyr/push-updates -H "x-api-key: your-key"
# Push test results
curl -X POST http://localhost:8000/sync/zephyr/push-results -H "x-api-key: your-key"
# Pull test results
curl -X POST http://localhost:8000/sync/zephyr/pull-results -H "x-api-key: your-key"
Schema discovery (CLI)
testintel discover
This is a one-time setup command that scans your Zephyr instance and writes mappings to testintel_data/schema.yaml.
How it works
- Authentication: JWT bearer token via
Authorization: Bearer - API base:
https://api.zephyrscale.smartbear.com/v2 - Test cases: Created via REST. Steps are added separately via
POST /testcases/{key}/teststeps(Zephyr API doesn't accept steps in the create body) - Results: Require a Test Cycle. Push creates a cycle first, then adds executions
- Mapping: Pulled tests are tagged with
Zephyr-Importand the Zephyr key (e.g.HR-T1) for round-trip sync - Schema-driven: Priority and status mappings come from
testintel discover
Tags on pull
When you pull tests from Zephyr Scale, TestIntel adds tags automatically for traceability and round-trip sync:
| Tag | Source | Purpose |
|---|---|---|
Zephyr-Import | Always added | Identifies tests imported from Zephyr |
Zephyr-StepByStep | Test script type = Step-by-Step | Script format — structured steps |
Zephyr-PlainText | Test script type = Plain Text | Script format — freeform text |
Zephyr-BDD | Test script type = BDD | Script format — Gherkin/Cucumber |
| *(user labels)* | Zephyr labels field | Any labels assigned to the test in Zephyr |
If a pulled test triggers duplicate detection against existing inventory (≥80% name similarity), it also receives Needs Review - Potential Duplicate.
These tags are metadata only — the type field (E2E, Integration, etc.) is determined separately via label/tag scanning configured in config.yaml.
Reconciliation on pull (archived tests)
A Zephyr pull reconciles your inventory with what Zephyr returns:
- New / updated tests are added or merged into inventory (matched by Zephyr key).
- Tests missing from the pull (present in inventory with a Zephyr key, but not in the latest pull — e.g. archived or deleted in Zephyr) are soft-archived: they're tagged
Archivedand hidden from the default inventory view, but not deleted. Nothing is lost, and the action is reversible. - Reappearing tests (a previously-archived test that shows up in a later pull) are automatically un-archived.
Safety guard: if more than 50% of your Zephyr-sourced tests would be archived in a single pull, TestIntel skips archiving and logs a warning — this protects against a partial or failed pull wiping out large swaths of inventory. Re-run the pull once the source is healthy.
To permanently delete archived tests, remove them explicitly from the Inventory tab.
Status sync
When you update a test case's lifecycle status (Draft/Approved/Deprecated) in TestIntel, the change is automatically pushed back to Zephyr Scale if:
- The test has a Zephyr external key (i.e. it was pulled from Zephyr)
- Zephyr credentials are configured
This works for:
- Manual status changes via the API (
PUT /inventory/{test_id}) - Tests promoted from Staging to Inventory (automatically set to "Approved")
If the sync fails (e.g. network issue), the local status is still updated and a warning is logged.
Web UI
Zephyr sync buttons appear automatically in the Inventory tab when ZEPHYR_API_TOKEN is set:
- ⬇ Zephyr Pull — pull tests into inventory
- ⬆ Zephyr Push Updates — push local edits of already-synced tests back to Zephyr
- ⬆ Zephyr Push — push inventory tests to Zephyr (with real-time SSE progress)
- ⬇ Zephyr Results — pull execution results
Two-way sync (pushing edits back)
TestIntel tracks whether a synced test has been edited locally since its last
sync. When you change a test's name, steps, expected result, priority, or
user labels in TestIntel, an amber Edited pill appears on that test in the
Inventory list (use the Edited only filter to see just those). Execution
result and lifecycle status changes do not count as edits — those flow *from*
the source system, not back to it.
⬆ Zephyr Push Updates pushes the edited (or currently selected) synced tests
back to Zephyr Scale, updating the existing test cases in place rather than
creating new ones. After a successful push, the Edited indicator clears.
Scope and behavior:
- Only tests that already have a Zephyr key and have local edits are pushed.
- Lifecycle status is not pushed back here (see status sync above).
- Conflict detection (fail-closed): before overwriting, TestIntel fetches
the current Zephyr copy and only pushes if it can confirm the remote is
unchanged since your last pull. It skips a test as a conflict — never
overwriting — if the remote changed, if the fetch fails (network/auth), or if
the test has no sync baseline yet (pull it first). Pull to reconcile, then push
again. The result summary shows how many were updated, skipped as conflicts, or
failed.
- Partial-update safety: a test's fields and steps are updated in separate
API calls (not transactional). If the step update fails, the push is reported
as failed and the test stays flagged as edited (it is not marked synced),
so you can retry — the local baseline is only reset once the whole update
succeeds.
- Cannot clear all steps: Zephyr Scale's step endpoint requires at least one
step, so TestIntel cannot remove every step from a Zephyr test via sync. If you
clear all steps locally and push, the update is rejected with a clear message
and the remote test is left unchanged — leave at least one step, or edit the
test's steps directly in Zephyr.
- Resolving conflicts (concurrent edits): if a test was changed in both
Zephyr and TestIntel since the last pull, Push Updates reports it as a
conflict rather than overwriting. Click Review & Resolve to open a
three-way view (baseline / your local version / current Zephyr version) per
field. Fields only one side changed are pre-selected; for fields both sides
changed you choose which to keep or edit a merged value. Applying pushes the
resolved version back — and if the Zephyr copy changed *again* while you were
resolving, the apply is refused so you can re-review (nothing is clobbered).