fix: restore wechat payment oauth and jsapi flow
This commit is contained in:
177
backend/internal/service/payment_order_result_test.go
Normal file
177
backend/internal/service/payment_order_result_test.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
dbent "github.com/Wei-Shaw/sub2api/ent"
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
|
||||
)
|
||||
|
||||
func TestBuildCreateOrderResponseDefaultsToOrderCreated(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expiresAt := time.Date(2026, 4, 16, 12, 0, 0, 0, time.UTC)
|
||||
resp := buildCreateOrderResponse(
|
||||
&dbent.PaymentOrder{
|
||||
ID: 42,
|
||||
Amount: 12.34,
|
||||
FeeRate: 0.03,
|
||||
ExpiresAt: expiresAt,
|
||||
OutTradeNo: "sub2_42",
|
||||
},
|
||||
CreateOrderRequest{PaymentType: payment.TypeWxpay},
|
||||
12.71,
|
||||
&payment.InstanceSelection{PaymentMode: "qrcode"},
|
||||
&payment.CreatePaymentResponse{
|
||||
TradeNo: "sub2_42",
|
||||
QRCode: "weixin://wxpay/bizpayurl?pr=test",
|
||||
},
|
||||
payment.CreatePaymentResultOrderCreated,
|
||||
)
|
||||
|
||||
if resp.ResultType != payment.CreatePaymentResultOrderCreated {
|
||||
t.Fatalf("result type = %q, want %q", resp.ResultType, payment.CreatePaymentResultOrderCreated)
|
||||
}
|
||||
if resp.OutTradeNo != "sub2_42" {
|
||||
t.Fatalf("out_trade_no = %q, want %q", resp.OutTradeNo, "sub2_42")
|
||||
}
|
||||
if resp.QRCode != "weixin://wxpay/bizpayurl?pr=test" {
|
||||
t.Fatalf("qr_code = %q, want %q", resp.QRCode, "weixin://wxpay/bizpayurl?pr=test")
|
||||
}
|
||||
if resp.JSAPI != nil || resp.JSAPIPayload != nil {
|
||||
t.Fatal("order_created response should not include jsapi payload")
|
||||
}
|
||||
if !resp.ExpiresAt.Equal(expiresAt) {
|
||||
t.Fatalf("expires_at = %v, want %v", resp.ExpiresAt, expiresAt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCreateOrderResponseCopiesJSAPIPayload(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
jsapiPayload := &payment.WechatJSAPIPayload{
|
||||
AppID: "wx123",
|
||||
TimeStamp: "1712345678",
|
||||
NonceStr: "nonce-123",
|
||||
Package: "prepay_id=wx123",
|
||||
SignType: "RSA",
|
||||
PaySign: "signed-payload",
|
||||
}
|
||||
resp := buildCreateOrderResponse(
|
||||
&dbent.PaymentOrder{
|
||||
ID: 88,
|
||||
Amount: 66.88,
|
||||
FeeRate: 0.01,
|
||||
ExpiresAt: time.Date(2026, 4, 16, 13, 0, 0, 0, time.UTC),
|
||||
OutTradeNo: "sub2_88",
|
||||
},
|
||||
CreateOrderRequest{PaymentType: payment.TypeWxpay},
|
||||
67.55,
|
||||
&payment.InstanceSelection{PaymentMode: "popup"},
|
||||
&payment.CreatePaymentResponse{
|
||||
TradeNo: "sub2_88",
|
||||
ResultType: payment.CreatePaymentResultJSAPIReady,
|
||||
JSAPI: jsapiPayload,
|
||||
},
|
||||
payment.CreatePaymentResultJSAPIReady,
|
||||
)
|
||||
|
||||
if resp.ResultType != payment.CreatePaymentResultJSAPIReady {
|
||||
t.Fatalf("result type = %q, want %q", resp.ResultType, payment.CreatePaymentResultJSAPIReady)
|
||||
}
|
||||
if resp.JSAPI == nil || resp.JSAPIPayload == nil {
|
||||
t.Fatal("expected jsapi payload aliases to be populated")
|
||||
}
|
||||
if resp.JSAPI != jsapiPayload || resp.JSAPIPayload != jsapiPayload {
|
||||
t.Fatal("expected jsapi aliases to preserve the original pointer")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaybeBuildWeChatOAuthRequiredResponse(t *testing.T) {
|
||||
t.Setenv("WECHAT_OAUTH_MP_APP_ID", "wx123456")
|
||||
t.Setenv("WECHAT_OAUTH_MP_APP_SECRET", "wechat-secret")
|
||||
|
||||
svc := &PaymentService{}
|
||||
|
||||
resp, err := svc.maybeBuildWeChatOAuthRequiredResponse(context.Background(), CreateOrderRequest{
|
||||
Amount: 12.5,
|
||||
PaymentType: payment.TypeWxpay,
|
||||
IsWeChatBrowser: true,
|
||||
SrcURL: "https://merchant.example/payment?from=wechat",
|
||||
OrderType: payment.OrderTypeBalance,
|
||||
}, 12.5, 12.88, 0.03)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatal("expected oauth_required response, got nil")
|
||||
}
|
||||
if resp.ResultType != payment.CreatePaymentResultOAuthRequired {
|
||||
t.Fatalf("result type = %q, want %q", resp.ResultType, payment.CreatePaymentResultOAuthRequired)
|
||||
}
|
||||
if resp.OAuth == nil {
|
||||
t.Fatal("expected oauth payload, got nil")
|
||||
}
|
||||
if resp.OAuth.AppID != "wx123456" {
|
||||
t.Fatalf("appid = %q, want %q", resp.OAuth.AppID, "wx123456")
|
||||
}
|
||||
if resp.OAuth.Scope != "snsapi_base" {
|
||||
t.Fatalf("scope = %q, want %q", resp.OAuth.Scope, "snsapi_base")
|
||||
}
|
||||
if resp.OAuth.RedirectURL != "/auth/wechat/payment/callback" {
|
||||
t.Fatalf("redirect_url = %q, want %q", resp.OAuth.RedirectURL, "/auth/wechat/payment/callback")
|
||||
}
|
||||
if resp.OAuth.AuthorizeURL != "/api/v1/auth/oauth/wechat/payment/start?amount=12.5&order_type=balance&payment_type=wxpay&redirect=%2Fpurchase%3Ffrom%3Dwechat&scope=snsapi_base" {
|
||||
t.Fatalf("authorize_url = %q", resp.OAuth.AuthorizeURL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaybeBuildWeChatOAuthRequiredResponseRequiresMPConfigInWeChat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := &PaymentService{}
|
||||
|
||||
resp, err := svc.maybeBuildWeChatOAuthRequiredResponse(context.Background(), CreateOrderRequest{
|
||||
Amount: 12.5,
|
||||
PaymentType: payment.TypeWxpay,
|
||||
IsWeChatBrowser: true,
|
||||
SrcURL: "https://merchant.example/payment?from=wechat",
|
||||
OrderType: payment.OrderTypeBalance,
|
||||
}, 12.5, 12.88, 0.03)
|
||||
if resp != nil {
|
||||
t.Fatalf("expected nil response, got %+v", resp)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
|
||||
appErr := infraerrors.FromError(err)
|
||||
if appErr.Reason != "WECHAT_PAYMENT_MP_NOT_CONFIGURED" {
|
||||
t.Fatalf("reason = %q, want %q", appErr.Reason, "WECHAT_PAYMENT_MP_NOT_CONFIGURED")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaybeBuildWeChatOAuthRequiredResponseForSelectionSkipsEasyPayProvider(t *testing.T) {
|
||||
t.Setenv("WECHAT_OAUTH_MP_APP_ID", "wx123456")
|
||||
t.Setenv("WECHAT_OAUTH_MP_APP_SECRET", "wechat-secret")
|
||||
|
||||
svc := &PaymentService{}
|
||||
|
||||
resp, err := svc.maybeBuildWeChatOAuthRequiredResponseForSelection(context.Background(), CreateOrderRequest{
|
||||
Amount: 12.5,
|
||||
PaymentType: payment.TypeWxpay,
|
||||
IsWeChatBrowser: true,
|
||||
OrderType: payment.OrderTypeBalance,
|
||||
}, 12.5, 12.88, 0.03, &payment.InstanceSelection{
|
||||
ProviderKey: payment.TypeEasyPay,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatalf("expected nil response, got %+v", resp)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user