test: add coverage tests across backend + fix mock for PENDING checkout support
CI / Nginx config check (push) Successful in 13s
CI / Env docs check (push) Successful in 15s
CI / Docker compose check (push) Successful in 15s
CI / Frontend major deps (push) Failing after 24s
CI / Frontend deps check (push) Successful in 30s
CI / Secrets scan (push) Successful in 38s
CI / Go build (push) Successful in 39s
CI / Frontend build (push) Successful in 1m3s
CI / Knip (push) Successful in 45s
CI / Go vet (prod) (push) Failing after 1m42s
CI / Frontend a11y check (push) Successful in 2m34s
CI / Go vet (dev) (push) Successful in 2m29s
CI / Staticcheck (prod) (push) Failing after 2m38s
CI / go mod tidy (push) Successful in 1m3s
CI / Staticcheck (dev) (push) Successful in 2m55s
CI / Frontend QC (audit) (push) Successful in 51s
CI / golangci-lint (push) Successful in 3m22s
CI / Go vulnerabilities (push) Successful in 1m26s
CI / Frontend QC (typecheck) (push) Successful in 2m18s
CI / Security scan (prod) (push) Successful in 4m18s
CI / Security scan (dev) (push) Successful in 4m40s
CI / Tests (prod) (push) Has been skipped
CI / Tests (dev) (push) Has been skipped
CI / Race (prod) (push) Has been skipped
CI / Race (dev) (push) Has been skipped
CI / Frontend QC (lint) (push) Successful in 2m18s
CI / Svelte strict check (push) Successful in 43s

New test files cover previously untested paths across DAV, validators,
S3, Square, mw, bookings, user, and payments packages.

Includes mock fix: HoldCheckouts flag on MockClient allows tests to
pause auto-complete goroutine for testing PENDING checkout states.

Coverage: 50.4% → 65.0% (+14.6pp)
This commit is contained in:
2026-07-10 18:13:44 +01:00
parent c0442d4ebd
commit 3029fd5179
57 changed files with 12604 additions and 94 deletions
+43 -40
View File
@@ -23,12 +23,13 @@ func mockSleep(d time.Duration) {
}
type MockClient struct {
mu sync.RWMutex
cards map[string]map[string]*CardOnFile
checkouts map[string]*CheckoutResult
payments map[string]*PaymentResult
refunds map[string]*RefundResult
completed map[string]*PaymentResult
mu sync.RWMutex
cards map[string]map[string]*CardOnFile
checkouts map[string]*CheckoutResult
payments map[string]*PaymentResult
refunds map[string]*RefundResult
completed map[string]*PaymentResult
HoldCheckouts bool
}
type devProdClient struct{}
@@ -117,41 +118,43 @@ func (m *MockClient) CreateCheckout(ctx context.Context, req CreateCheckoutReq)
m.checkouts[checkoutID] = result
m.mu.Unlock()
go func() {
defer func() {
if r := recover(); r != nil {
log.Printf("Panic recovered in Square mock payment processing: %v", r)
if !m.HoldCheckouts {
go func() {
defer func() {
if r := recover(); r != nil {
log.Printf("Panic recovered in Square mock payment processing: %v", r)
}
}()
mockSleep(3 * time.Second)
m.mu.Lock()
defer m.mu.Unlock()
paymentID := fmt.Sprintf("pay_%d", clock.Now().UnixNano())
amount := req.Amount
tipAmount := int64(0)
if req.TipEnabled {
tipAmount = 500
amount += tipAmount
}
fees := amount * 175 / 10000 // in-person rate: 1.75%
paymentResult := &PaymentResult{
ID: paymentID,
Status: "COMPLETED",
Amount: amount,
CardBrand: "VISA",
CardLast4: "4242",
TipAmount: tipAmount,
ReceiptURL: "https://squareup.com/receipt/" + paymentID,
SquarePayID: "sqp_" + paymentID,
Fees: fees,
}
m.completed[checkoutID] = paymentResult
m.checkouts[checkoutID].Status = "COMPLETED"
log.Printf("[SQUARE-MOCK] Checkout completed: id=%s, amount=%d, tip=%d", checkoutID, amount, tipAmount)
}()
mockSleep(3 * time.Second)
m.mu.Lock()
defer m.mu.Unlock()
paymentID := fmt.Sprintf("pay_%d", clock.Now().UnixNano())
amount := req.Amount
tipAmount := int64(0)
if req.TipEnabled {
tipAmount = 500
amount += tipAmount
}
fees := amount * 175 / 10000 // in-person rate: 1.75%
paymentResult := &PaymentResult{
ID: paymentID,
Status: "COMPLETED",
Amount: amount,
CardBrand: "VISA",
CardLast4: "4242",
TipAmount: tipAmount,
ReceiptURL: "https://squareup.com/receipt/" + paymentID,
SquarePayID: "sqp_" + paymentID,
Fees: fees,
}
m.completed[checkoutID] = paymentResult
m.checkouts[checkoutID].Status = "COMPLETED"
log.Printf("[SQUARE-MOCK] Checkout completed: id=%s, amount=%d, tip=%d", checkoutID, amount, tipAmount)
}()
}
return result, nil
}
@@ -245,7 +248,7 @@ func (m *MockClient) CreateCardOnFileRaw(ctx context.Context, userID, cardNumber
brands := map[string]string{"4": "VISA", "5": "MASTERCARD", "3": "AMEX", "6": "DISCOVER"}
brand := brands[string(cardNumber[0])]
if brand == "" {
brand = "VISA"
brand = "UNKNOWN"
}
card := &CardOnFile{
@@ -0,0 +1,91 @@
//go:build test && dev
package square
import (
"context"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDevProdClient_CreatePayment(t *testing.T) {
saved := os.Getenv("SQUARE_ENVIRONMENT")
os.Setenv("SQUARE_ENVIRONMENT", "sandbox")
defer os.Setenv("SQUARE_ENVIRONMENT", saved)
client := NewDevClient()
_, err := client.CreatePayment(context.Background(), CreatePaymentReq{})
assert.Error(t, err)
}
func TestDevProdClient_CreateCheckout(t *testing.T) {
saved := os.Getenv("SQUARE_ENVIRONMENT")
os.Setenv("SQUARE_ENVIRONMENT", "sandbox")
defer os.Setenv("SQUARE_ENVIRONMENT", saved)
client := NewDevClient()
_, err := client.CreateCheckout(context.Background(), CreateCheckoutReq{})
assert.Error(t, err)
}
func TestDevProdClient_GetCheckout(t *testing.T) {
saved := os.Getenv("SQUARE_ENVIRONMENT")
os.Setenv("SQUARE_ENVIRONMENT", "sandbox")
defer os.Setenv("SQUARE_ENVIRONMENT", saved)
client := NewDevClient()
_, err := client.GetCheckout(context.Background(), "")
assert.Error(t, err)
}
func TestDevProdClient_RefundPayment(t *testing.T) {
saved := os.Getenv("SQUARE_ENVIRONMENT")
os.Setenv("SQUARE_ENVIRONMENT", "sandbox")
defer os.Setenv("SQUARE_ENVIRONMENT", saved)
client := NewDevClient()
_, err := client.RefundPayment(context.Background(), RefundPaymentReq{})
assert.Error(t, err)
}
func TestDevProdClient_CreateCardOnFile(t *testing.T) {
saved := os.Getenv("SQUARE_ENVIRONMENT")
os.Setenv("SQUARE_ENVIRONMENT", "sandbox")
defer os.Setenv("SQUARE_ENVIRONMENT", saved)
client := NewDevClient()
_, err := client.CreateCardOnFile(context.Background(), "", "")
assert.Error(t, err)
}
func TestDevProdClient_CreateCardOnFileRaw(t *testing.T) {
saved := os.Getenv("SQUARE_ENVIRONMENT")
os.Setenv("SQUARE_ENVIRONMENT", "sandbox")
defer os.Setenv("SQUARE_ENVIRONMENT", saved)
client := NewDevClient()
_, err := client.CreateCardOnFileRaw(context.Background(), "", "", 0, 0, "")
assert.Error(t, err)
}
func TestDevProdClient_GetCardsOnFile(t *testing.T) {
saved := os.Getenv("SQUARE_ENVIRONMENT")
os.Setenv("SQUARE_ENVIRONMENT", "sandbox")
defer os.Setenv("SQUARE_ENVIRONMENT", saved)
client := NewDevClient()
_, err := client.GetCardsOnFile(context.Background(), "")
assert.Error(t, err)
}
func TestDevProdClient_DeleteCardOnFile(t *testing.T) {
saved := os.Getenv("SQUARE_ENVIRONMENT")
os.Setenv("SQUARE_ENVIRONMENT", "sandbox")
defer os.Setenv("SQUARE_ENVIRONMENT", saved)
client := NewDevClient()
err := client.DeleteCardOnFile(context.Background(), "")
assert.Error(t, err)
}
@@ -7,6 +7,9 @@ import (
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDevClient_CreatePayment_ReturnsCompleted(t *testing.T) {
@@ -308,6 +311,56 @@ func TestDevClient_GetCheckout_NotFound(t *testing.T) {
}
}
func TestDevClient_CreateCardOnFileRaw_Visa(t *testing.T) {
client := NewDevClient().(*MockClient)
card, err := client.CreateCardOnFileRaw(context.Background(), "user-raw-1", "4111111111111111", 12, 2030, "123")
require.NoError(t, err)
assert.Equal(t, "VISA", card.Brand)
assert.Equal(t, "1111", card.Last4)
assert.True(t, card.IsDefault)
}
func TestDevClient_CreateCardOnFileRaw_Mastercard(t *testing.T) {
client := NewDevClient().(*MockClient)
ctx := context.Background()
// First card to set up non-default check
_, err := client.CreateCardOnFileRaw(ctx, "user-raw-2", "4111111111111111", 12, 2030, "123")
require.NoError(t, err)
// Mastercard is second → not default
card, err := client.CreateCardOnFileRaw(ctx, "user-raw-2", "5555555555554444", 12, 2030, "123")
require.NoError(t, err)
assert.Equal(t, "MASTERCARD", card.Brand)
assert.Equal(t, "4444", card.Last4)
assert.False(t, card.IsDefault)
}
func TestDevClient_CreateCardOnFileRaw_Amex(t *testing.T) {
client := NewDevClient().(*MockClient)
card, err := client.CreateCardOnFileRaw(context.Background(), "user-raw-3", "378282246310005", 12, 2030, "123")
require.NoError(t, err)
assert.Equal(t, "AMEX", card.Brand)
assert.Equal(t, "0005", card.Last4)
assert.True(t, card.IsDefault)
}
func TestDevClient_CreateCardOnFileRaw_Discover(t *testing.T) {
client := NewDevClient().(*MockClient)
card, err := client.CreateCardOnFileRaw(context.Background(), "user-raw-4", "6011111111111117", 12, 2030, "123")
require.NoError(t, err)
assert.Equal(t, "DISCOVER", card.Brand)
assert.Equal(t, "1117", card.Last4)
assert.True(t, card.IsDefault)
}
func TestDevClient_CreateCardOnFileRaw_UnknownBrand(t *testing.T) {
client := NewDevClient().(*MockClient)
card, err := client.CreateCardOnFileRaw(context.Background(), "user-raw-5", "9999999999999999", 12, 2030, "123")
require.NoError(t, err)
assert.Equal(t, "UNKNOWN", card.Brand)
assert.Equal(t, "9999", card.Last4)
assert.True(t, card.IsDefault)
}
func TestDevClient_ConcurrentPayments(t *testing.T) {
client := NewDevClient().(*MockClient)