Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.test.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# e2e test credentials template.
# Copy to .env.test and fill in real tokens (that file is git-excluded).

FIZZY_TEST_TOKEN=fizzy_your_token_here
FIZZY_TEST_ACCOUNT=1234567
FIZZY_TEST_API_URL=https://app.fizzy.do
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ completions/
# Profiling
profiles/
default.pgo

# Local test credentials
.env.test
64 changes: 41 additions & 23 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
.PHONY: test test-unit test-e2e test-go test-file test-run build clean tidy help \
.PHONY: test test-unit test-e2e e2e test-go test-file e2e-file test-run e2e-run build clean tidy help \
check-toolchain fmt fmt-check vet lint tidy-check race-test vuln secrets \
replace-check security check release-check release tools \
surface-snapshot surface-check lint-actions

BINARY := $(CURDIR)/bin/fizzy
FIZZY_TEST_BINARY ?= $(BINARY)

# Load local test credentials if present, but refuse tracked local secret files.
ifneq ($(shell git ls-files --error-unmatch .env.test >/dev/null 2>&1 && echo tracked),)
$(error .env.test is tracked by Git. Remove it from version control and keep local secret files untracked)
endif
-include .env.test
export FIZZY_TEST_TOKEN FIZZY_TEST_ACCOUNT FIZZY_TEST_API_URL FIZZY_TEST_BINARY
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
LDFLAGS := -X main.version=$(VERSION)

Expand All @@ -20,10 +28,13 @@ help:
@echo "Usage:"
@echo " make build Build the CLI"
@echo " make test-unit Run unit tests (no API required)"
@echo " make test-e2e Run e2e tests (requires API credentials)"
@echo " make test Alias for test-e2e"
@echo " make test-file Run a specific e2e test file"
@echo " make test-run Run a specific e2e test by name"
@echo " make e2e Run owner-only CLI contract e2e tests"
@echo " make test-e2e Alias for e2e"
@echo " make test Alias for e2e"
@echo " make e2e-file Run a specific CLI contract e2e test file"
@echo " make test-file Alias for e2e-file"
@echo " make e2e-run Run a specific CLI contract e2e test by name"
@echo " make test-run Alias for e2e-run"
@echo " make clean Remove build artifacts"
@echo " make tidy Tidy dependencies"
@echo ""
Expand All @@ -45,17 +56,19 @@ help:
@echo " make tools Install dev tools"
@echo ""
@echo "Environment variables (required for e2e tests):"
@echo " FIZZY_TEST_TOKEN API token"
@echo " FIZZY_TEST_ACCOUNT Account slug"
@echo " FIZZY_TEST_API_URL API base URL (default: https://app.fizzy.do)"
@echo " FIZZY_TEST_USER_ID User ID for user update/deactivate tests (optional)"
@echo " FIZZY_TEST_TOKEN API token"
@echo " FIZZY_TEST_ACCOUNT Account slug"
@echo " FIZZY_TEST_API_URL API base URL (default: https://app.fizzy.do)"
@echo " FIZZY_TEST_BINARY Prebuilt binary path (optional)"
@echo " FIZZY_E2E_KEEP_FIXTURE Set to 1 to skip final fixture teardown"
@echo " FIZZY_E2E_TEARDOWN_DELAY Delay teardown by N seconds"
@echo ""
@echo "Examples:"
@echo " make build"
@echo " make test-unit"
@echo " export FIZZY_TEST_TOKEN=your-token"
@echo " export FIZZY_TEST_ACCOUNT=your-account"
@echo " make test-e2e"
@echo " make e2e"

# Toolchain guard — fails fast when PATH go and GOROOT go disagree
check-toolchain:
Expand All @@ -80,28 +93,33 @@ test-unit: check-toolchain
go test -v ./internal/...

# Run e2e tests (requires API credentials)
test-e2e: build
e2e: build
@if [ -z "$$FIZZY_TEST_TOKEN" ]; then echo "Error: FIZZY_TEST_TOKEN not set"; exit 1; fi
@if [ -z "$$FIZZY_TEST_ACCOUNT" ]; then echo "Error: FIZZY_TEST_ACCOUNT not set"; exit 1; fi
FIZZY_TEST_BINARY=$(BINARY) go test -v ./e2e/tests/...
go test -v -count=1 -timeout 10m ./e2e/cli_tests/...

Comment thread
robzolkos marked this conversation as resolved.
# Alias for test-e2e
test: test-e2e
test-go: test-e2e
test-e2e: e2e

# Run a single test file (e.g., make test-file FILE=board)
test-file: build
@if [ -z "$(FILE)" ]; then echo "Usage: make test-file FILE=board"; exit 1; fi
test: e2e
test-go: e2e

# Run a single test file (e.g., make e2e-file FILE=crud_board)
e2e-file: build
@if [ -z "$(FILE)" ]; then echo "Usage: make e2e-file FILE=crud_board"; exit 1; fi
@if [ -z "$$FIZZY_TEST_TOKEN" ]; then echo "Error: FIZZY_TEST_TOKEN not set"; exit 1; fi
@if [ -z "$$FIZZY_TEST_ACCOUNT" ]; then echo "Error: FIZZY_TEST_ACCOUNT not set"; exit 1; fi
FIZZY_TEST_BINARY=$(BINARY) go test -v ./e2e/tests/$(FILE)_test.go
go test -v -count=1 ./e2e/cli_tests/$(FILE)_test.go

test-file: e2e-file

# Run a single test by name (e.g., make test-run NAME=TestBoardCRUD)
test-run: build
@if [ -z "$(NAME)" ]; then echo "Usage: make test-run NAME=TestBoardCRUD"; exit 1; fi
# Run a single test by name (e.g., make e2e-run NAME=TestBoardList)
e2e-run: build
@if [ -z "$(NAME)" ]; then echo "Usage: make e2e-run NAME=TestBoardList"; exit 1; fi
@if [ -z "$$FIZZY_TEST_TOKEN" ]; then echo "Error: FIZZY_TEST_TOKEN not set"; exit 1; fi
@if [ -z "$$FIZZY_TEST_ACCOUNT" ]; then echo "Error: FIZZY_TEST_ACCOUNT not set"; exit 1; fi
FIZZY_TEST_BINARY=$(BINARY) go test -v -run $(NAME) ./e2e/tests/...
go test -v -count=1 -run $(NAME) ./e2e/cli_tests/...

test-run: e2e-run

# Format Go source
fmt:
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,20 @@ fizzy skill install
```bash
make build # Build binary
make test-unit # Run unit tests (no API required)
make test-e2e # Run e2e tests (requires FIZZY_TEST_TOKEN, FIZZY_TEST_ACCOUNT)
make e2e # Run owner-only CLI contract e2e suite
make e2e-run NAME=TestBoardList
```

E2E requirements:
- `FIZZY_TEST_TOKEN`
- `FIZZY_TEST_ACCOUNT`
- optional: `FIZZY_TEST_API_URL`
- optional: `FIZZY_TEST_BINARY`

Useful local inspection modes:
- `FIZZY_E2E_KEEP_FIXTURE=1 make e2e`
- `FIZZY_E2E_TEARDOWN_DELAY=120 make e2e`

## License

[MIT](LICENSE)
124 changes: 124 additions & 0 deletions e2e/cli_tests/account_user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package clitests

import (
"strconv"
"testing"
)

func TestAccountShow(t *testing.T) {
assertOK(t, newHarness(t).Run("account", "show"))
}

func TestAccountSettingsUpdateWithCurrentName(t *testing.T) {
h := newHarness(t)
show := h.Run("account", "show")
assertOK(t, show)
currentName := show.GetDataString("name")
if currentName == "" {
t.Skip("account show returned no name")
}
assertOK(t, h.Run("account", "settings-update", "--name", currentName))
show = h.Run("account", "show")
assertOK(t, show)
if got := show.GetDataString("name"); got != currentName {
t.Fatalf("expected account name %q after settings-update, got %q", currentName, got)
}
}

func TestAccountEntropyWithCurrentValue(t *testing.T) {
h := newHarness(t)
show := h.Run("account", "show")
assertOK(t, show)
days := show.GetDataInt("auto_postpone_period_in_days")
if days == 0 {
days = 7
}
assertOK(t, h.Run("account", "entropy", "--auto_postpone_period_in_days", strconv.Itoa(days)))
show = h.Run("account", "show")
assertOK(t, show)
if got := show.GetDataInt("auto_postpone_period_in_days"); got != days {
t.Fatalf("expected auto_postpone_period_in_days=%d, got %d", days, got)
}
}

func TestAccountJoinCodeShow(t *testing.T) {
assertOK(t, newHarness(t).Run("account", "join-code-show"))
}

func TestAccountExportCreateShow(t *testing.T) {
h := newHarness(t)
create := h.Run("account", "export-create")
assertOK(t, create)
exportID := create.GetDataString("id")
if exportID == "" {
exportID = mapValueString(create.GetDataMap(), "id")
}
if exportID == "" {
t.Fatal("expected export ID in export-create response")
}
show := h.Run("account", "export-show", exportID)
assertOK(t, show)
if got := mapValueString(show.GetDataMap(), "id"); got != exportID {
t.Fatalf("expected export-show id %q, got %q", exportID, got)
}
if got := mapValueString(show.GetDataMap(), "status"); got == "" {
t.Fatal("expected export status in export-show response")
}
}

func TestUserList(t *testing.T) {
result := newHarness(t).Run("user", "list")
assertOK(t, result)
if result.GetDataArray() == nil {
t.Fatal("expected array response")
}
}

func TestUserShowAndUpdateOwnProfile(t *testing.T) {
h := newHarness(t)
userID := currentUserID(t, h)
show := h.Run("user", "show", userID)
assertOK(t, show)
currentName := show.GetDataString("name")
if currentName == "" {
t.Skip("user show returned no name")
}
assertOK(t, h.Run("user", "update", userID, "--name", currentName))
show = h.Run("user", "show", userID)
assertOK(t, show)
if got := show.GetDataString("name"); got != currentName {
t.Fatalf("expected user name %q after update, got %q", currentName, got)
}
}

func TestUserAvatarUpdateAndRemove(t *testing.T) {
h := newHarness(t)
userID := currentUserID(t, h)
fixturePath := fixtureFile(t, "test_image.png")

show := h.Run("user", "show", userID)
assertOK(t, show)
avatarURL := show.GetDataString("avatar_url")
if avatarURL == "" {
t.Skip("user show returned no avatar_url")
}
initiallyAttached := avatarRedirects(t, avatarURL)
if initiallyAttached {
t.Cleanup(func() {
assertOK(t, newHarness(t).Run("user", "update", userID, "--avatar", fixturePath))
if !avatarRedirects(t, avatarURL) {
t.Fatal("expected avatar to be restored")
}
})
}

assertOK(t, h.Run("user", "update", userID, "--avatar", fixturePath))
if !avatarRedirects(t, avatarURL) {
t.Fatal("expected uploaded avatar endpoint to redirect to an image blob")
}

assertOK(t, h.Run("user", "avatar-remove", userID))
if avatarRedirects(t, avatarURL) {
t.Fatal("expected avatar endpoint to fall back to generated SVG after removal")
}
}
Loading
Loading