diff --git a/.github/workflows/dart_test.yml b/.github/workflows/dart_test.yml index 902a861239..17694e3fec 100644 --- a/.github/workflows/dart_test.yml +++ b/.github/workflows/dart_test.yml @@ -67,7 +67,7 @@ jobs: - name: Build FlowySDK working-directory: frontend run: | - cargo make --profile development-linux-x86_64 flowy-sdk-dev + cargo make --profile test-linux test-lib-build - name: Code Generation working-directory: frontend/app_flowy diff --git a/frontend/Makefile.toml b/frontend/Makefile.toml index 3e73dd7a36..332a8e72db 100644 --- a/frontend/Makefile.toml +++ b/frontend/Makefile.toml @@ -40,10 +40,15 @@ PRODUCT_NAME = "AppFlowy" # for cdylib: # if (Platform.isMacOS) return DynamicLibrary.open('${prefix}/libdart_ffi.dylib'); CRATE_TYPE = "staticlib" -SDK_EXT = "a" +LIB_EXT = "a" APP_ENVIRONMENT = "local" FLUTTER_FLOWY_SDK_PATH = "app_flowy/packages/flowy_sdk" PROTOBUF_DERIVE_CACHE = "../shared-lib/flowy-derive/src/derive_cache/derive_cache.rs" +# Test default config +TEST_CRATE_TYPE = "cdylib" +TEST_LIB_EXT = "dylib" +TEST_BUILD_FLAG = "debug" +TEST_COMPILE_TARGET = "x86_64-apple-darwin" [env.development-mac-arm64] RUST_LOG = "info" @@ -88,7 +93,7 @@ BUILD_FLAG = "debug" FLUTTER_OUTPUT_DIR = "Debug" PRODUCT_EXT = "exe" CRATE_TYPE = "cdylib" -SDK_EXT = "dll" +LIB_EXT = "dll" [env.production-windows-x86] BUILD_FLAG = "release" @@ -97,7 +102,7 @@ RUST_COMPILE_TARGET = "x86_64-pc-windows-msvc" FLUTTER_OUTPUT_DIR = "Release" PRODUCT_EXT = "exe" CRATE_TYPE = "cdylib" -SDK_EXT = "dll" +LIB_EXT = "dll" APP_ENVIRONMENT = "production" [env.development-linux-x86_64] @@ -106,7 +111,7 @@ RUST_COMPILE_TARGET = "x86_64-unknown-linux-gnu" BUILD_FLAG = "debug" CRATE_TYPE = "cdylib" FLUTTER_OUTPUT_DIR = "Debug" -SDK_EXT = "so" +LIB_EXT = "so" LINUX_ARCH = "x64" [env.production-linux-x86_64] @@ -115,7 +120,7 @@ TARGET_OS = "linux" RUST_COMPILE_TARGET = "x86_64-unknown-linux-gnu" CRATE_TYPE = "cdylib" FLUTTER_OUTPUT_DIR = "Release" -SDK_EXT = "so" +LIB_EXT = "so" LINUX_ARCH = "x64" APP_ENVIRONMENT = "production" @@ -125,7 +130,7 @@ RUST_COMPILE_TARGET = "aarch64-unknown-linux-gnu" BUILD_FLAG = "debug" CRATE_TYPE = "cdylib" FLUTTER_OUTPUT_DIR = "Debug" -SDK_EXT = "so" +LIB_EXT = "so" LINUX_ARCH = "arm64" [env.production-linux-aarch64] @@ -134,7 +139,7 @@ TARGET_OS = "linux" RUST_COMPILE_TARGET = "aarch64-unknown-linux-gnu" CRATE_TYPE = "cdylib" FLUTTER_OUTPUT_DIR = "Release" -SDK_EXT = "so" +LIB_EXT = "so" LINUX_ARCH = "arm64" APP_ENVIRONMENT = "production" @@ -197,6 +202,46 @@ script = [ ] script_runner = "@duckscript" +[env.test-macos] +TEST_CRATE_TYPE = "cdylib" +TEST_LIB_EXT = "dylib" +# For the moment, the DynamicLibrary only supports open x86_64 architectures binary. +TEST_COMPILE_TARGET = "x86_64-apple-darwin" + +[env.test-linux] +TEST_CRATE_TYPE = "cdylib" +TEST_LIB_EXT = "so" +TEST_COMPILE_TARGET = "x86_64-unknown-linux-gnu" + +[env.test-windows] +TEST_CRATE_TYPE = "cdylib" +TEST_LIB_EXT = "dll" +TEST_COMPILE_TARGET = "x86_64-pc-windows-msvc" + +[tasks.setup-test-crate-type] +private = true +script = [ + """ + toml = readfile ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/${CARGO_MAKE_CRATE_NAME}/Cargo.toml + val = replace ${toml} "staticlib" ${TEST_CRATE_TYPE} + result = writefile ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/${CARGO_MAKE_CRATE_NAME}/Cargo.toml ${val} + assert ${result} + """, +] +script_runner = "@duckscript" + +[tasks.restore-test-crate-type] +private = true +script = [ + """ + toml = readfile ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/${CARGO_MAKE_CRATE_NAME}/Cargo.toml + val = replace ${toml} ${TEST_CRATE_TYPE} "staticlib" + result = writefile ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/${CARGO_MAKE_CRATE_NAME}/Cargo.toml ${val} + assert ${result} + """, +] +script_runner = "@duckscript" + [tasks.test-build] condition = { env_set = ["FLUTTER_FLOWY_SDK_PATH"] } script = [""" @@ -204,3 +249,5 @@ script = [""" cargo build -vv --features=dart """] script_runner = "@shell" + + diff --git a/frontend/app_flowy/lib/plugins/board/tests/integrate_test/card_test.dart b/frontend/app_flowy/lib/plugins/board/tests/integrate_test/card_test.dart new file mode 100644 index 0000000000..fa267744c7 --- /dev/null +++ b/frontend/app_flowy/lib/plugins/board/tests/integrate_test/card_test.dart @@ -0,0 +1,16 @@ +// import 'package:flutter_test/flutter_test.dart'; +// import 'package:integration_test/integration_test.dart'; +// import 'package:app_flowy/main.dart' as app; + +// void main() { +// IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + +// group('end-to-end test', () { +// testWidgets('tap on the floating action button, verify counter', +// (tester) async { +// app.main(); + +// await tester.pumpAndSettle(); +// }); +// }); +// } diff --git a/frontend/app_flowy/lib/startup/tasks/rust_sdk.dart b/frontend/app_flowy/lib/startup/tasks/rust_sdk.dart index cdac0fa9e3..7e12c19f44 100644 --- a/frontend/app_flowy/lib/startup/tasks/rust_sdk.dart +++ b/frontend/app_flowy/lib/startup/tasks/rust_sdk.dart @@ -16,12 +16,12 @@ class InitRustSDKTask extends LaunchTask { } Future appFlowyDocumentDirectory() async { - Directory documentsDir = await getApplicationDocumentsDirectory(); - switch (integrationEnv()) { case IntegrationMode.develop: + Directory documentsDir = await getApplicationDocumentsDirectory(); return Directory('${documentsDir.path}/flowy_dev').create(); case IntegrationMode.release: + Directory documentsDir = await getApplicationDocumentsDirectory(); return Directory('${documentsDir.path}/flowy').create(); case IntegrationMode.test: return Directory("${Directory.current.path}/.sandbox"); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/ffi.dart b/frontend/app_flowy/packages/flowy_sdk/lib/ffi.dart index 5ced5b2e83..6d9d5a2416 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/ffi.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/ffi.dart @@ -7,10 +7,10 @@ import 'package:ffi/ffi.dart' as ffi; import 'package:flutter/foundation.dart' as Foundation; // ignore_for_file: unused_import, camel_case_types, non_constant_identifier_names -final DynamicLibrary _dl = _open(); +final DynamicLibrary _dart_ffi_lib = _open(); /// Reference to the Dynamic Library, it should be only used for low-level access -final DynamicLibrary dl = _dl; +final DynamicLibrary dl = _dart_ffi_lib; DynamicLibrary _open() { if (Platform.environment.containsKey('FLUTTER_TEST')) { final prefix = "${Directory.current.path}/.sandbox"; @@ -18,7 +18,8 @@ DynamicLibrary _open() { return DynamicLibrary.open('${prefix}/libdart_ffi.so'); if (Platform.isAndroid) return DynamicLibrary.open('${prefix}/libdart_ffi.so'); - if (Platform.isMacOS) return DynamicLibrary.open('${prefix}/libdart_ffi.a'); + if (Platform.isMacOS) + return DynamicLibrary.open('${prefix}/libdart_ffi.dylib'); if (Platform.isIOS) return DynamicLibrary.open('${prefix}/libdart_ffi.a'); if (Platform.isWindows) return DynamicLibrary.open('${prefix}/dart_ffi.dll'); @@ -42,8 +43,8 @@ void async_event( _invoke_async(port, input, len); } -final _invoke_async_Dart _invoke_async = - _dl.lookupFunction<_invoke_async_C, _invoke_async_Dart>('async_event'); +final _invoke_async_Dart _invoke_async = _dart_ffi_lib + .lookupFunction<_invoke_async_C, _invoke_async_Dart>('async_event'); typedef _invoke_async_C = Void Function( Int64 port, Pointer input, @@ -63,8 +64,8 @@ Pointer sync_event( return _invoke_sync(input, len); } -final _invoke_sync_Dart _invoke_sync = - _dl.lookupFunction<_invoke_sync_C, _invoke_sync_Dart>('sync_event'); +final _invoke_sync_Dart _invoke_sync = _dart_ffi_lib + .lookupFunction<_invoke_sync_C, _invoke_sync_Dart>('sync_event'); typedef _invoke_sync_C = Pointer Function( Pointer input, Uint64 len, @@ -82,7 +83,7 @@ int init_sdk( } final _init_sdk_Dart _init_sdk = - _dl.lookupFunction<_init_sdk_C, _init_sdk_Dart>('init_sdk'); + _dart_ffi_lib.lookupFunction<_init_sdk_C, _init_sdk_Dart>('init_sdk'); typedef _init_sdk_C = Int64 Function( Pointer path, ); @@ -96,7 +97,7 @@ int set_stream_port(int port) { } final _set_stream_port_Dart _set_stream_port = - _dl.lookupFunction<_set_stream_port_C, _set_stream_port_Dart>( + _dart_ffi_lib.lookupFunction<_set_stream_port_C, _set_stream_port_Dart>( 'set_stream_port'); typedef _set_stream_port_C = Int32 Function( @@ -111,7 +112,7 @@ void link_me_please() { _link_me_please(); } -final _link_me_please_Dart _link_me_please = _dl +final _link_me_please_Dart _link_me_please = _dart_ffi_lib .lookupFunction<_link_me_please_C, _link_me_please_Dart>('link_me_please'); typedef _link_me_please_C = Void Function(); typedef _link_me_please_Dart = void Function(); @@ -123,7 +124,7 @@ void store_dart_post_cobject( _store_dart_post_cobject(ptr); } -final _store_dart_post_cobject_Dart _store_dart_post_cobject = _dl +final _store_dart_post_cobject_Dart _store_dart_post_cobject = _dart_ffi_lib .lookupFunction<_store_dart_post_cobject_C, _store_dart_post_cobject_Dart>( 'store_dart_post_cobject'); typedef _store_dart_post_cobject_C = Void Function( diff --git a/frontend/app_flowy/pubspec.lock b/frontend/app_flowy/pubspec.lock index b10cbf3629..f280d3b4ca 100644 --- a/frontend/app_flowy/pubspec.lock +++ b/frontend/app_flowy/pubspec.lock @@ -49,7 +49,7 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.3.1" + version: "3.1.11" args: dependency: transitive description: @@ -245,7 +245,7 @@ packages: name: coverage url: "https://pub.dartlang.org" source: hosted - version: "1.3.2" + version: "1.2.0" cross_file: dependency: transitive description: @@ -259,7 +259,7 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.0.1" csslib: dependency: transitive description: @@ -454,6 +454,11 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.1" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" flutter_inappwebview: dependency: transitive description: @@ -555,6 +560,11 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.3" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" get_it: dependency: "direct main" description: @@ -660,6 +670,11 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.5.0" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" intl: dependency: "direct main" description: @@ -1246,6 +1261,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.3.1+2" + sync_http: + dependency: transitive + description: + name: sync_http + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" table_calendar: dependency: "direct main" description: @@ -1322,7 +1344,7 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "1.3.0" universal_platform: dependency: transitive description: @@ -1441,7 +1463,7 @@ packages: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "8.3.0" + version: "8.2.2" watcher: dependency: transitive description: @@ -1456,6 +1478,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.0" + webdriver: + dependency: transitive + description: + name: webdriver + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" webkit_inspection_protocol: dependency: transitive description: diff --git a/frontend/app_flowy/pubspec.yaml b/frontend/app_flowy/pubspec.yaml index d689ed688e..302d8b920e 100644 --- a/frontend/app_flowy/pubspec.yaml +++ b/frontend/app_flowy/pubspec.yaml @@ -97,6 +97,8 @@ dev_dependencies: flutter_test: sdk: flutter + integration_test: + sdk: flutter build_runner: ^2.2.0 freezed: ^2.1.0+1 bloc_test: ^9.0.2 diff --git a/frontend/app_flowy/test/workspace_bloc_test.dart b/frontend/app_flowy/test/bloc_test/workspace_bloc_test.dart similarity index 86% rename from frontend/app_flowy/test/workspace_bloc_test.dart rename to frontend/app_flowy/test/bloc_test/workspace_bloc_test.dart index d0b898cc42..100611b73b 100644 --- a/frontend/app_flowy/test/workspace_bloc_test.dart +++ b/frontend/app_flowy/test/bloc_test/workspace_bloc_test.dart @@ -4,13 +4,13 @@ import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_test/bloc_test.dart'; -import 'util/test_env.dart'; +import '../util.dart'; void main() { UserProfilePB? userInfo; setUpAll(() async { - final flowyTest = await FlowyTest.setup(); - userInfo = await flowyTest.signIn(); + await AppFlowyBlocTest.ensureInitialized(); + userInfo = await signIn(); }); group('WelcomeBloc', () { diff --git a/frontend/app_flowy/test/util.dart b/frontend/app_flowy/test/util.dart new file mode 100644 index 0000000000..b65469a9ab --- /dev/null +++ b/frontend/app_flowy/test/util.dart @@ -0,0 +1,65 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/user/application/auth_service.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/uuid.dart'; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:app_flowy/main.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class AppFlowyIntegrateTest { + static Future ensureInitialized() async { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + SharedPreferences.setMockInitialValues({}); + main(); + return AppFlowyIntegrateTest(); + } +} + +class AppFlowyBlocTest { + static Future ensureInitialized() async { + TestWidgetsFlutterBinding.ensureInitialized(); + SharedPreferences.setMockInitialValues({}); + pathProviderInitialized(); + + await EasyLocalization.ensureInitialized(); + await FlowyRunner.run(FlowyTestApp()); + return AppFlowyBlocTest(); + } +} + +void pathProviderInitialized() { + const MethodChannel channel = + MethodChannel('plugins.flutter.io/path_provider'); + channel.setMockMethodCallHandler((MethodCall methodCall) async { + return "."; + }); +} + +Future signIn() async { + final authService = getIt(); + const password = "AppFlowy123@"; + final uid = uuid(); + final userEmail = "$uid@appflowy.io"; + final result = await authService.signUp( + name: "FlowyTestUser", + password: password, + email: userEmail, + ); + return result.fold( + (user) => user, + (error) { + throw StateError("$error"); + }, + ); +} + +class FlowyTestApp implements EntryPoint { + @override + Widget create() { + return Container(); + } +} diff --git a/frontend/app_flowy/test/util/test_env.dart b/frontend/app_flowy/test/util/test_env.dart deleted file mode 100644 index 1743e4b920..0000000000 --- a/frontend/app_flowy/test/util/test_env.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/user/application/auth_service.dart'; -import 'package:flowy_infra/uuid.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -class FlowyTest { - static Future setup() async { - TestWidgetsFlutterBinding.ensureInitialized(); - // await EasyLocalization.ensureInitialized(); - - await FlowyRunner.run(FlowyTestApp()); - return FlowyTest(); - } - - Future signIn() async { - final authService = getIt(); - const password = "AppFlowy123@"; - final uid = uuid(); - final userEmail = "$uid@appflowy.io"; - final result = await authService.signUp( - name: "FlowyTestUser", - password: password, - email: userEmail, - ); - return result.fold( - (user) => user, - (error) { - throw StateError("$error"); - }, - ); - } -} - -class FlowyTestApp implements EntryPoint { - @override - Widget create() { - return Container(); - } -} diff --git a/frontend/scripts/makefile/desktop.toml b/frontend/scripts/makefile/desktop.toml index 09b1680f3f..b97770378b 100644 --- a/frontend/scripts/makefile/desktop.toml +++ b/frontend/scripts/makefile/desktop.toml @@ -21,17 +21,18 @@ run_task = { name = ["setup-crate-type","sdk-build-android", "restore-crate-type [tasks.flowy-sdk-dev-macos] category = "Build" dependencies = ["env_check"] -run_task = { name = ["setup-crate-type","sdk-build", "post-desktop", "restore-crate-type", "copy-to-sys-tmpdir"] } +run_task = { name = ["setup-crate-type","sdk-build", "post-desktop", "restore-crate-type"] } [tasks.flowy-sdk-dev-windows] category = "Build" dependencies = ["env_check"] -run_task = { name = ["setup-crate-type","sdk-build", "post-desktop", "restore-crate-type", "copy-to-sys-tmpdir"] } +run_task = { name = ["setup-crate-type","sdk-build", "post-desktop", "restore-crate-type"] } [tasks.flowy-sdk-dev-linux] category = "Build" dependencies = ["env_check"] -run_task = { name = ["setup-crate-type","sdk-build", "post-desktop", "restore-crate-type", "copy-to-sys-tmpdir"] } +run_task = { name = ["setup-crate-type","sdk-build", "post-desktop", "restore-crate-type"] } + # [tasks.sdk-build] @@ -114,7 +115,7 @@ script = [ """ echo "🚀 🚀 🚀 Flowy-SDK(macOS) build success" dart_ffi_dir= set ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/packages/flowy_sdk/${TARGET_OS} - lib = set lib${LIB_NAME}.${SDK_EXT} + lib = set lib${LIB_NAME}.${LIB_EXT} cp ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/target/${RUST_COMPILE_TARGET}/${BUILD_FLAG}/${lib} \ ${dart_ffi_dir}/${lib} @@ -131,7 +132,7 @@ script = [ """ echo "🚀 🚀 🚀 Flowy-SDK(windows) build success" dart_ffi_dir= set ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/windows/flutter/dart_ffi - lib = set ${LIB_NAME}.${SDK_EXT} + lib = set ${LIB_NAME}.${LIB_EXT} # copy dll cp ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/target/${RUST_COMPILE_TARGET}/${BUILD_FLAG}/${lib} \ @@ -150,7 +151,7 @@ script = [ """ echo "🚀 🚀 🚀 Flowy-SDK(linux) build success" dart_ffi_dir= set ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/linux/flutter/dart_ffi - lib = set lib${LIB_NAME}.${SDK_EXT} + lib = set lib${LIB_NAME}.${LIB_EXT} # copy dll cp ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/target/${RUST_COMPILE_TARGET}/${BUILD_FLAG}/${lib} \ @@ -163,25 +164,34 @@ script = [ ] script_runner = "@duckscript" -[tasks.copy-to-sys-tmpdir] +[tasks.test-lib-build] +category = "Build" +dependencies = ["env_check"] +run_task = { name = ["setup-test-crate-type","test-sdk-build", "copy-to-sandbox-folder", "restore-test-crate-type"] } + +[tasks.test-sdk-build] +private = true +script = [ + """ + cd rust-lib/ + rustup show + echo cargo build --package=dart-ffi --target ${TEST_COMPILE_TARGET} --features "${FEATURES}" + cargo build --package=dart-ffi --target ${TEST_COMPILE_TARGET} --features "${FEATURES}" + cd ../ + """, +] +script_runner = "@shell" + +[tasks.copy-to-sandbox-folder] private = true script = [ """ # Copy the flowy_sdk lib to system temp directory for flutter unit test. - lib = set lib${LIB_NAME}.${SDK_EXT} + lib = set lib${LIB_NAME}.${TEST_LIB_EXT} dest = set ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/.sandbox/${lib} rm ${dest} - cp ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/target/${RUST_COMPILE_TARGET}/${BUILD_FLAG}/${lib} \ + cp ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/target/${TEST_COMPILE_TARGET}/${TEST_BUILD_FLAG}/${lib} \ ${dest} """, ] script_runner = "@duckscript" - -[tasks.copy-to-sys-tmpdir.windows] -private = true -script = [ - """ - # Doesn't work on windows - """, -] -script_runner = "@duckscript" \ No newline at end of file