Web API
Testspace provides a REST API, designed to have predictable, resource-oriented URLs that leverage built-in features of HTTP, like authentication, verbs and response codes. All data is sent and received in JSON format and UTF-8 encoding. Any off-the-shelf HTTP client can be used to communicate with the API.
This API is not for publishing test results. The Testspace client is required for pushing data to the server.
Overview
Authentication
Testspace API is authenticated using HTTP Basic Auth over HTTPS. Always use https://: a plain HTTP request is redirected, but only after its credentials were sent unencrypted.
The credentials may be given either as username:password or as access-token: (You can generate and get an Access token from your user settings).
For example using curl you can pass the -u flag:
$ curl -u <username:password> "https://domain.testspace.com/api/projects"
$ curl -u <access-token:> "https://domain.testspace.com/api/projects"
or set the Authorization header:
$ curl -H "Authorization: Token <access-token>" "https://domain.testspace.com/api/projects"
All requests are associated with a specific user in Testspace and permissions are limited to that user's capabilities.
Requests
The base URL of the API is https://domain.testspace.com/api where domain should be replaced with your organization subdomain.
Parameters
Many API methods take optional parameters. For GET requests, any parameters not specified as a segment in the path can be passed as an HTTP query string parameter:
$ curl -u username:password "https://domain.testspace.com/api/projects/123/spaces/1234/results?name=MyResult"
In this example, the values '123' and '1234' are provided for the project :project_id and space :space_id parameters in the path, while name is passed in the query string.
For POST, PATCH, PUT, and DELETE requests, parameters not included in the URL are sent as JSON, with a Content-Type of application/json. A request whose Accept header asks for something other than JSON gets 415 Unsupported Media Type:
$ curl -u username:password "https://domain.testspace.com/api/spaces/1234" \
-X PATCH \
-H 'Content-Type: application/json' \
-d '{"description":"some description"}'
HTTP Verbs
The API strives to use appropriate HTTP verbs for each action:
GET- To retrieve a resource or a collection of resourcesPOST- To create a resourcePATCHorPUT- To modify a resourceDELETE- To delete a resource
Responses
All response bodies, including errors, are JSON encoded with a Content-Type of application/json.
A single resource is represented as a JSON object:
{
"field1": "value",
"field2": true,
"field3": []
}
A collection of resources is represented as a JSON array of objects:
[
{
"field1": "value",
"field2": true,
"field3": []
},
{
"field1": "another value",
"field2": false,
"field3": []
}
]
All timestamps are returned in ISO 8601 format.
Unset fields will be represented as a null instead of being omitted. If the field is an array, it will be represented as an empty array - i.e. [].
Errors
The API uses HTTP status codes to indicate success or failure of a request. In general, codes in the 2xx range indicate success, codes in the 4xx range indicate an error that resulted from the provided information (e.g. authentication failed, a resource not found, a validation error, etc.), and codes in the 5xx range indicate an internal server error.
4xx series errors are returned with a JSON object in the body, except 415 Unsupported Media Type:
{
"message": "Page not found"
}
5xx series error codes do not return JSON bodies.
Pagination
Listing resources will be paginated to 30 items by default. To control that you can pass the following parameters:
| parameter | description |
|---|---|
| page | Page number (default: 1) |
| per_page | Number of items to list per page (default: 30, max: 100) |
For example to list 50 projects per page:
$ curl -u username:password "https://domain.testspace.com/api/projects?per_page=50"
A Link header is sent back with each response. It has a rel set to prev/next/first/last and contains the relevant URL. Follow these links instead of constructing your own URLs: a page past the last one returns 500, not an empty list. The Total-Count and Total-Pages headers give the size of the whole collection.
The Result failures and Result issues lists are not paginated: each returns the whole list.
Projects
All the information in Testspace is organized in Projects. A project contains one or more Spaces.
| Field | Type | Notes |
|---|---|---|
| id | integer | The unique ID of the project |
| name | string | The name of the project |
| description | string | The description of the project |
| is_private | boolean | True if the project is private, false otherwise |
| archived | boolean | True if the project is archived, false otherwise |
| source_repo_url | string | The URL of the repo if connected project |
| issues_provider | string | The selected issues provider: generic, github:org/repo, gitlab:org/repo, bitbucket:org/repo or jira:site/KEY |
| push_token | string | The project's specific token for results pushing (only available to admin users) |
| spaces_url | string | The URL of the contained Spaces list API |
| created_at | timestamp | The date/time when the project was created |
| updated_at | timestamp | The date/time when the project was last updated |
To request details about projects and to create or modify projects use the following API methods.
List projects
GET /api/projects
| parameter | description |
|---|---|
| name | Optional query parameter: lists only the projects with this name |
A successful response includes an array of projects, ordered by name, as each entry in the list follows the same format as get a project:
200 OK
Content-Type: application/json
[
{ "id": 123, "name": "..." },
{ "id": 345, "name": "..." },
]
Get a project
GET /api/projects/:project_id
| parameter | description |
|---|---|
| :project_id | The name or the ID of a project. A Connected Project can also be given as service:org/repo (e.g. github:myorg/myrepo) |
A successful response looks like:
200 OK
Content-Type: application/json
{
"id": 123,
"name": "MyProject",
"description": "Some description for my project",
"is_private": true,
"archived": false,
"source_repo_url": null,
"issues_provider": "generic",
"push_token": "tsp_0123456789abcdef0123456789abcdef01234567",
"spaces_url": "https://myorg.testspace.com/api/projects/123/spaces",
"created_at": "2014-10-06T18:02:54Z",
"updated_at": "2014-12-04T19:59:42Z"
}
Create a project
POST /api/projects
Only Organization admins can create a project.
| Field | Required | Notes |
|---|---|---|
| name | yes | The name of the project |
| description | no | The description of the project |
| is_private | no | True (default) if the project is private, false otherwise |
| source_repo | no | For connected projects creation only! The source repo identifier, formatted as service:org/repo, where service is github, bitbucket or gitlab |
Sample request:
POST /api/projects
Content-Type: application/json
{
"name": "MyProject",
"description": "Some description for my project",
"...": "..."
}
A successful response returns the new project following the same format as get a project:
201 Created
Location: https://domain.testspace.com/api/projects/123
Content-Type: application/json
{
"id": 123,
"name": "MyProject",
"...": "..."
}
Update a project
PATCH /api/projects/:project_id
PUT /api/projects/:project_id
Only Organization admins can update a project.
| parameter | description |
|---|---|
| :project_id | The name or the ID of a project |
| Field | Required | Notes |
|---|---|---|
| name | no | The name of the project |
| description | no | The description of the project |
| is_private | no | True if the project is private, false otherwise |
| archived | no | True to archive the project, false to restore it |
| issues_provider | no | The issues provider, in the same form as the issues_provider field |
Sample request:
PATCH /api/projects/123
Content-Type: application/json
{
"name": "NewProject",
"...": "..."
}
A successful response returns no content:
205 Reset Content
Delete a project
DELETE /api/projects/:project_id
| parameter | description |
|---|---|
| :project_id | The name or the ID of a project |
Sample request:
DELETE /api/projects/123
A successful response returns no content:
204 No Content
Spaces
Each Project consists of Spaces. A Space is a collection of test Results and Metrics.
| Field | Type | Notes |
|---|---|---|
| id | integer | The unique ID of the space |
| name | string | The name of the space |
| description | string | The description of the space |
| type | string | In a Connected Project: branch, fork (a pull request's Space, named PR-n), tags or manual. In a Standalone Project: manual for a Space with Manual testing, otherwise null |
| manual | boolean | True if the space has Manual testing enabled, false otherwise |
| project_id | integer | The associated project |
| sandbox | boolean | True if the space is a sandbox, false otherwise |
| result_set_aggregation | boolean | True if the space aggregates its results (see Show), false otherwise |
| stale | boolean | True if the space's pull request was closed or its project was disconnected, false otherwise |
| min_run_period | integer | Publication deadline for results in days (0 to disable) |
| active_result_set_id | integer | The ID of the space's active (latest complete) result |
| latest_result_set_id | integer | The ID of the space's latest result |
| results_url | string | The URL of the contained Results list API |
| metrics_url | string | The URL of the contained Metrics list API |
| created_at | timestamp | The date/time when the space was created |
| updated_at | timestamp | The date/time when the space was last updated |
To request details about spaces and to create or modify spaces use the following API methods.
List spaces
GET /api/projects/:project_id/spaces
Lists the Spaces as the Spaces listing does: newest Result first, then by name, without stale Spaces. In a Connected Project, a branch with no complete Result is left out, unless it has Manual testing or is the default branch.
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
A successful response includes an array of spaces, as each entry in the list follows the same format as Get a space:
200 OK
Content-Type: application/json
[
{ "id": 1234, "name": "..." },
{ "id": 5678, "name": "..." },
]
To get one space by its name, use Get a space with the project in the path.
Get a space
GET /api/spaces/:space_id
| parameter | description |
|---|---|
| :space_id | The ID of a space |
GET /api/projects/:project_id/spaces/:space_id
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The ID or the URL-encoded name of a space |
A successful response looks like:
200 OK
Content-Type: application/json
{
"id": 1234,
"name": "MySpace",
"description": "Some description for my space",
"type": null,
"manual": false,
"project_id": 12,
"sandbox": false,
"result_set_aggregation": false,
"stale": false,
"min_run_period": 1,
"active_result_set_id": 10823,
"latest_result_set_id": 10823,
"results_url": "https://myorg.testspace.com/api/projects/12/spaces/1234/results",
"metrics_url": "https://myorg.testspace.com/api/projects/12/spaces/1234/metrics",
"created_at": "2014-10-06T18:02:54Z",
"updated_at": "2014-12-04T19:59:42Z"
}
Create a space
POST /api/projects/:project_id/spaces
Only in a Standalone Project: a Connected Project's Spaces follow its repository, and the request returns 403.
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| Field | Required | Notes |
|---|---|---|
| name | yes | The name of the space |
| description | no | The description of the space |
| sandbox | no | True for a sandbox space, false (default) otherwise |
| min_run_period | no | Publication deadline for results in days (0 to disable) |
| result_set_aggregation | no | True for a space that aggregates its results; false by default, true for a Manual space |
| manual | no | Standalone Projects only: true to enable Manual testing |
| publish_path | no | Standalone Projects only: where the space's Manual results are placed in the Suite tree (see Publish Path) |
| base | no | The name of an existing Space to copy settings from (see Copy Settings) |
spacemanual and base are read only inside a space object; sent at the top level, they are ignored, and the Space is created without Manual testing or copied settings. Send every field inside space:
Sample request:
POST /api/projects/12/spaces
Content-Type: application/json
{
"space": {
"name": "MySpace",
"description": "Some description for my space",
"manual": true,
"base": "main"
}
}
A successful response returns the new space following the same format as Get a space:
201 Created
Location: https://domain.testspace.com/api/projects/12/spaces/1234
Content-Type: application/json
{
"id": 1234,
"name": "MySpace",
"...": "..."
}
Update a space
PATCH /api/spaces/:space_id
PATCH /api/projects/:project_id/spaces/:space_id
PUT works the same as PATCH.
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The ID of a space, or its name when the project is specified |
| Field | Required | Notes |
|---|---|---|
| name | no | The name of the space (not in a Connected Project) |
| description | no | The description of the space |
| sandbox | no | True for a sandbox space, false otherwise (not in a Connected Project) |
| min_run_period | no | Publication deadline for results in days (0 to disable) |
| result_set_aggregation | no | True for a space that aggregates its results, false otherwise |
| stale | no | Accepted only while the space is not stale |
| manual | no | Standalone Projects only: true to enable Manual testing, false to disable it |
| publish_path | no | Standalone Projects only: where the space's Manual results are placed in the Suite tree |
Fields a space can't change are ignored. As in Create a space, send manual inside a space object, or it is ignored.
Sample request:
PATCH /api/spaces/1234
Content-Type: application/json
{
"space": {
"name": "NewSpace",
"manual": true
}
}
A successful response returns no content:
205 Reset Content
Delete a space
DELETE /api/spaces/:space_id
DELETE /api/projects/:project_id/spaces/:space_id
In a Connected Project, only a stale Space can be deleted (its branch or pull request is gone); otherwise the request returns 403.
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The ID of a space, or its name when the project is specified |
Sample request:
DELETE /api/spaces/1234
A successful response returns no content:
204 No Content
Results
Each Space consists of a collection of Results. A Result is a collection of test cases organized in folders and Suites.
The counters are arrays of numbers, in this order:
| Counters | Order |
|---|---|
suite_counts | [passed, failed, not applicable] |
case_counts | [passed, failed, not applicable, errored (blocked), untested] |
annotation_counts | [error, warn, info] |
failure_counts | [new, flaky, consistent, passing, resolved, exempt] (see Failure Tracking) |
issue_counts | [open, closed] |
Each counter except annotation_counts, and duration, has a session_ twin: in a Space that aggregates its results, the plain one covers the whole Result and the session_ one only what ran in this Result, without what was carried from earlier ones (see Show). Elsewhere the two are the same.
| Field | Type | Notes |
|---|---|---|
| id | integer | The unique ID of the result |
| name | string | The name of the result |
| sequence_number | integer | The result's number in its space (1 for the first result) |
| description | string | The description of the result |
| complete | boolean | True if the result is complete, false otherwise |
| pinned | boolean | True if the result is pinned, false otherwise |
| space_id | integer | The associated space |
| user_id | integer | The user who created the result |
| commit_id | string | The associated repo commit id (e.g. SHA for git) |
| build_url | string | The URL of the originating CI build |
| build_status | string | The status of the originating CI build: success, failure or error. Shown with the result, never used to judge Health (see CI Build Status and the CI Check) |
| build_started_at | timestamp | When the originating CI build started |
| build_completed_at | timestamp | When the originating CI build completed |
| suite_counts | array | The contained suites counters |
| session_suite_counts | array | The contained suites counters for session only results |
| case_counts | array | The contained cases counters |
| session_case_counts | array | The contained cases counters for session only results |
| annotation_counts | array | The contained annotations counters |
| failure_counts | array | The contained failures counters |
| session_failure_counts | array | The contained failures counters for session only results |
| issue_counts | array | The referenced issues counters |
| session_issue_counts | array | The referenced issues counters for session only results |
| duration | number | The duration of the result in milliseconds |
| session_duration | number | The duration of the result in milliseconds for session only results |
| health | object | The health of the result |
| result_contents_url | string | The URL of the Result contents API |
| result_failures_url | string | The URL of the Result failures API |
| download_url | string | Only with ?download=1 on Get a result: the URL to download the result as a Testspace XML file |
| created_at | timestamp | The date/time when the result was created |
| updated_at | timestamp | The date/time when the result was last updated |
Health
The health object holds the result's Health:
| Field | Type | Notes |
|---|---|---|
| state | string | success (Healthy), failure (Unhealthy), invalid (Invalid), or pending while Testspace is still analyzing the result |
| partial | boolean | True if the result is partial (a subset, or a metric not reported), false otherwise. Information beside the verdict: it doesn't change state |
| description | string | The Health description, listing the checks that failed |
| badges | array | The result's badges: the test cases badge (named test) first, then each enabled metric badge |
Each badge has:
| Field | Type | Notes |
|---|---|---|
| metric_id | integer | The ID of the badge's metric |
| name | string | The badge's name, which its metric's settings can change (Release 78 renamed the coverage badges): match a badge by metric_id, not by name |
| value | number or string | The badge's value for the result: the pass rate for test, the metric's badge value otherwise (not reported for a metric that normally reports and has no value in this result, hidden once its badge is hidden, see Metrics That Stop Reporting; blank when the metric has no data) |
| status | string | passing (the check passed), failing (it failed), neutral (the badge has no criteria, so nothing is checked), no_results (no data for this result; not checked) or invalid (the test badge of an Invalid result) |
To request details about results and to create or modify results use the following API methods.
List results
GET /api/projects/:project_id/spaces/:space_id/results
GET /api/spaces/:space_id/results
Lists the Results that have content, newest first. A Result created with Create a result and never given content isn't listed; Get a result still returns it.
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| name | Optional query parameter: lists only the results with this name |
| sequence_number | Optional query parameter: lists only the result with this number; -1 returns only the latest result (of that name, if name is given) |
A successful response includes an array of results, newest first, as each entry in the list follows the same format as Get a result:
200 OK
Content-Type: application/json
[
{ "id": 1234, "name": "..." },
{ "id": 5678, "name": "..." },
]
Get a result
This API point is provided only for the purpose of accessing a result record without its content. To obtain a result's content please use the Get result contents API or if interested in the associated result failures use the Get result failures API.
GET /api/projects/:project_id/spaces/:space_id/results/:result_id
GET /api/spaces/:space_id/results/:result_id
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :result_id | The name (the latest result of that name) or the ID of a result; 0 for the space's active result |
| download | Optional query parameter: 1 adds download_url. The file is built in the background: until it is ready, downloading it returns 503 Service Unavailable with a Retry-After header |
A successful response looks like:
200 OK
Content-Type: application/json
{
"id": 123456,
"name": "MyResult",
"sequence_number": 20,
"description": "Some description for my result",
"complete": true,
"pinned": false,
"user_id": 15,
"space_id": 1234,
"commit_id": "220cc4abf6989d38726403a085c542290c7f4c13",
"build_url": "https://...",
"build_status": "success",
"build_started_at": "2014-12-04T19:40:12Z",
"build_completed_at": "2014-12-04T19:58:30Z",
"suite_counts": [1508, 147, 4],
"session_suite_counts": [1508, 147, 4],
"case_counts": [35093, 517, 292, 5, 0],
"session_case_counts": [35093, 517, 292, 5, 0],
"annotation_counts": [5951, 3558, 332415],
"failure_counts": [5, 17, 495, 21, 8, 35],
"session_failure_counts": [5, 17, 495, 21, 8, 35],
"issue_counts": [2, 0],
"session_issue_counts": [2, 0],
"duration": 7201360.0,
"session_duration": 7201360.0,
"health": {
"state": "failure",
"partial": false,
"description": "Unhealthy. One or more Testspace metrics were out of range.\n* Test Cases: 522 unexpected failures! 98.5% passed (100.0% threshold and 35 exempt cases)",
"badges": [
{
"metric_id": 1234567,
"name": "test",
"value": 98,
"status": "failing"
},
{
"metric_id": 1234568,
"name": "line coverage",
"value": "85%",
"status": "passing"
}
]
},
"result_contents_url": "https://myorg.testspace.com/api/projects/12/spaces/1234/results/123456/contents",
"result_failures_url": "https://myorg.testspace.com/api/projects/12/spaces/1234/results/123456/failures",
"created_at": "2014-10-06T18:02:54Z",
"updated_at": "2014-12-04T19:59:42Z"
}
Create a result
This API point is provided only for the purpose of creation of
empty(no content) result records. To create a result and push content to it please use the Testspace client.
POST /api/projects/:project_id/spaces/:space_id/results
POST /api/spaces/:space_id/results
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| Field | Required | Notes |
|---|---|---|
| name | no | The name of the result (Sequence_N if not given) |
| description | no | The description of the result |
| complete | no | True for a complete result, false (default) for an incomplete one |
| commit_id | no | The associated repo commit id |
| build_url | no | The URL of the originating CI build |
| build_status | no | The status of the originating CI build: success, failure or error |
| build_started_at | no | When the originating CI build started (ISO 8601) |
| build_completed_at | no | When the originating CI build completed (ISO 8601) |
Send at least one field: an empty body returns 400. When the Organization has reached its plan's Results limit, the request returns 423 Locked.
If the space has an incomplete result with the same name, no new result is created: the request updates that result instead, as Update a result does.
Sample request:
POST /api/spaces/1234/results
Content-Type: application/json
{
"name": "MyResult",
"description": "Some description for my result"
}
A successful response returns the new result following the same format as Get a result:
201 Created
Location: https://domain.testspace.com/api/spaces/1234/result_sets/123456
Content-Type: application/json
{
"id": 123456,
"name": "MyResult",
"...": "..."
}
Update a result
This API point is provided only for the purpose of updating a result record without affecting its content. To update a result's content please use the Testspace client.
PATCH /api/projects/:project_id/spaces/:space_id/results/:result_id
PATCH /api/spaces/:space_id/results/:result_id
PUT and POST to the same URLs work the same as PATCH. Organization admins and the user who created the result can update it.
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :result_id | The name or the ID of a result; 0 for the space's active result |
Which fields are accepted depends on whether the result is complete; others are ignored:
| Field | Incomplete result | Complete result | Notes |
|---|---|---|---|
| name | yes | yes | The name of the result |
| description | yes | yes | The description of the result |
| complete | yes | yes | True to complete the result; false to reopen a complete result, which must be sent on its own |
| pinned | no | yes | True to pin the result, false to unpin it (see also Pin a result) |
| commit_id | yes | no | The associated repo commit id |
| build_url | yes | no | The URL of the originating CI build |
| build_status | yes | no | The status of the originating CI build: success, failure or error |
| build_started_at | yes | no | When the originating CI build started (ISO 8601) |
| build_completed_at | yes | no | When the originating CI build completed (ISO 8601) |
Sample request:
PATCH /api/spaces/1234/results/123456
Content-Type: application/json
{
"name": "NewResult",
"...": "..."
}
A successful response returns no content:
205 Reset Content
Pin a result
A pinned result keeps its content when the retention policy removes older results' content. Only a complete result can be pinned or unpinned.
PUT /api/projects/:project_id/spaces/:space_id/results/:result_id/pin
PUT /api/spaces/:space_id/results/:result_id/pin
PATCH works the same as PUT.
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :result_id | The name or the ID of a result; 0 for the space's active result |
Sample request:
PUT /api/spaces/1234/results/123456/pin
A successful response returns no content:
205 Reset Content
Unpin a result
DELETE /api/projects/:project_id/spaces/:space_id/results/:result_id/pin
DELETE /api/spaces/:space_id/results/:result_id/pin
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :result_id | The name or the ID of a result; 0 for the space's active result |
Sample request:
DELETE /api/spaces/1234/results/123456/pin
A successful response returns no content:
204 No Content
Delete a result
DELETE /api/projects/:project_id/spaces/:space_id/results/:result_id
DELETE /api/spaces/:space_id/results/:result_id
Only Organization admins and the user who published the Result can delete it.
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :result_id | The name or the ID of a result |
Sample request:
DELETE /api/spaces/1234/results/123456
The result is deleted in the background; the request returns at once. A successful response returns no content:
204 No Content
Get result contents
Each Result is a collection of test cases organized in folders and Suites. Each folder and Suite has the counters described under Results.
Folder
| Field | Type | Notes |
|---|---|---|
| id | integer | The unique ID of the folder |
| result_id | integer | The associated result |
| type | string | Always folder |
| name | string | The name of the folder |
| path | string | The full path to the folder |
| description | string | The description of the folder |
| carried | boolean | True if the folder has one or more suites carried from another session, false otherwise |
| custom_data | object | The folder's custom data, by name |
| suite_counts | array | The contained suites counters |
| session_suite_counts | array | The contained suites counters for session only results |
| case_counts | array | The contained cases counters |
| session_case_counts | array | The contained cases counters for session only results |
| annotation_counts | array | The contained annotations counters |
| failure_counts | array | The contained failures counters |
| session_failure_counts | array | The contained failures counters for session only results |
| issue_counts | array | The referenced issues counters |
| session_issue_counts | array | The referenced issues counters for session only results |
| duration | number | The duration of the folder in milliseconds |
| session_duration | number | The duration of the folder in milliseconds for session only results |
| folder_contents_url | string | The URL of the folder's contents (by its ID, see below) |
Suite
| Field | Type | Notes |
|---|---|---|
| id | integer | The unique ID of the suite |
| result_id | integer | The associated result |
| type | string | suite for a test suite; other kinds of suite are suite (<kind>), where <kind> is manual, exploratory, custom, code_coverage, static_analysis or code_change (e.g. suite (code_coverage)) |
| name | string | The name of the suite |
| path | string | The full path to the suite |
| description | string | The description of the suite |
| status | string | The status of the suite: passed, failed, missing or not applicable |
| carried | boolean | True if the suite is carried from another session, false otherwise |
| source_file | string | The source file reported for the suite, if any |
| runner | string | The test runner reported for the suite, if any |
| start_time | timestamp | When the suite started, if reported |
| custom_data | object | The suite's custom data, by name |
| case_counts | array | The contained cases counters |
| session_case_counts | array | The contained cases counters for session only results |
| annotation_counts | array | The contained annotations counters |
| failure_counts | array | The contained failures counters |
| session_failure_counts | array | The contained failures counters for session only results |
| issue_counts | array | The referenced issues counters |
| session_issue_counts | array | The referenced issues counters for session only results |
| duration | number | The duration of the suite in milliseconds |
| session_duration | number | The duration of the suite in milliseconds for session only results |
| suite_contents_url | string | The URL of the Suite's contents API |
| download_url | string | The URL to download from an XML-snippet of the contained test cases |
Annotation
| Field | Type | Notes |
|---|---|---|
| id | integer | The unique ID of the annotation |
| result_id | integer | The associated result |
| type | string | Always annotation |
| name | string | The name of the annotation |
| description | string | The description of the annotation |
| download_url | string | The URL to download from the associated file content |
To get the contents of a result use the following API methods.
GET /api/projects/:project_id/spaces/:space_id/results/:result_id/contents/<:path>
GET /api/spaces/:space_id/results/:result_id/contents/<:path>
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :result_id | The name or the ID of a result; 0 for the space's active result |
| :path | The named folder/suite path; omit it for the result's top level |
A folder or suite can also be given by its ID, as in folder_contents_url:
GET /api/projects/:project_id/spaces/:space_id/results/:result_id/contents/:element_id
GET /api/spaces/:space_id/results/:result_id/contents/:element_id
A successful response looks like:
- a collection, when
:pathrepresents a Folder (or the top level)
200 OK
Content-Type: application/json
[
{
"id": 1234,
"result_id": 123456,
"type": "folder",
"name": "MyFolder",
"path": "path/MyFolder",
"description": "Some description for my folder",
"carried": false,
"suite_counts": [150, 14, 4],
"case_counts": [3509, 51, 29, 5, 0],
"annotation_counts": [5951, 355, 3324],
"failure_counts": [5, 17, 49, 21, 8, 35],
"issue_counts": [1, 0],
"duration": 1234.5,
"custom_data": {},
"folder_contents_url": "https://myorg.testspace.com/api/projects/12/spaces/1234/results/123456/contents/1234"
},
{
"id": 5678,
"result_id": 123456,
"type": "suite",
"name": "MySuite",
"path": "path/MySuite",
"description": "Some description for my suite",
"status": "failed",
"carried": false,
"source_file": "spec/my_suite_spec.rb",
"runner": null,
"start_time": "2014-12-04T19:42:10Z",
"case_counts": [50, 6, 2, 0, 0],
"annotation_counts": [10, 0, 3],
"failure_counts": [5, 17, 4, 2, 8, 5],
"issue_counts": [0, 0],
"duration": 1234.5,
"custom_data": {},
"suite_contents_url": "https://myorg.testspace.com/api/projects/12/spaces/1234/results/123456/suite_contents/5678",
"download_url": "https://..."
},
{
"id": 16369873,
"result_id": 123456,
"type": "annotation",
"name": "MyAnnotation",
"description": "Some description for my annotation",
"download_url": "https://..."
},
]
The session_ counters are left out of these examples.
- an object, when
:pathrepresents a Suite
200 OK
Content-Type: application/json
{
"id": 5678,
"result_id": 123456,
"type": "suite",
"name": "MySuite",
"path": "path/MySuite",
"description": "Some description for my suite",
"status": "failed",
"case_counts": [50, 6, 2, 0, 0],
"annotation_counts": [10, 0, 3],
"failure_counts": [5, 17, 4, 2, 8, 5],
"duration": 1234.5,
"suite_contents_url": "https://myorg.testspace.com/api/projects/12/spaces/1234/results/123456/suite_contents/5678",
"download_url": "https://...",
"...": "..."
}
Get suite contents
Each Suite is a collection of test cases. The list also includes tracked cases that didn't run in this result (status missing) and the suite's annotations (in the Annotation format).
| Field | Type | Notes |
|---|---|---|
| id | integer | The unique ID of the test case |
| result_id | integer | The associated result |
| suite_id | integer | The associated suite |
| type | string | Always case |
| name | string | The name of the test case |
| description | string | The description of the test case |
| status | string | The status of the test case: passed, failed, errored (shown as blocked), not_applicable, untested, ignored or missing |
| cause | string | The failure cause in case of failed/errored status |
| annotation_counts | array | The contained annotations [error, warn, info] counters |
| duration | number | The duration of the test case in milliseconds |
| tracking | object | A failure object if the test case is being tracked (without key and issues). For details see the Result failures API |
| issues | array | The keys of the issues the test case references (see Get result issues) |
To get the contents of a suite use the following API methods.
GET /api/projects/:project_id/spaces/:space_id/results/:result_id/suite_contents/:suite_id
GET /api/spaces/:space_id/results/:result_id/suite_contents/:suite_id
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :result_id | The name or the ID of a result; 0 for the space's active result |
| :suite_id | The ID of a suite |
A successful response looks like:
200 OK
Content-Type: application/json
[
{
"id": 456789,
"result_id": 123456,
"suite_id": 5678,
"type": "case",
"name": "MyCase",
"description": "blah blah",
"status": "failed",
"cause": "Expected 200, got 500",
"annotation_counts": [2, 0, 1],
"duration": 567.0,
"tracking": {
"state": "flaky",
"history": ["F", "P", "F2"],
"exempt": false,
"message": null,
"tracked_count": 4,
"failed_at": "2014-10-06T18:02:54Z",
"passed_at": null
},
"issues": []
}
]
Get result failures
For each Result any failed/errored test case is being tracked. The set of those test cases is provided via the Failures end point.
| Field | Type | Notes |
|---|---|---|
| key | string | The key of a test case failure (formatted as path/to/suite().case) |
| state | string | The tracking state of the failure: new, flaky, consistent, passing, resolved or retired. Failures shows only New, Flaky and Consistent; passing and resolved are the internal states described in Failure Tracking. retired (missing too long, tracking ended without a fix) appears in the result where tracking ended; like a resolved failure, it isn't listed in later results |
| history | array | The runs of the failure, oldest first (see History notation) |
| exempt | boolean | True if the failure is exempt, false otherwise |
| message | string | The triage note associated with the failure |
| issues | array | The keys of the issues linked to the failure |
| tracked_count | integer | The number of results the failure has been tracked for |
| failed_at | timestamp | The date/time when the failure first occurred |
| passed_at | timestamp | The date/time when the failure started passing before being resolved |
History notation
Each history entry is one run, or several identical runs in a row, written as [X|x][C]<status>[n]:
| Part | Means |
|---|---|
F | failed |
E | errored (blocked) |
P | passed |
N | not applicable |
U | untested |
M | missing: the test didn't run in that result (counts toward retiring it) |
D | missing from a subset or an Invalid result (doesn't count toward retiring it) |
X prefix | exempt, set in Triage |
x prefix | exempt as an expected failure: a pytest xfail, or a test case pushed with the exempt attribute |
C | the run was carried from an earlier session (in a Space that aggregates its results) |
n suffix | the number of identical runs in a row, e.g. P4 |
To get the failures of a result use the following API methods.
GET /api/projects/:project_id/spaces/:space_id/results/:result_id/failures
GET /api/spaces/:space_id/results/:result_id/failures
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :result_id | The name or the ID of a result; 0 for the space's active result |
A successful response looks like:
200 OK
Content-Type: application/json
[
{
"key": "path/to/MySuite().MyCase",
"state": "flaky",
"history": ["F", "P3", "F"],
"exempt": false,
"message": null,
"tracked_count": 8,
"failed_at": "2014-10-06T18:02:54Z",
"passed_at": null,
"issues": []
},
{
"key": "path/to/MySuite().OtherCase",
"state": "passing",
"history": ["F3", "P4"],
"exempt": false,
"message": "Fixed by the timeout change",
"tracked_count": 7,
"failed_at": "2014-10-01T10:15:31Z",
"passed_at": "2014-10-03T08:20:12Z",
"issues": ["#482"]
}
]
Get result issues
The issues referenced by the result's test cases, for example through Triage (see the Issues tab).
| Field | Type | Notes |
|---|---|---|
| key | string | The issue's key, e.g. #482 or PROJ-123 |
| title | string | The issue's title |
| url | string | The issue's URL in its issues provider |
| state | string | open or closed |
| case_counts | array | The referencing cases [passed, failed, not applicable, errored (blocked), untested] counters; exempt cases count as not applicable |
To get the issues of a result use the following API methods.
GET /api/projects/:project_id/spaces/:space_id/results/:result_id/issues
GET /api/spaces/:space_id/results/:result_id/issues
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :result_id | The name or the ID of a result; 0 for the space's active result |
A successful response looks like:
200 OK
Content-Type: application/json
[
{
"key": "#482",
"title": "Search times out on large projects",
"url": "https://github.com/myorg/myrepo/issues/482",
"state": "open",
"case_counts": [0, 1, 0, 0, 0]
}
]
Metrics
For each Result push to a Space a set of Metrics are collected. A Metric consists of a collection of historical datasets.
| Field | Type | Notes |
|---|---|---|
| id | integer | The unique ID of the metric |
| name | string | The name of the metric |
| data_source | string | The path to the data source of the metric |
| chart_type | string | The type (i.e. lines or columns) of the metric's chart |
| max_range | integer | The "default" max range on the metric's chart y-axes |
| max_range_limit | integer | The max range "limit" (0 for unlimited) on the metric's chart y-axes |
| units | string | The units of the data being graphed |
| space_id | integer | The associated space |
| badge_url | string | The URL of the associated badge |
| embed_url | string | The URL of the associated graph |
| variables | array | The "variables" (calculated of the input dataset) being graphed |
| thresholds | array | The "thresholds" (calculated of the input dataset) being graphed |
| badge | object | The "badge" (calculated of the variables/thresholds and/or input datasets) being computed |
| created_at | timestamp | The date/time when the metric was created |
| updated_at | timestamp | The date/time when the metric was last updated |
To request details about metrics and to create or modify metrics use the following API methods.
List metrics
GET /api/projects/:project_id/spaces/:space_id/metrics
GET /api/spaces/:space_id/metrics
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| name | Optional query parameter: lists only the metrics with this name |
A successful response includes an array of metrics, ordered by name, as each entry in the list follows the same format as Get a metric:
200 OK
Content-Type: application/json
[
{ "id": 1234, "name": "..." },
{ "id": 5678, "name": "..." },
]
Get a metric
This API point is provided only for the purpose of accessing a metric record without its datasets. To obtain metric's datasets please use the Get Metric Datasets API.
GET /api/projects/:project_id/spaces/:space_id/metrics/:metric_id
GET /api/spaces/:space_id/metrics/:metric_id
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :metric_id | The ID of a metric |
A successful response looks like:
200 OK
Content-Type: application/json
{
"id": 123456,
"name": "MyMetric",
"data_source": "/path/to/suite[dataset_label]",
"chart_type": "lines",
"max_range": 10,
"max_range_limit": 10,
"units": "seconds",
"space_id": 1234,
"badge_url": "https://...",
"embed_url": "https://...",
"variables": [
{
"name": "var-one",
"color": "#008000",
"expression": "round(d1/1000,1)"
},
],
"thresholds": [
{
"name": "thresh-one",
"color": "#464646",
"expression": "3"
},
],
"badge": {
"name": "thresh-one",
"value_expression": "concat(v1,'s')",
"criteria_expression": "v1 <= t1",
"is_enabled": true
},
"created_at": "2014-10-06T18:02:54Z",
"updated_at": "2014-12-04T19:59:42Z"
}
Create a metric
Only Custom Metrics can be created via this API.
POST /api/projects/:project_id/spaces/:space_id/metrics
POST /api/spaces/:space_id/metrics
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| Field | Required | Notes |
|---|---|---|
| name | yes | The name of the metric |
| data_source | yes | The path to the data source of the metric |
| chart_type | no | The type (i.e. lines or columns) of the metric's chart |
| max_range | no | The "default" max range on the metric's chart y-axes |
| max_range_limit | no | The max range "limit" (0 for unlimited) on the metric's chart y-axes |
| units | no | The units of the data being graphed |
| variables | yes | The "variables" (calculated of the input dataset) being graphed |
| thresholds | no | The "thresholds" (calculated of the input dataset) being graphed |
| badge | no | The "badge" (calculated of the variables/thresholds and/or input datasets) being computed |
Sample request:
POST /api/spaces/1234/metrics
Content-Type: application/json
{
"name": "MyMetric",
"data_source": "/path/to/suite[dataset_label]",
"...": "..."
}
A successful response returns the new metric following the same format as Get a metric:
201 Created
Location: https://domain.testspace.com/api/spaces/1234/metrics/123456
Content-Type: application/json
{
"id": 123456,
"name": "MyMetric",
"...": "..."
}
Update a metric
PATCH /api/projects/:project_id/spaces/:space_id/metrics/:metric_id
PATCH /api/spaces/:space_id/metrics/:metric_id
The Test Suites, Code Change, Health and Failure Tracks metrics can't be updated (403).
PUT works the same as PATCH.
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :metric_id | The ID of a metric |
| Field | Required | Notes |
|---|---|---|
| name | no | The name of the metric |
| data_source | no | The path to the data source of the metric |
| chart_type | no | The type (i.e. lines or columns) of the metric's chart |
| max_range | no | The "default" max range on the metric's chart y-axes |
| max_range_limit | no | The max range "limit" (0 for unlimited) on the metric's chart y-axes |
| units | no | The units of the data being graphed |
| variables | no | The "variables" (calculated of the input dataset) being graphed |
| thresholds | no | The "thresholds" (calculated of the input dataset) being graphed |
| badge | no | The "badge" (calculated of the variables/thresholds and/or input datasets) being computed |
Sample request:
PATCH /api/spaces/1234/metrics/123456
Content-Type: application/json
{
"name": "NewMetric"
}
A successful response returns no content:
205 Reset Content
Delete a metric
DELETE /api/projects/:project_id/spaces/:space_id/metrics/:metric_id
DELETE /api/spaces/:space_id/metrics/:metric_id
The standard metrics (Test Suites, Test Cases, Health, Failure Tracks) can't be deleted (403).
parameter | description
------| -----------
:project_id | The name or the ID of the associated project |
:space_id | The name (only when project is specified) or the ID of the associated space |
:metric_id | The ID of a metric |
Sample request:
DELETE /api/spaces/1234/metrics/123456
A successful response returns no content:
204 No Content
Get metric datasets
A Metric consists of a collection of historical datasets, one per result that reported the metric.
| Field | Type | Notes |
|---|---|---|
| id | integer | The unique ID of the dataset |
| metric_id | integer | The associated metric |
| result_set_id | integer | The associated result |
| raw_values | object | The set of raw metric data (named d1 to d10) pushed with the result |
| evaluated_values | object | The set of evaluated data (named v1..v5, t1, t2, b and bc) that are being graphed |
| created_at | timestamp | The date/time when the metric dataset was created |
| updated_at | timestamp | The date/time when the metric dataset was last updated |
| published_at | timestamp | The date/time of the associated result, where the dataset is placed on the metric's graph |
To get the datasets of a metric use the following API methods.
GET /api/projects/:project_id/spaces/:space_id/metrics/:metric_id/datasets
GET /api/spaces/:space_id/metrics/:metric_id/datasets
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of the associated space |
| :metric_id | The ID of a metric |
| days | Optional query parameter: how many days back to list datasets for (default: 28) |
A successful response, newest first, looks like:
200 OK
Content-Type: application/json
[
{
"id": 369040,
"metric_id": 94828,
"result_set_id": 112168,
"raw_values": {"d1":2093,"d2":1900,"d3":2740,"d4":null,"d5":null,"d6":null,"d7":null,"d8":null,"d9":null,"d10":null},
"evaluated_values": {"v1":"2.1","v2":"1.9","v3":"2.7","v4":null,"v5":null,"t1":3,"t2":null,"b":"2.1s","bc":true},
"created_at":"2019-10-11T10:58:02.000-07:00",
"updated_at":"2019-10-11T10:58:02.000-07:00",
"published_at":"2019-10-11T10:58:02.000-07:00"
},
]
Insights
Insights summarize a project's or a space's results over a period. The values are formatted as Insights shows them: most are a percentage followed by the numbers it is computed from, e.g. "92.7% (873/942)", and N/A when there isn't enough data. Invalid results are left out of the statistics.
Get project insights
GET /api/projects/:project_id/insights
| parameter | description |
|---|---|
| :project_id | The name or the ID of a project |
| days | Optional query parameter: the period in days (default: 28) |
The response has one object for each of the three indicators: results_strength, test_effectiveness and workflow_efficiency. Each has a status (good, mediocre, poor or unknown) and a status_message explaining it, followed by the indicator's statistics (see Project Insights). The key regressed_spaces is regressed_branches in a Connected Project.
A successful response looks like:
200 OK
Content-Type: application/json
{
"results_strength": {
"status": "good",
"status_message": "Pass Rate is greater than 95%.",
"pass_rate": "95.6% (2,112/2,210)",
"health_rate": "9.8% (5/51)",
"health_recovery_time": "3.0d",
"invalid_rate": "0% (0/51)",
"file_churn": "N/A",
"pass_rate_change": "N/A ",
"health_rate_change": "N/A ",
"health_recovery_rate": "100% (1/1)",
"failure_volatility": 0.05,
"unhealthy_metrics": 2,
"flaky_failures": "22.7% (0.5/2.2)",
"error_failures": "9.1% (0.2/2.2)",
"invalid_with_errors": 0
},
"test_effectiveness": {
"status": "mediocre",
"status_message": "Effective Regression is over 30%. Most likely caused by system instability.",
"effective_regression": "33.3% (17/51)",
"new_failures": 21,
"test_cases": 44,
"test_duration": 46672.0,
"regressed_spaces": "80% (4/5)",
"unique_regressions": "38.6% (17/44)",
"new_failure_rate": "33.3% (1.2/3.6)",
"test_suites": 6
},
"workflow_efficiency": {
"status": "poor",
"status_message": "Resolved Failures are below 60%.",
"resolved_failures": "33.3% (7/21)",
"failure_resolution_time": "0.0d",
"long_term_failures": "50% (1/2)",
"merged_pull_requests": "N/A ",
"pr_resolution_time": "N/A",
"failures_per_regression": "5.1% (2.2/43)",
"triage_long_term_failures": "33.3% (0.3/0.9)",
"new_prs": 0,
"closed_prs": 0,
"rejected_prs": 0,
"stale_prs": 0,
"pr_comments": 0,
"pr_additions": 0,
"pr_deletions": 0,
"pr_changed_files": 0,
"pr_participants": 0
}
}
Get space insights
GET /api/projects/:project_id/spaces/:space_id/insights
GET /api/spaces/:space_id/insights
| parameter | description |
|---|---|
| :project_id | The name or the ID of the associated project |
| :space_id | The name (only when project is specified) or the ID of a space |
| days | Optional query parameter: the period in days (default: 28) |
The response is one object (see Space Cards): the number of results in the period, the growth of test cases and static analysis issues, a <metric name>_growth key for each code coverage metric, then the space's Results Strength, Test Effectiveness and Workflow Efficiency statistics, without the indicator statuses. In a Connected Project it also has merged_prs and pr_resolution_time.
A successful response looks like:
200 OK
Content-Type: application/json
{
"results": 20,
"test_growth": "0 | 0.0%",
"line coverage_growth": "1.2%",
"static_analysis_growth": "0%",
"pass_rate": "92.7% (873/942)",
"health_rate": "0% (0/20)",
"invalid_rate": "0% (0/20)",
"file_churn": "N/A",
"pass_rate_change": "N/A ",
"health_rate_change": "N/A ",
"health_recovery_rate": "0% (0/1)",
"failure_volatility": 0.29,
"unhealthy_metrics": 0,
"test_cases_processed": 984,
"flaky_failures": "28.6% (1.0/3.5)",
"error_failures": "14.3% (0.5/3.5)",
"invalid_with_errors": 0,
"unique_regressions": "60% (12/20)",
"new_failures": 16,
"new_failure_rate": "28.3% (1.3/4.6)",
"test_cases": 49,
"test_suites": 7,
"test_duration": 51208.0,
"resolved_failures": "31.3% (5/16)",
"failure_resolution_time": "0.0d",
"failures_per_regression": "7.4% (3.5/47)",
"long_term_failures": "25% (1/4)",
"triage_long_term_failures": "46.2% (0.6/1.3)"
}