test: add env-gated live sandbox smoke tests
This commit is contained in:
1 file changed
+159
@@ -0,0 +1,159 @@
|
||||
"""Live sandbox smoke tests, gated behind environment variables.
|
||||
|
||||
These tests make real requests to provider sandbox endpoints and are **skipped
|
||||
by default** — no network contact happens unless the caller provides actual
|
||||
credentials via environment variables:
|
||||
|
||||
- eSewa: ``NEPALI_PAYMENT_ESEWA_SECRET``
|
||||
- Khalti: ``NEPALI_PAYMENT_KHALTI_SECRET``
|
||||
- Fonepay: ``NEPALI_PAYMENT_FONEPAY_SECRET``, ``NEPALI_PAYMENT_FONEPAY_MERCHANT``,
|
||||
``NEPALI_PAYMENT_FONEPAY_USERNAME``, ``NEPALI_PAYMENT_FONEPAY_PASSWORD``
|
||||
|
||||
They assert only that a well-formed result is returned and that the transport
|
||||
succeeds, never hard-code expected provider data. Run with:
|
||||
|
||||
NEPALI_PAYMENT_KHALTI_SECRET=... pytest -m live
|
||||
|
||||
To opt in is deliberate: pushing a CI or a shared-hosting deploy without keys
|
||||
must never trigger live egress.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from nepali_payment.enums import PaymentMethod, PaymentMode
|
||||
from nepali_payment.http import ApiService
|
||||
from nepali_payment.manager import PaymentManager
|
||||
from nepali_payment.models import PaymentResult
|
||||
from nepali_payment.models.esewa import PaymentRequest as EsewaRequest
|
||||
from nepali_payment.models.fonepay import TaxRefundRequest
|
||||
from nepali_payment.models.khalti import PaymentRequest as KhaltiRequest
|
||||
|
||||
pytestmark = pytest.mark.live
|
||||
|
||||
|
||||
def _env(name: str) -> str:
|
||||
return os.environ.get(name, "").strip()
|
||||
|
||||
|
||||
esewa_creds = pytest.mark.skipif(
|
||||
not _env("NEPALI_PAYMENT_ESEWA_SECRET"),
|
||||
reason="NEPALI_PAYMENT_ESEWA_SECRET not set; skipping live eSewa test",
|
||||
)
|
||||
|
||||
khalti_creds = pytest.mark.skipif(
|
||||
not _env("NEPALI_PAYMENT_KHALTI_SECRET"),
|
||||
reason="NEPALI_PAYMENT_KHALTI_SECRET not set; skipping live Khalti test",
|
||||
)
|
||||
|
||||
fonepay_creds = pytest.mark.skipif(
|
||||
not (
|
||||
_env("NEPALI_PAYMENT_FONEPAY_SECRET")
|
||||
and _env("NEPALI_PAYMENT_FONEPAY_MERCHANT")
|
||||
and _env("NEPALI_PAYMENT_FONEPAY_USERNAME")
|
||||
and _env("NEPALI_PAYMENT_FONEPAY_PASSWORD")
|
||||
),
|
||||
reason="Fonepay credentials not set; skipping live Fonepay test",
|
||||
)
|
||||
|
||||
|
||||
def _manager(gateway, secret, mode=PaymentMode.SANDBOX):
|
||||
api = ApiService(timeout=30.0)
|
||||
return PaymentManager(gateway, mode, secret, api=api)
|
||||
|
||||
|
||||
@esewa_creds
|
||||
def test_live_esewa_v2_initiate():
|
||||
"""Initiate an eSewa payment against the sandbox and confirm transport works."""
|
||||
secret = _env("NEPALI_PAYMENT_ESEWA_SECRET")
|
||||
manager = _manager(PaymentMethod.ESEWA, secret)
|
||||
request = EsewaRequest(
|
||||
amount="100",
|
||||
total_amount="113",
|
||||
transaction_uuid="live-smoke-test",
|
||||
product_code="EPAYTEST",
|
||||
signed_field_names="total_amount,transaction_uuid,product_code",
|
||||
)
|
||||
result = manager.initiate_payment(PaymentResult, request)
|
||||
assert isinstance(result, PaymentResult)
|
||||
# The assertion proves the transport reached the live sandbox and returned a
|
||||
# structured result (success data, or a provider / network error message).
|
||||
assert result.message
|
||||
|
||||
|
||||
@khalti_creds
|
||||
def test_live_khalti_v2_initiate():
|
||||
"""Initiate a Khalti payment against the sandbox."""
|
||||
secret = _env("NEPALI_PAYMENT_KHALTI_SECRET")
|
||||
manager = _manager(PaymentMethod.KHALTI, secret)
|
||||
request = KhaltiRequest(
|
||||
return_url="https://example.test/callback",
|
||||
website_url="https://example.test",
|
||||
amount=1000,
|
||||
purchase_order_id="live-smoke-test",
|
||||
purchase_order_name="Live smoke test",
|
||||
)
|
||||
result = manager.initiate_payment(PaymentResult, request)
|
||||
assert isinstance(result, PaymentResult)
|
||||
assert isinstance(result.success, bool)
|
||||
|
||||
|
||||
@fonepay_creds
|
||||
def test_live_fonepay_initiate():
|
||||
"""Generate a Fonepay QR against the provider, using real merchant creds."""
|
||||
secret = _env("NEPALI_PAYMENT_FONEPAY_SECRET")
|
||||
manager = _manager(PaymentMethod.FONEPAY, secret)
|
||||
from nepali_payment.models.fonepay import QrRequest
|
||||
|
||||
qr = QrRequest(
|
||||
amount="100",
|
||||
remarks1="live",
|
||||
remarks2="smoke",
|
||||
prn="live-smoke-prn",
|
||||
merchant_code=_env("NEPALI_PAYMENT_FONEPAY_MERCHANT"),
|
||||
username=_env("NEPALI_PAYMENT_FONEPAY_USERNAME"),
|
||||
password=_env("NEPALI_PAYMENT_FONEPAY_PASSWORD"),
|
||||
)
|
||||
result = manager.initiate_payment(PaymentResult, qr)
|
||||
assert isinstance(result, PaymentResult)
|
||||
assert isinstance(result.success, bool)
|
||||
|
||||
|
||||
@fonepay_creds
|
||||
def test_live_fonepay_status():
|
||||
"""Query Fonepay QR status using real merchant creds."""
|
||||
secret = _env("NEPALI_PAYMENT_FONEPAY_SECRET")
|
||||
manager = _manager(PaymentMethod.FONEPAY, secret)
|
||||
payload = json.dumps(
|
||||
{
|
||||
"prn": "live-smoke-prn",
|
||||
"merchantCode": _env("NEPALI_PAYMENT_FONEPAY_MERCHANT"),
|
||||
"username": _env("NEPALI_PAYMENT_FONEPAY_USERNAME"),
|
||||
"password": _env("NEPALI_PAYMENT_FONEPAY_PASSWORD"),
|
||||
}
|
||||
)
|
||||
result = manager.verify_payment(PaymentResult, payload)
|
||||
assert isinstance(result, PaymentResult)
|
||||
assert isinstance(result.success, bool)
|
||||
|
||||
|
||||
@fonepay_creds
|
||||
def test_live_fonepay_tax_refund():
|
||||
"""Submit a Fonepay tax refund using real merchant creds."""
|
||||
secret = _env("NEPALI_PAYMENT_FONEPAY_SECRET")
|
||||
manager = _manager(PaymentMethod.FONEPAY, secret)
|
||||
request = TaxRefundRequest(
|
||||
fonepay_trace_id=0,
|
||||
transaction_amount="100",
|
||||
merchant_prn="live-smoke-prn",
|
||||
invoice_number="INV-1",
|
||||
invoice_date="31/07/2026",
|
||||
merchant_code=_env("NEPALI_PAYMENT_FONEPAY_MERCHANT"),
|
||||
username=_env("NEPALI_PAYMENT_FONEPAY_USERNAME"),
|
||||
password=_env("NEPALI_PAYMENT_FONEPAY_PASSWORD"),
|
||||
)
|
||||
result = manager.process_tax_refund(PaymentResult, request)
|
||||
assert isinstance(result, PaymentResult)
|
||||
assert isinstance(result.success, bool)
|
||||
Reference in new issue
Block a user