Migrate all test files from SetupTestDB/db.DB pattern to per-test transactions: - Replace SetupTestDB(t) with SetupTestTx(t) for context + transaction - Replace db.DB.Query/QueryRow/Exec with tx.Query/QueryRow/Exec - Replace context.Background() with context from SetupTestTx - Replace defer rows.Close() pattern with explicit rows.Close() - Add testdb.SeedBaseline(pool) to all TestMain functions - Wire db.Conn = db.NewPoolProxy(pool) in all TestMain functions Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
245 lines
8.2 KiB
Go
245 lines
8.2 KiB
Go
//go:build test
|
|
// +build test
|
|
|
|
package admin
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
|
|
"crussell/testutils"
|
|
)
|
|
|
|
func intPtr(i int) *int { return &i }
|
|
func float64Ptr(f float64) *float64 { return &f }
|
|
func boolPtr(b bool) *bool { return &b }
|
|
|
|
// TestGetBusinessSettings verifies that GET /api/admin/settings returns the
|
|
// current business settings row.
|
|
func TestGetBusinessSettings(t *testing.T) {
|
|
ctx, tx := testutils.SetupTestTx(t)
|
|
|
|
_, err := tx.Exec(ctx, `UPDATE business_settings SET business_name = 'Test Salon', business_address = '123 Test St', currency_code = 'GBP', gift_card_expiry_months = 12, voucher_type = 'SPV'`)
|
|
if err != nil {
|
|
t.Fatalf("failed to seed business settings: %v", err)
|
|
}
|
|
|
|
handler := http.HandlerFunc(GetBusinessSettings)
|
|
w := makeAdminRequest(handler, "GET", "/api/admin/settings", nil, ctx)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var s BusinessSettings
|
|
if err := parseResponseBody(w, &s); err != nil {
|
|
t.Fatalf("failed to parse response: %v", err)
|
|
}
|
|
|
|
if s.BusinessName != "Test Salon" {
|
|
t.Errorf("expected BusinessName 'Test Salon', got '%s'", s.BusinessName)
|
|
}
|
|
if s.BusinessAddress != "123 Test St" {
|
|
t.Errorf("expected BusinessAddress '123 Test St', got '%s'", s.BusinessAddress)
|
|
}
|
|
if s.CurrencyCode != "GBP" {
|
|
t.Errorf("expected CurrencyCode 'GBP', got '%s'", s.CurrencyCode)
|
|
}
|
|
if s.GiftCardExpiryMonths != 12 {
|
|
t.Errorf("expected GiftCardExpiryMonths 12, got %d", s.GiftCardExpiryMonths)
|
|
}
|
|
if s.VoucherType != "SPV" {
|
|
t.Errorf("expected VoucherType 'SPV', got '%s'", s.VoucherType)
|
|
}
|
|
}
|
|
|
|
// TestUpdateBusinessSettings verifies that updating a single field via
|
|
// PUT /api/admin/settings returns 200 with the updated settings.
|
|
func TestUpdateBusinessSettings(t *testing.T) {
|
|
ctx, _ := testutils.SetupTestTx(t)
|
|
|
|
handler := http.HandlerFunc(UpdateBusinessSettings)
|
|
body := UpdateBusinessSettingsRequest{
|
|
BusinessName: stringPtr("Updated Salon Name"),
|
|
}
|
|
w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var s BusinessSettings
|
|
if err := parseResponseBody(w, &s); err != nil {
|
|
t.Fatalf("failed to parse response: %v", err)
|
|
}
|
|
|
|
if s.BusinessName != "Updated Salon Name" {
|
|
t.Errorf("expected BusinessName 'Updated Salon Name', got '%s'", s.BusinessName)
|
|
}
|
|
}
|
|
|
|
// TestUpdateBusinessSettings_MultipleFields verifies that updating several
|
|
// fields at once works correctly.
|
|
func TestUpdateBusinessSettings_MultipleFields(t *testing.T) {
|
|
ctx, _ := testutils.SetupTestTx(t)
|
|
|
|
handler := http.HandlerFunc(UpdateBusinessSettings)
|
|
body := UpdateBusinessSettingsRequest{
|
|
BusinessName: stringPtr("Multi Update Salon"),
|
|
BusinessAddress: stringPtr("456 New St"),
|
|
GiftCardExpiryMonths: intPtr(24),
|
|
VoucherType: stringPtr("MPV"),
|
|
}
|
|
w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var s BusinessSettings
|
|
if err := parseResponseBody(w, &s); err != nil {
|
|
t.Fatalf("failed to parse response: %v", err)
|
|
}
|
|
|
|
if s.BusinessName != "Multi Update Salon" {
|
|
t.Errorf("expected BusinessName 'Multi Update Salon', got '%s'", s.BusinessName)
|
|
}
|
|
if s.BusinessAddress != "456 New St" {
|
|
t.Errorf("expected BusinessAddress '456 New St', got '%s'", s.BusinessAddress)
|
|
}
|
|
if s.GiftCardExpiryMonths != 24 {
|
|
t.Errorf("expected GiftCardExpiryMonths 24, got %d", s.GiftCardExpiryMonths)
|
|
}
|
|
if s.VoucherType != "MPV" {
|
|
t.Errorf("expected VoucherType 'MPV', got '%s'", s.VoucherType)
|
|
}
|
|
}
|
|
|
|
// TestUpdateBusinessSettings_InvalidVoucherType verifies that an invalid
|
|
// voucher_type value returns 400.
|
|
func TestUpdateBusinessSettings_InvalidVoucherType(t *testing.T) {
|
|
ctx, _ := testutils.SetupTestTx(t)
|
|
|
|
handler := http.HandlerFunc(UpdateBusinessSettings)
|
|
body := UpdateBusinessSettingsRequest{
|
|
VoucherType: stringPtr("INVALID"),
|
|
}
|
|
w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("expected status 400, got %d. body: %s", w.Code, w.Body.String())
|
|
}
|
|
if w.Body.String() != "voucher_type must be 'SPV' or 'MPV'\n" {
|
|
t.Errorf("unexpected error message: %s", w.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestUpdateBusinessSettings_NegativeExpiryMonths verifies that a
|
|
// gift_card_expiry_months value less than 1 returns 400.
|
|
func TestUpdateBusinessSettings_NegativeExpiryMonths(t *testing.T) {
|
|
ctx, _ := testutils.SetupTestTx(t)
|
|
|
|
handler := http.HandlerFunc(UpdateBusinessSettings)
|
|
body := UpdateBusinessSettingsRequest{
|
|
GiftCardExpiryMonths: intPtr(0),
|
|
}
|
|
w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("expected status 400, got %d. body: %s", w.Code, w.Body.String())
|
|
}
|
|
if w.Body.String() != "gift_card_expiry_months must be at least 1\n" {
|
|
t.Errorf("unexpected error message: %s", w.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestUpdateBusinessSettings_InvalidVATRate verifies that a default_vat_rate
|
|
// outside the 0-100 range returns 400.
|
|
func TestUpdateBusinessSettings_InvalidVATRate(t *testing.T) {
|
|
ctx, _ := testutils.SetupTestTx(t)
|
|
|
|
handler := http.HandlerFunc(UpdateBusinessSettings)
|
|
|
|
body := UpdateBusinessSettingsRequest{
|
|
DefaultVATRate: float64Ptr(-1),
|
|
}
|
|
w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("expected status 400 for negative rate, got %d. body: %s", w.Code, w.Body.String())
|
|
}
|
|
if w.Body.String() != "default_vat_rate must be between 0 and 100\n" {
|
|
t.Errorf("unexpected error message: %s", w.Body.String())
|
|
}
|
|
body2 := UpdateBusinessSettingsRequest{
|
|
DefaultVATRate: float64Ptr(101),
|
|
}
|
|
w2 := makeAdminRequest(handler, "PUT", "/api/admin/settings", body2, ctx)
|
|
|
|
if w2.Code != http.StatusBadRequest {
|
|
t.Errorf("expected status 400 for rate > 100, got %d. body: %s", w2.Code, w2.Body.String())
|
|
}
|
|
if w2.Body.String() != "default_vat_rate must be between 0 and 100\n" {
|
|
t.Errorf("unexpected error message: %s", w2.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestUpdateBusinessSettings_NoFields verifies that an empty request body
|
|
// (no fields to update) returns 400.
|
|
func TestUpdateBusinessSettings_NoFields(t *testing.T) {
|
|
ctx, _ := testutils.SetupTestTx(t)
|
|
|
|
handler := http.HandlerFunc(UpdateBusinessSettings)
|
|
w := makeAdminRequest(handler, "PUT", "/api/admin/settings", UpdateBusinessSettingsRequest{}, ctx)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("expected status 400, got %d. body: %s", w.Code, w.Body.String())
|
|
}
|
|
if w.Body.String() != "No fields to update\n" {
|
|
t.Errorf("unexpected error message: %s", w.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestUpdateBusinessSettings_PartialUpdate verifies that updating a single field
|
|
// leaves other fields unchanged.
|
|
func TestUpdateBusinessSettings_PartialUpdate(t *testing.T) {
|
|
ctx, tx := testutils.SetupTestTx(t)
|
|
|
|
_, err := tx.Exec(ctx, `UPDATE business_settings SET business_name = 'Test Salon', business_address = '123 Test St', currency_code = 'GBP', gift_card_expiry_months = 12, voucher_type = 'SPV'`)
|
|
if err != nil {
|
|
t.Fatalf("failed to seed business settings: %v", err)
|
|
}
|
|
|
|
handler := http.HandlerFunc(UpdateBusinessSettings)
|
|
body := UpdateBusinessSettingsRequest{
|
|
GiftCardExpiryMonths: intPtr(36),
|
|
}
|
|
w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var s BusinessSettings
|
|
if err := parseResponseBody(w, &s); err != nil {
|
|
t.Fatalf("failed to parse response: %v", err)
|
|
}
|
|
|
|
if s.GiftCardExpiryMonths != 36 {
|
|
t.Errorf("expected GiftCardExpiryMonths 36, got %d", s.GiftCardExpiryMonths)
|
|
}
|
|
|
|
if s.BusinessName != "Test Salon" {
|
|
t.Errorf("expected BusinessName 'Test Salon' (unchanged), got '%s'", s.BusinessName)
|
|
}
|
|
if s.BusinessAddress != "123 Test St" {
|
|
t.Errorf("expected BusinessAddress '123 Test St' (unchanged), got '%s'", s.BusinessAddress)
|
|
}
|
|
if s.VoucherType != "SPV" {
|
|
t.Errorf("expected VoucherType 'SPV' (unchanged), got '%s'", s.VoucherType)
|
|
}
|
|
if s.CurrencyCode != "GBP" {
|
|
t.Errorf("expected CurrencyCode 'GBP' (unchanged), got '%s'", s.CurrencyCode)
|
|
}
|
|
}
|