Summary|
Tags|
Feature:
api/purchase-approved-flow/purchase-approved-flow.feature|
Ticketing MVP - Approved Purchase Flow
As a Ticketing MVP automation
I want to execute the complete happy path of approved purchase
So that I can verify the core transactional value of the system
Scenario: [1:15]
Happy Path - Approved Purchase Flow
ms: 117
>>
Background:
7
* def baseUrlEvents = karate.properties['baseUrlEvents'] || 'http://localhost:8081'
0
22:53:18.481 karate.env system property was: null
8
* def baseUrlTicketing = karate.properties['baseUrlTicketing'] || 'http://localhost:8082'
0
9
* def UUID = Java.type('java.util.UUID')
0
10
* def buyerId = UUID.randomUUID() + ''
0
11
* def buyerEmail = 'buyer-' + java.lang.System.currentTimeMillis() + '@karate-test.com'
0
12
* def eventTitle = 'Karate Test Event ' + java.lang.System.currentTimeMillis()
0
13
* def futureDate = '2026-12-15T20:00:00'
0
# Setup API: Crear sala
18
Given url baseUrlEvents + '/api/v1/rooms'
0
19
And header X-Role = 'ADMIN'
0
20
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
21
And request
0
{
"name": "Karate Test Room",
"maxCapacity": 100
}
28
When method post
13
22:53:18.484 request:
1 > POST http://localhost:8081/api/v1/rooms
1 > X-Role: ADMIN
1 > X-User-Id: 00000000-0000-0000-0000-000000000001
1 > Content-Type: application/json; charset=UTF-8
1 > Content-Length: 45
1 > Host: localhost:8081
1 > Connection: Keep-Alive
1 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17)
1 > Accept-Encoding: gzip,deflate
{"name":"Karate Test Room","maxCapacity":100}
22:53:18.497 response time in milliseconds: 12
1 < 201
1 < Content-Type: application/json
1 < Transfer-Encoding: chunked
1 < Date: Wed, 08 Apr 2026 03:53:18 GMT
1 < Keep-Alive: timeout=60
1 < Connection: keep-alive
{"id":"ddfd21ab-b683-421b-b99a-48551795c38f","name":"Karate Test Room","maxCapacity":100,"created_at":"2026-04-08T03:53:18.486727194","updated_at":"2026-04-08T03:53:18.486737857"}
29
Then status 201
0
30
* def roomId = response.id ? response.id : response.roomId
0
31
* match roomId == '#uuid'
0
32
* match response.maxCapacity == 100
0
# Setup API: Crear evento
# Nota técnica: según la implementación auditada, el evento se crea inicialmente con estado interno DRAFT y luego se publica.
36
Given url baseUrlEvents + '/api/v1/events'
0
37
And header X-Role = 'ADMIN'
0
38
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
39
And request
0
{
"roomId": "#(roomId)",
"title": "#(eventTitle)",
"description": "Test event for purchase flow",
"date": "#(futureDate)",
"capacity": 50,
"enableSeats": false
}
50
When method post
18
22:53:18.498 request:
2 > POST http://localhost:8081/api/v1/events
2 > X-Role: ADMIN
2 > X-User-Id: 00000000-0000-0000-0000-000000000001
2 > Content-Type: application/json; charset=UTF-8
2 > Content-Length: 199
2 > Host: localhost:8081
2 > Connection: Keep-Alive
2 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17)
2 > Accept-Encoding: gzip,deflate
{"roomId":"ddfd21ab-b683-421b-b99a-48551795c38f","title":"Karate Test Event 1775620398483","description":"Test event for purchase flow","date":"2026-12-15T20:00:00","capacity":50,"enableSeats":false}
22:53:18.515 response time in milliseconds: 17
2 < 201
2 < Content-Type: application/json
2 < Transfer-Encoding: chunked
2 < Date: Wed, 08 Apr 2026 03:53:18 GMT
2 < Keep-Alive: timeout=60
2 < Connection: keep-alive
{"id":"cd1fdf85-65d5-4a13-8b69-a3102c66594c","roomId":"ddfd21ab-b683-421b-b99a-48551795c38f","title":"Karate Test Event 1775620398483","description":"Test event for purchase flow","date":"2026-12-15T20:00:00","capacity":50,"status":"DRAFT","createdAt":"2026-04-08T03:53:18.504123179","updatedAt":"2026-04-08T03:53:18.50413292","createdBy":"00000000-0000-0000-0000-000000000001","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
51
Then status 201
0
52
* def eventId = response.id ? response.id : response.eventId
0
53
* match eventId == '#uuid'
0
54
* match response.status == 'DRAFT'
0
# HU-02: Configuración de tiers y precios por evento
57
Given url baseUrlEvents + '/api/v1/events/' + eventId + '/tiers'
0
58
And header X-Role = 'ADMIN'
0
59
And request
0
[
{
"tierType": "GENERAL",
"price": 100,
"quota": 40
}
]
69
When method post
13
22:53:18.517 request:
3 > POST http://localhost:8081/api/v1/events/cd1fdf85-65d5-4a13-8b69-a3102c66594c/tiers
3 > X-Role: ADMIN
3 > Content-Type: application/json; charset=UTF-8
3 > Content-Length: 47
3 > Host: localhost:8081
3 > Connection: Keep-Alive
3 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17)
3 > Accept-Encoding: gzip,deflate
[{"tierType":"GENERAL","price":100,"quota":40}]
22:53:18.529 response time in milliseconds: 12
3 < 201
3 < Content-Type: application/json
3 < Transfer-Encoding: chunked
3 < Date: Wed, 08 Apr 2026 03:53:18 GMT
3 < Keep-Alive: timeout=60
3 < Connection: keep-alive
{"eventId":"cd1fdf85-65d5-4a13-8b69-a3102c66594c","tiers":[{"id":"5bc6c01e-8de5-40cc-adb2-e690378ed8c0","tierType":"GENERAL","price":100,"quota":40,"validFrom":null,"validUntil":null,"createdAt":"2026-04-08T03:53:18.522257449","updatedAt":"2026-04-08T03:53:18.522268244"}]}
70
Then status 201
0
71
* def tierBlock = response.tiers ? response.tiers[0] : response[0]
0
72
* def tierId = tierBlock.id ? tierBlock.id : tierBlock.tierId
0
73
* match tierId == '#uuid'
0
74
* match tierBlock.tierType == 'GENERAL'
0
# Setup API: Publicar evento
77
Given url baseUrlEvents + '/api/v1/events/' + eventId + '/publish'
0
78
And header X-Role = 'ADMIN'
0
79
When method patch
10
22:53:18.530 request:
4 > PATCH http://localhost:8081/api/v1/events/cd1fdf85-65d5-4a13-8b69-a3102c66594c/publish
4 > X-Role: ADMIN
4 > Host: localhost:8081
4 > Connection: Keep-Alive
4 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17)
4 > Accept-Encoding: gzip,deflate
22:53:18.540 response time in milliseconds: 10
4 < 200
4 < Content-Type: application/json
4 < Transfer-Encoding: chunked
4 < Date: Wed, 08 Apr 2026 03:53:18 GMT
4 < Keep-Alive: timeout=60
4 < Connection: keep-alive
{"id":"cd1fdf85-65d5-4a13-8b69-a3102c66594c","roomId":"ddfd21ab-b683-421b-b99a-48551795c38f","title":"Karate Test Event 1775620398483","description":"Test event for purchase flow","date":"2026-12-15T20:00:00","capacity":50,"status":"PUBLISHED","createdAt":"2026-04-08T03:53:18.504123","updatedAt":"2026-04-08T03:53:18.534118672","createdBy":"00000000-0000-0000-0000-000000000001","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
80
Then status 200
0
81
* match response.status == 'PUBLISHED'
0
# HU-04: Reserva y compra de entrada con pago simulado (Creación de reserva)
84
Given url baseUrlTicketing + '/api/v1/reservations'
0
85
And header X-User-Id = buyerId
0
86
And request
0
{
"eventId": "#(eventId)",
"tierId": "#(tierId)",
"buyerEmail": "#(buyerEmail)"
}
94
When method post
29
22:53:18.541 request:
5 > POST http://localhost:8082/api/v1/reservations
5 > X-User-Id: 6ee4c206-af28-48f9-bfef-9efe1c03049f
5 > Content-Type: application/json; charset=UTF-8
5 > Content-Length: 149
5 > Host: localhost:8082
5 > Connection: Keep-Alive
5 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17)
5 > Accept-Encoding: gzip,deflate
{"eventId":"cd1fdf85-65d5-4a13-8b69-a3102c66594c","tierId":"5bc6c01e-8de5-40cc-adb2-e690378ed8c0","buyerEmail":"buyer-1775620398483@karate-test.com"}
22:53:18.570 response time in milliseconds: 28
5 < 201
5 < Content-Type: application/json
5 < Transfer-Encoding: chunked
5 < Date: Wed, 08 Apr 2026 03:53:18 GMT
5 < Keep-Alive: timeout=60
5 < Connection: keep-alive
{"id":"5174e3d6-9cce-4a52-af8a-42af5610cbae","eventId":"cd1fdf85-65d5-4a13-8b69-a3102c66594c","tierId":"5bc6c01e-8de5-40cc-adb2-e690378ed8c0","buyerId":"6ee4c206-af28-48f9-bfef-9efe1c03049f","status":"PENDING","createdAt":"2026-04-08T03:53:18.562478663","updatedAt":"2026-04-08T03:53:18.562478663","validUntilAt":"2026-04-08T04:03:18.562478663"}
95
Then status 201
0
96
* def reservationId = response.id
0
97
* match response == { id: '#uuid', eventId: '#uuid', tierId: '#uuid', buyerId: '#uuid', status: 'PENDING', createdAt: '#string', updatedAt: '#string', validUntilAt: '#string' }
0
# HU-04: Reserva y compra de entrada con pago simulado (Pago aprobado)
100
Given url baseUrlTicketing + '/api/v1/reservations/' + reservationId + '/payments'
0
101
And header X-User-Id = buyerId
0
102
And request
0
{
"amount": 100,
"paymentMethod": "MOCK",
"status": "APPROVED"
}
110
When method post
28
22:53:18.571 request:
6 > POST http://localhost:8082/api/v1/reservations/5174e3d6-9cce-4a52-af8a-42af5610cbae/payments
6 > X-User-Id: 6ee4c206-af28-48f9-bfef-9efe1c03049f
6 > Content-Type: application/json; charset=UTF-8
6 > Content-Length: 57
6 > Host: localhost:8082
6 > Connection: Keep-Alive
6 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17)
6 > Accept-Encoding: gzip,deflate
{"amount":100,"paymentMethod":"MOCK","status":"APPROVED"}
22:53:18.599 response time in milliseconds: 28
6 < 200
6 < Content-Type: application/json
6 < Transfer-Encoding: chunked
6 < Date: Wed, 08 Apr 2026 03:53:18 GMT
6 < Keep-Alive: timeout=60
6 < Connection: keep-alive
{"reservationId":"5174e3d6-9cce-4a52-af8a-42af5610cbae","status":"CONFIRMED","ticketId":"4b2241b0-81a7-4d71-ba9c-8e7244294100","message":"Payment approved. Ticket generated.","ticket":{"ticketId":"4b2241b0-81a7-4d71-ba9c-8e7244294100","eventId":"cd1fdf85-65d5-4a13-8b69-a3102c66594c","eventTitle":"Karate Test Event 1775620398483","eventDate":"2026-12-15T20:00:00","tier":"GENERAL","pricePaid":100,"status":"VALID","purchasedAt":"2026-04-08T03:53:18.583788034","buyerEmail":"buyer-1775620398483@karate-test.com","reservationId":"5174e3d6-9cce-4a52-af8a-42af5610cbae"},"timestamp":"2026-04-08T03:53:18.590987839"}
111
Then status 200
0
112
* match response == { reservationId: '#uuid', status: 'CONFIRMED', ticketId: '#uuid', message: '#string', ticket: { ticketId: '#uuid', eventId: '#uuid', eventTitle: '#string', eventDate: '#string', tier: '#string', pricePaid: '#number', status: '#string', buyerEmail: '#string', reservationId: '#uuid', purchasedAt: '#string' }, timestamp: '#string' }
0
113
* def ticketId = response.ticketId
0
114
* print 'Purchase complete! Ticket generated:', ticketId
0
22:53:18.600 [print] Purchase complete! Ticket generated: 4b2241b0-81a7-4d71-ba9c-8e7244294100