ios, android, desktop: previews render the same in every snapshot run (#7938)

* ios, android, desktop: previews draw fixed sample data instead of calling the core

* desktop: database error preview passes the keychain setting

* ios: snapshot fixtures use fixed parsed markdown instead of the core

* ios: snapshot fixtures: raw string delimiters past the # in markdown JSON

* desktop: snapshot test sets the app bar height as the app does

* docs: plan to replace preview-only parameters with test measures

* ios, desktop: previews run master's code; badges and version views split

Preview-only parameters are removed. BadgesCheckOrderView, BadgesHowLongView and VersionView are split into a loader and a layout, which their previews draw. Snapshot tests set a fixed QR picture: the environment value fixedQRCode on iOS, LocalFixedQRCode on desktop.

* ios: snapshot fixtures build parsed markdown with initializers

The table held the JSON of the Linux core, which the iOS app does not decode. The values are those the core returns for each text.

* ci: references of fixed QR codes and version; ios: call overlay preview as on master

iOS references from https://github.com/evgeny-simplex/simplex-chat/actions/runs/40944118370, desktop references from https://github.com/evgeny-simplex/simplex-chat/actions/runs/40932566864. ActiveCallOverlay_Previews, its scene and its references are restored as on master.

* ios, desktop: snapshot tests render every preview, no exclusion lists

BadgesChooseBadgeView, ServersSummaryView and TerminalView are split into a loader and a layout. AddChannelView, AddGroupView, GroupProfileView and UserProfileView layouts take the name and description validators, so desktop previews render without the core library. NewChatView's preview opens the Connect tab, UserProfilesView's preview has its own users. AppearanceSettings, MigrateFromDevice and the duplicate UserProfileLayoutEditOn previews are deleted.

* ios, desktop: previews show short links; tests draw the fixed QR code with each app's generator

The snapshot tests draw the fixed QR picture for a short address link with generateImage on iOS and qrCodeBitmap on desktop, in place of committed images. Previews of group links, addresses, a pending connection and QR codes pass short links, as the apps show them. The fixture markdown table equals the output of master's parser.

* ios, desktop: excluded previews and their views as on master

* ci: references of short-link QR codes
This commit is contained in:
Evgeny @ SimpleX Chat authored and GitHub committed 2026-10-30 06:41:40 +00:00
1 parent b6b985f95c
commit 17c9ad1c61
36 files changed
+529 -44

No files matched your search

+2 -2
View File
@@ -31,11 +31,11 @@ Queueing for a runner adds from under a minute to 20 minutes. Results are artifa
## Snapshots
`:common:desktopTest` runs `SnapshotTest` (`apps/multiplatform/common/src/desktopTest/kotlin/chat/simplex/app/SnapshotTest.kt`). It renders each preview listed in `previewScenes` with Compose's `ImageComposeScene`, 402 dp wide at density 1, one pixel per dp, as tall as the preview's content up to 874 dp, so a preview that fills any height is 874 pixels tall. It renders the light and dark themes without a wallpaper, over the theme's background, and keeps the fourth frame, 3 s of frame time after the first. The scene's coroutine context sets the animation duration scale (`MotionDurationScale`) to 0, so each animation ends at its first frame and a spinner is drawn the same in every run. As the app does for its screens, the test provides an `AppBarHandler` (`LocalAppBarHandler`) and the window state (`simplexWindowState`, sized as the scene). Each preview is rendered at the default font size; the chat item previews (package `views.chat.item`) also at 1.4 and 1.5, the two largest values of the desktop app's font size setting.
`:common:desktopTest` runs `SnapshotTest` (`apps/multiplatform/common/src/desktopTest/kotlin/chat/simplex/app/SnapshotTest.kt`). It renders each preview listed in `previewScenes` with Compose's `ImageComposeScene`, 402 dp wide at density 1, one pixel per dp, as tall as the preview's content up to 874 dp, so a preview that fills any height is 874 pixels tall. It renders the light and dark themes without a wallpaper, over the theme's background, and keeps the fourth frame, 3 s of frame time after the first. The scene's coroutine context sets the animation duration scale (`MotionDurationScale`) to 0, so each animation ends at its first frame and a spinner is drawn the same in every run. As the app does for its screens, the test provides an `AppBarHandler` (`LocalAppBarHandler`), the window state (`simplexWindowState`, sized as the scene) and the app bar height in pixels (`AppBarHandler.appBarMaxHeightPx`, which `AppScreen` sets), and restores the height when it finishes. Each preview is rendered at the default font size; the chat item previews (package `views.chat.item`) also at 1.4 and 1.5, the two largest values of the desktop app's font size setting.
`everyPreviewIsRendered` reads the Kotlin sources of `commonMain` and `desktopMain` without comments, and fails when a `@Preview` function is missing from both `previewScenes` and `previewsCallingCore`, or when either names a function absent from the sources; a scene is named `<file>.<function>`. `previewsCallingCore` lists the previews whose layouts validate names or descriptions with the core library (`chatValidName`, `chatJsonLength`), which the test JVM does not load, so they are not rendered. The previews of `androidMain` and of the Android app module are left out too, since they use Android APIs.
The test runs in UTC and en_US (the JVM's default `TimeZone` and `Locale`), and replaces the theme overrides with ones without a wallpaper. It sets the app's theme and font size for each render, and restores these settings and defaults when it finishes. Before each render it clears the terminal's items, which previews that send commands to the core add with the time they are sent, so that `PreviewTerminalLayout` shows an empty terminal. Previews show `previewDate` (`ChatItemView.kt`) in place of the current time.
The test runs in UTC and en_US (the JVM's default `TimeZone` and `Locale`), and replaces the theme overrides with ones without a wallpaper. It sets the app's theme and font size for each render, sets the density scale, the one-hand UI, the chat toolbar position, the message shape, the media blur and the bars' blur and opacity to their defaults, and restores these settings and defaults when it finishes. Before each render it clears the terminal's items, which previews that send commands to the core add with the time they are sent, so that `PreviewTerminalLayout` shows an empty terminal. Previews show `previewDate` (`ChatItemView.kt`) in place of the current time. The test provides `LocalFixedQRCode` (`QRCode.kt`) with the bitmap that `qrCodeBitmap` draws for a short address link in the theme of the render, so every QR code draws this bitmap.
The images go to `SNAPSHOT_DIR`, otherwise to `apps/multiplatform/common/build/snapshots`, as PNG files named `<file>.<function>-<light|dark>-font-<100|140|150>.png`, with `index-desktop.json` listing each file's scene, theme, font scale, and pixel width and height. The app job sets `SNAPSHOT_DIR` to `snapshots/` of the artifact `desktop-snapshots`, then the step "Compare snapshots" runs `scripts/ci/snapshots-compare.py` with the references in `apps/multiplatform/common/src/desktopTest/snapshots`, as the iOS workflow does ([iOS](../ios-sim/README.md), "Snapshots"): a missing, extra or resized render, or a pixel beyond the tolerance, fails the step, and the diff images go to `snapshots-diff/` of the same artifact.
+1 -1
View File
@@ -46,7 +46,7 @@ At the end of the app job's smoke test, `smoke-test.sh` runs `snapshots.sh <deri
`previewScenes()` lists every `PreviewProvider` in `apps/ios` except those in `EXCLUDED` of `apps/ios/SimpleX Snapshots/check-previews.py`, whose renders differ between runs and can be made identical only by a change of the app's code. The iOS job of `build.yml` runs `check-previews.py`, which fails when a `PreviewProvider` is neither listed nor excluded, or when a file has a `#Preview`, since the test renders previews by their type.
The test runs in UTC (`NSTimeZone.default`) and en_US (`-testLanguage en -testRegion US`), so the renders do not depend on the runner's time zone or locale; a preview that shows the current date or time differs between runs, so the previews and the sample contact use `previewDate` (`SimpleXChat/ChatTypes.swift`) in place of the current time. The keyboard autocorrects the profile name typed in the smoke test differently between runs, so the test sets the app's current user to the sample user.
The test runs in UTC (`NSTimeZone.default`) and en_US (`-testLanguage en -testRegion US`), so the renders do not depend on the runner's time zone or locale; a preview that shows the current date or time differs between runs, so the previews and the sample contact use `previewDate` (`SimpleXChat/ChatTypes.swift`) in place of the current time. The test sets the environment value `fixedQRCode` (`QRCode.swift`) to the image that `generateImage` draws for a short address link, so every QR code draws this image. The keyboard autocorrects the profile name typed in the smoke test differently between runs, so the test sets the app's current user to the sample user.
The images go to `snapshots/` of the artifact `ios-sim-smoke-test` as 8-bit sRGB PNG files without alpha (`preferredRange = .standard`, `opaque`), named `<preview>-<light|dark>-<size>.png`, with `index-<size>.json` listing each file's scene, theme, size, pixel width and height, scale and the content size category the app saw.