Skip to content

Commit d265f04

Browse files
authored
Merge branch 'main' into remote-provider
2 parents 9933b92 + 211349b commit d265f04

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+938
-335
lines changed

.ios/Podfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
platform :ios, '11.0'
1+
platform :ios, '12.0'
22

33
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
44
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5+
# need since some packages (workmanager) doesn't set Swift version. Do not remove otherwise integration tests won't work.
56
ENV['SWIFT_VERSION'] = '5'
67

78
project 'Runner', {
@@ -32,7 +33,6 @@ target 'Runner' do
3233
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
3334

3435
pod 'FlutterPluginRegistrant', :path => File.join('Flutter', 'FlutterPluginRegistrant'), :inhibit_warnings => true
35-
pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '10.10.0'
3636
end
3737

3838
post_install do |installer|

integration_test/framework/test_helper.dart

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,42 +17,37 @@ class TestHelper {
1717
/// the result but no longer available for the next run, causing the
1818
/// subsequent tests to hang. For this reason, call this in your Test class's
1919
/// setupApp() once before running the tests.
20-
static Future<EnsembleConfig> setupApp({required String appName}) async {
21-
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
22-
WidgetsFlutterBinding.ensureInitialized();
23-
24-
I18nProps i18nProps = I18nProps('en', 'en', false);
25-
i18nProps.path = 'ensemble/i18n';
20+
static Future<EnsembleConfig> setupApp(
21+
{required String appName, String? forcedLocale}) async {
22+
I18nProps i18nProps =
23+
I18nProps('en', 'en', false, forcedLocale: forcedLocale);
24+
i18nProps.path = 'integration_test/local/$appName/i18n';
2625

2726
EnsembleConfig config = EnsembleConfig(
2827
definitionProvider: LocalDefinitionProvider(
29-
"ensemble/integration_tests/$appName/", "", i18nProps));
30-
return await config.updateAppBundle();
28+
"integration_test/local/$appName/", "", i18nProps));
29+
return config.updateAppBundle();
3130
}
3231

32+
// load a screen based on the config returned from setupApp
3333
static loadScreen(
34-
{required String screenName, required EnsembleConfig? config}) {
35-
if (config == null) {
36-
throw Exception(
37-
'Config is required. Please run setupApp() per Test Class to initialize the EnsembleConfig once !');
38-
}
39-
40-
runApp(EnsembleApp(
41-
key: UniqueKey(),
34+
WidgetTester tester, String screenName, EnsembleConfig config) async {
35+
await tester.pumpWidget(EnsembleApp(
4236
ensembleConfig: config,
43-
screenPayload: ScreenPayload(screenName: screenName),
37+
screenPayload: ScreenPayload(screenId: screenName),
4438
));
39+
await tester.pumpAndSettle();
4540
}
4641

4742
/// initialize an App and init a single screen for testing.
4843
/// This is a quick way to run a test, but it should be the only test
4944
/// in your test class.
5045
/// Considering using setupApp(), followed by loadScreen() for multiple
5146
/// test cases within a class.
52-
static Future<void> setupAppForSingleScreen(
47+
static loadAppAndScreen(WidgetTester tester,
5348
{required String appName, required String screenName}) async {
5449
EnsembleConfig config = await setupApp(appName: appName);
55-
loadScreen(screenName: screenName, config: config);
50+
await loadScreen(tester, screenName, config);
5651
}
5752

5853
/// remove focus if any widget currently has focus
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import 'package:ensemble/ensemble.dart';
2+
import 'package:ensemble/widget/button.dart';
3+
import 'package:flutter/material.dart';
4+
import 'package:flutter_test/flutter_test.dart';
5+
6+
import '../framework/test_helper.dart';
7+
8+
void main() {
9+
late EnsembleConfig config;
10+
setUpAll(() async {
11+
config = await TestHelper.setupApp(appName: 'widgets');
12+
});
13+
14+
group('Custom Widgets', () {
15+
testWidgets("test basic widget features", (tester) async {
16+
await TestHelper.loadScreen(tester, 'Custom Widget', config);
17+
18+
// test visibility
19+
expect(find.text('I am visible'), findsOneWidget);
20+
expect(find.text('I am really visible'), findsOneWidget);
21+
expect(find.text('I am invisible'), findsNothing);
22+
23+
await tester.tap(find.descendant(
24+
of: find.byType(Button), matching: find.text('Toggle Visibility')));
25+
await tester.pumpAndSettle();
26+
expect(find.text('I am visible'), findsNothing);
27+
expect(find.text('I am really visible'), findsNothing);
28+
expect(find.text('I am invisible'), findsOneWidget);
29+
30+
// test flex and its modification
31+
32+
// equal distribution with default flex
33+
expect(tester.getSize(find.text("hello")).width,
34+
tester.getSize(find.text("world")).width);
35+
36+
// changing flex under FlexBox is a problem because the parent FlexBox already
37+
// make the child Expanded if not specified, so if we update it later, there will
38+
// be duplicate Expanded.
39+
// ALmost like we want to travel up to the Flexbox and ask it to refresh itself,
40+
// but that is not recommended. TODO: figure this out
41+
// change "world" to 2x
42+
// await tester.tap(find.descendant(
43+
// of: find.byType(Button), matching: find.text('Change Flex')));
44+
// await tester.pumpAndSettle();
45+
// expect(tester.getSize(find.text("hello")).width, 100);
46+
// expect(tester.getSize(find.text("world")).width, 200);
47+
48+
expect(tester.getSize(find.text("1x")).width, 100);
49+
expect(tester.getSize(find.text("2x")).width, 200);
50+
});
51+
});
52+
}

ensemble/integration_tests/defaultApp/Widget Bindings.yaml renamed to integration_test/local/defaultApp/Custom Widget.yaml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ View:
2222

2323
Custom:
2424
inputs: [txt]
25+
onLoad:
26+
showToast:
27+
message: Hello ${txt}
2528
body:
2629
Column:
2730
children:
@@ -35,6 +38,13 @@ Custom:
3538

3639
Custom2:
3740
inputs: [text]
41+
onLoad: |-
42+
setByJS.text = "Hi " + text;
43+
3844
body:
39-
Text:
40-
text: "Custom Custom Widget: ${text}"
45+
Column:
46+
children:
47+
- Text:
48+
text: "Custom Custom Widget: ${text}"
49+
- Text:
50+
id: setByJS

integration_test/defaultApp_test.dart renamed to integration_test/local/defaultApp_test.dart

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import 'package:flutter/material.dart';
1111
import 'package:flutter/rendering.dart';
1212
import 'package:flutter_test/flutter_test.dart';
1313

14-
import '../test/widget/test_utils.dart';
15-
import 'framework/test_helper.dart';
14+
import '../../test/widget/test_utils.dart';
15+
import '../framework/test_helper.dart';
1616

1717
void main() {
18-
EnsembleConfig? config;
18+
late EnsembleConfig config;
1919
setUpAll(() async {
2020
config = await TestHelper.setupApp(appName: 'defaultApp');
2121
});
@@ -24,16 +24,22 @@ void main() {
2424
/// test that binding to a TextInput works properly in the same scope
2525
/// and also in a custom widget's scope
2626
testWidgets("Bindings to widget's value", (tester) async {
27-
await TestHelper.loadScreen(
28-
screenName: 'Widget Bindings', config: config);
29-
await tester.pumpAndSettle();
27+
await TestHelper.loadScreen(tester, 'Custom Widget', config);
3028

3129
// TextInput has initial value of 'first'
3230
// so first make sure our EnsembleText is correctly bind to that
3331
Finder text = find.descendant(
3432
of: find.byType(EnsembleText), matching: find.text('first'));
3533
expect(text, findsOneWidget);
3634

35+
// Custom Widget's onLoad can access inputs
36+
// search for toast message
37+
await tester.pumpAndSettle();
38+
expect(find.text('Hello first'), findsOneWidget);
39+
40+
// ensure Nested widget's onLoad can access inputs via JS too
41+
expect(find.text('Hi first'), findsOneWidget);
42+
3743
// Custom Widget's text should also bind to the same value
3844
Finder customText = find.descendant(
3945
of: find.byType(EnsembleText),
@@ -69,11 +75,14 @@ void main() {
6975
of: find.byType(EnsembleText),
7076
matching: find.text('Custom Custom Widget: second'));
7177
expect(customCustomText, findsOneWidget);
78+
79+
// ensure onLoad never run again and still retain original value
80+
expect(find.text('Hi first'), findsOneWidget);
7281
});
7382

7483
/// test bindings to API is working properly
7584
testWidgets('API Binding', (tester) async {
76-
await TestHelper.loadScreen(screenName: 'API Bindings', config: config);
85+
await TestHelper.loadScreen(tester, 'API Bindings', config);
7786
await tester.pumpAndSettle();
7887

7988
// before the API loads
@@ -101,8 +110,8 @@ void main() {
101110
});
102111

103112
/// test invokeApi
104-
testWidgets("invokeApi Test", (tester) async {
105-
await TestHelper.loadScreen(screenName: "Invoke Api", config: config);
113+
/**testWidgets("invokeApi Test", (tester) async {
114+
await TestHelper.loadScreen(tester, "Invoke Api", config);
106115
await tester.pumpAndSettle();
107116
108117
await tester.tap(find.widgetWithText(Button, "Call API"));
@@ -118,7 +127,7 @@ void main() {
118127
119128
await tester
120129
.tap(find.widgetWithText(Button, 'Call API with invalid URI'));
121-
await tester.pumpAndSettle(const Duration(seconds: 2));
130+
await tester.pumpAndSettle(const Duration(seconds: 4));
122131
Finder badapiOnerror = find.text("Bad Api onResponse called");
123132
Finder badApiStatus =
124133
find.text("Invalid argument(s): No host specified in URI blah");
@@ -132,12 +141,11 @@ void main() {
132141
Finder errorStatus = find.text("500");
133142
expect(errorText, findsNWidgets(2));
134143
expect(errorStatus, findsOneWidget);
135-
});
144+
});*/
136145

137146
// test nested textSTyle
138147
testWidgets('Nested TextStyle update via Bindings/JS', (tester) async {
139-
await TestHelper.loadScreen(
140-
screenName: 'Nested TextStyle', config: config);
148+
await TestHelper.loadScreen(tester, 'Nested TextStyle', config);
141149
await tester.pumpAndSettle();
142150

143151
Finder textFinder = find.descendant(
@@ -187,8 +195,7 @@ void main() {
187195
/// with side-by-side labels. The structure for both is different hence
188196
/// the demonstration on how to do for each
189197
testWidgets('Test finding Ensemble widgets in Forms', (tester) async {
190-
await TestHelper.loadScreen(
191-
screenName: 'Dropdown and Form', config: config);
198+
await TestHelper.loadScreen(tester, 'Dropdown and Form', config);
192199
await tester.pumpAndSettle();
193200

194201
// two TextInputs on the screen
@@ -243,7 +250,7 @@ void main() {
243250
});
244251

245252
testWidgets('Conditional', (tester) async {
246-
await TestHelper.loadScreen(screenName: 'Conditional', config: config);
253+
await TestHelper.loadScreen(tester, 'Conditional', config);
247254
await tester.pumpAndSettle();
248255

249256
Finder textInputFinder = find.byType(TextInput);

0 commit comments

Comments
 (0)