Commit graph

19 commits

Author SHA1 Message Date
Jamie Ontiveros
02425038aa
Make the test suite pass on MySQL (#307)
* Give the foreign key a backing index before dropping the unique

social_accounts.workspace_id carries a foreign key, and the composite
unique index is the only one covering it, as its leftmost prefix. MySQL
refuses to drop the sole index backing a foreign key (SQLSTATE[HY000]
1553), so both rehearsal suites failed in beforeEach and never ran a
single assertion on MySQL. Add a plain index on workspace_id first;
PostgreSQL has no such requirement and simply carries it.

This unmasks one assertion underneath that had never executed: the
automation graph comparison at DuplicateIdentityMigrationTest.php:419
depended on JSON object key order, which MySQL normalises on storage.

(cherry picked from commit 98a494bd2205e873321a18232f63b358ae259fdf)

* Compare JSON payloads without depending on key order

MySQL normalises JSON object keys (length, then lexicographic) on
storage, so an identity comparison against a literal asserts how the
driver chose to lay the object out rather than what it contains.
PostgreSQL preserves insertion order, which is why these passed there.

toEqual compares associative arrays recursively without regard to key
order. Applied to every assertion in this class, including the few that
pass today only because their keys already happen to match MySQL's
ordering.

(cherry picked from commit 3124023c548d6c2b8b52126afc6fc5f38d461ea6)

* Match logged SQL without depending on identifier quoting

Four DB::listen predicates matched 'select * from "post_platforms"'.
PostgreSQL quotes identifiers with double quotes and MySQL with
backticks, so on MySQL the predicates never matched, the simulated
mid-run pause never fired, and the race these tests exist to cover went
unexercised while the tests still reported failures elsewhere.

Compare against the unquoted form via a small helper.

(cherry picked from commit 67a81df5de155e80227df748b34cd8b3cfd744f9)

* Cast raw boolean reads in tests so they pass on MySQL

Three assertions read oauth_refresh_tokens.revoked through the query
builder rather than Eloquent, so no cast applies and the driver's native
representation leaks into the test: a real boolean on PostgreSQL, 1 on
MySQL. Cast explicitly at the call site.

(cherry picked from commit 2911c5c48cf65d24a34a41e667335c40005839a7)

* Use a scheduling date inside MySQL's TIMESTAMP range

MySQL TIMESTAMP columns end at 2038-01-19, so the 2099 sentinel these
tests used is rejected outright with SQLSTATE[22007]. 2037-12-31 still
reads as a far-future schedule and works on both engines.

(cherry picked from commit bde33eb239cdbd3a5567d4c21e1d85302913cdd7)

* Remove the duplicate-identity migration scenario test

The suite rebuilt a pre-migration schema by dropping the unique index in
beforeEach and re-running the migration by hand, exercising a database
state the application never runs in.

* Fix the MySQL rollback path and run CI on both engines

The migration's down() dropped a unique whose leftmost prefix is an FK
column, which MySQL refuses when nothing else backs the constraint
(SQLSTATE 1553). It now creates a standalone index first, so
migrate:rollback works on MySQL and stays a no-op change for PostgreSQL.
up() is untouched: every database already migrated keeps its schema.

The rehearsal test calls that down() instead of hand-rolling the drop,
so it exercises the real rollback rather than an imitation of it.

Matches logged SQL through the connection's query grammar rather than
stripping quote characters, and adds a MySQL leg to the backend CI job.

* Use a readiness check both database images can run

mysql:8.4 installs mysql-community-server-minimal, which ships neither
mysqladmin nor the mysql client, so a mysqladmin health command never
succeeds and the service never reports healthy. Both images run their
init phase without networking, so an open port is the point either
engine starts accepting connections - one check covers both, and the
per-engine matrix key goes away.

* Use each engine's own readiness tool

pg_isready and mysqladmin ping are what the respective images ship for
this, and the mysql image's entrypoint invokes mysqladmin itself, so it
is present. Keeps 20 retries, which MySQL needs to finish initialising.

* State the two-engine ceiling as a rule, not a test detail

The 2038 TIMESTAMP limit binds anything written to the column, not just
the sentinel dates in fixtures, and the same reasoning generalises: what
the app supports is the intersection of both engines.

* Let the release image connect to MySQL

The published image installed only pdo_pgsql, so DB_CONNECTION=mysql
failed with "could not find driver" before any query ran - the app
supports MySQL but the image people actually deploy could not reach it.
mysql-client mirrors the postgresql-client already present, for
artisan db and dumps.

* Keep "backend" a single required status check

Matrixing the job split its check in two, so the "backend" context the
branch protection requires was never reported and every PR sat waiting
on it. The matrix is now "tests" and a small "backend" job gates on it,
which keeps the required check stable however many engines the matrix
grows to - and leaves the open PRs mergeable without a rebase.

---------

Co-authored-by: Paulo Castellano <paulo@castellanos.llc>
2026-08-29 11:05:33 -03:00
Paulo Castellano
80888641e5
ci: local TIA test runs; simplify e2e (drop sharding + e2e-gate) (#262)
* ci: name e2e shards descriptively and add time-balanced sharding

- e2e job now shows as "e2e (shard 1/2)" / "e2e (shard 2/2)" in checks
  instead of the unlabeled matrix "(1)" / "(2)" suffix
- add scheduled/manual "Update Shards" workflow that generates and
  commits tests/.pest/shards.json so Pest balances the two e2e shards
  by real execution time instead of file count

* ci: enable Pest TIA for local test runs

Scoped to local via locally() so CI keeps running the full suite on
every commit. Add composer test:tia script using herd coverage, since
Herd bundles Xdebug but doesn't load it by default.

* ci: drop Herd-specific prefix from test:tia composer script

trypost is open-source and self-hosted; not every contributor runs
Herd. The script now just needs a coverage driver (Xdebug/PCOV)
active however the environment provides it — Herd users can run it
via "herd coverage composer test:tia".

* ci: revert e2e sharding, drop Update Shards workflow

Sharding across 2 runners added complexity (unbalanced shards without
timing data, plus an Update Shards workflow that can't push straight
to main under branch protection) that isn't worth it here. e2e now
runs tests/Browser as a single job again; e2e-gate stays as a
pass-through so the required branch protection check name is
unchanged.

* ci: drop redundant e2e-gate job

e2e-gate only mirrored e2e's own result once sharding was removed.
Updated main's branch protection required_status_checks to require
"e2e" directly instead of "e2e-gate".
2026-08-09 12:24:10 -03:00
Paulo Castellano
44127c4890 Remove the Vitest frontend unit-test layer
The project's test strategy is backend + e2e only, so drop the Vitest setup that had been added for the crop math: the imageCrop.test.ts suite, vitest.config.ts, the dependency and test:unit script, the CI step, and the test:all reference. The crop math is exercised through the Pest browser test.
2026-07-04 10:53:08 -03:00
Paulo Castellano
de75ef4703 Bump release-docker actions to Node 24
Move checkout, upload-artifact, and download-artifact to their current majors so the release image build stops relying on the deprecated Node 20 runtime. Docker actions are left as-is (not flagged). Only runs on release tags, so it is not exercised by PR CI.
2026-07-04 10:35:36 -03:00
Paulo Castellano
45d0dbf510 Bump CI actions to Node 24 and shard the e2e job
Move actions/checkout, setup-node, cache, and upload-artifact to their current majors (Node 24 runtime). Run the browser suite as a sharded matrix aggregated by an e2e-gate job, so the required status check stays a stable name as the shard count scales. Vitest runs once (shard 1). Ready for the incoming e2e test expansion.
2026-07-04 10:28:17 -03:00
Paulo Castellano
2d72d74cc8 Split CI into parallel backend and e2e jobs
Extract the shared PHP/Composer/Node/database/Passport setup into a composite action, and run the backend suite (Unit + Feature) and the frontend/e2e suite (Vitest + Playwright browser tests) as two parallel jobs. This isolates the flaky browser suite so it can be rerun on its own, surfaces failures by area, gives the growing e2e suite room to shard, and uploads Playwright artifacts on failure.
2026-07-04 10:14:01 -03:00
Paulo Castellano
ef81ea74a8 Add frontend unit tests and harden the cropper's test coverage
Add Vitest (test:unit) with exact-value tests for the crop math (containScale, defaultSelection, clampSelection, all resizeSelection corners, and mime/filename resolution), and wire it plus the Pest browser test into CI. The browser test now samples output pixels against a four-quadrant fixture, so it detects a blank, flipped, or wrong crop rather than only asserting a 512x512 canvas. Add composer test:all to run PHP + Vitest + browser tests locally.
2026-07-04 09:56:38 -03:00
Paulo Castellano
09fa97d539 refactor(docker): align echo.ts with the shared sendkit config
Make resources/js/echo.ts byte-identical to the sendkit Echo setup
(VITE_REVERB_* read directly, no window.location derivation). The release
workflow now bakes only VITE_REVERB_APP_KEY, and compose.prod.yaml restores
the 8080 host port so the published image's Reverb client (baked at
localhost:8080) works for local docker compose. A custom-domain deploy needs
the image rebuilt with VITE_REVERB_HOST/PORT/SCHEME set.
2026-05-27 15:17:47 -03:00
Paulo Castellano
48727c80cd feat(docker): add Caddy reverse proxy and domain-portable Reverb config
Add an optional Caddy service (proxy profile) to compose.prod.yaml for
automatic HTTPS on a custom domain, with a Caddyfile that transparently
proxies WebSocket upgrades.

Move Echo setup into resources/js/echo.ts and derive the Reverb host from
window.location when VITE_REVERB_* is unset, so the published image's frontend
connects on any domain without a rebuild. The release workflow bakes a fixed
public Reverb key and leaves host/port/scheme empty to enable this; the Herd
dev setup keeps its explicit VITE_REVERB_* values, so its behaviour is
unchanged.

Drop the now-unneeded 8080 host port — the WebSocket rides the main HTTP(S)
port via the in-container nginx /app proxy.
2026-05-27 14:53:46 -03:00
Paulo Castellano
5b9226569f feat(docker): publish multi-arch image to GHCR and add self-host compose
Add a release workflow that builds docker/Dockerfile (production target) for
linux/amd64 and linux/arm64 on native runners and publishes a single
multi-arch manifest to ghcr.io/trypostit/trypost on every v*.*.* tag, tagged
with semver (1.2.3, 1.2, 1) and latest.

Add compose.prod.yaml: a self-host stack that pulls the published image
alongside Postgres and Redis with persistent volumes. Config is inline with
sectioned comments, including a commented S3/R2 block (storage already uses
the default disk, so switching is config-only).

No application code is changed.
2026-05-27 14:40:35 -03:00
Paulo Castellano
7852ad04d5 ci: enable parallel execution for test suite in GitHub Actions workflow 2026-05-06 17:28:41 -03:00
Paulo Castellano
bec831fec6 ci: fix tests workflow and clear pre-existing lint errors
- Add `php artisan passport:keys --force` step to tests workflow
  so the OAuth2 server keys exist before tests run. Without them
  every API test failed with `LogicException: Invalid key supplied`
  from `vendor/league/oauth2-server/src/CryptKey.php`.

- Clear 4 pre-existing unused-variable lint errors that were
  blocking this PR's CI (auth/GoogleAuthButton, billing/Subscribe,
  posts/editor/CommentsTab, posts/editor/TikTokSettings).

- `eslint --fix` also reordered imports alphabetically in 11 other
  files — pure cosmetic.
2026-05-04 12:03:44 -03:00
Paulo Castellano
d48b508ab3 fix: reorder CI steps — env before composer, key after 2026-03-31 12:08:04 -03:00
Paulo Castellano
2691bf172c fix: copy .env.ci before composer install in CI 2026-03-31 12:07:15 -03:00
Paulo Castellano
fb732495b2 feat: adding tests 2026-01-18 22:12:25 -03:00
Paulo Castellano
100e52be54 feat: adding tests.. 2026-01-18 22:01:55 -03:00
Paulo Castellano
69fba7af23 feat: working on ci/cd 2026-01-18 19:02:48 -03:00
Paulo Castellano
d5485a8389 feat: update CI workflow to use PostgreSQL and Redis services, configure test environment, and enhance .env.example with PostgreSQL defaults, Reverb settings, and social platform credentials. 2026-01-18 18:00:09 -03:00
Paulo Castellano
6890147aa6 chore: first commit 2026-01-14 22:13:44 -03:00