Skip to content

Adds end to end server-client testing to miso-tests#1402

Draft
Zer0- wants to merge 92 commits into
dmjio:masterfrom
Zer0-:miso-testing
Draft

Adds end to end server-client testing to miso-tests#1402
Zer0- wants to merge 92 commits into
dmjio:masterfrom
Zer0-:miso-testing

Conversation

@Zer0-
Copy link
Copy Markdown
Contributor

@Zer0- Zer0- commented Feb 7, 2026

This PR adds two tests:
- TestApp: generates a random html page with a link, clicks the link and
makes sure the app reacts to it (which implies hydration was successful)
- TestBindingsApp: Creates a variable-length chain of components with
variables bound to one another. The expectation is a change to
the value of the first component will propagate all the way down each component
and come back up to change a second value in the first component.

In order to test end-to-end playwright.ts was changed to be an http endpoint, that
way our haskell test server can control playwrite, which in turn points a browser at
the test server.
- Note: The changes to playwright.ts were almost entirely vibe-coded and then
tested by hand. It could definitely be slimmed down but I lack the motivation
atm.

There is also the server module TestServer that uses environment variables
to determine whether to link to the ghcjs or wasm payloads in the html, as well
as serving the initial html for each test. The tests rely on quickcheck's ioProperty,
for each iteration the actual http server is started in the background and the
test makes an http request to the playwright server to hit the server.

TODO:

  • add asserts to bindings test
  • possibly rename the new binaries to something other than integration-* if that's more appropriate
  • comment out or delete serveFailed in TestServer (though it's useful)

I definitely expect a good amount of comments but I do think this way of testing is necessary.

Zer0- and others added 30 commits December 30, 2025 21:11
- Lower the test to mount 10k components to 10 so it won't take forever
- so far only js version
- add executable integration-tests-server section to
  tests/miso-tests.cabal
- remove tests/CHANGELOG.md and it's mention in the cabal file because
  it was making the build fail
- vibe code a generator
    - missing some sections
- see how we can generate an explicit seed in QuickCheck
- compiles
- adds missing sections
- might throw this out
- quickcheck, even when using the exact same seed (which had to be
  generated as an Int32 because haskell's Int range is a lot larger than
  javascript's Number), does not generate the same view.
- have an intermediate html representation we can ship to the client
- this time it's hand written and cleaner
- no errors according to w3c validator
    - except for the defer attribute on the script tag for loading the
      app, but that can't be the issue otherwise the app wouldn't even
      boot (defer should be present or not present, it shouldn't have a
      value)
- even the simplified html generation causes hydration issues (need to
  investigate this)
- javascript backend only, wasm is TODO
- tests pass
- There's a change to nix/haskell/packages/ghc/default.nix where I added
  the -fssr flag to miso, this fixes my test but i'm not sure if it
  breaks something else.
- also commit a js file to load the wasm script
- need to make client work with new test, which means being able to
  hydrate different kinds of data.
- should this work? This may be a failing test case
- missing assertions that should run clientside
- all small API changes
- TODO:need to replace jsaddle with miso's internal API
- rename mount -> mount_
- TODO: fix ToJSON/FromJSON instance (use miso's json instead of aeson?)
- Miso.JSON seems to be missing some implementation server-side ?
This PR adds JSON encoding to `Text` when using vanilla GHC.

- [x] Add `encode`
Zer0- and others added 11 commits April 9, 2026 01:37
This reverts commit 57127c7.
This was superceeded by dmjio#1489
- it seems the CI server times out waiting for networkidle, which
  results in a NAVIGATION_ERROR and the test suite fails
- sometimes the browser fails to load a resource and the test never
  actually runs but times out
- this is a very quick, not well thought out commit that's mean to give
  it a chance to retry
- something is failing even with retry logic
- we are closing the page
- the server appears to be serving up our files
- i'm not sure if this will help
* Make GToJSON/GFromJSON aeson-compatible

- Add Fields sum type (RecordFields/PositionalFields) to represent
  constructor fields before encoding
- Add GToFields class: collects fields, detects record vs positional
  via selName at the S1 level
- Add GToJSONRep/GToJSONSum: dispatch single-constructor (no tag) vs
  sum (tagged) at the D1 level
- Add encodeProduct: single-constructor encoding without tag wrapper
- Add encodeTaggedCon: sum encoding with TaggedObject "tag"/"contents"
- Add GFromFields class: symmetric decoder with gIsRecord, gFieldCount,
  gFromRecord (key lookup), gFromPositional (index)
- Add GFromJSONRep/GFromJSONSum: symmetric dispatch at D1/sum level
- Add OVERLAPPING instance for Maybe fields using .:? (missing = Nothing)
- Add AllowAmbiguousTypes pragma for gIsRecord/gFieldCount type-level use
- Remove old GToProduct, GFromProduct, taggedVal, parseEnvelope
- Update exports: GToFields, GToJSONSum, Fields, GFromFields, GFromJSONSum

Wire format now matches aeson default DeriveGeneric encoding:
  nullary sum        -> {"tag":"C"}
  record sum         -> {"tag":"C","field":v}
  positional sum 1   -> {"tag":"C","contents":v}
  positional sum N   -> {"tag":"C","contents":[v1,v2]}
  single-con record  -> {"field1":v1,"field2":v2}
  single-con newtype -> v  (unwrapped)

* Add generic JSON encoding/decoding tests

Test coverage for the aeson-compatible GToJSON/GFromJSON machinery:

- Color   (nullary sum)            → {"tag":"C"}
- Point   (single-con record)      → {"px":v,"py":v}
- Wrapper (single-con positional)  → unwrapped value
- Shape   (sum positional)         → {"tag":"C","contents":v} / [v1,v2]
- Animal  (sum record)             → {"tag":"C","field":v,...}
- Profile (record with Maybe)      → null / present value

Each case tests both encoding (toJSON) and round-trip (fromJSON . toJSON).

* Adjust selName

* Implement allNullaryToStringTag for full aeson compatibility

Add Options.allNullaryToStringTag :: Bool (default True, matching aeson):
- When True and all constructors of a sum type are nullary, encode each
  as a bare String (e.g. "Red") rather than a tagged object ({"tag":"Red"})
- Symmetric decode: String -> nullary constructor by name match

New machinery:
- GAllNullary typeclass: type-level predicate, True iff every constructor
  in the sum has no fields (U1 leaves); instances for U1, K1, S1, C1,
  f :+: g, f :*: g
- GToJSONSumNullary: encode nullary sum as bare String; overlappable
  catch-all for non-nullary C1 (unreachable under gAllNullary guard)
- GFromJSONSumNullary: decode bare String to nullary constructor by name;
  same catch-all pattern
- GToJSONRep / GFromJSONRep (f :+: g): dispatch to nullary or tagged
  path based on allNullaryToStringTag opts && gAllNullary @f && gAllNullary @g

Update tests: Color encoding now expects bare String ("Red", etc.)

* Add additional Options

* Add constructorTagModifier, omitNothingFields; fix conName on undefined; fix duplicate export

* Use explicit constructor

* Comment out broken GHCJS tests

Add tests for encoding and decoding single-constructor records.
@Zer0- Zer0- force-pushed the miso-testing branch 4 times, most recently from 099964f to 33cb881 Compare May 14, 2026 05:28
@dmjio dmjio force-pushed the master branch 3 times, most recently from e53cd20 to c13e1e8 Compare May 14, 2026 12:54
Zer0- added 8 commits May 14, 2026 18:37
- the socket issues that were seen were caused by trying to load a
  missing and unused import in init_integration_wasm_client.js
- this was probably a hack to appease w3c validator but it leads to
  other issues with said validator and possibly issues with hydration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants