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