Skip to content

Commit af84ae2

Browse files
authored
Merge pull request #53 from dustywusty/hashbrown
Hashbrown
2 parents d3ed383 + 754945b commit af84ae2

File tree

11 files changed

+2539
-715
lines changed

11 files changed

+2539
-715
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ go.work.sum
2727
# env file
2828
.env
2929

30+
# e2e artifacts
31+
e2e-artifacts/
32+
3033
# Editor/IDE
3134
# .idea/
3235
# .vscode/

Makefile

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,22 @@ APP := tinychess
22
BIN := bin/$(APP)
33
PKG := .
44
PORT ?= 8080
5+
CHROMEDP_HEADLESS ?= 1
6+
CHROMEDP_VIEWPORT_WIDTH ?= 1280
7+
CHROMEDP_VIEWPORT_HEIGHT ?= 2000
8+
E2E_RECORD ?= 1
9+
E2E_RECORD_FORMAT ?= gif
10+
E2E_RECORD_FPS ?= 6
11+
E2E_MOVE_DELAY_MS ?= 0
12+
E2E_START_DELAY_MS ?= 0
13+
E2E_CAPTURE_DELAY_MS ?= 200
14+
E2E_RECORD_HOLD_MS ?= 2000
15+
E2E_SEND_EMOJI ?= 1
516

617
# ldflags embeds a build stamp and commit hash; feel free to remove
718
LDFLAGS := -s -w -X 'main.build=$$(date -u +%Y%m%d-%H%M%S)' -X 'main.commit=$$(git rev-parse --short HEAD)'
819

9-
.PHONY: all build run dev clean lint test race
20+
.PHONY: all build run dev clean lint test race test-e2e
1021

1122
all: build
1223

@@ -29,6 +40,26 @@ lint:
2940
test:
3041
go test ./...
3142

43+
test-e2e:
44+
@if [ "$(E2E_RECORD)" = "1" ] && [ "$(E2E_RECORD_FORMAT)" != "frames" ]; then \
45+
command -v ffmpeg >/dev/null || { echo "ffmpeg not found (set E2E_RECORD_FORMAT=frames to skip stitching)"; exit 1; }; \
46+
fi
47+
@mkdir -p e2e-artifacts
48+
@rm -f e2e-artifacts/*.png e2e-artifacts/*.gif e2e-artifacts/*.mp4
49+
CHROMEDP_HEADLESS=$(CHROMEDP_HEADLESS) \
50+
CHROMEDP_VIEWPORT_WIDTH=$(CHROMEDP_VIEWPORT_WIDTH) \
51+
CHROMEDP_VIEWPORT_HEIGHT=$(CHROMEDP_VIEWPORT_HEIGHT) \
52+
E2E_RECORD=$(E2E_RECORD) \
53+
E2E_RECORD_FORMAT=$(E2E_RECORD_FORMAT) \
54+
E2E_RECORD_FPS=$(E2E_RECORD_FPS) \
55+
E2E_RECORD_HOLD_MS=$(E2E_RECORD_HOLD_MS) \
56+
E2E_MOVE_DELAY_MS=$(E2E_MOVE_DELAY_MS) \
57+
E2E_START_DELAY_MS=$(E2E_START_DELAY_MS) \
58+
E2E_CAPTURE_DELAY_MS=$(E2E_CAPTURE_DELAY_MS) \
59+
E2E_SEND_EMOJI=$(E2E_SEND_EMOJI) \
60+
go test -tags e2e ./internal/e2e -run TestPlay -v
61+
@echo "e2e artifacts: e2e-artifacts/"
62+
3263
dev:
3364
@command -v air >/dev/null || { echo "air not found"; exit 1; }
34-
air -c .air.toml
65+
air -c .air.toml

README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,91 @@ Anyone else who opens the link is a spectator.
1414

1515
Players can react with any emoji using the built-in emoji picker.
1616

17+
## Local development
18+
19+
### Bootstrap
20+
21+
- Go 1.22+
22+
- Make
23+
- Optional: `air` for live reload (`go install github.com/cosmtrek/air@latest`)
24+
- Optional: Postgres if you want persistence
25+
26+
### Install + run
27+
28+
```sh
29+
go mod download
30+
make run
31+
```
32+
33+
Open http://localhost:8080.
34+
35+
### Live reload (optional)
36+
37+
```sh
38+
make dev
39+
```
40+
41+
### Database (optional)
42+
43+
Set `DATABASE_URL` to enable persistence (Postgres DSN), for example:
44+
45+
```sh
46+
export DATABASE_URL="postgres://user:pass@localhost:5432/tinychess?sslmode=disable"
47+
```
48+
49+
## Tests
50+
51+
### Unit tests
52+
53+
```sh
54+
go test ./...
55+
```
56+
57+
### Browser e2e test (full game)
58+
59+
Runs a headless browser test that opens two clients and plays a complete legal
60+
game (Fool's Mate) to verify a game can finish.
61+
62+
```sh
63+
go test -tags e2e ./internal/e2e -run TestPlayFullGame
64+
```
65+
66+
Notes:
67+
- Requires a local Chrome/Chromium install.
68+
- If Chrome isn't on your PATH, set `CHROME_BIN` to the browser executable.
69+
- If your environment needs it, set `CHROMEDP_NO_SANDBOX=1`.
70+
- To watch the game being played, run headed with `CHROMEDP_HEADLESS=0`.
71+
- To slow down moves, set `E2E_MOVE_DELAY_MS` (milliseconds between moves).
72+
- To pause before the first move, set `E2E_START_DELAY_MS`.
73+
- To wait for UI updates before capturing, set `E2E_CAPTURE_DELAY_MS`.
74+
- Famous quick mates:
75+
- Fool's Mate: `go test -tags e2e ./internal/e2e -run TestPlayFullGame`
76+
- Scholar's Mate: `go test -tags e2e ./internal/e2e -run TestPlayScholarsMate`
77+
- A longer demo test is available: `go test -tags e2e ./internal/e2e -run TestPlayLongGame`.
78+
- Optional recording:
79+
- Set `E2E_RECORD=1` to capture screenshots before each move (white client).
80+
- Output defaults to `e2e-artifacts/` (override with `E2E_RECORD_DIR`).
81+
- Use `E2E_RECORD_FORMAT=mp4` (default), `gif`, or `frames` (PNGs only).
82+
- Set `E2E_RECORD_FPS` to control playback (default `6`).
83+
- Set `E2E_RECORD_HOLD_MS` to hold the final frame (default `2000`).
84+
- Requires `ffmpeg` on PATH for mp4/gif.
85+
86+
### Make target (run all e2e tests + stitch gifs)
87+
88+
```sh
89+
E2E_RECORD=1 E2E_RECORD_FORMAT=gif E2E_RECORD_FPS=6 make test-e2e
90+
```
91+
92+
Defaults can be overridden:
93+
- `CHROMEDP_HEADLESS=0` to watch the run.
94+
- `CHROMEDP_VIEWPORT_WIDTH` and `CHROMEDP_VIEWPORT_HEIGHT` for mobile/aspect testing.
95+
- `E2E_MOVE_DELAY_MS` and `E2E_START_DELAY_MS` for timing.
96+
- `E2E_CAPTURE_DELAY_MS` to wait for SSE/UI updates before each capture.
97+
- `E2E_RECORD_HOLD_MS` to extend the final frame.
98+
- `E2E_RECORD_FORMAT=frames` to skip stitching (no ffmpeg needed).
99+
- `E2E_SEND_EMOJI=0` to skip the emoji taunt (default on).
100+
- `E2E_EMOJI` to override the emoji character.
101+
17102
## Links
18103

19104
- Production: https://tinychess.dusty.wtf/

bin/tinychess

1.03 MB
Binary file not shown.

go.mod

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
module tinychess
22

3-
go 1.22.2
3+
go 1.24
44

55
require (
6+
github.com/chromedp/chromedp v0.14.2
67
github.com/corentings/chess/v2 v2.2.0
78
github.com/google/uuid v1.5.0
89
gorm.io/driver/postgres v1.5.4
910
gorm.io/gorm v1.25.5
1011
)
1112

1213
require (
14+
github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327 // indirect
15+
github.com/chromedp/sysutil v1.1.0 // indirect
16+
github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2 // indirect
17+
github.com/gobwas/httphead v0.1.0 // indirect
18+
github.com/gobwas/pool v0.2.1 // indirect
19+
github.com/gobwas/ws v1.4.0 // indirect
1320
github.com/jackc/pgpassfile v1.0.0 // indirect
1421
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
1522
github.com/jackc/pgx/v5 v5.4.3 // indirect
1623
github.com/jinzhu/inflection v1.0.0 // indirect
1724
github.com/jinzhu/now v1.1.5 // indirect
1825
golang.org/x/crypto v0.14.0 // indirect
1926
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect
27+
golang.org/x/sys v0.34.0 // indirect
2028
golang.org/x/text v0.13.0 // indirect
2129
)

go.sum

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
1+
github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327 h1:UQ4AU+BGti3Sy/aLU8KVseYKNALcX9UXY6DfpwQ6J8E=
2+
github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
3+
github.com/chromedp/chromedp v0.14.2 h1:r3b/WtwM50RsBZHMUm9fsNhhzRStTHrKdr2zmwbZSzM=
4+
github.com/chromedp/chromedp v0.14.2/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
5+
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
6+
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
17
github.com/corentings/chess/v2 v2.2.0 h1:cvponglvX2gw73hGCgeP2B/RJOWqS1NElwBKNc2eue8=
28
github.com/corentings/chess/v2 v2.2.0/go.mod h1:JhWYDbjY81/7NECXrLzz4g2r9taaMEXvyqS4gYZciVE=
39
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
410
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
511
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12+
github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2 h1:iizUGZ9pEquQS5jTGkh4AqeeHCMbfbjeb0zMt0aEFzs=
13+
github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
14+
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
15+
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
16+
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
17+
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
18+
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
19+
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
620
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
721
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
822
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
@@ -15,6 +29,10 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
1529
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
1630
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
1731
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
32+
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
33+
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
34+
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
35+
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
1836
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1937
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2038
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -26,6 +44,9 @@ golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
2644
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
2745
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
2846
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
47+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
48+
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
49+
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
2950
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
3051
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
3152
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

0 commit comments

Comments
 (0)