Files
Oxicloud/tests/api/contacts.hurl
T
Edouard Vanbelle 8ab537797a test(api): add API test on contacts
next will be to add CI on it
2026-05-11 00:53:29 +02:00

259 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================
# OxiCloud – Contacts API end-to-end scenario
# =============================================================
# Run:
# hurl --variables-file tests/api/hurl.vars --test tests/api/contacts.hurl
#
# Variables required (see hurl.vars):
# base_url – e.g. http://localhost:8087
# username – OxiCloud username
# password – OxiCloud password
# =============================================================
# ─────────────────────────────────────────────────────────────
# Step 1 – Login and capture the JWT token
# ─────────────────────────────────────────────────────────────
POST {{base_url}}/api/auth/login
Content-Type: application/json
{
"username": "{{username}}",
"password": "{{password}}"
}
HTTP 200
[Captures]
token: jsonpath "$.access_token"
[Asserts]
jsonpath "$.access_token" isString
jsonpath "$.token_type" == "Bearer"
# ─────────────────────────────────────────────────────────────
# Step 2 – List address books (at least the system book)
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/address-books
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$" isCollection
# System address book must always be present
jsonpath "$[?(@.id == 'system')].is_system" == true
jsonpath "$[?(@.id == 'system')].is_readonly" == true
# ─────────────────────────────────────────────────────────────
# Step 3 – Create a personal address book
# ─────────────────────────────────────────────────────────────
POST {{base_url}}/api/address-books
Authorization: Bearer {{token}}
Content-Type: application/json
{
"name": "Personal",
"description": "Personal address book created by Hurl tests",
"is_public": false
}
HTTP 201
[Captures]
book_id: jsonpath "$.id"
[Asserts]
jsonpath "$.id" isString
jsonpath "$.name" == "Personal"
jsonpath "$.description" == "Personal address book created by Hurl tests"
jsonpath "$.is_public" == false
jsonpath "$.is_system" == false
jsonpath "$.is_readonly" == false
# ─────────────────────────────────────────────────────────────
# Step 4 – List contacts in the new book – must be empty
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/address-books/{{book_id}}/contacts
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$" isCollection
jsonpath "$" count == 0
# ─────────────────────────────────────────────────────────────
# Step 5 – Create contact John Doe
# ─────────────────────────────────────────────────────────────
POST {{base_url}}/api/address-books/{{book_id}}/contacts
Authorization: Bearer {{token}}
Content-Type: application/json
{
"first_name": "John",
"last_name": "Doe",
"full_name": "John Doe",
"email": [
{
"email": "john.doe@example.com",
"type": "work",
"is_primary": true
}
],
"phone": [
{
"number": "+1-555-0100",
"type": "mobile",
"is_primary": true
}
]
}
HTTP 201
[Captures]
contact_id: jsonpath "$.id"
[Asserts]
jsonpath "$.id" isString
jsonpath "$.address_book_id" == {{book_id}}
jsonpath "$.first_name" == "John"
jsonpath "$.last_name" == "Doe"
jsonpath "$.full_name" == "John Doe"
jsonpath "$.email" count == 1
jsonpath "$.email[0].email" == "john.doe@example.com"
jsonpath "$.email[0].type" == "work"
jsonpath "$.email[0].is_primary" == true
jsonpath "$.phone" count == 1
jsonpath "$.phone[0].number" == "+1-555-0100"
jsonpath "$.phone[0].type" == "mobile"
jsonpath "$.phone[0].is_primary" == true
# ─────────────────────────────────────────────────────────────
# Step 6 – List contacts – exactly 1 result, must be John Doe
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/address-books/{{book_id}}/contacts
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$" count == 1
jsonpath "$[*].id" contains {{contact_id}}
jsonpath "$[0].first_name" == "John"
jsonpath "$[0].last_name" == "Doe"
jsonpath "$[0].full_name" == "John Doe"
# ─────────────────────────────────────────────────────────────
# Step 7 – Get John Doe by id and verify all fields
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/address-books/{{book_id}}/contacts/{{contact_id}}
Authorization: Bearer {{token}}
HTTP 200
[Captures]
etag: header "ETag"
[Asserts]
header "ETag" exists
jsonpath "$.id" == {{contact_id}}
jsonpath "$.address_book_id" == {{book_id}}
jsonpath "$.first_name" == "John"
jsonpath "$.last_name" == "Doe"
jsonpath "$.full_name" == "John Doe"
jsonpath "$.email[0].email" == "john.doe@example.com"
jsonpath "$.email[0].type" == "work"
jsonpath "$.email[0].is_primary" == true
jsonpath "$.phone[0].number" == "+1-555-0100"
jsonpath "$.phone[0].type" == "mobile"
# ─────────────────────────────────────────────────────────────
# Step 8 – Update John Doe: add nickname, notes, and organisation
# Uses If-Match for optimistic concurrency
# ─────────────────────────────────────────────────────────────
PUT {{base_url}}/api/address-books/{{book_id}}/contacts/{{contact_id}}
Authorization: Bearer {{token}}
Content-Type: application/json
If-Match: {{etag}}
{
"first_name": "John",
"last_name": "Doe",
"full_name": "John Doe",
"nickname": "JD",
"organization": "ACME Corp",
"notes": "Updated via Hurl test",
"email": [
{
"email": "john.doe@example.com",
"type": "work",
"is_primary": true
}
],
"phone": [
{
"number": "+1-555-0100",
"type": "mobile",
"is_primary": true
}
]
}
HTTP 200
[Captures]
etag: header "ETag"
[Asserts]
header "ETag" exists
jsonpath "$.id" == {{contact_id}}
jsonpath "$.first_name" == "John"
jsonpath "$.last_name" == "Doe"
jsonpath "$.nickname" == "JD"
jsonpath "$.organization" == "ACME Corp"
jsonpath "$.notes" == "Updated via Hurl test"
# ─────────────────────────────────────────────────────────────
# Step 9 – Delete John Doe (uses refreshed ETag from step 8)
# ─────────────────────────────────────────────────────────────
DELETE {{base_url}}/api/address-books/{{book_id}}/contacts/{{contact_id}}
Authorization: Bearer {{token}}
If-Match: {{etag}}
HTTP 204
# ─────────────────────────────────────────────────────────────
# Step 10 – Address book must be empty again
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/address-books/{{book_id}}/contacts
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$" count == 0
# ─────────────────────────────────────────────────────────────
# Step 11 – Delete the personal address book
# ─────────────────────────────────────────────────────────────
DELETE {{base_url}}/api/address-books/{{book_id}}
Authorization: Bearer {{token}}
HTTP 204
# ─────────────────────────────────────────────────────────────
# Step 12 – Verify the address book is gone from the list
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/address-books
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$[*].id" not contains {{book_id}}
# ─────────────────────────────────────────────────────────────
# Step 13 – List the system address book (OxiCloud users)
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/address-books/system/contacts
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$" isCollection