Skip to content

Commit d268f8c

Browse files
authored
feat: integrate codemagic for testing ios/android (#6719)
* fix: pages overflow when selecting homepage * feat: integrate codemagic * Revert "fix: pages overflow when selecting homepage" This reverts commit 156882a. * chore: try to fix build * chore: remove flutter analyuze * chore: launch ios simulator * fix: flutter version * fix: integration tests on mobile * fix: mobile tests * test: fix page style test * chore: enable ios ci * chore: update codemagic token * chore: update app_id
1 parent 3cd26cc commit d268f8c

File tree

10 files changed

+186
-44
lines changed

10 files changed

+186
-44
lines changed

.github/workflows/ios_ci.yaml

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,21 +97,25 @@ jobs:
9797
cargo make --profile development-ios-arm64-sim appflowy-core-dev-ios
9898
cargo make --profile development-ios-arm64-sim code_generation
9999
100-
# - uses: futureware-tech/simulator-action@v3
101-
# id: simulator-action
102-
# with:
103-
# model: "iPhone 15"
104-
# shutdown_after_job: false
105-
106-
# - name: Run AppFlowy on simulator
107-
# working-directory: frontend/appflowy_flutter
108-
# run: |
109-
# flutter run -d ${{ steps.simulator-action.outputs.udid }} &
110-
# pid=$!
111-
# sleep 500
112-
# kill $pid
113-
# continue-on-error: true
114-
115-
# - name: Run integration tests
116-
# working-directory: frontend/appflowy_flutter
117-
# run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}
100+
- uses: futureware-tech/simulator-action@v3
101+
id: simulator-action
102+
with:
103+
model: "iPhone 15"
104+
shutdown_after_job: false
105+
106+
- name: Run AppFlowy on simulator
107+
working-directory: frontend/appflowy_flutter
108+
run: |
109+
flutter run -d ${{ steps.simulator-action.outputs.udid }} &
110+
pid=$!
111+
sleep 500
112+
kill $pid
113+
continue-on-error: true
114+
115+
- name: Run integration tests
116+
working-directory: frontend/appflowy_flutter
117+
# The integration tests are flaky and sometimes fail with "Connection timed out":
118+
# Don't block the CI. If the tests fail, the CI will still pass.
119+
# Instead, we're using Code Magic to re-run the tests to check if they pass.
120+
continue-on-error: true
121+
run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}

.github/workflows/mobile_ci.yml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Mobile-CI
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
branch:
7+
description: "Branch to build"
8+
required: true
9+
default: "main"
10+
workflow_id:
11+
description: "Codemagic workflow ID"
12+
required: true
13+
default: "ios-workflow"
14+
type: choice
15+
options:
16+
- ios-workflow
17+
- android-workflow
18+
19+
env:
20+
CODEMAGIC_API_TOKEN: ${{ secrets.CODEMAGIC_API_TOKEN }}
21+
APP_ID: "6731d2f427e7c816080c3674"
22+
23+
jobs:
24+
trigger-mobile-build:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- name: Trigger Codemagic Build
28+
id: trigger_build
29+
run: |
30+
RESPONSE=$(curl -X POST \
31+
--header "Content-Type: application/json" \
32+
--header "x-auth-token: $CODEMAGIC_API_TOKEN" \
33+
--data '{
34+
"appId": "${{ env.APP_ID }}",
35+
"workflowId": "${{ github.event.inputs.workflow_id }}",
36+
"branch": "${{ github.event.inputs.branch }}"
37+
}' \
38+
https://api.codemagic.io/builds)
39+
40+
BUILD_ID=$(echo $RESPONSE | jq -r '.buildId')
41+
echo "build_id=$BUILD_ID" >> $GITHUB_OUTPUT
42+
echo "build_id=$BUILD_ID"
43+
44+
- name: Wait for build and check status
45+
id: check_status
46+
run: |
47+
while true; do
48+
RESPONSE=$(curl -X GET \
49+
--header "Content-Type: application/json" \
50+
--header "x-auth-token: $CODEMAGIC_API_TOKEN" \
51+
https://api.codemagic.io/builds/${{ steps.trigger_build.outputs.build_id }})
52+
53+
STATUS=$(echo $RESPONSE | jq -r '.build.status')
54+
55+
if [ "$STATUS" = "finished" ]; then
56+
SUCCESS=$(echo $RESPONSE | jq -r '.success')
57+
BUILD_URL=$(echo $RESPONSE | jq -r '.buildUrl')
58+
echo "status=$STATUS" >> $GITHUB_OUTPUT
59+
echo "success=$SUCCESS" >> $GITHUB_OUTPUT
60+
echo "build_url=$BUILD_URL" >> $GITHUB_OUTPUT
61+
break
62+
elif [ "$STATUS" = "failed" ]; then
63+
echo "status=failed" >> $GITHUB_OUTPUT
64+
break
65+
fi
66+
67+
sleep 60
68+
done
69+
70+
- name: Slack Notification
71+
uses: 8398a7/action-slack@v3
72+
if: always()
73+
with:
74+
status: ${{ steps.check_status.outputs.success == 'true' && 'success' || 'failure' }}
75+
fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
76+
text: |
77+
Mobile CI Build Result
78+
Branch: ${{ github.event.inputs.branch }}
79+
Workflow: ${{ github.event.inputs.workflow_id }}
80+
Build URL: ${{ steps.check_status.outputs.build_url }}
81+
env:
82+
SLACK_WEBHOOK_URL: ${{ secrets.RELEASE_SLACK_WEBHOOK }}

codemagic.yaml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
workflows:
2+
ios-workflow:
3+
name: iOS Workflow
4+
instance_type: mac_mini_m2
5+
max_build_duration: 30
6+
environment:
7+
flutter: 3.22.3
8+
xcode: latest
9+
cocoapods: default
10+
11+
scripts:
12+
- name: Build Flutter
13+
script: |
14+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
15+
source "$HOME/.cargo/env"
16+
rustc --version
17+
cargo --version
18+
19+
cd frontend
20+
21+
rustup target install aarch64-apple-ios-sim
22+
cargo install --force cargo-make
23+
cargo install --force duckscript_cli
24+
cargo install --force cargo-lipo
25+
26+
cargo make appflowy-flutter-deps-tools
27+
cargo make --profile development-ios-arm64-sim appflowy-core-dev-ios
28+
cargo make --profile development-ios-arm64-sim code_generation
29+
30+
- name: iOS integration tests
31+
script: |
32+
cd frontend/appflowy_flutter
33+
flutter emulators --launch apple_ios_simulator
34+
flutter -d iPhone test integration_test/runner.dart
35+
36+
artifacts:
37+
- build/ios/ipa/*.ipa
38+
- /tmp/xcodebuild_logs/*.log
39+
- flutter_drive.log
40+
41+
publishing:
42+
email:
43+
recipients:
44+
45+
notify:
46+
success: true
47+
failure: true

frontend/appflowy_flutter/integration_test/mobile/document/page_style_test.dart

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import '../../shared/util.dart';
3636
void main() {
3737
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
3838

39-
group('document page style', () {
39+
group('document page style:', () {
4040
double getCurrentEditorFontSize() {
4141
final editorPage = find
4242
.byType(AppFlowyEditorPage)
@@ -57,11 +57,9 @@ void main() {
5757
.single
5858
.widget as AppFlowyEditorPage;
5959
return editorPage.styleCustomizer
60-
.style()
61-
.textStyleConfiguration
62-
.text
63-
.height ??
64-
PageStyleLineHeightLayout.normal.lineHeight;
60+
.style()
61+
.textStyleConfiguration
62+
.lineHeight;
6563
}
6664

6765
testWidgets('change font size in page style settings', (tester) async {
@@ -87,20 +85,24 @@ void main() {
8785
await tester.openPage(gettingStarted);
8886
// click the layout button
8987
await tester.tapButton(find.byType(MobileViewPageLayoutButton));
88+
var lineHeight = getCurrentEditorLineHeight();
9089
expect(
91-
getCurrentEditorLineHeight(),
90+
lineHeight,
9291
PageStyleLineHeightLayout.normal.lineHeight,
9392
);
9493
// change line height from normal to large
9594
await tester.tapSvgButton(FlowySvgs.m_layout_large_s);
95+
await tester.pumpAndSettle();
96+
lineHeight = getCurrentEditorLineHeight();
9697
expect(
97-
getCurrentEditorLineHeight(),
98+
lineHeight,
9899
PageStyleLineHeightLayout.large.lineHeight,
99100
);
100101
// change line height from large to small
101102
await tester.tapSvgButton(FlowySvgs.m_layout_small_s);
103+
lineHeight = getCurrentEditorLineHeight();
102104
expect(
103-
getCurrentEditorLineHeight(),
105+
lineHeight,
104106
PageStyleLineHeightLayout.small.lineHeight,
105107
);
106108
});

frontend/appflowy_flutter/integration_test/mobile/home_page/create_new_page_test.dart

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,18 @@ import '../../shared/util.dart';
2929
void main() {
3030
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
3131

32-
group('create new page', () {
32+
group('create new page in home page:', () {
3333
testWidgets('create document', (tester) async {
34-
await tester.initializeAppFlowy(
35-
cloudType: AuthenticatorType.local,
36-
);
34+
await tester.launchInAnonymousMode();
3735

3836
// tap the create page button
3937
final createPageButton = find.byWidgetPredicate(
4038
(widget) =>
4139
widget is FlowySvg &&
42-
widget.svg.path == FlowySvgs.m_home_unselected_m.path,
40+
widget.svg.path == FlowySvgs.m_home_add_m.path,
4341
);
4442
await tester.tapButton(createPageButton);
43+
await tester.pumpAndSettle();
4544
expect(find.byType(MobileDocumentScreen), findsOneWidget);
4645
});
4746
});

frontend/appflowy_flutter/integration_test/mobile/sign_in/anonymous_sign_in_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ import '../../shared/util.dart';
2525
void main() {
2626
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
2727

28-
group('anonymous sign in on mobile', () {
28+
group('anonymous sign in on mobile:', () {
2929
testWidgets('anon user and then sign in', (tester) async {
30-
await tester.initializeAppFlowy();
30+
await tester.launchInAnonymousMode();
3131

3232
// expect to see the home page
3333
expect(find.byType(MobileHomeScreen), findsOneWidget);

frontend/appflowy_flutter/integration_test/mobile_runner.dart renamed to frontend/appflowy_flutter/integration_test/mobile_runner_1.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ import 'mobile/document/page_style_test.dart' as page_style_test;
55
import 'mobile/home_page/create_new_page_test.dart' as create_new_page_test;
66
import 'mobile/sign_in/anonymous_sign_in_test.dart' as anonymous_sign_in_test;
77

8-
Future<void> runIntegrationOnMobile() async {
8+
Future<void> main() async {
99
Log.shared.disableLog = true;
10+
11+
await runIntegration1OnMobile();
12+
}
13+
14+
Future<void> runIntegration1OnMobile() async {
1015
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
1116

1217
anonymous_sign_in_test.main();

frontend/appflowy_flutter/integration_test/runner.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'desktop_runner_5.dart';
88
import 'desktop_runner_6.dart';
99
import 'desktop_runner_7.dart';
1010
import 'desktop_runner_8.dart';
11-
import 'mobile_runner.dart';
11+
import 'mobile_runner_1.dart';
1212

1313
/// The main task runner for all integration tests in AppFlowy.
1414
///
@@ -28,7 +28,7 @@ Future<void> main() async {
2828
await runIntegration7OnDesktop();
2929
await runIntegration8OnDesktop();
3030
} else if (Platform.isIOS || Platform.isAndroid) {
31-
await runIntegrationOnMobile();
31+
await runIntegration1OnMobile();
3232
} else {
3333
throw Exception('Unsupported platform');
3434
}

frontend/appflowy_flutter/lib/mobile/presentation/base/mobile_view_page.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ class _MobileViewPageState extends State<MobileViewPage> {
6565
@override
6666
void dispose() {
6767
_appBarOpacity.dispose();
68-
_scrollNotificationObserver?.removeListener(_onScrollNotification);
68+
69+
// there's no need to remove the listener, because the observer will be disposed when the widget is unmounted.
70+
// inside the observer, the listener will be removed automatically.
71+
// _scrollNotificationObserver?.removeListener(_onScrollNotification);
6972
_scrollNotificationObserver = null;
7073

7174
super.dispose();

frontend/appflowy_flutter/pubspec.lock

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,10 +1543,10 @@ packages:
15431543
dependency: transitive
15441544
description:
15451545
name: platform
1546-
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
1546+
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
15471547
url: "https://pub.dev"
15481548
source: hosted
1549-
version: "3.1.4"
1549+
version: "3.1.5"
15501550
plugin_platform_interface:
15511551
dependency: "direct dev"
15521552
description:
@@ -1941,10 +1941,10 @@ packages:
19411941
dependency: transitive
19421942
description:
19431943
name: string_scanner
1944-
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
1944+
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
19451945
url: "https://pub.dev"
19461946
source: hosted
1947-
version: "1.2.0"
1947+
version: "1.3.0"
19481948
string_validator:
19491949
dependency: "direct main"
19501950
description:
@@ -2246,10 +2246,10 @@ packages:
22462246
dependency: transitive
22472247
description:
22482248
name: vm_service
2249-
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
2249+
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
22502250
url: "https://pub.dev"
22512251
source: hosted
2252-
version: "14.2.1"
2252+
version: "14.2.5"
22532253
watcher:
22542254
dependency: transitive
22552255
description:

0 commit comments

Comments
 (0)