|
| 1 | +import 'package:codelessly_api/codelessly_api.dart'; |
| 2 | +import 'package:codelessly_sdk/codelessly_sdk.dart'; |
| 3 | +import 'package:flutter/material.dart'; |
| 4 | +import 'package:flutter_test/flutter_test.dart'; |
| 5 | +import 'package:provider/provider.dart'; |
| 6 | + |
| 7 | +// RowColumnNode.spacing becomes the gap between children of the rendered |
| 8 | +// Row/Column, taken out of the main axis before flex children share the |
| 9 | +// free space. |
| 10 | + |
| 11 | +RectangleNode rect( |
| 12 | + String id, { |
| 13 | + double width = 50, |
| 14 | + double height = 50, |
| 15 | + SizeFit horizontalFit = SizeFit.fixed, |
| 16 | + SizeFit verticalFit = SizeFit.fixed, |
| 17 | +}) => RectangleNode( |
| 18 | + id: id, |
| 19 | + name: id, |
| 20 | + basicBoxLocal: NodeBox(0, 0, width, height), |
| 21 | + horizontalFit: horizontalFit, |
| 22 | + verticalFit: verticalFit, |
| 23 | +); |
| 24 | + |
| 25 | +RowColumnNode flex( |
| 26 | + String id, |
| 27 | + List<BaseNode> children, { |
| 28 | + required RowColumnType type, |
| 29 | + required double spacing, |
| 30 | + double width = 300, |
| 31 | + double height = 300, |
| 32 | + SizeFit horizontalFit = SizeFit.fixed, |
| 33 | + SizeFit verticalFit = SizeFit.fixed, |
| 34 | + bool isScrollable = false, |
| 35 | +}) { |
| 36 | + for (final child in children) { |
| 37 | + child.parentID = id; |
| 38 | + } |
| 39 | + return RowColumnNode( |
| 40 | + id: id, |
| 41 | + name: id, |
| 42 | + basicBoxLocal: NodeBox(0, 0, width, height), |
| 43 | + children: [for (final child in children) child.id], |
| 44 | + rowColumnType: type, |
| 45 | + horizontalFit: horizontalFit, |
| 46 | + verticalFit: verticalFit, |
| 47 | + isScrollable: isScrollable, |
| 48 | + mainAxisAlignment: MainAxisAlignmentC.start, |
| 49 | + crossAxisAlignment: CrossAxisAlignmentC.start, |
| 50 | + spacing: spacing, |
| 51 | + )..parentID = kRootNode; |
| 52 | +} |
| 53 | + |
| 54 | +Finder rectOf(String id) => |
| 55 | + find.byKey(ValueKey('Rectangle Transformer of $id [$id]')); |
| 56 | + |
| 57 | +/// Pumps [root] at [screen] and returns each node's global rect. |
| 58 | +Future<Map<String, Rect>> pump( |
| 59 | + WidgetTester tester, |
| 60 | + BaseNode root, |
| 61 | + List<BaseNode> nodes, { |
| 62 | + Size screen = const Size(1440, 900), |
| 63 | +}) async { |
| 64 | + tester.view.physicalSize = screen; |
| 65 | + tester.view.devicePixelRatio = 1; |
| 66 | + addTearDown(tester.view.reset); |
| 67 | + |
| 68 | + final registry = NodeRegistry() |
| 69 | + ..setNodes({ |
| 70 | + for (final node in [root, ...nodes]) node.id: node, |
| 71 | + }); |
| 72 | + final manager = PassiveNodeTransformerManager( |
| 73 | + registry.getNodeByID, |
| 74 | + (context, bounds, pageID, layoutID, canvasID) => const SizedBox(), |
| 75 | + ); |
| 76 | + await tester.pumpWidget( |
| 77 | + ChangeNotifierProvider<CodelesslyContext>.value( |
| 78 | + value: CodelesslyContext.empty(), |
| 79 | + child: MaterialApp( |
| 80 | + home: Material( |
| 81 | + child: Align( |
| 82 | + alignment: Alignment.topLeft, |
| 83 | + child: Builder( |
| 84 | + builder: (context) => manager.buildWidgetFromNode( |
| 85 | + root, |
| 86 | + context, |
| 87 | + settings: const WidgetBuildSettings(debugLabel: 'test'), |
| 88 | + ), |
| 89 | + ), |
| 90 | + ), |
| 91 | + ), |
| 92 | + ), |
| 93 | + ), |
| 94 | + ); |
| 95 | + expect(tester.takeException(), isNull); |
| 96 | + return { |
| 97 | + for (final node in [root, ...nodes]) |
| 98 | + if (rectOf(node.id).evaluate().isNotEmpty) |
| 99 | + node.id: tester.getRect(rectOf(node.id)), |
| 100 | + }; |
| 101 | +} |
| 102 | + |
| 103 | +void main() { |
| 104 | + testWidgets('expanded children share the room left after spacing', ( |
| 105 | + tester, |
| 106 | + ) async { |
| 107 | + final children = [ |
| 108 | + for (final id in ['a', 'b', 'c']) |
| 109 | + rect(id, width: 100, horizontalFit: SizeFit.expanded), |
| 110 | + ]; |
| 111 | + final row = flex( |
| 112 | + 'row', |
| 113 | + children, |
| 114 | + type: RowColumnType.row, |
| 115 | + spacing: 20, |
| 116 | + width: 1072, |
| 117 | + height: 50, |
| 118 | + ); |
| 119 | + final rects = await pump(tester, row, children); |
| 120 | + |
| 121 | + expect(rects['row']!.width, 1072); |
| 122 | + for (final id in ['a', 'b', 'c']) { |
| 123 | + expect(rects[id]!.width, 344, reason: id); |
| 124 | + } |
| 125 | + expect(rects['a']!.left, 0); |
| 126 | + expect(rects['b']!.left, 364); |
| 127 | + expect(rects['c']!.left, 728); |
| 128 | + }); |
| 129 | + |
| 130 | + testWidgets('a hugging column is as tall as its children plus gaps', ( |
| 131 | + tester, |
| 132 | + ) async { |
| 133 | + final children = [ |
| 134 | + rect('a', height: 40), |
| 135 | + rect('b', height: 60), |
| 136 | + rect('c', height: 30), |
| 137 | + ]; |
| 138 | + final column = flex( |
| 139 | + 'column', |
| 140 | + children, |
| 141 | + type: RowColumnType.column, |
| 142 | + spacing: 12, |
| 143 | + width: 50, |
| 144 | + height: 154, |
| 145 | + verticalFit: SizeFit.shrinkWrap, |
| 146 | + ); |
| 147 | + final rects = await pump(tester, column, children); |
| 148 | + |
| 149 | + expect(rects['column']!.height, 40 + 60 + 30 + 2 * 12); |
| 150 | + expect(rects['b']!.top, 52); |
| 151 | + expect(rects['c']!.top, 124); |
| 152 | + }); |
| 153 | + |
| 154 | + testWidgets('a scrollable row keeps its spacing', (tester) async { |
| 155 | + final children = [ |
| 156 | + for (final id in ['a', 'b', 'c', 'd']) rect(id, width: 200), |
| 157 | + ]; |
| 158 | + final row = flex( |
| 159 | + 'row', |
| 160 | + children, |
| 161 | + type: RowColumnType.row, |
| 162 | + spacing: 16, |
| 163 | + width: 400, |
| 164 | + height: 50, |
| 165 | + isScrollable: true, |
| 166 | + ); |
| 167 | + final rects = await pump(tester, row, children); |
| 168 | + |
| 169 | + expect(rects['b']!.left - rects['a']!.right, 16); |
| 170 | + expect(rects['c']!.left - rects['b']!.right, 16); |
| 171 | + }); |
| 172 | + |
| 173 | + testWidgets('zero spacing leaves children adjacent', (tester) async { |
| 174 | + final children = [rect('a'), rect('b')]; |
| 175 | + final row = flex( |
| 176 | + 'row', |
| 177 | + children, |
| 178 | + type: RowColumnType.row, |
| 179 | + spacing: 0, |
| 180 | + width: 300, |
| 181 | + height: 50, |
| 182 | + ); |
| 183 | + final rects = await pump(tester, row, children); |
| 184 | + |
| 185 | + expect(rects['b']!.left, rects['a']!.right); |
| 186 | + }); |
| 187 | +} |
0 commit comments