nandi/frqpublic Fork 0
9c1dfe96e622c7a42cc8d4fec7ade9e5ddf074b0
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

nim_layout_test.dart · 181 lines · 6.2 KBDart Blame HistoryRaw
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 23h ago1/// Every screen, laid out for real, at sizes that squeeze.
2///
3/// This is the test that was missing. `Cannot hit test a render box that has
4/// never been laid out` is what a failed layout looks like from the outside,
5/// and nothing automated ever laid the chat screen out — a GUI on Wayland
6/// cannot be clicked, so every check stopped at the room list while the
7/// biggest screen in the app went out unverified.
8///
9/// `tester.takeException()` is the whole point: a layout error is reported to
10/// FlutterError rather than thrown at the caller, so a test that only pumps
11/// and asserts on widgets passes while the screen is broken. These fail.
12///
13/// just test layout
Quality pass: reuse, dead weight, and two real costs 4dfc719 nandi 23h ago14library;
15
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 23h ago16import 'package:flutter/material.dart';
17import 'package:flutter_test/flutter_test.dart';
18import 'package:frq_core/frq_core.dart' as core;
The last of the Clojure 284b59c nandi 16h ago19import 'package:frq/nim_renderer.dart';
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 23h ago20
21/// Phone, small desktop, and a deliberately cramped one. The head row of the
22/// chat screen asks for more than 360 points has, which is why it wraps.
23const sizes = <String, Size>{
24 'phone': Size(360, 690),
25 'desktop': Size(1280, 800),
26 'cramped': Size(300, 500),
27};
28
29Future<void> layOut(WidgetTester tester, Size size) async {
30 await tester.binding.setSurfaceSize(size);
31 addTearDown(() => tester.binding.setSurfaceSize(null));
32 await tester.pumpWidget(const NimApp());
33 await tester.pump();
34}
35
36/// Nothing went to FlutterError while that frame was built.
37void expectLaidOut(WidgetTester tester, String what) {
38 final e = tester.takeException();
39 expect(e, isNull, reason: '$what reported: $e');
40}
41
42void main() {
43 // No offline guard needed: `demoUi` sets the state directly and none of
44 // these dispatch `connect`, so nothing here opens a socket.
45
46 group('the connect screen', () {
47 for (final entry in sizes.entries) {
48 testWidgets('lays out at ${entry.key}', (tester) async {
49 core.resetUi();
50 await layOut(tester, entry.value);
51 expectLaidOut(tester, 'connect at ${entry.key}');
52 });
53 }
54
55 testWidgets('lays out in every auth mode', (tester) async {
56 for (final mode in ['guest', 'bluesky', 'app-password']) {
57 core.resetUi();
58 core.dispatch('mode.$mode');
59 await layOut(tester, sizes['phone']!);
60 expectLaidOut(tester, 'connect in $mode');
61 }
62 });
63 });
64
65 group('the chat screen', () {
66 // The one that was never laid out by anything automated.
67 for (final entry in sizes.entries) {
68 testWidgets('lays out at ${entry.key}', (tester) async {
69 core.demoUi();
70 await layOut(tester, entry.value);
71 expectLaidOut(tester, 'chat at ${entry.key}');
72 });
73 }
74
75 testWidgets('renders the conversation it was given', (tester) async {
76 core.demoUi();
77 await layOut(tester, sizes['desktop']!);
78 expect(find.text('hello there'), findsOneWidget);
79 expect(find.text('#test'), findsWidgets);
80 expectLaidOut(tester, 'chat content');
81 });
82
83 testWidgets('lays out with the people panel up', (tester) async {
84 core.demoUi();
85 core.dispatch('users.toggle');
86 await layOut(tester, sizes['desktop']!);
87 expectLaidOut(tester, 'chat with people');
88 });
89
90 testWidgets('lays out with every compose banner showing', (tester) async {
91 core.demoUi();
92 core.dispatch('reply.to:2');
93 await layOut(tester, sizes['phone']!);
94 expectLaidOut(tester, 'chat replying');
95
96 core.demoUi();
97 core.dispatch('edit.start:7');
98 await layOut(tester, sizes['phone']!);
99 expectLaidOut(tester, 'chat editing');
100 });
101
Three buttons that did nothing now do what they say 98d6135 nandi 16h ago102 testWidgets('lays out with the emoji picker open', (tester) async {
103 // 120 emoji in a grid under a message, on a phone.
104 core.demoUi();
105 core.dispatch('react.open:2');
106 await layOut(tester, sizes['phone']!);
107 expectLaidOut(tester, 'chat with the picker');
108 });
109
110 testWidgets('lays out with the picker showing a whole group',
111 (tester) async {
112 core.demoUi();
113 core.dispatch('react.open:2');
114 core.dispatch('emoji.group:Smileys & Emotion');
115 await layOut(tester, sizes['cramped']!);
116 expectLaidOut(tester, 'chat with a full picker');
117 });
118
119 testWidgets('lays out with the overview open', (tester) async {
120 core.demoUi();
121 core.dispatch('overview.toggle');
122 await layOut(tester, sizes['phone']!);
123 expectLaidOut(tester, 'chat with the overview');
124 });
125
126 testWidgets('lays out with the lightbox open', (tester) async {
127 core.demoUi();
128 core.dispatch('lightbox:https://example.com/a.png');
129 await layOut(tester, sizes['phone']!);
130 expectLaidOut(tester, 'chat with the lightbox');
131 });
132
A face that opens someone 9bb81a1 nandi 16h ago133 testWidgets('lays out with a profile open', (tester) async {
134 core.demoUi();
135 // A guest: no identity to fetch, so the panel says so rather than
136 // spinning — and it lays out without a network.
137 core.dispatch('profile.open:alice:');
138 await layOut(tester, sizes['phone']!);
139 expectLaidOut(tester, 'chat with a guest profile');
140 });
141
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 23h ago142 testWidgets('lays out when scrolled off the present', (tester) async {
143 core.demoUi();
144 core.dispatch('jump.present');
145 await layOut(tester, sizes['phone']!);
146 expectLaidOut(tester, 'chat jumping');
147 });
148 });
149
150 group('the chats list', () {
151 for (final entry in sizes.entries) {
152 testWidgets('lays out at ${entry.key}', (tester) async {
153 core.demoUi();
154 core.dispatch('screen.chats');
155 await layOut(tester, entry.value);
156 expectLaidOut(tester, 'chats at ${entry.key}');
157 });
158 }
159
160 testWidgets('lays out with a search term in the box', (tester) async {
161 core.demoUi();
162 core.dispatch('screen.chats');
163 core.dispatch('search.change', 'te');
164 await layOut(tester, sizes['phone']!);
165 expectLaidOut(tester, 'chats searching');
166 });
167 });
168
169 group('discover and settings', () {
170 for (final screen in ['discover', 'settings']) {
171 for (final entry in sizes.entries) {
172 testWidgets('$screen lays out at ${entry.key}', (tester) async {
173 core.demoUi();
174 core.dispatch('screen.$screen');
175 await layOut(tester, entry.value);
176 expectLaidOut(tester, '$screen at ${entry.key}');
177 });
178 }
179 }
180 });
181}