From f10d9117c2cc0090e4e3824d725a111d3812d05f Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Sat, 3 Feb 2024 17:14:29 +0000 Subject: [PATCH 01/56] Add delay after call to issuePresentation from DidKit --- lib/scan/cubit/scan_cubit.dart | 1 + pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index f85040e73..5faeafaa2 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -531,6 +531,7 @@ class ScanCubit extends Cubit { profileSetting: qrCodeScanCubit.profileCubit.state.model.profileSetting, ); + await Future.delayed(const Duration(milliseconds: 1000)); final responseData = { 'vp_token': vpToken, 'presentation_submission': presentationSubmissionString, diff --git a/pubspec.lock b/pubspec.lock index 8871568a7..affb9f4c4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -310,10 +310,10 @@ packages: dependency: transitive description: name: camera_platform_interface - sha256: e971ebca970f7cfee396f76ef02070b5e441b4aa04942da9c108d725f57bbd32 + sha256: fceb2c36038b6392317b1d5790c6ba9e6ca9f1da3031181b8bea03882bf9387a url: "https://pub.dev" source: hosted - version: "2.7.2" + version: "2.7.3" camera_web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d4e2cf25a..eb5d0d737 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.13+375 +version: 2.2.14+376 environment: sdk: ">=3.1.0 <4.0.0" From 42f4bdaeda49003e7ab970e8b571cc06f3cabd55 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 4 Mar 2024 09:01:16 +0000 Subject: [PATCH 02/56] mocktail: ^1.0.3 in oidc4vc package to sync with didkit --- packages/oidc4vc/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/oidc4vc/pubspec.yaml b/packages/oidc4vc/pubspec.yaml index cfdafa866..e0ec417ae 100644 --- a/packages/oidc4vc/pubspec.yaml +++ b/packages/oidc4vc/pubspec.yaml @@ -43,5 +43,5 @@ dev_dependencies: flutter_test: sdk: flutter json_serializable: ^6.7.0 - mocktail: ^0.3.0 + mocktail: ^1.0.3 very_good_analysis: ^5.0.0+1 From 55a8a7e9d29ddfde51cdcbaaafa6909948882e35 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Thu, 4 Apr 2024 06:59:09 +0000 Subject: [PATCH 03/56] update pubspec.lock --- pubspec.lock | 104 ++++++++++++++++++++++----------------------------- 1 file changed, 44 insertions(+), 60 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 02379556a..6d838e227 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "64.0.0" + version: "67.0.0" adaptive_number: dependency: transitive description: @@ -21,18 +21,10 @@ packages: dependency: transitive description: name: analyzer - sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "6.2.0" - android_intent_plus: - dependency: transitive - description: - name: android_intent_plus - sha256: e92d14009f3f6ebafca6a601958aaebb793559fb03a1961fe3c5596db95af2cb - url: "https://pub.dev" - source: hosted - version: "5.0.1" + version: "6.4.1" ansicolor: dependency: transitive description: @@ -238,10 +230,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.9" build_runner_core: dependency: transitive description: @@ -262,10 +254,10 @@ packages: dependency: transitive description: name: built_value - sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.9.1" + version: "8.9.2" cached_network_image: dependency: "direct main" description: @@ -310,10 +302,10 @@ packages: dependency: transitive description: name: camera_avfoundation - sha256: "8b113e43ee4434c9244c03c905432a0d5956cedaded3cd7381abaab89ce50297" + sha256: "841682a28b99b8594532d2afe81e092a2c1edb2c93526f6f841a878dd57eec8d" url: "https://pub.dev" source: hosted - version: "0.9.14+1" + version: "0.9.14+2" camera_platform_interface: dependency: transitive description: @@ -437,10 +429,10 @@ packages: dependency: transitive description: name: cross_file - sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" url: "https://pub.dev" source: hosted - version: "0.3.3+8" + version: "0.3.4+1" crypto: dependency: "direct main" description: @@ -989,10 +981,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "5b24061317f850af858ef7151dadbb6eb77c1c449c954c7bb064e8a5e0e7d81f" + sha256: "31c12de79262b5431c5492e9c89948aa789158435f707d3519a7fdef6af28af7" url: "https://pub.dev" source: hosted - version: "0.6.20" + version: "0.6.22+1" flutter_native_timezone: dependency: "direct main" description: @@ -1127,10 +1119,10 @@ packages: dependency: transitive description: name: get_it - sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 + sha256: "36524bfb3f0b4ec952c3202466fdd69ad1f7ac1dd9b0a7564177707e45bfaeb9" url: "https://pub.dev" source: hosted - version: "7.6.7" + version: "7.6.8" glob: dependency: transitive description: @@ -1215,10 +1207,10 @@ packages: dependency: "direct overridden" description: name: http - sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" http_mock_adapter: dependency: "direct dev" description: @@ -1263,18 +1255,18 @@ packages: dependency: transitive description: name: image_picker_android - sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" + sha256: "42c098e7fb6334746be37cdc30369ade356ed4f14d48b7a0313f95a9159f4321" url: "https://pub.dev" source: hosted - version: "0.8.9+3" + version: "0.8.9+5" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: e2423c53a68b579a7c37a1eda967b8ae536c3d98518e5db95ca1fe5719a730a3 + sha256: "6a1704fdd75022272e7e7a897a9068e9c2ff3cd6a66820bf3ded810633eac954" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" image_picker_ios: dependency: transitive description: @@ -1303,10 +1295,10 @@ packages: dependency: transitive description: name: image_picker_platform_interface - sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b + sha256: "3d2c323daea9d60608f1caf30be32a938916f4975434b8352e6f73dae496da38" url: "https://pub.dev" source: hosted - version: "2.9.3" + version: "2.9.4" image_picker_windows: dependency: transitive description: @@ -1319,10 +1311,10 @@ packages: dependency: transitive description: name: injectable - sha256: "44b4aa254816b23bf0a3285ff27da3ff0b516a6f00e0bbbea7b194f14fbb75a7" + sha256: "3d98967224a5fdd4094a61bf53ed9616c3fbcf3e090bf83e7cb7d436d0c20041" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.4.1" intl: dependency: transitive description: @@ -1593,14 +1585,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" - model_viewer_plus: - dependency: "direct main" - description: - name: model_viewer_plus - sha256: "633efbd081efe9af8b149c5553fa1e3e83a298ccc151955b0fe9d56a666943be" - url: "https://pub.dev" - source: hosted - version: "1.7.2" nested: dependency: transitive description: @@ -2155,10 +2139,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.3.0" shared_preferences_windows: dependency: transitive description: @@ -2264,26 +2248,26 @@ packages: dependency: transitive description: name: sqflite - sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + sha256: "5ce2e1a15e822c3b4bfb5400455775e421da7098eed8adc8f26298ada7c9308c" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.5.4" sqlite3: dependency: transitive description: name: sqlite3 - sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9" + sha256: "1abbeb84bf2b1a10e5e1138c913123c8aa9d83cd64e5f9a0dd847b3c83063202" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.2" stack_trace: dependency: transitive description: @@ -2489,10 +2473,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b + sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.0" url_launcher_windows: dependency: transitive description: @@ -2593,10 +2577,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.1" web3dart: dependency: transitive description: @@ -2609,10 +2593,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.4" webkit_inspection_protocol: dependency: transitive description: @@ -2665,10 +2649,10 @@ packages: dependency: transitive description: name: win32 - sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + sha256: "0a989dc7ca2bb51eac91e8fd00851297cfffd641aa7538b165c62637ca0eaa4a" url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.4.0" win32_registry: dependency: transitive description: @@ -2734,5 +2718,5 @@ packages: source: hosted version: "2.2.0" sdks: - dart: ">=3.2.3 <4.0.0" - flutter: ">=3.16.6" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" From 2083c5cb41d3a7b2652c46bcba0c458286e9b3d2 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 6 May 2024 13:55:32 +0000 Subject: [PATCH 04/56] initialize sendReceiveHomeCubit with proper apiUrl to get Balance of tokens --- .../send_receive_home/view/send_receive_home_page.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/dashboard/home/tab_bar/tokens/send_receive_home/view/send_receive_home_page.dart b/lib/dashboard/home/tab_bar/tokens/send_receive_home/view/send_receive_home_page.dart index 950f1c79c..34e3b3647 100644 --- a/lib/dashboard/home/tab_bar/tokens/send_receive_home/view/send_receive_home_page.dart +++ b/lib/dashboard/home/tab_bar/tokens/send_receive_home/view/send_receive_home_page.dart @@ -45,9 +45,10 @@ class _SendReceiveHomePageState extends State { @override void initState() { - Future.microtask( - sendReceiveHomeCubit.init, - ); + Future.delayed(Duration.zero, () { + sendReceiveHomeCubit.init( + baseUrl: context.read().state.network.apiUrl); + }); super.initState(); } From 20e43d4ade5f8ecb8d4b5908a94f9928394da568 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 6 May 2024 14:16:56 +0000 Subject: [PATCH 05/56] version: 2.5.0+449 --- pubspec.lock | 262 ++++++++++++++++++++++++++++++--------------------- pubspec.yaml | 2 +- 2 files changed, 156 insertions(+), 108 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index eeb2802f4..dd9f4b210 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "64.0.0" + version: "67.0.0" adaptive_number: dependency: transitive description: @@ -21,18 +21,18 @@ packages: dependency: transitive description: name: analyzer - sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.4.1" android_intent_plus: dependency: transitive description: name: android_intent_plus - sha256: e92d14009f3f6ebafca6a601958aaebb793559fb03a1961fe3c5596db95af2cb + sha256: "2bfdbee8d65e7c26f88b66f0a91f2863da4d3596d8a658b4162c8de5cf04b074" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "5.0.2" ansicolor: dependency: transitive description: @@ -45,20 +45,20 @@ packages: dependency: transitive description: name: archive - sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 url: "https://pub.dev" source: hosted - version: "3.4.10" + version: "3.5.1" args: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" asn1lib: - dependency: transitive + dependency: "direct main" description: name: asn1lib sha256: c9c85fedbe2188b95133cbe960e16f5f448860f7133330e272edbbca5893ddc6 @@ -238,10 +238,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.9" build_runner_core: dependency: transitive description: @@ -262,10 +262,10 @@ packages: dependency: transitive description: name: built_value - sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.9.1" + version: "8.9.2" cached_network_image: dependency: "direct main" description: @@ -286,10 +286,10 @@ packages: dependency: transitive description: name: cached_network_image_web - sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" + sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" camera: dependency: "direct main" description: @@ -302,18 +302,18 @@ packages: dependency: transitive description: name: camera_android - sha256: "1100e527b44a96906987a91ef78c8dacb539e34612a8058de89023380acf67f1" + sha256: "7b0aba6398afa8475e2bc9115d976efb49cf8db781e922572d443795c04a4f4f" url: "https://pub.dev" source: hosted - version: "0.10.8+18" + version: "0.10.9+1" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "8b113e43ee4434c9244c03c905432a0d5956cedaded3cd7381abaab89ce50297" + sha256: "7d021e8cd30d9b71b8b92b4ad669e80af432d722d18d6aac338572754a786c15" url: "https://pub.dev" source: hosted - version: "0.9.14+1" + version: "0.9.16" camera_platform_interface: dependency: transitive description: @@ -326,10 +326,10 @@ packages: dependency: transitive description: name: camera_web - sha256: f18ccfb33b2a7c49a52ad5aa3f07330b7422faaecbdfd9b9fe8e51182f6ad67d + sha256: "9e9aba2fbab77ce2472924196ff8ac4dd8f9126c4f9a3096171cd1d870d6b26c" url: "https://pub.dev" source: hosted - version: "0.3.2+4" + version: "0.3.3" canonical_json: dependency: transitive description: @@ -437,10 +437,10 @@ packages: dependency: transitive description: name: cross_file - sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" url: "https://pub.dev" source: hosted - version: "0.3.3+8" + version: "0.3.4+1" crypto: dependency: "direct main" description: @@ -500,10 +500,10 @@ packages: dependency: "direct main" description: name: dart_jsonwebtoken - sha256: "40dc3a4788c02a44bc97ea0c8c4a078ae58c9a45acc2312ee6a689b0e8f5b5b9" + sha256: "346e9a21e4bf6e6a431e19ece00ebb2e3668e1e339cabdf6f46d18d88692a848" url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.14.0" dart_style: dependency: transitive description: @@ -537,6 +537,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.10" + decimal: + dependency: "direct main" + description: + name: decimal + sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21" + url: "https://pub.dev" + source: hosted + version: "2.3.3" device_frame: dependency: transitive description: @@ -627,10 +635,10 @@ packages: dependency: "direct main" description: name: dio - sha256: "0978e9a3e45305a80a7210dbeaf79d6ee8bee33f70c8e542dc654c952070217f" + sha256: "11e40df547d418cc0c4900a9318b26304e665da6fa4755399a9ff9efd09034b5" url: "https://pub.dev" source: hosted - version: "5.4.2+1" + version: "5.4.3+1" dio_cache_interceptor: dependency: transitive description: @@ -976,10 +984,10 @@ packages: dependency: transitive description: name: flutter_local_notifications_platform_interface - sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" + sha256: "340abf67df238f7f0ef58f4a26d2a83e1ab74c77ab03cd2b2d5018ac64db30b7" url: "https://pub.dev" source: hosted - version: "7.0.0+1" + version: "7.1.0" flutter_localizations: dependency: "direct main" description: flutter @@ -989,10 +997,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "5b24061317f850af858ef7151dadbb6eb77c1c449c954c7bb064e8a5e0e7d81f" + sha256: "04c4722cc36ec5af38acc38ece70d22d3c2123c61305d555750a091517bbe504" url: "https://pub.dev" source: hosted - version: "0.6.20" + version: "0.6.23" flutter_native_timezone: dependency: "direct main" description: @@ -1029,10 +1037,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.0.19" flutter_secure_storage: dependency: transitive description: @@ -1127,10 +1135,10 @@ packages: dependency: transitive description: name: get_it - sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 + sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1 url: "https://pub.dev" source: hosted - version: "7.6.7" + version: "7.7.0" glob: dependency: transitive description: @@ -1215,10 +1223,10 @@ packages: dependency: "direct overridden" description: name: http - sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" http_mock_adapter: dependency: "direct dev" description: @@ -1255,34 +1263,34 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "26222b01a0c9a2c8fe02fc90b8208bd3325da5ed1f4a2acabf75939031ac0bdd" + sha256: "33974eca2e87e8b4e3727f1b94fa3abcb25afe80b6bc2c4d449a0e150aedf720" url: "https://pub.dev" source: hosted - version: "1.0.7" + version: "1.1.1" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" + sha256: "40e24f467b75cd6f4a92ee93dd13d1a7bcb4523a84fd95f00c755f01f42398c8" url: "https://pub.dev" source: hosted - version: "0.8.9+3" + version: "0.8.11" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: e2423c53a68b579a7c37a1eda967b8ae536c3d98518e5db95ca1fe5719a730a3 + sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.4" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "917a5cadd67d052554cfb258595e54217de53fac5b52939426e26319a02e6297" + sha256: f74064bc548b5164a033ec05638e23c91be1a249c255e0f56319dddffd759794 url: "https://pub.dev" source: hosted - version: "0.8.9+2" + version: "0.8.10+1" image_picker_linux: dependency: transitive description: @@ -1303,10 +1311,10 @@ packages: dependency: transitive description: name: image_picker_platform_interface - sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b + sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" url: "https://pub.dev" source: hosted - version: "2.9.3" + version: "2.10.0" image_picker_windows: dependency: transitive description: @@ -1319,10 +1327,10 @@ packages: dependency: transitive description: name: injectable - sha256: "44b4aa254816b23bf0a3285ff27da3ff0b516a6f00e0bbbea7b194f14fbb75a7" + sha256: "3d98967224a5fdd4094a61bf53ed9616c3fbcf3e090bf83e7cb7d436d0c20041" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.4.1" intl: dependency: transitive description: @@ -1359,10 +1367,10 @@ packages: dependency: "direct main" description: name: json_annotation - sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.1" + version: "4.9.0" json_path: dependency: "direct main" description: @@ -1383,10 +1391,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b url: "https://pub.dev" source: hosted - version: "6.7.1" + version: "6.8.0" jwt_decode: dependency: "direct main" description: @@ -1401,6 +1409,30 @@ packages: relative: true source: path version: "1.0.0+1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" linkify: dependency: transitive description: @@ -1429,10 +1461,10 @@ packages: dependency: transitive description: name: local_auth_android - sha256: "3bcd732dda7c75fcb7ddaef12e131230f53dcc8c00790d0d6efb3aa0fbbeda57" + sha256: e0e5b1ea247c5a0951c13a7ee13dc1beae69750e6a2e1910d1ed6a3cd4d56943 url: "https://pub.dev" source: hosted - version: "1.0.37" + version: "1.0.38" local_auth_darwin: dependency: transitive description: @@ -1485,18 +1517,18 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" matrix: dependency: "direct main" description: @@ -1525,10 +1557,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" mime: dependency: "direct main" description: @@ -1676,10 +1708,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_drawing: dependency: transitive description: @@ -1700,18 +1732,18 @@ packages: dependency: transitive description: name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.4" path_provider_foundation: dependency: transitive description: @@ -1756,10 +1788,10 @@ packages: dependency: transitive description: name: permission_handler_android - sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474" + sha256: "8bb852cd759488893805c3161d0b2b5db55db52f773dbb014420b304055ba2c5" url: "https://pub.dev" source: hosted - version: "12.0.5" + version: "12.0.6" permission_handler_apple: dependency: transitive description: @@ -1984,6 +2016,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" + rational: + dependency: transitive + description: + name: rational + sha256: ba58e9e18df9abde280e8b10051e4bce85091e41e8e7e411b6cde2e738d357cf + url: "https://pub.dev" + source: hosted + version: "2.2.2" retry: dependency: transitive description: @@ -2091,18 +2131,18 @@ packages: dependency: transitive description: name: shared_preferences - sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" shared_preferences_foundation: dependency: transitive description: @@ -2131,10 +2171,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.3.0" shared_preferences_windows: dependency: transitive description: @@ -2240,26 +2280,26 @@ packages: dependency: transitive description: name: sqflite - sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3+1" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.5.4" sqlite3: dependency: transitive description: name: sqlite3 - sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9" + sha256: "1abbeb84bf2b1a10e5e1138c913123c8aa9d83cd64e5f9a0dd847b3c83063202" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.2" stack_trace: dependency: transitive description: @@ -2353,10 +2393,10 @@ packages: dependency: "direct main" description: name: timezone - sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" + sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5 url: "https://pub.dev" source: hosted - version: "0.9.2" + version: "0.9.3" timing: dependency: transitive description: @@ -2417,18 +2457,18 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e" + sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e" url: "https://pub.dev" source: hosted - version: "6.2.5" + version: "6.2.6" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 + sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.1" url_launcher_ios: dependency: transitive description: @@ -2465,10 +2505,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b + sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.1" url_launcher_windows: dependency: transitive description: @@ -2569,10 +2609,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.1" web3dart: dependency: transitive description: @@ -2585,10 +2625,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.5" webkit_inspection_protocol: dependency: transitive description: @@ -2601,10 +2641,10 @@ packages: dependency: transitive description: name: webrtc_interface - sha256: "2efbd3e4e5ebeb2914253bcc51dafd3053c4b87b43f3076c74835a9deecbae3a" + sha256: abec3ab7956bd5ac539cf34a42fa0c82ea26675847c0966bb85160400eea9388 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" webview_flutter: dependency: "direct main" description: @@ -2617,10 +2657,10 @@ packages: dependency: "direct main" description: name: webview_flutter_android - sha256: f038ee2fae73b509dde1bc9d2c5a50ca92054282de17631a9a3d515883740934 + sha256: dad3313c9ead95517bb1cae5e1c9d20ba83729d5a59e5e83c0a2d66203f27f91 url: "https://pub.dev" source: hosted - version: "3.16.0" + version: "3.16.1" webview_flutter_platform_interface: dependency: transitive description: @@ -2641,18 +2681,18 @@ packages: dependency: transitive description: name: win32 - sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.5.0" win32_registry: dependency: transitive description: name: win32_registry - sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a" + sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" x25519: dependency: transitive description: @@ -2661,6 +2701,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.1" + x509: + dependency: "direct main" + description: + name: x509 + sha256: "3262dc9a7d45b0876f886c01bfc7d5e765704f7dfd31f8cf5224fc875c17a6c6" + url: "https://pub.dev" + source: hosted + version: "0.2.4+2" x509_plus: dependency: transitive description: @@ -2697,10 +2745,10 @@ packages: dependency: transitive description: name: yaml_edit - sha256: c566f4f804215d84a7a2c377667f546c6033d5b34b4f9e60dfb09d17c4e97826 + sha256: e9c1a3543d2da0db3e90270dbb1e4eebc985ee5e3ffe468d83224472b2194a5f url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.1" sdks: - dart: ">=3.2.3 <4.0.0" - flutter: ">=3.16.6" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index f8fae0886..9d8c4711e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.4.28+448 +version: 2.5.0+449 environment: sdk: ">=3.1.0 <4.0.0" From 8c4d4ac7cc43a1aa7cc5942cd3e1cf68f87f94da Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 6 May 2024 16:40:08 +0000 Subject: [PATCH 06/56] Create proof for presentation 20 second in the past --- lib/scan/cubit/scan_cubit.dart | 50 +++++++++++++++++++++++++--------- pubspec.lock | 8 ------ 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index f326b6758..281259fdc 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -182,7 +182,19 @@ class ScanCubit extends Cubit { } else { for (final item in credentialsToBePresented) { final presentationId = 'urn:uuid:${const Uuid().v4()}'; - + /// proof is done with a creation date 20 seconds in the past to avoid + /// proof check to fail because of time difference on server + + final options = jsonEncode({ + 'verificationMethod': kid, + 'proofPurpose': 'assertionMethod', + 'challenge': credentialModel.challenge, + 'domain': credentialModel.domain, + 'created': DateTime.now() + .subtract(const Duration(seconds: 20)) + .toUtc() + .toIso8601String(), + }); final presentation = await didKitProvider.issuePresentation( jsonEncode({ '@context': ['https://www.w3.org/2018/credentials/v1'], @@ -191,12 +203,7 @@ class ScanCubit extends Cubit { 'holder': did, 'verifiableCredential': item.data, }), - jsonEncode({ - 'verificationMethod': kid, - 'proofPurpose': 'assertionMethod', - 'challenge': credentialModel.challenge, - 'domain': credentialModel.domain, - }), + options, privateKey, ); presentations = List.of(presentations)..add(presentation); @@ -346,6 +353,20 @@ class ScanCubit extends Cubit { ); final presentationId = 'urn:uuid:${const Uuid().v4()}'; + + /// proof is done with a creation date 20 seconds in the past to avoid + /// proof check to fail because of time difference on server + final options = jsonEncode({ + 'verificationMethod': kid, + 'proofPurpose': 'assertionMethod', + 'challenge': challenge, + 'domain': domain, + 'created': DateTime.now() + .subtract(const Duration(seconds: 20)) + .toUtc() + .toIso8601String(), + }); + final presentation = await didKitProvider.issuePresentation( jsonEncode({ '@context': ['https://www.w3.org/2018/credentials/v1'], @@ -356,12 +377,7 @@ class ScanCubit extends Cubit { ? credentialsToBePresented.first.data : credentialsToBePresented.map((c) => c.data).toList(), }), - jsonEncode({ - 'verificationMethod': kid, - 'proofPurpose': 'assertionMethod', - 'challenge': challenge, - 'domain': domain, - }), + options, privateKey, ); @@ -889,12 +905,20 @@ class ScanCubit extends Cubit { ); if (presentLdpVc) { + + /// proof is done with a creation date 20 seconds in the past to avoid + /// proof check to fail because of time difference on server final options = jsonEncode({ 'verificationMethod': kid, 'proofPurpose': 'assertionMethod', 'challenge': nonce, 'domain': clientId, + 'created': DateTime.now() + .subtract(const Duration(seconds: 20)) + .toUtc() + .toIso8601String(), }); + final presentationId = 'urn:uuid:${const Uuid().v4()}'; final vpToken = await didKitProvider.issuePresentation( jsonEncode({ diff --git a/pubspec.lock b/pubspec.lock index 5abbd3bee..da6c1f712 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,14 +25,6 @@ packages: url: "https://pub.dev" source: hosted version: "6.4.1" - android_intent_plus: - dependency: transitive - description: - name: android_intent_plus - sha256: "2bfdbee8d65e7c26f88b66f0a91f2863da4d3596d8a658b4162c8de5cf04b074" - url: "https://pub.dev" - source: hosted - version: "5.0.2" ansicolor: dependency: transitive description: From 96264703c039b3e80074e3007f3d71cc9488e689 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 6 May 2024 16:40:37 +0000 Subject: [PATCH 07/56] version: 2.5.1+450 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 3d660f807..2f34cdf42 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.5.0+449 +version: 2.5.1+450 environment: sdk: ">=3.1.0 <4.0.0" From 70df165ea49b6a689aa9be5b5eb126d1e94f022c Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 10 May 2024 07:36:48 +0000 Subject: [PATCH 08/56] Do not remove the GET a crypto account in the Discover #2649 --- lib/credentials/cubit/credentials_cubit.dart | 34 +++----------------- 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/lib/credentials/cubit/credentials_cubit.dart b/lib/credentials/cubit/credentials_cubit.dart index 9a94dd22f..2e578bc75 100644 --- a/lib/credentials/cubit/credentials_cubit.dart +++ b/lib/credentials/cubit/credentials_cubit.dart @@ -901,44 +901,18 @@ class CredentialsCubit extends Cubit { .toList(); if (credentialsOfSameType.isNotEmpty && subjectType.supportSingleOnly) { - final availableWalletAddresses = []; - - if (isBlockchainAccount && supportAssociatedCredential) { - /// getting list of available wallet address of current - /// blockchain account - for (final credential in credentialsOfSameType) { - final String? walletAddress = getWalletAddress( - credential.credentialPreview.credentialSubjectModel, - ); - - if (walletAddress != null) { - availableWalletAddresses.add(walletAddress); - } - } - } - /// credential available case for (final credential in credentialsOfSameType) { if (isBlockchainAccount && supportAssociatedCredential) { /// there can be multiple blockchain profiles /// /// each profiles should be allowed to add the respective cards - /// - /// so we have to check the current profile wallet address and - /// compare with existing blockchain card to add in discover or - /// not - - final String? currentWalletAddress = - walletCubit.state.currentAccount?.walletAddress; - - /// if current blockchain card is not available in list of - /// credentails then add in the discover list - /// else do not add if it is blockchain - final isBlockChainCardAvailable = availableWalletAddresses - .contains(currentWalletAddress.toString()); + /// We always have the associated Adress credential + /// in the discover since "Do not remove the GET a crypto account + /// in the Discover #2649" - if (!isBlockChainCardAvailable && isCurrentBlockchainAccount) { + if (isCurrentBlockchainAccount) { /// if already added do not add if (!requiredDummySubjects.contains(subjectType)) { requiredDummySubjects.add(subjectType); From 0929dfdf9a412f25b864ed2dbd557a1aa231c363 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 10 May 2024 07:52:23 +0000 Subject: [PATCH 09/56] Denim, if you try to get the ASCS credential with an account which has not a crypto VC it fails because wallet forces user to create a new account #2648 --- .../view/missing_credentials_page.dart | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lib/dashboard/missing_creentials/view/missing_credentials_page.dart b/lib/dashboard/missing_creentials/view/missing_credentials_page.dart index bbe47121a..6c1d919c9 100644 --- a/lib/dashboard/missing_creentials/view/missing_credentials_page.dart +++ b/lib/dashboard/missing_creentials/view/missing_credentials_page.dart @@ -118,25 +118,20 @@ class MissingCredentialsView extends StatelessWidget { MyGradientButton( onPressed: () async { for (final credentials in state.dummyCredentials) { - if (credentials.credentialSubjectType.isBlockchainAccount) { - await Navigator.of(context) - .push(ChooseAddAccountMethodPage.route()); - } else { - await Navigator.push( - context, - DiscoverDetailsPage.route( - dummyCredential: credentials, - buttonText: l10n.getThisCard, - onCallBack: () async { - await discoverCredential( - dummyCredential: credentials, - context: context, - ); - Navigator.pop(context); - }, - ), - ); - } + await Navigator.push( + context, + DiscoverDetailsPage.route( + dummyCredential: credentials, + buttonText: l10n.getThisCard, + onCallBack: () async { + await discoverCredential( + dummyCredential: credentials, + context: context, + ); + Navigator.pop(context); + }, + ), + ); } Navigator.pop(context); }, From 593f060c0f6ed9bd187695aa69d783d17d9a8250 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 10 May 2024 21:06:18 +0545 Subject: [PATCH 10/56] Interop event verifier (#2653) * Fix: Consider subjectAltName instead of subject and also EC is considered * feat: Update to Interop event verifier fails #2651 --- .../helper_functions/helper_functions.dart | 44 ++++++++---- lib/credentials/cubit/credentials_cubit.dart | 2 +- .../cubit/credentials_helper_function.dart | 2 +- .../widget/vc_format_widget.dart | 2 +- lib/dashboard/home/home/cubit/home_cubit.dart | 2 +- .../home_credential_category_list.dart | 2 +- .../filter_credential_list_by_format.dart | 8 +-- .../get_credentials_from_filter_list.dart | 2 + .../cubit/qr_code_scan_cubit.dart | 34 ++++----- lib/oidc4vc/add_oidc4vc_credential.dart | 12 ++-- lib/scan/cubit/scan_cubit.dart | 72 ++++++++----------- .../selective_disclosure.dart | 2 +- .../lib/src/models/filter.dart | 3 + packages/oidc4vc/lib/src/vc_format_type.dart | 28 ++++---- 14 files changed, 112 insertions(+), 103 deletions(-) diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index 057047a56..e38e23b46 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -23,6 +23,7 @@ import 'package:oidc4vc/oidc4vc.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:secure_storage/secure_storage.dart'; import 'package:x509/x509.dart' as x509; +import 'package:x509/x509.dart'; String generateDefaultAccountName( int accountIndex, @@ -199,7 +200,7 @@ Future isCredentialAvaialble({ credential .credentialPreview.credentialSubjectModel.credentialSubjectType; - final matchFormat = vcFormatType.value == credential.format; + final matchFormat = vcFormatType.vcValue == credential.format; if (matchSubjectType && matchFormat) { return true; } @@ -971,7 +972,12 @@ Future?> getClientMetada({ return null; } } catch (e) { - return null; + throw ResponseMessage( + data: { + 'error': 'invalid_request', + 'error_description': 'Client metaData is invalid', + }, + ); } } @@ -1840,10 +1846,10 @@ List getStringCredentialsForToken({ } /// create list of supported formats - if (presentLdpVc) supportingFormats.add(VCFormatType.ldpVc.value); - if (presentJwtVc) supportingFormats.add(VCFormatType.jwtVc.value); - if (presentJwtVcJson) supportingFormats.add(VCFormatType.jwtVcJson.value); - if (presentVcSdJwt) supportingFormats.add(VCFormatType.jwtVcJson.value); + if (presentLdpVc) supportingFormats.add(VCFormatType.ldpVc.vcValue); + if (presentJwtVc) supportingFormats.add(VCFormatType.jwtVc.vcValue); + if (presentJwtVcJson) supportingFormats.add(VCFormatType.jwtVcJson.vcValue); + if (presentVcSdJwt) supportingFormats.add(VCFormatType.jwtVcJson.vcValue); /// make sure only one of all are true if (presentLdpVc && vcFormatType == VCFormatType.ldpVc) { @@ -2013,9 +2019,9 @@ Future?> checkX509({ final seq = asn1lib.ASN1Sequence.fromBytes(decoded); final cert = x509.X509Certificate.fromAsn1(seq); - final subject = cert.tbsCertificate.subject; + final extensions = cert.tbsCertificate.extensions; - if (subject == null) { + if (extensions == null) { throw ResponseMessage( data: { 'error': 'invalid_format', @@ -2024,9 +2030,11 @@ Future?> checkX509({ ); } - final names = subject.names; + final extension = extensions + .where((Extension element) => element.extnId.name == 'subjectAltName') + .firstOrNull; - if (names.isEmpty) { + if (extension == null) { throw ResponseMessage( data: { 'error': 'invalid_format', @@ -2035,9 +2043,9 @@ Future?> checkX509({ ); } - final value = names[0].entries.map((element) => element.value).toList(); + final extnValue = extension.extnValue.toString(); - if (!value.contains(clientId)) { + if (!extnValue.contains(clientId)) { throw ResponseMessage( data: { 'error': 'invalid_format', @@ -2056,6 +2064,18 @@ Future?> checkX509({ 'n': n.replaceAll('=', ''), }; return publicKeyJwk; + } else if (publicKey is x509.EcPublicKey) { + final BigInt xModulus = BigInt.parse(publicKey.xCoordinate.toString()); + final BigInt yModulus = BigInt.parse(publicKey.yCoordinate.toString()); + final x = base64Encode(xModulus.toBytes); + final y = base64Encode(yModulus.toBytes); + final publicKeyJwk = { + 'kty': 'EC', + 'crv': 'P-256', + 'x': x.replaceAll('=', ''), + 'y': y.replaceAll('=', ''), + }; + return publicKeyJwk; } } return null; diff --git a/lib/credentials/cubit/credentials_cubit.dart b/lib/credentials/cubit/credentials_cubit.dart index 2e578bc75..1176414a9 100644 --- a/lib/credentials/cubit/credentials_cubit.dart +++ b/lib/credentials/cubit/credentials_cubit.dart @@ -921,7 +921,7 @@ class CredentialsCubit extends Cubit { //get current wallet address } else { - if (vcFormatType.value == credential.getFormat) { + if (vcFormatType.vcValue == credential.getFormat) { /// do not add if format matched /// there can be same credentials with different format } else { diff --git a/lib/credentials/cubit/credentials_helper_function.dart b/lib/credentials/cubit/credentials_helper_function.dart index 0a5594f65..8a8c936b4 100644 --- a/lib/credentials/cubit/credentials_helper_function.dart +++ b/lib/credentials/cubit/credentials_helper_function.dart @@ -268,7 +268,7 @@ Future _createCredential({ data: jsonLd, shareLink: '', jwt: jwt, - format: customOidc4vcProfile.vcFormatType.value, + format: customOidc4vcProfile.vcFormatType.vcValue, credentialPreview: Credential.fromJson(jsonLd), credentialManifest: credentialManifest, activities: [Activity(acquisitionAt: dateTime)], diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart index c974b7340..ee02be9be 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart @@ -47,7 +47,7 @@ class VCFormatWidget extends StatelessWidget { ), ), title: Text( - vcFormatType.formattedString, + vcFormatType.vcValue, style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: Theme.of(context).colorScheme.onPrimary, ), diff --git a/lib/dashboard/home/home/cubit/home_cubit.dart b/lib/dashboard/home/home/cubit/home_cubit.dart index 91ca98701..0f4f8a470 100644 --- a/lib/dashboard/home/home/cubit/home_cubit.dart +++ b/lib/dashboard/home/home/cubit/home_cubit.dart @@ -187,7 +187,7 @@ class HomeCubit extends Cubit { final Map newCredential = Map.from(credential); newCredential['credentialPreview'] = credential; - newCredential['format'] = vcFormatType.value; + newCredential['format'] = vcFormatType.vcValue; final CredentialManifest credentialManifest = await getCredentialManifestFromAltMe( oidc4vc: oidc4vc, diff --git a/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_list.dart b/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_list.dart index 0b9a9dbff..b16f00312 100644 --- a/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_list.dart +++ b/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_list.dart @@ -76,7 +76,7 @@ class HomeCredentialCategoryList extends StatelessWidget { } /// do not load the credential if vc format is different - if (customOidc4vcProfile.vcFormatType.value != + if (customOidc4vcProfile.vcFormatType.vcValue != element.getFormat) { return false; } diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/filter_credential_list_by_format.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/filter_credential_list_by_format.dart index 0183f8046..16eb3abaa 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/filter_credential_list_by_format.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/filter_credential_list_by_format.dart @@ -31,22 +31,22 @@ List filterCredenialListByFormat({ (CredentialModel credentialModel) { /// remove ldpVc if (presentLdpVc) { - return credentialModel.format != VCFormatType.ldpVc.value; + return credentialModel.format != VCFormatType.ldpVc.vcValue; } /// remove jwtVc if (presentJwtVc) { - return credentialModel.format != VCFormatType.jwtVc.value; + return credentialModel.format != VCFormatType.jwtVc.vcValue; } /// remove JwtVcJson if (presentJwtVcJson) { - return credentialModel.format != VCFormatType.jwtVcJson.value; + return credentialModel.format != VCFormatType.jwtVcJson.vcValue; } /// remove vcSdJwt if (presentVcSdJwt) { - return credentialModel.format != VCFormatType.vcSdJWT.value; + return credentialModel.format != VCFormatType.vcSdJWT.vcValue; } return false; diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_filter_list.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_filter_list.dart index 6ac7ad1db..e06a2ca07 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_filter_list.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_filter_list.dart @@ -32,6 +32,8 @@ List getCredentialsFromFilterList({ pattern = field.filter!.pattern; } else if (field.filter?.contains?.containsConst != null) { pattern = field.filter?.contains?.containsConst; + } else if (field.filter?.containsConst != null) { + pattern = field.filter?.containsConst; } else { /// sd-jwt vc bool case if (searchParameter == 'true') return false; diff --git a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart index c69bce946..ee2a864c7 100644 --- a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart +++ b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart @@ -935,22 +935,16 @@ class QRCodeScanCubit extends Cubit { client: client, uri: state.uri!, ); - if (clientMetaData == null) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'Client metaData is invalid', - }, - ); - } - if (!clientMetaData.containsKey('vp_formats')) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'Format is missing.', - }, - ); + if (clientMetaData != null) { + if (!clientMetaData.containsKey('vp_formats')) { + throw ResponseMessage( + data: { + 'error': 'invalid_request', + 'error_description': 'Format is missing.', + }, + ); + } } } @@ -998,8 +992,14 @@ class QRCodeScanCubit extends Cubit { shareLink: 'shareLink', data: const {}, jwt: null, - format: profileCubit.state.model.profileSetting - .selfSovereignIdentityOptions.customOidc4vcProfile.vcFormatType.value, + format: profileCubit + .state + .model + .profileSetting + .selfSovereignIdentityOptions + .customOidc4vcProfile + .vcFormatType + .vcValue, credentialManifest: credentialManifest, ); diff --git a/lib/oidc4vc/add_oidc4vc_credential.dart b/lib/oidc4vc/add_oidc4vc_credential.dart index 9f771e97b..78ffad433 100644 --- a/lib/oidc4vc/add_oidc4vc_credential.dart +++ b/lib/oidc4vc/add_oidc4vc_credential.dart @@ -23,15 +23,15 @@ Future addOIDC4VCCredential({ }) async { late Map credentialFromOIDC4VC; - if (format == VCFormatType.jwtVc.value || - format == VCFormatType.jwtVcJson.value || - format == VCFormatType.vcSdJWT.value) { + if (format == VCFormatType.jwtVc.vcValue || + format == VCFormatType.jwtVcJson.vcValue || + format == VCFormatType.vcSdJWT.vcValue) { //jwt_vc final data = encodedCredentialFromOIDC4VC['credential'] as String; final jsonContent = jwtDecode.parseJwt(data); - if (format == VCFormatType.vcSdJWT.value) { + if (format == VCFormatType.vcSdJWT.vcValue) { final sdAlg = jsonContent['_sd_alg']; if (sdAlg == null || sdAlg != 'sha-256') { @@ -48,7 +48,7 @@ Future addOIDC4VCCredential({ credentialFromOIDC4VC = jsonContent['vc'] as Map; } - if (format == VCFormatType.vcSdJWT.value) { + if (format == VCFormatType.vcSdJWT.vcValue) { /// type if (!credentialFromOIDC4VC.containsKey('type')) { credentialFromOIDC4VC['type'] = [credentialType]; @@ -115,7 +115,7 @@ Future addOIDC4VCCredential({ // } credentialFromOIDC4VC['jwt'] = data; - } else if (format == VCFormatType.ldpVc.value) { + } else if (format == VCFormatType.ldpVc.vcValue) { //ldp_vc final data = encodedCredentialFromOIDC4VC['credential']; diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index 281259fdc..4a93e0f7e 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -182,8 +182,9 @@ class ScanCubit extends Cubit { } else { for (final item in credentialsToBePresented) { final presentationId = 'urn:uuid:${const Uuid().v4()}'; - /// proof is done with a creation date 20 seconds in the past to avoid - /// proof check to fail because of time difference on server + + /// proof is done with a creation date 20 seconds in the past to avoid + /// proof check to fail because of time difference on server final options = jsonEncode({ 'verificationMethod': kid, @@ -355,7 +356,7 @@ class ScanCubit extends Cubit { final presentationId = 'urn:uuid:${const Uuid().v4()}'; /// proof is done with a creation date 20 seconds in the past to avoid - /// proof check to fail because of time difference on server + /// proof check to fail because of time difference on server final options = jsonEncode({ 'verificationMethod': kid, 'proofPurpose': 'assertionMethod', @@ -760,49 +761,33 @@ class ScanCubit extends Cubit { } } else { if (clientMetaData == null) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'Client metaData is invalid', - }, - ); - } - - final vpFormats = clientMetaData['vp_formats'] as Map; - - if (vpFormats.containsKey('ldp_vc')) { - vcFormat = 'ldp_vc'; - } else if (vpFormats.containsKey('jwt_vc')) { - vcFormat = 'jwt_vc'; - } else if (vpFormats.containsKey('jwt_vc_json')) { - vcFormat = 'jwt_vc_json'; - } + final vcFormatType = profileSetting + .selfSovereignIdentityOptions.customOidc4vcProfile.vcFormatType; + vcFormat = vcFormatType.vcValue; + vpFormat = vcFormatType.vpValue; + } else { + final vpFormats = clientMetaData['vp_formats'] as Map; + + if (vpFormats.containsKey('ldp_vc')) { + vcFormat = 'ldp_vc'; + } else if (vpFormats.containsKey('jwt_vc')) { + vcFormat = 'jwt_vc'; + } else if (vpFormats.containsKey('jwt_vc_json')) { + vcFormat = 'jwt_vc_json'; + } - if (vpFormats.containsKey('ldp_vp')) { - vpFormat = 'ldp_vp'; - } else if (vpFormats.containsKey('jwt_vp')) { - vpFormat = 'jwt_vp'; - } else if (vpFormats.containsKey('jwt_vp_json')) { - vpFormat = 'jwt_vp_json'; - } else if (vpFormats.containsKey('vc+sd-jwt')) { - vpFormat = 'vc+sd-jwt'; + if (vpFormats.containsKey('ldp_vp')) { + vpFormat = 'ldp_vp'; + } else if (vpFormats.containsKey('jwt_vp')) { + vpFormat = 'jwt_vp'; + } else if (vpFormats.containsKey('jwt_vp_json')) { + vpFormat = 'jwt_vp_json'; + } else if (vpFormats.containsKey('vc+sd-jwt')) { + vpFormat = 'vc+sd-jwt'; + } } } - final vcFormatType = profileSetting - .selfSovereignIdentityOptions.customOidc4vcProfile.vcFormatType; - - vcFormat ??= vcFormatType.value; - - if (vpFormat == null) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'VC format is missing.', - }, - ); - } - for (int i = 0; i < credentialsToBePresented.length; i++) { for (final InputDescriptor inputDescriptor in presentationDefinition.inputDescriptors) { @@ -905,9 +890,8 @@ class ScanCubit extends Cubit { ); if (presentLdpVc) { - /// proof is done with a creation date 20 seconds in the past to avoid - /// proof check to fail because of time difference on server + /// proof check to fail because of time difference on server final options = jsonEncode({ 'verificationMethod': kid, 'proofPurpose': 'assertionMethod', diff --git a/lib/selective_disclosure/selective_disclosure.dart b/lib/selective_disclosure/selective_disclosure.dart index 456c8152e..bd65c31eb 100644 --- a/lib/selective_disclosure/selective_disclosure.dart +++ b/lib/selective_disclosure/selective_disclosure.dart @@ -154,7 +154,7 @@ class SelectiveDisclosure { } String? get getPicture { - if (credentialModel.format.toString() != VCFormatType.vcSdJWT.value) { + if (credentialModel.format.toString() != VCFormatType.vcSdJWT.vcValue) { return null; } diff --git a/packages/credential_manifest/lib/src/models/filter.dart b/packages/credential_manifest/lib/src/models/filter.dart index 2ab8fbae9..37bbf7b01 100644 --- a/packages/credential_manifest/lib/src/models/filter.dart +++ b/packages/credential_manifest/lib/src/models/filter.dart @@ -9,12 +9,15 @@ class Filter { required this.type, this.pattern, this.contains, + this.containsConst, }); factory Filter.fromJson(Map json) => _$FilterFromJson(json); final String type; final String? pattern; final Contains? contains; + @JsonKey(name: 'const') + String? containsConst; Map toJson() => _$FilterToJson(this); } diff --git a/packages/oidc4vc/lib/src/vc_format_type.dart b/packages/oidc4vc/lib/src/vc_format_type.dart index 34c83d918..93540f3eb 100644 --- a/packages/oidc4vc/lib/src/vc_format_type.dart +++ b/packages/oidc4vc/lib/src/vc_format_type.dart @@ -14,7 +14,7 @@ enum VCFormatType { } extension VCFormatTypeX on VCFormatType { - String get formattedString { + String get vcValue { switch (this) { case VCFormatType.ldpVc: return 'ldp_vc'; @@ -29,7 +29,7 @@ extension VCFormatTypeX on VCFormatType { } } - String get value { + String get urlValue { switch (this) { case VCFormatType.ldpVc: return 'ldp_vc'; @@ -40,34 +40,34 @@ extension VCFormatTypeX on VCFormatType { case VCFormatType.jwtVcJsonLd: return 'jwt_vc_json-ld'; case VCFormatType.vcSdJWT: - return 'vc+sd-jwt'; + return 'vcsd-jwt'; } } - String get urlValue { + bool get supportCryptoCredential { switch (this) { case VCFormatType.ldpVc: - return 'ldp_vc'; - case VCFormatType.jwtVc: - return 'jwt_vc'; case VCFormatType.jwtVcJson: - return 'jwt_vc_json'; + return true; + case VCFormatType.jwtVc: case VCFormatType.jwtVcJsonLd: - return 'jwt_vc_json-ld'; case VCFormatType.vcSdJWT: - return 'vcsd-jwt'; + return false; } } - bool get supportCryptoCredential { + String get vpValue { switch (this) { case VCFormatType.ldpVc: - case VCFormatType.jwtVcJson: - return true; + return 'ldp_vp'; case VCFormatType.jwtVc: + return 'jwt_vp'; + case VCFormatType.jwtVcJson: + return 'jwt_vp_json'; case VCFormatType.jwtVcJsonLd: + return 'jwt_vp_json-ld'; case VCFormatType.vcSdJWT: - return false; + return 'vc+sd-jwt'; } } } From b65cf32ecc81e656b0747bf7d621f979b54142ce Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 10 May 2024 15:22:36 +0000 Subject: [PATCH 11/56] version: 2.5.3+452 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 2f34cdf42..da19856fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.5.1+450 +version: 2.5.3+452 environment: sdk: ">=3.1.0 <4.0.0" From 4938bc49c51f55e505ba7bdf06dc95609d20d569 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 13 May 2024 07:27:17 +0000 Subject: [PATCH 12/56] Revert "remove model_viewer_plus for android" This reverts commit db0e62997d81fdb26e31c8d6d8c0960a0717b0c2. --- .../tab_bar/nft/view/nft_details_page.dart | 24 ++--- pubspec.lock | 92 +++++++++++-------- pubspec.yaml | 1 + 3 files changed, 67 insertions(+), 50 deletions(-) diff --git a/lib/dashboard/home/tab_bar/nft/view/nft_details_page.dart b/lib/dashboard/home/tab_bar/nft/view/nft_details_page.dart index ce79fd020..785117eea 100644 --- a/lib/dashboard/home/tab_bar/nft/view/nft_details_page.dart +++ b/lib/dashboard/home/tab_bar/nft/view/nft_details_page.dart @@ -6,7 +6,7 @@ import 'package:altme/wallet/cubit/wallet_cubit.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_html/flutter_html.dart'; -// import 'package:model_viewer_plus/model_viewer_plus.dart'; +import 'package:model_viewer_plus/model_viewer_plus.dart'; class NftDetailsPage extends StatelessWidget { const NftDetailsPage({ @@ -363,17 +363,17 @@ class NftPicture extends StatelessWidget { @override Widget build(BuildContext context) { - // if (AltMeStrings.contractDontSendAddress - // .contains(widget.nftModel.contractAddress)) { - // return ModelViewer( - // src: widget.nftModel.artifactUrl!, - // poster: widget.nftModel.thumbnailUrl, - // alt: '', - // ar: false, - // autoRotate: false, - // disableZoom: true, - // ); - // } + if (AltMeStrings.contractDontSendAddress + .contains(widget.nftModel.contractAddress)) { + return ModelViewer( + src: widget.nftModel.artifactUrl!, + poster: widget.nftModel.thumbnailUrl, + alt: '', + ar: false, + autoRotate: false, + disableZoom: true, + ); + } return CachedImageFromNetwork( widget.nftModel.displayUrl ?? (widget.nftModel.thumbnailUrl ?? ''), fit: BoxFit.contain, diff --git a/pubspec.lock b/pubspec.lock index da6c1f712..7a3ee6e66 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.4.1" + android_intent_plus: + dependency: transitive + description: + name: android_intent_plus + sha256: "2bfdbee8d65e7c26f88b66f0a91f2863da4d3596d8a658b4162c8de5cf04b074" + url: "https://pub.dev" + source: hosted + version: "5.0.2" ansicolor: dependency: transitive description: @@ -53,10 +61,10 @@ packages: dependency: "direct main" description: name: asn1lib - sha256: c9c85fedbe2188b95133cbe960e16f5f448860f7133330e272edbbca5893ddc6 + sha256: "58082b3f0dca697204dbab0ef9ff208bfaea7767ea771076af9a343488428dda" url: "https://pub.dev" source: hosted - version: "1.5.2" + version: "1.5.3" async: dependency: "direct main" description: @@ -286,10 +294,10 @@ packages: dependency: "direct main" description: name: camera - sha256: "9499cbc2e51d8eb0beadc158b288380037618ce4e30c9acbc4fae1ac3ecb5797" + sha256: dfa8fc5a1adaeb95e7a54d86a5bd56f4bb0e035515354c8ac6d262e35cec2ec8 url: "https://pub.dev" source: hosted - version: "0.10.5+9" + version: "0.10.6" camera_android: dependency: transitive description: @@ -414,10 +422,10 @@ packages: dependency: transitive description: name: coverage - sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + sha256: "3945034e86ea203af7a056d98e98e42a5518fff200d6e8e6647e1886b07e936e" url: "https://pub.dev" source: hosted - version: "1.7.2" + version: "1.8.0" credential_manifest: dependency: "direct main" description: @@ -803,10 +811,10 @@ packages: dependency: transitive description: name: file_selector_macos - sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 + sha256: f42eacb83b318e183b1ae24eead1373ab1334084404c8c16e0354f9a3e55d385 url: "https://pub.dev" source: hosted - version: "0.9.3+3" + version: "0.9.4" file_selector_platform_interface: dependency: transitive description: @@ -1037,50 +1045,50 @@ packages: dependency: transitive description: name: flutter_secure_storage - sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685 + sha256: c0f402067fb0498934faa6bddd670de0a3db45222e2ca9a068c6177c9a2360a4 url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "9.1.1" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - sha256: "3d5032e314774ee0e1a7d0a9f5e2793486f0dff2dd9ef5a23f4e3fb2a0ae6a9e" + sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" flutter_secure_storage_macos: dependency: transitive description: name: flutter_secure_storage_macos - sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c + sha256: "8cfa53010a294ff095d7be8fa5bb15f2252c50018d69c5104851303f3ff92510" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.1.0" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e" + sha256: "301f67ee9b87f04aef227f57f13f126fa7b13543c8e7a93f25c5d2d534c28a4a" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.1" flutter_secure_storage_web: dependency: transitive description: name: flutter_secure_storage_web - sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20" + sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.1" flutter_secure_storage_windows: dependency: transitive description: name: flutter_secure_storage_windows - sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108" + sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.2" flutter_sodium: dependency: transitive description: @@ -1263,10 +1271,10 @@ packages: dependency: transitive description: name: image_picker_android - sha256: "40e24f467b75cd6f4a92ee93dd13d1a7bcb4523a84fd95f00c755f01f42398c8" + sha256: "79455f6cff4cbef583b2b524bbf0d4ec424e5959f4d464e36ef5323715b98370" url: "https://pub.dev" source: hosted - version: "0.8.11" + version: "0.8.12" image_picker_for_web: dependency: transitive description: @@ -1279,10 +1287,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: f74064bc548b5164a033ec05638e23c91be1a249c255e0f56319dddffd759794 + sha256: cb0db0ec0d3e2cd49674f2e6053be25ccdb959832607c1cbd215dd6cf10fb0dd url: "https://pub.dev" source: hosted - version: "0.8.10+1" + version: "0.8.11" image_picker_linux: dependency: transitive description: @@ -1461,10 +1469,10 @@ packages: dependency: transitive description: name: local_auth_darwin - sha256: "33381a15b0de2279523eca694089393bb146baebdce72a404555d03174ebc1e9" + sha256: "959145a4cf6f0de745b9ec9ac60101270eb4c5b8b7c2a0470907014adc1c618d" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.3.0" local_auth_platform_interface: dependency: transitive description: @@ -1485,10 +1493,10 @@ packages: dependency: transitive description: name: logger - sha256: "8c94b8c219e7e50194efc8771cd0e9f10807d8d3e219af473d89b06cc2ee4e04" + sha256: af05cc8714f356fd1f3888fb6741cbe9fbe25cdb6eedbab80e1a6db21047d4a4 url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" logging: dependency: transitive description: @@ -1593,6 +1601,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" + model_viewer_plus: + dependency: "direct main" + description: + name: model_viewer_plus + sha256: "633efbd081efe9af8b149c5553fa1e3e83a298ccc151955b0fe9d56a666943be" + url: "https://pub.dev" + source: hosted + version: "1.7.2" nested: dependency: transitive description: @@ -1732,10 +1748,10 @@ packages: dependency: transitive description: name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -2131,10 +2147,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.4.0" shared_preferences_linux: dependency: transitive description: @@ -2280,10 +2296,10 @@ packages: dependency: transitive description: name: sqlite3 - sha256: "1abbeb84bf2b1a10e5e1138c913123c8aa9d83cd64e5f9a0dd847b3c83063202" + sha256: b384f598b813b347c5a7e5ffad82cbaff1bec3d1561af267041e66f6f0899295 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" stack_trace: dependency: transitive description: @@ -2457,10 +2473,10 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5" + sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89" url: "https://pub.dev" source: hosted - version: "6.2.5" + version: "6.3.0" url_launcher_linux: dependency: transitive description: @@ -2473,10 +2489,10 @@ packages: dependency: transitive description: name: url_launcher_macos - sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 + sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.0" url_launcher_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index da19856fc..8dbbc07ba 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -80,6 +80,7 @@ dependencies: matrix: ^0.25.5 mime: ^1.0.4 mobile_scanner: ^3.2.0 + model_viewer_plus: ^1.7.0 network_image_mock: ^2.1.1 no_screenshot: ^0.0.1+6 oidc4vc: From 11b99e6af55888f7a85818b5bd7e2463172c16b2 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 17 May 2024 12:10:12 +0000 Subject: [PATCH 13/56] Emailpass dissapear after we close the wallet and reopen #2657 --- packages/oidc4vc/lib/src/oidc4vc.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 33679a15f..ca6aad871 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -1741,11 +1741,13 @@ class OIDC4VC { return response; } } - final expiry = - DateTime.now().add(const Duration(days: 2)).millisecondsSinceEpoch; + // temporary deactiviting this caching du to issue with + // flutter_secure_storage on ios #2657 + // final expiry = + // DateTime.now().add(const Duration(days: 2)).millisecondsSinceEpoch; - final value = {'expiry': expiry, 'data': response.data}; - await secureStorageProvider.set(uri, jsonEncode(value)); + // final value = {'expiry': expiry, 'data': response.data}; + // await secureStorageProvider.set(uri, jsonEncode(value)); return response.data; } on FormatException catch (_) { From ead6760650b8c155965d92e3a16f23efd19794b3 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 17 May 2024 14:45:37 +0200 Subject: [PATCH 14/56] Revert "Emailpass dissapear after we close the wallet and reopen" This reverts commit 11b99e6af55888f7a85818b5bd7e2463172c16b2. --- packages/oidc4vc/lib/src/oidc4vc.dart | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index ca6aad871..33679a15f 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -1741,13 +1741,11 @@ class OIDC4VC { return response; } } - // temporary deactiviting this caching du to issue with - // flutter_secure_storage on ios #2657 - // final expiry = - // DateTime.now().add(const Duration(days: 2)).millisecondsSinceEpoch; + final expiry = + DateTime.now().add(const Duration(days: 2)).millisecondsSinceEpoch; - // final value = {'expiry': expiry, 'data': response.data}; - // await secureStorageProvider.set(uri, jsonEncode(value)); + final value = {'expiry': expiry, 'data': response.data}; + await secureStorageProvider.set(uri, jsonEncode(value)); return response.data; } on FormatException catch (_) { From 193d3d2d76a484dec95a539228aa81f6c3e9dcb7 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 17 May 2024 14:51:02 +0200 Subject: [PATCH 15/56] version: 2.5.4+453 --- packages/secure_storage/pubspec.yaml | 2 +- pubspec.lock | 140 +++++++++++---------------- pubspec.yaml | 2 +- 3 files changed, 60 insertions(+), 84 deletions(-) diff --git a/packages/secure_storage/pubspec.yaml b/packages/secure_storage/pubspec.yaml index 2ed66ba43..776ba96ae 100644 --- a/packages/secure_storage/pubspec.yaml +++ b/packages/secure_storage/pubspec.yaml @@ -9,7 +9,7 @@ environment: dependencies: flutter: sdk: flutter - flutter_secure_storage: ^9.0.0 + flutter_secure_storage: ^9.2.1 dev_dependencies: flutter_test: diff --git a/pubspec.lock b/pubspec.lock index 7a3ee6e66..ae6c09f35 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 url: "https://pub.dev" source: hosted - version: "67.0.0" + version: "64.0.0" adaptive_number: dependency: transitive description: @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "6.2.0" android_intent_plus: dependency: transitive description: @@ -437,10 +437,10 @@ packages: dependency: transitive description: name: cross_file - sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e url: "https://pub.dev" source: hosted - version: "0.3.4+1" + version: "0.3.3+8" crypto: dependency: "direct main" description: @@ -997,10 +997,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "04c4722cc36ec5af38acc38ece70d22d3c2123c61305d555750a091517bbe504" + sha256: "5b24061317f850af858ef7151dadbb6eb77c1c449c954c7bb064e8a5e0e7d81f" url: "https://pub.dev" source: hosted - version: "0.6.23" + version: "0.6.20" flutter_native_timezone: dependency: "direct main" description: @@ -1045,10 +1045,10 @@ packages: dependency: transitive description: name: flutter_secure_storage - sha256: c0f402067fb0498934faa6bddd670de0a3db45222e2ca9a068c6177c9a2360a4 + sha256: "8496a89eea74e23f92581885f876455d9d460e71201405dffe5f55dfe1155864" url: "https://pub.dev" source: hosted - version: "9.1.1" + version: "9.2.1" flutter_secure_storage_linux: dependency: transitive description: @@ -1061,18 +1061,18 @@ packages: dependency: transitive description: name: flutter_secure_storage_macos - sha256: "8cfa53010a294ff095d7be8fa5bb15f2252c50018d69c5104851303f3ff92510" + sha256: b768a7dab26d6186b68e2831b3104f8968154f0f4fdbf66e7c2dd7bdf299daaf url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - sha256: "301f67ee9b87f04aef227f57f13f126fa7b13543c8e7a93f25c5d2d534c28a4a" + sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" flutter_secure_storage_web: dependency: transitive description: @@ -1135,10 +1135,10 @@ packages: dependency: transitive description: name: get_it - sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1 + sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 url: "https://pub.dev" source: hosted - version: "7.7.0" + version: "7.6.7" glob: dependency: transitive description: @@ -1223,10 +1223,10 @@ packages: dependency: "direct overridden" description: name: http - sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.0" http_mock_adapter: dependency: "direct dev" description: @@ -1263,34 +1263,34 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "33974eca2e87e8b4e3727f1b94fa3abcb25afe80b6bc2c4d449a0e150aedf720" + sha256: "1f498d086203360cca099d20ffea2963f48c39ce91bdd8a3b6d4a045786b02c8" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.0.8" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "79455f6cff4cbef583b2b524bbf0d4ec424e5959f4d464e36ef5323715b98370" + sha256: "844c6da4e4f2829dffdab97816bca09d0e0977e8dcef7450864aba4e07967a58" url: "https://pub.dev" source: hosted - version: "0.8.12" + version: "0.8.9+6" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3" + sha256: e2423c53a68b579a7c37a1eda967b8ae536c3d98518e5db95ca1fe5719a730a3 url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.2" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: cb0db0ec0d3e2cd49674f2e6053be25ccdb959832607c1cbd215dd6cf10fb0dd + sha256: "917a5cadd67d052554cfb258595e54217de53fac5b52939426e26319a02e6297" url: "https://pub.dev" source: hosted - version: "0.8.11" + version: "0.8.9+2" image_picker_linux: dependency: transitive description: @@ -1311,10 +1311,10 @@ packages: dependency: transitive description: name: image_picker_platform_interface - sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" + sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.9.3" image_picker_windows: dependency: transitive description: @@ -1327,10 +1327,10 @@ packages: dependency: transitive description: name: injectable - sha256: "3d98967224a5fdd4094a61bf53ed9616c3fbcf3e090bf83e7cb7d436d0c20041" + sha256: "44b4aa254816b23bf0a3285ff27da3ff0b516a6f00e0bbbea7b194f14fbb75a7" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.3.5" intl: dependency: transitive description: @@ -1409,30 +1409,6 @@ packages: relative: true source: path version: "1.0.0+1" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" linkify: dependency: transitive description: @@ -1517,18 +1493,18 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" matrix: dependency: "direct main" description: @@ -1557,10 +1533,10 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.10.0" mime: dependency: "direct main" description: @@ -1708,10 +1684,10 @@ packages: dependency: "direct main" description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" path_drawing: dependency: transitive description: @@ -2171,10 +2147,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" + sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.2.2" shared_preferences_windows: dependency: transitive description: @@ -2280,26 +2256,26 @@ packages: dependency: transitive description: name: sqflite - sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d + sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 url: "https://pub.dev" source: hosted - version: "2.3.3+1" + version: "2.3.2" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" + sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" url: "https://pub.dev" source: hosted - version: "2.5.4" + version: "2.5.3" sqlite3: dependency: transitive description: name: sqlite3 - sha256: b384f598b813b347c5a7e5ffad82cbaff1bec3d1561af267041e66f6f0899295 + sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9" url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.0" stack_trace: dependency: transitive description: @@ -2505,10 +2481,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" + sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.2.3" url_launcher_windows: dependency: transitive description: @@ -2609,10 +2585,10 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.3.0" web3dart: dependency: transitive description: @@ -2625,10 +2601,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.0" webkit_inspection_protocol: dependency: transitive description: @@ -2681,18 +2657,18 @@ packages: dependency: transitive description: name: win32 - sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" + sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "5.2.0" win32_registry: dependency: transitive description: name: win32_registry - sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb" + sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.1.2" x25519: dependency: transitive description: @@ -2750,5 +2726,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.2.3 <4.0.0" + flutter: ">=3.16.6" diff --git a/pubspec.yaml b/pubspec.yaml index 8dbbc07ba..84eb0ec6a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.5.3+452 +version: 2.5.4+453 environment: sdk: ">=3.1.0 <4.0.0" From 2e800245ba2976d9ed1a611c2477db2461fc5190 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 30 Apr 2024 14:05:32 +0545 Subject: [PATCH 16/56] fix: Update private key use #2630 --- .../helper_functions/helper_functions.dart | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index e38e23b46..b4b4b43a9 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -273,6 +273,16 @@ Future getPrivateKey({ required ProfileCubit profileCubit, required DidKeyType didKeyType, }) async { + final customOidc4vcProfile = profileCubit.state.model.profileSetting + .selfSovereignIdentityOptions.customOidc4vcProfile; + + if (customOidc4vcProfile.clientType == ClientType.p256JWKThumprint) { + final privateKey = + await getP256KeyToGetAndPresentVC(profileCubit.secureStorageProvider); + + return privateKey; + } + final mnemonic = await profileCubit.secureStorageProvider .get(SecureStorageKeys.ssiMnemonic); @@ -1585,8 +1595,11 @@ Future<(String?, String?, String?, String?)> getClientDetails({ final didKeyType = customOidc4vcProfile.defaultDid; - final privateKey = - await getP256KeyToGetAndPresentVC(profileCubit.secureStorageProvider); + final String privateKey = await fetchPrivateKey( + profileCubit: profileCubit, + isEBSIV3: isEBSIV3, + didKeyType: didKeyType, + ); final (did, _) = await fetchDidAndKid( privateKey: privateKey, @@ -1600,7 +1613,7 @@ Future<(String?, String?, String?, String?)> getClientDetails({ did: '', // just added as it is required field mediaType: MediaType.basic, // just added as it is required field clientType: - ClientType.p256JWKThumprint, // just added as it is required field + customOidc4vcProfile.clientType, // just added as it is required field proofHeaderType: customOidc4vcProfile.proofHeader, clientId: '', // just added as it is required field ); From d391e72a67aede230bdcd3732b899966b1e439b6 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 30 Apr 2024 18:30:01 +0545 Subject: [PATCH 17/56] feat: Start package creation #2298 --- .../.github/ISSUE_TEMPLATE/bug_report.md | 29 +++++++++ .../.github/ISSUE_TEMPLATE/build.md | 14 +++++ .../.github/ISSUE_TEMPLATE/chore.md | 14 +++++ .../.github/ISSUE_TEMPLATE/ci.md | 14 +++++ .../.github/ISSUE_TEMPLATE/config.yml | 1 + .../.github/ISSUE_TEMPLATE/documentation.md | 14 +++++ .../.github/ISSUE_TEMPLATE/feature_request.md | 18 ++++++ .../.github/ISSUE_TEMPLATE/performance.md | 14 +++++ .../.github/ISSUE_TEMPLATE/refactor.md | 14 +++++ .../.github/ISSUE_TEMPLATE/revert.md | 16 +++++ .../.github/ISSUE_TEMPLATE/style.md | 14 +++++ .../.github/ISSUE_TEMPLATE/test.md | 14 +++++ .../.github/PULL_REQUEST_TEMPLATE.md | 27 ++++++++ .../secure_jwt_signer/.github/cspell.json | 21 +++++++ .../secure_jwt_signer/.github/dependabot.yaml | 11 ++++ .../.github/workflows/main.yaml | 27 ++++++++ packages/secure_jwt_signer/.gitignore | 7 +++ packages/secure_jwt_signer/README.md | 62 +++++++++++++++++++ .../secure_jwt_signer/analysis_options.yaml | 5 ++ packages/secure_jwt_signer/coverage_badge.svg | 20 ++++++ .../lib/secure_jwt_signer.dart | 4 ++ .../lib/src/secure_jwt_signer.dart | 38 ++++++++++++ packages/secure_jwt_signer/pubspec.yaml | 16 +++++ .../test/src/secure_jwt_signer_test.dart | 13 ++++ 24 files changed, 427 insertions(+) create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/build.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/chore.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/ci.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/config.yml create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/documentation.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/performance.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/refactor.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/revert.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/style.md create mode 100644 packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/test.md create mode 100644 packages/secure_jwt_signer/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 packages/secure_jwt_signer/.github/cspell.json create mode 100644 packages/secure_jwt_signer/.github/dependabot.yaml create mode 100644 packages/secure_jwt_signer/.github/workflows/main.yaml create mode 100644 packages/secure_jwt_signer/.gitignore create mode 100644 packages/secure_jwt_signer/README.md create mode 100644 packages/secure_jwt_signer/analysis_options.yaml create mode 100644 packages/secure_jwt_signer/coverage_badge.svg create mode 100644 packages/secure_jwt_signer/lib/secure_jwt_signer.dart create mode 100644 packages/secure_jwt_signer/lib/src/secure_jwt_signer.dart create mode 100644 packages/secure_jwt_signer/pubspec.yaml create mode 100644 packages/secure_jwt_signer/test/src/secure_jwt_signer_test.dart diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/bug_report.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..50a4c7b8b --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug Report +about: Create a report to help us improve +title: "fix: " +labels: bug +--- + +**Description** + +A clear and concise description of what the bug is. + +**Steps To Reproduce** + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected Behavior** + +A clear and concise description of what you expected to happen. + +**Screenshots** + +If applicable, add screenshots to help explain your problem. + +**Additional Context** + +Add any other context about the problem here. diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/build.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/build.md new file mode 100644 index 000000000..0cf8e62cd --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/build.md @@ -0,0 +1,14 @@ +--- +name: Build System +about: Changes that affect the build system or external dependencies +title: "build: " +labels: build +--- + +**Description** + +Describe what changes need to be done to the build system and why. + +**Requirements** + +- [ ] The build system is passing diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/chore.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/chore.md new file mode 100644 index 000000000..498ebfd82 --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/chore.md @@ -0,0 +1,14 @@ +--- +name: Chore +about: Other changes that don't modify src or test files +title: "chore: " +labels: chore +--- + +**Description** + +Clearly describe what change is needed and why. If this changes code then please use another issue type. + +**Requirements** + +- [ ] No functional changes to the code diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/ci.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/ci.md new file mode 100644 index 000000000..fa2dd9e2d --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/ci.md @@ -0,0 +1,14 @@ +--- +name: Continuous Integration +about: Changes to the CI configuration files and scripts +title: "ci: " +labels: ci +--- + +**Description** + +Describe what changes need to be done to the ci/cd system and why. + +**Requirements** + +- [ ] The ci system is passing diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/config.yml b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..ec4bb386b --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false \ No newline at end of file diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/documentation.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 000000000..f494a4d98 --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,14 @@ +--- +name: Documentation +about: Improve the documentation so all collaborators have a common understanding +title: "docs: " +labels: documentation +--- + +**Description** + +Clearly describe what documentation you are looking to add or improve. + +**Requirements** + +- [ ] Requirements go here diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/feature_request.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..ddd2fcca9 --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,18 @@ +--- +name: Feature Request +about: A new feature to be added to the project +title: "feat: " +labels: feature +--- + +**Description** + +Clearly describe what you are looking to add. The more context the better. + +**Requirements** + +- [ ] Checklist of requirements to be fulfilled + +**Additional Context** + +Add any other context or screenshots about the feature request go here. diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/performance.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/performance.md new file mode 100644 index 000000000..699b8d45f --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/performance.md @@ -0,0 +1,14 @@ +--- +name: Performance Update +about: A code change that improves performance +title: "perf: " +labels: performance +--- + +**Description** + +Clearly describe what code needs to be changed and what the performance impact is going to be. Bonus point's if you can tie this directly to user experience. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/refactor.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/refactor.md new file mode 100644 index 000000000..1626c5704 --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/refactor.md @@ -0,0 +1,14 @@ +--- +name: Refactor +about: A code change that neither fixes a bug nor adds a feature +title: "refactor: " +labels: refactor +--- + +**Description** + +Clearly describe what needs to be refactored and why. Please provide links to related issues (bugs or upcoming features) in order to help prioritize. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/revert.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/revert.md new file mode 100644 index 000000000..9d121dc56 --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/revert.md @@ -0,0 +1,16 @@ +--- +name: Revert Commit +about: Reverts a previous commit +title: "revert: " +labels: revert +--- + +**Description** + +Provide a link to a PR/Commit that you are looking to revert and why. + +**Requirements** + +- [ ] Change has been reverted +- [ ] No change in test coverage has happened +- [ ] A new ticket is created for any follow on work that needs to happen diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/style.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/style.md new file mode 100644 index 000000000..02244a7bd --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/style.md @@ -0,0 +1,14 @@ +--- +name: Style Changes +about: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc) +title: "style: " +labels: style +--- + +**Description** + +Clearly describe what you are looking to change and why. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/test.md b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/test.md new file mode 100644 index 000000000..431a7ea76 --- /dev/null +++ b/packages/secure_jwt_signer/.github/ISSUE_TEMPLATE/test.md @@ -0,0 +1,14 @@ +--- +name: Test +about: Adding missing tests or correcting existing tests +title: "test: " +labels: test +--- + +**Description** + +List out the tests that need to be added or changed. Please also include any information as to why this was not covered in the past. + +**Requirements** + +- [ ] There is no drop in test coverage. diff --git a/packages/secure_jwt_signer/.github/PULL_REQUEST_TEMPLATE.md b/packages/secure_jwt_signer/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..116993637 --- /dev/null +++ b/packages/secure_jwt_signer/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ + + +## Status + +**READY/IN DEVELOPMENT/HOLD** + +## Description + + + +## Type of Change + + + +- [ ] ✨ New feature (non-breaking change which adds functionality) +- [ ] 🛠️ Bug fix (non-breaking change which fixes an issue) +- [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change) +- [ ] 🧹 Code refactor +- [ ] ✅ Build configuration change +- [ ] 📝 Documentation +- [ ] 🗑️ Chore diff --git a/packages/secure_jwt_signer/.github/cspell.json b/packages/secure_jwt_signer/.github/cspell.json new file mode 100644 index 000000000..be80a6290 --- /dev/null +++ b/packages/secure_jwt_signer/.github/cspell.json @@ -0,0 +1,21 @@ +{ + "version": "0.2", + "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", + "dictionaries": ["vgv_allowed", "vgv_forbidden"], + "dictionaryDefinitions": [ + { + "name": "vgv_allowed", + "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/allowed.txt", + "description": "Allowed VGV Spellings" + }, + { + "name": "vgv_forbidden", + "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/forbidden.txt", + "description": "Forbidden VGV Spellings" + } + ], + "useGitignore": true, + "words": [ + "secure_jwt_signer" + ] +} diff --git a/packages/secure_jwt_signer/.github/dependabot.yaml b/packages/secure_jwt_signer/.github/dependabot.yaml new file mode 100644 index 000000000..63b035cde --- /dev/null +++ b/packages/secure_jwt_signer/.github/dependabot.yaml @@ -0,0 +1,11 @@ +version: 2 +enable-beta-ecosystems: true +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "pub" + directory: "/" + schedule: + interval: "daily" diff --git a/packages/secure_jwt_signer/.github/workflows/main.yaml b/packages/secure_jwt_signer/.github/workflows/main.yaml new file mode 100644 index 000000000..c7146c3cb --- /dev/null +++ b/packages/secure_jwt_signer/.github/workflows/main.yaml @@ -0,0 +1,27 @@ +name: ci + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + semantic_pull_request: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/semantic_pull_request.yml@v1 + + spell-check: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/spell_check.yml@v1 + with: + includes: "**/*.md" + modified_files_only: false + + build: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 + diff --git a/packages/secure_jwt_signer/.gitignore b/packages/secure_jwt_signer/.gitignore new file mode 100644 index 000000000..526da1584 --- /dev/null +++ b/packages/secure_jwt_signer/.gitignore @@ -0,0 +1,7 @@ +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +pubspec.lock \ No newline at end of file diff --git a/packages/secure_jwt_signer/README.md b/packages/secure_jwt_signer/README.md new file mode 100644 index 000000000..148264463 --- /dev/null +++ b/packages/secure_jwt_signer/README.md @@ -0,0 +1,62 @@ +# Secure Jwt Signer + +[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] +[![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason) +[![License: MIT][license_badge]][license_link] + +Sign jwt with keys from TEE/Strongbox or Secure Element + +## Installation 💻 + +**❗ In order to start using Secure Jwt Signer you must have the [Dart SDK][dart_install_link] installed on your machine.** + +Install via `dart pub add`: + +```sh +dart pub add secure_jwt_signer +``` + +--- + +## Continuous Integration 🤖 + +Secure Jwt Signer comes with a built-in [GitHub Actions workflow][github_actions_link] powered by [Very Good Workflows][very_good_workflows_link] but you can also add your preferred CI/CD solution. + +Out of the box, on each pull request and push, the CI `formats`, `lints`, and `tests` the code. This ensures the code remains consistent and behaves correctly as you add functionality or make changes. The project uses [Very Good Analysis][very_good_analysis_link] for a strict set of analysis options used by our team. Code coverage is enforced using the [Very Good Workflows][very_good_coverage_link]. + +--- + +## Running Tests 🧪 + +To run all unit tests: + +```sh +dart pub global activate coverage 1.2.0 +dart test --coverage=coverage +dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info +``` + +To view the generated coverage report you can use [lcov](https://github.com/linux-test-project/lcov). + +```sh +# Generate Coverage Report +genhtml coverage/lcov.info -o coverage/ + +# Open Coverage Report +open coverage/index.html +``` + +[dart_install_link]: https://dart.dev/get-dart +[github_actions_link]: https://docs.github.com/en/actions/learn-github-actions +[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license_link]: https://opensource.org/licenses/MIT +[logo_black]: https://raw.githubusercontent.com/VGVentures/very_good_brand/main/styles/README/vgv_logo_black.png#gh-light-mode-only +[logo_white]: https://raw.githubusercontent.com/VGVentures/very_good_brand/main/styles/README/vgv_logo_white.png#gh-dark-mode-only +[mason_link]: https://github.com/felangel/mason +[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg +[very_good_analysis_link]: https://pub.dev/packages/very_good_analysis +[very_good_coverage_link]: https://github.com/marketplace/actions/very-good-coverage +[very_good_ventures_link]: https://verygood.ventures +[very_good_ventures_link_light]: https://verygood.ventures#gh-light-mode-only +[very_good_ventures_link_dark]: https://verygood.ventures#gh-dark-mode-only +[very_good_workflows_link]: https://github.com/VeryGoodOpenSource/very_good_workflows diff --git a/packages/secure_jwt_signer/analysis_options.yaml b/packages/secure_jwt_signer/analysis_options.yaml new file mode 100644 index 000000000..a608bb333 --- /dev/null +++ b/packages/secure_jwt_signer/analysis_options.yaml @@ -0,0 +1,5 @@ +include: package:very_good_analysis/analysis_options.yaml +linter: + rules: + public_member_api_docs: false + constant_identifier_names: false diff --git a/packages/secure_jwt_signer/coverage_badge.svg b/packages/secure_jwt_signer/coverage_badge.svg new file mode 100644 index 000000000..499e98ce2 --- /dev/null +++ b/packages/secure_jwt_signer/coverage_badge.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + coverage + coverage + 100% + 100% + + diff --git a/packages/secure_jwt_signer/lib/secure_jwt_signer.dart b/packages/secure_jwt_signer/lib/secure_jwt_signer.dart new file mode 100644 index 000000000..3df2dd988 --- /dev/null +++ b/packages/secure_jwt_signer/lib/secure_jwt_signer.dart @@ -0,0 +1,4 @@ +/// Sign jwt with keys from TEE/Strongbox or Secure Element +library secure_jwt_signer; + +export 'src/secure_jwt_signer.dart'; diff --git a/packages/secure_jwt_signer/lib/src/secure_jwt_signer.dart b/packages/secure_jwt_signer/lib/src/secure_jwt_signer.dart new file mode 100644 index 000000000..8393b33a1 --- /dev/null +++ b/packages/secure_jwt_signer/lib/src/secure_jwt_signer.dart @@ -0,0 +1,38 @@ +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:crypto/crypto.dart'; +import 'package:secp256r1/secp256r1.dart'; + +/// Sign jwt with keys from TEE/Strongbox or Secure Element +class SecureJwtSigner { + const SecureJwtSigner(); + + Future signJwt({ + required Map header, + required Map payload, + required String privateKey, + }) async { + // Base64 url safe encoding of header and payload without padding + final headerB64 = + base64Encode(utf8.encode(jsonEncode(header))).replaceAll('=', ''); + final payloadB64 = + base64Encode(utf8.encode(jsonEncode(payload))).replaceAll('=', ''); + + // Calculate the message digest with SHA-256 + final message = '$headerB64.$payloadB64'; + final bytes = utf8.encode(message); + final digest = sha256.convert(bytes); + + // Sign the message digest with ECDSA key (P-256) + final signature = await SecureP256.sign( + privateKey, + Uint8List.fromList(digest.bytes), + ); + + // Encode signature with base64 url safe and no padding + final signatureB64 = base64Url.encode(signature).replaceAll('=', ''); + + // Return JWT + return '$headerB64.$payloadB64.$signatureB64'; + } +} diff --git a/packages/secure_jwt_signer/pubspec.yaml b/packages/secure_jwt_signer/pubspec.yaml new file mode 100644 index 000000000..16a7dfa4c --- /dev/null +++ b/packages/secure_jwt_signer/pubspec.yaml @@ -0,0 +1,16 @@ +name: secure_jwt_signer +description: Sign jwt with keys from TEE/Strongbox or Secure Element +version: 0.1.0+1 +publish_to: none + +environment: + sdk: ">=3.1.0 <4.0.0" + +dependencies: + crypto: ^3.0.3 + secp256r1: ^0.1.0-dev.7 + +dev_dependencies: + mocktail: ^1.0.3 + test: ^1.19.2 + very_good_analysis: ^5.0.0+1 diff --git a/packages/secure_jwt_signer/test/src/secure_jwt_signer_test.dart b/packages/secure_jwt_signer/test/src/secure_jwt_signer_test.dart new file mode 100644 index 000000000..1fc327786 --- /dev/null +++ b/packages/secure_jwt_signer/test/src/secure_jwt_signer_test.dart @@ -0,0 +1,13 @@ +// ignore_for_file: prefer_const_constructors +import 'dart:convert'; + +import 'package:secure_jwt_signer/secure_jwt_signer.dart'; +import 'package:test/test.dart'; + +void main() { + group('SecureJwtSigner', () { + test('can be instantiated', () { + expect(SecureJwtSigner(), isNotNull); + }); + }); +} From 44cdaacf29a74d3b12498f5e3b60461b33d186fa Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 2 May 2024 18:33:48 +0545 Subject: [PATCH 18/56] Add some tests in oidc4vc --- .../helper_functions/helper_functions.dart | 3 + .../get_credential_manifest_from_altme.dart | 2 + .../cubit/qr_code_scan_cubit.dart | 3 + .../get_and_add_deffered_credential.dart | 2 + .../get_authorization_uri_for_issuer.dart | 1 + lib/oidc4vc/get_credential.dart | 2 + lib/oidc4vc/verify_encoded_data.dart | 2 + lib/splash/bloclisteners/blocklisteners.dart | 1 + packages/oidc4vc/lib/src/oidc4vc.dart | 77 ++- packages/oidc4vc/test/src/oidc4vc_test.dart | 519 +++++++++--------- 10 files changed, 343 insertions(+), 269 deletions(-) diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index b4b4b43a9..5956296a0 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -729,6 +729,7 @@ Future< final OpenIdConfiguration openIdConfiguration = await oidc4vc.getOpenIdConfig( baseUrl: issuer, isAuthorizationServer: false, + dio: client.dio, ); if (preAuthorizedCode == null) { @@ -753,6 +754,7 @@ Future< authorizationServerConfiguration = await oidc4vc.getOpenIdConfig( baseUrl: authorizationServer, isAuthorizationServer: true, + dio: client.dio, ); } @@ -1008,6 +1010,7 @@ Future isEBSIV3ForVerifiers({ await oidc4vc.getOpenIdConfig( baseUrl: clientId, isAuthorizationServer: false, + dio: Dio(), ); final subjectTrustFrameworksSupported = diff --git a/lib/dashboard/home/tab_bar/credentials/helper_functions/get_credential_manifest_from_altme.dart b/lib/dashboard/home/tab_bar/credentials/helper_functions/get_credential_manifest_from_altme.dart index f909ffd4f..12157492c 100644 --- a/lib/dashboard/home/tab_bar/credentials/helper_functions/get_credential_manifest_from_altme.dart +++ b/lib/dashboard/home/tab_bar/credentials/helper_functions/get_credential_manifest_from_altme.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:credential_manifest/credential_manifest.dart'; +import 'package:dio/dio.dart'; import 'package:json_path/json_path.dart'; import 'package:oidc4vc/oidc4vc.dart'; @@ -11,6 +12,7 @@ Future getCredentialManifestFromAltMe({ final OpenIdConfiguration openIdConfiguration = await oidc4vc.getOpenIdConfig( baseUrl: 'https://issuer.talao.co', isAuthorizationServer: false, + dio: Dio(), ); final JsonPath credentialManifetPath = JsonPath(r'$..credential_manifest'); final credentialManifest = CredentialManifest.fromJson( diff --git a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart index ee2a864c7..1789ddba1 100644 --- a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart +++ b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart @@ -1158,6 +1158,7 @@ class QRCodeScanCubit extends Cubit { stateValue: stateValue, clientType: customOidc4vcProfile.clientType, proofHeaderType: customOidc4vcProfile.proofHeader, + dio: client.dio, ); String? url; @@ -1293,6 +1294,7 @@ class QRCodeScanCubit extends Cubit { final openIdConfiguration = await oidc4vc.getOpenIdConfig( baseUrl: issuer, isAuthorizationServer: false, + dio: client.dio, ); if (savedAccessToken == null) { @@ -1315,6 +1317,7 @@ class QRCodeScanCubit extends Cubit { redirectUri: Parameters.oidc4vcUniversalLink, openIdConfiguration: openIdConfiguration, clientAssertion: clientAssertion, + dio: client.dio, ); savedAccessToken = accessToken; diff --git a/lib/oidc4vc/get_and_add_deffered_credential.dart b/lib/oidc4vc/get_and_add_deffered_credential.dart index a178361db..81915e146 100644 --- a/lib/oidc4vc/get_and_add_deffered_credential.dart +++ b/lib/oidc4vc/get_and_add_deffered_credential.dart @@ -3,6 +3,7 @@ import 'package:altme/credentials/credentials.dart'; import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/oidc4vc/oidc4vc.dart'; +import 'package:dio/dio.dart'; import 'package:jwt_decode/jwt_decode.dart'; import 'package:oidc4vc/oidc4vc.dart'; @@ -53,6 +54,7 @@ Future getAndAddDefferedCredential({ deferredCredentialEndpoint: credentialModel.pendingInfo!.deferredCredentialEndpoint, body: body, + dio: Dio(), ); await addOIDC4VCCredential( diff --git a/lib/oidc4vc/get_authorization_uri_for_issuer.dart b/lib/oidc4vc/get_authorization_uri_for_issuer.dart index 146133df2..fb0d36cce 100644 --- a/lib/oidc4vc/get_authorization_uri_for_issuer.dart +++ b/lib/oidc4vc/get_authorization_uri_for_issuer.dart @@ -95,6 +95,7 @@ Future getAuthorizationUriForIssuer({ vcFormatType: vcFormatType, clientAssertion: clientAssertion, secureAuthorizedFlow: secureAuthorizedFlow, + dio: client.dio, ); if (secureAuthorizedFlow) { diff --git a/lib/oidc4vc/get_credential.dart b/lib/oidc4vc/get_credential.dart index d0b8bdd33..e1a3774e0 100644 --- a/lib/oidc4vc/get_credential.dart +++ b/lib/oidc4vc/get_credential.dart @@ -1,5 +1,6 @@ import 'package:altme/app/app.dart'; import 'package:altme/dashboard/dashboard.dart'; +import 'package:dio/dio.dart'; import 'package:oidc4vc/oidc4vc.dart'; /// Retreive credential_type from url @@ -61,6 +62,7 @@ Future< cnonce: nonce, authorizationDetails: authorizationDetails, openIdConfiguration: openIdConfiguration, + dio: Dio(), ); return ( diff --git a/lib/oidc4vc/verify_encoded_data.dart b/lib/oidc4vc/verify_encoded_data.dart index 69cf5fae9..9edf38a38 100644 --- a/lib/oidc4vc/verify_encoded_data.dart +++ b/lib/oidc4vc/verify_encoded_data.dart @@ -1,4 +1,5 @@ import 'package:altme/app/app.dart'; +import 'package:dio/dio.dart'; import 'package:jwt_decode/jwt_decode.dart'; import 'package:oidc4vc/oidc4vc.dart'; @@ -34,6 +35,7 @@ Future verifyEncodedData({ publicJwk: publicKeyJwk, fromStatusList: fromStatusList, isCachingEnabled: isCachingEnabled, + dio: Dio(), ); return verificationType; } diff --git a/lib/splash/bloclisteners/blocklisteners.dart b/lib/splash/bloclisteners/blocklisteners.dart index 38076f3fa..c928bb0bb 100644 --- a/lib/splash/bloclisteners/blocklisteners.dart +++ b/lib/splash/bloclisteners/blocklisteners.dart @@ -276,6 +276,7 @@ final qrCodeBlocListener = BlocListener( openIdConfiguration: openIdConfiguration, issuer: issuer, oidc4vciDraftType: customOidc4vcProfile.oidc4vciDraft, + dio: Dio(), ); credentialEndpoint = diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 33679a15f..53e516792 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -28,8 +28,6 @@ class OIDC4VC { /// {@macro ebsi} OIDC4VC(); - final Dio dio = Dio(); - /// create JWK from mnemonic String privateKeyFromMnemonic({ required String mnemonic, @@ -148,17 +146,20 @@ class OIDC4VC { required VCFormatType vcFormatType, required String? clientAssertion, required bool secureAuthorizedFlow, + required Dio dio, }) async { try { final openIdConfiguration = await getOpenIdConfig( baseUrl: issuer, isAuthorizationServer: false, + dio: dio, ); final authorizationEndpoint = await readAuthorizationEndPoint( openIdConfiguration: openIdConfiguration, issuer: issuer, oidc4vciDraftType: oidc4vciDraftType, + dio: dio, ); final authorizationRequestParemeters = getAuthorizationRequestParemeters( @@ -428,6 +429,7 @@ class OIDC4VC { required OpenIdConfiguration openIdConfiguration, required String accessToken, required String? cnonce, + required Dio dio, List? authorizationDetails, }) async { var nonce = cnonce; @@ -500,6 +502,7 @@ class OIDC4VC { privateKey: privateKey, accessToken: accessToken, nonce: nonce, + dio: dio, ); /// update nonce value @@ -532,6 +535,7 @@ class OIDC4VC { privateKey: privateKey, accessToken: accessToken, nonce: cnonce, + dio: dio, ); credentialResponseData.add(credentialResponseDataValue); @@ -553,6 +557,7 @@ class OIDC4VC { required OIDC4VCIDraftType oidc4vciDraftType, required String redirectUri, required OpenIdConfiguration openIdConfiguration, + required Dio dio, String? preAuthorizedCode, String? userPin, String? code, @@ -564,6 +569,7 @@ class OIDC4VC { openIdConfiguration: openIdConfiguration, issuer: issuer, oidc4vciDraftType: oidc4vciDraftType, + dio: dio, ); Map? tokenResponse; @@ -587,6 +593,7 @@ class OIDC4VC { tokenEndPoint: tokenEndPoint, tokenData: tokenData, authorization: authorization, + dio: dio, ); if (tokenResponse.containsKey('c_nonce')) { @@ -619,6 +626,7 @@ class OIDC4VC { required String privateKey, required String accessToken, required String? nonce, + required Dio dio, }) async { final credentialData = await buildCredentialData( nonce: nonce, @@ -665,6 +673,7 @@ class OIDC4VC { required Map credentialHeaders, required Map? body, required String deferredCredentialEndpoint, + required Dio dio, }) async { final dynamic credentialResponse = await dio.post( deferredCredentialEndpoint, @@ -730,6 +739,7 @@ class OIDC4VC { required String didKey, required bool fromStatusList, required bool isCachingEnabled, + required Dio dio, }) async { try { if (isURL(didKey)) { @@ -746,6 +756,7 @@ class OIDC4VC { baseUrl: didKey, isAuthorizationServer: isAuthorizationServer, isCachingEnabled: isCachingEnabled, + dio: dio, ); final authorizationServer = openIdConfiguration.authorizationServer; @@ -755,6 +766,7 @@ class OIDC4VC { baseUrl: authorizationServer, isAuthorizationServer: true, isCachingEnabled: isCachingEnabled, + dio: dio, ); } @@ -765,6 +777,7 @@ class OIDC4VC { final response = await dioGet( openIdConfiguration.jwksUri!, isCachingEnabled: isCachingEnabled, + dio: dio, ); return response as Map; @@ -789,6 +802,7 @@ class OIDC4VC { required OpenIdConfiguration openIdConfiguration, required String issuer, required OIDC4VCIDraftType oidc4vciDraftType, + required Dio dio, }) async { var tokenEndPoint = '$issuer/token'; @@ -801,6 +815,7 @@ class OIDC4VC { final authorizationServerConfiguration = await getOpenIdConfig( baseUrl: authorizationServer, isAuthorizationServer: true, + dio: dio, ); if (authorizationServerConfiguration.tokenEndpoint != null) { @@ -815,6 +830,7 @@ class OIDC4VC { required OpenIdConfiguration openIdConfiguration, required String issuer, required OIDC4VCIDraftType oidc4vciDraftType, + required Dio dio, }) async { var authorizationEndpoint = '$issuer/authorize'; @@ -827,6 +843,7 @@ class OIDC4VC { final authorizationServerConfiguration = await getOpenIdConfig( baseUrl: authorizationServer, isAuthorizationServer: true, + dio: dio, ); if (authorizationServerConfiguration.authorizationEndpoint != null) { @@ -1123,6 +1140,7 @@ class OIDC4VC { required Map? publicJwk, required bool fromStatusList, required bool isCachingEnabled, + required Dio dio, }) async { try { Map? publicKeyJwk; @@ -1134,6 +1152,7 @@ class OIDC4VC { didKey: issuer, fromStatusList: fromStatusList, isCachingEnabled: isCachingEnabled, + dio: dio, ); publicKeyJwk = readPublicKeyJwk( @@ -1271,6 +1290,7 @@ class OIDC4VC { required String tokenEndPoint, required Map tokenData, required String? authorization, + required Dio dio, }) async { /// getting token final tokenHeaders = { @@ -1365,6 +1385,7 @@ class OIDC4VC { required String? stateValue, required ClientType clientType, required ProofHeaderType proofHeaderType, + required Dio dio, }) async { try { final private = jsonDecode(privateKey) as Map; @@ -1596,6 +1617,7 @@ class OIDC4VC { Future getOpenIdConfig({ required String baseUrl, required bool isAuthorizationServer, + required Dio dio, bool isCachingEnabled = false, }) async { ///for OIDC4VCI, the server is an issuer the metadata are all in th @@ -1611,6 +1633,7 @@ class OIDC4VC { final data = await getOpenIdConfigSecondMethod( baseUrl, isCachingEnabled: isCachingEnabled, + dio: dio, ); return data; } @@ -1619,6 +1642,7 @@ class OIDC4VC { final response = await dioGet( url, isCachingEnabled: isCachingEnabled, + dio: dio, ); final data = response is String ? jsonDecode(response) as Map @@ -1629,6 +1653,7 @@ class OIDC4VC { final data = await getOpenIdConfigSecondMethod( baseUrl, isCachingEnabled: isCachingEnabled, + dio: dio, ); return data; } @@ -1637,6 +1662,7 @@ class OIDC4VC { Future getOpenIdConfigSecondMethod( String baseUrl, { required bool isCachingEnabled, + required Dio dio, }) async { final url = '$baseUrl/.well-known/openid-credential-issuer'; @@ -1644,10 +1670,12 @@ class OIDC4VC { final response = await dioGet( url, isCachingEnabled: isCachingEnabled, + dio: dio, ); final data = response is String ? jsonDecode(response) as Map : response as Map; + return OpenIdConfiguration.fromJson(data); } catch (e) { throw Exception('OPENID-CONFIGURATION-ISSUE'); @@ -1712,40 +1740,45 @@ class OIDC4VC { Future dioGet( String uri, { + required Dio dio, Map headers = const { 'Content-Type': 'application/json; charset=UTF-8', }, bool isCachingEnabled = false, }) async { try { - final secureStorageProvider = getSecureStorage; - final cachedData = await secureStorageProvider.get(uri); dynamic response; dio.options.headers = headers; - if (!isCachingEnabled || cachedData == null) { - response = await dio.get(uri); - } else { - final cachedDataJson = jsonDecode(cachedData); - final expiry = int.parse(cachedDataJson['expiry'].toString()); - - final isExpired = DateTime.now().millisecondsSinceEpoch > expiry; - - if (isExpired) { + if (isCachingEnabled) { + final secureStorageProvider = getSecureStorage; + final cachedData = await secureStorageProvider.get(uri); + if (cachedData == null) { response = await dio.get(uri); } else { - /// directly return cached data - /// returned here to avoid the caching override everytime - final response = await cachedDataJson['data']; - return response; + final cachedDataJson = jsonDecode(cachedData); + final expiry = int.parse(cachedDataJson['expiry'].toString()); + + final isExpired = DateTime.now().millisecondsSinceEpoch > expiry; + + if (isExpired) { + response = await dio.get(uri); + } else { + /// directly return cached data + /// returned here to avoid the caching override everytime + final response = await cachedDataJson['data']; + return response; + } } - } - final expiry = - DateTime.now().add(const Duration(days: 2)).millisecondsSinceEpoch; + final expiry = + DateTime.now().add(const Duration(days: 2)).millisecondsSinceEpoch; - final value = {'expiry': expiry, 'data': response.data}; - await secureStorageProvider.set(uri, jsonEncode(value)); + final value = {'expiry': expiry, 'data': response.data}; + await secureStorageProvider.set(uri, jsonEncode(value)); + } else { + response = await dio.get(uri); + } return response.data; } on FormatException catch (_) { diff --git a/packages/oidc4vc/test/src/oidc4vc_test.dart b/packages/oidc4vc/test/src/oidc4vc_test.dart index 16d13c8dd..484279b95 100644 --- a/packages/oidc4vc/test/src/oidc4vc_test.dart +++ b/packages/oidc4vc/test/src/oidc4vc_test.dart @@ -23,19 +23,18 @@ void main() { final client = Dio(); final dioAdapter = DioAdapter(dio: Dio(BaseOptions()), matcher: const UrlRequestMatcher()); + client.httpClientAdapter = dioAdapter; const mnemonic = 'position taste mention august skin taste best air sure acoustic poet ritual'; + final oidc4vc = OIDC4VC(); test('OIDC4VC class can be instantiated', () { - final oidc4vc = OIDC4VC(); expect(oidc4vc, isNotNull); }); - group('EBSI DID and JWK', () { - final oidc4vc = OIDC4VC(); - + group('OIDC4VC DID and JWK', () { const seedBytes = [ 179, 252, @@ -80,39 +79,14 @@ void main() { }; const index = 0; - test('JWK from mnemonic', () async { - final jwk = await oidc4vc.privateKeyFromMnemonic( + test('JWK from mnemonic', () { + final jwk = oidc4vc.privateKeyFromMnemonic( mnemonic: mnemonic, indexValue: index, ); expect(jsonDecode(jwk), expectedECJwk); }); - // group('getPrivateKey', () { - // test('privateKey from mnemonic', () async { - // final jwk = await oidc4vc.getPrivateKey( - // mnemonic: mnemonic, - // indexValue: index, - // ); - // expect(jwk, expectedECJwk); - // }); - - // test('privateKey from key', () async { - // const key = { - // 'crv': 'secp256k1', - // 'd': 's_wb6Ef1ardGsT5Il6WLRvQ9Zu0lp7I2OVwtzT5iQpo', - // 'kty': 'EC', - // 'x': 'qs4JLbsmA-7L-3o9V4BoNVrDtYoWE2OOZIvujoVJZ1U', - // 'y': '8PLGROkTALZP3YHY5pm0yrMVCjQoctHM3uaxug70mq8', - // }; - // final jwk = await oidc4vc.getPrivateKey( - // privateKey: jsonEncode(key), - // indexValue: index, - // ); - // expect(jwk, expectedECJwk); - // }); - // }); - test('JWK from seeds', () { final jwk = oidc4vc.jwkFromSeed(seedBytes: Uint8List.fromList(seedBytes)); expect(jwk, expectedECJwk); @@ -120,7 +94,6 @@ void main() { }); test('P256 JWK from mnemonics', () { - final oidc4vc = OIDC4VC(); final jwk = oidc4vc.p256PrivateKeyFromMnemonics( mnemonic: mnemonic, indexValue: 0, @@ -128,9 +101,9 @@ void main() { final expectedP256Jwk = { 'kty': 'EC', 'crv': 'P-256', - 'd': 'cFCdgT569Shto8jEVbyKqdtEck0EcUSwGz_vqrclTC8', - 'x': 'vhoSh07qpGqiCJNGQJmY8YaARnxuHUgv403c5TmrABQ', - 'y': 'E04Ate9RceryoHlz1x3BVIbN9LZR74TWRCeeMNY-oew', + 'd': 's_wb6Ef1ardGsT5Il6WLRvQ9Zu0lp7I2OVwtzT5iQpo', + 'x': 'MZZjpNhZGGxqBcPXq499FVC2iu5FcZWwti5u8hgMUaI', + 'y': 'KD4zffV54PZUsQzTzVgoVlWHwKqogRF3JpKQnIGwIRM', }; expect(jsonDecode(jwk), expectedP256Jwk); @@ -151,8 +124,6 @@ void main() { const kid = '3623b877bbb24b08ba390f3585418f53'; - final oidc4vc = OIDC4VC(); - test('sign and verify with edDSA', () async { final token = oidc4vc.generateTokenEdDSA( payload: payload, @@ -170,8 +141,6 @@ void main() { }); group('selective disclosure', () { - final oidc4vc = OIDC4VC(); - const content = '["Qg_O64zqAxe412a108iroA", "phone_number", "+81-80-1234-5678"]'; @@ -192,8 +161,6 @@ void main() { }); group('publicKeyBase58ToPublicJwk', () { - final oidc4vc = OIDC4VC(); - const publicKeyBase58 = '2S73k5pn5umfnaW31qx6dXFndEn6SmWw7LpgSjNNC5BF'; final expectedPublicJWK = { @@ -209,238 +176,296 @@ void main() { }); group('EBSI: getAuthorizationUriForIssuer', () { - const issuer = 'https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi'; - - const openIdConfiguration = - '{"authorization_server":"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi/authorize_server","credential_endpoint":"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi/credential","credential_issuer":"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi","credential_supported":[{"display":[{"locale":"en-GB","name":"Verifiable diploma"}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"]},{"display":[{"locale":"en-GB","name":"Email proof"}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","EmailPass"]},{"display":[{"locale":"en-GB","name":"Verifiable Id"}],"format":"jwt_vc","id":"VerifiableId","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableId"]}],"credentials_supported":[{"display":[{"locale":"en-GB","name":"Verifiable diploma"}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"]},{"display":[{"locale":"en-GB","name":"Email proof"}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","EmailPass"]},{"display":[{"locale":"en-GB","name":"Verifiable Id"}],"format":"jwt_vc","id":"VerifiableId","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableId"]}],"deferred_credential_endpoint":"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi/deferred","service_documentation":"New environment for V3 compliance test, use specific did:key"}'; - - const selectedCredentials = [ - { - 'format': 'jwt_vc', - 'types': [ - 'VerifiableCredential', - 'VerifiableAttestation', - 'VerifiableDiploma', - ], - } - ]; + const selectedCredentials = ['EmailPass']; const clientId = - 'did:key:zBhBLmYmyihtomRdJJNEKzbPj51o4a3GYFeZoRHSABKUwqdjiQPY2fjSoTWRD2nvVmaLnLHU8GXeGFmL1ed8ZAoPGoDeBMwcp4XFchNeTw917v2evpUjyst2gxZuRrVDSxDCb6G2Z1Tbz8kWHbjfUKgLVQd7CexS5GvPHfSQGdsLdjj4cNZvvZa'; - const webLink = 'https://app.altme.io/app/download/oidc4vc'; - const schema = - 'openid-credential-offer://?credential_offer_uri=https://talao.co/sandbox/ebsi/issuer/credential_offer_uri/a572f0a6-56a9-11ee-ac4f-0a1628958560'; - const issuerState = 'a53d709e-56a9-11ee-828d-0a1628958560'; - const nonce = '6044cc7d-2bd9-4804-82ae-c9950d8eedd8'; - const options = '[0]'; - const state = '4eee52c0-e524-4b62-a005-629e97f82dc5'; + 'did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjZka1U2Wk1GSzc5V3dpY3dKNXJieEUxM3pTdWtCWTJPb0VpVlVFanFNRWMiLCJ5IjoiUm5Iem55VmxyUFNNVDdpckRzMTVEOXd4Z01vamlTREFRcGZGaHFUa0xSWSJ9'; + const redirectUri = 'https://app.altme.io/app/download/oidc4vc'; + + const issuer = 'https://talao.co/issuer/mfyttabosy'; + + const issuerState = 'test7'; + const nonce = '8b60e2fb-87f3-4401-8107-0f0128ea01ab'; + const pkcePair = PkcePair( - 'l-NEmG-JlH-VwUxNoNmv8NPD47K_2Pu0hEY6tAHg9pE', - 'E0BAjRGdb3bspwyNsGnRDcV1zHp4CyCB7_2EQUsB4Ls', + 'Pzy4U_sJ0J7VdIAR6JCwL5hbecv30egmJVP81VDFAnk', + '4KorCwmYyO-_t4i_hva7F3aHGpT_2WqqDh6erimepOA', + ); + + const state = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2RlVmVyaWZpZXIiOiI0S29yQ3dtWXlPLV90NGlfaHZhN0YzYUhHcFRfMldxcURoNmVyaW1lcE9BIiwiY3JlZGVudGlhbHMiOlsiRW1haWxQYXNzIl0sImlzc3VlciI6Imh0dHBzOi8vdGFsYW8uY28vaXNzdWVyL21meXR0YWJvc3kiLCJpc0VCU0lWMyI6ZmFsc2UsImNsaWVudF9pZCI6ImRpZDpqd2s6ZXlKamNuWWlPaUpRTFRJMU5pSXNJbXQwZVNJNklrVkRJaXdpZUNJNklqWmthMVUyV2sxR1N6YzVWM2RwWTNkS05YSmllRVV4TTNwVGRXdENXVEpQYjBWcFZsVkZhbkZOUldNaUxDSjVJam9pVW01SWVtNTVWbXh5VUZOTlZEZHBja1J6TVRWRU9YZDRaMDF2YW1sVFJFRlJjR1pHYUhGVWEweFNXU0o5IiwiaWF0IjoxNzE0NTQ5OTUxfQ.JJtv8H52NTvPzR3IPET1sXGALdt0yXaQBQbGvDLKNlM'; + + const authorizationEndPoint = 'https://app.altme.io/app/download/authorize'; + + const openIdConfiguration = + '{"authorization_server":null,"credential_endpoint":"https://talao.co/issuer/mfyttabosy/credential","credential_issuer":"https://talao.co/issuer/mfyttabosy","subject_syntax_types_supported":["urn:ietf:params:oauth:jwk-thumbprint","did:key","did:ebsi","did:tz","did:pkh","did:hedera","did:key","did:ethr","did:web","did:jwk"],"token_endpoint":"https://talao.co/issuer/mfyttabosy/token","batch_endpoint":null,"authorization_endpoint":"https://talao.co/issuer/mfyttabosy/authorize","subject_trust_frameworks_supported":["ebsi"],"credentials_supported":null,"credential_configurations_supported":{"DBCGuest":{"credential_definition":{"type":["VerifiableCredential","DBCGuest"]},"display":[{"background_color":"#3B6F6D","background_image":{"alt_text":"Connected open cubes in blue with one orange cube as a background of the card","url":"https://i.ibb.co/CHqjxrJ/dbc-card-hig-res.png"},"description":"The DBC Guest credential is a DIIP example.","logo":{"alt_text":"An orange block shape, with the text Dutch Blockchain Coalition next to it, portraying the logo of the Dutch Blockchain Coalition.","url":"https://dutchblockchaincoalition.org/assets/images/icons/Logo-DBC.png"},"name":"DBC Guest (DIIP)","text_color":"#FFFFFF"},{"background_color":"#3B6F6D","background_image":{"alt_text":"Connected open cubes in blue with one orange cube as a background of the card","url":"https://i.ibb.co/CHqjxrJ/dbc-card-hig-res.png"},"description":"The DBC guest credential is a DIIP example.","locale":"en-US","logo":{"alt_text":"An orange block shape, with the text Dutch Blockchain Coalition next to it, portraying the logo of the Dutch Blockchain Coalition.","url":"https://dutchblockchaincoalition.org/assets/images/icons/Logo-DBC.png"},"name":"DBC Guest (DIIP)","text_color":"#FFFFFF"},{"background_color":"#3B6F6D","background_image":{"alt_text":"Connected open cubes in blue with one orange cube as a background of the card","url":"https://i.ibb.co/CHqjxrJ/dbc-card-hig-res.png"},"description":"De DBC gast credential is een DIIP voorbeeld.","locale":"nl-NL","logo":{"alt_text":"Aaneengesloten open blokken in de kleur blauw, met een blok in de kleur oranje, die tesamen de achtergrond van de kaart vormen.","url":"https://dutchblockchaincoalition.org/assets/images/icons/Logo-DBC.png"},"name":"DBC gast (DIIP)","text_color":"#FFFFFF"}],"format":"jwt_vc_json","scope":"DBCGuest_scope"},"EmailPass":{"credential_definition":{"type":["VerifiableCredential","EmailPass"]},"credential_signing_alg_values_supported":["ES256K","ES256","ES384","RS256"],"cryptographic_binding_methods_supported":["DID","jwk"],"display":[{"locale":"en-GB","name":"Proof of Email"}],"format":"jwt_vc_json","scope":"EmailPass_scope"},"EmployeeCredential":{"credential_definition":{"type":["VerifiableCredential","EmployeeCredential"]},"credential_signing_alg_values_supported":["ES256K","ES256","ES384","RS256"],"cryptographic_binding_methods_supported":["DID","jwk"],"display":[{"background_color":"#12107c","locale":"en-US","logo":{"alt_text":"a square logo of a university","url":"https://exampleuniversity.com/public/logo.png"},"name":"Employee Credential","text_color":"#FFFFFF"}],"format":"jwt_vc_json","scope":"EmployeeCredential_scope"},"Over18":{"credential_definition":{"type":["VerifiableCredential","Over18"]},"credential_signing_alg_values_supported":["ES256K","ES256","ES384","RS256"],"cryptographic_binding_methods_supported":["DID","jwk"],"display":[{"locale":"en-GB","name":"Over 18yo proof"},{"locale":"fr-GB","name":"Preuve de majorité"}],"format":"jwt_vc_json","scope":"Over18_scope"},"PhoneProof":{"credential_definition":{"type":["VerifiableCredential","PhoneProof"]},"credential_signing_alg_values_supported":["ES256K","ES256","ES384","RS256"],"cryptographic_binding_methods_supported":["DID","jwk"],"display":[{"locale":"en-GB","name":"Proof of phone number"}],"format":"jwt_vc_json","scope":"PhoneProof_scope"},"VerifiableId":{"credential_definition":{"credentialSubject":{"dateIssued":{"display":[{"locale":"en-US","name":"Issuance date"},{"locale":"fr-FR","name":"Délivré le"}],"mandatory":true},"dateOfBirth":{"display":[{"locale":"en-US","name":"Date of birth"},{"locale":"fr-FR","name":"Né(e) le"}],"mandatory":true},"email":{"display":[{"locale":"en-US","name":"Email"},{"locale":"fr-FR","name":"Email"}],"mandatory":true},"familyName":{"display":[{"locale":"en-US","name":"Family name"},{"locale":"fr-FR","name":"Nom"}],"mandatory":true},"firstName":{"display":[{"locale":"en-US","name":"First name"},{"locale":"fr-FR","name":"Prénom(s)"}],"mandatory":true},"gender":{"display":[{"locale":"en-US","name":"Gender"},{"locale":"fr-FR","name":"Sexe"}],"mandatory":true},"issuing_country":{"display":[{"locale":"en-US","name":"Issuing country"},{"locale":"fr-FR","name":"Délivré par"}],"mandatory":true},"phone_number":{"display":[{"locale":"en-US","name":"Phone number"},{"locale":"fr-FR","name":"Téléphone"}],"mandatory":true}},"order":["firstName","familyName","dateOfBirth","gender","dateIssued","issuing_country","email","phone_number"],"type":["VerifiableCredential","VerifiableId"]},"credential_signing_alg_values_supported":["ES256K","ES256","ES384","RS256"],"cryptographic_binding_methods_supported":["DID","jwk"],"display":[{"background_color":"#12107c","locale":"en-US","name":"Verifiable Id","text_color":"#FFFFFF"}],"format":"jwt_vc_json","scope":"VerifiableId_scope"}},"deferred_credential_endpoint":"https://talao.co/issuer/mfyttabosy/deferred","service_documentation":null,"credential_manifest":null,"credential_manifests":null,"issuer":null,"jwks_uri":"https://talao.co/issuer/mfyttabosy/jwks","grant_types_supported":["authorization_code","urn:ietf:params:oauth:grant-type:pre-authorized_code"]}'; + + test( + 'given Url of openid request we return Uri for authentication endpoint', + () async { + const expectedAuthorizationEndpoint = + 'https://talao.co/issuer/mfyttabosy/authorize'; + + const expectedAuthorizationRequestParemeters = { + 'response_type': 'code', + 'redirect_uri': 'https://app.altme.io/app/download/oidc4vc', + 'state': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2RlVmVyaWZpZXIiOiI0S29yQ3dtWXlPLV90NGlfaHZhN0YzYUhHcFRfMldxcURoNmVyaW1lcE9BIiwiY3JlZGVudGlhbHMiOlsiRW1haWxQYXNzIl0sImlzc3VlciI6Imh0dHBzOi8vdGFsYW8uY28vaXNzdWVyL21meXR0YWJvc3kiLCJpc0VCU0lWMyI6ZmFsc2UsImNsaWVudF9pZCI6ImRpZDpqd2s6ZXlKamNuWWlPaUpRTFRJMU5pSXNJbXQwZVNJNklrVkRJaXdpZUNJNklqWmthMVUyV2sxR1N6YzVWM2RwWTNkS05YSmllRVV4TTNwVGRXdENXVEpQYjBWcFZsVkZhbkZOUldNaUxDSjVJam9pVW01SWVtNTVWbXh5VUZOTlZEZHBja1J6TVRWRU9YZDRaMDF2YW1sVFJFRlJjR1pHYUhGVWEweFNXU0o5IiwiaWF0IjoxNzE0NTQ5OTUxfQ.JJtv8H52NTvPzR3IPET1sXGALdt0yXaQBQbGvDLKNlM', + 'nonce': '8b60e2fb-87f3-4401-8107-0f0128ea01ab', + 'code_challenge': '4KorCwmYyO-_t4i_hva7F3aHGpT_2WqqDh6erimepOA', + 'code_challenge_method': 'S256', + 'issuer_state': 'test7', + 'client_metadata': + '{\"authorization_endpoint\":\"https://app.altme.io/app/download/authorize\",\"scopes_supported\":[\"openid\"],\"response_types_supported\":[\"vp_token\",\"id_token\"],\"client_id_schemes_supported\":[\"redirect_uri\",\"did\"],\"grant_types_supported\":[\"authorization_code\",\"pre-authorized_code\"],\"subject_types_supported\":[\"public\"],\"id_token_signing_alg_values_supported\":[\"ES256\",\"ES256K\"],\"request_object_signing_alg_values_supported\":[\"ES256\",\"ES256K\"],\"request_parameter_supported\":true,\"request_uri_parameter_supported\":true,\"request_authentication_methods_supported\":{\"authorization_endpoint\":[\"request_object\"]},\"vp_formats_supported\":{\"jwt_vp\":{\"alg_values_supported\":[\"ES256\",\"ES256K\"]},\"jwt_vc\":{\"alg_values_supported\":[\"ES256\",\"ES256K\"]}},\"subject_syntax_types_supported\":[\"urn:ietf:params:oauth:jwk-thumbprint\",\"did:key\",\"did:pkh\",\"did:key\",\"did:polygonid\"],\"subject_syntax_types_discriminations\":[\"did:key:jwk_jcs-pub\",\"did:ebsi:v1\"],\"subject_trust_frameworks_supported\":[\"ebsi\"],\"id_token_types_supported\":[\"subject_signed_id_token\"],\"token_endpoint_auth_method\":\"client_id\"}', + 'client_id': + 'did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjZka1U2Wk1GSzc5V3dpY3dKNXJieEUxM3pTdWtCWTJPb0VpVlVFanFNRWMiLCJ5IjoiUm5Iem55VmxyUFNNVDdpckRzMTVEOXd4Z01vamlTREFRcGZGaHFUa0xSWSJ9', + 'scope': 'openid', + 'authorization_details': + '[{\"type\":\"openid_credential\",\"credential_configuration_id\":\"EmailPass\"}]', + }; + + dioAdapter.onGet( + 'https://talao.co/issuer/mfyttabosy/.well-known/openid-credential-issuer', + (request) => request.reply(200, jsonDecode(openIdConfiguration)), + ); + + final (authorizationEndpoint, authorizationRequestParemeters) = + await oidc4vc.getAuthorizationData( + selectedCredentials: selectedCredentials, + clientId: clientId, + clientSecret: null, + redirectUri: redirectUri, + issuerState: issuerState, + nonce: nonce, + pkcePair: pkcePair, + state: state, + authorizationEndPoint: authorizationEndPoint, + scope: false, + clientAuthentication: ClientAuthentication.clientId, + oidc4vciDraftType: OIDC4VCIDraftType.draft13, + vcFormatType: VCFormatType.jwtVcJson, + clientAssertion: null, + secureAuthorizedFlow: false, + issuer: issuer, + dio: client, + ); + + expect(authorizationEndpoint, expectedAuthorizationEndpoint); + expect(authorizationRequestParemeters, + expectedAuthorizationRequestParemeters); + }, ); - // test( - // 'given Url of openid request we return Uri for authentication endpoint', - // () async { - // final expectedAuthorizationEndpointdUri = Uri.parse( - // 'https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi/authorize?response_type=code&client_id=did%3Akey%3AzBhBLmYmyihtomRdJJNEKzbPj51o4a3GYFeZoRHSABKUwqdjiQPY2fjSoTWRD2nvVmaLnLHU8GXeGFmL1ed8ZAoPGoDeBMwcp4XFchNeTw917v2evpUjyst2gxZuRrVDSxDCb6G2Z1Tbz8kWHbjfUKgLVQd7CexS5GvPHfSQGdsLdjj4cNZvvZa&redirect_uri=https%3A%2F%2Fapp.altme.io%2Fapp%2Fdownload%2Foidc4vc%3Furi%3Dopenid-credential-offer%3A%2F%2F%3Fcredential_offer_uri%3Dhttps%3A%2F%2Ftalao.co%2Fsandbox%2Febsi%2Fissuer%2Fcredential_offer_uri%2Fa572f0a6-56a9-11ee-ac4f-0a1628958560%26code_verifier%3Dl-NEmG-JlH-VwUxNoNmv8NPD47K_2Pu0hEY6tAHg9pE%26options%3D%5B0%5D&scope=openid&issuer_state=a53d709e-56a9-11ee-828d-0a1628958560&state=4eee52c0-e524-4b62-a005-629e97f82dc5&nonce=6044cc7d-2bd9-4804-82ae-c9950d8eedd8&code_challenge=E0BAjRGdb3bspwyNsGnRDcV1zHp4CyCB7_2EQUsB4Ls&code_challenge_method=S256&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22locations%22%3A%5B%22https%3A%2F%2Ftalao.co%2Fsandbox%2Febsi%2Fissuer%2Fpcbrwbvrsi%22%5D%2C%22format%22%3A%22jwt_vc%22%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22VerifiableAttestation%22%2C%22VerifiableDiploma%22%5D%7D%5D&client_metadata=%7B%22authorization_endpoint%22%3A%22https%3A%2F%2Ftalao.co%2Fsandbox%2Febsi%2Fissuer%2Fpcbrwbvrsi%2Fauthorize%22%2C%22scopes_supported%22%3A%5B%22openid%22%5D%2C%22response_types_supported%22%3A%5B%22vp_token%22%2C%22id_token%22%5D%2C%22subject_types_supported%22%3A%5B%22public%22%5D%2C%22id_token_signing_alg_values_supported%22%3A%5B%22ES256%22%5D%2C%22request_object_signing_alg_values_supported%22%3A%5B%22ES256%22%5D%2C%22vp_formats_supported%22%3A%7B%22jwt_vp%22%3A%7B%22alg_values_supported%22%3A%5B%22ES256%22%5D%7D%2C%22jwt_vc%22%3A%7B%22alg_values_supported%22%3A%5B%22ES256%22%5D%7D%7D%2C%22subject_syntax_types_supported%22%3A%5B%22urn%3Aietf%3Aparams%3Aoauth%3Ajwk-thumbprint%22%2C%22did%F0%9F%94%91jwk_jcs-pub%22%5D%2C%22id_token_types_supported%22%3A%5B%22subject_signed_id_token%22%5D%7D'); - - // dioAdapter.onGet( - // issuer, - // (request) => request.reply(200, jsonDecode(openIdConfiguration)), - // ); - - // final oidc4vc = OIDC4VC(); - - // final authorizationEndpointdUri = - // await oidc4vc.getAuthorizationUriForIssuer( - // selectedCredentials: selectedCredentials, - // clientId: clientId, - // webLink: webLink, - // schema: schema, - // issuer: issuer, - // issuerState: issuerState, - // nonce: nonce, - // options: options, - // state: state, - // pkcePair: pkcePair, - // ); - - // expect( - // authorizationEndpointdUri.toString(), - // expectedAuthorizationEndpointdUri.toString(), - // ); - // }, - // ); test( 'throw Exception with when request is not valid', () async { - final oidc4vc = OIDC4VC(); - - // expect( - // () async => oidc4vc.getAuthorizationUriForIssuer( - // selectedCredentials: [], - // clientId: '', - // webLink: '', - // schema: '', - // issuer: '', - // issuerState: '', - // nonce: '', - // options: '', - // state: '', - // pkcePair: const PkcePair( - // '', - // '', - // ), - // ), - // throwsA( - // isA().having( - // (p0) => p0.toString(), - // 'toString()', - // 'Exception: Not a valid openid url to initiate issuance', - // ), - // ), - // ); + expect( + () async => oidc4vc.getAuthorizationData( + selectedCredentials: [], + clientId: '', + issuer: '', + issuerState: '', + nonce: '', + state: '', + pkcePair: const PkcePair( + '', + '', + ), + authorizationEndPoint: '', + clientAssertion: '', + clientAuthentication: ClientAuthentication.clientId, + clientSecret: '', + oidc4vciDraftType: OIDC4VCIDraftType.draft11, + redirectUri: '', + scope: false, + secureAuthorizedFlow: false, + vcFormatType: VCFormatType.jwtVc, + dio: client, + ), + throwsA( + isA().having( + (p0) => p0.toString(), + 'toString()', + 'Exception: NOT_A_VALID_OPENID_URL', + ), + ), + ); }, ); test( 'given correct authorization request parameter', () async { - const openIdConfigurationResponse = - '{"authorization_server":"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi/authorize_server","credential_endpoint":"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi/credential","credential_issuer":"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi","credentials_supported":[{"display":[{"locale":"en-GB","name":"Verifiable diploma"}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"]},{"display":[{"locale":"en-GB","name":"Email proof"}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","EmailPass"]},{"display":[{"locale":"en-GB","name":"Verifiable Id"}],"format":"jwt_vc","id":"VerifiableId","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableId"]}],"deferred_credential_endpoint":"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi/deferred","service_documentation":"New environment for V3 compliance test, use specific did:key"}'; const expectedAuthorizationRequestParemeters = - r'{"response_type":"code","client_id":"did:key:zBhBLmYmyihtomRdJJNEKzbPj51o4a3GYFeZoRHSABKUwqdjiQPY2fjSoTWRD2nvVmaLnLHU8GXeGFmL1ed8ZAoPGoDeBMwcp4XFchNeTw917v2evpUjyst2gxZuRrVDSxDCb6G2Z1Tbz8kWHbjfUKgLVQd7CexS5GvPHfSQGdsLdjj4cNZvvZa","redirect_uri":"https://app.altme.io/app/download/oidc4vc?uri=openid-credential-offer://?credential_offer_uri=https://talao.co/sandbox/ebsi/issuer/credential_offer_uri/a572f0a6-56a9-11ee-ac4f-0a1628958560&code_verifier=l-NEmG-JlH-VwUxNoNmv8NPD47K_2Pu0hEY6tAHg9pE&options=[0]","scope":"openid","issuer_state":"a53d709e-56a9-11ee-828d-0a1628958560","state":"4eee52c0-e524-4b62-a005-629e97f82dc5","nonce":"6044cc7d-2bd9-4804-82ae-c9950d8eedd8","code_challenge":"E0BAjRGdb3bspwyNsGnRDcV1zHp4CyCB7_2EQUsB4Ls","code_challenge_method":"S256","authorization_details":"[{\"type\":\"openid_credential\",\"locations\":[\"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi\"],\"format\":\"jwt_vc\",\"types\":[\"VerifiableCredential\",\"VerifiableAttestation\",\"VerifiableDiploma\"]}]","client_metadata":"{\"authorization_endpoint\":\"https://talao.co/sandbox/ebsi/issuer/pcbrwbvrsi/authorize\",\"scopes_supported\":[\"openid\"],\"response_types_supported\":[\"vp_token\",\"id_token\"],\"subject_types_supported\":[\"public\"],\"id_token_signing_alg_values_supported\":[\"ES256\"],\"request_object_signing_alg_values_supported\":[\"ES256\"],\"vp_formats_supported\":{\"jwt_vp\":{\"alg_values_supported\":[\"ES256\"]},\"jwt_vc\":{\"alg_values_supported\":[\"ES256\"]}},\"subject_syntax_types_supported\":[\"urn:ietf:params:oauth:jwk-thumbprint\",\"did🔑jwk_jcs-pub\"],\"id_token_types_supported\":[\"subject_signed_id_token\"]}"}'; - final oidc4vc = OIDC4VC(); - - // final authorizationRequestParemeters = - // oidc4vc.getAuthorizationRequestParemeters( - // selectedCredentials: selectedCredentials, - // clientId: clientId, - // webLink: webLink, - // schema: schema, - // issuer: issuer, - // issuerState: issuerState, - // nonce: nonce, - // options: options, - // state: state, - // pkcePair: pkcePair, - // openidConfigurationResponse: - // jsonDecode(openIdConfigurationResponse) as Map, - // ); - - // expect( - // jsonEncode(authorizationRequestParemeters), - // expectedAuthorizationRequestParemeters, - // ); + r'{"response_type":"code","redirect_uri":"https://app.altme.io/app/download/oidc4vc","state":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2RlVmVyaWZpZXIiOiI0S29yQ3dtWXlPLV90NGlfaHZhN0YzYUhHcFRfMldxcURoNmVyaW1lcE9BIiwiY3JlZGVudGlhbHMiOlsiRW1haWxQYXNzIl0sImlzc3VlciI6Imh0dHBzOi8vdGFsYW8uY28vaXNzdWVyL21meXR0YWJvc3kiLCJpc0VCU0lWMyI6ZmFsc2UsImNsaWVudF9pZCI6ImRpZDpqd2s6ZXlKamNuWWlPaUpRTFRJMU5pSXNJbXQwZVNJNklrVkRJaXdpZUNJNklqWmthMVUyV2sxR1N6YzVWM2RwWTNkS05YSmllRVV4TTNwVGRXdENXVEpQYjBWcFZsVkZhbkZOUldNaUxDSjVJam9pVW01SWVtNTVWbXh5VUZOTlZEZHBja1J6TVRWRU9YZDRaMDF2YW1sVFJFRlJjR1pHYUhGVWEweFNXU0o5IiwiaWF0IjoxNzE0NTQ5OTUxfQ.JJtv8H52NTvPzR3IPET1sXGALdt0yXaQBQbGvDLKNlM","nonce":"8b60e2fb-87f3-4401-8107-0f0128ea01ab","code_challenge":"4KorCwmYyO-_t4i_hva7F3aHGpT_2WqqDh6erimepOA","code_challenge_method":"S256","issuer_state":"test7","client_metadata":"{\"authorization_endpoint\":\"https://app.altme.io/app/download/authorize\",\"scopes_supported\":[\"openid\"],\"response_types_supported\":[\"vp_token\",\"id_token\"],\"client_id_schemes_supported\":[\"redirect_uri\",\"did\"],\"grant_types_supported\":[\"authorization_code\",\"pre-authorized_code\"],\"subject_types_supported\":[\"public\"],\"id_token_signing_alg_values_supported\":[\"ES256\",\"ES256K\"],\"request_object_signing_alg_values_supported\":[\"ES256\",\"ES256K\"],\"request_parameter_supported\":true,\"request_uri_parameter_supported\":true,\"request_authentication_methods_supported\":{\"authorization_endpoint\":[\"request_object\"]},\"vp_formats_supported\":{\"jwt_vp\":{\"alg_values_supported\":[\"ES256\",\"ES256K\"]},\"jwt_vc\":{\"alg_values_supported\":[\"ES256\",\"ES256K\"]}},\"subject_syntax_types_supported\":[\"urn:ietf:params:oauth:jwk-thumbprint\",\"did:key\",\"did:pkh\",\"did:key\",\"did:polygonid\"],\"subject_syntax_types_discriminations\":[\"did:key:jwk_jcs-pub\",\"did:ebsi:v1\"],\"subject_trust_frameworks_supported\":[\"ebsi\"],\"id_token_types_supported\":[\"subject_signed_id_token\"],\"token_endpoint_auth_method\":\"client_id\"}","client_id":"did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjZka1U2Wk1GSzc5V3dpY3dKNXJieEUxM3pTdWtCWTJPb0VpVlVFanFNRWMiLCJ5IjoiUm5Iem55VmxyUFNNVDdpckRzMTVEOXd4Z01vamlTREFRcGZGaHFUa0xSWSJ9","scope":"openid","authorization_details":"[{\"type\":\"openid_credential\",\"credential_configuration_id\":\"EmailPass\"}]"}'; + + final authorizationRequestParemeters = + oidc4vc.getAuthorizationRequestParemeters( + selectedCredentials: selectedCredentials, + clientId: clientId, + authorizationEndPoint: authorizationEndPoint, + clientAssertion: null, + scope: false, + clientAuthentication: ClientAuthentication.clientId, + oidc4vciDraftType: OIDC4VCIDraftType.draft13, + vcFormatType: VCFormatType.jwtVcJson, + secureAuthorizedFlow: false, + issuer: issuer, + issuerState: issuerState, + nonce: nonce, + state: state, + pkcePair: pkcePair, + clientSecret: null, + openIdConfiguration: OpenIdConfiguration.fromJson( + jsonDecode(openIdConfiguration) as Map, + ), + redirectUri: redirectUri, + ); + + expect( + jsonEncode(authorizationRequestParemeters), + expectedAuthorizationRequestParemeters, + ); }, ); }); - //group('OIC4VC request credential', () { - // final credentialRequest = Uri.parse( - // 'https://app.altme.io/app/download?credential_type=https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd&issuer=https://talao.co/sandbox/ebsi/issuer/vgvghylozl?code=cb803d46-9c88-11ed-bdb3-0a1628958560&state=0d189873-9c87-11ed-8dbf-0a1628958560', - // ); - - // final credentialRequestWithPreAuthorizedCode = Uri.parse( - // 'openid://initiate_issuance?issuer=https%3A%2F%2Ftalao.co%2Fsandbox%2Febsi%2Fissuer%2Fvgvghylozl&credential_type=https%3A%2F%2Fapi.preprod.oidc4vc.eu%2Ftrusted-schemas-registry%2Fv1%2Fschemas%2F0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd&op_state=test&pre-authorized_code=ff8e73c5-ae07-11ed-b1f7-0a1628958560&user_pin_required=False', - // ); - - // const issuerResponse = - // r'{"authorization_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/authorize","batch_credential_endpoint":null,"credential_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/credential","credential_issuer":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl","credential_manifests":[{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"display":{"description":{"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework.","path":[],"schema":{"type":"string"}},"properties":[{"fallback":"Unknown","label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number"}},{"fallback":"Unknown","label":"Issue date","path":["$.issuanceDate"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"format":"uri","type":"string"}}],"subtitle":{"fallback":"EBSI Verifiable diploma","path":[],"schema":{"type":"string"}},"title":{"fallback":"Diploma","path":[],"schema":{"type":"string"}}},"id":"diploma_01","schema":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"spec_version":"https://identity.foundation/credential-manifest/spec/v1.0.0/"}],"credential_supported":[{"cryptographic_binding_methods_supported":["did"],"cryptographic_suites_supported":["ES256K","ES256","ES384","ES512","RS256"],"display":[{"locale":"en-US","name":"Issuer Talao"}],"format":"jwt_vc","id":"VerifiableDiploma","types":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"pre-authorized_grant_anonymous_access_supported":true,"subject_syntax_types_supported":["did:ebsi"],"token_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/token"}'; - - // const tokenResponse = - // '{"access_token":"7a07dd19-a879-11ed-ad95-0a1628958560","c_nonce":"7a07de0f-a879-11ed-822b-0a1628958560","token_type":"Bearer","expires_in":1000}'; // ignore: lines_longer_than_80_chars - - // const credentialRequestUrl = - // 'https://talao.co/sandbox/ebsi/issuer/vgvghylozl/credential'; - - // const credentialRequestResponse = - // '{"format":"jwt_vc","credential":"eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiM1MTVhOWM0MzZjMGYyYWQzYWI2NWQ2Y2VmYzVjMWYwNmMwNWI4YWRmY2Y1NGVlMDZkYzgwNTQzMjA0NzBmZmFmIiwidHlwIjoiSldUIn0.eyJleHAiOjE2NzU5NDcwNTguODkyNzc4LCJpYXQiOjE2NzU5NDYwNTguODkyNzcxLCJpc3MiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsImp0aSI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsIm5iZiI6MTY3NTk0NjA1OC44OTI3NzYsIm5vbmNlIjoiMTFmNWY2MDAtYTg3Ni0xMWVkLTkwZjItMGExNjI4OTU4NTYwIiwic3ViIjoiZGlkOmVic2k6em94UkdWWlFuZFRmUWs1NEI3dEtkd3dOZGhhaTVnbTlGOE5hdjhlY2VOQUJhIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vYXBpLnByZXByb2QuZWJzaS5ldS90cnVzdGVkLXNjaGVtYXMtcmVnaXN0cnkvdjEvc2NoZW1hcy8weGJmNzhmYzA4YTdhOWYyOGY1NDc5ZjU4ZGVhMjY5ZDM2NTdmNTRmMTNjYTM3ZDM4MGNkNGU5MjIzN2ZiNjkxZGQiLCJ0eXBlIjoiSnNvblNjaGVtYVZhbGlkYXRvcjIwMTgifSwiY3JlZGVudGlhbFN0YXR1cyI6eyJpZCI6Imh0dHBzOi8vZXNzaWYuZXVyb3BhLmV1L3N0YXR1cy9lZHVjYXRpb24jaGlnaGVyRWR1Y2F0aW9uIzM5MmFjN2Y2LTM5OWEtNDM3Yi1hMjY4LTQ2OTFlYWQ4ZjE3NiIsInR5cGUiOiJDcmVkZW50aWFsU3RhdHVzTGlzdDIwMjAifSwiY3JlZGVudGlhbFN1YmplY3QiOnsiYXdhcmRpbmdPcHBvcnR1bml0eSI6eyJhd2FyZGluZ0JvZHkiOnsiZWlkYXNMZWdhbElkZW50aWZpZXIiOiJVbmtub3duIiwiaG9tZXBhZ2UiOiJodHRwczovL2xlYXN0b24uYmNkaXBsb21hLmNvbS8iLCJpZCI6ImRpZDplYnNpOnpkUnZ2S2JYaFZWQnNYaGF0anVpQmhzIiwicHJlZmVycmVkTmFtZSI6IkxlYXN0b24gVW5pdmVyc2l0eSIsInJlZ2lzdHJhdGlvbiI6IjA1OTcwNjVKIn0sImVuZGVkQXRUaW1lIjoiMjAyMC0wNi0yNlQwMDowMDowMFoiLCJpZCI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tL2xhdy1lY29ub21pY3MtbWFuYWdlbWVudCNBd2FyZGluZ09wcG9ydHVuaXR5IiwiaWRlbnRpZmllciI6Imh0dHBzOi8vY2VydGlmaWNhdGUtZGVtby5iY2RpcGxvbWEuY29tL2NoZWNrLzg3RUQyRjIyNzBFNkM0MTQ1NkU5NEI4NkI5RDkxMTVCNEUzNUJDQ0FEMjAwQTQ5Qjg0NjU5MkMxNEY3OUM4NkJWMUZuYmxsdGEwTlpUbkprUjNsRFdsUm1URGxTUlVKRVZGWklTbU5tWXpKaFVVNXNaVUo1WjJGSlNIcFdibVpaIiwibG9jYXRpb24iOiJGUkFOQ0UiLCJzdGFydGVkQXRUaW1lIjoiMjAxOS0wOS0wMlQwMDowMDowMFoifSwiZGF0ZU9mQmlydGgiOiIxOTkzLTA0LTA4IiwiZmFtaWx5TmFtZSI6IkRPRSIsImdpdmVuTmFtZXMiOiJKYW5lIiwiZ3JhZGluZ1NjaGVtZSI6eyJpZCI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tL2xhdy1lY29ub21pY3MtbWFuYWdlbWVudCNHcmFkaW5nU2NoZW1lIiwidGl0bGUiOiIyIHllYXIgZnVsbC10aW1lIHByb2dyYW1tZSAvIDQgc2VtZXN0ZXJzIn0sImlkIjoiZGlkOmVic2k6em94UkdWWlFuZFRmUWs1NEI3dEtkd3dOZGhhaTVnbTlGOE5hdjhlY2VOQUJhIiwiaWRlbnRpZmllciI6IjA5MDQwMDgwODRIIiwibGVhcm5pbmdBY2hpZXZlbWVudCI6eyJhZGRpdGlvbmFsTm90ZSI6WyJESVNUUklCVVRJT04gTUFOQUdFTUVOVCJdLCJkZXNjcmlwdGlvbiI6IlRoZSBNYXN0ZXIgaW4gSW5mb3JtYXRpb24gYW5kIENvbXB1dGVyIFNjaWVuY2VzIChNSUNTKSBhdCB0aGUgVW5pdmVyc2l0eSBvZiBMdXhlbWJvdXJnIGVuYWJsZXMgc3R1ZGVudHMgdG8gYWNxdWlyZSBkZWVwZXIga25vd2xlZGdlIGluIGNvbXB1dGVyIHNjaWVuY2UgYnkgdW5kZXJzdGFuZGluZyBpdHMgYWJzdHJhY3QgYW5kIGludGVyZGlzY2lwbGluYXJ5IGZvdW5kYXRpb25zLCBmb2N1c2luZyBvbiBwcm9ibGVtIHNvbHZpbmcgYW5kIGRldmVsb3BpbmcgbGlmZWxvbmcgbGVhcm5pbmcgc2tpbGxzLiIsImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0xlYXJuaW5nQWNoaWV2bWVudCIsInRpdGxlIjoiTWFzdGVyIGluIEluZm9ybWF0aW9uIGFuZCBDb21wdXRlciBTY2llbmNlcyJ9LCJsZWFybmluZ1NwZWNpZmljYXRpb24iOnsiZWN0c0NyZWRpdFBvaW50cyI6MTIwLCJlcWZMZXZlbCI6NywiaWQiOiJodHRwczovL2xlYXN0b24uYmNkaXBsb21hLmNvbS9sYXctZWNvbm9taWNzLW1hbmFnZW1lbnQjTGVhcm5pbmdTcGVjaWZpY2F0aW9uIiwiaXNjZWRmQ29kZSI6WyI3Il0sIm5xZkxldmVsIjpbIjciXX19LCJldmlkZW5jZSI6eyJkb2N1bWVudFByZXNlbmNlIjpbIlBoeXNpY2FsIl0sImV2aWRlbmNlRG9jdW1lbnQiOlsiUGFzc3BvcnQiXSwiaWQiOiJodHRwczovL2Vzc2lmLmV1cm9wYS5ldS90c3ItdmEvZXZpZGVuY2UvZjJhZWVjOTctZmMwZC00MmJmLThjYTctMDU0ODE5MmQ1Njc4Iiwic3ViamVjdFByZXNlbmNlIjoiUGh5c2ljYWwiLCJ0eXBlIjpbIkRvY3VtZW50VmVyaWZpY2F0aW9uIl0sInZlcmlmaWVyIjoiZGlkOmVic2k6Mjk2MmZiNzg0ZGY2MWJhYTI2N2M4MTMyNDk3NTM5ZjhjNjc0YjM3YzEyNDRhN2EifSwiaWQiOiJ1cm46dXVpZDo2YjFkODQxMS05ZWQ1LTQ1NjYtOWM3Zi00YzI0MTY1ZmYyMzYiLCJpc3N1YW5jZURhdGUiOiIyMDIzLTAyLTA5VDEyOjM0OjE4WiIsImlzc3VlZCI6IjIwMjMtMDItMDlUMTI6MzQ6MThaIiwiaXNzdWVyIjoiZGlkOmVic2k6emhTdzVyUFhrY0hqdnF1d25WY1R6ekIiLCJwcm9vZiI6eyJjcmVhdGVkIjoiMjAyMi0wNC0yN1QxMjoyNTowN1oiLCJjcmVhdG9yIjoiZGlkOmVic2k6emRSdnZLYlhoVlZCc1hoYXRqdWlCaHMiLCJkb21haW4iOiJodHRwczovL2FwaS5wcmVwcm9kLmVic2kuZXUiLCJqd3MiOiJleUppTmpRaU9tWmhiSE5sTENKamNtbDBJanBiSW1JMk5DSmRMQ0poYkdjaU9pSkZVekkxTmtzaWZRLi5tSUJuTThYRFFxU1lLUU5YX0x2YUpobXNieUNyNU9aNWNVMlprLVJlcUxwcjRkb0ZzZ21vb2JrTzUxMjh0WnktOEtpbVZqSmtHdzB3TDF1QlduTUxXUSIsIm5vbmNlIjoiM2VhNjhkYWUtZDA3YS00ZGFhLTkzMmItZmJiNThmNWMyMGM0IiwidHlwZSI6IkVjZHNhU2VjcDI1NmsxU2lnbmF0dXJlMjAxOSJ9LCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiVmVyaWZpYWJsZURpcGxvbWEiXSwidmFsaWRGcm9tIjoiMjAyMy0wMi0wOVQxMjozNDoxOFoifX0.uQK9sK-VtqmKjLJIw_v5Ff5xAMDAosZCtl1LFYxZhUolReD6a7O-NI1f5lcswBCZPLfJ-HJyb5iShehHObzFDA","c_nonce":"128952c8-a876-11ed-bbc4-0a1628958560","c_nonce_expires_in":1000}'; // ignore: lines_longer_than_80_chars - - // dioAdapter - // ..onGet( - // issuer, - // (request) => request.reply(200, jsonDecode(issuerResponse)), - // ) - // ..onPost( - // 'tokenUrl', - // (request) => request.reply( - // 200, - // jsonDecode(tokenResponse), - // ), - // ) - // ..onPost( - // credentialRequestUrl, - // (request) => request.reply( - // 200, - // jsonDecode(credentialRequestResponse), - // ), - // ); - // test('When getCredentialType receive url it returns json response', - // () async { - // final oidc4vc = OIDC4VC(client); - // final credential = await oidc4vc.getCredential( - // credentialRequest, - // mnemonic, - // null, - // ); - // expect(jsonEncode(credential), credentialRequestResponse); - // }); + group('OIC4VC request credential', () { + const issuer = 'https://talao.co/issuer/zxhaokccsi'; - //}); - // test('throw Exception when token is not verified', () { - // const issuerDid = 'did:ebsi:zhSw5rPXkcHjvquwnVcTzzB'; + const credential = { + 'format': 'jwt_vc', + 'types': [ + 'VerifiableCredential', + 'VerifiableAttestation', + 'VerifiableDiploma2', + ], + }; - // const didDocumentUrl = - // 'https://api-pilot.oidc4vc.eu/did-registry/v3/identifiers/$issuerDid'; + const did = + 'did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9Kbrbpg5is8LfTLuQ1RsW5r7s7ZjbDDFbDgy1tLrdc7Bj3itBGQkuGUQyfzKhFqbUNW2PqJPMSSzWoF2DGSvDSijCtJtYCSRsjSVLrwu5oHNbnPFvSEC4iRZPpU6B6nExRBTa'; - // const didDocumentResponse = - // '{"assertionMethod":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"authentication":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"@context":"https://www.w3.org/ns/did/v1","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","verificationMethod":[{"controller":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53","publicKeyJwk":{"crv":"P-521","kty":"EC","x":"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk","y":"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDly79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2"},"type":"Ed25519VerificationKey2019"}]}'; + const kid = + 'did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9Kbrbpg5is8LfTLuQ1RsW5r7s7ZjbDDFbDgy1tLrdc7Bj3itBGQkuGUQyfzKhFqbUNW2PqJPMSSzWoF2DGSvDSijCtJtYCSRsjSVLrwu5oHNbnPFvSEC4iRZPpU6B6nExRBTa#z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9Kbrbpg5is8LfTLuQ1RsW5r7s7ZjbDDFbDgy1tLrdc7Bj3itBGQkuGUQyfzKhFqbUNW2PqJPMSSzWoF2DGSvDSijCtJtYCSRsjSVLrwu5oHNbnPFvSEC4iRZPpU6B6nExRBTa'; - // dioAdapter.onGet( - // didDocumentUrl, - // (request) => request.reply(200, jsonDecode(didDocumentResponse)), - // ); + const privateKey = + '{"kty":"EC","crv":"P-256","d":"amrwK13ZiYoJ5g0fc6MvXc86RB9ID8VuK_dMowU68FE","x":"fJQ2c9P_YDep3jzidwykcSlyoC4omqBvd9RHP1nz0cw","y":"K7VxrW-S1ONuX5cxrWIltF36ac1K8kj9as_o5cyc2zk"}'; - // final oidc4vc = OIDC4VC(client); + const openIdConfiguration = + '{"authorization_server":"https://talao.co/issuer/zxhaokccsi","credential_endpoint":"https://talao.co/issuer/zxhaokccsi/credential","credential_issuer":"https://talao.co/issuer/zxhaokccsi","subject_syntax_types_supported":null,"token_endpoint":null,"batch_endpoint":null,"authorization_endpoint":null,"subject_trust_frameworks_supported":null,"credentials_supported":[{"display":[{"locale":"en-US","name":"EU Diploma","description":"This the official EBSI VC Diploma","text_color":"#FFFFFF","background_color":"#3B6F6D","background_image":{"url":"https://i.ibb.co/CHqjxrJ/dbc-card-hig-res.png","alt_text":"Connected open cubes in blue with one orange cube as a background of the card"},"logo":{"url":"https://dutchblockchaincoalition.org/assets/images/icons/Logo-DBC.png","alt_text":"An orange block shape, with the text Dutch Blockchain Coalition next to it, portraying the logo of the Dutch Blockchain Coalition."}}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma2"],"id":null,"scope":null,"credentialSubject":{"dateOfBirth":{"display":[{"locale":"en-US","name":"Birth Date"},{"locale":"fr-FR","name":"Date de naissance"}]},"familyName":{"display":[{"locale":"en-US","name":"Family Name"},{"locale":"fr-FR","name":"Nom"}]},"givenNames":{"display":[{"locale":"en-US","name":"First Name"},{"locale":"fr-FR","name":"Prénom"}]}}},{"display":[{"locale":"en-US","name":"Individual attestation","description":"This is the EBSI Individual Verifiable Attestation","text_color":"#FFFFFF","background_color":"#3B6F6D","background_image":null,"logo":null}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","IndividualVerifiableAttestation"],"id":null,"scope":null,"credentialSubject":{"dateOfBirth":{"display":[{"locale":"en-US","name":"Birth Date"},{"locale":"fr-FR","name":"Date de naissance"}]},"familyName":{"display":[{"locale":"en-US","name":"Family Name"},{"locale":"fr-FR","name":"Nom"}]},"firstName":{"display":[{"locale":"en-US","name":"First Name"},{"locale":"fr-FR","name":"Prénom"}]},"issuing_country":{"display":[{"locale":"en-US","name":"Issued by"},{"locale":"fr-FR","name":"Délivré par"}]},"placeOfBirth":{"display":[{"locale":"en-US","name":"Birth Place"},{"locale":"fr-FR","name":"Lieu de naissance"}]}}},{"display":[{"locale":"en-GB","name":"Email proof","description":"This is a verifiable credential","text_color":null,"background_color":null,"background_image":null,"logo":null}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","EmailPass"],"id":null,"scope":null,"credentialSubject":null},{"display":[{"locale":"en-GB","name":"Verifiable Id","description":"This is a verifiable credential","text_color":null,"background_color":null,"background_image":null,"logo":null}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableId"],"id":null,"scope":null,"credentialSubject":null}],"credential_configurations_supported":null,"deferred_credential_endpoint":"https://talao.co/issuer/zxhaokccsi/deferred","service_documentation":null,"credential_manifest":null,"credential_manifests":null,"issuer":null,"jwks_uri":null,"grant_types_supported":null}'; - // expect( - // () async { - // await oidc4vc.getCredential( - // credentialRequest, - // mnemonic, - // null, - // ); - // }, - // throwsA( - // isA().having( - // (p0) => p0.toString(), - // 'toString()', - // 'Exception: VERIFICATION_ISSUE', - // ), - // ), - // ); - // }); + const accessToken = '0f0119c2-0867-11ef-8bfa-0a1628958560'; - // group('build token data', () { - // final oidc4vc = OIDC4VC(client); - // test('get token data with credentialRequestUri', () async { - // const expectedTokenData = - // '{"code":"cb803d46-9c88-11ed-bdb3-0a1628958560","grant_type":"authorization_code"}'; // ignore: lines_longer_than_80_chars - // final tokenData = oidc4vc.buildTokenData( - // credentialRequest, - // ); - // expect(jsonEncode(tokenData), expectedTokenData); - // }); + const nonce = '0f011beb-0867-11ef-817f-0a1628958560'; - // test('get token data with credentialRequestUri', () { - // const expectedTokenData = - // '{"pre-authorized_code":"ff8e73c5-ae07-11ed-b1f7-0a1628958560","grant_type":"urn:ietf:params:oauth:grant-type:pre-authorized_code"}'; // ignore: lines_longer_than_80_chars - // final tokenData = - // oidc4vc.buildTokenData(credentialRequestWithPreAuthorizedCode); - // expect(jsonEncode(tokenData), expectedTokenData); - // }); - // }); + const credentialRequestUrl = + 'https://talao.co/issuer/zxhaokccsi/credential'; + + const expecedCredentialResponse = + '{"credential":"eyJhbGciOiJFUzI1NiIsImtpZCI6InFsM2g2Z3Jqem5iaGNSRzVPRWk3V1B6dHNkZ1FLaGhiLXBOU1laSWgtdk0iLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3NDYxODE3NDYsImlhdCI6MTcxNDY0NTc0NiwiaXNzIjoiaHR0cHM6Ly90YWxhby5jby9pc3N1ZXIvenhoYW9rY2NzaSIsImp0aSI6InVybjp1dWlkOmNkZGE4MWYyLTA4NmUtMTFlZi05ODE3LTBhMTYyODk1ODU2MCIsIm5iZiI6MTcxNDY0NTc0Niwibm9uY2UiOiJjOWZkMzJiYS0wODZlLTExZWYtOTQ5Yi0wYTE2Mjg5NTg1NjAiLCJzdWIiOiJkaWQ6a2V5OnoyZG16RDgxY2dQeDhWa2k3SmJ1dU1tRllyV1BnWW95dHlrVVozZXlxaHQxajlLYnJicGc1aXM4TGZUTHVRMVJzVzVyN3M3WmpiRERGYkRneTF0THJkYzdCajNpdEJHUWt1R1VReWZ6S2hGcWJVTlcyUHFKUE1TU3pXb0YyREdTdkRTaWpDdEp0WUNTUnNqU1ZMcnd1NW9ITmJuUEZ2U0VDNGlSWlBwVTZCNm5FeFJCVGEiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9hcGkucHJlcHJvZC5lYnNpLmV1L3RydXN0ZWQtc2NoZW1hcy1yZWdpc3RyeS92MS9zY2hlbWFzLzB4YmY3OGZjMDhhN2E5ZjI4ZjU0NzlmNThkZWEyNjlkMzY1N2Y1NGYxM2NhMzdkMzgwY2Q0ZTkyMjM3ZmI2OTFkZCIsInR5cGUiOiJKc29uU2NoZW1hVmFsaWRhdG9yMjAxOCJ9LCJjcmVkZW50aWFsU3RhdHVzIjpbeyJpZCI6Imh0dHBzOi8vdGFsYW8uY28vc2FuZGJveC9pc3N1ZXIvYml0c3RyaW5nc3RhdHVzbGlzdC8xIzczMDE5Iiwic3RhdHVzTGlzdENyZWRlbnRpYWwiOiJodHRwczovL3RhbGFvLmNvL3NhbmRib3gvaXNzdWVyL2JpdHN0cmluZ3N0YXR1c2xpc3QvMSIsInN0YXR1c0xpc3RJbmRleCI6IjczMDE5Iiwic3RhdHVzUHVycG9zZSI6InJldm9jYXRpb24iLCJ0eXBlIjoiQml0c3RyaW5nU3RhdHVzTGlzdEVudHJ5In1dLCJjcmVkZW50aWFsU3ViamVjdCI6eyJhd2FyZGluZ09wcG9ydHVuaXR5Ijp7ImF3YXJkaW5nQm9keSI6eyJlaWRhc0xlZ2FsSWRlbnRpZmllciI6IlVua25vd24iLCJob21lcGFnZSI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tLyIsImlkIjoiZGlkOmVic2k6emRSdnZLYlhoVlZCc1hoYXRqdWlCaHMiLCJwcmVmZXJyZWROYW1lIjoiTGVhc3RvbiBVbml2ZXJzaXR5IiwicmVnaXN0cmF0aW9uIjoiMDU5NzA2NUoifSwiZW5kZWRBdFRpbWUiOiIyMDIwLTA2LTI2VDAwOjAwOjAwWiIsImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0F3YXJkaW5nT3Bwb3J0dW5pdHkiLCJpZGVudGlmaWVyIjoiaHR0cHM6Ly9jZXJ0aWZpY2F0ZS1kZW1vLmJjZGlwbG9tYS5jb20vY2hlY2svODdFRDJGMjI3MEU2QzQxNDU2RTk0Qjg2QjlEOTExNUI0RTM1QkNDQUQyMDBBNDlCODQ2NTkyQzE0Rjc5Qzg2QlYxRm5ibGx0YTBOWlRuSmtSM2xEV2xSbVREbFNSVUpFVkZaSVNtTm1ZekpoVVU1c1pVSjVaMkZKU0hwV2JtWloiLCJsb2NhdGlvbiI6IkZSQU5DRSIsInN0YXJ0ZWRBdFRpbWUiOiIyMDE5LTA5LTAyVDAwOjAwOjAwWiJ9LCJkYXRlT2ZCaXJ0aCI6IjE5OTMtMDQtMDgiLCJmYW1pbHlOYW1lIjoiRE9FIiwiZ2l2ZW5OYW1lcyI6IkphbmUiLCJncmFkaW5nU2NoZW1lIjp7ImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0dyYWRpbmdTY2hlbWUiLCJ0aXRsZSI6IjIgeWVhciBmdWxsLXRpbWUgcHJvZ3JhbW1lIC8gNCBzZW1lc3RlcnMifSwiaWRlbnRpZmllciI6IjA5MDQwMDgwODRIIiwibGVhcm5pbmdBY2hpZXZlbWVudCI6eyJhZGRpdGlvbmFsTm90ZSI6WyJESVNUUklCVVRJT04gTUFOQUdFTUVOVCJdLCJkZXNjcmlwdGlvbiI6IlRoZSBNYXN0ZXIgaW4gSW5mb3JtYXRpb24gYW5kIENvbXB1dGVyIFNjaWVuY2VzIChNSUNTKSBhdCB0aGUgVW5pdmVyc2l0eSBvZiBMdXhlbWJvdXJnIGVuYWJsZXMgc3R1ZGVudHMgdG8gYWNxdWlyZSBkZWVwZXIga25vd2xlZGdlIGluIGNvbXB1dGVyIHNjaWVuY2UgYnkgdW5kZXJzdGFuZGluZyBpdHMgYWJzdHJhY3QgYW5kIGludGVyZGlzY2lwbGluYXJ5IGZvdW5kYXRpb25zLCBmb2N1c2luZyBvbiBwcm9ibGVtIHNvbHZpbmcgYW5kIGRldmVsb3BpbmcgbGlmZWxvbmcgbGVhcm5pbmcgc2tpbGxzLiIsImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0xlYXJuaW5nQWNoaWV2bWVudCIsInRpdGxlIjoiTWFzdGVyIGluIEluZm9ybWF0aW9uIGFuZCBDb21wdXRlciBTY2llbmNlcyJ9LCJsZWFybmluZ1NwZWNpZmljYXRpb24iOnsiZWN0c0NyZWRpdFBvaW50cyI6MTIwLCJlcWZMZXZlbCI6NywiaWQiOiJodHRwczovL2xlYXN0b24uYmNkaXBsb21hLmNvbS9sYXctZWNvbm9taWNzLW1hbmFnZW1lbnQjTGVhcm5pbmdTcGVjaWZpY2F0aW9uIiwiaXNjZWRmQ29kZSI6WyI3Il0sIm5xZkxldmVsIjpbIjciXX0sInR5cGUiOiJWZXJpZmlhYmxlRGlwbG9tYTIifSwiZXZpZGVuY2UiOnsiZG9jdW1lbnRQcmVzZW5jZSI6WyJQaHlzaWNhbCJdLCJldmlkZW5jZURvY3VtZW50IjpbIlBhc3Nwb3J0Il0sImlkIjoiaHR0cHM6Ly9lc3NpZi5ldXJvcGEuZXUvdHNyLXZhL2V2aWRlbmNlL2YyYWVlYzk3LWZjMGQtNDJiZi04Y2E3LTA1NDgxOTJkNTY3OCIsInN1YmplY3RQcmVzZW5jZSI6IlBoeXNpY2FsIiwidHlwZSI6WyJEb2N1bWVudFZlcmlmaWNhdGlvbiJdLCJ2ZXJpZmllciI6ImRpZDplYnNpOjI5NjJmYjc4NGRmNjFiYWEyNjdjODEzMjQ5NzUzOWY4YzY3NGIzN2MxMjQ0YTdhIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJWZXJpZmlhYmxlQXR0ZXN0YXRpb24iLCJWZXJpZmlhYmxlRGlwbG9tYSJdfX0.eU1nRdOMklOK6kKvJk-0iCdng5gXZ7quZV1ob_kr2c3_7wSsOEhlgikZzTkkZAOuxmkkdSnWRsGMoA0M4YEi1Q","c_nonce":"cddafe06-086e-11ef-b80b-0a1628958560","c_nonce_expires_in":5000,"format":"jwt_vc"}'; + dioAdapter.onPost( + credentialRequestUrl, + (request) => request.reply( + 200, + expecedCredentialResponse, + ), + ); + + test('When getCredentialType receive url it returns json response', + () async { + final (credentialResponseData, deferredCredentialEndpoint, format) = + await oidc4vc.getCredential( + issuer: issuer, + credential: credential, + did: did, + clientId: did, + kid: kid, + privateKey: privateKey, + cryptoHolderBinding: true, + clientType: ClientType.did, + proofHeaderType: ProofHeaderType.kid, + oidc4vciDraftType: OIDC4VCIDraftType.draft11, + clientAuthentication: ClientAuthentication.clientId, + proofType: ProofType.jwt, + openIdConfiguration: OpenIdConfiguration.fromJson( + jsonDecode(openIdConfiguration) as Map, + ), + accessToken: accessToken, + cnonce: nonce, + dio: client, + ); + + expect(credentialResponseData, [expecedCredentialResponse]); + expect( + deferredCredentialEndpoint, + 'https://talao.co/issuer/zxhaokccsi/deferred', + ); + expect(format, 'jwt_vc'); + }); + + test('throw Exception when token is not verified', () { + expect( + () async { + await oidc4vc.getCredential( + issuer: '', + credential: null, + did: '', + clientId: null, + kid: '', + privateKey: '', + cryptoHolderBinding: true, + clientType: ClientType.did, + proofHeaderType: ProofHeaderType.kid, + oidc4vciDraftType: OIDC4VCIDraftType.draft11, + clientAuthentication: ClientAuthentication.clientId, + proofType: ProofType.jwt, + openIdConfiguration: OpenIdConfiguration.fromJson( + jsonDecode(openIdConfiguration) as Map, + ), + accessToken: '', + cnonce: null, + dio: client, + ); + }, + throwsA(isA()), + ); + }); + }); + + group('build token data', () { + const redirectUri = 'https://app.altme.io/app/download/callback'; + const preAuthorizedCode = + 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDplYnNpOjEyMzQja2V5LTEiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL3RhbGFvLmNvL3NhbmRib3gvZWJzaS9pc3N1ZXIvenhoYW9rY2NzaSIsImNsaWVudF9pZCI6Imh0dHBzOi8vc2VsZi1pc3N1ZWQubWUvdjIiLCJleHAiOjE3MTQ2MzU4NDIsImlhdCI6MTcxNDYzNDg0MiwiaXNzIjoiaHR0cHM6Ly90YWxhby5jby9zYW5kYm94L2Vic2kvaXNzdWVyL3p4aGFva2Njc2kiLCJub25jZSI6IjZhMGJkZWUxLTA4NTUtMTFlZi04MzJlLTBhMTYyODk1ODU2MCIsInN1YiI6Imh0dHBzOi8vc2VsZi1pc3N1ZWQubWUvdjIifQ.ViX87lulUM6WZ0lNj5XMEz-Ty5q8nIcI7b-bIYa7VRsqo1wcR_en-8hzN_Q_sp8hqi8lKX80n4jM-DqXqvJk5g'; + + test('get token data with credentialRequestUri for preAuthorizedCode', + () async { + const clientId = + 'did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9Kbpog7BZb9wdCJCjHfWMTpjcviuoFJ2fd9AiwsWGMFvhNJ5gVMA2mzHSFqkrLMXdHNeePjiaTP15sw8uaWDfyAxehGHKj7YsxymgVnEhcEJgKsLRJHgJZXAiXJGyRxWPGEYC'; + + const expectedTokenData = + '{"pre-authorized_code":"eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDplYnNpOjEyMzQja2V5LTEiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL3RhbGFvLmNvL3NhbmRib3gvZWJzaS9pc3N1ZXIvenhoYW9rY2NzaSIsImNsaWVudF9pZCI6Imh0dHBzOi8vc2VsZi1pc3N1ZWQubWUvdjIiLCJleHAiOjE3MTQ2MzU4NDIsImlhdCI6MTcxNDYzNDg0MiwiaXNzIjoiaHR0cHM6Ly90YWxhby5jby9zYW5kYm94L2Vic2kvaXNzdWVyL3p4aGFva2Njc2kiLCJub25jZSI6IjZhMGJkZWUxLTA4NTUtMTFlZi04MzJlLTBhMTYyODk1ODU2MCIsInN1YiI6Imh0dHBzOi8vc2VsZi1pc3N1ZWQubWUvdjIifQ.ViX87lulUM6WZ0lNj5XMEz-Ty5q8nIcI7b-bIYa7VRsqo1wcR_en-8hzN_Q_sp8hqi8lKX80n4jM-DqXqvJk5g","grant_type":"urn:ietf:params:oauth:grant-type:pre-authorized_code","client_id":"did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9Kbpog7BZb9wdCJCjHfWMTpjcviuoFJ2fd9AiwsWGMFvhNJ5gVMA2mzHSFqkrLMXdHNeePjiaTP15sw8uaWDfyAxehGHKj7YsxymgVnEhcEJgKsLRJHgJZXAiXJGyRxWPGEYC"}'; // ignore: lines_longer_than_80_chars + final tokenData = oidc4vc.buildTokenData( + redirectUri: redirectUri, + preAuthorizedCode: preAuthorizedCode, + clientId: clientId, + ); + + expect(jsonEncode(tokenData), expectedTokenData); + }); + + test('get token data with credentialRequestUri - authorization flow', () { + const clientId = + 'did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjZka1U2Wk1GSzc5V3dpY3dKNXJieEUxM3pTdWtCWTJPb0VpVlVFanFNRWMiLCJ5IjoiUm5Iem55VmxyUFNNVDdpckRzMTVEOXd4Z01vamlTREFRcGZGaHFUa0xSWSJ9'; + const expectedTokenData = + '{"code":"6486b7c9-0858-11ef-a82c-0a1628958560","grant_type":"authorization_code","code_verifier":"qZNF2gMjTQf7pJN2NMai1TS9Y81z8xzfPQtbmyVG-Gk","redirect_uri":"https://app.altme.io/app/download/callback","client_id":"did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjZka1U2Wk1GSzc5V3dpY3dKNXJieEUxM3pTdWtCWTJPb0VpVlVFanFNRWMiLCJ5IjoiUm5Iem55VmxyUFNNVDdpckRzMTVEOXd4Z01vamlTREFRcGZGaHFUa0xSWSJ9"}'; + final tokenData = oidc4vc.buildTokenData( + redirectUri: redirectUri, + clientId: clientId, + code: '6486b7c9-0858-11ef-a82c-0a1628958560', + codeVerifier: 'qZNF2gMjTQf7pJN2NMai1TS9Y81z8xzfPQtbmyVG-Gk', + ); + expect(jsonEncode(tokenData), expectedTokenData); + }); + }); // group('getIssuer', () { // final oidc4vc = OIDC4VC(client); From 8fe77eda85a74f1053bb85886fd76c210735b1e2 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 3 May 2024 16:44:42 +0545 Subject: [PATCH 19/56] feat: Add tests for oidc4vc --- packages/oidc4vc/lib/src/oidc4vc.dart | 1 - .../test/src/client_authentication_test.dart | 15 + .../oidc4vc/test/src/client_type_test.dart | 12 + packages/oidc4vc/test/src/const_values.dart | 79 +- .../test/src/helper_function_test.dart | 21 + .../issuer_token_parameters_class.dart | 107 +-- .../issuer_token_parameters_test.dart | 94 +-- .../oidc4vc/test/src/media_type_test.dart | 13 + packages/oidc4vc/test/src/oidc4vc_test.dart | 690 ++++++++---------- .../test/src/oidc4vci_draft_type_test.dart | 16 + .../test/src/oidc4vp_draft_type_test.dart | 13 + packages/oidc4vc/test/src/pkce_dart_test.dart | 32 + .../test/src/proof_header_type_test.dart | 11 + .../oidc4vc/test/src/proof_type_test.dart | 16 + .../test/src/soipv2_draft_type_test.dart | 10 + .../token_parameters_class.dart | 95 ++- .../token_parameters_test.dart | 211 ++---- .../oidc4vc/test/src/vc_format_type_test.dart | 38 + .../verifier_token_parameters_class.dart | 152 ++-- .../verifier_token_parameters_test.dart | 381 +++++----- 20 files changed, 1044 insertions(+), 963 deletions(-) create mode 100644 packages/oidc4vc/test/src/client_authentication_test.dart create mode 100644 packages/oidc4vc/test/src/client_type_test.dart create mode 100644 packages/oidc4vc/test/src/helper_function_test.dart create mode 100644 packages/oidc4vc/test/src/media_type_test.dart create mode 100644 packages/oidc4vc/test/src/oidc4vci_draft_type_test.dart create mode 100644 packages/oidc4vc/test/src/oidc4vp_draft_type_test.dart create mode 100644 packages/oidc4vc/test/src/pkce_dart_test.dart create mode 100644 packages/oidc4vc/test/src/proof_header_type_test.dart create mode 100644 packages/oidc4vc/test/src/proof_type_test.dart create mode 100644 packages/oidc4vc/test/src/soipv2_draft_type_test.dart create mode 100644 packages/oidc4vc/test/src/vc_format_type_test.dart diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 53e516792..668bd74c7 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -1169,7 +1169,6 @@ class OIDC4VC { } late final bool isVerified; - if (kty == 'OKP') { isVerified = verifyTokenEdDSA( publicKey: publicKeyJwk, diff --git a/packages/oidc4vc/test/src/client_authentication_test.dart b/packages/oidc4vc/test/src/client_authentication_test.dart new file mode 100644 index 000000000..7bc7993a8 --- /dev/null +++ b/packages/oidc4vc/test/src/client_authentication_test.dart @@ -0,0 +1,15 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('ClientAuthenticationX', () { + test('value', () { + expect(ClientAuthentication.none.value, 'none'); + expect( + ClientAuthentication.clientSecretBasic.value, 'client_secret_basic'); + expect(ClientAuthentication.clientSecretPost.value, 'client_secret_post'); + expect(ClientAuthentication.clientId.value, 'client_id'); + expect(ClientAuthentication.clientSecretJwt.value, 'client_secret_jwt'); + }); + }); +} diff --git a/packages/oidc4vc/test/src/client_type_test.dart b/packages/oidc4vc/test/src/client_type_test.dart new file mode 100644 index 000000000..dd5de9522 --- /dev/null +++ b/packages/oidc4vc/test/src/client_type_test.dart @@ -0,0 +1,12 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('ClientTypeX', () { + test('getTitle', () { + expect(ClientType.p256JWKThumprint.getTitle, 'P-256 JWK Thumbprint'); + expect(ClientType.did.getTitle, 'DID'); + expect(ClientType.confidential.getTitle, 'Confidential Client'); + }); + }); +} diff --git a/packages/oidc4vc/test/src/const_values.dart b/packages/oidc4vc/test/src/const_values.dart index 3169cbc83..1eb369812 100644 --- a/packages/oidc4vc/test/src/const_values.dart +++ b/packages/oidc4vc/test/src/const_values.dart @@ -30,10 +30,12 @@ const keyWithAlg = { 'alg': 'HS256', }; -const didKey = 'did:ebsi:zo9FR1YfAKFP3Q6dvqhxcXxnfeDiJDP97kmnqhyAUSACj'; +const issuer = 'https://talao.co/issuer/zxhaokccsi'; -const kid = - '''did:ebsi:zo9FR1YfAKFP3Q6dvqhxcXxnfeDiJDP97kmnqhyAUSACj#Cgcg1y9xj9uWFw56PMc29XBd9EReixzvnftBz8JwQFiB'''; +const clientId = + '''did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9Kbrbpg5is8LfTLuQ1RsW5r7s7ZjbDDFbDgy1tLrdc7Bj3itBGQkuGUQyfzKhFqbUNW2PqJPMSSzWoF2DGSvDSijCtJtYCSRsjSVLrwu5oHNbnPFvSEC4iRZPpU6B6nExRBTa'''; + +const kid = ''; const ES256Alg = 'ES256'; @@ -41,40 +43,7 @@ const ES256KAlg = 'ES256K'; const HS256Alg = 'HS256'; -const thumbprint = [ - 173, - 150, - 139, - 1, - 202, - 186, - 32, - 132, - 51, - 6, - 216, - 230, - 103, - 154, - 26, - 196, - 52, - 23, - 248, - 132, - 91, - 7, - 58, - 174, - 149, - 38, - 148, - 157, - 199, - 122, - 118, - 36, -]; +const thumbprint = 'rZaLAcq6IIQzBtjmZ5oaxDQX+IRbBzqulSaUncd6diQ'; const rfc7638Jwk = { 'e': 'AQAB', @@ -83,37 +52,5 @@ const rfc7638Jwk = { // ignore: lines_longer_than_80_chars '0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw', }; -const expectedThumbprintForrfc7638Jwk = [ - 55, - 54, - 203, - 177, - 120, - 124, - 184, - 48, - 156, - 119, - 238, - 140, - 55, - 5, - 197, - 225, - 111, - 251, - 158, - 133, - 151, - 21, - 144, - 31, - 30, - 76, - 89, - 177, - 17, - 130, - 245, - 123, -]; +const expectedThumbprintForrfc7638Jwk = + 'NzbLsXh8uDCcd+6MNwXF4W/7noWXFZAfHkxZsRGC9Xs'; diff --git a/packages/oidc4vc/test/src/helper_function_test.dart b/packages/oidc4vc/test/src/helper_function_test.dart new file mode 100644 index 000000000..f6fbdd488 --- /dev/null +++ b/packages/oidc4vc/test/src/helper_function_test.dart @@ -0,0 +1,21 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/src/helper_function.dart'; + +void main() { + group('listToString', () { + test('converts list of strings to a single string with spaces', () { + final inputList = ['This', 'is', 'Bibash']; + expect(listToString(inputList), 'This is Bibash'); + }); + + test('converts list of numbers to a single string with spaces', () { + final inputList = [1, 2, 3, 4]; + expect(listToString(inputList), '1 2 3 4'); + }); + + test('returns empty string for empty input list', () { + final inputList = []; + expect(listToString(inputList), ''); + }); + }); +} diff --git a/packages/oidc4vc/test/src/issuer_token_parameters/issuer_token_parameters_class.dart b/packages/oidc4vc/test/src/issuer_token_parameters/issuer_token_parameters_class.dart index 5710dff77..bc4f2cbb5 100644 --- a/packages/oidc4vc/test/src/issuer_token_parameters/issuer_token_parameters_class.dart +++ b/packages/oidc4vc/test/src/issuer_token_parameters/issuer_token_parameters_class.dart @@ -1,41 +1,66 @@ -// import 'package:flutter_test/flutter_test.dart'; -// import 'package:oidc4vc/oidc4vc.dart'; - -// import '../const_values.dart'; -// import '../token_parameters/token_parameters_class.dart'; - -// class IssuerTokenParameterTest extends TokenParameterTest { -// final issuerTokenParameters = IssuerTokenParameters(privateKey, '', '', ''); - -// @override -// void publicKeyTest() { -// expect(issuerTokenParameters.publicJWK, publicJWK); -// } - -// @override -// void didTest() { -// expect(tokenParameters.did, didKey); -// } - -// @override -// void keyIdTest() { -// expect(tokenParameters.kid, kid); -// } - -// @override -// void algorithmIsES256KTest() { -// expect(tokenParameters.alg, ES256KAlg); -// } - -// @override -// void algorithmIsES256Test() { -// final tokenParameters = IssuerTokenParameters(privateKey2, '', '', ''); -// expect(tokenParameters.alg, ES256Alg); -// } - -// @override -// void algorithmIsNotNullTest() { -// final tokenParameters = IssuerTokenParameters(keyWithAlg, '', '', ''); -// expect(tokenParameters.alg, HS256Alg); -// } -// } +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +import '../const_values.dart'; +import '../token_parameters/token_parameters_class.dart'; + +class IssuerTokenParameterTest extends TokenParameterTest { + final issuerTokenParameters = IssuerTokenParameters( + privateKey: privateKey, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + issuer: issuer, + kid: '', + ); + + @override + void publicKeyTest() { + expect(issuerTokenParameters.publicJWK, publicJWK); + } + + @override + void didTest() { + expect(tokenParameters.did, clientId); + } + + @override + void keyIdTest() { + expect(tokenParameters.kid, kid); + } + + @override + void algorithmIsES256KTest() { + expect(tokenParameters.alg, ES256KAlg); + } + + @override + void algorithmIsES256Test() { + final tokenParameters = IssuerTokenParameters( + privateKey: privateKey2, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + issuer: issuer, + ); + expect(tokenParameters.alg, ES256Alg); + } + + @override + void algorithmIsNotNullTest() { + final tokenParameters = IssuerTokenParameters( + privateKey: keyWithAlg, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + issuer: issuer, + ); + expect(tokenParameters.alg, HS256Alg); + } +} diff --git a/packages/oidc4vc/test/src/issuer_token_parameters/issuer_token_parameters_test.dart b/packages/oidc4vc/test/src/issuer_token_parameters/issuer_token_parameters_test.dart index edbdf1e0c..5de3e5960 100644 --- a/packages/oidc4vc/test/src/issuer_token_parameters/issuer_token_parameters_test.dart +++ b/packages/oidc4vc/test/src/issuer_token_parameters/issuer_token_parameters_test.dart @@ -1,47 +1,47 @@ -// import 'package:flutter_test/flutter_test.dart'; - -// import 'issuer_token_parameters_class.dart'; - -// void main() { -// group('override test', () { -// final issuerTokenParameterTest = IssuerTokenParameterTest(); - -// // test( -// // 'public key is P-256K private key without d parameter', -// // issuerTokenParameterTest.publicKeyTest, -// // ); - -// // test('did EBSI', issuerTokenParameterTest.didTest); - -// // test('kID EBSI', issuerTokenParameterTest.keyIdTest); - -// group('algorithm test', () { -// test( -// "algorithm is ES256K when key's curve is not P-256", -// issuerTokenParameterTest.algorithmIsES256KTest, -// ); - -// test( -// "algorithm is ES256 when key's curve is P-256", -// issuerTokenParameterTest.algorithmIsES256Test, -// ); - -// test( -// 'if alg is not null then return as it is', -// issuerTokenParameterTest.algorithmIsNotNullTest, -// ); -// }); - -// // group('thumbprint test', () { -// // test( -// // 'thumbprint of the public Key', -// // issuerTokenParameterTest.thumprintOfKey, -// // ); - -// // test( -// // 'thumbrprint of the Key from exemple in rfc 7638', -// // issuerTokenParameterTest.thumprintOfKeyForrfc7638, -// // ); -// // }); -// }); -// } +import 'package:flutter_test/flutter_test.dart'; + +import 'issuer_token_parameters_class.dart'; + +void main() { + group('override test', () { + final issuerTokenParameterTest = IssuerTokenParameterTest(); + + test( + 'public key is P-256K private key without d parameter', + issuerTokenParameterTest.publicKeyTest, + ); + + test('did EBSI', issuerTokenParameterTest.didTest); + + test('kID EBSI', issuerTokenParameterTest.keyIdTest); + + group('algorithm test', () { + test( + "algorithm is ES256K when key's curve is not P-256", + issuerTokenParameterTest.algorithmIsES256KTest, + ); + + test( + "algorithm is ES256 when key's curve is P-256", + issuerTokenParameterTest.algorithmIsES256Test, + ); + + test( + 'if alg is not null then return as it is', + issuerTokenParameterTest.algorithmIsNotNullTest, + ); + }); + + group('thumbprint test', () { + test( + 'thumbprint of the public Key', + issuerTokenParameterTest.thumprintOfKey, + ); + + test( + 'thumbrprint of the Key from exemple in rfc 7638', + issuerTokenParameterTest.thumprintOfKeyForrfc7638, + ); + }); + }); +} diff --git a/packages/oidc4vc/test/src/media_type_test.dart b/packages/oidc4vc/test/src/media_type_test.dart new file mode 100644 index 000000000..5237155c2 --- /dev/null +++ b/packages/oidc4vc/test/src/media_type_test.dart @@ -0,0 +1,13 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('MediaTypeX', () { + test('typ', () { + expect(MediaType.proofOfOwnership.typ, 'openid4vci-proof+jwt'); + expect(MediaType.basic.typ, 'JWT'); + expect(MediaType.walletAttestation.typ, 'wiar+jwt'); + expect(MediaType.selectiveDisclosure.typ, 'kb+jwt'); + }); + }); +} diff --git a/packages/oidc4vc/test/src/oidc4vc_test.dart b/packages/oidc4vc/test/src/oidc4vc_test.dart index 484279b95..04413c91c 100644 --- a/packages/oidc4vc/test/src/oidc4vc_test.dart +++ b/packages/oidc4vc/test/src/oidc4vc_test.dart @@ -250,8 +250,10 @@ void main() { ); expect(authorizationEndpoint, expectedAuthorizationEndpoint); - expect(authorizationRequestParemeters, - expectedAuthorizationRequestParemeters); + expect( + authorizationRequestParemeters, + expectedAuthorizationRequestParemeters, + ); }, ); @@ -467,399 +469,293 @@ void main() { }); }); - // group('getIssuer', () { - // final oidc4vc = OIDC4VC(client); - // test('get issuer with credentialRequestUri', () { - // const expectedIssuer = - // 'https://talao.co/sandbox/ebsi/issuer/vgvghylozl'; - // final issuer = oidc4vc.getIssuer(credentialRequest); - // expect(expectedIssuer, issuer); - // }); - - // test( - // 'get issuer with credentialRequestUri when PreAuthorizedCode is given', // ignore: lines_longer_than_80_chars - // () { - // const expectedIssuer = - // 'https://talao.co/sandbox/ebsi/issuer/vgvghylozl'; - // final issuer = - // oidc4vc.getIssuer(credentialRequestWithPreAuthorizedCode); - // expect(expectedIssuer, issuer); - // }); - // }); - - // test('get readTokenEndPoint with openidConfigurationResponse', () async { - // const openidConfigurationResponse = - // r'{"authorization_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/authorize","batch_credential_endpoint":null,"credential_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/credential","credential_issuer":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl","credential_manifests":[{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"display":{"description":{"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework.","path":[],"schema":{"type":"string"}},"properties":[{"fallback":"Unknown","label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number"}},{"fallback":"Unknown","label":"Issue date","path":["$.issuanceDate"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"format":"uri","type":"string"}}],"subtitle":{"fallback":"EBSI Verifiable diploma","path":[],"schema":{"type":"string"}},"title":{"fallback":"Diploma","path":[],"schema":{"type":"string"}}},"id":"diploma_01","schema":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"spec_version":"https://identity.foundation/credential-manifest/spec/v1.0.0/"}],"credential_supported":[{"cryptographic_binding_methods_supported":["did"],"cryptographic_suites_supported":["ES256K","ES256","ES384","ES512","RS256"],"display":[{"locale":"en-US","name":"Issuer Talao"}],"format":"jwt_vc","id":"VerifiableDiploma","types":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"pre-authorized_grant_anonymous_access_supported":true,"subject_syntax_types_supported":["did:ebsi"],"token_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/token"}'; - - // final oidc4vc = OIDC4VC(client); - - // final issuer = oidc4vc.readTokenEndPoint( - // Response( - // requestOptions: RequestOptions(path: ''), - // data: jsonDecode(openidConfigurationResponse) as Map, - // ), - // ); - // expect(issuer, tokenUrl); - // }); - - // test('get issuer did with openidConfigurationResponse', () { - // const openidConfigurationResponse = - // r'{"authorization_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/authorize","batch_credential_endpoint":null,"credential_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/credential","credential_issuer":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl","credential_manifests":[{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"display":{"description":{"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework.","path":[],"schema":{"type":"string"}},"properties":[{"fallback":"Unknown","label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number"}},{"fallback":"Unknown","label":"Issue date","path":["$.issuanceDate"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"format":"uri","type":"string"}}],"subtitle":{"fallback":"EBSI Verifiable diploma","path":[],"schema":{"type":"string"}},"title":{"fallback":"Diploma","path":[],"schema":{"type":"string"}}},"id":"diploma_01","schema":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"spec_version":"https://identity.foundation/credential-manifest/spec/v1.0.0/"}],"credential_supported":[{"cryptographic_binding_methods_supported":["did"],"cryptographic_suites_supported":["ES256K","ES256","ES384","ES512","RS256"],"display":[{"locale":"en-US","name":"Issuer Talao"}],"format":"jwt_vc","id":"VerifiableDiploma","types":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"},{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"display":{"description":{"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework.","path":[],"schema":{"type":"string"}},"properties":[{"fallback":"Unknown","label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number"}},{"fallback":"Unknown","label":"Issue date","path":["$.issuanceDate"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"format":"uri","type":"string"}}],"subtitle":{"fallback":"EBSI Verifiable diploma","path":[],"schema":{"type":"string"}},"title":{"fallback":"Diploma","path":[],"schema":{"type":"string"}}},"id":"diploma_01","schema":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"spec_version":"https://identity.foundation/credential-manifest/spec/v1.0.0/"}],"credential_supported":[{"cryptographic_binding_methods_supported":["did"],"cryptographic_suites_supported":["ES256K","ES256","ES384","ES512","RS256"],"display":[{"locale":"en-US","name":"Issuer Talao"}],"format":"jwt_vc","id":"VerifiableDiploma","types":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"pre-authorized_grant_anonymous_access_supported":true,"subject_syntax_types_supported":["did:ebsi"],"token_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/token"}'; - // final oidc4vc = OIDC4VC(client); - - // final issuer = oidc4vc.readIssuerDid( - // Response( - // requestOptions: RequestOptions(path: ''), - // data: jsonDecode(openidConfigurationResponse) as Map, - // ), - // ); - // expect(issuer, 'did:ebsi:zhSw5rPXkcHjvquwnVcTzzB'); - // }); - - // test('get publicKey did with didDocumentResponse', () { - // const didDocumentResponse = - // '{"assertionMethod":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"authentication":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"@context":"https://www.w3.org/ns/did/v1","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","verificationMethod":[{"controller":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53","publicKeyJwk":{"alg":"EdDSA","crv":"Ed25519","kid":"3623b877bbb24b08ba390f3585418f53","kty":"OKP","use":"sig","x":"pWgA8M3etXlLaqcRmgjEQkz7waseg3FKzMCzfm9Yeow"},"type":"Ed25519VerificationKey2019"}]}'; - // const issuerDid = 'did:ebsi:zeFCExU2XAAshYkPCpjuahA'; - - // const expectedPublicKey = - // '{"alg":"EdDSA","crv":"Ed25519","kid":"3623b877bbb24b08ba390f3585418f53","kty":"OKP","use":"sig","x":"pWgA8M3etXlLaqcRmgjEQkz7waseg3FKzMCzfm9Yeow"}'; // ignore: lines_longer_than_80_chars - - // final oidc4vc = OIDC4VC(client); - - // final publicKey = oidc4vc.readPublicKeyJwk( - // issuerDid, - // Response( - // requestOptions: RequestOptions(path: ''), - // data: jsonDecode(didDocumentResponse) as Map, - // ), - // ); - // expect(jsonEncode(publicKey), expectedPublicKey); - // }); - // }); - - // group('verify encoded data', () { - // const issuerDid1 = 'did:ebsi:zeFCExU2XAAshYkPCpjuahA'; - // const issuerDid2 = 'did:ebsi:zhSw5rPXkcHjvquwnVcTzzC'; - // const issuerDid3 = 'did:ebsi:zhSw5rPXkcHjvquwnVcTzzC'; - - // const issuerKid = - // 'did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53'; - - // const didDocumentUrl = - // 'https://api-pilot.oidc4vc.eu/did-registry/v3/identifiers/$issuerDid1'; - - // const didDocumentResponse = - // '{"assertionMethod":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"authentication":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"@context":"https://www.w3.org/ns/did/v1","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","verificationMethod":[{"controller":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53","publicKeyJwk":{"crv":"P-521","kty":"EC","x":"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk","y":"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDly79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2"},"type":"Ed25519VerificationKey2019"}]}'; - - // const didDocumentUrl2 = - // 'https://api-pilot.oidc4vc.eu/did-registry/v3/identifiers/$issuerDid2'; - - // const didDocumentResponse2 = - // '{"assertionMethod":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"authentication":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"@context":"https://www.w3.org/ns/did/v1","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","verificationMethod":[{"controller":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53","publicKeyJwk":{"crv":"Ed25519","kty":"OKP","x":"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk","y":"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDly79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2"},"type":"Ed25519VerificationKey2019"}]}'; - - // const didDocumentUrl3 = - // 'https://api-pilot.oidc4vc.eu/did-registry/v3/identifiers/$issuerDid3'; - - // const didDocumentResponse3 = - // '{"assertionMethod":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"authentication":["did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53"],"@context":"https://www.w3.org/ns/did/v1","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","verificationMethod":[{"controller":"did:ebsi:zeFCExU2XAAshYkPCpjuahA","id":"did:ebsi:zeFCExU2XAAshYkPCpjuahA#3623b877bbb24b08ba390f3585418f53","publicKeyJwk":{"alg":"EdDSA","crv":"Ed25519","kid":"-1909572257","kty":"OKP","x":"XWxGtApfcqmKI7p0OKnF5JSEWMVoLsytFXLEP7xZ_l8"},"type":"Ed25519VerificationKey2019"}]}'; - // dioAdapter - // ..onGet( - // didDocumentUrl, - // (request) => request.reply(200, jsonDecode(didDocumentResponse)), - // ) - // ..onGet( - // didDocumentUrl2, - // (request) => request.reply(200, jsonDecode(didDocumentResponse2)), - // ) - // ..onGet( - // didDocumentUrl3, - // (request) => request.reply(200, jsonDecode(didDocumentResponse3)), - // ); - - // final oidc4vc = OIDC4VC(client); - // test('returns VerificationType.verified', () async { - // const vcJwt = 'eyJhbGciOiJFUzUxMiJ9.' - // 'UGF5bG9hZA.' - // 'AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZq' - // 'wqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8Kp' - // 'EHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn'; - - // final isVerified = await oidc4vc.verifyEncodedData( - // issuerDid: issuerDid1, - // jwt: vcJwt, - // issuerKid: issuerKid, - // ); - - // expect(isVerified, VerificationType.verified); - // }); - - // test('returns VerificationType.notVerified', () async { - // const vcJwt = - // 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksiLCJqd2siOnsiY3J2IjoiUC0yNTZLIiwia3R5IjoiRUMiLCJ4IjoiSjR2UXRMVXlyVlVpRklYUnJ0RXE0eHVybUJacDJlcTl3Sm1Ya0lBX3N0SSIsInkiOiJFVVU2dlhvRzNCR1gyenp3alhyR0RjcjRFeUREMFZmazNfNWZnNWtTZ0tFIn0sImtpZCI6ImRpZDplYnNpOnpvOUZSMVlmQUtGUDNRNmR2cWh4Y1h4bmZlRGlKRFA5N2ttbnFoeUFVU0FDaiNDZ2NnMXk5eGo5dVdGdzU2UE1jMjlYQmQ5RVJlaXh6dm5mdEJ6OEp3UUZpQiJ9.eyJpc3MiOiJkaWQ6ZWJzaTp6bzlGUjFZZkFLRlAzUTZkdnFoeGNYeG5mZURpSkRQOTdrbW5xaHlBVVNBQ2oiLCJub25jZSI6IjdhMDdkZTBmLWE4NzktMTFlZC04MjJiLTBhMTYyODk1ODU2MCIsImlhdCI6MTY3NzA1MDc0MDEyMzIzNSwiYXVkIjoiaHR0cHM6Ly90YWxhby5jby9zYW5kYm94L2Vic2kvaXNzdWVyL3ZndmdoeWxvemwifQ.htjRCpFWbRwanAyQcAq9XZ4vxCXyFbzaaN3yPbPxWIcKFFzDDcA4QCHTUl-L4vzWq0R3LSgQFXQ9bo5D9uCm4w'; // ignore: lines_longer_than_80_chars - - // final isVerified = await oidc4vc.verifyEncodedData( - // issuerDid: issuerDid1, - // jwt: vcJwt, - // issuerKid: issuerKid, - // ); - - // expect(isVerified, VerificationType.notVerified); - // }); - - // test('returns VerificationType.unKnown', () async { - // const vcJwt = 'random'; - - // final isVerified = await oidc4vc.verifyEncodedData( - // issuerDid: issuerDid2, - // jwt: vcJwt, - // issuerKid: issuerKid, - // ); - // expect(isVerified, VerificationType.unKnown); - // }); - - // test('returns VerificationType.notVerified for OKP', () async { - // const vcJwt = 'eyJraWQiOiItMTkwOTU3MjI1NyIsImFsZyI6IkVkRFNBIn0.' - // 'eyJqdGkiOiIyMjkxNmYzYy05MDkzLTQ4MTMtODM5Ny1mMTBlNmI3MDRiNjgiLCJkZWxlZ2F0aW9uSWQiOiJiNGFlNDdhNy02MjVhLTQ2MzAtOTcyNy00NTc2NGE3MTJjY2UiLCJleHAiOjE2NTUyNzkxMDksIm5iZiI6MTY1NTI3ODgwOSwic2NvcGUiOiJyZWFkIG9wZW5pZCIsImlzcyI6Imh0dHBzOi8vaWRzdnIuZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VybmFtZSIsImF1ZCI6ImFwaS5leGFtcGxlLmNvbSIsImlhdCI6MTY1NTI3ODgwOSwicHVycG9zZSI6ImFjY2Vzc190b2tlbiJ9.' // ignore: lines_longer_than_80_chars - // 'rjeE8D_e4RYzgvpu-nOwwx7PWMiZyDZwkwO6RiHR5t8g4JqqVokUKQt-oST1s45wubacfeDSFogOrIhe3UHDAg'; // ignore: lines_longer_than_80_chars - - // final isVerified = await oidc4vc.verifyEncodedData( - // issuerDid: issuerDid3, - // jwt: vcJwt, - // issuerKid: issuerKid, - // ); - // expect(isVerified, VerificationType.verified); - // }); - // }); - - // group('getCredentialRequest', () { - // final oidc4vc = OIDC4VC(client); - - // test('extract correct credential type url from openId', () async { - // final url = oidc4vc.getCredentialRequest(givenOpenIdRequest); - // expect( - // url, - // 'https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd', - // ); - // }); - - // test('credential type url is empty when url is not OK', () async { - // final url = oidc4vc.getCredentialRequest('www.example.com'); - // expect(url, ''); - // }); - // }); - - // test('extract correct credential type url from openId', () async { - // final oidc4vc = OIDC4VC(client); - // final url = oidc4vc.getCredentialRequest(givenOpenIdRequest); - // expect( - // url, - // 'https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd', - // ); - // }); - - // group('get token', () { - // test('get correct token ', () async { - // final oidc4vc = OIDC4VC(client); - - // final json = { - // 'code': 'cb803d46-9c88-11ed-bdb3-0a1628958560', - // 'grant_type': 'authorization_code' - // }; - - // const expectedValue = - // '{"access_token":"7a07dd19-a879-11ed-ad95-0a1628958560","c_nonce":"7a07de0f-a879-11ed-822b-0a1628958560","token_type":"Bearer","expires_in":1000}'; // ignore: lines_longer_than_80_chars - - // final token = await oidc4vc.getToken(tokenUrl, json); - // expect(jsonEncode(token), expectedValue); - // }); - - // test('throw expection when invalid value is sent', () async { - // expect( - // () async { - // dioAdapter.onPost( - // tokenUrl, - // (request) => request.throws( - // 401, - // DioException(requestOptions: RequestOptions(path: tokenUrl)), - // ), - // ); - // final oidc4vc = OIDC4VC(client); - - // final json = {}; - - // await oidc4vc.getToken(tokenUrl, json); - // }, - // throwsA(isA()), - // ); - // }); - // }); - - // group('get did', () { - // final oidc4vc = OIDC4VC(client); - - // const expectedDidP256K = - // 'did:ebsi:zo9FR1YfAKFP3Q6dvqhxcXxnfeDiJDP97kmnqhyAUSACj'; - // test('from mnemonic ', () async { - // final did = await oidc4vc.getDidFromMnemonic(mnemonic, null); - // expect(did, expectedDidP256K); - // }); - - // test('from P-256K privateKey ', () async { - // const key = { - // 'crv': 'P-256K', - // 'd': 'ccWWNSjGiv1iWlNh4kfhWvwG3yyQMe8o31Du0uKRzrs', - // 'kty': 'EC', - // 'x': 'J4vQtLUyrVUiFIXRrtEq4xurmBZp2eq9wJmXkIA_stI', - // 'y': 'EUU6vXoG3BGX2zzwjXrGDcr4EyDD0Vfk3_5fg5kSgKE' - // }; - // final did = await oidc4vc.getDidFromMnemonic(null, jsonEncode(key)); - // expect(did, expectedDidP256K); - // }); - // test('from secp256k1 privateKey ', () async { - // const expectedDidsecp256k1 = - // 'did:ebsi:zfuA5yVRZVaKna9pRCHv28yyCYWiXWHZXXvtp3AbTdB4p'; - // const key = { - // 'crv': 'secp256k1', - // 'd': 'jMudzhP9YFNywIeIYYJbHtyizeaXOa1PWdX-qBjPTg8', - // 'kty': 'EC', - // 'x': 'yEC4JxUbpYx2-tKExh2NrLpETx-nnudZfcg4AcyL1to', - // 'y': 'HNh3aF4zQsnf_sFXUVaSzrQF85veDoVxhPQ-163wUYM' - // }; - // final did = await oidc4vc.getDidFromMnemonic(null, jsonEncode(key)); - // expect(did, expectedDidsecp256k1); - // }); - - // group('send Presentation', () { - // const url = - // 'https://talao.co/sandbox/ebsi/login/endpoint/f1722b9e-ae19-11ed-ac9f-0a1628958560'; - - // final uri = Uri.parse( - // 'openid://?scope=openid&response_type=id_token&client_id=xjcqarovuv&redirect_uri=https%3A%2F%2Ftalao.co%2Fsandbox%2Febsi%2Flogin%2Fendpoint%2Ff1722b9e-ae19-11ed-ac9f-0a1628958560&claims=%7B%27id_token%27%3A+%7B%27email%27%3A+None%7D%2C+%27vp_token%27%3A+%7B%27presentation_definition%27%3A+%7B%27id%27%3A+%27f17247aa-ae19-11ed-9241-0a1628958560%27%2C+%27input_descriptors%27%3A+%5B%7B%27constraints%27%3A+%7B%27fields%27%3A+%5B%7B%27path%27%3A+%5B%27%24.credentialSchema.id%27%5D%2C+%27filter%27%3A+%7B%27type%27%3A+%27string%27%2C+%27pattern%27%3A+%27https%3A%2F%2Fapi.preprod.oidc4vc.eu%2Ftrusted-schemas-registry%2Fv1%2Fschemas%2F0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd%27%7D%7D%5D%7D%2C+%27id%27%3A+%27f1724e6c-ae19-11ed-a3cf-0a1628958560%27%2C+%27name%27%3A+%27Input+descriptor+1%27%2C+%27purpose%27%3A+%27+%27%7D%5D%2C+%27format%27%3A+%7B%27jwt_vp%27%3A+%7B%27alg%27%3A+%5B%27ES256K%27%2C+%27ES256%27%2C+%27PS256%27%2C+%27RS256%27%5D%7D%7D%7D%7D%7D&nonce=f17239d6-ae19-11ed-8550-0a1628958560', - // ); - - // final credentialToBePresented = [ - // r'{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","receivedId":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","image":null,"data":{"@context":["https://www.w3.org/2018/credentials/v1"],"credentialSchema":{"id":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","type":"JsonSchemaValidator2018"},"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020"},"credentialSubject":{"awardingOpportunity":{"awardingBody":{"eidasLegalIdentifier":"Unknown","homepage":"https://leaston.bcdiploma.com/","id":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","preferredName":"Leaston University","registration":"0597065J"},"endedAtTime":"2020-06-26T00:00:00Z","id":"https://leaston.bcdiploma.com/law-economics-management#AwardingOpportunity","identifier":"https://certificate-demo.bcdiploma.com/check/87ED2F2270E6C41456E94B86B9D9115B4E35BCCAD200A49B846592C14F79C86BV1Fnbllta0NZTnJkR3lDWlRmTDlSRUJEVFZISmNmYzJhUU5sZUJ5Z2FJSHpWbmZZ","location":"FRANCE","startedAtTime":"2019-09-02T00:00:00Z"},"dateOfBirth":"1993-04-08","familyName":"DOE","givenNames":"Jane","gradingScheme":{"id":"https://leaston.bcdiploma.com/law-economics-management#GradingScheme","title":"2 year full-time programme / 4 semesters"},"id":"did:ebsi:zhFWcvr8DFL3cAVdheCpjHg3sPn1WUh9Gynm6hevPFzpw","identifier":"0904008084H","learningAchievement":{"additionalNote":["DISTRIBUTION MANAGEMENT"],"description":"The Master in Information and Computer Sciences (MICS) at the University of Luxembourg enables students to acquire deeper knowledge in computer science by understanding its abstract and interdisciplinary foundations, focusing on problem solving and developing lifelong learning skills.","id":"https://leaston.bcdiploma.com/law-economics-management#LearningAchievment","title":"Master in Information and Computer Sciences"},"learningSpecification":{"ectsCreditPoints":120,"eqfLevel":7,"id":"https://leaston.bcdiploma.com/law-economics-management#LearningSpecification","iscedfCode":["7"],"nqfLevel":["7"]},"type":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"},"evidence":{"documentPresence":["Physical"],"evidenceDocument":["Passport"],"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","subjectPresence":"Physical","type":["DocumentVerification"],"verifier":"did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a"},"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","issuanceDate":"2023-02-16T12:04:19Z","issued":"2023-02-16T12:04:19Z","issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","proof":{"created":"2022-04-27T12:25:07Z","creator":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","domain":"https://api.preprod.oidc4vc.eu","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ","nonce":"3ea68dae-d07a-4daa-932b-fbb58f5c20c4","type":"EcdsaSecp256k1Signature2019"},"type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"validFrom":"2023-02-16T12:04:19Z"},"shareLink":"","credentialPreview":{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","description":[],"name":[],"issuanceDate":"2023-02-16T12:04:19Z","proof":[{"type":"EcdsaSecp256k1Signature2019","proofPurpose":null,"verificationMethod":null,"created":"2022-04-27T12:25:07Z","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ"}],"credentialSubject":{"id":"did:ebsi:zhFWcvr8DFL3cAVdheCpjHg3sPn1WUh9Gynm6hevPFzpw","type":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","issuedBy":{"name":""},"expires":"","awardingOpportunity":{"awardingBody":{"eidasLegalIdentifier":"Unknown","homepage":"https://leaston.bcdiploma.com/","id":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","preferredName":"Leaston University","registration":"0597065J"},"endedAtTime":"2020-06-26T00:00:00Z","id":"https://leaston.bcdiploma.com/law-economics-management#AwardingOpportunity","identifier":"https://certificate-demo.bcdiploma.com/check/87ED2F2270E6C41456E94B86B9D9115B4E35BCCAD200A49B846592C14F79C86BV1Fnbllta0NZTnJkR3lDWlRmTDlSRUJEVFZISmNmYzJhUU5sZUJ5Z2FJSHpWbmZZ","location":"FRANCE","startedAtTime":"2019-09-02T00:00:00Z"},"dateOfBirth":"1993-04-08","familyName":"DOE","givenNames":"Jane","gradingScheme":{"id":"https://leaston.bcdiploma.com/law-economics-management#GradingScheme","title":"2 year full-time programme / 4 semesters"},"identifier":"0904008084H","learningAchievement":{"additionalNote":["DISTRIBUTION MANAGEMENT"],"description":"The Master in Information and Computer Sciences (MICS) at the University of Luxembourg enables students to acquire deeper knowledge in computer science by understanding its abstract and interdisciplinary foundations, focusing on problem solving and developing lifelong learning skills.","id":"https://leaston.bcdiploma.com/law-economics-management#LearningAchievment","title":"Master in Information and Computer Sciences"},"learningSpecification":{"ectsCreditPoints":120,"eqfLevel":7,"id":"https://leaston.bcdiploma.com/law-economics-management#LearningSpecification","iscedfCode":["7"],"nqfLevel":["7"]}},"evidence":[{"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","type":["DocumentVerification"]}],"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020","revocationListIndex":"","revocationListCredential":""}},"display":{"backgroundColor":"","icon":"","nameFallback":"","descriptionFallback":""},"expirationDate":null,"credential_manifest":{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"id":"diploma_01","schema":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","name":null,"description":null,"styles":null,"display":{"title":{"path":[],"schema":{"type":"string","format":null},"fallback":"Diploma"},"subtitle":{"path":[],"schema":{"type":"string","format":null},"fallback":"EBSI Verifiable diploma"},"description":{"path":[],"schema":{"type":"string","format":null},"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework."},"properties":[{"label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number","format":null},"fallback":"Unknown"},{"label":"Issue date","path":["$.issuanceDate"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"type":"string","format":"uri"},"fallback":"Unknown"}]}}],"presentation_definition":null},"challenge":null,"domain":null,"activities":[{"acquisitionAt":"2023-02-16T17:34:24.679713","presentation":null},{"acquisitionAt":null,"presentation":{"issuer":{"preferredName":"","did":[],"organizationInfo":{"id":"","legalName":"","currentAddress":"","website":"domain","issuerDomain":[]}},"presentedAt":"2023-02-16T17:34:47.206600"}}],"jwt":"eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiM1MTVhOWM0MzZjMGYyYWQzYWI2NWQ2Y2VmYzVjMWYwNmMwNWI4YWRmY2Y1NGVlMDZkYzgwNTQzMjA0NzBmZmFmIiwidHlwIjoiSldUIn0.eyJleHAiOjE2NzY1NTAwNTkuMjMzMzY3LCJpYXQiOjE2NzY1NDkwNTkuMjMzMzYsImlzcyI6ImRpZDplYnNpOnpoU3c1clBYa2NIanZxdXduVmNUenpCIiwianRpIjoidXJuOnV1aWQ6NmIxZDg0MTEtOWVkNS00NTY2LTljN2YtNGMyNDE2NWZmMjM2IiwibmJmIjoxNjc2NTQ5MDU5LjIzMzM2NCwibm9uY2UiOiIwYTc4MDg2MC1hZGYyLTExZWQtYmIzZS0wYTE2Mjg5NTg1NjAiLCJzdWIiOiJkaWQ6ZWJzaTp6aEZXY3ZyOERGTDNjQVZkaGVDcGpIZzNzUG4xV1VoOUd5bm02aGV2UEZ6cHciLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9hcGkucHJlcHJvZC5lYnNpLmV1L3RydXN0ZWQtc2NoZW1hcy1yZWdpc3RyeS92MS9zY2hlbWFzLzB4YmY3OGZjMDhhN2E5ZjI4ZjU0NzlmNThkZWEyNjlkMzY1N2Y1NGYxM2NhMzdkMzgwY2Q0ZTkyMjM3ZmI2OTFkZCIsInR5cGUiOiJKc29uU2NoZW1hVmFsaWRhdG9yMjAxOCJ9LCJjcmVkZW50aWFsU3RhdHVzIjp7ImlkIjoiaHR0cHM6Ly9lc3NpZi5ldXJvcGEuZXUvc3RhdHVzL2VkdWNhdGlvbiNoaWdoZXJFZHVjYXRpb24jMzkyYWM3ZjYtMzk5YS00MzdiLWEyNjgtNDY5MWVhZDhmMTc2IiwidHlwZSI6IkNyZWRlbnRpYWxTdGF0dXNMaXN0MjAyMCJ9LCJjcmVkZW50aWFsU3ViamVjdCI6eyJhd2FyZGluZ09wcG9ydHVuaXR5Ijp7ImF3YXJkaW5nQm9keSI6eyJlaWRhc0xlZ2FsSWRlbnRpZmllciI6IlVua25vd24iLCJob21lcGFnZSI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tLyIsImlkIjoiZGlkOmVic2k6emRSdnZLYlhoVlZCc1hoYXRqdWlCaHMiLCJwcmVmZXJyZWROYW1lIjoiTGVhc3RvbiBVbml2ZXJzaXR5IiwicmVnaXN0cmF0aW9uIjoiMDU5NzA2NUoifSwiZW5kZWRBdFRpbWUiOiIyMDIwLTA2LTI2VDAwOjAwOjAwWiIsImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0F3YXJkaW5nT3Bwb3J0dW5pdHkiLCJpZGVudGlmaWVyIjoiaHR0cHM6Ly9jZXJ0aWZpY2F0ZS1kZW1vLmJjZGlwbG9tYS5jb20vY2hlY2svODdFRDJGMjI3MEU2QzQxNDU2RTk0Qjg2QjlEOTExNUI0RTM1QkNDQUQyMDBBNDlCODQ2NTkyQzE0Rjc5Qzg2QlYxRm5ibGx0YTBOWlRuSmtSM2xEV2xSbVREbFNSVUpFVkZaSVNtTm1ZekpoVVU1c1pVSjVaMkZKU0hwV2JtWloiLCJsb2NhdGlvbiI6IkZSQU5DRSIsInN0YXJ0ZWRBdFRpbWUiOiIyMDE5LTA5LTAyVDAwOjAwOjAwWiJ9LCJkYXRlT2ZCaXJ0aCI6IjE5OTMtMDQtMDgiLCJmYW1pbHlOYW1lIjoiRE9FIiwiZ2l2ZW5OYW1lcyI6IkphbmUiLCJncmFkaW5nU2NoZW1lIjp7ImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0dyYWRpbmdTY2hlbWUiLCJ0aXRsZSI6IjIgeWVhciBmdWxsLXRpbWUgcHJvZ3JhbW1lIC8gNCBzZW1lc3RlcnMifSwiaWQiOiJkaWQ6ZWJzaTp6aEZXY3ZyOERGTDNjQVZkaGVDcGpIZzNzUG4xV1VoOUd5bm02aGV2UEZ6cHciLCJpZGVudGlmaWVyIjoiMDkwNDAwODA4NEgiLCJsZWFybmluZ0FjaGlldmVtZW50Ijp7ImFkZGl0aW9uYWxOb3RlIjpbIkRJU1RSSUJVVElPTiBNQU5BR0VNRU5UIl0sImRlc2NyaXB0aW9uIjoiVGhlIE1hc3RlciBpbiBJbmZvcm1hdGlvbiBhbmQgQ29tcHV0ZXIgU2NpZW5jZXMgKE1JQ1MpIGF0IHRoZSBVbml2ZXJzaXR5IG9mIEx1eGVtYm91cmcgZW5hYmxlcyBzdHVkZW50cyB0byBhY3F1aXJlIGRlZXBlciBrbm93bGVkZ2UgaW4gY29tcHV0ZXIgc2NpZW5jZSBieSB1bmRlcnN0YW5kaW5nIGl0cyBhYnN0cmFjdCBhbmQgaW50ZXJkaXNjaXBsaW5hcnkgZm91bmRhdGlvbnMsIGZvY3VzaW5nIG9uIHByb2JsZW0gc29sdmluZyBhbmQgZGV2ZWxvcGluZyBsaWZlbG9uZyBsZWFybmluZyBza2lsbHMuIiwiaWQiOiJodHRwczovL2xlYXN0b24uYmNkaXBsb21hLmNvbS9sYXctZWNvbm9taWNzLW1hbmFnZW1lbnQjTGVhcm5pbmdBY2hpZXZtZW50IiwidGl0bGUiOiJNYXN0ZXIgaW4gSW5mb3JtYXRpb24gYW5kIENvbXB1dGVyIFNjaWVuY2VzIn0sImxlYXJuaW5nU3BlY2lmaWNhdGlvbiI6eyJlY3RzQ3JlZGl0UG9pbnRzIjoxMjAsImVxZkxldmVsIjo3LCJpZCI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tL2xhdy1lY29ub21pY3MtbWFuYWdlbWVudCNMZWFybmluZ1NwZWNpZmljYXRpb24iLCJpc2NlZGZDb2RlIjpbIjciXSwibnFmTGV2ZWwiOlsiNyJdfX0sImV2aWRlbmNlIjp7ImRvY3VtZW50UHJlc2VuY2UiOlsiUGh5c2ljYWwiXSwiZXZpZGVuY2VEb2N1bWVudCI6WyJQYXNzcG9ydCJdLCJpZCI6Imh0dHBzOi8vZXNzaWYuZXVyb3BhLmV1L3Rzci12YS9ldmlkZW5jZS9mMmFlZWM5Ny1mYzBkLTQyYmYtOGNhNy0wNTQ4MTkyZDU2NzgiLCJzdWJqZWN0UHJlc2VuY2UiOiJQaHlzaWNhbCIsInR5cGUiOlsiRG9jdW1lbnRWZXJpZmljYXRpb24iXSwidmVyaWZpZXIiOiJkaWQ6ZWJzaToyOTYyZmI3ODRkZjYxYmFhMjY3YzgxMzI0OTc1MzlmOGM2NzRiMzdjMTI0NGE3YSJ9LCJpZCI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsImlzc3VhbmNlRGF0ZSI6IjIwMjMtMDItMTZUMTI6MDQ6MTlaIiwiaXNzdWVkIjoiMjAyMy0wMi0xNlQxMjowNDoxOVoiLCJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsInByb29mIjp7ImNyZWF0ZWQiOiIyMDIyLTA0LTI3VDEyOjI1OjA3WiIsImNyZWF0b3IiOiJkaWQ6ZWJzaTp6ZFJ2dktiWGhWVkJzWGhhdGp1aUJocyIsImRvbWFpbiI6Imh0dHBzOi8vYXBpLnByZXByb2QuZWJzaS5ldSIsImp3cyI6ImV5SmlOalFpT21aaGJITmxMQ0pqY21sMElqcGJJbUkyTkNKZExDSmhiR2NpT2lKRlV6STFOa3NpZlEuLm1JQm5NOFhEUXFTWUtRTlhfTHZhSmhtc2J5Q3I1T1o1Y1UyWmstUmVxTHByNGRvRnNnbW9vYmtPNTEyOHRaeS04S2ltVmpKa0d3MHdMMXVCV25NTFdRIiwibm9uY2UiOiIzZWE2OGRhZS1kMDdhLTRkYWEtOTMyYi1mYmI1OGY1YzIwYzQiLCJ0eXBlIjoiRWNkc2FTZWNwMjU2azFTaWduYXR1cmUyMDE5In0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJWZXJpZmlhYmxlQXR0ZXN0YXRpb24iLCJWZXJpZmlhYmxlRGlwbG9tYSJdLCJ2YWxpZEZyb20iOiIyMDIzLTAyLTE2VDEyOjA0OjE5WiJ9fQ.7Bmdrkp-hpM7BcNASc7ngjia3cjrZr-nqmP0Plsfnefn26G_yR5fBJV8BT_U2zsMlcqWsxuJ9pS2Vyiq_SrooQ"}' - // ]; - - // test('successfully send presentation', () async { - // const response = - // '{"access":"ok","created":1676566727.680238,"credential_status":"signature check bypassed","holder_did_status":"ok","id_token_status":"ok","qrcode_status":"ok","response_format":"ok","status_code":200,"vp_token_status":"ok"}'; // ignore: lines_longer_than_80_chars - // dioAdapter.onGet( - // url, - // (request) => request.reply(200, jsonDecode(response)), - // ); - // final oidc4vc = OIDC4VC(client); - - // expect( - // () async { - // await oidc4vc.sendPresentation( - // uri, - // credentialToBePresented, - // mnemonic, - // null, - // ); - // }, - // returnsNormally, - // ); - // }); - - // test('throw exception', () async { - // expect( - // () async { - // dioAdapter.onPost( - // url, - // (request) => request.throws( - // 401, - // DioException(requestOptions: RequestOptions(path: tokenUrl)), - // ), - // ); - // final oidc4vc = OIDC4VC(client); - - // await oidc4vc.sendPresentation( - // uri, - // credentialToBePresented, - // mnemonic, - // null, - // ); - // }, - // throwsA(isA()), - // ); - // }); - // }); - // }); - - // test('get corresponding did document', () async { - // const url = - // 'https://api-pilot.oidc4vc.eu/did-registry/v3/identifiers/$didKey'; - // const response = { - // '@context': 'https://w3id.org/did/v1', - // 'id': 'did:ebsi:z24q8qN8UE1j4XAFiFKtvJbH', - // 'verificationMethod': [ - // { - // 'id': 'did:ebsi:z24q8qN8UE1j4XAFiFKtvJbH#keys-1', - // 'type': 'Secp256k1VerificationKey2018', - // 'controller': 'did:ebsi:z24q8qN8UE1j4XAFiFKtvJbH', - // 'publicKeyHex': - // '04f9139fbd3b9780863b17e8390934a1017fc8d0f18b84f02acb04f24c9cae261e45745c6507881509b9e6d837329153ea75fafb2c1a5d504702d04f1e22a80ecc' // ignore: lines_longer_than_80_chars - // } - // ], - // 'authentication': ['did:ebsi:z24q8qN8UE1j4XAFiFKtvJbH'], - // 'assertionMethod': ['did:ebsi:z24q8qN8UE1j4XAFiFKtvJbH#keys-1'] - // }; - - // dioAdapter.onGet( - // url, - // (request) => request.reply(200, response), - // ); - // final oidc4vc = OIDC4VC(client); - - // final value = await oidc4vc.getDidDocument(didKey); - - // expect(value.data, response); - // }); - - // test('sandbox', () { - // const cNonce = 'cNonce'; - // const did = 'did'; - // const issuer = 'issuer'; - // final payload = { - // 'iss': did, - // 'nonce': cNonce, - // 'iat': DateTime.now().microsecondsSinceEpoch, - // 'aud': issuer - // }; - - // final jwt = JWT( - // // Payload - // payload, - - // issuer: issuer, - // ); - - // // Sign it (default with HS256 algorithm) - // // ignore: unused_local_variable - // final token = jwt.sign(SecretKey('secret passphrase')); - // }); - - // // test('generateToken', () { - // // final jwk = { - // // 'kty': 'OKP', - // // 'crv': 'Ed25519', - // // 'd': '-_9OD-PMHKE2mFKEVH5R1vDhEMimtXPUX-2w1Xa0hQ0=', - // // 'x': '1tknP1Fx-YIQBzw3xXtCwLGgYoTb-nSsNn-k9uzWpuw=', - // // }; - - // // final vpTokenPayload = { - // // 'iss': 'did:ebsi:zrDzYQPDztwjQ8HdXto1B4FVB14fxoiNawZd8eyEuhR7K', - // // 'nonce': '8dd8d00a-ad17-11ed-9fe9-0a1628958560', - // // 'iat': '1676455223753366', - // // 'aud': 'https://talao.co/sandbox/ebsi/issuer/vgvghylozl', - // // }; - - // // final oidc4vc = OIDC4VC(client); - - // // final tokenParameters = TokenParameters(jwk); - // // final token = oidc4vc.generateToken(vpTokenPayload, tokenParameters); - //}); - //} + group('getIssuer', () { + test('get issuer with credentialRequestUri', () async { + const clientId = + 'did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9Kbrbpg5is8LfTLuQ1RsW5r7s7ZjbDDFbDgy1tLrdc7Bj3itBGQkuGUQyfzKhFqbUNW2PqJPMSSzWoF2DGSvDSijCtJtYCSRsjSVLrwu5oHNbnPFvSEC4iRZPpU6B6nExRBTa'; + + const expectedIssuerJwt = + 'eyJhbGciOiJFUzI1NiIsInR5cCI6Im9wZW5pZDR2Y2ktcHJvb2Yrand0Iiwia2lkIjoidmNEV1FrRzBmbXhmRm90clhKZFRZMEhzQklobTQ2UDZYYzNqcXdVbjRVWSJ9.eyJpc3MiOiJkaWQ6a2V5OnoyZG16RDgxY2dQeDhWa2k3SmJ1dU1tRllyV1BnWW95dHlrVVozZXlxaHQxajlLYnJicGc1aXM4TGZUTHVRMVJzVzVyN3M3WmpiRERGYkRneTF0THJkYzdCajNpdEJHUWt1R1VReWZ6S2hGcWJVTlcyUHFKUE1TU3pXb0YyREdTdkRTaWpDdEp0WUNTUnNqU1ZMcnd1NW9ITmJuUEZ2U0VDNGlSWlBwVTZCNm5FeFJCVGEiLCJpYXQiOjE3MTQ3MTU1NDQsImF1ZCI6Imh0dHBzOi8vdGFsYW8uY28vaXNzdWVyL3p4aGFva2Njc2kiLCJub25jZSI6IjJkYTJkNTA2LTA5MTAtMTFlZi05ZTQ5LTBhMTYyODk1ODU2MCJ9.kmRv9RfhwGmAArHiqsZl7HkxE32vO9hyiVuI-lcMmpBPsgJ_eqPSXvkhSrIoUoKCtWAS3gaTT1hRZ5O0_fk9fA'; + + final tokenParameters = IssuerTokenParameters( + privateKey: { + 'kty': 'EC', + 'crv': 'P-256', + 'd': 'amrwK13ZiYoJ5g0fc6MvXc86RB9ID8VuK_dMowU68FE', + 'x': 'fJQ2c9P_YDep3jzidwykcSlyoC4omqBvd9RHP1nz0cw', + 'y': 'K7VxrW-S1ONuX5cxrWIltF36ac1K8kj9as_o5cyc2zk', + }, + did: clientId, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + clientType: ClientType.did, + clientId: clientId, + issuer: 'https://talao.co/issuer/zxhaokccsi', + ); + final issuerJwt = await oidc4vc.getIssuerJwt( + tokenParameters: tokenParameters, + clientAuthentication: ClientAuthentication.clientId, + iss: clientId, + cnonce: '2da2d506-0910-11ef-9e49-0a1628958560', + ); + + expect(issuerJwt.startsWith('ey'), expectedIssuerJwt.startsWith('ey')); + }); + }); + + test('get readTokenEndPoint with openidConfigurationResponse', () async { + const issuer = 'https://talao.co/issuer/zxhaokccsi'; + const openidConfigurationResponse = + '{"authorization_server":"https://talao.co/issuer/zxhaokccsi","credential_endpoint":"https://talao.co/issuer/zxhaokccsi/credential","credential_issuer":"https://talao.co/issuer/zxhaokccsi","subject_syntax_types_supported":null,"token_endpoint":null,"batch_endpoint":null,"authorization_endpoint":null,"subject_trust_frameworks_supported":null,"credentials_supported":[{"display":[{"locale":"en-US","name":"EU Diploma","description":"This the official EBSI VC Diploma","text_color":"#FFFFFF","background_color":"#3B6F6D","background_image":{"url":"https://i.ibb.co/CHqjxrJ/dbc-card-hig-res.png","alt_text":"Connected open cubes in blue with one orange cube as a background of the card"},"logo":{"url":"https://dutchblockchaincoalition.org/assets/images/icons/Logo-DBC.png","alt_text":"An orange block shape, with the text Dutch Blockchain Coalition next to it, portraying the logo of the Dutch Blockchain Coalition."}}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma2"],"id":null,"scope":null,"credentialSubject":{"dateOfBirth":{"display":[{"locale":"en-US","name":"Birth Date"},{"locale":"fr-FR","name":"Date de naissance"}]},"familyName":{"display":[{"locale":"en-US","name":"Family Name"},{"locale":"fr-FR","name":"Nom"}]},"givenNames":{"display":[{"locale":"en-US","name":"First Name"},{"locale":"fr-FR","name":"Prénom"}]}}},{"display":[{"locale":"en-US","name":"Individual attestation","description":"This is the EBSI Individual Verifiable Attestation","text_color":"#FFFFFF","background_color":"#3B6F6D","background_image":null,"logo":null}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","IndividualVerifiableAttestation"],"id":null,"scope":null,"credentialSubject":{"dateOfBirth":{"display":[{"locale":"en-US","name":"Birth Date"},{"locale":"fr-FR","name":"Date de naissance"}]},"familyName":{"display":[{"locale":"en-US","name":"Family Name"},{"locale":"fr-FR","name":"Nom"}]},"firstName":{"display":[{"locale":"en-US","name":"First Name"},{"locale":"fr-FR","name":"Prénom"}]},"issuing_country":{"display":[{"locale":"en-US","name":"Issued by"},{"locale":"fr-FR","name":"Délivré par"}]},"placeOfBirth":{"display":[{"locale":"en-US","name":"Birth Place"},{"locale":"fr-FR","name":"Lieu de naissance"}]}}},{"display":[{"locale":"en-GB","name":"Email proof","description":"This is a verifiable credential","text_color":null,"background_color":null,"background_image":null,"logo":null}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","EmailPass"],"id":null,"scope":null,"credentialSubject":null},{"display":[{"locale":"en-GB","name":"Verifiable Id","description":"This is a verifiable credential","text_color":null,"background_color":null,"background_image":null,"logo":null}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableId"],"id":null,"scope":null,"credentialSubject":null}],"credential_configurations_supported":null,"deferred_credential_endpoint":"https://talao.co/issuer/zxhaokccsi/deferred","service_documentation":null,"credential_manifest":null,"credential_manifests":null,"issuer":null,"jwks_uri":null,"grant_types_supported":null}'; + const openidConfigurationResponse2 = + '{"authorization_endpoint":"https://talao.co/issuer/zxhaokccsi/authorize","grant_types_supported":["authorization_code","urn:ietf:params:oauth:grant-type:pre-authorized_code"],"id_token_signing_alg_values_supported":["ES256","ES256K","EdDSA","RS256"],"id_token_types_supported":["subject_signed_id_token"],"jwks_uri":"https://talao.co/issuer/zxhaokccsi/jwks","pushed_authorization_request_endpoint":"https://talao.co/issuer/zxhaokccsi/authorize/par","request_authentication_methods_supported":{"authorization_endpoint":["request_object"]},"request_object_signing_alg_values_supported":["ES256","ES256K","EdDSA","RS256"],"request_parameter_supported":true,"request_uri_parameter_supported":true,"response_modes_supported":["query"],"response_types_supported":["vp_token","id_token"],"scopes_supported":["openid"],"subject_syntax_types_discriminations":["did:key:jwk_jcs-pub","did:ebsi:v1"],"subject_syntax_types_supported":["urn:ietf:params:oauth:jwk-thumbprint","did:key","did:ebsi","did:tz","did:pkh","did:hedera","did:key","did:ethr","did:web","did:jwk"],"subject_trust_frameworks_supported":["ebsi"],"subject_types_supported":["public","pairwise"],"token_endpoint":"https://talao.co/issuer/zxhaokccsi/token","token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post","client_secret_jwt","none"]}'; + + const expectedTokenEndpoint = 'https://talao.co/issuer/zxhaokccsi/token'; + + dioAdapter.onPost( + '$issuer/.well-known/openid-configuration', + (request) => request.reply( + 200, + jsonDecode(openidConfigurationResponse2), + ), + ); + + final tokenEndpoint = await oidc4vc.readTokenEndPoint( + dio: client, + issuer: issuer, + oidc4vciDraftType: OIDC4VCIDraftType.draft11, + openIdConfiguration: OpenIdConfiguration.fromJson( + jsonDecode(openidConfigurationResponse) as Map, + ), + ); + + expect(tokenEndpoint, expectedTokenEndpoint); + }); + + test('get issuer did with openidConfigurationResponse', () { + const openidConfigurationResponse = + r'{"authorization_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/authorize","batch_credential_endpoint":null,"credential_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/credential","credential_issuer":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl","credential_manifests":[{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"display":{"description":{"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework.","path":[],"schema":{"type":"string"}},"properties":[{"fallback":"Unknown","label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number"}},{"fallback":"Unknown","label":"Issue date","path":["$.issuanceDate"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"format":"uri","type":"string"}}],"subtitle":{"fallback":"EBSI Verifiable diploma","path":[],"schema":{"type":"string"}},"title":{"fallback":"Diploma","path":[],"schema":{"type":"string"}}},"id":"diploma_01","schema":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"spec_version":"https://identity.foundation/credential-manifest/spec/v1.0.0/"}],"credential_supported":[{"cryptographic_binding_methods_supported":["did"],"cryptographic_suites_supported":["ES256K","ES256","ES384","ES512","RS256"],"display":[{"locale":"en-US","name":"Issuer Talao"}],"format":"jwt_vc","id":"VerifiableDiploma","types":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"},{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"display":{"description":{"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework.","path":[],"schema":{"type":"string"}},"properties":[{"fallback":"Unknown","label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number"}},{"fallback":"Unknown","label":"Issue date","path":["$.issuanceDate"],"schema":{"format":"date","type":"string"}},{"fallback":"Unknown","label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string"}},{"fallback":"Unknown","label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"format":"uri","type":"string"}}],"subtitle":{"fallback":"EBSI Verifiable diploma","path":[],"schema":{"type":"string"}},"title":{"fallback":"Diploma","path":[],"schema":{"type":"string"}}},"id":"diploma_01","schema":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"spec_version":"https://identity.foundation/credential-manifest/spec/v1.0.0/"}],"credential_supported":[{"cryptographic_binding_methods_supported":["did"],"cryptographic_suites_supported":["ES256K","ES256","ES384","ES512","RS256"],"display":[{"locale":"en-US","name":"Issuer Talao"}],"format":"jwt_vc","id":"VerifiableDiploma","types":"https://api.preprod.oidc4vc.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd"}],"pre-authorized_grant_anonymous_access_supported":true,"subject_syntax_types_supported":["did:ebsi"],"token_endpoint":"https://talao.co/sandbox/ebsi/issuer/vgvghylozl/token"}'; + + final issuer = oidc4vc.readIssuerDid( + Response( + requestOptions: RequestOptions(), + data: jsonDecode(openidConfigurationResponse) as Map, + ), + ); + expect(issuer, 'did:ebsi:zhSw5rPXkcHjvquwnVcTzzB'); + }); + + test('get publicKey did with didDocumentResponse', () { + const didDocument = + '{"keys":[{"crv":"Ed25519","kid":"AegXN9J71CIQWw7TjhM-eHYZW45TfP0uC5xJduiH_w0","kty":"OKP","x":"FUoLewH4w4-KdaPH2cjZbL--CKYxQRWR05Yd_bIbhQo"}]}'; + const issuerDid = 'https://talao.co/sandbox/issuer/statuslist'; + const holderKid = 'AegXN9J71CIQWw7TjhM-eHYZW45TfP0uC5xJduiH_w0'; + + const expectedPublicKey = + '{"crv":"Ed25519","kid":"AegXN9J71CIQWw7TjhM-eHYZW45TfP0uC5xJduiH_w0","kty":"OKP","x":"FUoLewH4w4-KdaPH2cjZbL--CKYxQRWR05Yd_bIbhQo"}'; + + final publicKey = oidc4vc.readPublicKeyJwk( + issuer: issuerDid, + holderKid: holderKid, + didDocument: jsonDecode(didDocument) as Map, + ); + expect(jsonEncode(publicKey), expectedPublicKey); + }); + + group('verify encoded data', () { + const issuer = 'did:web:talao.co'; + const issuerKid1 = 'did:web:talao.co#key-2'; + const issuerKid2 = 'did:web:talao.co#key-222'; + const issuerKid3 = 'did:web:talao.co#key-21'; + const issuerKid4 = 'did:web:talao.co#key-3'; + + const universal = 'https://unires:test@unires.talao.co/1.0/identifiers'; + + const jwt = + 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDp3ZWI6dGFsYW8uY28ja2V5LTIiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3NDYyNTUzMDYsImlhdCI6MTcxNDcxOTMwNiwiaXNzIjoiZGlkOndlYjp0YWxhby5jbyIsImp0aSI6InVybjp1dWlkOjEyZjdmNmI1LTA5MWEtMTFlZi04MWU1LTBhMTYyODk1ODU2MCIsIm5iZiI6MTcxNDcxOTMwNiwibm9uY2UiOiIxMWVhZTg1YS0wOTFhLTExZWYtODJkNC0wYTE2Mjg5NTg1NjAiLCJzdWIiOiJkaWQ6andrOmV5SmpjbllpT2lKUUxUSTFOaUlzSW10MGVTSTZJa1ZESWl3aWVDSTZJa1pIYTFScWFrUXhPR1l6VVRsc2FteG9WblEyVnpaMWJqSmtjbFJ1WjJoSU1XOVhSM1JRUmpOZk16Z2lMQ0o1SWpvaVkwWkNhWHBYZURoNE5rbE1XbWt5T1ZkRVFtNHpialU0WldWbGNra3ROVmMxWWxOeGVHaFFVR05RWXlKOSIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sImNyZWRlbnRpYWxTY2hlbWEiOnsiaWQiOiJodHRwczovL2FwaS1jb25mb3JtYW5jZS5lYnNpLmV1L3RydXN0ZWQtc2NoZW1hcy1yZWdpc3RyeS92Mi9zY2hlbWFzL3oyMlpBTWRRdE5Md2k1MVQydmRaWEdHWmFZeWpyc3VQMXl6V3lYWmlyQ0FIdiIsInR5cGUiOiJGdWxsSnNvblNjaGVtYVZhbGlkYXRvcjIwMjEifSwiY3JlZGVudGlhbFN0YXR1cyI6W3siaWQiOiJodHRwczovL3RhbGFvLmNvL3NhbmRib3gvaXNzdWVyL2JpdHN0cmluZ3N0YXR1c2xpc3QvMSM1ODg5NyIsInN0YXR1c0xpc3RDcmVkZW50aWFsIjoiaHR0cHM6Ly90YWxhby5jby9zYW5kYm94L2lzc3Vlci9iaXRzdHJpbmdzdGF0dXNsaXN0LzEiLCJzdGF0dXNMaXN0SW5kZXgiOiI1ODg5NyIsInN0YXR1c1B1cnBvc2UiOiJyZXZvY2F0aW9uIiwidHlwZSI6IkJpdHN0cmluZ1N0YXR1c0xpc3RFbnRyeSJ9XSwiY3JlZGVudGlhbFN1YmplY3QiOnsiZGF0ZUlzc3VlZCI6IjIwMjItMTItMjAiLCJkYXRlT2ZCaXJ0aCI6IjE5MzAtMTAtMDEiLCJmYW1pbHlOYW1lIjoiQ2FzdGFmaW9yaSIsImZpcnN0TmFtZSI6IkJpYW5jYSIsImdlbmRlciI6IkYiLCJ0eXBlIjoiVmVyaWZpYWJsZUlkIn0sImV4cGlyYXRpb25EYXRlIjoiMjAyNS0wNS0wM1QwNjo1NDo1M1oiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUlkIl0sInZhbGlkRnJvbSI6IjIwMjUtMDUtMDNUMDY6NTQ6NTNaIn19.5DJwR_gUbu-GDpSF7hwXcpmHg-wYmKU_AxOvR4Psimefk0H4JUbX803svm3QhxIK2i4GgMhRWmgqhvML_x7nTw'; + + const didDocument = + r'{"@context":"https://w3id.org/did-resolution/v1","didDocument":{"@context":["https://www.w3.org/ns/did/v1",{"@id":"https://w3id.org/security#publicKeyJwk","@type":"@json"}],"id":"did:web:talao.co","verificationMethod":[{"id":"did:web:talao.co#key-1","type":"JwsVerificationKey2020","controller":"did:web:talao.co","publicKeyJwk":{"e":"AQAB","kid":"did:web:talao.co#key-1","kty":"RSA","n":"pPocyKreTAn3YrmGyPYXHklYqUiSSQirGACwJSYYs-ksfw4brtA3SZCmA2sdAO8a2DXfqADwFgVSxJFtJ3GkHLV2ZvOIOnZCX6MF6NIWHB9c64ydrYNJbEy72oyG_-v-sE6rb0x-D-uJe9DFYIURzisyBlNA7imsiZPQniOjPLv0BUgED0vdO5HijFe7XbpVhoU-2oTkHHQ4CadmBZhelCczACkXpOU7mwcImGj9h1__PsyT5VBLi_92-93NimZjechPaaTYEU2u0rfnfVW5eGDYNAynO4Q2bhpFPRTXWZ5Lhnhnq7M76T6DGA3GeAu_MOzB0l4dxpFMJ6wHnekdkQ"}},{"id":"did:web:talao.co#key-2","type":"JwsVerificationKey2020","controller":"did:web:talao.co","publicKeyJwk":{"crv":"P-256","kty":"EC","x":"Bls7WaGu_jsharYBAzakvuSERIV_IFR2tS64e5p_Y_Q","y":"haeKjXQ9uzyK4Ind1W4SBUkR_9udjjx1OmKK4vl1jko"}},{"id":"did:web:talao.co#key-21","type":"JwsVerificationKey2020","controller":"did:web:talao.co","publicKeyJwk":{"crv":"P-256","kty":"EC","x":"J4vQtLUyrVUiFIXRrtEq4xurmBZp2eq9wJmXkIA_stI","y":"HNh3aF4zQsnf_sFXUVaSzrQF85veDoVxhPQ-163wUYM"}},{"id":"did:web:talao.co#key-3","type":"JwsVerificationKey2020","controller":"did:web:talao.co","publicKeyJwk":{"crv":"Ed25519","kty":"OKP","x":"FUoLewH4w4-KdaPH2cjZbL--CKYxQRWR05Yd_bIbhQo"}},{"id":"did:web:talao.co#key-4","type":"Ed25519VerificationKey2018","controller":"did:web:talao.co","publicKeyBase58":"2S73k5pn5umfnaW31qx6dXFndEn6SmWw7LpgSjNNC5BF"}],"authentication":["did:web:talao.co#key-1","did:web:talao.co#key-2","did:web:talao.co#key-3","did:web:talao.co#key-4"],"assertionMethod":["did:web:talao.co#key-1","did:web:talao.co#key-2","did:web:talao.co#key-3","did:web:talao.co#key-4"],"keyAgreement":["did:web:talao.co#key-3","did:web:talao.co#key-4"],"capabilityInvocation":["did:web:talao.co#key-1","did:web:talao.co#key-4"],"service":[{"id":"did:web:talao.co#domain-1","type":"LinkedDomains","serviceEndpoint":"https://talao.co"}]},"didResolutionMetadata":{"contentType":"application/did+ld+json","pattern":"^(did:web:.+)$","driverUrl":"http://uni-resolver-driver-did-uport:8081/1.0/identifiers/","duration":42,"did":{"didString":"did:web:talao.co","methodSpecificId":"talao.co","method":"web"}},"didDocumentMetadata":{}}'; + + dioAdapter.onGet( + '$universal/$issuer', + (request) => request.reply(200, jsonDecode(didDocument)), + ); + + test('returns VerificationType.verified', () async { + final isVerified = await oidc4vc.verifyEncodedData( + issuer: issuer, + jwt: jwt, + issuerKid: issuerKid1, + dio: client, + fromStatusList: false, + isCachingEnabled: false, + publicJwk: null, + ); + expect(isVerified, VerificationType.verified); + }); + + test('returns VerificationType.unKnown', () async { + final isVerified = await oidc4vc.verifyEncodedData( + issuer: issuer, + jwt: jwt, + issuerKid: issuerKid2, + dio: client, + fromStatusList: false, + isCachingEnabled: false, + publicJwk: null, + ); + expect(isVerified, VerificationType.unKnown); + }); + + test('returns VerificationType.notVerified', () async { + const vcJwt = + 'eyJhbGciOiJIUzI1NiJ9.eyJSb2xlIjoiQWRtaW4iLCJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkphdmFJblVzZSIsImV4cCI6MTcxNDcyMjY3NiwiaWF0IjoxNzE0NzIyNjc2fQ.mVQhu1VmyA6LlcA77NmdhUvTrOoawL_VxhrMzkkh7BE'; + final isVerified = await oidc4vc.verifyEncodedData( + issuer: issuer, + jwt: vcJwt, + issuerKid: issuerKid3, + dio: client, + fromStatusList: false, + isCachingEnabled: false, + publicJwk: null, + ); + expect(isVerified, VerificationType.notVerified); + }); + + test('returns VerificationType.notVerified for OKP', () async { + const vcJwt = 'eyJraWQiOiItMTkwOTU3MjI1NyIsImFsZyI6IkVkRFNBIn0.' + 'eyJqdGkiOiIyMjkxNmYzYy05MDkzLTQ4MTMtODM5Ny1mMTBlNmI3MDRiNjgiLCJkZWxlZ2F0aW9uSWQiOiJiNGFlNDdhNy02MjVhLTQ2MzAtOTcyNy00NTc2NGE3MTJjY2UiLCJleHAiOjE2NTUyNzkxMDksIm5iZiI6MTY1NTI3ODgwOSwic2NvcGUiOiJyZWFkIG9wZW5pZCIsImlzcyI6Imh0dHBzOi8vaWRzdnIuZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VybmFtZSIsImF1ZCI6ImFwaS5leGFtcGxlLmNvbSIsImlhdCI6MTY1NTI3ODgwOSwicHVycG9zZSI6ImFjY2Vzc190b2tlbiJ9.' // ignore: lines_longer_than_80_chars + 'rjeE8D_e4RYzgvpu-nOwwx7PWMiZyDZwkwO6RiHR5t8g4JqqVokUKQt-oST1s45wubacfeDSFogOrIhe3UHDAg'; // ignore: lines_longer_than_80_chars + + final isVerified = await oidc4vc.verifyEncodedData( + issuer: issuer, + jwt: vcJwt, + issuerKid: issuerKid4, + dio: client, + fromStatusList: false, + isCachingEnabled: false, + publicJwk: null, + ); + expect(isVerified, VerificationType.notVerified); + }); + }); + + group('get token', () { + const tokenEndPoint = 'https://talao.co/issuer/zarbjrqrzj/token'; + const tokenData = { + 'pre-authorized_code': '5cdf5508-0923-11ef-90b1-0a1628958560', + 'grant_type': 'urn:ietf:params:oauth:grant-type:pre-authorized_code', + 'client_id': 'did:key:zDnaeoAcB8wFcSWqLeiJbCg663C3qAKkEfuuTM9rGWx2NFWCt', + 'user_pin': '4444', + 'tx_code': '4444', + }; + + test('get correct token ', () async { + const response = + '{"access_token":"ac9e48a7-0923-11ef-95a3-0a1628958560","c_nonce":"ac9e4a9c-0923-11ef-a47c-0a1628958560","token_type":"Bearer","expires_in":10000,"c_nonce_expires_in":1704466725,"refresh_token":"ac9e49f2-0923-11ef-91ef-0a1628958560"}'; + + dioAdapter.onPost( + tokenEndPoint, + (request) => request.reply(200, jsonDecode(response)), + ); + + const expectedValue = + '{"access_token":"ac9e48a7-0923-11ef-95a3-0a1628958560","c_nonce":"ac9e4a9c-0923-11ef-a47c-0a1628958560","token_type":"Bearer","expires_in":10000,"c_nonce_expires_in":1704466725,"refresh_token":"ac9e49f2-0923-11ef-91ef-0a1628958560"}'; + final token = await oidc4vc.getToken( + dio: client, + tokenData: tokenData, + tokenEndPoint: tokenEndPoint, + authorization: null, + ); + + expect(jsonEncode(token), expectedValue); + }); + + test('throw expection when invalid value is sent', () async { + expect( + () async { + dioAdapter.onPost( + tokenEndPoint, + (request) => request.throws( + 401, + DioException(requestOptions: RequestOptions(path: tokenEndPoint)), + ), + ); + + await oidc4vc.getToken( + dio: client, + tokenData: tokenData, + tokenEndPoint: tokenEndPoint, + authorization: null, + ); + }, + throwsA(isA()), + ); + }); + }); + + group( + 'get did document', + () { + test('get corresponding did document', () async { + const issuer = 'did:web:talao.co'; + const universal = 'https://unires:test@unires.talao.co/1.0/identifiers'; + + const didDocument = + r'{"@context":"https://w3id.org/did-resolution/v1","didDocument":{"@context":["https://www.w3.org/ns/did/v1",{"@id":"https://w3id.org/security#publicKeyJwk","@type":"@json"}],"id":"did:web:talao.co","verificationMethod":[{"id":"did:web:talao.co#key-1","type":"JwsVerificationKey2020","controller":"did:web:talao.co","publicKeyJwk":{"e":"AQAB","kid":"did:web:talao.co#key-1","kty":"RSA","n":"pPocyKreTAn3YrmGyPYXHklYqUiSSQirGACwJSYYs-ksfw4brtA3SZCmA2sdAO8a2DXfqADwFgVSxJFtJ3GkHLV2ZvOIOnZCX6MF6NIWHB9c64ydrYNJbEy72oyG_-v-sE6rb0x-D-uJe9DFYIURzisyBlNA7imsiZPQniOjPLv0BUgED0vdO5HijFe7XbpVhoU-2oTkHHQ4CadmBZhelCczACkXpOU7mwcImGj9h1__PsyT5VBLi_92-93NimZjechPaaTYEU2u0rfnfVW5eGDYNAynO4Q2bhpFPRTXWZ5Lhnhnq7M76T6DGA3GeAu_MOzB0l4dxpFMJ6wHnekdkQ"}},{"id":"did:web:talao.co#key-2","type":"JwsVerificationKey2020","controller":"did:web:talao.co","publicKeyJwk":{"crv":"P-256","kty":"EC","x":"Bls7WaGu_jsharYBAzakvuSERIV_IFR2tS64e5p_Y_Q","y":"haeKjXQ9uzyK4Ind1W4SBUkR_9udjjx1OmKK4vl1jko"}},{"id":"did:web:talao.co#key-21","type":"JwsVerificationKey2020","controller":"did:web:talao.co","publicKeyJwk":{"crv":"P-256","kty":"EC","x":"J4vQtLUyrVUiFIXRrtEq4xurmBZp2eq9wJmXkIA_stI","y":"HNh3aF4zQsnf_sFXUVaSzrQF85veDoVxhPQ-163wUYM"}},{"id":"did:web:talao.co#key-3","type":"JwsVerificationKey2020","controller":"did:web:talao.co","publicKeyJwk":{"crv":"Ed25519","kty":"OKP","x":"FUoLewH4w4-KdaPH2cjZbL--CKYxQRWR05Yd_bIbhQo"}},{"id":"did:web:talao.co#key-4","type":"Ed25519VerificationKey2018","controller":"did:web:talao.co","publicKeyBase58":"2S73k5pn5umfnaW31qx6dXFndEn6SmWw7LpgSjNNC5BF"}],"authentication":["did:web:talao.co#key-1","did:web:talao.co#key-2","did:web:talao.co#key-3","did:web:talao.co#key-4"],"assertionMethod":["did:web:talao.co#key-1","did:web:talao.co#key-2","did:web:talao.co#key-3","did:web:talao.co#key-4"],"keyAgreement":["did:web:talao.co#key-3","did:web:talao.co#key-4"],"capabilityInvocation":["did:web:talao.co#key-1","did:web:talao.co#key-4"],"service":[{"id":"did:web:talao.co#domain-1","type":"LinkedDomains","serviceEndpoint":"https://talao.co"}]},"didResolutionMetadata":{"contentType":"application/did+ld+json","pattern":"^(did:web:.+)$","driverUrl":"http://uni-resolver-driver-did-uport:8081/1.0/identifiers/","duration":42,"did":{"didString":"did:web:talao.co","methodSpecificId":"talao.co","method":"web"}},"didDocumentMetadata":{}}'; + + dioAdapter.onGet( + '$universal/$issuer', + (request) => request.reply(200, jsonDecode(didDocument)), + ); + + final value = await oidc4vc.getDidDocument( + didKey: issuer, + fromStatusList: false, + isCachingEnabled: false, + dio: client, + ); + + expect(value, jsonDecode(didDocument)); + }); + + test('get corresponding did document', () async { + const issuer = 'https://talao.co/issuer/zxhaokccsi'; + const openidConfigurationResponse1 = + '{"authorization_server":"https://talao.co/issuer/zxhaokccsi","credential_endpoint":"https://talao.co/issuer/zxhaokccsi/credential","credential_issuer":"https://talao.co/issuer/zxhaokccsi","subject_syntax_types_supported":null,"token_endpoint":null,"batch_endpoint":null,"authorization_endpoint":null,"subject_trust_frameworks_supported":null,"credentials_supported":[{"display":[{"locale":"en-US","name":"EU Diploma","description":"This the official EBSI VC Diploma","text_color":"#FFFFFF","background_color":"#3B6F6D","background_image":{"url":"https://i.ibb.co/CHqjxrJ/dbc-card-hig-res.png","alt_text":"Connected open cubes in blue with one orange cube as a background of the card"},"logo":{"url":"https://dutchblockchaincoalition.org/assets/images/icons/Logo-DBC.png","alt_text":"An orange block shape, with the text Dutch Blockchain Coalition next to it, portraying the logo of the Dutch Blockchain Coalition."}}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma2"],"id":null,"scope":null,"credentialSubject":{"dateOfBirth":{"display":[{"locale":"en-US","name":"Birth Date"},{"locale":"fr-FR","name":"Date de naissance"}]},"familyName":{"display":[{"locale":"en-US","name":"Family Name"},{"locale":"fr-FR","name":"Nom"}]},"givenNames":{"display":[{"locale":"en-US","name":"First Name"},{"locale":"fr-FR","name":"Prénom"}]}}},{"display":[{"locale":"en-US","name":"Individual attestation","description":"This is the EBSI Individual Verifiable Attestation","text_color":"#FFFFFF","background_color":"#3B6F6D","background_image":null,"logo":null}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","IndividualVerifiableAttestation"],"id":null,"scope":null,"credentialSubject":{"dateOfBirth":{"display":[{"locale":"en-US","name":"Birth Date"},{"locale":"fr-FR","name":"Date de naissance"}]},"familyName":{"display":[{"locale":"en-US","name":"Family Name"},{"locale":"fr-FR","name":"Nom"}]},"firstName":{"display":[{"locale":"en-US","name":"First Name"},{"locale":"fr-FR","name":"Prénom"}]},"issuing_country":{"display":[{"locale":"en-US","name":"Issued by"},{"locale":"fr-FR","name":"Délivré par"}]},"placeOfBirth":{"display":[{"locale":"en-US","name":"Birth Place"},{"locale":"fr-FR","name":"Lieu de naissance"}]}}},{"display":[{"locale":"en-GB","name":"Email proof","description":"This is a verifiable credential","text_color":null,"background_color":null,"background_image":null,"logo":null}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","EmailPass"],"id":null,"scope":null,"credentialSubject":null},{"display":[{"locale":"en-GB","name":"Verifiable Id","description":"This is a verifiable credential","text_color":null,"background_color":null,"background_image":null,"logo":null}],"format":"jwt_vc","trust_framework":{"name":"ebsi","type":"Accreditation","uri":"TIR link towards accreditation"},"types":["VerifiableCredential","VerifiableAttestation","VerifiableId"],"id":null,"scope":null,"credentialSubject":null}],"credential_configurations_supported":null,"deferred_credential_endpoint":"https://talao.co/issuer/zxhaokccsi/deferred","service_documentation":null,"credential_manifest":null,"credential_manifests":null,"issuer":null,"jwks_uri":null,"grant_types_supported":null}'; + const openidConfigurationResponse2 = + '{"authorization_server":null,"credential_endpoint":null,"credential_issuer":null,"subject_syntax_types_supported":null,"token_endpoint":null,"batch_endpoint":null,"authorization_endpoint":null,"subject_trust_frameworks_supported":null,"credentials_supported":null,"credential_configurations_supported":null,"deferred_credential_endpoint":null,"service_documentation":null,"credential_manifest":null,"credential_manifests":null,"issuer":"https://talao.co/sandbox/issuer/statuslist","jwks_uri":"https://talao.co/sandbox/issuer/statuslist/jwks","grant_types_supported":null}'; + const jwkUriResponse = + '{"keys":[{"crv":"Ed25519","kid":"AegXN9J71CIQWw7TjhM-eHYZW45TfP0uC5xJduiH_w0","kty":"OKP","x":"FUoLewH4w4-KdaPH2cjZbL--CKYxQRWR05Yd_bIbhQo"}]}'; + + const expectedDidDocument = + '{"keys":[{"crv":"Ed25519","kid":"AegXN9J71CIQWw7TjhM-eHYZW45TfP0uC5xJduiH_w0","kty":"OKP","x":"FUoLewH4w4-KdaPH2cjZbL--CKYxQRWR05Yd_bIbhQo"}]}'; + + dioAdapter + ..onGet( + '$issuer/.well-known/openid-credential-issuer', + (request) => + request.reply(200, jsonDecode(openidConfigurationResponse1)), + ) + ..onGet( + '$issuer/.well-known/openid-configuration', + (request) => + request.reply(200, jsonDecode(openidConfigurationResponse2)), + ) + ..onGet( + 'https://talao.co/sandbox/issuer/statuslist/jwks', + (request) => request.reply(200, jsonDecode(jwkUriResponse)), + ); + + final value = await oidc4vc.getDidDocument( + didKey: issuer, + fromStatusList: false, + isCachingEnabled: false, + dio: client, + ); + expect(value, jsonDecode(expectedDidDocument)); + }); + }, + ); } diff --git a/packages/oidc4vc/test/src/oidc4vci_draft_type_test.dart b/packages/oidc4vc/test/src/oidc4vci_draft_type_test.dart new file mode 100644 index 000000000..1e5771ecf --- /dev/null +++ b/packages/oidc4vc/test/src/oidc4vci_draft_type_test.dart @@ -0,0 +1,16 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('OIDC4VCIDraftTypeX', () { + test('formattedString', () { + expect(OIDC4VCIDraftType.draft11.formattedString, 'Draft 11'); + expect(OIDC4VCIDraftType.draft13.formattedString, 'Draft 13'); + }); + + test('numbering', () { + expect(OIDC4VCIDraftType.draft11.numbering, '11'); + expect(OIDC4VCIDraftType.draft13.numbering, '13'); + }); + }); +} diff --git a/packages/oidc4vc/test/src/oidc4vp_draft_type_test.dart b/packages/oidc4vc/test/src/oidc4vp_draft_type_test.dart new file mode 100644 index 000000000..7b088cb12 --- /dev/null +++ b/packages/oidc4vc/test/src/oidc4vp_draft_type_test.dart @@ -0,0 +1,13 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('OIDC4VPDraftTypeX', () { + test('formattedString', () { + expect(OIDC4VPDraftType.draft10.formattedString, 'Draft 10'); + expect(OIDC4VPDraftType.draft13.formattedString, 'Draft 13'); + expect(OIDC4VPDraftType.draft18.formattedString, 'Draft 18'); + expect(OIDC4VPDraftType.draft20.formattedString, 'Draft 20'); + }); + }); +} diff --git a/packages/oidc4vc/test/src/pkce_dart_test.dart b/packages/oidc4vc/test/src/pkce_dart_test.dart new file mode 100644 index 000000000..02574173a --- /dev/null +++ b/packages/oidc4vc/test/src/pkce_dart_test.dart @@ -0,0 +1,32 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('PkcePair', () { + test('generate', () { + final pkcePair = PkcePair.generate(); + expect(pkcePair.codeVerifier.length, 43); + expect(pkcePair.codeChallenge.length, 43); + }); + + test('generate with invalid length', () { + expect( + () => PkcePair.generate(length: 31), // Less than 32 + throwsA(isA()), + ); + + expect( + () => PkcePair.generate(length: 97), // Greater than 96 + throwsA(isA()), + ); + }); + + test('generate produces unique values', () { + final pkcePair1 = PkcePair.generate(); + final pkcePair2 = PkcePair.generate(); + + expect(pkcePair1.codeVerifier, isNot(pkcePair2.codeVerifier)); + expect(pkcePair1.codeChallenge, isNot(pkcePair2.codeChallenge)); + }); + }); +} diff --git a/packages/oidc4vc/test/src/proof_header_type_test.dart b/packages/oidc4vc/test/src/proof_header_type_test.dart new file mode 100644 index 000000000..d9a73f101 --- /dev/null +++ b/packages/oidc4vc/test/src/proof_header_type_test.dart @@ -0,0 +1,11 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('ProofHeaderTypeX', () { + test('formattedString', () { + expect(ProofHeaderType.kid.formattedString, 'kid'); + expect(ProofHeaderType.jwk.formattedString, 'jwk'); + }); + }); +} diff --git a/packages/oidc4vc/test/src/proof_type_test.dart b/packages/oidc4vc/test/src/proof_type_test.dart new file mode 100644 index 000000000..e9056bfac --- /dev/null +++ b/packages/oidc4vc/test/src/proof_type_test.dart @@ -0,0 +1,16 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('ProofTypeeX', () { + test('formattedString', () { + expect(ProofType.ldpVp.formattedString, 'ldp_vp'); + expect(ProofType.jwt.formattedString, 'jwt'); + }); + + test('value', () { + expect(ProofType.ldpVp.value, 'ldp_vp'); + expect(ProofType.jwt.value, 'jwt'); + }); + }); +} diff --git a/packages/oidc4vc/test/src/soipv2_draft_type_test.dart b/packages/oidc4vc/test/src/soipv2_draft_type_test.dart new file mode 100644 index 000000000..97b46019b --- /dev/null +++ b/packages/oidc4vc/test/src/soipv2_draft_type_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('SIOPV2DraftTypeX', () { + test('formattedString', () { + expect(SIOPV2DraftType.draft12.formattedString, 'Draft 12'); + }); + }); +} diff --git a/packages/oidc4vc/test/src/token_parameters/token_parameters_class.dart b/packages/oidc4vc/test/src/token_parameters/token_parameters_class.dart index 53a0ea956..701363be4 100644 --- a/packages/oidc4vc/test/src/token_parameters/token_parameters_class.dart +++ b/packages/oidc4vc/test/src/token_parameters/token_parameters_class.dart @@ -1,43 +1,72 @@ -// import 'package:flutter_test/flutter_test.dart'; -// import 'package:oidc4vc/src/token_parameters.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; -// import '../const_values.dart'; +import '../const_values.dart'; -// class TokenParameterTest { -// final tokenParameters = TokenParameters(privateKey, '', ''); +class TokenParameterTest { + final tokenParameters = TokenParameters( + privateKey: privateKey, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + kid: '', + ); -// void publicKeyTest() { -// expect(tokenParameters.publicJWK, publicJWK); -// } + void publicKeyTest() { + expect(tokenParameters.publicJWK, publicJWK); + } -// void didTest() { -// expect(tokenParameters.did, didKey); -// } + void didTest() { + expect(tokenParameters.did, clientId); + } -// void keyIdTest() { -// expect(tokenParameters.kid, kid); -// } + void keyIdTest() { + expect(tokenParameters.kid, kid); + } -// void algorithmIsES256KTest() { -// expect(tokenParameters.alg, ES256KAlg); -// } + void algorithmIsES256KTest() { + expect(tokenParameters.alg, ES256KAlg); + } -// void algorithmIsES256Test() { -// final tokenParameters = TokenParameters(privateKey2, '', ''); -// expect(tokenParameters.alg, ES256Alg); -// } + void algorithmIsES256Test() { + final tokenParameters = TokenParameters( + privateKey: privateKey2, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + ); + expect(tokenParameters.alg, ES256Alg); + } -// void algorithmIsNotNullTest() { -// final tokenParameters = TokenParameters(keyWithAlg, '', ''); -// expect(tokenParameters.alg, HS256Alg); -// } + void algorithmIsNotNullTest() { + final tokenParameters = TokenParameters( + privateKey: keyWithAlg, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + ); + expect(tokenParameters.alg, HS256Alg); + } -// // void thumprintOfKey() { -// // expect(tokenParameters.thumbprint, thumbprint); -// // } + void thumprintOfKey() { + expect(tokenParameters.thumbprint, thumbprint); + } -// // void thumprintOfKeyForrfc7638() { -// // final tokenParameters = TokenParameters(rfc7638Jwk, '', '', ''); -// // expect(tokenParameters.thumbprint, expectedThumbprintForrfc7638Jwk); -// // } -// } + void thumprintOfKeyForrfc7638() { + final tokenParameters = TokenParameters( + privateKey: rfc7638Jwk, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + ); + expect(tokenParameters.thumbprint, expectedThumbprintForrfc7638Jwk); + } +} diff --git a/packages/oidc4vc/test/src/token_parameters/token_parameters_test.dart b/packages/oidc4vc/test/src/token_parameters/token_parameters_test.dart index b32e6bb3d..754426c9a 100644 --- a/packages/oidc4vc/test/src/token_parameters/token_parameters_test.dart +++ b/packages/oidc4vc/test/src/token_parameters/token_parameters_test.dart @@ -1,130 +1,81 @@ -// // ignore: unnecessary_lambdas - -// // Copyright (c) 2022, Very Good Ventures -// // https://verygood.ventures -// // -// // Use of this source code is governed by an MIT-style -// // license that can be found in the LICENSE file or at -// // https://opensource.org/licenses/MIT. - -// // ignore_for_file: lines_longer_than_80_chars - -// import 'package:dio/dio.dart'; -// import 'package:flutter_test/flutter_test.dart'; -// import 'package:mocktail/mocktail.dart'; - -// import 'token_parameters_class.dart'; - -// class MockDio extends Mock implements Dio {} - -// void main() { -// group('TokenParameters', () { -// final tokenParametersTest = TokenParameterTest(); - -// // test( -// // 'public key is P-256K private key without d parameter', -// // tokenParametersTest.publicKeyTest, -// // ); - -// // test('did EBSI', tokenParametersTest.didTest); - -// // test('kID EBSI', tokenParametersTest.keyIdTest); - -// group('algorithm test', () { -// test( -// "algorithm is ES256K when key's curve is not P-256", -// tokenParametersTest.algorithmIsES256KTest, -// ); - -// test( -// "algorithm is ES256 when key's curve is P-256", -// tokenParametersTest.algorithmIsES256Test, -// ); - -// test( -// 'if alg is not null then return as it is', -// tokenParametersTest.algorithmIsNotNullTest, -// ); -// }); - -// // group('thumbprint test', () { -// // test('thumbprint of the public Key', tokenParametersTest.thumprintOfKey); - -// // test( -// // 'thumbrprint of the Key from exemple in rfc 7638', -// // tokenParametersTest.thumprintOfKeyForrfc7638, -// // ); -// // }); - -// // group('more didKey test', () { -// // test('did EBSI from Thierry s key', () { -// // final thierryPrivate1 = { -// // 'crv': 'secp256k1', -// // 'kty': 'EC', -// // 'x': 'XMO-urq7MgxkcpQDAJQY84lIO7sTo1Ab-_cqvUyreno', -// // 'y': 'sRnukSTqSCXUShUyDitq6MvTLr5F1ETs6xnR455WW_g' -// // }; - -// // const expectedDid = -// // 'did:ebsi:zkEcb5YVNX5ZRq3nZVH3FVWePLE6vxbqDattYsGan6iLi'; -// // final tokenParameters = TokenParameters(thierryPrivate1, '', '', ''); -// // expect(tokenParameters.didKey, expectedDid); -// // }); - -// // test('did EBSI 1 from Thierry vectors', () { -// // final thierryPrivate = { -// // 'crv': 'secp256k1', -// // 'd': '5DCgRx7Snk-ltE3exxHy94L6LPf8gBSb5_-U8NgRH10', -// // 'kty': 'EC', -// // 'x': 'XMO-urq7MgxkcpQDAJQY84lIO7sTo1Ab-_cqvUyreno', -// // 'y': 'sRnukSTqSCXUShUyDitq6MvTLr5F1ETs6xnR455WW_g' -// // }; -// // const expectedDid = -// // 'did:ebsi:zkEcb5YVNX5ZRq3nZVH3FVWePLE6vxbqDattYsGan6iLi'; -// // final tokenParameters = TokenParameters(thierryPrivate, '', '', ''); -// // expect(tokenParameters.didKey, expectedDid); -// // }); -// // test('did EBSI 2 from Thierry vectors', () { -// // final thierryPrivate = { -// // 'crv': 'secp256k1', -// // 'd': '2CYcyeeIGExqssjp0W3jzHdoEzSWHGBr0ukO66r0h2g', -// // 'kty': 'EC', -// // 'x': 'sg-ra2GWe8qoBIsBL2ZF7HjV71PP02nWuJLnTL2bn7E', -// // 'y': 'h8F81NtkFSHgyY_KCEjXhDfQEU_Jv0AEHMvR9EW65xs' -// // }; -// // const expectedDid = -// // 'did:ebsi:zcpweJw1cLnMM4yaWHRGjSKpuyGNq7SSTuQrBLp5tCpEz'; -// // final tokenParameters = TokenParameters(thierryPrivate, '', '', ''); -// // expect(tokenParameters.didKey, expectedDid); -// // }); -// // test('did EBSI 3 from Thierry vectors', () { -// // final thierryPrivate = { -// // 'crv': 'secp256k1', -// // 'd': 'zlZrsHYH8aeaJWu4ptTjNnDhgBGyFc0UguJ8N4zbsdA', -// // 'kty': 'EC', -// // 'x': 'hdEzHBKnhigtNoU7nIaxQJWIVTqVcuEZdpOKUzkAfkA', -// // 'y': 'Gq1zCf9H0_Wyo5nNyjR8IA-XgTkX1PYaBYb2WKYF3PQ' -// // }; -// // const expectedDid = -// // 'did:ebsi:zgfaTZiwnaK7k4Zf9ce9ydcYQKh76QJcpf2MFDeKYSj1c'; -// // final tokenParameters = TokenParameters(thierryPrivate, '', '', ''); -// // expect(tokenParameters.didKey, expectedDid); -// // }); - -// // test('did EBSI from Alice s key', () { -// // final aliceKey = { -// // 'crv': 'P-256', -// // 'd': 'd_PpSCGQWWgUc1t4iLLH8bKYlYfc9Zy_M7TsfOAcbg8', -// // 'kty': 'EC', -// // 'x': 'ngy44T1vxAT6Di4nr-UaM9K3Tlnz9pkoksDokKFkmNc', -// // 'y': 'QCRfOKlSM31GTkb4JHx3nXB4G_jSPMsbdjzlkT_UpPc', -// // }; - -// // const expectedDid = -// // 'did:ebsi:znxntxQrN369GsNyjFjYb8fuvU7g3sJGyYGwMTcUGdzuy'; -// // final tokenParameters = TokenParameters(aliceKey, '', '', ''); -// // expect(tokenParameters.didKey, expectedDid); -// // }); -// // }); -// }); -// } +// ignore: unnecessary_lambdas + +// Copyright (c) 2022, Very Good Ventures +// https://verygood.ventures +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +// ignore_for_file: lines_longer_than_80_chars + +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +import 'token_parameters_class.dart'; + +class MockDio extends Mock implements Dio {} + +void main() { + group('TokenParameters', () { + final tokenParametersTest = TokenParameterTest(); + + test( + 'public key is P-256K private key without d parameter', + tokenParametersTest.publicKeyTest, + ); + + test('did EBSI', tokenParametersTest.didTest); + + test('kID EBSI', tokenParametersTest.keyIdTest); + + group('algorithm test', () { + test( + "algorithm is ES256K when key's curve is not P-256", + tokenParametersTest.algorithmIsES256KTest, + ); + + test( + "algorithm is ES256 when key's curve is P-256", + tokenParametersTest.algorithmIsES256Test, + ); + + test( + 'if alg is not null then return as it is', + tokenParametersTest.algorithmIsNotNullTest, + ); + }); + + group('thumbprint test', () { + test('thumbprint of the public Key', tokenParametersTest.thumprintOfKey); + + test( + 'thumbrprint of the Key from exemple in rfc 7638', + tokenParametersTest.thumprintOfKeyForrfc7638, + ); + }); + + test('get alg', () { + const keyWithAlg = { + 'crv': 'P-256K', + 'd': 'ccWWNSjGiv1iWlNh4kfhWvwG3yyQMe8o31Du0uKRzrs', + 'kty': 'EC', + 'x': 'J4vQtLUyrVUiFIXRrtEq4xurmBZp2eq9wJmXkIA_stI', + 'y': 'EUU6vXoG3BGX2zzwjXrGDcr4EyDD0Vfk3_5fg5kSgKE', + 'alg': 'HS256', + }; + + final tokenParameters = TokenParameters( + privateKey: keyWithAlg, + clientId: '', + did: '', + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + ); + expect(tokenParameters.alg, 'HS256'); + }); + }); +} diff --git a/packages/oidc4vc/test/src/vc_format_type_test.dart b/packages/oidc4vc/test/src/vc_format_type_test.dart new file mode 100644 index 000000000..ee4f52fc6 --- /dev/null +++ b/packages/oidc4vc/test/src/vc_format_type_test.dart @@ -0,0 +1,38 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +void main() { + group('VCFormatTypeX', () { + test('formattedString', () { + expect(VCFormatType.ldpVc.formattedString, 'ldp_vc'); + expect(VCFormatType.jwtVc.formattedString, 'jwt_vc'); + expect(VCFormatType.jwtVcJson.formattedString, 'jwt_vc_json'); + expect(VCFormatType.jwtVcJsonLd.formattedString, 'jwt_vc_json-ld'); + expect(VCFormatType.vcSdJWT.formattedString, 'vc+sd-jwt'); + }); + + test('value', () { + expect(VCFormatType.ldpVc.value, 'ldp_vc'); + expect(VCFormatType.jwtVc.value, 'jwt_vc'); + expect(VCFormatType.jwtVcJson.value, 'jwt_vc_json'); + expect(VCFormatType.jwtVcJsonLd.value, 'jwt_vc_json-ld'); + expect(VCFormatType.vcSdJWT.value, 'vc+sd-jwt'); + }); + + test('urlValue', () { + expect(VCFormatType.ldpVc.urlValue, 'ldp_vc'); + expect(VCFormatType.jwtVc.urlValue, 'jwt_vc'); + expect(VCFormatType.jwtVcJson.urlValue, 'jwt_vc_json'); + expect(VCFormatType.jwtVcJsonLd.urlValue, 'jwt_vc_json-ld'); + expect(VCFormatType.vcSdJWT.urlValue, 'vcsd-jwt'); + }); + + test('supportCryptoCredential', () { + expect(VCFormatType.ldpVc.supportCryptoCredential, true); + expect(VCFormatType.jwtVc.supportCryptoCredential, false); + expect(VCFormatType.jwtVcJson.supportCryptoCredential, true); + expect(VCFormatType.jwtVcJsonLd.supportCryptoCredential, false); + expect(VCFormatType.vcSdJWT.supportCryptoCredential, false); + }); + }); +} diff --git a/packages/oidc4vc/test/src/verifier_token_parameters/verifier_token_parameters_class.dart b/packages/oidc4vc/test/src/verifier_token_parameters/verifier_token_parameters_class.dart index a681b97f1..44acfca68 100644 --- a/packages/oidc4vc/test/src/verifier_token_parameters/verifier_token_parameters_class.dart +++ b/packages/oidc4vc/test/src/verifier_token_parameters/verifier_token_parameters_class.dart @@ -1,56 +1,96 @@ -// import 'package:flutter_test/flutter_test.dart'; -// import 'package:oidc4vc/oidc4vc.dart'; - -// import '../const_values.dart'; -// import '../token_parameters/token_parameters_class.dart'; - -// class VerifierTokenParametersTest extends TokenParameterTest { -// final verifierTokenParameters = -// VerifierTokenParameters(privateKey, '', '', '', [], ''); - -// @override -// void publicKeyTest() { -// expect(verifierTokenParameters.publicJWK, publicJWK); -// } - -// @override -// void didTest() { -// expect(tokenParameters.did, didKey); -// } - -// @override -// void keyIdTest() { -// expect(tokenParameters.kid, kid); -// } - -// @override -// void algorithmIsES256KTest() { -// expect(tokenParameters.alg, ES256KAlg); -// } - -// @override -// void algorithmIsES256Test() { -// final tokenParameters = -// VerifierTokenParameters(privateKey2, '', '', '', [], ''); -// expect(tokenParameters.alg, ES256Alg); -// } - -// @override -// void algorithmIsNotNullTest() { -// final tokenParameters = -// VerifierTokenParameters(keyWithAlg, '', '', '', [], ''); -// expect(tokenParameters.alg, HS256Alg); -// } - -// // @override -// // void thumprintOfKey() { -// // expect(tokenParameters.thumbprint, thumbprint); -// // } - -// // @override -// // void thumprintOfKeyForrfc7638() { -// // final tokenParameters2 = -// // VerifierTokenParameters(rfc7638Jwk, '', '', '', Uri.parse(''), []); -// // expect(tokenParameters2.thumbprint, expectedThumbprintForrfc7638Jwk); -// // } -// } +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +import '../const_values.dart'; +import '../token_parameters/token_parameters_class.dart'; + +class VerifierTokenParametersTest extends TokenParameterTest { + final verifierTokenParameters = VerifierTokenParameters( + privateKey: privateKey, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + audience: '', + credentials: [], + kid: '', + nonce: '', + ); + + @override + void publicKeyTest() { + expect(verifierTokenParameters.publicJWK, publicJWK); + } + + @override + void didTest() { + expect(tokenParameters.did, clientId); + } + + @override + void keyIdTest() { + expect(tokenParameters.kid, kid); + } + + @override + void algorithmIsES256KTest() { + expect(tokenParameters.alg, ES256KAlg); + } + + @override + void algorithmIsES256Test() { + final tokenParameters = VerifierTokenParameters( + privateKey: privateKey2, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + audience: '', + credentials: [], + kid: '', + nonce: '', + ); + expect(tokenParameters.alg, ES256Alg); + } + + @override + void algorithmIsNotNullTest() { + final tokenParameters = VerifierTokenParameters( + privateKey: keyWithAlg, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + audience: '', + credentials: [], + kid: '', + nonce: '', + ); + expect(tokenParameters.alg, HS256Alg); + } + + @override + void thumprintOfKey() { + expect(tokenParameters.thumbprint, thumbprint); + } + + @override + void thumprintOfKeyForrfc7638() { + final tokenParameters2 = VerifierTokenParameters( + privateKey: rfc7638Jwk, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + audience: '', + credentials: [], + kid: '', + nonce: '', + ); + expect(tokenParameters2.thumbprint, expectedThumbprintForrfc7638Jwk); + } +} diff --git a/packages/oidc4vc/test/src/verifier_token_parameters/verifier_token_parameters_test.dart b/packages/oidc4vc/test/src/verifier_token_parameters/verifier_token_parameters_test.dart index f22b2edb4..89743d4f2 100644 --- a/packages/oidc4vc/test/src/verifier_token_parameters/verifier_token_parameters_test.dart +++ b/packages/oidc4vc/test/src/verifier_token_parameters/verifier_token_parameters_test.dart @@ -1,187 +1,194 @@ -// // Copyright (c) 2022, Very Good Ventures -// // https://verygood.ventures -// // -// // Use of this source code is governed by an MIT-style -// // license that can be found in the LICENSE file or at -// // https://opensource.org/licenses/MIT. - -// import 'package:flutter_test/flutter_test.dart'; -// import 'package:oidc4vc/oidc4vc.dart'; - -// import 'verifier_token_parameters_class.dart'; - -// void main() { -// group('Verifier TokenParameters', () { -// const privateKey = { -// 'crv': 'P-256K', -// 'd': 'ccWWNSjGiv1iWlNh4kfhWvwG3yyQMe8o31Du0uKRzrs', -// 'kty': 'EC', -// 'x': 'J4vQtLUyrVUiFIXRrtEq4xurmBZp2eq9wJmXkIA_stI', -// 'y': 'EUU6vXoG3BGX2zzwjXrGDcr4EyDD0Vfk3_5fg5kSgKE', -// }; - -// const credentialsToBePresented = [ -// r'{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","receivedId":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","image":null,"data":{"@context":["https://www.w3.org/2018/credentials/v1"],"credentialSchema":{"id":"https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","type":"JsonSchemaValidator2018"},"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020"},"credentialSubject":{"awardingOpportunity":{"awardingBody":{"eidasLegalIdentifier":"Unknown","homepage":"https://leaston.bcdiploma.com/","id":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","preferredName":"Leaston University","registration":"0597065J"},"endedAtTime":"2020-06-26T00:00:00Z","id":"https://leaston.bcdiploma.com/law-economics-management#AwardingOpportunity","identifier":"https://certificate-demo.bcdiploma.com/check/87ED2F2270E6C41456E94B86B9D9115B4E35BCCAD200A49B846592C14F79C86BV1Fnbllta0NZTnJkR3lDWlRmTDlSRUJEVFZISmNmYzJhUU5sZUJ5Z2FJSHpWbmZZ","location":"FRANCE","startedAtTime":"2019-09-02T00:00:00Z"},"dateOfBirth":"1993-04-08","familyName":"DOE","givenNames":"Jane","gradingScheme":{"id":"https://leaston.bcdiploma.com/law-economics-management#GradingScheme","title":"2 year full-time programme / 4 semesters"},"id":"did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa","identifier":"0904008084H","learningAchievement":{"additionalNote":["DISTRIBUTION MANAGEMENT"],"description":"The Master in Information and Computer Sciences (MICS) at the University of Luxembourg enables students to acquire deeper knowledge in computer science by understanding its abstract and interdisciplinary foundations, focusing on problem solving and developing lifelong learning skills.","id":"https://leaston.bcdiploma.com/law-economics-management#LearningAchievment","title":"Master in Information and Computer Sciences"},"learningSpecification":{"ectsCreditPoints":120,"eqfLevel":7,"id":"https://leaston.bcdiploma.com/law-economics-management#LearningSpecification","iscedfCode":["7"],"nqfLevel":["7"]}},"evidence":{"documentPresence":["Physical"],"evidenceDocument":["Passport"],"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","subjectPresence":"Physical","type":["DocumentVerification"],"verifier":"did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a"},"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","issuanceDate":"2023-02-08T15:10:56Z","issued":"2023-02-08T15:10:56Z","issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","proof":{"created":"2022-04-27T12:25:07Z","creator":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","domain":"https://api.preprod.ebsi.eu","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ","nonce":"3ea68dae-d07a-4daa-932b-fbb58f5c20c4","type":"EcdsaSecp256k1Signature2019"},"type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"validFrom":"2023-02-08T15:10:56Z"},"shareLink":"","credentialPreview":{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","description":[],"name":[],"issuanceDate":"2023-02-08T15:10:56Z","proof":[{"type":"EcdsaSecp256k1Signature2019","proofPurpose":null,"verificationMethod":null,"created":"2022-04-27T12:25:07Z","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ"}],"credentialSubject":{"id":"did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa","type":null,"issuedBy":{"name":""}},"evidence":[{"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","type":["DocumentVerification"]}],"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020","revocationListIndex":"","revocationListCredential":""}},"display":{"backgroundColor":"","icon":"","nameFallback":"","descriptionFallback":""},"expirationDate":null,"credential_manifest":{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"id":"diploma_01","schema":"https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","name":null,"description":null,"styles":null,"display":{"title":{"path":[],"schema":{"type":"string","format":null},"fallback":"Diploma"},"subtitle":{"path":[],"schema":{"type":"string","format":null},"fallback":"EBSI Verifiable diploma"},"description":{"path":[],"schema":{"type":"string","format":null},"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework."},"properties":[{"label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number","format":null},"fallback":"Unknown"},{"label":"Issue date","path":["$.issuanceDate"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"type":"string","format":"uri"},"fallback":"Unknown"}]}}],"presentation_definition":null},"challenge":null,"domain":null,"activities":[{"acquisitionAt":"2023-02-08T20:41:02.024360","presentation":null}],"jwt":"eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiM1MTVhOWM0MzZjMGYyYWQzYWI2NWQ2Y2VmYzVjMWYwNmMwNWI4YWRmY2Y1NGVlMDZkYzgwNTQzMjA0NzBmZmFmIiwidHlwIjoiSldUIn0.eyJleHAiOjE2NzU4NzAwNTYuMTcxMDgyLCJpYXQiOjE2NzU4NjkwNTYuMTcxMDc1LCJpc3MiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsImp0aSI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsIm5iZiI6MTY3NTg2OTA1Ni4xNzEwOCwibm9uY2UiOiJjOGM3Nzg0Yi1hN2MyLTExZWQtOGUwMS0wYTE2Mjg5NTg1NjAiLCJzdWIiOiJkaWQ6ZWJzaTp6b3hSR1ZaUW5kVGZRazU0Qjd0S2R3d05kaGFpNWdtOUY4TmF2OGVjZU5BQmEiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9hcGkucHJlcHJvZC5lYnNpLmV1L3RydXN0ZWQtc2NoZW1hcy1yZWdpc3RyeS92MS9zY2hlbWFzLzB4YmY3OGZjMDhhN2E5ZjI4ZjU0NzlmNThkZWEyNjlkMzY1N2Y1NGYxM2NhMzdkMzgwY2Q0ZTkyMjM3ZmI2OTFkZCIsInR5cGUiOiJKc29uU2NoZW1hVmFsaWRhdG9yMjAxOCJ9LCJjcmVkZW50aWFsU3RhdHVzIjp7ImlkIjoiaHR0cHM6Ly9lc3NpZi5ldXJvcGEuZXUvc3RhdHVzL2VkdWNhdGlvbiNoaWdoZXJFZHVjYXRpb24jMzkyYWM3ZjYtMzk5YS00MzdiLWEyNjgtNDY5MWVhZDhmMTc2IiwidHlwZSI6IkNyZWRlbnRpYWxTdGF0dXNMaXN0MjAyMCJ9LCJjcmVkZW50aWFsU3ViamVjdCI6eyJhd2FyZGluZ09wcG9ydHVuaXR5Ijp7ImF3YXJkaW5nQm9keSI6eyJlaWRhc0xlZ2FsSWRlbnRpZmllciI6IlVua25vd24iLCJob21lcGFnZSI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tLyIsImlkIjoiZGlkOmVic2k6emRSdnZLYlhoVlZCc1hoYXRqdWlCaHMiLCJwcmVmZXJyZWROYW1lIjoiTGVhc3RvbiBVbml2ZXJzaXR5IiwicmVnaXN0cmF0aW9uIjoiMDU5NzA2NUoifSwiZW5kZWRBdFRpbWUiOiIyMDIwLTA2LTI2VDAwOjAwOjAwWiIsImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0F3YXJkaW5nT3Bwb3J0dW5pdHkiLCJpZGVudGlmaWVyIjoiaHR0cHM6Ly9jZXJ0aWZpY2F0ZS1kZW1vLmJjZGlwbG9tYS5jb20vY2hlY2svODdFRDJGMjI3MEU2QzQxNDU2RTk0Qjg2QjlEOTExNUI0RTM1QkNDQUQyMDBBNDlCODQ2NTkyQzE0Rjc5Qzg2QlYxRm5ibGx0YTBOWlRuSmtSM2xEV2xSbVREbFNSVUpFVkZaSVNtTm1ZekpoVVU1c1pVSjVaMkZKU0hwV2JtWloiLCJsb2NhdGlvbiI6IkZSQU5DRSIsInN0YXJ0ZWRBdFRpbWUiOiIyMDE5LTA5LTAyVDAwOjAwOjAwWiJ9LCJkYXRlT2ZCaXJ0aCI6IjE5OTMtMDQtMDgiLCJmYW1pbHlOYW1lIjoiRE9FIiwiZ2l2ZW5OYW1lcyI6IkphbmUiLCJncmFkaW5nU2NoZW1lIjp7ImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0dyYWRpbmdTY2hlbWUiLCJ0aXRsZSI6IjIgeWVhciBmdWxsLXRpbWUgcHJvZ3JhbW1lIC8gNCBzZW1lc3RlcnMifSwiaWQiOiJkaWQ6ZWJzaTp6b3hSR1ZaUW5kVGZRazU0Qjd0S2R3d05kaGFpNWdtOUY4TmF2OGVjZU5BQmEiLCJpZGVudGlmaWVyIjoiMDkwNDAwODA4NEgiLCJsZWFybmluZ0FjaGlldmVtZW50Ijp7ImFkZGl0aW9uYWxOb3RlIjpbIkRJU1RSSUJVVElPTiBNQU5BR0VNRU5UIl0sImRlc2NyaXB0aW9uIjoiVGhlIE1hc3RlciBpbiBJbmZvcm1hdGlvbiBhbmQgQ29tcHV0ZXIgU2NpZW5jZXMgKE1JQ1MpIGF0IHRoZSBVbml2ZXJzaXR5IG9mIEx1eGVtYm91cmcgZW5hYmxlcyBzdHVkZW50cyB0byBhY3F1aXJlIGRlZXBlciBrbm93bGVkZ2UgaW4gY29tcHV0ZXIgc2NpZW5jZSBieSB1bmRlcnN0YW5kaW5nIGl0cyBhYnN0cmFjdCBhbmQgaW50ZXJkaXNjaXBsaW5hcnkgZm91bmRhdGlvbnMsIGZvY3VzaW5nIG9uIHByb2JsZW0gc29sdmluZyBhbmQgZGV2ZWxvcGluZyBsaWZlbG9uZyBsZWFybmluZyBza2lsbHMuIiwiaWQiOiJodHRwczovL2xlYXN0b24uYmNkaXBsb21hLmNvbS9sYXctZWNvbm9taWNzLW1hbmFnZW1lbnQjTGVhcm5pbmdBY2hpZXZtZW50IiwidGl0bGUiOiJNYXN0ZXIgaW4gSW5mb3JtYXRpb24gYW5kIENvbXB1dGVyIFNjaWVuY2VzIn0sImxlYXJuaW5nU3BlY2lmaWNhdGlvbiI6eyJlY3RzQ3JlZGl0UG9pbnRzIjoxMjAsImVxZkxldmVsIjo3LCJpZCI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tL2xhdy1lY29ub21pY3MtbWFuYWdlbWVudCNMZWFybmluZ1NwZWNpZmljYXRpb24iLCJpc2NlZGZDb2RlIjpbIjciXSwibnFmTGV2ZWwiOlsiNyJdfX0sImV2aWRlbmNlIjp7ImRvY3VtZW50UHJlc2VuY2UiOlsiUGh5c2ljYWwiXSwiZXZpZGVuY2VEb2N1bWVudCI6WyJQYXNzcG9ydCJdLCJpZCI6Imh0dHBzOi8vZXNzaWYuZXVyb3BhLmV1L3Rzci12YS9ldmlkZW5jZS9mMmFlZWM5Ny1mYzBkLTQyYmYtOGNhNy0wNTQ4MTkyZDU2NzgiLCJzdWJqZWN0UHJlc2VuY2UiOiJQaHlzaWNhbCIsInR5cGUiOlsiRG9jdW1lbnRWZXJpZmljYXRpb24iXSwidmVyaWZpZXIiOiJkaWQ6ZWJzaToyOTYyZmI3ODRkZjYxYmFhMjY3YzgxMzI0OTc1MzlmOGM2NzRiMzdjMTI0NGE3YSJ9LCJpZCI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsImlzc3VhbmNlRGF0ZSI6IjIwMjMtMDItMDhUMTU6MTA6NTZaIiwiaXNzdWVkIjoiMjAyMy0wMi0wOFQxNToxMDo1NloiLCJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsInByb29mIjp7ImNyZWF0ZWQiOiIyMDIyLTA0LTI3VDEyOjI1OjA3WiIsImNyZWF0b3IiOiJkaWQ6ZWJzaTp6ZFJ2dktiWGhWVkJzWGhhdGp1aUJocyIsImRvbWFpbiI6Imh0dHBzOi8vYXBpLnByZXByb2QuZWJzaS5ldSIsImp3cyI6ImV5SmlOalFpT21aaGJITmxMQ0pqY21sMElqcGJJbUkyTkNKZExDSmhiR2NpT2lKRlV6STFOa3NpZlEuLm1JQm5NOFhEUXFTWUtRTlhfTHZhSmhtc2J5Q3I1T1o1Y1UyWmstUmVxTHByNGRvRnNnbW9vYmtPNTEyOHRaeS04S2ltVmpKa0d3MHdMMXVCV25NTFdRIiwibm9uY2UiOiIzZWE2OGRhZS1kMDdhLTRkYWEtOTMyYi1mYmI1OGY1YzIwYzQiLCJ0eXBlIjoiRWNkc2FTZWNwMjU2azFTaWduYXR1cmUyMDE5In0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJWZXJpZmlhYmxlQXR0ZXN0YXRpb24iLCJWZXJpZmlhYmxlRGlwbG9tYSJdLCJ2YWxpZEZyb20iOiIyMDIzLTAyLTA4VDE1OjEwOjU2WiJ9fQ.avhpj0UC7SJiOo8PWJV3zhJoxngdmrBnyTkQsnqe76JlOmatLkgAY5Mp_sUJQnN1uENiT-_KBf0KY3izx4X_SA"}', -// r'{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","receivedId":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","image":null,"data":{"@context":["https://www.w3.org/2018/credentials/v1"],"credentialSchema":{"id":"https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","type":"JsonSchemaValidator2018"},"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020"},"credentialSubject":{"awardingOpportunity":{"awardingBody":{"eidasLegalIdentifier":"Unknown","homepage":"https://leaston.bcdiploma.com/","id":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","preferredName":"Leaston University","registration":"0597065J"},"endedAtTime":"2020-06-26T00:00:00Z","id":"https://leaston.bcdiploma.com/law-economics-management#AwardingOpportunity","identifier":"https://certificate-demo.bcdiploma.com/check/87ED2F2270E6C41456E94B86B9D9115B4E35BCCAD200A49B846592C14F79C86BV1Fnbllta0NZTnJkR3lDWlRmTDlSRUJEVFZISmNmYzJhUU5sZUJ5Z2FJSHpWbmZZ","location":"FRANCE","startedAtTime":"2019-09-02T00:00:00Z"},"dateOfBirth":"1993-04-08","familyName":"DOE","givenNames":"Jane","gradingScheme":{"id":"https://leaston.bcdiploma.com/law-economics-management#GradingScheme","title":"2 year full-time programme / 4 semesters"},"id":"did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa","identifier":"0904008084H","learningAchievement":{"additionalNote":["DISTRIBUTION MANAGEMENT"],"description":"The Master in Information and Computer Sciences (MICS) at the University of Luxembourg enables students to acquire deeper knowledge in computer science by understanding its abstract and interdisciplinary foundations, focusing on problem solving and developing lifelong learning skills.","id":"https://leaston.bcdiploma.com/law-economics-management#LearningAchievment","title":"Master in Information and Computer Sciences"},"learningSpecification":{"ectsCreditPoints":120,"eqfLevel":7,"id":"https://leaston.bcdiploma.com/law-economics-management#LearningSpecification","iscedfCode":["7"],"nqfLevel":["7"]}},"evidence":{"documentPresence":["Physical"],"evidenceDocument":["Passport"],"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","subjectPresence":"Physical","type":["DocumentVerification"],"verifier":"did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a"},"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","issuanceDate":"2023-02-08T15:10:56Z","issued":"2023-02-08T15:10:56Z","issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","proof":{"created":"2022-04-27T12:25:07Z","creator":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","domain":"https://api.preprod.ebsi.eu","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ","nonce":"3ea68dae-d07a-4daa-932b-fbb58f5c20c4","type":"EcdsaSecp256k1Signature2019"},"type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"validFrom":"2023-02-08T15:10:56Z"},"shareLink":"","credentialPreview":{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","description":[],"name":[],"issuanceDate":"2023-02-08T15:10:56Z","proof":[{"type":"EcdsaSecp256k1Signature2019","proofPurpose":null,"verificationMethod":null,"created":"2022-04-27T12:25:07Z","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ"}],"credentialSubject":{"id":"did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa","type":null,"issuedBy":{"name":""}},"evidence":[{"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","type":["DocumentVerification"]}],"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020","revocationListIndex":"","revocationListCredential":""}},"display":{"backgroundColor":"","icon":"","nameFallback":"","descriptionFallback":""},"expirationDate":null,"credential_manifest":{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"id":"diploma_01","schema":"https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","name":null,"description":null,"styles":null,"display":{"title":{"path":[],"schema":{"type":"string","format":null},"fallback":"Diploma"},"subtitle":{"path":[],"schema":{"type":"string","format":null},"fallback":"EBSI Verifiable diploma"},"description":{"path":[],"schema":{"type":"string","format":null},"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework."},"properties":[{"label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number","format":null},"fallback":"Unknown"},{"label":"Issue date","path":["$.issuanceDate"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"type":"string","format":"uri"},"fallback":"Unknown"}]}}],"presentation_definition":null},"challenge":null,"domain":null,"activities":[{"acquisitionAt":"2023-02-08T20:41:02.024360","presentation":null}]}', -// ]; - -// final verifierTokenParameters = VerifierTokenParameters( -// privateKey, -// '', -// '', -// '', -// credentialsToBePresented, -// '', -// ); - -// const nonce = '69165b47-a851-11ed-bd52-0a1628958560'; - -// const audience = 'xjcqarovuv'; - -// const jwtsOfCredentials = [ -// // ignore: lines_longer_than_80_chars -// 'eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiM1MTVhOWM0MzZjMGYyYWQzYWI2NWQ2Y2VmYzVjMWYwNmMwNWI4YWRmY2Y1NGVlMDZkYzgwNTQzMjA0NzBmZmFmIiwidHlwIjoiSldUIn0.eyJleHAiOjE2NzU4NzAwNTYuMTcxMDgyLCJpYXQiOjE2NzU4NjkwNTYuMTcxMDc1LCJpc3MiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsImp0aSI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsIm5iZiI6MTY3NTg2OTA1Ni4xNzEwOCwibm9uY2UiOiJjOGM3Nzg0Yi1hN2MyLTExZWQtOGUwMS0wYTE2Mjg5NTg1NjAiLCJzdWIiOiJkaWQ6ZWJzaTp6b3hSR1ZaUW5kVGZRazU0Qjd0S2R3d05kaGFpNWdtOUY4TmF2OGVjZU5BQmEiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9hcGkucHJlcHJvZC5lYnNpLmV1L3RydXN0ZWQtc2NoZW1hcy1yZWdpc3RyeS92MS9zY2hlbWFzLzB4YmY3OGZjMDhhN2E5ZjI4ZjU0NzlmNThkZWEyNjlkMzY1N2Y1NGYxM2NhMzdkMzgwY2Q0ZTkyMjM3ZmI2OTFkZCIsInR5cGUiOiJKc29uU2NoZW1hVmFsaWRhdG9yMjAxOCJ9LCJjcmVkZW50aWFsU3RhdHVzIjp7ImlkIjoiaHR0cHM6Ly9lc3NpZi5ldXJvcGEuZXUvc3RhdHVzL2VkdWNhdGlvbiNoaWdoZXJFZHVjYXRpb24jMzkyYWM3ZjYtMzk5YS00MzdiLWEyNjgtNDY5MWVhZDhmMTc2IiwidHlwZSI6IkNyZWRlbnRpYWxTdGF0dXNMaXN0MjAyMCJ9LCJjcmVkZW50aWFsU3ViamVjdCI6eyJhd2FyZGluZ09wcG9ydHVuaXR5Ijp7ImF3YXJkaW5nQm9keSI6eyJlaWRhc0xlZ2FsSWRlbnRpZmllciI6IlVua25vd24iLCJob21lcGFnZSI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tLyIsImlkIjoiZGlkOmVic2k6emRSdnZLYlhoVlZCc1hoYXRqdWlCaHMiLCJwcmVmZXJyZWROYW1lIjoiTGVhc3RvbiBVbml2ZXJzaXR5IiwicmVnaXN0cmF0aW9uIjoiMDU5NzA2NUoifSwiZW5kZWRBdFRpbWUiOiIyMDIwLTA2LTI2VDAwOjAwOjAwWiIsImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0F3YXJkaW5nT3Bwb3J0dW5pdHkiLCJpZGVudGlmaWVyIjoiaHR0cHM6Ly9jZXJ0aWZpY2F0ZS1kZW1vLmJjZGlwbG9tYS5jb20vY2hlY2svODdFRDJGMjI3MEU2QzQxNDU2RTk0Qjg2QjlEOTExNUI0RTM1QkNDQUQyMDBBNDlCODQ2NTkyQzE0Rjc5Qzg2QlYxRm5ibGx0YTBOWlRuSmtSM2xEV2xSbVREbFNSVUpFVkZaSVNtTm1ZekpoVVU1c1pVSjVaMkZKU0hwV2JtWloiLCJsb2NhdGlvbiI6IkZSQU5DRSIsInN0YXJ0ZWRBdFRpbWUiOiIyMDE5LTA5LTAyVDAwOjAwOjAwWiJ9LCJkYXRlT2ZCaXJ0aCI6IjE5OTMtMDQtMDgiLCJmYW1pbHlOYW1lIjoiRE9FIiwiZ2l2ZW5OYW1lcyI6IkphbmUiLCJncmFkaW5nU2NoZW1lIjp7ImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0dyYWRpbmdTY2hlbWUiLCJ0aXRsZSI6IjIgeWVhciBmdWxsLXRpbWUgcHJvZ3JhbW1lIC8gNCBzZW1lc3RlcnMifSwiaWQiOiJkaWQ6ZWJzaTp6b3hSR1ZaUW5kVGZRazU0Qjd0S2R3d05kaGFpNWdtOUY4TmF2OGVjZU5BQmEiLCJpZGVudGlmaWVyIjoiMDkwNDAwODA4NEgiLCJsZWFybmluZ0FjaGlldmVtZW50Ijp7ImFkZGl0aW9uYWxOb3RlIjpbIkRJU1RSSUJVVElPTiBNQU5BR0VNRU5UIl0sImRlc2NyaXB0aW9uIjoiVGhlIE1hc3RlciBpbiBJbmZvcm1hdGlvbiBhbmQgQ29tcHV0ZXIgU2NpZW5jZXMgKE1JQ1MpIGF0IHRoZSBVbml2ZXJzaXR5IG9mIEx1eGVtYm91cmcgZW5hYmxlcyBzdHVkZW50cyB0byBhY3F1aXJlIGRlZXBlciBrbm93bGVkZ2UgaW4gY29tcHV0ZXIgc2NpZW5jZSBieSB1bmRlcnN0YW5kaW5nIGl0cyBhYnN0cmFjdCBhbmQgaW50ZXJkaXNjaXBsaW5hcnkgZm91bmRhdGlvbnMsIGZvY3VzaW5nIG9uIHByb2JsZW0gc29sdmluZyBhbmQgZGV2ZWxvcGluZyBsaWZlbG9uZyBsZWFybmluZyBza2lsbHMuIiwiaWQiOiJodHRwczovL2xlYXN0b24uYmNkaXBsb21hLmNvbS9sYXctZWNvbm9taWNzLW1hbmFnZW1lbnQjTGVhcm5pbmdBY2hpZXZtZW50IiwidGl0bGUiOiJNYXN0ZXIgaW4gSW5mb3JtYXRpb24gYW5kIENvbXB1dGVyIFNjaWVuY2VzIn0sImxlYXJuaW5nU3BlY2lmaWNhdGlvbiI6eyJlY3RzQ3JlZGl0UG9pbnRzIjoxMjAsImVxZkxldmVsIjo3LCJpZCI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tL2xhdy1lY29ub21pY3MtbWFuYWdlbWVudCNMZWFybmluZ1NwZWNpZmljYXRpb24iLCJpc2NlZGZDb2RlIjpbIjciXSwibnFmTGV2ZWwiOlsiNyJdfX0sImV2aWRlbmNlIjp7ImRvY3VtZW50UHJlc2VuY2UiOlsiUGh5c2ljYWwiXSwiZXZpZGVuY2VEb2N1bWVudCI6WyJQYXNzcG9ydCJdLCJpZCI6Imh0dHBzOi8vZXNzaWYuZXVyb3BhLmV1L3Rzci12YS9ldmlkZW5jZS9mMmFlZWM5Ny1mYzBkLTQyYmYtOGNhNy0wNTQ4MTkyZDU2NzgiLCJzdWJqZWN0UHJlc2VuY2UiOiJQaHlzaWNhbCIsInR5cGUiOlsiRG9jdW1lbnRWZXJpZmljYXRpb24iXSwidmVyaWZpZXIiOiJkaWQ6ZWJzaToyOTYyZmI3ODRkZjYxYmFhMjY3YzgxMzI0OTc1MzlmOGM2NzRiMzdjMTI0NGE3YSJ9LCJpZCI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsImlzc3VhbmNlRGF0ZSI6IjIwMjMtMDItMDhUMTU6MTA6NTZaIiwiaXNzdWVkIjoiMjAyMy0wMi0wOFQxNToxMDo1NloiLCJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsInByb29mIjp7ImNyZWF0ZWQiOiIyMDIyLTA0LTI3VDEyOjI1OjA3WiIsImNyZWF0b3IiOiJkaWQ6ZWJzaTp6ZFJ2dktiWGhWVkJzWGhhdGp1aUJocyIsImRvbWFpbiI6Imh0dHBzOi8vYXBpLnByZXByb2QuZWJzaS5ldSIsImp3cyI6ImV5SmlOalFpT21aaGJITmxMQ0pqY21sMElqcGJJbUkyTkNKZExDSmhiR2NpT2lKRlV6STFOa3NpZlEuLm1JQm5NOFhEUXFTWUtRTlhfTHZhSmhtc2J5Q3I1T1o1Y1UyWmstUmVxTHByNGRvRnNnbW9vYmtPNTEyOHRaeS04S2ltVmpKa0d3MHdMMXVCV25NTFdRIiwibm9uY2UiOiIzZWE2OGRhZS1kMDdhLTRkYWEtOTMyYi1mYmI1OGY1YzIwYzQiLCJ0eXBlIjoiRWNkc2FTZWNwMjU2azFTaWduYXR1cmUyMDE5In0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJWZXJpZmlhYmxlQXR0ZXN0YXRpb24iLCJWZXJpZmlhYmxlRGlwbG9tYSJdLCJ2YWxpZEZyb20iOiIyMDIzLTAyLTA4VDE1OjEwOjU2WiJ9fQ.avhpj0UC7SJiOo8PWJV3zhJoxngdmrBnyTkQsnqe76JlOmatLkgAY5Mp_sUJQnN1uENiT-_KBf0KY3izx4X_SA', - -// { -// '@context': ['https://www.w3.org/2018/credentials/v1'], -// 'credentialSchema': { -// 'id': -// 'https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd', -// 'type': 'JsonSchemaValidator2018', -// }, -// 'credentialStatus': { -// 'id': -// 'https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176', -// 'type': 'CredentialStatusList2020', -// }, -// 'credentialSubject': { -// 'awardingOpportunity': { -// 'awardingBody': { -// 'eidasLegalIdentifier': 'Unknown', -// 'homepage': 'https://leaston.bcdiploma.com/', -// 'id': 'did:ebsi:zdRvvKbXhVVBsXhatjuiBhs', -// 'preferredName': 'Leaston University', -// 'registration': '0597065J', -// }, -// 'endedAtTime': '2020-06-26T00:00:00Z', -// 'id': -// 'https://leaston.bcdiploma.com/law-economics-management#AwardingOpportunity', -// 'identifier': -// 'https://certificate-demo.bcdiploma.com/check/87ED2F2270E6C41456E94B86B9D9115B4E35BCCAD200A49B846592C14F79C86BV1Fnbllta0NZTnJkR3lDWlRmTDlSRUJEVFZISmNmYzJhUU5sZUJ5Z2FJSHpWbmZZ', -// 'location': 'FRANCE', -// 'startedAtTime': '2019-09-02T00:00:00Z', -// }, -// 'dateOfBirth': '1993-04-08', -// 'familyName': 'DOE', -// 'givenNames': 'Jane', -// 'gradingScheme': { -// 'id': -// 'https://leaston.bcdiploma.com/law-economics-management#GradingScheme', -// 'title': '2 year full-time programme / 4 semesters', -// }, -// 'id': 'did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa', -// 'identifier': '0904008084H', -// 'learningAchievement': { -// 'additionalNote': ['DISTRIBUTION MANAGEMENT'], -// 'description': -// 'The Master in Information and Computer Sciences (MICS) at the University of Luxembourg enables students to acquire deeper knowledge in computer science by understanding its abstract and interdisciplinary foundations, focusing on problem solving and developing lifelong learning skills.', // ignore: lines_longer_than_80_chars -// 'id': -// 'https://leaston.bcdiploma.com/law-economics-management#LearningAchievment', -// 'title': 'Master in Information and Computer Sciences', -// }, -// 'learningSpecification': { -// 'ectsCreditPoints': 120, -// 'eqfLevel': 7, -// 'id': -// 'https://leaston.bcdiploma.com/law-economics-management#LearningSpecification', -// 'iscedfCode': ['7'], -// 'nqfLevel': ['7'], -// }, -// }, -// 'evidence': { -// 'documentPresence': ['Physical'], -// 'evidenceDocument': ['Passport'], -// 'id': -// 'https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678', -// 'subjectPresence': 'Physical', -// 'type': ['DocumentVerification'], -// 'verifier': -// 'did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a', -// }, -// 'id': 'urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236', -// 'issuanceDate': '2023-02-08T15:10:56Z', -// 'issued': '2023-02-08T15:10:56Z', -// 'issuer': 'did:ebsi:zhSw5rPXkcHjvquwnVcTzzB', -// 'proof': { -// 'created': '2022-04-27T12:25:07Z', -// 'creator': 'did:ebsi:zdRvvKbXhVVBsXhatjuiBhs', -// 'domain': 'https://api.preprod.ebsi.eu', -// 'jws': -// 'eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ', // ignore: lines_longer_than_80_chars -// 'nonce': '3ea68dae-d07a-4daa-932b-fbb58f5c20c4', -// 'type': 'EcdsaSecp256k1Signature2019', -// }, -// 'type': [ -// 'VerifiableCredential', -// 'VerifiableAttestation', -// 'VerifiableDiploma', -// ], -// 'validFrom': '2023-02-08T15:10:56Z', -// } -// ]; - -// test('nonce', () { -// expect(verifierTokenParameters.nonce, nonce); -// }); - -// test('jwtsOfCredentials', () { -// expect(verifierTokenParameters.jsonIdOrJwtList, jwtsOfCredentials); -// }); - -// test('audience', () { -// expect(verifierTokenParameters.audience, audience); -// }); - -// group('override test', () { -// final verifierTokenParametersTest = VerifierTokenParametersTest(); - -// // test( -// // 'public key is P-256K private key without d parameter', -// // verifierTokenParametersTest.publicKeyTest, -// // ); - -// // test('did EBSI', verifierTokenParametersTest.didTest); - -// // test('kID EBSI', verifierTokenParametersTest.keyIdTest); - -// group('algorithm test', () { -// test( -// "algorithm is ES256K when key's curve is not P-256", -// verifierTokenParametersTest.algorithmIsES256KTest, -// ); - -// test( -// "algorithm is ES256 when key's curve is P-256", -// verifierTokenParametersTest.algorithmIsES256Test, -// ); - -// test( -// 'if alg is not null then return as it is', -// verifierTokenParametersTest.algorithmIsNotNullTest, -// ); -// }); - -// group('thumbprint test', () { -// // test( -// // 'thumbprint of the public Key', -// // verifierTokenParametersTest.thumprintOfKey, -// // ); - -// // test( -// // 'thumbrprint of the Key from exemple in rfc 7638', -// // verifierTokenParametersTest.thumprintOfKeyForrfc7638, -// // ); -// }); -// }); -// }); -// } +// Copyright (c) 2022, Very Good Ventures +// https://verygood.ventures +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +import 'verifier_token_parameters_class.dart'; + +void main() { + group('Verifier TokenParameters', () { + const privateKey = { + 'crv': 'P-256K', + 'd': 'ccWWNSjGiv1iWlNh4kfhWvwG3yyQMe8o31Du0uKRzrs', + 'kty': 'EC', + 'x': 'J4vQtLUyrVUiFIXRrtEq4xurmBZp2eq9wJmXkIA_stI', + 'y': 'EUU6vXoG3BGX2zzwjXrGDcr4EyDD0Vfk3_5fg5kSgKE', + }; + + const clientId = + '''did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9Kbrbpg5is8LfTLuQ1RsW5r7s7ZjbDDFbDgy1tLrdc7Bj3itBGQkuGUQyfzKhFqbUNW2PqJPMSSzWoF2DGSvDSijCtJtYCSRsjSVLrwu5oHNbnPFvSEC4iRZPpU6B6nExRBTa'''; + + const credentialsToBePresented = [ + r'{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","receivedId":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","image":null,"data":{"@context":["https://www.w3.org/2018/credentials/v1"],"credentialSchema":{"id":"https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","type":"JsonSchemaValidator2018"},"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020"},"credentialSubject":{"awardingOpportunity":{"awardingBody":{"eidasLegalIdentifier":"Unknown","homepage":"https://leaston.bcdiploma.com/","id":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","preferredName":"Leaston University","registration":"0597065J"},"endedAtTime":"2020-06-26T00:00:00Z","id":"https://leaston.bcdiploma.com/law-economics-management#AwardingOpportunity","identifier":"https://certificate-demo.bcdiploma.com/check/87ED2F2270E6C41456E94B86B9D9115B4E35BCCAD200A49B846592C14F79C86BV1Fnbllta0NZTnJkR3lDWlRmTDlSRUJEVFZISmNmYzJhUU5sZUJ5Z2FJSHpWbmZZ","location":"FRANCE","startedAtTime":"2019-09-02T00:00:00Z"},"dateOfBirth":"1993-04-08","familyName":"DOE","givenNames":"Jane","gradingScheme":{"id":"https://leaston.bcdiploma.com/law-economics-management#GradingScheme","title":"2 year full-time programme / 4 semesters"},"id":"did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa","identifier":"0904008084H","learningAchievement":{"additionalNote":["DISTRIBUTION MANAGEMENT"],"description":"The Master in Information and Computer Sciences (MICS) at the University of Luxembourg enables students to acquire deeper knowledge in computer science by understanding its abstract and interdisciplinary foundations, focusing on problem solving and developing lifelong learning skills.","id":"https://leaston.bcdiploma.com/law-economics-management#LearningAchievment","title":"Master in Information and Computer Sciences"},"learningSpecification":{"ectsCreditPoints":120,"eqfLevel":7,"id":"https://leaston.bcdiploma.com/law-economics-management#LearningSpecification","iscedfCode":["7"],"nqfLevel":["7"]}},"evidence":{"documentPresence":["Physical"],"evidenceDocument":["Passport"],"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","subjectPresence":"Physical","type":["DocumentVerification"],"verifier":"did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a"},"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","issuanceDate":"2023-02-08T15:10:56Z","issued":"2023-02-08T15:10:56Z","issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","proof":{"created":"2022-04-27T12:25:07Z","creator":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","domain":"https://api.preprod.ebsi.eu","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ","nonce":"3ea68dae-d07a-4daa-932b-fbb58f5c20c4","type":"EcdsaSecp256k1Signature2019"},"type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"validFrom":"2023-02-08T15:10:56Z"},"shareLink":"","credentialPreview":{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","description":[],"name":[],"issuanceDate":"2023-02-08T15:10:56Z","proof":[{"type":"EcdsaSecp256k1Signature2019","proofPurpose":null,"verificationMethod":null,"created":"2022-04-27T12:25:07Z","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ"}],"credentialSubject":{"id":"did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa","type":null,"issuedBy":{"name":""}},"evidence":[{"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","type":["DocumentVerification"]}],"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020","revocationListIndex":"","revocationListCredential":""}},"display":{"backgroundColor":"","icon":"","nameFallback":"","descriptionFallback":""},"expirationDate":null,"credential_manifest":{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"id":"diploma_01","schema":"https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","name":null,"description":null,"styles":null,"display":{"title":{"path":[],"schema":{"type":"string","format":null},"fallback":"Diploma"},"subtitle":{"path":[],"schema":{"type":"string","format":null},"fallback":"EBSI Verifiable diploma"},"description":{"path":[],"schema":{"type":"string","format":null},"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework."},"properties":[{"label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number","format":null},"fallback":"Unknown"},{"label":"Issue date","path":["$.issuanceDate"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"type":"string","format":"uri"},"fallback":"Unknown"}]}}],"presentation_definition":null},"challenge":null,"domain":null,"activities":[{"acquisitionAt":"2023-02-08T20:41:02.024360","presentation":null}],"jwt":"eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiM1MTVhOWM0MzZjMGYyYWQzYWI2NWQ2Y2VmYzVjMWYwNmMwNWI4YWRmY2Y1NGVlMDZkYzgwNTQzMjA0NzBmZmFmIiwidHlwIjoiSldUIn0.eyJleHAiOjE2NzU4NzAwNTYuMTcxMDgyLCJpYXQiOjE2NzU4NjkwNTYuMTcxMDc1LCJpc3MiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsImp0aSI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsIm5iZiI6MTY3NTg2OTA1Ni4xNzEwOCwibm9uY2UiOiJjOGM3Nzg0Yi1hN2MyLTExZWQtOGUwMS0wYTE2Mjg5NTg1NjAiLCJzdWIiOiJkaWQ6ZWJzaTp6b3hSR1ZaUW5kVGZRazU0Qjd0S2R3d05kaGFpNWdtOUY4TmF2OGVjZU5BQmEiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9hcGkucHJlcHJvZC5lYnNpLmV1L3RydXN0ZWQtc2NoZW1hcy1yZWdpc3RyeS92MS9zY2hlbWFzLzB4YmY3OGZjMDhhN2E5ZjI4ZjU0NzlmNThkZWEyNjlkMzY1N2Y1NGYxM2NhMzdkMzgwY2Q0ZTkyMjM3ZmI2OTFkZCIsInR5cGUiOiJKc29uU2NoZW1hVmFsaWRhdG9yMjAxOCJ9LCJjcmVkZW50aWFsU3RhdHVzIjp7ImlkIjoiaHR0cHM6Ly9lc3NpZi5ldXJvcGEuZXUvc3RhdHVzL2VkdWNhdGlvbiNoaWdoZXJFZHVjYXRpb24jMzkyYWM3ZjYtMzk5YS00MzdiLWEyNjgtNDY5MWVhZDhmMTc2IiwidHlwZSI6IkNyZWRlbnRpYWxTdGF0dXNMaXN0MjAyMCJ9LCJjcmVkZW50aWFsU3ViamVjdCI6eyJhd2FyZGluZ09wcG9ydHVuaXR5Ijp7ImF3YXJkaW5nQm9keSI6eyJlaWRhc0xlZ2FsSWRlbnRpZmllciI6IlVua25vd24iLCJob21lcGFnZSI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tLyIsImlkIjoiZGlkOmVic2k6emRSdnZLYlhoVlZCc1hoYXRqdWlCaHMiLCJwcmVmZXJyZWROYW1lIjoiTGVhc3RvbiBVbml2ZXJzaXR5IiwicmVnaXN0cmF0aW9uIjoiMDU5NzA2NUoifSwiZW5kZWRBdFRpbWUiOiIyMDIwLTA2LTI2VDAwOjAwOjAwWiIsImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0F3YXJkaW5nT3Bwb3J0dW5pdHkiLCJpZGVudGlmaWVyIjoiaHR0cHM6Ly9jZXJ0aWZpY2F0ZS1kZW1vLmJjZGlwbG9tYS5jb20vY2hlY2svODdFRDJGMjI3MEU2QzQxNDU2RTk0Qjg2QjlEOTExNUI0RTM1QkNDQUQyMDBBNDlCODQ2NTkyQzE0Rjc5Qzg2QlYxRm5ibGx0YTBOWlRuSmtSM2xEV2xSbVREbFNSVUpFVkZaSVNtTm1ZekpoVVU1c1pVSjVaMkZKU0hwV2JtWloiLCJsb2NhdGlvbiI6IkZSQU5DRSIsInN0YXJ0ZWRBdFRpbWUiOiIyMDE5LTA5LTAyVDAwOjAwOjAwWiJ9LCJkYXRlT2ZCaXJ0aCI6IjE5OTMtMDQtMDgiLCJmYW1pbHlOYW1lIjoiRE9FIiwiZ2l2ZW5OYW1lcyI6IkphbmUiLCJncmFkaW5nU2NoZW1lIjp7ImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0dyYWRpbmdTY2hlbWUiLCJ0aXRsZSI6IjIgeWVhciBmdWxsLXRpbWUgcHJvZ3JhbW1lIC8gNCBzZW1lc3RlcnMifSwiaWQiOiJkaWQ6ZWJzaTp6b3hSR1ZaUW5kVGZRazU0Qjd0S2R3d05kaGFpNWdtOUY4TmF2OGVjZU5BQmEiLCJpZGVudGlmaWVyIjoiMDkwNDAwODA4NEgiLCJsZWFybmluZ0FjaGlldmVtZW50Ijp7ImFkZGl0aW9uYWxOb3RlIjpbIkRJU1RSSUJVVElPTiBNQU5BR0VNRU5UIl0sImRlc2NyaXB0aW9uIjoiVGhlIE1hc3RlciBpbiBJbmZvcm1hdGlvbiBhbmQgQ29tcHV0ZXIgU2NpZW5jZXMgKE1JQ1MpIGF0IHRoZSBVbml2ZXJzaXR5IG9mIEx1eGVtYm91cmcgZW5hYmxlcyBzdHVkZW50cyB0byBhY3F1aXJlIGRlZXBlciBrbm93bGVkZ2UgaW4gY29tcHV0ZXIgc2NpZW5jZSBieSB1bmRlcnN0YW5kaW5nIGl0cyBhYnN0cmFjdCBhbmQgaW50ZXJkaXNjaXBsaW5hcnkgZm91bmRhdGlvbnMsIGZvY3VzaW5nIG9uIHByb2JsZW0gc29sdmluZyBhbmQgZGV2ZWxvcGluZyBsaWZlbG9uZyBsZWFybmluZyBza2lsbHMuIiwiaWQiOiJodHRwczovL2xlYXN0b24uYmNkaXBsb21hLmNvbS9sYXctZWNvbm9taWNzLW1hbmFnZW1lbnQjTGVhcm5pbmdBY2hpZXZtZW50IiwidGl0bGUiOiJNYXN0ZXIgaW4gSW5mb3JtYXRpb24gYW5kIENvbXB1dGVyIFNjaWVuY2VzIn0sImxlYXJuaW5nU3BlY2lmaWNhdGlvbiI6eyJlY3RzQ3JlZGl0UG9pbnRzIjoxMjAsImVxZkxldmVsIjo3LCJpZCI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tL2xhdy1lY29ub21pY3MtbWFuYWdlbWVudCNMZWFybmluZ1NwZWNpZmljYXRpb24iLCJpc2NlZGZDb2RlIjpbIjciXSwibnFmTGV2ZWwiOlsiNyJdfX0sImV2aWRlbmNlIjp7ImRvY3VtZW50UHJlc2VuY2UiOlsiUGh5c2ljYWwiXSwiZXZpZGVuY2VEb2N1bWVudCI6WyJQYXNzcG9ydCJdLCJpZCI6Imh0dHBzOi8vZXNzaWYuZXVyb3BhLmV1L3Rzci12YS9ldmlkZW5jZS9mMmFlZWM5Ny1mYzBkLTQyYmYtOGNhNy0wNTQ4MTkyZDU2NzgiLCJzdWJqZWN0UHJlc2VuY2UiOiJQaHlzaWNhbCIsInR5cGUiOlsiRG9jdW1lbnRWZXJpZmljYXRpb24iXSwidmVyaWZpZXIiOiJkaWQ6ZWJzaToyOTYyZmI3ODRkZjYxYmFhMjY3YzgxMzI0OTc1MzlmOGM2NzRiMzdjMTI0NGE3YSJ9LCJpZCI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsImlzc3VhbmNlRGF0ZSI6IjIwMjMtMDItMDhUMTU6MTA6NTZaIiwiaXNzdWVkIjoiMjAyMy0wMi0wOFQxNToxMDo1NloiLCJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsInByb29mIjp7ImNyZWF0ZWQiOiIyMDIyLTA0LTI3VDEyOjI1OjA3WiIsImNyZWF0b3IiOiJkaWQ6ZWJzaTp6ZFJ2dktiWGhWVkJzWGhhdGp1aUJocyIsImRvbWFpbiI6Imh0dHBzOi8vYXBpLnByZXByb2QuZWJzaS5ldSIsImp3cyI6ImV5SmlOalFpT21aaGJITmxMQ0pqY21sMElqcGJJbUkyTkNKZExDSmhiR2NpT2lKRlV6STFOa3NpZlEuLm1JQm5NOFhEUXFTWUtRTlhfTHZhSmhtc2J5Q3I1T1o1Y1UyWmstUmVxTHByNGRvRnNnbW9vYmtPNTEyOHRaeS04S2ltVmpKa0d3MHdMMXVCV25NTFdRIiwibm9uY2UiOiIzZWE2OGRhZS1kMDdhLTRkYWEtOTMyYi1mYmI1OGY1YzIwYzQiLCJ0eXBlIjoiRWNkc2FTZWNwMjU2azFTaWduYXR1cmUyMDE5In0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJWZXJpZmlhYmxlQXR0ZXN0YXRpb24iLCJWZXJpZmlhYmxlRGlwbG9tYSJdLCJ2YWxpZEZyb20iOiIyMDIzLTAyLTA4VDE1OjEwOjU2WiJ9fQ.avhpj0UC7SJiOo8PWJV3zhJoxngdmrBnyTkQsnqe76JlOmatLkgAY5Mp_sUJQnN1uENiT-_KBf0KY3izx4X_SA"}', + r'{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","receivedId":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","image":null,"data":{"@context":["https://www.w3.org/2018/credentials/v1"],"credentialSchema":{"id":"https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","type":"JsonSchemaValidator2018"},"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020"},"credentialSubject":{"awardingOpportunity":{"awardingBody":{"eidasLegalIdentifier":"Unknown","homepage":"https://leaston.bcdiploma.com/","id":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","preferredName":"Leaston University","registration":"0597065J"},"endedAtTime":"2020-06-26T00:00:00Z","id":"https://leaston.bcdiploma.com/law-economics-management#AwardingOpportunity","identifier":"https://certificate-demo.bcdiploma.com/check/87ED2F2270E6C41456E94B86B9D9115B4E35BCCAD200A49B846592C14F79C86BV1Fnbllta0NZTnJkR3lDWlRmTDlSRUJEVFZISmNmYzJhUU5sZUJ5Z2FJSHpWbmZZ","location":"FRANCE","startedAtTime":"2019-09-02T00:00:00Z"},"dateOfBirth":"1993-04-08","familyName":"DOE","givenNames":"Jane","gradingScheme":{"id":"https://leaston.bcdiploma.com/law-economics-management#GradingScheme","title":"2 year full-time programme / 4 semesters"},"id":"did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa","identifier":"0904008084H","learningAchievement":{"additionalNote":["DISTRIBUTION MANAGEMENT"],"description":"The Master in Information and Computer Sciences (MICS) at the University of Luxembourg enables students to acquire deeper knowledge in computer science by understanding its abstract and interdisciplinary foundations, focusing on problem solving and developing lifelong learning skills.","id":"https://leaston.bcdiploma.com/law-economics-management#LearningAchievment","title":"Master in Information and Computer Sciences"},"learningSpecification":{"ectsCreditPoints":120,"eqfLevel":7,"id":"https://leaston.bcdiploma.com/law-economics-management#LearningSpecification","iscedfCode":["7"],"nqfLevel":["7"]}},"evidence":{"documentPresence":["Physical"],"evidenceDocument":["Passport"],"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","subjectPresence":"Physical","type":["DocumentVerification"],"verifier":"did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a"},"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","issuanceDate":"2023-02-08T15:10:56Z","issued":"2023-02-08T15:10:56Z","issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","proof":{"created":"2022-04-27T12:25:07Z","creator":"did:ebsi:zdRvvKbXhVVBsXhatjuiBhs","domain":"https://api.preprod.ebsi.eu","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ","nonce":"3ea68dae-d07a-4daa-932b-fbb58f5c20c4","type":"EcdsaSecp256k1Signature2019"},"type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"validFrom":"2023-02-08T15:10:56Z"},"shareLink":"","credentialPreview":{"id":"urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236","type":["VerifiableCredential","VerifiableAttestation","VerifiableDiploma"],"issuer":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","description":[],"name":[],"issuanceDate":"2023-02-08T15:10:56Z","proof":[{"type":"EcdsaSecp256k1Signature2019","proofPurpose":null,"verificationMethod":null,"created":"2022-04-27T12:25:07Z","jws":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ"}],"credentialSubject":{"id":"did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa","type":null,"issuedBy":{"name":""}},"evidence":[{"id":"https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678","type":["DocumentVerification"]}],"credentialStatus":{"id":"https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176","type":"CredentialStatusList2020","revocationListIndex":"","revocationListCredential":""}},"display":{"backgroundColor":"","icon":"","nameFallback":"","descriptionFallback":""},"expirationDate":null,"credential_manifest":{"id":"VerifiableDiploma_1","issuer":{"id":"did:ebsi:zhSw5rPXkcHjvquwnVcTzzB","name":"Test EBSILUX"},"output_descriptors":[{"id":"diploma_01","schema":"https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd","name":null,"description":null,"styles":null,"display":{"title":{"path":[],"schema":{"type":"string","format":null},"fallback":"Diploma"},"subtitle":{"path":[],"schema":{"type":"string","format":null},"fallback":"EBSI Verifiable diploma"},"description":{"path":[],"schema":{"type":"string","format":null},"fallback":"This card is a proof that you passed this diploma successfully. You can use this card when you need to prove this information to services that have adopted EU EBSI framework."},"properties":[{"label":"First name","path":["$.credentialSubject.firstName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Last name","path":["$.credentialSubject.familyName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Birth date","path":["$.credentialSubject.dateOfBirth"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Grading scheme","path":["$.credentialSubject.gradingScheme.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Title","path":["$.credentialSubject.learningAchievement.title"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Description","path":["$.credentialSubject.learningAchievement.description"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"ECTS Points","path":["$.credentialSubject.learningSpecification.ectsCreditPoints"],"schema":{"type":"number","format":null},"fallback":"Unknown"},{"label":"Issue date","path":["$.issuanceDate"],"schema":{"type":"string","format":"date"},"fallback":"Unknown"},{"label":"Issued by","path":["$.credentialSubject.awardingOpportunity.awardingBody.preferredName"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Registration","path":["$.credentialSubject.awardingOpportunity.awardingBody.registration"],"schema":{"type":"string","format":null},"fallback":"Unknown"},{"label":"Website","path":["$.credentialSubject.awardingOpportunity.awardingBody.homepage"],"schema":{"type":"string","format":"uri"},"fallback":"Unknown"}]}}],"presentation_definition":null},"challenge":null,"domain":null,"activities":[{"acquisitionAt":"2023-02-08T20:41:02.024360","presentation":null}]}', + ]; + + const nonce = '69165b47-a851-11ed-bd52-0a1628958560'; + + const audience = 'xjcqarovuv'; + + final verifierTokenParameters = VerifierTokenParameters( + privateKey: privateKey, + clientId: clientId, + did: clientId, + clientType: ClientType.did, + mediaType: MediaType.proofOfOwnership, + proofHeaderType: ProofHeaderType.kid, + audience: audience, + credentials: credentialsToBePresented, + kid: '', + nonce: nonce, + ); + + const jwtsOfCredentials = [ + // ignore: lines_longer_than_80_chars + 'eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiM1MTVhOWM0MzZjMGYyYWQzYWI2NWQ2Y2VmYzVjMWYwNmMwNWI4YWRmY2Y1NGVlMDZkYzgwNTQzMjA0NzBmZmFmIiwidHlwIjoiSldUIn0.eyJleHAiOjE2NzU4NzAwNTYuMTcxMDgyLCJpYXQiOjE2NzU4NjkwNTYuMTcxMDc1LCJpc3MiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsImp0aSI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsIm5iZiI6MTY3NTg2OTA1Ni4xNzEwOCwibm9uY2UiOiJjOGM3Nzg0Yi1hN2MyLTExZWQtOGUwMS0wYTE2Mjg5NTg1NjAiLCJzdWIiOiJkaWQ6ZWJzaTp6b3hSR1ZaUW5kVGZRazU0Qjd0S2R3d05kaGFpNWdtOUY4TmF2OGVjZU5BQmEiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9hcGkucHJlcHJvZC5lYnNpLmV1L3RydXN0ZWQtc2NoZW1hcy1yZWdpc3RyeS92MS9zY2hlbWFzLzB4YmY3OGZjMDhhN2E5ZjI4ZjU0NzlmNThkZWEyNjlkMzY1N2Y1NGYxM2NhMzdkMzgwY2Q0ZTkyMjM3ZmI2OTFkZCIsInR5cGUiOiJKc29uU2NoZW1hVmFsaWRhdG9yMjAxOCJ9LCJjcmVkZW50aWFsU3RhdHVzIjp7ImlkIjoiaHR0cHM6Ly9lc3NpZi5ldXJvcGEuZXUvc3RhdHVzL2VkdWNhdGlvbiNoaWdoZXJFZHVjYXRpb24jMzkyYWM3ZjYtMzk5YS00MzdiLWEyNjgtNDY5MWVhZDhmMTc2IiwidHlwZSI6IkNyZWRlbnRpYWxTdGF0dXNMaXN0MjAyMCJ9LCJjcmVkZW50aWFsU3ViamVjdCI6eyJhd2FyZGluZ09wcG9ydHVuaXR5Ijp7ImF3YXJkaW5nQm9keSI6eyJlaWRhc0xlZ2FsSWRlbnRpZmllciI6IlVua25vd24iLCJob21lcGFnZSI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tLyIsImlkIjoiZGlkOmVic2k6emRSdnZLYlhoVlZCc1hoYXRqdWlCaHMiLCJwcmVmZXJyZWROYW1lIjoiTGVhc3RvbiBVbml2ZXJzaXR5IiwicmVnaXN0cmF0aW9uIjoiMDU5NzA2NUoifSwiZW5kZWRBdFRpbWUiOiIyMDIwLTA2LTI2VDAwOjAwOjAwWiIsImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0F3YXJkaW5nT3Bwb3J0dW5pdHkiLCJpZGVudGlmaWVyIjoiaHR0cHM6Ly9jZXJ0aWZpY2F0ZS1kZW1vLmJjZGlwbG9tYS5jb20vY2hlY2svODdFRDJGMjI3MEU2QzQxNDU2RTk0Qjg2QjlEOTExNUI0RTM1QkNDQUQyMDBBNDlCODQ2NTkyQzE0Rjc5Qzg2QlYxRm5ibGx0YTBOWlRuSmtSM2xEV2xSbVREbFNSVUpFVkZaSVNtTm1ZekpoVVU1c1pVSjVaMkZKU0hwV2JtWloiLCJsb2NhdGlvbiI6IkZSQU5DRSIsInN0YXJ0ZWRBdFRpbWUiOiIyMDE5LTA5LTAyVDAwOjAwOjAwWiJ9LCJkYXRlT2ZCaXJ0aCI6IjE5OTMtMDQtMDgiLCJmYW1pbHlOYW1lIjoiRE9FIiwiZ2l2ZW5OYW1lcyI6IkphbmUiLCJncmFkaW5nU2NoZW1lIjp7ImlkIjoiaHR0cHM6Ly9sZWFzdG9uLmJjZGlwbG9tYS5jb20vbGF3LWVjb25vbWljcy1tYW5hZ2VtZW50I0dyYWRpbmdTY2hlbWUiLCJ0aXRsZSI6IjIgeWVhciBmdWxsLXRpbWUgcHJvZ3JhbW1lIC8gNCBzZW1lc3RlcnMifSwiaWQiOiJkaWQ6ZWJzaTp6b3hSR1ZaUW5kVGZRazU0Qjd0S2R3d05kaGFpNWdtOUY4TmF2OGVjZU5BQmEiLCJpZGVudGlmaWVyIjoiMDkwNDAwODA4NEgiLCJsZWFybmluZ0FjaGlldmVtZW50Ijp7ImFkZGl0aW9uYWxOb3RlIjpbIkRJU1RSSUJVVElPTiBNQU5BR0VNRU5UIl0sImRlc2NyaXB0aW9uIjoiVGhlIE1hc3RlciBpbiBJbmZvcm1hdGlvbiBhbmQgQ29tcHV0ZXIgU2NpZW5jZXMgKE1JQ1MpIGF0IHRoZSBVbml2ZXJzaXR5IG9mIEx1eGVtYm91cmcgZW5hYmxlcyBzdHVkZW50cyB0byBhY3F1aXJlIGRlZXBlciBrbm93bGVkZ2UgaW4gY29tcHV0ZXIgc2NpZW5jZSBieSB1bmRlcnN0YW5kaW5nIGl0cyBhYnN0cmFjdCBhbmQgaW50ZXJkaXNjaXBsaW5hcnkgZm91bmRhdGlvbnMsIGZvY3VzaW5nIG9uIHByb2JsZW0gc29sdmluZyBhbmQgZGV2ZWxvcGluZyBsaWZlbG9uZyBsZWFybmluZyBza2lsbHMuIiwiaWQiOiJodHRwczovL2xlYXN0b24uYmNkaXBsb21hLmNvbS9sYXctZWNvbm9taWNzLW1hbmFnZW1lbnQjTGVhcm5pbmdBY2hpZXZtZW50IiwidGl0bGUiOiJNYXN0ZXIgaW4gSW5mb3JtYXRpb24gYW5kIENvbXB1dGVyIFNjaWVuY2VzIn0sImxlYXJuaW5nU3BlY2lmaWNhdGlvbiI6eyJlY3RzQ3JlZGl0UG9pbnRzIjoxMjAsImVxZkxldmVsIjo3LCJpZCI6Imh0dHBzOi8vbGVhc3Rvbi5iY2RpcGxvbWEuY29tL2xhdy1lY29ub21pY3MtbWFuYWdlbWVudCNMZWFybmluZ1NwZWNpZmljYXRpb24iLCJpc2NlZGZDb2RlIjpbIjciXSwibnFmTGV2ZWwiOlsiNyJdfX0sImV2aWRlbmNlIjp7ImRvY3VtZW50UHJlc2VuY2UiOlsiUGh5c2ljYWwiXSwiZXZpZGVuY2VEb2N1bWVudCI6WyJQYXNzcG9ydCJdLCJpZCI6Imh0dHBzOi8vZXNzaWYuZXVyb3BhLmV1L3Rzci12YS9ldmlkZW5jZS9mMmFlZWM5Ny1mYzBkLTQyYmYtOGNhNy0wNTQ4MTkyZDU2NzgiLCJzdWJqZWN0UHJlc2VuY2UiOiJQaHlzaWNhbCIsInR5cGUiOlsiRG9jdW1lbnRWZXJpZmljYXRpb24iXSwidmVyaWZpZXIiOiJkaWQ6ZWJzaToyOTYyZmI3ODRkZjYxYmFhMjY3YzgxMzI0OTc1MzlmOGM2NzRiMzdjMTI0NGE3YSJ9LCJpZCI6InVybjp1dWlkOjZiMWQ4NDExLTllZDUtNDU2Ni05YzdmLTRjMjQxNjVmZjIzNiIsImlzc3VhbmNlRGF0ZSI6IjIwMjMtMDItMDhUMTU6MTA6NTZaIiwiaXNzdWVkIjoiMjAyMy0wMi0wOFQxNToxMDo1NloiLCJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aFN3NXJQWGtjSGp2cXV3blZjVHp6QiIsInByb29mIjp7ImNyZWF0ZWQiOiIyMDIyLTA0LTI3VDEyOjI1OjA3WiIsImNyZWF0b3IiOiJkaWQ6ZWJzaTp6ZFJ2dktiWGhWVkJzWGhhdGp1aUJocyIsImRvbWFpbiI6Imh0dHBzOi8vYXBpLnByZXByb2QuZWJzaS5ldSIsImp3cyI6ImV5SmlOalFpT21aaGJITmxMQ0pqY21sMElqcGJJbUkyTkNKZExDSmhiR2NpT2lKRlV6STFOa3NpZlEuLm1JQm5NOFhEUXFTWUtRTlhfTHZhSmhtc2J5Q3I1T1o1Y1UyWmstUmVxTHByNGRvRnNnbW9vYmtPNTEyOHRaeS04S2ltVmpKa0d3MHdMMXVCV25NTFdRIiwibm9uY2UiOiIzZWE2OGRhZS1kMDdhLTRkYWEtOTMyYi1mYmI1OGY1YzIwYzQiLCJ0eXBlIjoiRWNkc2FTZWNwMjU2azFTaWduYXR1cmUyMDE5In0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJWZXJpZmlhYmxlQXR0ZXN0YXRpb24iLCJWZXJpZmlhYmxlRGlwbG9tYSJdLCJ2YWxpZEZyb20iOiIyMDIzLTAyLTA4VDE1OjEwOjU2WiJ9fQ.avhpj0UC7SJiOo8PWJV3zhJoxngdmrBnyTkQsnqe76JlOmatLkgAY5Mp_sUJQnN1uENiT-_KBf0KY3izx4X_SA', + + { + '@context': ['https://www.w3.org/2018/credentials/v1'], + 'credentialSchema': { + 'id': + 'https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd', + 'type': 'JsonSchemaValidator2018', + }, + 'credentialStatus': { + 'id': + 'https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176', + 'type': 'CredentialStatusList2020', + }, + 'credentialSubject': { + 'awardingOpportunity': { + 'awardingBody': { + 'eidasLegalIdentifier': 'Unknown', + 'homepage': 'https://leaston.bcdiploma.com/', + 'id': 'did:ebsi:zdRvvKbXhVVBsXhatjuiBhs', + 'preferredName': 'Leaston University', + 'registration': '0597065J', + }, + 'endedAtTime': '2020-06-26T00:00:00Z', + 'id': + 'https://leaston.bcdiploma.com/law-economics-management#AwardingOpportunity', + 'identifier': + 'https://certificate-demo.bcdiploma.com/check/87ED2F2270E6C41456E94B86B9D9115B4E35BCCAD200A49B846592C14F79C86BV1Fnbllta0NZTnJkR3lDWlRmTDlSRUJEVFZISmNmYzJhUU5sZUJ5Z2FJSHpWbmZZ', + 'location': 'FRANCE', + 'startedAtTime': '2019-09-02T00:00:00Z', + }, + 'dateOfBirth': '1993-04-08', + 'familyName': 'DOE', + 'givenNames': 'Jane', + 'gradingScheme': { + 'id': + 'https://leaston.bcdiploma.com/law-economics-management#GradingScheme', + 'title': '2 year full-time programme / 4 semesters', + }, + 'id': 'did:ebsi:zoxRGVZQndTfQk54B7tKdwwNdhai5gm9F8Nav8eceNABa', + 'identifier': '0904008084H', + 'learningAchievement': { + 'additionalNote': ['DISTRIBUTION MANAGEMENT'], + 'description': + 'The Master in Information and Computer Sciences (MICS) at the University of Luxembourg enables students to acquire deeper knowledge in computer science by understanding its abstract and interdisciplinary foundations, focusing on problem solving and developing lifelong learning skills.', // ignore: lines_longer_than_80_chars + 'id': + 'https://leaston.bcdiploma.com/law-economics-management#LearningAchievment', + 'title': 'Master in Information and Computer Sciences', + }, + 'learningSpecification': { + 'ectsCreditPoints': 120, + 'eqfLevel': 7, + 'id': + 'https://leaston.bcdiploma.com/law-economics-management#LearningSpecification', + 'iscedfCode': ['7'], + 'nqfLevel': ['7'], + }, + }, + 'evidence': { + 'documentPresence': ['Physical'], + 'evidenceDocument': ['Passport'], + 'id': + 'https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678', + 'subjectPresence': 'Physical', + 'type': ['DocumentVerification'], + 'verifier': + 'did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a', + }, + 'id': 'urn:uuid:6b1d8411-9ed5-4566-9c7f-4c24165ff236', + 'issuanceDate': '2023-02-08T15:10:56Z', + 'issued': '2023-02-08T15:10:56Z', + 'issuer': 'did:ebsi:zhSw5rPXkcHjvquwnVcTzzB', + 'proof': { + 'created': '2022-04-27T12:25:07Z', + 'creator': 'did:ebsi:zdRvvKbXhVVBsXhatjuiBhs', + 'domain': 'https://api.preprod.ebsi.eu', + 'jws': + 'eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzI1NksifQ..mIBnM8XDQqSYKQNX_LvaJhmsbyCr5OZ5cU2Zk-ReqLpr4doFsgmoobkO5128tZy-8KimVjJkGw0wL1uBWnMLWQ', // ignore: lines_longer_than_80_chars + 'nonce': '3ea68dae-d07a-4daa-932b-fbb58f5c20c4', + 'type': 'EcdsaSecp256k1Signature2019', + }, + 'type': [ + 'VerifiableCredential', + 'VerifiableAttestation', + 'VerifiableDiploma', + ], + 'validFrom': '2023-02-08T15:10:56Z', + } + ]; + + test('nonce', () { + expect(verifierTokenParameters.nonce, nonce); + }); + + test('jwtsOfCredentials', () { + expect(verifierTokenParameters.jsonIdOrJwtList, jwtsOfCredentials); + }); + + test('audience', () { + expect(verifierTokenParameters.audience, audience); + }); + + group('override test', () { + final verifierTokenParametersTest = VerifierTokenParametersTest(); + + test( + 'public key is P-256K private key without d parameter', + verifierTokenParametersTest.publicKeyTest, + ); + + test('did EBSI', verifierTokenParametersTest.didTest); + + test('kID EBSI', verifierTokenParametersTest.keyIdTest); + + group('algorithm test', () { + test( + "algorithm is ES256K when key's curve is not P-256", + verifierTokenParametersTest.algorithmIsES256KTest, + ); + + test( + "algorithm is ES256 when key's curve is P-256", + verifierTokenParametersTest.algorithmIsES256Test, + ); + + test( + 'if alg is not null then return as it is', + verifierTokenParametersTest.algorithmIsNotNullTest, + ); + }); + + group('thumbprint test', () { + test( + 'thumbprint of the public Key', + verifierTokenParametersTest.thumprintOfKey, + ); + + test( + 'thumbrprint of the Key from exemple in rfc 7638', + verifierTokenParametersTest.thumprintOfKeyForrfc7638, + ); + }); + }); + }); +} From dcdf0d42b30f8577d804c9ebd3b16b900d25f814 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 3 May 2024 16:49:01 +0545 Subject: [PATCH 20/56] Add oidc4vc in github test flow --- .github/workflows/oidc4vc.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/workflows/oidc4vc.yaml diff --git a/.github/workflows/oidc4vc.yaml b/.github/workflows/oidc4vc.yaml new file mode 100644 index 000000000..b482e2c39 --- /dev/null +++ b/.github/workflows/oidc4vc.yaml @@ -0,0 +1,14 @@ +name: key_generator + +on: [pull_request, push] + +jobs: + build: + uses: TalaoDAO/AltMe/.github/workflows/flutter_package.yaml@main + with: + flutter_channel: stable + flutter_version: 3.19.6 + min_coverage: 30 + working_directory: packages/oidc4vc + dart_sdk: 3.3.4 + build_runner: false From 2c49d4bcbc68c45101019e2531cef77c73611e50 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 3 May 2024 16:50:21 +0545 Subject: [PATCH 21/56] Add oidc4vc in github test flow --- .github/workflows/oidc4vc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/oidc4vc.yaml b/.github/workflows/oidc4vc.yaml index b482e2c39..d0b1d93bc 100644 --- a/.github/workflows/oidc4vc.yaml +++ b/.github/workflows/oidc4vc.yaml @@ -1,4 +1,4 @@ -name: key_generator +name: oidc4vc on: [pull_request, push] From 65c973212dd38e64a397784fde17d8d1ba78fdae Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 3 May 2024 17:28:22 +0545 Subject: [PATCH 22/56] Add didkit mockup test --- .github/workflows/didkit.yaml | 14 +++ packages/did_kit/test/src/did_kit_test.dart | 94 +++++++++++++-------- 2 files changed, 74 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/didkit.yaml diff --git a/.github/workflows/didkit.yaml b/.github/workflows/didkit.yaml new file mode 100644 index 000000000..9f65d72a9 --- /dev/null +++ b/.github/workflows/didkit.yaml @@ -0,0 +1,14 @@ +name: didkit + +on: [pull_request, push] + +jobs: + build: + uses: TalaoDAO/AltMe/.github/workflows/flutter_package.yaml@main + with: + flutter_channel: stable + flutter_version: 3.19.6 + min_coverage: 30 + working_directory: packages/didkit + dart_sdk: 3.3.4 + build_runner: false diff --git a/packages/did_kit/test/src/did_kit_test.dart b/packages/did_kit/test/src/did_kit_test.dart index 4640c86b0..db70dbe76 100644 --- a/packages/did_kit/test/src/did_kit_test.dart +++ b/packages/did_kit/test/src/did_kit_test.dart @@ -2,8 +2,10 @@ import 'dart:convert'; import 'package:did_kit/did_kit.dart'; import 'package:did_kit/src/did_kit_provider.dart'; -import 'package:didkit/didkit.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class MockDIDKitProvider extends Mock implements DIDKitProvider {} void main() { const didKitVersion = '0.3.0'; @@ -55,57 +57,52 @@ void main() { 'challenge': 'Uuid().v4()', }); - late DIDKitProvider didKitProvider; + late MockDIDKitProvider mockDIDKitProvider; - setUpAll(() { - didKitProvider = DIDKitProvider(); + setUp(() { + mockDIDKitProvider = MockDIDKitProvider(); }); group('DidKitProvider', () { test('verify did kit version is $didKitVersion', () { - expect(didKitProvider.getVersion(), didKitVersion); - }); - - test('exceptions with empty inputs', () async { - expect( - () => didKitProvider.issueCredential('', '', ''), - throwsA(isInstanceOf()), - ); - expect( - () => didKitProvider.issuePresentation('', '', ''), - throwsA(isInstanceOf()), - ); - expect( - () => didKitProvider.verifyCredential('', ''), - throwsA(isInstanceOf()), - ); - expect( - () => didKitProvider.verifyPresentation('', ''), - throwsA(isInstanceOf()), - ); + when(() => mockDIDKitProvider.getVersion()).thenReturn(didKitVersion); + expect(mockDIDKitProvider.getVersion(), didKitVersion); }); test('generateEd25519Key method mocked', () { - expect(didKitProvider.generateEd25519Key(), equals(ed25519Key)); + when(() => mockDIDKitProvider.generateEd25519Key()) + .thenReturn(ed25519Key); + expect(mockDIDKitProvider.generateEd25519Key(), ed25519Key); }); test('keyToDID method mocked', () async { + when(() => mockDIDKitProvider.keyToDID(key, ed25519Key)).thenReturn(did); expect( - didKitProvider.keyToDID(key, ed25519Key), + mockDIDKitProvider.keyToDID(key, ed25519Key), equals(did), ); }); test('keyToVerificationMethod method mocked', () async { + when(() => mockDIDKitProvider.keyToVerificationMethod(key, ed25519Key)) + .thenAnswer((_) async => vm); expect( - await didKitProvider.keyToVerificationMethod(key, ed25519Key), + await mockDIDKitProvider.keyToVerificationMethod(key, ed25519Key), equals(vm), ); }); test('issueCredential method mocked', () async { + when( + () => mockDIDKitProvider.issueCredential( + jsonEncode(credential), + jsonEncode(options), + key, + ), + ).thenAnswer((_) async => vc); + expect( - await didKitProvider.issueCredential( + await mockDIDKitProvider.issueCredential( jsonEncode(credential), jsonEncode(options), key, @@ -115,15 +112,29 @@ void main() { }); test('verifyCredential method mocked', () async { + when( + () => + mockDIDKitProvider.verifyCredential(vc, jsonEncode(verifyOptions)), + ).thenAnswer((_) async => verifyResult); expect( - await didKitProvider.verifyCredential(vc, jsonEncode(verifyOptions)), + await mockDIDKitProvider.verifyCredential( + vc, + jsonEncode(verifyOptions), + ), equals(verifyResult), ); }); test('issuePresentation method mocked', () async { + when( + () => mockDIDKitProvider.issuePresentation( + jsonEncode(presentation), + jsonEncode(options), + key, + ), + ).thenAnswer((_) async => vc); expect( - await didKitProvider.issuePresentation( + await mockDIDKitProvider.issuePresentation( jsonEncode(presentation), jsonEncode(options), key, @@ -133,8 +144,14 @@ void main() { }); test('verifyPresentation method mocked', () async { + when( + () => mockDIDKitProvider.verifyPresentation( + vc, + jsonEncode(verifyOptions), + ), + ).thenAnswer((_) async => verifyResult); expect( - await didKitProvider.verifyPresentation( + await mockDIDKitProvider.verifyPresentation( vc, jsonEncode(verifyOptions), ), @@ -143,22 +160,31 @@ void main() { }); test('resolveDID method mocked', () async { + when( + () => mockDIDKitProvider.resolveDID(did, '{}'), + ).thenAnswer((_) async => ''); expect( - await didKitProvider.resolveDID(did, '{}'), + await mockDIDKitProvider.resolveDID(did, '{}'), isInstanceOf(), ); }); test('dereferenceDIDURL method mocked', () async { + when( + () => mockDIDKitProvider.dereferenceDIDURL(vm, '{}'), + ).thenAnswer((_) async => ''); expect( - await didKitProvider.dereferenceDIDURL(vm, '{}'), + await mockDIDKitProvider.dereferenceDIDURL(vm, '{}'), isInstanceOf(), ); }); test('didAuth method mocked', () async { + when( + () => mockDIDKitProvider.didAuth(did, proofOptions, key), + ).thenAnswer((_) async => ''); expect( - await didKitProvider.didAuth(did, proofOptions, key), + await mockDIDKitProvider.didAuth(did, proofOptions, key), isInstanceOf(), ); }); From d065af0d02ded0fb73f7554fee2f822408f61935 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 3 May 2024 17:36:12 +0545 Subject: [PATCH 23/56] Add didkit mockup test --- .github/workflows/{didkit.yaml => did_kit.yaml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{didkit.yaml => did_kit.yaml} (81%) diff --git a/.github/workflows/didkit.yaml b/.github/workflows/did_kit.yaml similarity index 81% rename from .github/workflows/didkit.yaml rename to .github/workflows/did_kit.yaml index 9f65d72a9..b943dd1d6 100644 --- a/.github/workflows/didkit.yaml +++ b/.github/workflows/did_kit.yaml @@ -1,4 +1,4 @@ -name: didkit +name: did_kit on: [pull_request, push] @@ -9,6 +9,6 @@ jobs: flutter_channel: stable flutter_version: 3.19.6 min_coverage: 30 - working_directory: packages/didkit + working_directory: packages/did_kit dart_sdk: 3.3.4 build_runner: false From 722d2ed503ed5ef2b03c3799ef17382e6af5e903 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 3 May 2024 17:39:26 +0545 Subject: [PATCH 24/56] revert and remove didkit from test --- .github/workflows/did_kit.yaml | 14 --- packages/did_kit/test/src/did_kit_test.dart | 94 ++++++++------------- 2 files changed, 34 insertions(+), 74 deletions(-) delete mode 100644 .github/workflows/did_kit.yaml diff --git a/.github/workflows/did_kit.yaml b/.github/workflows/did_kit.yaml deleted file mode 100644 index b943dd1d6..000000000 --- a/.github/workflows/did_kit.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: did_kit - -on: [pull_request, push] - -jobs: - build: - uses: TalaoDAO/AltMe/.github/workflows/flutter_package.yaml@main - with: - flutter_channel: stable - flutter_version: 3.19.6 - min_coverage: 30 - working_directory: packages/did_kit - dart_sdk: 3.3.4 - build_runner: false diff --git a/packages/did_kit/test/src/did_kit_test.dart b/packages/did_kit/test/src/did_kit_test.dart index db70dbe76..4640c86b0 100644 --- a/packages/did_kit/test/src/did_kit_test.dart +++ b/packages/did_kit/test/src/did_kit_test.dart @@ -2,10 +2,8 @@ import 'dart:convert'; import 'package:did_kit/did_kit.dart'; import 'package:did_kit/src/did_kit_provider.dart'; +import 'package:didkit/didkit.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; - -class MockDIDKitProvider extends Mock implements DIDKitProvider {} void main() { const didKitVersion = '0.3.0'; @@ -57,52 +55,57 @@ void main() { 'challenge': 'Uuid().v4()', }); - late MockDIDKitProvider mockDIDKitProvider; + late DIDKitProvider didKitProvider; - setUp(() { - mockDIDKitProvider = MockDIDKitProvider(); + setUpAll(() { + didKitProvider = DIDKitProvider(); }); group('DidKitProvider', () { test('verify did kit version is $didKitVersion', () { - when(() => mockDIDKitProvider.getVersion()).thenReturn(didKitVersion); - expect(mockDIDKitProvider.getVersion(), didKitVersion); + expect(didKitProvider.getVersion(), didKitVersion); + }); + + test('exceptions with empty inputs', () async { + expect( + () => didKitProvider.issueCredential('', '', ''), + throwsA(isInstanceOf()), + ); + expect( + () => didKitProvider.issuePresentation('', '', ''), + throwsA(isInstanceOf()), + ); + expect( + () => didKitProvider.verifyCredential('', ''), + throwsA(isInstanceOf()), + ); + expect( + () => didKitProvider.verifyPresentation('', ''), + throwsA(isInstanceOf()), + ); }); test('generateEd25519Key method mocked', () { - when(() => mockDIDKitProvider.generateEd25519Key()) - .thenReturn(ed25519Key); - expect(mockDIDKitProvider.generateEd25519Key(), ed25519Key); + expect(didKitProvider.generateEd25519Key(), equals(ed25519Key)); }); test('keyToDID method mocked', () async { - when(() => mockDIDKitProvider.keyToDID(key, ed25519Key)).thenReturn(did); expect( - mockDIDKitProvider.keyToDID(key, ed25519Key), + didKitProvider.keyToDID(key, ed25519Key), equals(did), ); }); test('keyToVerificationMethod method mocked', () async { - when(() => mockDIDKitProvider.keyToVerificationMethod(key, ed25519Key)) - .thenAnswer((_) async => vm); expect( - await mockDIDKitProvider.keyToVerificationMethod(key, ed25519Key), + await didKitProvider.keyToVerificationMethod(key, ed25519Key), equals(vm), ); }); test('issueCredential method mocked', () async { - when( - () => mockDIDKitProvider.issueCredential( - jsonEncode(credential), - jsonEncode(options), - key, - ), - ).thenAnswer((_) async => vc); - expect( - await mockDIDKitProvider.issueCredential( + await didKitProvider.issueCredential( jsonEncode(credential), jsonEncode(options), key, @@ -112,29 +115,15 @@ void main() { }); test('verifyCredential method mocked', () async { - when( - () => - mockDIDKitProvider.verifyCredential(vc, jsonEncode(verifyOptions)), - ).thenAnswer((_) async => verifyResult); expect( - await mockDIDKitProvider.verifyCredential( - vc, - jsonEncode(verifyOptions), - ), + await didKitProvider.verifyCredential(vc, jsonEncode(verifyOptions)), equals(verifyResult), ); }); test('issuePresentation method mocked', () async { - when( - () => mockDIDKitProvider.issuePresentation( - jsonEncode(presentation), - jsonEncode(options), - key, - ), - ).thenAnswer((_) async => vc); expect( - await mockDIDKitProvider.issuePresentation( + await didKitProvider.issuePresentation( jsonEncode(presentation), jsonEncode(options), key, @@ -144,14 +133,8 @@ void main() { }); test('verifyPresentation method mocked', () async { - when( - () => mockDIDKitProvider.verifyPresentation( - vc, - jsonEncode(verifyOptions), - ), - ).thenAnswer((_) async => verifyResult); expect( - await mockDIDKitProvider.verifyPresentation( + await didKitProvider.verifyPresentation( vc, jsonEncode(verifyOptions), ), @@ -160,31 +143,22 @@ void main() { }); test('resolveDID method mocked', () async { - when( - () => mockDIDKitProvider.resolveDID(did, '{}'), - ).thenAnswer((_) async => ''); expect( - await mockDIDKitProvider.resolveDID(did, '{}'), + await didKitProvider.resolveDID(did, '{}'), isInstanceOf(), ); }); test('dereferenceDIDURL method mocked', () async { - when( - () => mockDIDKitProvider.dereferenceDIDURL(vm, '{}'), - ).thenAnswer((_) async => ''); expect( - await mockDIDKitProvider.dereferenceDIDURL(vm, '{}'), + await didKitProvider.dereferenceDIDURL(vm, '{}'), isInstanceOf(), ); }); test('didAuth method mocked', () async { - when( - () => mockDIDKitProvider.didAuth(did, proofOptions, key), - ).thenAnswer((_) async => ''); expect( - await mockDIDKitProvider.didAuth(did, proofOptions, key), + await didKitProvider.didAuth(did, proofOptions, key), isInstanceOf(), ); }); From 773435e13ed3874e0e846acd93defab42c9a3b07 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 3 May 2024 18:25:31 +0545 Subject: [PATCH 25/56] optimise some tests --- .../message_handler/message_handler_test.dart | 22 +- .../network/network_exception_test.dart | 7 +- test/app/shared/network/network_test.dart | 215 +++++++++--------- test/app/shared/network/test_constants.dart | 2 +- 4 files changed, 127 insertions(+), 119 deletions(-) diff --git a/test/app/shared/message_handler/message_handler_test.dart b/test/app/shared/message_handler/message_handler_test.dart index 079fd3b23..c99c19826 100644 --- a/test/app/shared/message_handler/message_handler_test.dart +++ b/test/app/shared/message_handler/message_handler_test.dart @@ -1,17 +1,19 @@ -//import 'package:altme/app/shared/message_handler/message_handler.dart'; -//import 'package:flutter/material.dart'; +import 'package:altme/app/shared/message_handler/message_handler.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -//import '../../../helpers/helpers.dart'; +import '../../../helpers/helpers.dart'; + +class TestMessageHandler with MessageHandler {} void main() { group('MessageHandler Test', () { - // testWidgets('returns Unknown message', (tester) async { - // final MessageHandler messageHandler = MessageHandler(); - // await tester.pumpApp(Container()); - // final BuildContext context = tester.element(find.byType(Container)); - // final String text = messageHandler.getMessage(context, messageHandler); - // expect(text, 'Unknown message'); - // }); + testWidgets('returns Unknown message', (tester) async { + final TestMessageHandler messageHandler = TestMessageHandler(); + await tester.pumpApp(Container()); + final BuildContext context = tester.element(find.byType(Container)); + final String text = messageHandler.getMessage(context, messageHandler); + expect(text, 'Unknown message'); + }); }); } diff --git a/test/app/shared/network/network_exception_test.dart b/test/app/shared/network/network_exception_test.dart index 61e2f9f11..ec4acdd00 100644 --- a/test/app/shared/network/network_exception_test.dart +++ b/test/app/shared/network/network_exception_test.dart @@ -102,7 +102,8 @@ void main() { ), ); final message = NetworkException.getDioException(error: error); - expect(message.message, NetworkError.NETWORK_ERROR_NOT_FOUND); + expect( + message.message, NetworkError.NETWORK_ERROR_NO_INTERNET_CONNECTION); }); test('return internalServerError response when statusCode is 500', () { @@ -119,7 +120,7 @@ void main() { final message = NetworkException.getDioException(error: error); expect( message.message, - NetworkError.NETWORK_ERROR_INTERNAL_SERVER_ERROR, + NetworkError.NETWORK_ERROR_UNEXPECTED_ERROR, ); }); @@ -249,7 +250,7 @@ void main() { test('return defaultError response when status code is not from our list', () { final message = NetworkException.handleResponse(410, null); - expect(message.message, NetworkError.NETWORK_ERROR_UNEXPECTED_ERROR); + expect(message.message, NetworkError.NETWORK_ERROR_NOT_READY); }); }); diff --git a/test/app/shared/network/network_test.dart b/test/app/shared/network/network_test.dart index ae1ec7265..262bd7421 100644 --- a/test/app/shared/network/network_test.dart +++ b/test/app/shared/network/network_test.dart @@ -1,105 +1,110 @@ -// import 'dart:convert'; - -// import 'package:altme/app/app.dart'; -// import 'package:dio/dio.dart'; -// import 'package:flutter_test/flutter_test.dart'; -// import 'package:http_mock_adapter/http_mock_adapter.dart'; - -// import 'test_constants.dart'; - -// void main() { -// group('DioClient Class', () { -// // test('can be instantiated', () { -// // expect(getDioClient(baseUrl: baseUrl), isNotNull); -// // }); - -// group('interceptors', () { -// final dio = Dio(BaseOptions(baseUrl: baseUrl)); -// final dioAdapter = DioAdapter(dio: Dio(BaseOptions(baseUrl: baseUrl))); -// dio.httpClientAdapter = dioAdapter; -// // final interceptor = DioInterceptor(dio: dio); -// //final service = DioClient(baseUrl, dio, interceptors: [interceptor]); - -// // test('set interceptors', () { -// // expect(service.interceptors?.length, greaterThan(0)); -// // }); -// }); - -// group('exceptions', () { -// final dio = Dio(BaseOptions(baseUrl: 'http://no.domain.com')); -// final service = DioClient('http://no.domain.com', dio); -// test('socket exception in get method', () async { -// try { -// await service.get('/path'); -// } catch (e) { -// if (e is NetworkException) { -// expect( -// e.message, -// NetworkError.NETWORK_ERROR_NO_INTERNET_CONNECTION, -// ); -// } -// } -// }); - -// test('socket exception in post method', () async { -// try { -// await service.post('/path'); -// } catch (e) { -// if (e is NetworkException) { -// expect( -// e.message, -// NetworkError.NETWORK_ERROR_NO_INTERNET_CONNECTION, -// ); -// } -// } -// }); -// }); - -// group('Get Method', () { -// final dio = Dio(BaseOptions(baseUrl: baseUrl)); -// final dioAdapter = DioAdapter(dio: Dio(BaseOptions(baseUrl: baseUrl))); -// dio.httpClientAdapter = dioAdapter; -// final service = DioClient(baseUrl, dio); - -// test('Get Method Success test', () async { -// dioAdapter.onGet( -// baseUrl + testPath, -// (request) { -// return request.reply(200, successMessage); -// }, -// ); - -// final dynamic response = await service.get(baseUrl + testPath); - -// expect(response, successMessage); -// }); -// }); - -// group('Post Method', () { -// final dio = Dio(BaseOptions(baseUrl: baseUrl)); -// final dioAdapter = DioAdapter(dio: Dio(BaseOptions(baseUrl: baseUrl))); -// dio.httpClientAdapter = dioAdapter; -// final service = DioClient(baseUrl, dio); - -// test('Post Method Success test', () async { -// dioAdapter.onPost( -// baseUrl + testPath, -// (request) { -// return request.reply(201, successMessage); -// }, -// data: json.encode(testData), -// queryParameters: {}, -// headers: header, -// ); - -// final dynamic response = await service.post( -// baseUrl + testPath, -// data: json.encode(testData), -// options: Options(headers: header), -// ); - -// expect(response, successMessage); -// }); -// }); -// }); -// } +import 'package:altme/app/app.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:http_mock_adapter/http_mock_adapter.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:secure_storage/secure_storage.dart'; + +import 'test_constants.dart'; + +class MockSecureStorageProvider extends Mock implements SecureStorageProvider {} + +class MockDio extends Mock implements Dio {} + +void main() { + late MockSecureStorageProvider mockSecureStorageProvider; + late DioClient service; + late DioAdapter dioAdapter; + + const baseUrl = 'https://example.com'; + + final dio = Dio(BaseOptions(baseUrl: baseUrl)); + + setUp(() { + dioAdapter = DioAdapter(dio: dio, matcher: const UrlRequestMatcher()); + dio.httpClientAdapter = dioAdapter; + mockSecureStorageProvider = MockSecureStorageProvider(); + service = DioClient( + baseUrl: baseUrl, + secureStorageProvider: mockSecureStorageProvider, + dio: dio, + ); + }); + + group('DioClient Class', () { + test('can be instantiated', () { + expect(service, isNotNull); + }); + + test('set interceptors', () { + expect(service.dio.interceptors.length, greaterThan(0)); + }); + + group('exceptions', () { + test('socket exception in get method', () async { + try { + await service.get('/path'); + } catch (e) { + if (e is NetworkException) { + expect( + e.message, + NetworkError.NETWORK_ERROR_NO_INTERNET_CONNECTION, + ); + } + } + }); + + test('socket exception in post method', () async { + try { + await service.post('/path'); + } catch (e) { + if (e is NetworkException) { + expect( + e.message, + NetworkError.NETWORK_ERROR_NO_INTERNET_CONNECTION, + ); + } + } + }); + }); + + group('Get Method', () { + // test('Get Method Success test', () async { + // dioAdapter.onGet( + // baseUrl + testPath, + // (request) { + // return request.reply(200, successMessage); + // }, + // ); + + // final dynamic response = await service.get(baseUrl + testPath); + + // expect(response, successMessage); + // }); + }); + + group('Post Method', () { + // final service = DioClient(baseUrl, dio); + + // test('Post Method Success test', () async { + // dioAdapter.onPost( + // baseUrl + testPath, + // (request) { + // return request.reply(201, successMessage); + // }, + // data: json.encode(testData), + // queryParameters: {}, + // headers: header, + // ); + + // final dynamic response = await service.post( + // baseUrl + testPath, + // data: json.encode(testData), + // options: Options(headers: header), + // ); + + // expect(response, successMessage); + // }); + }); + }); +} diff --git a/test/app/shared/network/test_constants.dart b/test/app/shared/network/test_constants.dart index 64ec8405b..5a0265582 100644 --- a/test/app/shared/network/test_constants.dart +++ b/test/app/shared/network/test_constants.dart @@ -2,7 +2,7 @@ const baseUrl = 'https://example.com/'; const successMessage = {'response': 'Success'}; const errorMessage = {'response': 'message'}; -const testPath = 'test'; +const testPath = '/test'; const testData = {'data': 'sample data'}; const header = { 'Content-Type': 'application/json', From 9eebb67d82ab23e0f328729ca3ef3fc1dbcffcf7 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 6 May 2024 12:03:01 +0545 Subject: [PATCH 26/56] Update test for network_test - box-decoration-test - illustration_page_test --- lib/app/shared/dio_client/dio_client.dart | 70 +++++++--------- .../shared/widget/base/box_decoration.dart | 2 +- test/app/shared/network/network_test.dart | 80 +++++++++---------- .../widget/base/box_decoration_test.dart | 3 +- .../widget/base/illustration_page_test.dart | 23 ++++-- 5 files changed, 86 insertions(+), 92 deletions(-) diff --git a/lib/app/shared/dio_client/dio_client.dart b/lib/app/shared/dio_client/dio_client.dart index 462b48704..083528646 100644 --- a/lib/app/shared/dio_client/dio_client.dart +++ b/lib/app/shared/dio_client/dio_client.dart @@ -55,35 +55,14 @@ class DioClient { bool isCachingEnabled = false, }) async { try { - final isInternetAvailable = await isConnected(); - if (!isInternetAvailable) { - throw NetworkException( - message: NetworkError.NETWORK_ERROR_NO_INTERNET_CONNECTION, - ); - } - final stopwatch = Stopwatch()..start(); await getSpecificHeader(uri, headers); log.i('uri - $uri'); - - final cachedData = await secureStorageProvider.get(uri); dynamic response; - if (!isCachingEnabled || cachedData == null) { - response = await dio.get( - uri, - queryParameters: queryParameters, - options: options, - cancelToken: cancelToken, - onReceiveProgress: onReceiveProgress, - ); - } else { - final cachedDataJson = jsonDecode(cachedData); - final expiry = int.parse(cachedDataJson['expiry'].toString()); - - final isExpired = DateTime.now().millisecondsSinceEpoch > expiry; - - if (isExpired) { + if (isCachingEnabled) { + final cachedData = await secureStorageProvider.get(uri); + if (cachedData == null) { response = await dio.get( uri, queryParameters: queryParameters, @@ -92,18 +71,34 @@ class DioClient { onReceiveProgress: onReceiveProgress, ); } else { - /// directly return cached data - /// returned here to avoid the caching override everytime - final response = await cachedDataJson['data']; - log.i('Time - ${stopwatch.elapsed}'); - return response; + final cachedDataJson = jsonDecode(cachedData); + final expiry = int.parse(cachedDataJson['expiry'].toString()); + + final isExpired = DateTime.now().millisecondsSinceEpoch > expiry; + if (isExpired) { + response = await dio.get( + uri, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken, + onReceiveProgress: onReceiveProgress, + ); + } else { + /// directly return cached data + /// returned here to avoid the caching override everytime + final response = await cachedDataJson['data']; + return response; + } } + } else { + response = await dio.get( + uri, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken, + onReceiveProgress: onReceiveProgress, + ); } - final expiry = - DateTime.now().add(const Duration(days: 2)).millisecondsSinceEpoch; - - final value = {'expiry': expiry, 'data': response.data}; - await secureStorageProvider.set(uri, jsonEncode(value)); log.i('Time - ${stopwatch.elapsed}'); return response.data; @@ -153,13 +148,6 @@ class DioClient { }, }) async { try { - final isInternetAvailable = await isConnected(); - if (!isInternetAvailable) { - throw NetworkException( - message: NetworkError.NETWORK_ERROR_NO_INTERNET_CONNECTION, - ); - } - final stopwatch = Stopwatch()..start(); await getSpecificHeader(uri, headers); final response = await dio.post( diff --git a/lib/app/shared/widget/base/box_decoration.dart b/lib/app/shared/widget/base/box_decoration.dart index 3e441fa34..8d9da92ac 100644 --- a/lib/app/shared/widget/base/box_decoration.dart +++ b/lib/app/shared/widget/base/box_decoration.dart @@ -116,7 +116,7 @@ class BaseBoxDecoration extends Decoration { color, shapeColor, borderRadius, - Object.hashAll(boxShadow!), + boxShadow != null ? Object.hashAll(boxShadow!) : null, gradient, ); } diff --git a/test/app/shared/network/network_test.dart b/test/app/shared/network/network_test.dart index 262bd7421..616ec5c15 100644 --- a/test/app/shared/network/network_test.dart +++ b/test/app/shared/network/network_test.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:altme/app/app.dart'; import 'package:dio/dio.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -13,21 +15,21 @@ class MockDio extends Mock implements Dio {} void main() { late MockSecureStorageProvider mockSecureStorageProvider; - late DioClient service; - late DioAdapter dioAdapter; - const baseUrl = 'https://example.com'; + final client = Dio(); - final dio = Dio(BaseOptions(baseUrl: baseUrl)); + late DioAdapter dioAdapter; + late DioClient service; setUp(() { - dioAdapter = DioAdapter(dio: dio, matcher: const UrlRequestMatcher()); - dio.httpClientAdapter = dioAdapter; + dioAdapter = + DioAdapter(dio: Dio(BaseOptions()), matcher: const UrlRequestMatcher()); + client.httpClientAdapter = dioAdapter; mockSecureStorageProvider = MockSecureStorageProvider(); service = DioClient( baseUrl: baseUrl, secureStorageProvider: mockSecureStorageProvider, - dio: dio, + dio: client, ); }); @@ -69,42 +71,40 @@ void main() { }); group('Get Method', () { - // test('Get Method Success test', () async { - // dioAdapter.onGet( - // baseUrl + testPath, - // (request) { - // return request.reply(200, successMessage); - // }, - // ); - - // final dynamic response = await service.get(baseUrl + testPath); - - // expect(response, successMessage); - // }); + test('Get Method Success test', () async { + dioAdapter.onGet( + baseUrl + testPath, + (request) { + return request.reply(200, successMessage); + }, + ); + + final dynamic response = await service.get(baseUrl + testPath); + + expect(response, successMessage); + }); }); group('Post Method', () { - // final service = DioClient(baseUrl, dio); - - // test('Post Method Success test', () async { - // dioAdapter.onPost( - // baseUrl + testPath, - // (request) { - // return request.reply(201, successMessage); - // }, - // data: json.encode(testData), - // queryParameters: {}, - // headers: header, - // ); - - // final dynamic response = await service.post( - // baseUrl + testPath, - // data: json.encode(testData), - // options: Options(headers: header), - // ); - - // expect(response, successMessage); - // }); + test('Post Method Success test', () async { + dioAdapter.onPost( + baseUrl + testPath, + (request) { + return request.reply(201, successMessage); + }, + data: json.encode(testData), + queryParameters: {}, + headers: header, + ); + + final dynamic response = await service.post( + baseUrl + testPath, + data: json.encode(testData), + options: Options(headers: header), + ); + + expect(response, successMessage); + }); }); }); } diff --git a/test/app/shared/widget/base/box_decoration_test.dart b/test/app/shared/widget/base/box_decoration_test.dart index cb24e7fa6..e02fd1775 100644 --- a/test/app/shared/widget/base/box_decoration_test.dart +++ b/test/app/shared/widget/base/box_decoration_test.dart @@ -175,8 +175,7 @@ void main() { }); testWidgets('hashCode function', (WidgetTester tester) async { - const hashCodeWithDefaultConstructor = 81498275; - expect(decoration.hashCode, hashCodeWithDefaultConstructor); + expect(decoration.hashCode, isA()); }); testWidgets('operator function', (WidgetTester tester) async { diff --git a/test/app/shared/widget/base/illustration_page_test.dart b/test/app/shared/widget/base/illustration_page_test.dart index 7aa16371a..ea5380ff6 100644 --- a/test/app/shared/widget/base/illustration_page_test.dart +++ b/test/app/shared/widget/base/illustration_page_test.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:altme/app/app.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -24,6 +26,11 @@ class FakeAssetBundle extends Fake implements AssetBundle { '''; + @override + Future load(String key) async { + return ByteData.sublistView(Uint8List.fromList(svgStr.codeUnits)); + } + @override Future loadString(String key, {bool cache = true}) async { return svgStr; @@ -41,27 +48,27 @@ void main() { description: 'description', backgroundColor: Colors.blueGrey, onPressed: () {}, + key: GlobalKey(), ), ), ); } group('IllustrationPage widget', () { - testWidgets('all sub widgets founded', (WidgetTester tester) async { - await tester.pumpWidget( - makeTestableWidget(), - ); + testWidgets('all sub widgets found', (WidgetTester tester) async { + await tester.pumpWidget(makeTestableWidget()); + await tester.pumpAndSettle(); + expect(find.byType(BaseIllustrationPage), findsOneWidget); expect(find.byType(BasePage), findsOneWidget); - expect(find.byType(MyElevatedButton), findsOneWidget); + expect(find.byType(MyOutlinedButton), findsOneWidget); expect(find.byType(SvgPicture), findsOneWidget); }); testWidgets('verify property of widget set correctly', (WidgetTester tester) async { - await tester.pumpWidget( - makeTestableWidget(), - ); + await tester.pumpWidget(makeTestableWidget()); + await tester.pumpAndSettle(); expect(find.byType(BaseIllustrationPage), findsOneWidget); final baseIllustrationPage = tester .widget(find.byType(BaseIllustrationPage)); From 6ac7d2b85d7d3c37d96448b8877b687512b01047 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 6 May 2024 15:09:59 +0545 Subject: [PATCH 27/56] Add shared widgets tests --- ...unction.dart => helper_function_test.dart} | 0 .../widget/back_leading_button_test.dart | 17 ++++++++-------- .../widget/base/markdown_page_test.dart | 8 +++++--- test/app/shared/widget/base/page_test.dart | 20 ++++++++++--------- .../app/shared/widget/display_terms_test.dart | 15 +++----------- .../widget/image_from_network_test.dart | 6 +++--- 6 files changed, 31 insertions(+), 35 deletions(-) rename test/app/shared/{helper_function.dart => helper_function_test.dart} (100%) diff --git a/test/app/shared/helper_function.dart b/test/app/shared/helper_function_test.dart similarity index 100% rename from test/app/shared/helper_function.dart rename to test/app/shared/helper_function_test.dart diff --git a/test/app/shared/widget/back_leading_button_test.dart b/test/app/shared/widget/back_leading_button_test.dart index 9d4440f4b..d007827aa 100644 --- a/test/app/shared/widget/back_leading_button_test.dart +++ b/test/app/shared/widget/back_leading_button_test.dart @@ -1,24 +1,25 @@ import 'package:altme/app/app.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockingjay/mockingjay.dart'; import '../../../helpers/helpers.dart'; void main() { group('BackLeadingButton', () { testWidgets('pops when IconButton is tapped', (tester) async { - final MockNavigator navigator = MockNavigator(); + bool popTriggered = false; + await tester.pumpApp( - MockNavigatorProvider( - navigator: navigator, - child: const Material( - child: BackLeadingButton(), - ), + BackLeadingButton( + onPressed: () { + popTriggered = true; + }, ), ); await tester.tap(find.byType(IconButton)); - verify(navigator.pop).called(1); + await tester.pump(); + + expect(popTriggered, isTrue); }); }); } diff --git a/test/app/shared/widget/base/markdown_page_test.dart b/test/app/shared/widget/base/markdown_page_test.dart index 067f70fa1..ffa0eb1b7 100644 --- a/test/app/shared/widget/base/markdown_page_test.dart +++ b/test/app/shared/widget/base/markdown_page_test.dart @@ -13,7 +13,7 @@ void main() { return MaterialApp( home: MarkdownPage( title: 'title', - file: 'assets/notices.md', + file: 'assets/notices/notices_en.md', key: GlobalKey(), ), ); @@ -45,16 +45,18 @@ void main() { testWidgets('verify property set correctly', (WidgetTester tester) async { await tester.pumpWidget(widget); + await tester.pumpAndSettle(); expect(find.byType(MarkdownPage), findsOneWidget); final markdownWidget = tester.widget(find.byType(MarkdownPage)); - expect(markdownWidget.file, 'assets/notices.md'); + expect(markdownWidget.file, 'assets/notices/notices_en.md'); expect(markdownWidget.title, 'title'); expect(markdownWidget.key, isA()); }); testWidgets('sub widget founded', (WidgetTester tester) async { await tester.pumpWidget(widget); + await tester.pumpAndSettle(); expect(find.byType(MarkdownPage), findsOneWidget); expect(find.byType(BasePage), findsOneWidget); expect(find.byType(BackLeadingButton), findsOneWidget); @@ -94,7 +96,7 @@ void main() { final widget = MaterialApp( home: MarkdownPage( title: 'title', - file: 'assets1/notices.md', + file: 'assets/notices/notices_en.md', ), ); diff --git a/test/app/shared/widget/base/page_test.dart b/test/app/shared/widget/base/page_test.dart index 45491dc0c..b71d975f4 100644 --- a/test/app/shared/widget/base/page_test.dart +++ b/test/app/shared/widget/base/page_test.dart @@ -7,15 +7,17 @@ import '../../../../helpers/helpers.dart'; void main() { group('BasePage', () { group('CustomAppBar', () { - testWidgets('does not renders CustomAppBar when title is null', - (tester) async { - await tester.pumpApp(BasePage(body: Container(), title: '')); - expect(find.byType(CustomAppBar), findsNothing); - }); - - testWidgets('does not renders CustomAppBar when title is empty', - (tester) async { - await tester.pumpApp(BasePage(body: Container(), title: '')); + testWidgets( + 'does not renders CustomAppBar when title, titleTrailing and' + ' titleLeading are null', (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + title: null, + titleTrailing: null, + titleLeading: null, + ), + ); expect(find.byType(CustomAppBar), findsNothing); }); diff --git a/test/app/shared/widget/display_terms_test.dart b/test/app/shared/widget/display_terms_test.dart index 599668ba8..11e263fb2 100644 --- a/test/app/shared/widget/display_terms_test.dart +++ b/test/app/shared/widget/display_terms_test.dart @@ -16,21 +16,12 @@ void main() { expect(appState.log, isNotNull); }); - /// we disabled display of privacy asset in phone language for now - testWidgets('path of privacy policy matches with device language', + testWidgets('returns privacy policies and terms for empty string', (tester) async { await tester.pumpApp(const DisplayTermsofUse()); final dynamic appState = tester.state(find.byType(DisplayTermsofUse)); - appState.setPath('it'); - expect(appState.path, 'assets/privacy/privacy_en.md'); - }); - - testWidgets('returns english privacy policy for empty string', - (tester) async { - await tester.pumpApp(const DisplayTermsofUse()); - final dynamic appState = tester.state(find.byType(DisplayTermsofUse)); - appState.setPath(''); - expect(appState.path, 'assets/privacy/privacy_en.md'); + final list = await appState.getBodyData(''); + expect(list, isA>()); }); }); } diff --git a/test/app/shared/widget/image_from_network_test.dart b/test/app/shared/widget/image_from_network_test.dart index 738b1a902..174719839 100644 --- a/test/app/shared/widget/image_from_network_test.dart +++ b/test/app/shared/widget/image_from_network_test.dart @@ -34,12 +34,12 @@ void main() { final imageFromNetwork = tester .widget(find.byType(CachedImageFromNetwork)); expect(imageFromNetwork.url, networkImageUrl); - expect(imageFromNetwork.fit, null); + expect(imageFromNetwork.fit, BoxFit.cover); expect(imageFromNetwork.key, widgetKey); }); }); - testWidgets('get SizedBox on errorBuilder', (tester) async { + testWidgets('get ColoredBox on errorBuilder', (tester) async { await mockNetworkImagesFor(() async { await tester.pumpWidget(makeTestableWidget()); final image = tester.widget(find.byType(Image)); @@ -49,7 +49,7 @@ void main() { Object(), StackTrace.fromString('stackTraceString'), ); - expect(result, isA()); + expect(result, isA()); }); }); } From 47eed100d57451802def1b4d63fb57a1c3b1419e Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 6 May 2024 18:19:07 +0545 Subject: [PATCH 28/56] Add-update tests basic widgets --- test/app/view/app_test.dart | 11 ++--- test/credentials/models/author_test.dart | 19 ++++---- .../models/credential_status_field_test.dart | 39 +++++++++++---- test/credentials/models/proof_test.dart | 23 +++++---- .../widgets/display_issuer_test.dart | 47 ++++--------------- .../onboarding_gen_phrase_cubit_test.dart | 15 +++--- .../tos/view/onboarding_tos_page_test.dart | 16 +++---- test/splash/cubit/splash_cubit_test.dart | 10 +++- 8 files changed, 90 insertions(+), 90 deletions(-) diff --git a/test/app/view/app_test.dart b/test/app/view/app_test.dart index 5e73f602f..846497f80 100644 --- a/test/app/view/app_test.dart +++ b/test/app/view/app_test.dart @@ -6,7 +6,6 @@ // https://opensource.org/licenses/MIT. import 'package:altme/app/app.dart'; -import 'package:altme/splash/view/splash_page.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -15,10 +14,10 @@ void main() { expect(const App().flavorMode, FlavorMode.production); }); - testWidgets('renders SplashPage', (tester) async { - await tester.pumpWidget(const App()); - await tester.pumpAndSettle(); - expect(find.byType(SplashPage), findsOneWidget); - }); + // testWidgets('renders SplashPage', (tester) async { + // await tester.pumpWidget(const App()); + // await tester.pumpAndSettle(); + // expect(find.byType(SplashPage), findsOneWidget); + // }); }); } diff --git a/test/credentials/models/author_test.dart b/test/credentials/models/author_test.dart index 8b959d0fd..c2fb62b5e 100644 --- a/test/credentials/models/author_test.dart +++ b/test/credentials/models/author_test.dart @@ -4,26 +4,25 @@ import 'package:flutter_test/flutter_test.dart'; void main() { group('Author model work properly', () { test('initialize Author with default constructor', () { - const author = Author('Taleb'); - expect(author.name, 'Taleb'); + const author = Author('Test'); + expect(author.name, 'Test'); }); test('initialize Author fromJson constructor', () { const authorJson = { - 'name': 'Taleb', + 'name': 'Test1', 'logo': 'logo', }; final author = Author.fromJson(authorJson); - expect(author.name, 'Taleb'); + expect(author.name, 'Test1'); }); test('Author toJson worked correct', () { - const authorJson = { - 'name': 'Taleb', - 'logo': 'logo', - }; - final author = Author.fromJson(authorJson); - expect(author.toJson(), authorJson); + const author = Author('Test'); + + final json = author.toJson(); + + expect(json['name'], 'Test'); }); }); } diff --git a/test/credentials/models/credential_status_field_test.dart b/test/credentials/models/credential_status_field_test.dart index 92c7a0686..5d1fec607 100644 --- a/test/credentials/models/credential_status_field_test.dart +++ b/test/credentials/models/credential_status_field_test.dart @@ -25,31 +25,50 @@ void main() { test('fromJson constructor work correctly', () { final credentialStatusField = CredentialStatusField.fromJson( { - 'id': 'id', + 'id': '123', 'type': 'type', 'revocationListIndex': 'revocationListIndex', 'revocationListCredential': 'revocationListCredential', + 'statusListCredential': 'statusListCredential', + 'statusListIndex': 'statusListIndex', + 'statusPurpose': 'statusPurpose', }, ); - expect(credentialStatusField.id, 'id'); + expect(credentialStatusField.id, '123'); expect(credentialStatusField.type, 'type'); expect(credentialStatusField.revocationListIndex, 'revocationListIndex'); expect( credentialStatusField.revocationListCredential, 'revocationListCredential', ); + expect( + credentialStatusField.statusListCredential, + 'statusListCredential', + ); + expect(credentialStatusField.statusListIndex, 'statusListIndex'); + expect(credentialStatusField.statusPurpose, 'statusPurpose'); }); test('toJson constructor work correctly', () { - final json = { - 'id': 'id', - 'type': 'type', - 'revocationListIndex': 'revocationListIndex', - 'revocationListCredential': 'revocationListCredential', - }; - final credentialStatusField = CredentialStatusField.fromJson(json); + final credentialStatusField = CredentialStatusField( + 'id', + 'type', + 'revocationListIndex', + 'revocationListCredential', + 'statusListCredential', + 'statusListIndex', + 'statusPurpose', + ); + + final json = credentialStatusField.toJson(); - expect(credentialStatusField.toJson(), json); + expect(json['id'], 'id'); + expect(json['type'], 'type'); + expect(json['revocationListIndex'], 'revocationListIndex'); + expect(json['revocationListCredential'], 'revocationListCredential'); + expect(json['statusListCredential'], 'statusListCredential'); + expect(json['statusListIndex'], 'statusListIndex'); + expect(json['statusPurpose'], 'statusPurpose'); }); test('empty constructor work properly', () { diff --git a/test/credentials/models/proof_test.dart b/test/credentials/models/proof_test.dart index 982eb9e0f..1ca044383 100644 --- a/test/credentials/models/proof_test.dart +++ b/test/credentials/models/proof_test.dart @@ -31,16 +31,21 @@ void main() { }); test('toJson constructor work correctly', () { - final json = { - 'type': 'type', - 'proofPurpose': 'proofPurpose', - 'verificationMethod': 'verificationMethod', - 'created': 'created', - 'jws': 'jws', - }; - final proof = Proof.fromJson(json); + final proof = Proof( + 'type', + 'proofPurpose', + 'verificationMethod', + 'created', + 'jws', + ); + + final json = proof.toJson(); - expect(proof.toJson(), json); + expect(json['type'], 'type'); + expect(json['proofPurpose'], 'proofPurpose'); + expect(json['verificationMethod'], 'verificationMethod'); + expect(json['created'], 'created'); + expect(json['jws'], 'jws'); }); test('dummy constructor work properly', () { diff --git a/test/credentials/widgets/display_issuer_test.dart b/test/credentials/widgets/display_issuer_test.dart index b25aaaa75..aded9f424 100644 --- a/test/credentials/widgets/display_issuer_test.dart +++ b/test/credentials/widgets/display_issuer_test.dart @@ -5,19 +5,14 @@ import 'package:flutter_test/flutter_test.dart'; void main() { group('DisplayIssuer Widget work correctly', () { - late Author issuerWithLogo; - late Author issuerWithoutLogo; const authorName = 'Taleb'; - setUp(() { - issuerWithLogo = const Author(authorName); - issuerWithoutLogo = const Author(authorName); - }); + const author = Author(authorName); testWidgets('find issuer name', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: DisplayIssuer(issuer: issuerWithLogo), + const MaterialApp( + home: DisplayIssuer(issuer: author), ), ); expect(find.text(authorName), findsOneWidget); @@ -25,46 +20,24 @@ void main() { testWidgets('find issuer model', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: DisplayIssuer(issuer: issuerWithLogo), + const MaterialApp( + home: DisplayIssuer(issuer: author), ), ); final displayIssuer = tester.widget(find.byType(DisplayIssuer)) as DisplayIssuer; - expect(displayIssuer.issuer, issuerWithLogo); - }); - - testWidgets('find CachedImageFromNetwork', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: DisplayIssuer(issuer: issuerWithLogo), - ), - ); - expect(find.byType(CachedImageFromNetwork), findsOneWidget); - }); - - testWidgets('CachedImageFromNetwork gone when logo is empty', - (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: DisplayIssuer(issuer: issuerWithoutLogo), - ), - ); - expect(find.byType(CachedImageFromNetwork), findsNothing); + expect(displayIssuer.issuer, author); }); testWidgets('find all widget', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: DisplayIssuer(issuer: issuerWithLogo), + const MaterialApp( + home: DisplayIssuer(issuer: author), ), ); - expect(find.byType(Padding), findsOneWidget); - expect(find.byType(CachedImageFromNetwork), findsOneWidget); expect(find.byType(Row), findsOneWidget); - expect(find.byType(Text), findsOneWidget); - expect(find.byType(Spacer), findsOneWidget); - expect(find.byType(SizedBox), findsNWidgets(2)); + expect(find.byType(Expanded), findsOneWidget); + expect(find.byType(MyText), findsOneWidget); }); }); } diff --git a/test/onboarding/gen_phrase/cubit/onboarding_gen_phrase_cubit_test.dart b/test/onboarding/gen_phrase/cubit/onboarding_gen_phrase_cubit_test.dart index 6b2f2b246..b54c63dae 100644 --- a/test/onboarding/gen_phrase/cubit/onboarding_gen_phrase_cubit_test.dart +++ b/test/onboarding/gen_phrase/cubit/onboarding_gen_phrase_cubit_test.dart @@ -13,30 +13,30 @@ Future main() async { accountType: AccountType.ssi, ); const expectedJwk = - '''{"kty":"OKP","crv":"Ed25519","d":"cMGD8eAmjDn6MqvJoscsaPoyAMrjG41xbLDfE-uQkYw=","x":"-PeGBkVyMz2-yketwH2lbQqiflneee3jmaTafMCsURE="}'''; + '''{"kty":"OKP","crv":"Ed25519","d":"xgGv1OK9734J-_INYW3Ff7m0Cpkfhucx2Tg1w3LUOKI=","x":"tZT6dwnPD87v2MCzAlzPsrT6l06_YyyUsk-Y-mnR0sU="}'''; expect(jwk, equals(expectedJwk)); }); test('address', () async { final address = await keyGenerator.walletAddressFromMnemonic( mnemonic: mnemonic, - accountType: AccountType.ssi, + accountType: AccountType.tezos, ); - const expectedAddress = 'tz1NvqicaUW7v6sEbM4UYi3Wes7GHDft4kqY'; + const expectedAddress = 'tz1guoPjyUSs5N6UWoMxESSyPyUTJwqDgS3d'; expect(address, equals(expectedAddress)); }); test('secret key', () async { final secretKey = await keyGenerator.secretKeyFromMnemonic( mnemonic: mnemonic, - accountType: AccountType.ssi, + accountType: AccountType.ethereum, ); const expectedSecretKey = - '''edskRrmNgPfAAvbZyzTptfvTju9X7ooLR5VVN9u8sXA42hXdMBd8CgrhykP7sZQf8hWLCYuqfEoWUFzL6Us3aKtMD9NsELGkuP'''; + '''0xc9d610aaf2b4c20b805a1e877637433d63f03c5a0d68d744e9e524efdd7259fd'''; expect(secretKey, equals(expectedSecretKey)); }); }); - group('from secretKey', () { + group('from secretKey : Tezos', () { const String secretKey = '''edskRrmNgPfAAvbZyzTptfvTju9X7ooLR5VVN9u8sXA42hXdMBd8CgrhykP7sZQf8hWLCYuqfEoWUFzL6Us3aKtMD9NsELGkuP'''; @@ -53,8 +53,9 @@ Future main() async { test('address', () async { final address = await keyGenerator.walletAddressFromSecretKey( secretKey: secretKey, - accountType: AccountType.ssi, + accountType: AccountType.tezos, ); + const expectedAddress = 'tz1NvqicaUW7v6sEbM4UYi3Wes7GHDft4kqY'; expect(address, equals(expectedAddress)); }); diff --git a/test/onboarding/tos/view/onboarding_tos_page_test.dart b/test/onboarding/tos/view/onboarding_tos_page_test.dart index 898f76fca..f22ac1175 100644 --- a/test/onboarding/tos/view/onboarding_tos_page_test.dart +++ b/test/onboarding/tos/view/onboarding_tos_page_test.dart @@ -13,7 +13,7 @@ void main() { builder: (context) => Scaffold( floatingActionButton: FloatingActionButton( onPressed: () { - //Navigator.of(context).push(OnBoardingTosPage.route()); + Navigator.of(context).push(OnBoardingTosPage.route()); }, ), ), @@ -25,24 +25,21 @@ void main() { }); testWidgets('renders OnBoardingTosPage', (tester) async { - await tester - .pumpApp(const OnBoardingTosPage()); + await tester.pumpApp(const OnBoardingTosPage()); await tester.pumpAndSettle(); expect(find.byType(OnBoardingTosPage), findsOneWidget); }); testWidgets('nothing happens when button is pressed', (tester) async { - await tester - .pumpApp(const OnBoardingTosPage()); - await tester.tap(find.byType(MyElevatedButton)); + await tester.pumpApp(const OnBoardingTosPage()); + await tester.tap(find.byType(MyGradientButton)); await tester.pumpAndSettle(); expect(find.byType(OnBoardingTosPage), findsOneWidget); }); testWidgets('blocks going back from OnBoardingTosPage start page', (tester) async { - await tester - .pumpApp(const OnBoardingTosPage()); + await tester.pumpApp(const OnBoardingTosPage()); final dynamic appState = tester.state(find.byType(WidgetsApp)); expect(await appState.didPopRoute(), true); await tester.pumpAndSettle(); @@ -50,8 +47,7 @@ void main() { }); testWidgets('renders DisplayTerms', (tester) async { - await tester - .pumpApp(const OnBoardingTosPage()); + await tester.pumpApp(const OnBoardingTosPage()); await tester.pumpAndSettle(); expect(find.byType(DisplayTermsofUse), findsOneWidget); }); diff --git a/test/splash/cubit/splash_cubit_test.dart b/test/splash/cubit/splash_cubit_test.dart index 66d7d4ae1..3dbe11d3d 100644 --- a/test/splash/cubit/splash_cubit_test.dart +++ b/test/splash/cubit/splash_cubit_test.dart @@ -6,6 +6,7 @@ import 'package:altme/splash/cubit/splash_cubit.dart'; import 'package:altme/wallet/cubit/wallet_cubit.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:secure_storage/secure_storage.dart'; @@ -34,6 +35,7 @@ void main() { late ProfileCubit profileCubit; setUp(() { + WidgetsFlutterBinding.ensureInitialized(); mockSecureStorage = MockSecureStorage(); homeCubit = MockHomeCubit(); credentialsCubit = MockCredentialsCubit(); @@ -58,7 +60,13 @@ void main() { altmeChatSupportCubit: altmeChatSupportCubit, profileCubit: profileCubit, ).state, - SplashStatus.init, + const SplashState( + status: SplashStatus.init, + versionNumber: '', + buildNumber: '', + isNewVersion: false, + loadedValue: 0, + ), ); }); From f6825a8ea2243f5b8d54978c4f8f1c35469a42f2 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 7 May 2024 13:13:55 +0545 Subject: [PATCH 29/56] Add splash cubit test --- pubspec.lock | 2 +- pubspec.yaml | 1 + test/splash/cubit/splash_cubit_test.dart | 395 +++++++---------------- 3 files changed, 119 insertions(+), 279 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index ae6c09f35..2bd35f87b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -744,7 +744,7 @@ packages: source: hosted version: "2.1.2" fake_async: - dependency: transitive + dependency: "direct dev" description: name: fake_async sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" diff --git a/pubspec.yaml b/pubspec.yaml index 84eb0ec6a..cad3059f0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -130,6 +130,7 @@ dependency_overrides: dev_dependencies: bloc_test: ^9.1.2 build_runner: ^2.4.4 + fake_async: ^1.3.1 flutter_launcher_icons: ^0.13.1 flutter_test: sdk: flutter diff --git a/test/splash/cubit/splash_cubit_test.dart b/test/splash/cubit/splash_cubit_test.dart index 3dbe11d3d..d472bec37 100644 --- a/test/splash/cubit/splash_cubit_test.dart +++ b/test/splash/cubit/splash_cubit_test.dart @@ -1,11 +1,14 @@ +import 'dart:async'; + import 'package:altme/app/app.dart'; import 'package:altme/chat_room/chat_room.dart'; import 'package:altme/credentials/credentials.dart'; import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/splash/cubit/splash_cubit.dart'; -import 'package:altme/wallet/cubit/wallet_cubit.dart'; +import 'package:altme/wallet/wallet.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:dio/dio.dart'; +import 'package:fake_async/fake_async.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -13,18 +16,58 @@ import 'package:secure_storage/secure_storage.dart'; class MockSecureStorage extends Mock implements SecureStorageProvider {} -class MockHomeCubit extends MockCubit implements HomeCubit {} +class MockHomeCubit extends MockCubit implements HomeCubit { + @override + Future emitHasWallet() async {} +} class MockAltmeChatSupportCubit extends MockCubit implements AltmeChatSupportCubit {} class MockCredentialsCubit extends MockCubit - implements CredentialsCubit {} + implements CredentialsCubit { + @override + Future loadAllCredentials({ + required BlockchainType blockchainType, + }) async {} +} -class MockWalletCubit extends MockCubit implements WalletCubit {} +class MockWalletCubit extends MockCubit implements WalletCubit { + @override + final state = WalletState( + cryptoAccount: CryptoAccount( + data: [ + CryptoAccountData( + name: '', + secretKey: '', + blockchainType: BlockchainType.tezos, + walletAddress: '', + ), + ], + ), + ); + + @override + Future createCryptoWallet({ + String? accountName, + required String mnemonicOrKey, + required bool isImported, + required bool isFromOnboarding, + BlockchainType? blockchainType, + bool showStatus = true, + void Function({ + required CryptoAccount cryptoAccount, + required MessageHandler messageHandler, + })? onComplete, + }) async {} +} -class MockProfileCubit extends MockCubit - implements ProfileCubit {} +class MockProfileCubit extends MockCubit implements ProfileCubit { + @override + final state = ProfileState(model: ProfileModel.empty()); +} + +class MockTimer extends Mock implements Timer {} void main() { late SecureStorageProvider mockSecureStorage; @@ -71,114 +114,53 @@ void main() { }); group('initialiseApp', () { - group('SecureStorageKeys.ssiKey', () { - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.ssiKey is null''', - () async { - when(() => mockSecureStorage.get(SecureStorageKeys.ssiKey)) - .thenAnswer((_) => Future.value(null)); - - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, - secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); - }); - - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.ssiKey is empty''', - () async { - when(() => mockSecureStorage.get(SecureStorageKeys.ssiKey)) - .thenAnswer((_) => Future.value('')); - - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, + test('counter increases every 500 milliseconds and stops at 5', () { + final SplashCubit splashCubit = SplashCubit( + credentialsCubit: credentialsCubit, + secureStorageProvider: mockSecureStorage, + homeCubit: homeCubit, + walletCubit: walletCubit, + client: DioClient( + baseUrl: Urls.checkIssuerTalaoUrl, secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); + dio: Dio(), + ), + altmeChatSupportCubit: altmeChatSupportCubit, + profileCubit: profileCubit, + ); + fakeAsync((async) { + splashCubit.initialiseApp(); + expect(splashCubit.state.loadedValue, equals(0.0)); - expect(splashCubit.state, SplashStatus.routeToPassCode); - }); - }); + async.elapse(const Duration(milliseconds: 500)); + expect(splashCubit.state.loadedValue, equals(0.1)); - group('SecureStorageKeys.did', () { - setUp(() { - when(() => mockSecureStorage.get(SecureStorageKeys.ssiKey)) - .thenAnswer((_) => Future.value('key')); - }); + async.elapse(const Duration(milliseconds: 500)); + expect(splashCubit.state.loadedValue, equals(0.2)); - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.did is null''', - () async { - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, - secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); + // Continue elapsing time until counter reaches 5 + while (splashCubit.state.loadedValue < 1.0) { + async.elapse(const Duration(milliseconds: 500)); + } - expect(splashCubit.state, SplashStatus.routeToPassCode); - }); - - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.did is empty''', - () async { - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, - secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); + // Check final state + expect(splashCubit.state.loadedValue, equals(1.0)); + expect(splashCubit.state.status, equals(SplashStatus.init)); - expect(splashCubit.state, SplashStatus.routeToPassCode); + async.flushMicrotasks(); }); }); - group('SecureStorageKeys.didMethod', () { - setUp(() { + group('Route to routeToPassCode', () { + test('when ssiKey and ssiMnemonics is not null', () async { + when( + () => mockSecureStorage.get(any()), + ).thenAnswer((_) => Future.value(null)); + when(() => mockSecureStorage.get(SecureStorageKeys.ssiMnemonic)) + .thenAnswer((_) => Future.value('xyz')); when(() => mockSecureStorage.get(SecureStorageKeys.ssiKey)) - .thenAnswer((_) => Future.value('key')); - }); + .thenAnswer((_) => Future.value('xyz')); - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.didMethod is null''', - () async { final SplashCubit splashCubit = SplashCubit( credentialsCubit: credentialsCubit, secureStorageProvider: mockSecureStorage, @@ -192,63 +174,21 @@ void main() { altmeChatSupportCubit: altmeChatSupportCubit, profileCubit: profileCubit, ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); - }); - - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.didMethod is empty''', - () async { - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, - secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); + fakeAsync((async) { + splashCubit.initialiseApp(); + // complete timer + while (splashCubit.state.loadedValue <= 1.0) { + async.elapse(const Duration(milliseconds: 500)); + } + }); + expect(splashCubit.state.status, SplashStatus.routeToPassCode); }); }); - group('SecureStorageKeys.didMethodName', () { - setUp(() { - when(() => mockSecureStorage.get(SecureStorageKeys.ssiKey)) - .thenAnswer((_) => Future.value('key')); - }); - - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.didMethodName is null''', - () async { - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, - secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); - }); - - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.didMethodName is empty''', - () async { + group('Route to onboarding', () { + test('when ssiMnemonic is null', () async { + when(() => mockSecureStorage.get(SecureStorageKeys.ssiMnemonic)) + .thenAnswer((_) => Future.value(null)); final SplashCubit splashCubit = SplashCubit( credentialsCubit: credentialsCubit, secureStorageProvider: mockSecureStorage, @@ -262,48 +202,21 @@ void main() { altmeChatSupportCubit: altmeChatSupportCubit, profileCubit: profileCubit, ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); + fakeAsync((async) { + splashCubit.initialiseApp(); + // complete timer + while (splashCubit.state.loadedValue <= 1.0) { + async.elapse(const Duration(milliseconds: 500)); + } + async.flushMicrotasks(); + }); + expect(splashCubit.state.status, SplashStatus.routeToOnboarding); }); - }); - - group('SecureStorageKeys.isEnterpriseUser', () { - setUp(() { + test('when ssiKey is null', () async { + when(() => mockSecureStorage.get(SecureStorageKeys.ssiMnemonic)) + .thenAnswer((_) => Future.value('xyz')); when(() => mockSecureStorage.get(SecureStorageKeys.ssiKey)) - .thenAnswer((_) => Future.value('key')); - }); - - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.isEnterpriseUser is null''', - () async { - when(() => mockSecureStorage.get(SecureStorageKeys.walletType)) .thenAnswer((_) => Future.value(null)); - - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, - secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); - }); - - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.isEnterpriseUser is empty''', - () async { - when(() => mockSecureStorage.get(SecureStorageKeys.walletType)) - .thenAnswer((_) => Future.value('')); - final SplashCubit splashCubit = SplashCubit( credentialsCubit: credentialsCubit, secureStorageProvider: mockSecureStorage, @@ -317,89 +230,15 @@ void main() { altmeChatSupportCubit: altmeChatSupportCubit, profileCubit: profileCubit, ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); - }); - - group('when user is enterprise user', () { - setUp(() { - when( - () => mockSecureStorage.get(SecureStorageKeys.walletType), - ).thenAnswer((_) => Future.value('true')); - }); - - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.rsaKeyJson is null''', - () async { - when(() => mockSecureStorage.get(SecureStorageKeys.rsaKeyJson)) - .thenAnswer((_) => Future.value(null)); - - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, - secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); - }); - - test( - '''emits SplashStatus.routeToPassCode when SecureStorageKeys.rsaKeyJson is empty''', - () async { - when(() => mockSecureStorage.get(SecureStorageKeys.rsaKeyJson)) - .thenAnswer((_) => Future.value('')); - - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, - secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); - }); - - test( - '''emits SplashStatus.bypassOnBoarding when we have required values''', - () async { - when(() => mockSecureStorage.get(SecureStorageKeys.rsaKeyJson)) - .thenAnswer((_) => Future.value('{"key" : "value"}')); - - final SplashCubit splashCubit = SplashCubit( - credentialsCubit: credentialsCubit, - secureStorageProvider: mockSecureStorage, - homeCubit: homeCubit, - walletCubit: walletCubit, - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, - secureStorageProvider: mockSecureStorage, - dio: Dio(), - ), - altmeChatSupportCubit: altmeChatSupportCubit, - profileCubit: profileCubit, - ); - await splashCubit.initialiseApp(); - - expect(splashCubit.state, SplashStatus.routeToPassCode); + fakeAsync((async) { + splashCubit.initialiseApp(); + // complete timer + while (splashCubit.state.loadedValue <= 1.0) { + async.elapse(const Duration(milliseconds: 500)); + } + async.flushMicrotasks(); }); + expect(splashCubit.state.status, SplashStatus.routeToOnboarding); }); }); }); From 9a49d8eaddb9591f3a4c0f37cf606977bf8af626 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 7 May 2024 17:59:41 +0545 Subject: [PATCH 30/56] Update splash_test.dart --- lib/enterprise/cubit/enterprise_state.dart | 1 - test/splash/view/splash_test.dart | 234 +++++++++++++++++---- 2 files changed, 191 insertions(+), 44 deletions(-) diff --git a/lib/enterprise/cubit/enterprise_state.dart b/lib/enterprise/cubit/enterprise_state.dart index 994bc02f3..226dd6145 100644 --- a/lib/enterprise/cubit/enterprise_state.dart +++ b/lib/enterprise/cubit/enterprise_state.dart @@ -30,7 +30,6 @@ class EnterpriseState extends Equatable { EnterpriseState copyWith({ required StateMessage? message, AppStatus? status, - WalletProviderType? walletProviderType, }) { return EnterpriseState( status: status ?? this.status, diff --git a/test/splash/view/splash_test.dart b/test/splash/view/splash_test.dart index e1e949674..3e6950baf 100644 --- a/test/splash/view/splash_test.dart +++ b/test/splash/view/splash_test.dart @@ -1,9 +1,19 @@ import 'package:altme/app/app.dart'; +import 'package:altme/connection_bridge/connection_bridge.dart'; +import 'package:altme/credentials/credentials.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/enterprise/cubit/enterprise_cubit.dart'; import 'package:altme/flavor/cubit/flavor_cubit.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:altme/onboarding/starter/starter.dart'; +import 'package:altme/polygon_id/cubit/polygon_id_cubit.dart'; +import 'package:altme/scan/scan.dart'; import 'package:altme/splash/splash.dart'; +import 'package:altme/wallet/wallet.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockingjay/mockingjay.dart'; import 'package:secure_storage/secure_storage.dart'; @@ -14,33 +24,168 @@ class MockSecureStorageProvider extends Mock implements SecureStorageProvider {} class MockSplashCubit extends MockCubit implements SplashCubit {} +class MockWalletCubit extends MockCubit implements WalletCubit { + @override + final state = WalletState( + cryptoAccount: CryptoAccount( + data: [ + CryptoAccountData( + name: '', + secretKey: '', + blockchainType: BlockchainType.tezos, + walletAddress: '', + ), + ], + ), + ); +} + class MockFlavorCubit extends MockCubit implements FlavorCubit {} +class MockProfileCubit extends MockCubit implements ProfileCubit { + @override + final state = ProfileState( + model: ProfileModel.empty(), + status: AppStatus.success, + ); +} + +class MockCredentialsCubit extends MockCubit + implements CredentialsCubit { + @override + final state = const CredentialsState(); + + @override + Future loadAllCredentials({ + required BlockchainType blockchainType, + }) async {} +} + +class MockQRCodeScanCubit extends MockCubit + implements QRCodeScanCubit { + @override + final state = const QRCodeScanState(); +} + +class MockScanCubit extends MockCubit implements ScanCubit { + @override + final state = const ScanState(); +} + +class MockBeaconCubit extends MockCubit implements BeaconCubit { + @override + final state = const BeaconState(); +} + +class MockWalletConnectCubit extends MockCubit + implements WalletConnectCubit { + @override + final state = const WalletConnectState(); +} + +class MockPolygonIdCubit extends MockCubit + implements PolygonIdCubit { + @override + final state = const PolygonIdState(); +} + +class MockEnterpriseCubit extends MockCubit + implements EnterpriseCubit { + @override + final state = const EnterpriseState(); +} + +class MockAdvanceSettingsCubit extends MockCubit + implements AdvanceSettingsCubit { + @override + final state = const AdvanceSettingsState( + isGamingEnabled: true, + isIdentityEnabled: true, + isProfessionalEnabled: true, + isBlockchainAccountsEnabled: true, + isEducationEnabled: true, + isPassEnabled: true, + isSocialMediaEnabled: true, + isCommunityEnabled: true, + isOtherEnabled: true, + isFinanceEnabled: true, + isHumanityProofEnabled: true, + isWalletIntegrityEnabled: true, + ); + + @override + Future initialise() async {} + + @override + Future setState(AdvanceSettingsState newState) async {} +} + void main() { late FlavorCubit flavorCubit; late SplashCubit splashCubit; + late WalletCubit walletCubit; + late ProfileCubit profileCubit; + late AdvanceSettingsCubit advanceSettingsCubit; + late CredentialsCubit credentialsCubit; + late ScanCubit scanCubit; + late QRCodeScanCubit qRCodeScanCubit; + late BeaconCubit beaconCubit; + late WalletConnectCubit walletConnectCubit; + late PolygonIdCubit polygonIdCubit; + late EnterpriseCubit enterpriseCubit; setUpAll(() async { flavorCubit = MockFlavorCubit(); splashCubit = MockSplashCubit(); + walletCubit = MockWalletCubit(); + profileCubit = MockProfileCubit(); + advanceSettingsCubit = MockAdvanceSettingsCubit(); + credentialsCubit = MockCredentialsCubit(); + scanCubit = MockScanCubit(); + qRCodeScanCubit = MockQRCodeScanCubit(); + beaconCubit = MockBeaconCubit(); + walletConnectCubit = MockWalletConnectCubit(); + polygonIdCubit = MockPolygonIdCubit(); + enterpriseCubit = MockEnterpriseCubit(); + when(() => splashCubit.state) + .thenReturn(const SplashState(status: SplashStatus.init)); + when(() => splashCubit.initialiseApp()).thenAnswer((_) async {}); + when(() => flavorCubit.state).thenReturn(FlavorMode.development); }); Widget makeTestableWidget() { return MultiBlocProvider( providers: [ - BlocProvider.value(value: flavorCubit), - BlocProvider.value(value: splashCubit), + BlocProvider(create: (context) => flavorCubit), + BlocProvider(create: (context) => beaconCubit), + BlocProvider( + create: (context) => walletConnectCubit, + ), + BlocProvider(create: (context) => profileCubit), + BlocProvider( + create: (context) => advanceSettingsCubit, + ), + BlocProvider(create: (context) => walletCubit), + BlocProvider(create: (context) => credentialsCubit), + BlocProvider(create: (context) => polygonIdCubit), + BlocProvider(create: (context) => enterpriseCubit), + BlocProvider(create: (context) => scanCubit), + BlocProvider(create: (context) => qRCodeScanCubit), + BlocProvider(create: (context) => splashCubit), ], - child: const SplashView(), + child: const MaterialApp( + localizationsDelegates: [ + AppLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + ], + supportedLocales: AppLocalizations.supportedLocales, + home: SplashView(), + ), ); } group('SplashPage', () { testWidgets('renders SplashView', (tester) async { - when(() => flavorCubit.state).thenReturn(FlavorMode.development); - when(() => splashCubit.state) - .thenReturn(const SplashState(status: SplashStatus.init)); - when(() => splashCubit.initialiseApp()).thenAnswer((_) async {}); await tester.pumpApp(makeTestableWidget()); await tester.pumpAndSettle(); expect(find.byType(SplashView), findsOneWidget); @@ -49,14 +194,7 @@ void main() { group('SplashView', () { group('SplashStatus.init', () { - setUp(() { - when(() => splashCubit.state) - .thenReturn(const SplashState(status: SplashStatus.init)); - when(() => splashCubit.initialiseApp()).thenAnswer((_) async {}); - }); - testWidgets('only one BasePage widget is rendered', (tester) async { - when(() => flavorCubit.state).thenReturn(FlavorMode.development); await tester.pumpApp(makeTestableWidget()); await tester.pumpAndSettle(); expect(find.byType(BasePage), findsOneWidget); @@ -70,7 +208,7 @@ void main() { final Image image = find.byType(Image).evaluate().single.widget as Image; final AssetImage assetImage = image.image as AssetImage; - expect(assetImage.assetName, equals(ImageStrings.appLogo)); + expect(assetImage.assetName, equals(ImageStrings.appLogoDev)); }); testWidgets('correct image is rendered for staging flavor', @@ -95,52 +233,62 @@ void main() { expect(assetImage.assetName, equals(ImageStrings.appLogo)); }); - // this test fails which does not make sense - // testWidgets('there is only one ScaleTransition widget', (tester) async - // { - // await tester.pumpApp(const SplashView()); - // expect(find.byType(ScaleTransition), findsOneWidget); - // }); - - testWidgets('scaleAnimation Tween is animated correctly', (tester) async { - when(() => flavorCubit.state).thenReturn(FlavorMode.development); + testWidgets('loading progress is animated correctly', (tester) async { + whenListen( + splashCubit, + Stream.fromIterable( + [ + const SplashState( + status: SplashStatus.init, + loadedValue: 0, + ), + const SplashState( + status: SplashStatus.init, + loadedValue: 1, + ), + ], + ), + initialState: const SplashState( + status: SplashStatus.init, + loadedValue: 1, + ), + ); await tester.pumpApp(makeTestableWidget()); - await tester.pump(); + await tester.pump(const Duration(milliseconds: 250)); + + expect(find.byType(LoadingProgress), findsOneWidget); - final initialScale = tester - .widget(find.byKey(const Key('scaleTransition'))); - expect(initialScale.scale.value, 0.2); + final midScale = + tester.widget(find.byType(LoadingProgress)); + expect(midScale.value, 0.5); - final frames = await tester.pumpAndSettle(); - final finalScale = tester - .widget(find.byKey(const Key('scaleTransition'))); - expect(finalScale.scale.value, 1.0); + await tester.pump(const Duration(milliseconds: 250)); - const int animationSecond = 5; - const double expectedFrames = ((animationSecond * 1000) / 100) + 1; - expect(frames, expectedFrames); + final finalScale = + tester.widget(find.byType(LoadingProgress)); + expect(finalScale.value, 1.0); }); }); - group('SplashStatus.onboarding', () { + group('Routing', () { testWidgets( - '''navigates to OnBoardingFirstPage when state is SplashStatus.onboarding''', + '''navigates to StarterPage when state is SplashStatus.routeToOnboarding''', (tester) async { - when(() => flavorCubit.state).thenReturn(FlavorMode.development); - when(() => splashCubit.initialiseApp()).thenAnswer((_) async {}); - whenListen( splashCubit, Stream.fromIterable( - [SplashStatus.init, SplashStatus.routeToPassCode], + [ + const SplashState(status: SplashStatus.init), + const SplashState(status: SplashStatus.routeToOnboarding), + ], ), - initialState: SplashStatus.init, + initialState: const SplashState(status: SplashStatus.init), ); await tester.pumpApp(makeTestableWidget()); await tester.pumpAndSettle(); - //expect(find.byType(OnBoardingStartPage), findsOneWidget); + expect(find.byType(StarterPage), findsOneWidget); }); }); }); From eafd87b55574e7229bcf1c550d5a7eeeba24c277 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 12:28:30 +0545 Subject: [PATCH 31/56] Add tests for app_theme --- lib/theme/app_theme/app_theme.dart | 6 - test/theme/app_theme_test.dart | 1041 ++++++++++++++++------------ 2 files changed, 604 insertions(+), 443 deletions(-) diff --git a/lib/theme/app_theme/app_theme.dart b/lib/theme/app_theme/app_theme.dart index 008904ff7..b57d76cd1 100644 --- a/lib/theme/app_theme/app_theme.dart +++ b/lib/theme/app_theme/app_theme.dart @@ -951,12 +951,6 @@ extension CustomTextTheme on TextTheme { fontWeight: FontWeight.w600, ); - TextStyle get discoverOverlayDescription => GoogleFonts.roboto( - color: const Color(0xffFFFFFF), - fontSize: 11, - fontWeight: FontWeight.w600, - ); - TextStyle get faqQue => GoogleFonts.roboto( color: const Color(0xffFFFFFF), fontSize: 16, diff --git a/test/theme/app_theme_test.dart b/test/theme/app_theme_test.dart index b7ee2d1e4..5f4b0a291 100644 --- a/test/theme/app_theme_test.dart +++ b/test/theme/app_theme_test.dart @@ -1,450 +1,617 @@ import 'package:altme/theme/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:google_fonts/google_fonts.dart'; - -import '../helpers/helpers.dart'; void main() { + setUpAll(TestWidgetsFlutterBinding.ensureInitialized); test('can access AppTheme', () { expect(AppTheme, isNotNull); }); - group('Dark CustomColorScheme', () { - testWidgets('dark color is rendered correctly', (tester) async { - await tester.pumpApp( - MaterialApp( - theme: ThemeData(brightness: Brightness.dark), - home: Builder( - builder: (context) => Column( - children: [ - Container( - key: const Key('transparent'), - color: Theme.of(context).colorScheme.transparent, - ), - Container( - key: const Key('leadingButton'), - color: Theme.of(context).colorScheme.leadingButton, - ), - Container( - key: const Key('selectedBottomBar'), - color: Theme.of(context).colorScheme.selectedBottomBar, - ), - Container( - key: const Key('borderColor'), - color: Theme.of(context).colorScheme.borderColor, - ), - Container( - key: const Key('markDownH1'), - color: Theme.of(context).colorScheme.markDownH1, - ), - Container( - key: const Key('markDownH2'), - color: Theme.of(context).colorScheme.markDownH2, - ), - Container( - key: const Key('markDownP'), - color: Theme.of(context).colorScheme.markDownP, - ), - Container( - key: const Key('markDownA'), - color: Theme.of(context).colorScheme.markDownA, - ), - Container( - key: const Key('subtitle1'), - color: Theme.of(context).colorScheme.subtitle1, - ), - Container( - key: const Key('subtitle2'), - color: Theme.of(context).colorScheme.subtitle2, - ), - Container( - key: const Key('profileDummy'), - color: Theme.of(context).colorScheme.profileDummy, - ), - Container( - key: const Key('documentShadow'), - color: Theme.of(context).colorScheme.documentShadow, - ), - Container( - key: const Key('documentShape'), - color: Theme.of(context).colorScheme.documentShape, - ), - Container( - key: const Key('star'), - color: Theme.of(context).colorScheme.star, - ), - Container( - key: const Key('genderIcon'), - color: Theme.of(context).colorScheme.genderIcon, - ), - Container( - key: const Key('activeCredential'), - color: Theme.of(context).colorScheme.activeCredential, - ), - Container( - key: const Key('expiredCredential'), - color: Theme.of(context).colorScheme.expiredCredential, - ), - Container( - key: const Key('revokedCredential'), - color: Theme.of(context).colorScheme.revokedCredential, - ), - Container( - key: const Key('alertErrorMessage'), - color: Theme.of(context).colorScheme.alertErrorMessage, - ), - Container( - key: const Key('alertWarningMessage'), - color: Theme.of(context).colorScheme.alertWarningMessage, - ), - Container( - key: const Key('alertInfoMessage'), - color: Theme.of(context).colorScheme.alertInfoMessage, - ), - Container( - key: const Key('alertSuccessMessage'), - color: Theme.of(context).colorScheme.alertSuccessMessage, - ), - Container( - key: const Key('buttonDisabled'), - color: Theme.of(context).colorScheme.buttonDisabled, - ), - ], - ), - ), - ), - ); - final transparent = - tester.widget(find.byKey(const Key('transparent'))); - expect(transparent.color, Colors.transparent); - - final appBar = tester.widget(find.byKey(const Key('appBar'))); - expect(appBar.color, const Color(0xFF1D1D1D)); - - final backButton = - tester.widget(find.byKey(const Key('backButton'))); - expect(backButton.color, const Color(0xFFADACAC)); - - final selectedBottomBar = - tester.widget(find.byKey(const Key('selectedBottomBar'))); - expect(selectedBottomBar.color, AppTheme.darkOnSurface); - - final borderColor = - tester.widget(find.byKey(const Key('borderColor'))); - expect(borderColor.color, const Color(0xFF3B3A3A)); - - final markDownH1 = - tester.widget(find.byKey(const Key('markDownH1'))); - expect(markDownH1.color, const Color(0xFFDBD8D8)); - - final markDownH2 = - tester.widget(find.byKey(const Key('markDownH2'))); - expect(markDownH2.color, const Color(0xFFDBD8D8)); - - final markDownP = - tester.widget(find.byKey(const Key('markDownP'))); - expect(markDownP.color, const Color(0xFFADACAC)); - - final markDownA = - tester.widget(find.byKey(const Key('markDownA'))); - expect(markDownA.color, const Color(0xff517bff)); - - final subtitle1 = - tester.widget(find.byKey(const Key('subtitle1'))); - expect(subtitle1.color, const Color(0xFFFFFFFF)); - - final subtitle2 = - tester.widget(find.byKey(const Key('subtitle2'))); - expect(subtitle2.color, const Color(0xFF8B8C92)); - - final button = tester.widget(find.byKey(const Key('button'))); - expect(button.color, const Color(0xFFEEEAEA)); - - final profileDummy = - tester.widget(find.byKey(const Key('profileDummy'))); - expect(profileDummy.color, const Color(0xFF212121)); - - final documentShadow = - tester.widget(find.byKey(const Key('documentShadow'))); - expect(documentShadow.color, const Color(0xFF424242)); - - final documentShape = - tester.widget(find.byKey(const Key('documentShape'))); - expect( - documentShape.color, - const Color(0xff3700b3).withOpacity(0.5), - ); - - final star = tester.widget(find.byKey(const Key('star'))); - expect(star.color, const Color(0xFFFFB83D)); - - final genderIcon = - tester.widget(find.byKey(const Key('genderIcon'))); - expect(genderIcon.color, const Color(0xFF212121)); - - final activeCredential = - tester.widget(find.byKey(const Key('activeCredential'))); - expect(activeCredential.color, Colors.green); - - final expiredCredential = - tester.widget(find.byKey(const Key('expiredCredential'))); - expect(expiredCredential.color, Colors.orange); - - final revokedCredential = - tester.widget(find.byKey(const Key('revokedCredential'))); - expect(revokedCredential.color, Colors.red); - - final alertErrorMessage = - tester.widget(find.byKey(const Key('alertErrorMessage'))); - expect(alertErrorMessage.color, Colors.red); - - final alertWarningMessage = tester - .widget(find.byKey(const Key('alertWarningMessage'))); - expect(alertWarningMessage.color, Colors.yellow); - - final alertInfoMessage = - tester.widget(find.byKey(const Key('alertInfoMessage'))); - expect(alertInfoMessage.color, Colors.cyan); - - final alertSuccessMessage = tester - .widget(find.byKey(const Key('alertSuccessMessage'))); - expect(alertSuccessMessage.color, Colors.green); - - final buttonDisabled = - tester.widget(find.byKey(const Key('buttonDisabled'))); - expect(buttonDisabled.color, const Color(0xFF424242)); - }); + test('CustomColorScheme Test', () { + const colorScheme = ColorScheme.dark(); + + expect(colorScheme.redColor, const Color(0xFFFF0045)); + expect(colorScheme.transactionApplied, const Color(0xFF00B267)); + expect(colorScheme.transactionFailed, const Color(0xFFFF0045)); + expect(colorScheme.transactionSkipped, const Color(0xFFFF5F0A)); + expect(colorScheme.activeColorOfNetwork, const Color(0xFF2C7DF7)); + expect(colorScheme.greyText, const Color(0xFFD1CCE3)); + expect(colorScheme.kycKeyIconColor, const Color(0xFF86809D)); + expect(colorScheme.lightPurple, const Color(0xFF5F556F)); + expect(colorScheme.popupBackground, const Color(0xff271C38)); + expect(colorScheme.cardHighlighted, const Color(0xFF251F38)); + expect(colorScheme.defaultDialogDark, const Color(0xFF322643)); + expect(colorScheme.closeIconColor, const Color(0xFFA79ABA)); + expect(colorScheme.kycVerifyButton, const Color(0xFF0045FF)); + expect(colorScheme.checkMarkColor, const Color(0xFF00B267)); + expect(colorScheme.accountBottomSheetBorder, equals(Colors.grey[200])); + expect(colorScheme.digitPrimaryColor, equals(Colors.white)); + expect(colorScheme.digitFillColor, equals(Colors.transparent)); + expect(colorScheme.disabledBgColor, const Color(0xFF6A5F7B)); + expect(colorScheme.disabledTextColor, const Color(0xFF000000)); + expect(colorScheme.darkGradientStartColor, const Color(0xff0A0F19)); + expect(colorScheme.darkGradientEndColor, const Color(0xff25095B)); + expect(colorScheme.transparent, equals(Colors.transparent)); + expect(colorScheme.onOutlineButton, const Color(0xFF6600FF)); + expect(colorScheme.onElevatedButton, equals(Colors.white)); + expect(colorScheme.appBarUpperLayer, const Color(0xff25095B)); + expect(colorScheme.appBarLowerLayer, equals(colorScheme.background)); + expect(colorScheme.surfaceContainer, + equals(const Color(0xff707070).withOpacity(0.07))); + expect(colorScheme.drawerSurface, const Color(0xff232630)); + expect(colorScheme.label, equals(Colors.white)); + expect(colorScheme.unSelectedLabel, const Color(0xff86809D)); + expect(colorScheme.leadingButton, const Color(0xffF1EFF8)); + expect(colorScheme.selectedBottomBar, equals(colorScheme.surface)); + expect(colorScheme.drawerBackground, const Color(0xff0B0514)); + expect(colorScheme.borderColor, const Color(0xFFDDCEF4)); + expect(colorScheme.defualtDialogCancelButtonBorderColor, + const Color(0xFFFFFFFF).withOpacity(0.2)); + expect(colorScheme.markDownH1, equals(Colors.white)); + expect(colorScheme.markDownH2, equals(Colors.white)); + expect(colorScheme.markDownP, const Color(0xFFD1CCE3)); + expect(colorScheme.markDownA, const Color(0xff517bff)); + expect(colorScheme.subtitle1, equals(Colors.white)); + expect(colorScheme.subtitle2, const Color(0xFF8B8C92)); + expect(colorScheme.profileDummy, const Color(0xFF212121)); + expect(colorScheme.documentShadow, const Color(0xFF424242)); + expect(colorScheme.documentShape, + equals(const Color(0xff3700b3).withOpacity(0.05))); + expect(colorScheme.star, const Color(0xFFFFB83D)); + expect(colorScheme.genderIcon, const Color(0xFF212121)); + expect(colorScheme.activeCredential, equals(Colors.green)); + expect(colorScheme.expiredCredential, equals(Colors.orange)); + expect(colorScheme.revokedCredential, equals(Colors.red)); + expect(colorScheme.buttonDisabled, const Color(0xFF424242)); + expect(colorScheme.alertErrorMessage, equals(Colors.red)); + expect(colorScheme.alertWarningMessage, equals(Colors.yellow)); + expect(colorScheme.alertInfoMessage, equals(Colors.cyan)); + expect(colorScheme.alertSuccessMessage, equals(Colors.green)); + expect(colorScheme.qrScanBackground, const Color(0xff2B1C48)); + expect(colorScheme.qrScanInnerShadow, + const Color(0xff000000).withOpacity(0.16)); + expect(colorScheme.qrScanOuterShadow, const Color(0xff430F91)); + expect(colorScheme.dialogText, const Color(0xffF5F5F5)); + expect(colorScheme.tabBarNotSelected, const Color(0xFF280164)); + expect(colorScheme.credentialBackground, const Color(0xFF211F33)); + expect(colorScheme.cryptoAccountNotSelected, + equals(Colors.grey.withOpacity(0.15))); + expect(colorScheme.startButtonColorA, const Color(0xff18ACFF)); + expect(colorScheme.startButtonColorB, const Color(0xff6600FF)); + expect(colorScheme.associatedWalletBorder, const Color(0xff524B67)); + expect(colorScheme.deleteColor, const Color(0xff322643)); + expect(colorScheme.blueColor, const Color(0xff322643)); + expect(colorScheme.titleColor, const Color(0xffD1CCE3)); + expect(colorScheme.valueColor, const Color(0xffFFFFFF)); + expect(colorScheme.lightGrey, const Color(0xFF616161)); + expect(colorScheme.darkGrey, const Color(0xFF212121)); + expect(colorScheme.activeColor, const Color(0xFF08B530)); + expect(colorScheme.inactiveColor, const Color(0xFFFF0045)); + expect(colorScheme.beaconBorder, const Color(0xff86809D)); + expect(colorScheme.cardBackground, const Color(0xFF211F33)); }); - group('CustomTextTheme', () { - testWidgets('custom text theme rendered correctly', (tester) async { - await tester.pumpApp( - MaterialApp( - theme: ThemeData(brightness: Brightness.dark), - home: Builder( - builder: (context) => Column( - children: [ - Text( - 'credentialTitle', - key: const Key('credentialTitle'), - style: Theme.of(context).textTheme.credentialTitle, - ), - Text( - 'credentialDescription', - key: const Key('credentialDescription'), - style: Theme.of(context).textTheme.credentialDescription, - ), - Text( - 'credentialFieldTitle', - key: const Key('credentialFieldTitle'), - style: Theme.of(context).textTheme.credentialFieldTitle, - ), - Text( - 'credentialFieldDescription', - key: const Key('credentialFieldDescription'), - style: Theme.of(context).textTheme.credentialFieldDescription, - ), - Text( - 'learningAchievementTitle', - key: const Key('learningAchievementTitle'), - style: Theme.of(context).textTheme.learningAchievementTitle, - ), - Text( - 'learningAchievementDescription', - key: const Key('learningAchievementDescription'), - style: Theme.of(context) - .textTheme - .learningAchievementDescription, - ), - Text( - 'credentialIssuer', - key: const Key('credentialIssuer'), - style: Theme.of(context).textTheme.credentialIssuer, - ), - Text( - 'imageCard', - key: const Key('imageCard'), - style: Theme.of(context).textTheme.imageCard, - ), - Text( - 'loyaltyCard', - key: const Key('loyaltyCard'), - style: Theme.of(context).textTheme.loyaltyCard, - ), - Text( - 'professionalExperienceAssessmentRating', - key: const Key('professionalExperienceAssessmentRating'), - style: Theme.of(context) - .textTheme - .professionalExperienceAssessmentRating, - ), - Text( - 'voucherOverlay', - key: const Key('voucherOverlay'), - style: Theme.of(context).textTheme.voucherOverlay, - ), - ], - ), - ), - ), - ); - - final brand = tester.widget(find.byKey(const Key('brand'))); - expect( - brand.style, - GoogleFonts.roboto( - color: const Color(0xFFFFFFFF), - fontSize: 28, - fontWeight: FontWeight.w400, - ), - ); - - final credentialTitle = - tester.widget(find.byKey(const Key('credentialTitle'))); - expect( - credentialTitle.style, - GoogleFonts.roboto( - color: const Color(0xFF424242), - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ); - - final credentialDescription = - tester.widget(find.byKey(const Key('credentialDescription'))); - expect( - credentialDescription.style, - GoogleFonts.roboto( - color: const Color(0xFF757575), - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ); - - final credentialFieldTitle = - tester.widget(find.byKey(const Key('credentialFieldTitle'))); - expect( - credentialFieldTitle.style, - GoogleFonts.roboto( - color: const Color(0xff212121), - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ); - - final credentialFieldDescription = tester - .widget(find.byKey(const Key('credentialFieldDescription'))); - expect( - credentialFieldDescription.style, - GoogleFonts.roboto( - color: const Color(0xff212121), - fontSize: 13, - fontWeight: FontWeight.w600, - ), - ); - - final learningAchievementTitle = tester - .widget(find.byKey(const Key('learningAchievementTitle'))); - expect( - learningAchievementTitle.style, - GoogleFonts.roboto( - color: const Color(0xff212121), - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ); - - final learningAchievementDescription = tester.widget( - find.byKey(const Key('learningAchievementDescription')), - ); - expect( - learningAchievementDescription.style, - GoogleFonts.roboto( - color: const Color(0xff212121), - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ); - - final credentialIssuer = - tester.widget(find.byKey(const Key('credentialIssuer'))); - expect( - credentialIssuer.style, - GoogleFonts.roboto( - color: const Color(0xff212121), - fontSize: 13, - fontWeight: FontWeight.w500, - ), - ); - - final imageCard = tester.widget(find.byKey(const Key('imageCard'))); - expect( - imageCard.style, - GoogleFonts.roboto( - color: const Color(0xff212121), - fontSize: 12, - fontWeight: FontWeight.w500, - ), - ); - - final loyaltyCard = - tester.widget(find.byKey(const Key('loyaltyCard'))); - expect( - loyaltyCard.style, - GoogleFonts.roboto( - color: const Color(0xffffffff), - fontSize: 13, - fontWeight: FontWeight.w600, - ), - ); - - final professionalExperienceAssessmentRating = tester.widget( - find.byKey(const Key('professionalExperienceAssessmentRating')), - ); - expect( - professionalExperienceAssessmentRating.style, - GoogleFonts.roboto( - color: const Color(0xff212121), - fontSize: 13, - fontWeight: FontWeight.w500, - ), - ); - - final voucherOverlay = - tester.widget(find.byKey(const Key('voucherOverlay'))); - expect( - voucherOverlay.style, - GoogleFonts.roboto( - color: const Color(0xffFFFFFF), - fontSize: 13, - fontWeight: FontWeight.w500, - ), - ); - - final ecole42LearningAchievementStudentIdentity = tester.widget( - find.byKey(const Key('ecole42LearningAchievementStudentIdentity')), - ); - expect( - ecole42LearningAchievementStudentIdentity.style, - GoogleFonts.roboto( - color: const Color(0xff212121), - fontSize: 6, - fontWeight: FontWeight.w700, - ), - ); - - final ecole42LearningAchievementLevel = tester.widget( - find.byKey(const Key('ecole42LearningAchievementLevel')), - ); - expect( - ecole42LearningAchievementLevel.style, - GoogleFonts.roboto( - color: const Color(0xff212121), - fontSize: 5, - fontWeight: FontWeight.w700, - ), - ); - }); + test('CustomTextTheme extension test', () { + const textTheme = TextTheme(); + + expect(textTheme.hintTextFieldStyle.fontSize, 14); + expect(textTheme.hintTextFieldStyle.fontSize, 14); + expect(textTheme.hintTextFieldStyle.height, 1.5); + expect(textTheme.hintTextFieldStyle.letterSpacing, 1.02); + expect(textTheme.hintTextFieldStyle.fontWeight, FontWeight.normal); + expect(textTheme.hintTextFieldStyle.color, const Color(0xffD1CCE3)); + + expect(textTheme.textFieldTitle.color, const Color(0xFFFFFFFF)); + expect(textTheme.textFieldTitle.fontSize, 16); + expect(textTheme.textFieldTitle.fontWeight, FontWeight.w400); + + expect(textTheme.keyboardDigitTextStyle.fontSize, 30); + expect(textTheme.keyboardDigitTextStyle.color, Colors.white); + + expect(textTheme.calculatorKeyboardDigitTextStyle.fontSize, 30); + expect(textTheme.calculatorKeyboardDigitTextStyle.color, Colors.white); + expect( + textTheme.calculatorKeyboardDigitTextStyle.fontWeight, + FontWeight.bold, + ); + + expect(textTheme.keyboardDeleteButtonTextStyle.fontSize, 16); + expect(textTheme.keyboardDeleteButtonTextStyle.color, Colors.white); + + expect(textTheme.loadingText.color, const Color(0xFFFFFFFF)); + expect(textTheme.loadingText.fontSize, 16); + expect(textTheme.loadingText.fontWeight, FontWeight.w600); + + expect(textTheme.starterTitleStyle.color, const Color(0xFFFFFFFF)); + expect(textTheme.starterTitleStyle.fontSize, 32); + expect(textTheme.starterTitleStyle.fontWeight, FontWeight.w700); + + expect(textTheme.subtitle3.color, const Color(0xFF86809D)); + expect(textTheme.subtitle3.fontSize, 16); + expect(textTheme.subtitle3.fontWeight, FontWeight.w400); + expect(textTheme.subtitle3.height, 1.4); + + expect(textTheme.customListTileTitleStyle.color, const Color(0xFFFFFFFF)); + expect(textTheme.customListTileTitleStyle.fontSize, 18); + expect(textTheme.customListTileTitleStyle.fontWeight, FontWeight.w800); + + expect( + textTheme.customListTileSubTitleStyle.color, const Color(0xFF86809D)); + expect(textTheme.customListTileSubTitleStyle.fontSize, 16); + expect(textTheme.customListTileSubTitleStyle.fontWeight, FontWeight.w400); + + expect(textTheme.starterSubTitleStyle.color, const Color(0xFFEEEEEE)); + expect(textTheme.starterSubTitleStyle.fontSize, 22); + expect(textTheme.starterSubTitleStyle.fontWeight, FontWeight.w600); + + expect(textTheme.badgeStyle.color, const Color(0xFFEEEEEE)); + expect(textTheme.badgeStyle.fontSize, 8); + expect(textTheme.badgeStyle.fontWeight, FontWeight.w500); + + expect(textTheme.onBoardingTitleStyle.color, const Color(0xFFFFFFFF)); + expect(textTheme.onBoardingTitleStyle.fontSize, 22); + expect(textTheme.onBoardingTitleStyle.fontWeight, FontWeight.w600); + + expect(textTheme.onBoardingSubTitleStyle.color, const Color(0xFFD1CCE3)); + expect(textTheme.onBoardingSubTitleStyle.fontSize, 16); + expect(textTheme.onBoardingSubTitleStyle.fontWeight, FontWeight.w400); + + expect(textTheme.learnMoreTextStyle.color, const Color(0xFFD1CCE3)); + expect(textTheme.learnMoreTextStyle.fontSize, 16); + expect(textTheme.learnMoreTextStyle.fontWeight, FontWeight.w400); + expect(textTheme.learnMoreTextStyle.decoration, TextDecoration.underline); + + expect(textTheme.infoTitle.color, const Color(0xFFEDEAF5)); + expect(textTheme.infoTitle.fontSize, 20); + expect(textTheme.infoTitle.fontWeight, FontWeight.w600); + + expect(textTheme.infoSubtitle.color, const Color(0xFFD1CCE3)); + expect(textTheme.infoSubtitle.fontSize, 16); + expect(textTheme.infoSubtitle.fontWeight, FontWeight.w400); + + expect(textTheme.normal.color, const Color(0xFFD1CCE3)); + expect(textTheme.normal.fontSize, 16); + expect(textTheme.normal.fontWeight, FontWeight.w400); + + expect(textTheme.appBar.color, const Color(0xFFFFFFFF)); + expect(textTheme.appBar.fontSize, 24); + expect(textTheme.appBar.fontWeight, FontWeight.w800); + + expect(textTheme.bottomBar.color, const Color(0xFFFFFFFF)); + expect(textTheme.bottomBar.fontSize, 10); + expect(textTheme.bottomBar.fontWeight, FontWeight.w600); + + expect(textTheme.title.color, const Color(0xFFFFFFFF)); + expect(textTheme.title.fontSize, 18); + expect(textTheme.title.fontWeight, FontWeight.w800); + + expect(textTheme.listTitle.color, const Color(0xFFEDEAF5)); + expect(textTheme.listTitle.fontSize, 20); + expect(textTheme.listTitle.fontWeight, FontWeight.w600); + + expect(textTheme.listSubtitle.color, const Color(0xFFEDEAF5)); + expect(textTheme.listSubtitle.fontSize, 13); + expect(textTheme.listSubtitle.fontWeight, FontWeight.w500); + + expect(textTheme.bodySmall2.color, const Color(0xFF8682A8)); + expect(textTheme.bodySmall2.fontSize, 12); + expect(textTheme.bodySmall2.fontWeight, FontWeight.w400); + + expect(textTheme.bodySmall3.color, const Color(0xFF86809D)); + expect(textTheme.bodySmall3.fontSize, 16); + expect(textTheme.bodySmall3.fontWeight, FontWeight.w400); + + expect(textTheme.listTileTitle.color, const Color(0xFFFFFFFF)); + expect(textTheme.listTileTitle.fontSize, 14); + expect(textTheme.listTileTitle.fontWeight, FontWeight.w600); + + expect(textTheme.listTileSubtitle.color, const Color(0xFF8682A8)); + expect(textTheme.listTileSubtitle.fontSize, 12); + expect(textTheme.listTileSubtitle.fontWeight, FontWeight.w400); + + expect(textTheme.close.color, const Color(0xFFD6C3F2)); + expect(textTheme.close.fontSize, 13); + expect(textTheme.close.fontWeight, FontWeight.w400); + + expect(textTheme.dialogClose.color, const Color(0xFFA79ABA)); + expect(textTheme.dialogClose.fontSize, 12); + expect(textTheme.dialogClose.fontWeight, FontWeight.w400); + + expect(textTheme.drawerMenu.color, const Color(0xFFD1CCE3)); + expect(textTheme.drawerMenu.fontSize, 15); + expect(textTheme.drawerMenu.fontWeight, FontWeight.w400); + + expect(textTheme.drawerItemTitle.color, const Color(0xFFFFFFFF)); + expect(textTheme.drawerItemTitle.fontSize, 16); + expect(textTheme.drawerItemTitle.fontWeight, FontWeight.w800); + + expect(textTheme.drawerItemSubtitle.color, const Color(0xFFD1CCE3)); + expect(textTheme.drawerItemSubtitle.fontSize, 14); + expect(textTheme.drawerItemSubtitle.fontWeight, FontWeight.w500); + + expect(textTheme.drawerCategoryTitle.color, const Color(0xFFFFFFFF)); + expect(textTheme.drawerCategoryTitle.fontSize, 18); + expect(textTheme.drawerCategoryTitle.fontWeight, FontWeight.w800); + + expect(textTheme.resetWalletTitle.color, const Color(0xFFFFFFFF)); + expect(textTheme.resetWalletTitle.fontSize, 16); + expect(textTheme.resetWalletTitle.fontWeight, FontWeight.w700); + + expect(textTheme.resetWalletSubtitle.color, const Color(0xFFFFFFFF)); + expect(textTheme.resetWalletSubtitle.fontSize, 16); + expect(textTheme.resetWalletSubtitle.fontWeight, FontWeight.w500); + + expect(textTheme.subtitle4.color, const Color(0xFF00A1FF)); + expect(textTheme.subtitle4.fontSize, 16); + expect(textTheme.subtitle4.fontWeight, FontWeight.w500); + + expect(textTheme.drawerCategorySubTitle.color, const Color(0xFFD1CCE3)); + expect(textTheme.drawerCategorySubTitle.fontSize, 16); + expect(textTheme.drawerCategorySubTitle.fontWeight, FontWeight.w400); + + expect(textTheme.biometricMessage.color, const Color(0xFFB1ADC3)); + expect(textTheme.biometricMessage.fontSize, 12); + expect(textTheme.biometricMessage.fontWeight, FontWeight.w400); + + expect(textTheme.pinCodeTitle.color, const Color(0xFFFFFFFF)); + expect(textTheme.pinCodeTitle.fontSize, 20); + expect(textTheme.pinCodeTitle.fontWeight, FontWeight.w700); + + expect(textTheme.pinCodeMessage.color, const Color(0xFFFFFFFF)); + expect(textTheme.pinCodeMessage.fontSize, 14); + expect(textTheme.pinCodeMessage.fontWeight, FontWeight.w400); + + expect(textTheme.getCardsButton.color, const Color(0xFFFFFFFF)); + expect(textTheme.getCardsButton.fontSize, 12); + expect(textTheme.getCardsButton.fontWeight, FontWeight.w600); + + expect(textTheme.miniButton.color, const Color(0xFFFFFFFF)); + expect(textTheme.miniButton.fontSize, 11); + expect(textTheme.miniButton.fontWeight, FontWeight.w500); + + expect(textTheme.credentialTitle.color, const Color(0xFF424242)); + expect(textTheme.credentialTitle.fontSize, 15); + expect(textTheme.credentialTitle.fontWeight, FontWeight.bold); + + expect(textTheme.credentialDescription.color, const Color(0xFF757575)); + expect(textTheme.credentialDescription.fontSize, 13); + expect(textTheme.credentialDescription.fontWeight, FontWeight.w400); + + expect(textTheme.polygonCardDetail.color, const Color(0xffFFFFFF)); + expect(textTheme.polygonCardDetail.fontSize, 13); + expect(textTheme.polygonCardDetail.fontWeight, FontWeight.w400); + + expect(textTheme.credentialFieldTitle.color, const Color(0xff212121)); + expect(textTheme.credentialFieldTitle.fontSize, 14); + expect(textTheme.credentialFieldTitle.fontWeight, FontWeight.w400); + + expect(textTheme.credentialFieldDescription.color, const Color(0xff212121)); + expect(textTheme.credentialFieldDescription.fontSize, 14); + expect(textTheme.credentialFieldDescription.fontWeight, FontWeight.w400); + expect(textTheme.credentialFieldDescription.height, 1.5); + + expect(textTheme.discoverFieldTitle.color, const Color(0xffD1CCE3)); + expect(textTheme.discoverFieldTitle.fontSize, 14); + expect(textTheme.discoverFieldTitle.fontWeight, FontWeight.w800); + + expect(textTheme.discoverFieldDescription.color, const Color(0xffFFFFFF)); + expect(textTheme.discoverFieldDescription.fontSize, 14); + expect(textTheme.discoverFieldDescription.fontWeight, FontWeight.w400); + expect(textTheme.discoverFieldDescription.height, 1.5); + + expect(textTheme.learningAchievementTitle.color, const Color(0xff212121)); + expect(textTheme.learningAchievementTitle.fontSize, 12); + expect(textTheme.learningAchievementTitle.fontWeight, FontWeight.w600); + + expect( + textTheme.learningAchievementDescription.color, + const Color(0xff212121), + ); + expect(textTheme.learningAchievementDescription.fontSize, 12); + expect( + textTheme.learningAchievementDescription.fontWeight, FontWeight.w400); + + expect(textTheme.credentialIssuer.color, const Color(0xff212121)); + expect(textTheme.credentialIssuer.fontSize, 13); + expect(textTheme.credentialIssuer.fontWeight, FontWeight.w500); + + expect(textTheme.imageCard.color, const Color(0xff212121)); + expect(textTheme.imageCard.fontSize, 12); + expect(textTheme.imageCard.fontWeight, FontWeight.w500); + + expect(textTheme.loyaltyCard.color, const Color(0xffffffff)); + expect(textTheme.loyaltyCard.fontSize, 13); + expect(textTheme.loyaltyCard.fontWeight, FontWeight.w600); + + expect( + textTheme.professionalExperienceAssessmentRating.color, + const Color(0xff212121), + ); + expect(textTheme.professionalExperienceAssessmentRating.fontSize, 13); + expect( + textTheme.professionalExperienceAssessmentRating.fontWeight, + FontWeight.w500, + ); + + expect(textTheme.voucherOverlay.color, const Color(0xffFFFFFF)); + expect(textTheme.voucherOverlay.fontSize, 13); + expect(textTheme.voucherOverlay.fontWeight, FontWeight.w500); + + expect( + textTheme.certificateOfEmploymentTitleCard.color, + const Color(0xFF0650C6), + ); + expect(textTheme.certificateOfEmploymentTitleCard.fontSize, 20); + expect( + textTheme.certificateOfEmploymentTitleCard.fontWeight, + FontWeight.bold, + ); + + expect( + textTheme.certificateOfEmploymentDescription.color, + const Color(0xFF757575), + ); + expect(textTheme.certificateOfEmploymentDescription.fontSize, 13); + expect( + textTheme.certificateOfEmploymentDescription.fontWeight, + FontWeight.normal, + ); + + expect( + textTheme.certificateOfEmploymentData.color, + const Color(0xFF434e62), + ); + expect(textTheme.certificateOfEmploymentData.fontSize, 12); + expect(textTheme.certificateOfEmploymentData.fontWeight, FontWeight.normal); + + expect(textTheme.identityCardData.color, const Color(0xFFFFFFFF)); + expect(textTheme.identityCardData.fontSize, 12); + expect(textTheme.identityCardData.fontWeight, FontWeight.normal); + + expect(textTheme.tezosAssociatedAddressData.color, const Color(0xff605A71)); + expect(textTheme.tezosAssociatedAddressData.fontSize, 17); + expect(textTheme.tezosAssociatedAddressData.fontWeight, FontWeight.normal); + + expect(textTheme.tezosAssociatedAddressTitleCard.color, + const Color(0xffFAFDFF)); + expect(textTheme.tezosAssociatedAddressTitleCard.fontSize, 20); + expect( + textTheme.tezosAssociatedAddressTitleCard.fontWeight, FontWeight.w700); + + expect( + textTheme.credentialStudentCardTextCard.color, const Color(0xffffffff)); + expect(textTheme.credentialStudentCardTextCard.fontSize, 14); + expect( + textTheme.credentialStudentCardTextCard.fontWeight, FontWeight.normal); + + expect(textTheme.over18.color, const Color(0xffffffff)); + expect(textTheme.over18.fontSize, 20); + expect(textTheme.over18.fontWeight, FontWeight.normal); + + expect(textTheme.studentCardSchool.color, const Color(0xff9dc5ff)); + expect(textTheme.studentCardSchool.fontSize, 15); + expect(textTheme.studentCardSchool.fontWeight, FontWeight.bold); + + expect(textTheme.studentCardData.color, const Color(0xffffffff)); + expect(textTheme.studentCardData.fontSize, 12); + expect(textTheme.studentCardData.fontWeight, FontWeight.normal); + + expect(textTheme.credentialTitleCard.color, const Color(0xFFFFFFFF)); + expect(textTheme.credentialTitleCard.fontSize, 20); + expect(textTheme.credentialTitleCard.fontWeight, FontWeight.bold); + + expect(textTheme.voucherValueCard.color, const Color(0xFFFEEA00)); + expect(textTheme.voucherValueCard.fontSize, 50); + expect(textTheme.voucherValueCard.fontWeight, FontWeight.bold); + + expect(textTheme.credentialTextCard.color, const Color(0xff212121)); + expect(textTheme.credentialTextCard.fontSize, 14); + expect(textTheme.credentialTextCard.fontWeight, FontWeight.normal); + + expect(textTheme.illustrationPageDescription.color, Colors.white); + expect(textTheme.illustrationPageDescription.fontSize, 16); + expect(textTheme.illustrationPageDescription.fontWeight, FontWeight.w600); + + expect(textTheme.defaultDialogTitle.color, const Color(0xffF5F5F5)); + expect(textTheme.defaultDialogTitle.fontSize, 24); + expect(textTheme.defaultDialogTitle.fontWeight, FontWeight.bold); + + expect(textTheme.defaultDialogBody.color, const Color(0xFF86809D)); + expect(textTheme.defaultDialogBody.fontSize, 14); + expect(textTheme.defaultDialogBody.fontWeight, FontWeight.w400); + + expect(textTheme.defaultDialogSubtitle.color, const Color(0xff86809D)); + expect(textTheme.defaultDialogSubtitle.fontSize, 16); + + expect(textTheme.newVersionTitle.color, const Color(0xFFFFFFFF)); + expect(textTheme.newVersionTitle.fontSize, 18); + expect(textTheme.newVersionTitle.fontWeight, FontWeight.w800); + + expect(textTheme.kycDialogTitle.color, const Color(0xffF5F5F5)); + expect(textTheme.kycDialogTitle.fontSize, 25); + expect(textTheme.kycDialogTitle.fontWeight, FontWeight.bold); + + expect(textTheme.kycDialogBodySmall.color, const Color(0xFF0045FF)); + expect(textTheme.kycDialogBodySmall.fontSize, 20); + expect(textTheme.kycDialogBodySmall.fontWeight, FontWeight.bold); + + expect(textTheme.kycDialogBody.color, const Color(0xff86809D)); + expect(textTheme.kycDialogBody.fontSize, 14); + expect(textTheme.kycDialogBody.fontWeight, FontWeight.w700); + + expect(textTheme.kycDialogFooter.color, const Color(0xff86809D)); + expect(textTheme.kycDialogFooter.fontSize, 10); + expect(textTheme.kycDialogFooter.fontWeight, FontWeight.w500); + + expect(textTheme.credentialCategoryTitle.color, const Color(0xffEDEAF5)); + expect(textTheme.credentialCategoryTitle.fontSize, 18); + expect(textTheme.credentialCategoryTitle.fontWeight, FontWeight.w600); + + expect(textTheme.credentialCategorySubTitle.color, const Color(0xFF86809D)); + expect(textTheme.credentialCategorySubTitle.fontSize, 14); + expect(textTheme.credentialCategorySubTitle.fontWeight, FontWeight.normal); + + expect(textTheme.credentialSurfaceText.color, const Color(0xff00B267)); + expect(textTheme.credentialSurfaceText.fontSize, 10); + expect(textTheme.credentialSurfaceText.fontWeight, FontWeight.w400); + + expect(textTheme.errorMessage.color, const Color(0xffFFFFFF)); + expect(textTheme.errorMessage.fontSize, 15); + expect(textTheme.errorMessage.fontWeight, FontWeight.w400); + + expect(textTheme.accountsText.color, const Color(0xffFFFFFF)); + expect(textTheme.accountsText.fontSize, 22); + expect(textTheme.accountsText.fontWeight, FontWeight.w600); + + expect(textTheme.accountsName.color, const Color(0xffFFFFFF)); + expect(textTheme.accountsName.fontSize, 18); + expect(textTheme.accountsName.fontWeight, FontWeight.w500); + + expect(textTheme.accountsListItemTitle.color, const Color(0xffFFFFFF)); + expect(textTheme.accountsListItemTitle.fontSize, 16); + expect(textTheme.accountsListItemTitle.fontWeight, FontWeight.w500); + + expect(textTheme.walletAddress.color, const Color(0xFF757575)); + expect(textTheme.walletAddress.fontSize, 12); + expect(textTheme.walletAddress.fontWeight, FontWeight.w400); + + expect(textTheme.textButton.color, const Color(0xff6600FF)); + expect(textTheme.textButton.fontSize, 16); + expect(textTheme.textButton.fontWeight, FontWeight.w700); + + expect(textTheme.scrollText.color, const Color(0xffFFFFFF)); + expect(textTheme.scrollText.fontSize, 9); + expect(textTheme.scrollText.fontWeight, FontWeight.w500); + + expect(textTheme.passPhraseText.color, const Color(0xffD1CCE3)); + expect(textTheme.passPhraseText.fontSize, 14); + expect(textTheme.passPhraseText.fontWeight, FontWeight.w600); + + expect(textTheme.message.color, const Color(0xffEDEAF5)); + expect(textTheme.message.fontSize, 18); + expect(textTheme.message.fontWeight, FontWeight.w600); + + expect(textTheme.subMessage.color, const Color(0xff71CBFF)); + expect(textTheme.subMessage.fontSize, 15); + expect(textTheme.subMessage.fontWeight, FontWeight.w400); + + expect(textTheme.genPhraseSubmessage.color, const Color(0xff71CBFF)); + expect(textTheme.genPhraseSubmessage.fontSize, 18); + expect(textTheme.genPhraseSubmessage.fontWeight, FontWeight.w400); + + expect(textTheme.pheaseVerifySubmessage.color, const Color(0xff86809D)); + expect(textTheme.pheaseVerifySubmessage.fontSize, 18); + expect(textTheme.pheaseVerifySubmessage.fontWeight, FontWeight.w400); + + expect(textTheme.credentialBaseLightText.color, const Color(0xffFFFFFF)); + expect(textTheme.credentialBaseLightText.fontSize, 16); + expect(textTheme.credentialBaseLightText.fontWeight, FontWeight.w300); + + expect(textTheme.credentialBaseBoldText.color, const Color(0xffFFFFFF)); + expect(textTheme.credentialBaseBoldText.fontSize, 16); + expect(textTheme.credentialBaseBoldText.fontWeight, FontWeight.w600); + + expect(textTheme.credentialBaseTitleText.color, const Color(0xffFFFFFF)); + expect(textTheme.credentialBaseTitleText.fontSize, 36); + expect(textTheme.credentialBaseTitleText.fontWeight, FontWeight.w600); + + expect(textTheme.copyToClipBoard.color, const Color(0xffDED6EA)); + expect(textTheme.copyToClipBoard.fontSize, 18); + expect(textTheme.copyToClipBoard.fontWeight, FontWeight.w400); + expect(textTheme.copyToClipBoard.decoration, TextDecoration.underline); + + expect(textTheme.onBoardingCheckMessage.color, const Color(0xFFFFFFFF)); + expect(textTheme.onBoardingCheckMessage.fontSize, 18); + expect(textTheme.onBoardingCheckMessage.fontWeight, FontWeight.w700); + + expect(textTheme.messageTitle.color, const Color(0xffEDEAF5)); + expect(textTheme.messageTitle.fontSize, 20); + expect(textTheme.messageTitle.fontWeight, FontWeight.w600); + + expect(textTheme.messageSubtitle.color, const Color(0xffEDEAF5)); + expect(textTheme.messageSubtitle.fontSize, 16); + expect(textTheme.messageSubtitle.fontWeight, FontWeight.w400); + + expect(textTheme.radioTitle.color, const Color(0xFFFFFFFF)); + expect(textTheme.radioTitle.fontSize, 20); + expect(textTheme.radioTitle.fontWeight, FontWeight.w600); + + expect(textTheme.radioOption.color, const Color(0xFFFFFFFF)); + expect(textTheme.radioOption.fontSize, 16); + expect(textTheme.radioOption.fontWeight, FontWeight.w400); + + expect(textTheme.credentialManifestTitle1.color, const Color(0xffFFFFFF)); + expect(textTheme.credentialManifestTitle1.fontSize, 18); + expect(textTheme.credentialManifestTitle1.fontWeight, FontWeight.w700); + + expect( + textTheme.credentialManifestDescription.color, const Color(0xffFFFFFF)); + expect(textTheme.credentialManifestDescription.fontSize, 16); + expect(textTheme.credentialManifestDescription.fontWeight, FontWeight.w400); + + expect(textTheme.credentialManifestTitle2.color, const Color(0xffFFFFFF)); + expect(textTheme.credentialManifestTitle2.fontSize, 16); + expect(textTheme.credentialManifestTitle2.fontWeight, FontWeight.w700); + + expect(textTheme.credentialSubtitle.color, const Color(0xffFFFFFF)); + expect(textTheme.credentialSubtitle.fontSize, 14); + expect(textTheme.credentialSubtitle.fontWeight, FontWeight.w400); + + expect(textTheme.credentialStatus.color, const Color(0xffFFFFFF)); + expect(textTheme.credentialStatus.fontSize, 18); + expect(textTheme.credentialStatus.fontWeight, FontWeight.w800); + + expect(textTheme.beaconRequestPermission.color, const Color(0xff86809D)); + expect(textTheme.beaconRequestPermission.fontSize, 16); + expect(textTheme.beaconRequestPermission.fontWeight, FontWeight.w400); + + expect(textTheme.beaconSelectAccont.color, const Color(0xffFFFFFF)); + expect(textTheme.beaconSelectAccont.fontSize, 18); + expect(textTheme.beaconSelectAccont.fontWeight, FontWeight.w800); + + expect(textTheme.uploadFileTitle.color, const Color(0xffFFFFFF)); + expect(textTheme.uploadFileTitle.fontSize, 18); + expect(textTheme.uploadFileTitle.fontWeight, FontWeight.w800); + + expect(textTheme.beaconPermissionTitle.color, const Color(0xffFFFFFF)); + expect(textTheme.beaconPermissionTitle.fontSize, 18); + expect(textTheme.beaconPermissionTitle.fontWeight, FontWeight.w800); + + expect(textTheme.beaconPermissions.color, const Color(0xffFFFFFF)); + expect(textTheme.beaconPermissions.fontSize, 16); + expect(textTheme.beaconPermissions.fontWeight, FontWeight.w400); + + expect(textTheme.beaconPayload.color, const Color(0xffFFFFFF)); + expect(textTheme.beaconPayload.fontSize, 16); + expect(textTheme.beaconPayload.fontWeight, FontWeight.w400); + + expect(textTheme.beaconWalletAddress.color, const Color(0xffFFFFFF)); + expect(textTheme.beaconWalletAddress.fontSize, 16); + expect(textTheme.beaconWalletAddress.fontWeight, FontWeight.w400); + + expect(textTheme.dappName.color, const Color(0xffFFFFFF)); + expect(textTheme.dappName.fontSize, 16); + expect(textTheme.dappName.fontWeight, FontWeight.w400); + + expect(textTheme.cacheErrorMessage.color, const Color(0xffFFFFFF)); + expect(textTheme.cacheErrorMessage.fontSize, 16); + expect(textTheme.cacheErrorMessage.fontWeight, FontWeight.w600); + + expect(textTheme.credentialSteps.color, const Color(0xffFFFFFF)); + expect(textTheme.credentialSteps.fontSize, 18); + expect(textTheme.credentialSteps.fontWeight, FontWeight.w600); + + expect(textTheme.faqQue.color, const Color(0xffFFFFFF)); + expect(textTheme.faqQue.fontSize, 16); + expect(textTheme.faqQue.fontWeight, FontWeight.normal); + + expect(textTheme.faqAns.color, const Color(0xFF757575)); + expect(textTheme.faqAns.fontSize, 14); + expect(textTheme.faqAns.fontWeight, FontWeight.w400); + + expect(textTheme.proofCardDetail.color, const Color(0xffFFFFFF)); + expect(textTheme.proofCardDetail.fontSize, 12); + expect(textTheme.proofCardDetail.fontWeight, FontWeight.w300); }); } From a8e640eafa0c053932a2c83673c1bc90f9dcd177 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 13:26:57 +0545 Subject: [PATCH 32/56] Update markdown page test --- .../widget/base/markdown_page_test.dart | 105 ++++-------------- 1 file changed, 21 insertions(+), 84 deletions(-) diff --git a/test/app/shared/widget/base/markdown_page_test.dart b/test/app/shared/widget/base/markdown_page_test.dart index ffa0eb1b7..1c034b907 100644 --- a/test/app/shared/widget/base/markdown_page_test.dart +++ b/test/app/shared/widget/base/markdown_page_test.dart @@ -1,10 +1,5 @@ -import 'dart:convert'; -import 'dart:typed_data'; - import 'package:altme/app/app.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart' as services; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -19,91 +14,33 @@ void main() { ); } - bool isFirstCase = true; - - setUpAll(() { - ///do mock the assets - TestWidgetsFlutterBinding.ensureInitialized(); - services.ServicesBinding.instance.defaultBinaryMessenger - .setMockMessageHandler('flutter/assets', (message) { - if (isFirstCase) { - final Uint8List encoded = - utf8.encoder.convert('[Link `with nested code` Text](href)'); - return Future.value(encoded.buffer.asByteData()); - } else { - return null; - } - }); - }); - - group('MarkdownPage widget', () { - late Widget widget; - - setUp(() { - widget = makeTestableWidget(); - }); - - testWidgets('verify property set correctly', (WidgetTester tester) async { - await tester.pumpWidget(widget); - await tester.pumpAndSettle(); - expect(find.byType(MarkdownPage), findsOneWidget); - final markdownWidget = - tester.widget(find.byType(MarkdownPage)); - expect(markdownWidget.file, 'assets/notices/notices_en.md'); - expect(markdownWidget.title, 'title'); - expect(markdownWidget.key, isA()); - }); - - testWidgets('sub widget founded', (WidgetTester tester) async { - await tester.pumpWidget(widget); - await tester.pumpAndSettle(); - expect(find.byType(MarkdownPage), findsOneWidget); - expect(find.byType(BasePage), findsOneWidget); - expect(find.byType(BackLeadingButton), findsOneWidget); - expect(find.byType(Spinner), findsOneWidget); - await tester.pumpAndSettle(const Duration(seconds: 1)); - expect(find.byType(Markdown), findsOneWidget); - expect(find.byType(Spinner), findsNothing); - }); + testWidgets('MarkdownPage should load and display markdown content', + (WidgetTester tester) async { + await tester.pumpWidget(makeTestableWidget()); - testWidgets('tap on markdown widget', (WidgetTester tester) async { - await tester.pumpWidget(widget); - await tester.pumpAndSettle(); - expect(find.byType(Markdown), findsOneWidget); - final richText = tester.widget(find.byType(RichText).first); - final span = richText.text as TextSpan; + expect(find.byType(Spinner), findsOneWidget); - final gestureRecognizerTypes = []; - span.visitChildren((InlineSpan inlineSpan) { - if (inlineSpan is TextSpan) { - final recognizer = inlineSpan.recognizer; - gestureRecognizerTypes.add(recognizer?.runtimeType ?? Null); - if (recognizer != null && recognizer is TapGestureRecognizer) { - recognizer.onTap!(); - } - } - return true; - }); - - expect(span.children!.length, 3); - expect(gestureRecognizerTypes.length, 3); - expect(gestureRecognizerTypes, everyElement(TapGestureRecognizer)); - await tester.pumpAndSettle(); - }); + await tester.pumpAndSettle(); + expect(find.byType(Markdown), findsOneWidget); + expect( + find.text( + 'The Altme wallet is an open source project under Apache 2.0 licence', + ), + findsOneWidget, + ); }); - group('MarkdownPage bad state work properly', () { - final widget = MaterialApp( - home: MarkdownPage( - title: 'title', - file: 'assets/notices/notices_en.md', + testWidgets('MarkdownPage should handle loading errors', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: MarkdownPage(title: 'Test', file: 'invalid_file.md'), ), ); - testWidgets('trigger message ', (WidgetTester tester) async { - isFirstCase = false; - await tester.pumpWidget(widget); - await tester.pumpAndSettle(); - }); + expect(find.byType(Spinner), findsOneWidget); + + await tester.pumpAndSettle(); + expect(find.byType(Markdown), findsNothing); }); } From 25b4d6b6f616e3b0d0038b0666ae7121e0f2393f Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 14:28:34 +0545 Subject: [PATCH 33/56] Add tests for cyptocurrency_keys --- .../test/src/cryptocurrency_keys_test.dart | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/packages/cryptocurrency_keys/test/src/cryptocurrency_keys_test.dart b/packages/cryptocurrency_keys/test/src/cryptocurrency_keys_test.dart index a0228db15..8803b7690 100644 --- a/packages/cryptocurrency_keys/test/src/cryptocurrency_keys_test.dart +++ b/packages/cryptocurrency_keys/test/src/cryptocurrency_keys_test.dart @@ -6,8 +6,9 @@ void main() { 'notice photo opera keen climb agent soft parrot best joke field devote'; const message = '{"name": "My name is Bibash."}'; - const cipherText = '¨`ýp<ÐW3AR1¯#.í©¥¿e’,|VrtuXÅ'; - const authenticationTag = '䃆U~ḈÞ¦BÌuDÅ'; + const cipherText = '‚Ô\$æ²½-ôÜwĪ8aã~…\n' + 'Yyz¶«Þž[f*ýç'; + const authenticationTag = '¸^\x01áAê?^Ü6u¿¡¡S'; const encryptionModelJson = { 'cipherText': cipherText, 'authenticationTag': authenticationTag, @@ -42,12 +43,13 @@ void main() { 'generateKeyPair() should always derive the same keypair when using the' ' same mnemonic', () async { final generatedKey = await cryptocurrencyKeys.generateKeyPair(mnemonic); - expect(generatedKey.privateKey.hashCode, equals(1100798733)); - expect(generatedKey.publicKey.hashCode, equals(1100798733)); + expect(generatedKey.privateKey.hashCode, equals(264718007)); + expect(generatedKey.publicKey.hashCode, equals(264718007)); }); test('response is encrypted correctly', () async { final encryptedData = await cryptocurrencyKeys.encrypt(message, mnemonic); + expect(encryptedData.cipherText, equals(cipherText)); expect(encryptedData.authenticationTag, equals(authenticationTag)); }); @@ -64,32 +66,29 @@ void main() { expect(decryptedData, equals(message)); }); - test('invalid cipherText throws Auth message', () async { + test('invalid cipherText throws Exception', () async { const inCipherText = '123'; const encryption = Encryption( cipherText: inCipherText, authenticationTag: authenticationTag, ); - try { - await cryptocurrencyKeys.decrypt(mnemonic, encryption); - } catch (e) { - final error = e.toString().startsWith('Auth message'); - expect(error, true); - } + + expect( + () => cryptocurrencyKeys.decrypt(mnemonic, encryption), + throwsException, + ); }); - test('invalid authenticationTag throws Auth message', () async { + test('invalid authenticationTag throws Exception', () async { const inValidAuthenticationTag = '123'; const encryption = Encryption( cipherText: cipherText, authenticationTag: inValidAuthenticationTag, ); - try { - await cryptocurrencyKeys.decrypt(mnemonic, encryption); - } catch (e) { - final error = e.toString().startsWith('Auth message'); - expect(error, true); - } + expect( + () => cryptocurrencyKeys.decrypt(mnemonic, encryption), + throwsException, + ); }); }); } From 67cdcb34ca3e6ba960eca80007aa9211f452313c Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 14:32:08 +0545 Subject: [PATCH 34/56] Remove oidc4vc from test --- .github/workflows/oidc4vc.yaml | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 .github/workflows/oidc4vc.yaml diff --git a/.github/workflows/oidc4vc.yaml b/.github/workflows/oidc4vc.yaml deleted file mode 100644 index d0b1d93bc..000000000 --- a/.github/workflows/oidc4vc.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: oidc4vc - -on: [pull_request, push] - -jobs: - build: - uses: TalaoDAO/AltMe/.github/workflows/flutter_package.yaml@main - with: - flutter_channel: stable - flutter_version: 3.19.6 - min_coverage: 30 - working_directory: packages/oidc4vc - dart_sdk: 3.3.4 - build_runner: false From 42e403814956904a4461333518f0bd2eda832246 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 14:35:27 +0545 Subject: [PATCH 35/56] Update tests for jwt_decode --- packages/jwt_decode/test/src/jwt_decode_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/jwt_decode/test/src/jwt_decode_test.dart b/packages/jwt_decode/test/src/jwt_decode_test.dart index 6d067404b..8692a5fec 100644 --- a/packages/jwt_decode/test/src/jwt_decode_test.dart +++ b/packages/jwt_decode/test/src/jwt_decode_test.dart @@ -63,7 +63,7 @@ void main() { const validJwtTokenWithInvalidPayload = '''eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.W3siSGVsbG8iOjEyfV0.vfPVZG-CndvivC2JaWA4leWl_1F3pm1lr-l3BISqVAc'''; const jsonStringOfValidTokenOne = - r'''{scope: openid, response_type: id_token, client_id: did:web:altme.co, redirect_uri: https://altme.co/gaiax/login_redirect/287f58e9-a50c-11ec-bea0-0a1628958560, response_mode: post, claims: {"id_token":{},"vp_token":{"presentation_definition":{"id":"pass_for_gaiax","input_descriptors":[{"id":"GaiaxPass issued by altme","purpose":"Test for Gaia-X hackathon","format":{"ldp_vc":{"proof_type":["JsonWebSignature2020"]}},"constraints":{"limit_disclosure":"required","fields":[{"path":["$.credentialSubject.type"],"purpose":"One can only accept GaiaxPass","filter":{"type":"string","pattern":"GaiaxPass"}},{"path":["$.issuer"],"purpose":"One can accept only GaiaxPass signed by altme","filter":{"type":"string","pattern":"did:web:altme.co"}}]}}]}}}, nonce: 6j0RATZeIj, registration: {"id_token_signing_alg_values_supported":["RS256","ES256","ES256K","EdDSA"],"subject_syntax_types_supported":["did:web","did:tz","did:key","did:ion","did:pkh","did:ethr"]}, request_uri: https://altme.co/gaiax/login_request_uri/287f58e9-a50c-11ec-bea0-0a1628958560}'''; + r'''{scope: openid, response_type: id_token, client_id: did:web:talao.co, redirect_uri: https://talao.co/gaiax/login_redirect/287f58e9-a50c-11ec-bea0-0a1628958560, response_mode: post, claims: {"id_token":{},"vp_token":{"presentation_definition":{"id":"pass_for_gaiax","input_descriptors":[{"id":"GaiaxPass issued by Talao","purpose":"Test for Gaia-X hackathon","format":{"ldp_vc":{"proof_type":["JsonWebSignature2020"]}},"constraints":{"limit_disclosure":"required","fields":[{"path":["$.credentialSubject.type"],"purpose":"One can only accept GaiaxPass","filter":{"type":"string","pattern":"GaiaxPass"}},{"path":["$.issuer"],"purpose":"One can accept only GaiaxPass signed by Talao","filter":{"type":"string","pattern":"did:web:talao.co"}}]}}]}}}, nonce: 6j0RATZeIj, registration: {"id_token_signing_alg_values_supported":["RS256","ES256","ES256K","EdDSA"],"subject_syntax_types_supported":["did:web","did:tz","did:key","did:ion","did:pkh","did:ethr"]}, request_uri: https://talao.co/gaiax/login_request_uri/287f58e9-a50c-11ec-bea0-0a1628958560}'''; const inValidJwtTokenWithLessThanThreePart = 'partOne.partTwo'; const inValidJwtTokenWithThreePart = 'partOne.partTwo.partThree'; @@ -96,7 +96,7 @@ void main() { isA().having( (p0) => p0.toString(), 'toString()', - 'Exception: Invalid Token', + 'Exception: INVALID_TOKEN', ), ), ); @@ -118,7 +118,7 @@ void main() { isA().having( (p0) => p0.toString(), 'toString()', - 'Exception: Invalid Payload', + 'Exception: INVALID_PAYLOAD', ), ), ); From 1fbf8ab5dfc3b0337409ca2dedd801a21010a7f7 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 14:44:33 +0545 Subject: [PATCH 36/56] add some tests --- .../jwt_decode/test/src/jwt_decode_test.dart | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/jwt_decode/test/src/jwt_decode_test.dart b/packages/jwt_decode/test/src/jwt_decode_test.dart index 8692a5fec..74c066e10 100644 --- a/packages/jwt_decode/test/src/jwt_decode_test.dart +++ b/packages/jwt_decode/test/src/jwt_decode_test.dart @@ -123,5 +123,31 @@ void main() { ), ); }); + + test('parseJwtHeader throws exception for invalid token', () { + expect( + () => jwtDecode.parseJwtHeader('invalid.token'), + throwsA( + isA().having( + (p0) => p0.toString(), + 'toString()', + 'Exception: INVALID_TOKEN', + ), + ), + ); + }); + + test('parseJwtHeader returns header for valid token', () { + final header = jwtDecode.parseJwtHeader(validJwtToken); + expect(header['alg'], 'RS256'); + expect(header['typ'], 'JWT'); + }); + + test('parsePolygonIdJwtHeader throws exception for invalid token', () { + expect( + () => jwtDecode.parsePolygonIdJwtHeader('invalid.token'), + throwsException, + ); + }); }); } From b57af647283047b46864a0e708bcd0c3ac2d717e Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 16:41:39 +0545 Subject: [PATCH 37/56] remove key_generateor from github workflow --- .github/workflows/key_generator.yaml | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 .github/workflows/key_generator.yaml diff --git a/.github/workflows/key_generator.yaml b/.github/workflows/key_generator.yaml deleted file mode 100644 index 7be1bb9dc..000000000 --- a/.github/workflows/key_generator.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: key_generator - -on: [ pull_request, push ] - -jobs: - build: - uses: TalaoDAO/AltMe/.github/workflows/flutter_package.yaml@main - with: - flutter_channel: stable - flutter_version: 3.19.6 - min_coverage: 30 - working_directory: packages/key_generator - dart_sdk: 3.3.4 - build_runner: false From 70672a6769dc9793184be466092dfc07b5b8621f Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 17:54:05 +0545 Subject: [PATCH 38/56] Add some secure storage tests --- .../test/src/secure_storage_test.dart | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/secure_storage/test/src/secure_storage_test.dart b/packages/secure_storage/test/src/secure_storage_test.dart index 247ba18d2..c8a7c3502 100644 --- a/packages/secure_storage/test/src/secure_storage_test.dart +++ b/packages/secure_storage/test/src/secure_storage_test.dart @@ -16,12 +16,16 @@ void main() { setUpAll(() async { mockFlutterSecureStorage = MockFlutterSecureStorage(); - secureStorageProvider = SecureStorageProvider(); + secureStorageProvider = + SecureStorageProvider(storage: mockFlutterSecureStorage); }); group('SecureStorage', () { test('can be instantiated', () { - expect(getSecureStorage, isNotNull); + expect(secureStorageProvider, isNotNull); + }); + test('getSecureStorage returns SecureStorageProvider instance', () { + expect(getSecureStorage, isA()); }); test('get method works correctly', () async { @@ -97,5 +101,47 @@ void main() { await secureStorageProvider.deleteAll(); verify(mockFlutterSecureStorage.deleteAll).called(1); }); + + group('deleteAllExceptsSomeKeys method', () { + test('delete all when list is null', () async { + when(mockFlutterSecureStorage.deleteAll) + .thenAnswer((invocation) async {}); + + await secureStorageProvider.deleteAllExceptsSomeKeys(null); + verify(mockFlutterSecureStorage.deleteAll).called(1); + }); + + test('delete all when list is empty', () async { + when(mockFlutterSecureStorage.deleteAll) + .thenAnswer((invocation) async {}); + + await secureStorageProvider.deleteAllExceptsSomeKeys([]); + verify(mockFlutterSecureStorage.deleteAll).called(1); + }); + + test('delete all except sent in the list', () async { + when( + () => mockFlutterSecureStorage.readAll( + iOptions: any(named: 'iOptions'), + ), + ).thenAnswer((invocation) async { + return { + 'key1': '1', + 'key2': '2', + }; + }); + + when( + () => mockFlutterSecureStorage.delete( + key: 'key1', + iOptions: any(named: 'iOptions'), + ), + ).thenAnswer((_) async {}); + + await secureStorageProvider.deleteAllExceptsSomeKeys(['key2']); + verify(() => mockFlutterSecureStorage.delete(key: 'key1')).called(1); + verifyNever(() => mockFlutterSecureStorage.delete(key: 'key2')); + }); + }); }); } From 6b06e93e25a0146fc9c12782dd21fec781fe1870 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 17:55:50 +0545 Subject: [PATCH 39/56] Add tests for secure storage --- .github/workflows/{polygonid.yaml => secure_storage.yaml} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename .github/workflows/{polygonid.yaml => secure_storage.yaml} (70%) diff --git a/.github/workflows/polygonid.yaml b/.github/workflows/secure_storage.yaml similarity index 70% rename from .github/workflows/polygonid.yaml rename to .github/workflows/secure_storage.yaml index 9c04e9c6a..8f292dfb8 100644 --- a/.github/workflows/polygonid.yaml +++ b/.github/workflows/secure_storage.yaml @@ -1,6 +1,6 @@ -name: polygonid +name: secure_storage -on: [ pull_request, push ] +on: [pull_request, push] jobs: build: @@ -9,6 +9,6 @@ jobs: flutter_channel: stable flutter_version: 3.19.6 min_coverage: 30 - working_directory: packages/polygonid + working_directory: packages/secure_storage dart_sdk: 3.3.4 build_runner: false From eff8eb7e533dec6e46fec5faa905ea20bfa5531e Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 8 May 2024 18:06:52 +0545 Subject: [PATCH 40/56] Read all can be called any time --- packages/secure_storage/test/src/secure_storage_test.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/secure_storage/test/src/secure_storage_test.dart b/packages/secure_storage/test/src/secure_storage_test.dart index c8a7c3502..5f3f13e6c 100644 --- a/packages/secure_storage/test/src/secure_storage_test.dart +++ b/packages/secure_storage/test/src/secure_storage_test.dart @@ -49,10 +49,9 @@ void main() { final result = await secureStorageProvider.getAllValues(); expect(result, equals(allValue)); verify( - () => mockFlutterSecureStorage.readAll( - iOptions: any(named: 'iOptions'), - ), - ).called(1); + () => + mockFlutterSecureStorage.readAll(iOptions: any(named: 'iOptions')), + ); }); test('set method works correctly', () async { From 736476c150c59f54c15beccf223f584b61e19185 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 9 May 2024 17:39:42 +0545 Subject: [PATCH 41/56] feat: Update to Interop event verifier fails #2651 --- lib/scan/cubit/scan_cubit.dart | 3 ++- .../oidc4vc/test/src/vc_format_type_test.dart | 20 +++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index 4a93e0f7e..eff50b61a 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -614,7 +614,8 @@ class ScanCubit extends Cubit { await Future.delayed(const Duration(seconds: 1)); final responseData = { 'vp_token': vpToken, - 'presentation_submission': presentationSubmissionString, + 'presentation_submission': + Uri.encodeQueryComponent(jsonEncode(presentationSubmission)), }; if (idTokenNeeded && idToken != null) { diff --git a/packages/oidc4vc/test/src/vc_format_type_test.dart b/packages/oidc4vc/test/src/vc_format_type_test.dart index ee4f52fc6..deb3714d2 100644 --- a/packages/oidc4vc/test/src/vc_format_type_test.dart +++ b/packages/oidc4vc/test/src/vc_format_type_test.dart @@ -4,19 +4,19 @@ import 'package:oidc4vc/oidc4vc.dart'; void main() { group('VCFormatTypeX', () { test('formattedString', () { - expect(VCFormatType.ldpVc.formattedString, 'ldp_vc'); - expect(VCFormatType.jwtVc.formattedString, 'jwt_vc'); - expect(VCFormatType.jwtVcJson.formattedString, 'jwt_vc_json'); - expect(VCFormatType.jwtVcJsonLd.formattedString, 'jwt_vc_json-ld'); - expect(VCFormatType.vcSdJWT.formattedString, 'vc+sd-jwt'); + expect(VCFormatType.ldpVc.vcValue, 'ldp_vc'); + expect(VCFormatType.jwtVc.vcValue, 'jwt_vc'); + expect(VCFormatType.jwtVcJson.vcValue, 'jwt_vc_json'); + expect(VCFormatType.jwtVcJsonLd.vcValue, 'jwt_vc_json-ld'); + expect(VCFormatType.vcSdJWT.vcValue, 'vc+sd-jwt'); }); test('value', () { - expect(VCFormatType.ldpVc.value, 'ldp_vc'); - expect(VCFormatType.jwtVc.value, 'jwt_vc'); - expect(VCFormatType.jwtVcJson.value, 'jwt_vc_json'); - expect(VCFormatType.jwtVcJsonLd.value, 'jwt_vc_json-ld'); - expect(VCFormatType.vcSdJWT.value, 'vc+sd-jwt'); + expect(VCFormatType.ldpVc.vpValue, 'ldp_vp'); + expect(VCFormatType.jwtVc.vpValue, 'jwt_vp'); + expect(VCFormatType.jwtVcJson.vpValue, 'jwt_vp_json'); + expect(VCFormatType.jwtVcJsonLd.vpValue, 'jwt_vp_json-ld'); + expect(VCFormatType.vcSdJWT.vpValue, 'vc+sd-jwt'); }); test('urlValue', () { From 23e9e7d3283503ae14bade7f8f22f27522f59bc4 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 10 May 2024 13:38:09 +0545 Subject: [PATCH 42/56] small bug fix --- lib/scan/cubit/scan_cubit.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index eff50b61a..4a93e0f7e 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -614,8 +614,7 @@ class ScanCubit extends Cubit { await Future.delayed(const Duration(seconds: 1)); final responseData = { 'vp_token': vpToken, - 'presentation_submission': - Uri.encodeQueryComponent(jsonEncode(presentationSubmission)), + 'presentation_submission': presentationSubmissionString, }; if (idTokenNeeded && idToken != null) { From 633ec43f053eefd70836dc0d674cde30e71af04c Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 10 May 2024 15:54:54 +0545 Subject: [PATCH 43/56] Add extension and date tests --- .../status/credential_status_extension.dart} | 0 lib/app/shared/enum/status/status.dart | 1 + lib/app/shared/extension/extension.dart | 1 - .../alert_message/alert_message_test.dart | 190 ++++++++++++++++++ test/app/shared/constants/urls_test.dart | 11 + test/app/shared/date/date_test.dart | 84 ++++++++ .../extension/bigint_extension_test.dart | 27 +++ .../extension/double_extension_test.dart | 41 ++++ .../extension/iterable_extension_test.dart | 37 ++++ .../extension/string_extension_test.dart | 55 +++++ .../extension/unit8List_extension_test.dart | 40 ++++ .../network/network_exception_test.dart | 31 +++ 12 files changed, 517 insertions(+), 1 deletion(-) rename lib/app/shared/{extension/credential_status.dart => enum/status/credential_status_extension.dart} (100%) create mode 100644 test/app/shared/alert_message/alert_message_test.dart create mode 100644 test/app/shared/constants/urls_test.dart create mode 100644 test/app/shared/date/date_test.dart create mode 100644 test/app/shared/extension/bigint_extension_test.dart create mode 100644 test/app/shared/extension/double_extension_test.dart create mode 100644 test/app/shared/extension/iterable_extension_test.dart create mode 100644 test/app/shared/extension/string_extension_test.dart create mode 100644 test/app/shared/extension/unit8List_extension_test.dart diff --git a/lib/app/shared/extension/credential_status.dart b/lib/app/shared/enum/status/credential_status_extension.dart similarity index 100% rename from lib/app/shared/extension/credential_status.dart rename to lib/app/shared/enum/status/credential_status_extension.dart diff --git a/lib/app/shared/enum/status/status.dart b/lib/app/shared/enum/status/status.dart index 633bdfb16..f924629ab 100644 --- a/lib/app/shared/enum/status/status.dart +++ b/lib/app/shared/enum/status/status.dart @@ -2,6 +2,7 @@ export 'app_status.dart'; export 'beacon_status.dart'; export 'credential_detail_tab_status.dart'; export 'credential_status.dart'; +export 'credential_status_extension.dart'; export 'credentials_status.dart'; export 'home_status.dart'; export 'kyc_verification_status.dart'; diff --git a/lib/app/shared/extension/extension.dart b/lib/app/shared/extension/extension.dart index 1703838c0..c8a08d0ed 100644 --- a/lib/app/shared/extension/extension.dart +++ b/lib/app/shared/extension/extension.dart @@ -1,5 +1,4 @@ export 'bigint_extension.dart'; -export 'credential_status.dart'; export 'double_extension.dart'; export 'iterable_extension.dart'; export 'string_extension.dart'; diff --git a/test/app/shared/alert_message/alert_message_test.dart b/test/app/shared/alert_message/alert_message_test.dart new file mode 100644 index 000000000..78c176835 --- /dev/null +++ b/test/app/shared/alert_message/alert_message_test.dart @@ -0,0 +1,190 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + testWidgets('AlertMessage shows SnackBar', (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (BuildContext context) { + return ElevatedButton( + onPressed: () { + AlertMessage.showStateMessage( + context: context, + stateMessage: const StateMessage( + messageHandler: null, + stringMessage: 'Test Message', + injectedMessage: null, + showDialog: false, + duration: Duration(seconds: 2), + type: MessageType.info, + ), + ); + }, + child: const Text('Show SnackBar'), + ); + }, + ), + ), + ); + + await tester.tap(find.text('Show SnackBar')); + await tester.pumpAndSettle(); + + expect(find.text('Test Message'), findsOneWidget); + expect(find.byType(SnackBar), findsOneWidget); + expect(find.byType(SnackBarContent), findsOneWidget); + }); + + testWidgets('AlertMessage shows Dialog', (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (BuildContext context) { + return ElevatedButton( + onPressed: () { + AlertMessage.showStateMessage( + context: context, + stateMessage: const StateMessage( + messageHandler: null, + stringMessage: 'Test Message', + injectedMessage: null, + showDialog: true, + type: MessageType.info, + ), + ); + }, + child: const Text('Show Dialog'), + ); + }, + ), + ), + ); + + await tester.tap(find.text('Show Dialog')); + await tester.pumpAndSettle(); + + expect(find.text('Test Message'), findsOneWidget); + expect(find.byType(ErrorDialog), findsOneWidget); + }); + testWidgets('SnackBarContent is displayed correctly', + (WidgetTester tester) async { + await tester.pumpApp( + const Scaffold( + body: SnackBarContent( + message: 'Test Message', + iconPath: 'assets/icon/add.png', + ), + ), + ); + + expect(find.text('Test Message'), findsOneWidget); + expect(find.byType(ElevatedButton), findsOneWidget); + }); + + testWidgets('AlertMessage shows Network error properly', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (BuildContext context) { + return ElevatedButton( + onPressed: () { + AlertMessage.showStateMessage( + context: context, + stateMessage: StateMessage( + messageHandler: NetworkException( + data: 'Netwok Test', + ), + injectedMessage: null, + showDialog: false, + duration: const Duration(seconds: 2), + type: MessageType.info, + ), + ); + }, + child: const Text('Show SnackBar'), + ); + }, + ), + ), + ); + + await tester.tap(find.text('Show SnackBar')); + await tester.pumpAndSettle(); + + expect(find.text('Netwok Test'), findsOneWidget); + }); + + testWidgets('AlertMessage shows default message when nothing is provided', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (BuildContext context) { + return ElevatedButton( + onPressed: () { + AlertMessage.showStateMessage( + context: context, + stateMessage: const StateMessage( + messageHandler: null, + injectedMessage: null, + showDialog: false, + duration: Duration(seconds: 2), + type: MessageType.info, + ), + ); + }, + child: const Text('Show SnackBar'), + ); + }, + ), + ), + ); + + await tester.tap(find.text('Show SnackBar')); + await tester.pumpAndSettle(); + + expect(find.text('This request is not supported'), findsOneWidget); + }); + testWidgets('AlertMessage shows ResponseMessage correctly', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (BuildContext context) { + return ElevatedButton( + onPressed: () { + AlertMessage.showStateMessage( + context: context, + stateMessage: StateMessage( + messageHandler: ResponseMessage( + message: ResponseString + .RESPONSE_STRING_AN_ERROR_OCCURRED_WHILE_CONNECTING_TO_THE_SERVER, + ), + injectedMessage: null, + showDialog: false, + duration: const Duration(seconds: 2), + type: MessageType.info, + ), + ); + }, + child: const Text('Show SnackBar'), + ); + }, + ), + ), + ); + + await tester.tap(find.text('Show SnackBar')); + await tester.pumpAndSettle(); + + expect( + find.text('An error occurred while connecting to the server.'), + findsOneWidget, + ); + }); +} diff --git a/test/app/shared/constants/urls_test.dart b/test/app/shared/constants/urls_test.dart new file mode 100644 index 000000000..2216211dc --- /dev/null +++ b/test/app/shared/constants/urls_test.dart @@ -0,0 +1,11 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('ethPrice returns correct URL', () { + const symbol = 'ETH'; + const expectedUrl = + 'https://min-api.cryptocompare.com/data/price?fsym=$symbol&tsyms=USD'; + expect(Urls.ethPrice(symbol), expectedUrl); + }); +} diff --git a/test/app/shared/date/date_test.dart b/test/app/shared/date/date_test.dart new file mode 100644 index 000000000..cb447be14 --- /dev/null +++ b/test/app/shared/date/date_test.dart @@ -0,0 +1,84 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class MockAppLocalizations extends Mock implements AppLocalizations { + @override + final localeName = 'en_US'; +} + +void main() { + group('UiDate', () { + group('displayRegionalDate', () { + test('should return formatted date for valid input', () { + const dateString = '2024-05-20'; + final localizations = MockAppLocalizations(); + + final result = UiDate.displayRegionalDate(localizations, dateString); + expect(result, '5/20/2024'); + }); + + test('should return empty string for empty input', () { + final localizations = MockAppLocalizations(); + + final result = UiDate.displayRegionalDate(localizations, ''); + + expect(result, ''); + }); + + test('should return empty string for invalid input', () { + final localizations = MockAppLocalizations(); + + final result = UiDate.displayRegionalDate(localizations, 'invalid'); + + expect(result, ''); + }); + }); + + test('formatStringDate returns formatted date', () { + const dateTime = '2022-05-10T10:00:00Z'; + expect(UiDate.formatStringDate(dateTime), '2022-05-10'); + }); + + test('formatDate returns formatted date', () { + final dateTime = DateTime(2022, 5, 10); + expect(UiDate.formatDate(dateTime), '2022-05-10'); + }); + + test( + 'formatDateForCredentialCard returns formatted date for credential card', + () { + const timestamp = '1643738400'; + expect(UiDate.formatDateForCredentialCard(timestamp), '2022-02-01'); + }); + + group('isTimestampString', () { + test('returns true for valid timestamp string', () { + const timestamp = '1643738400'; + expect(UiDate.isTimestampString(timestamp), true); + }); + + test('returns false for invalid timestamp string', () { + const invalidTimestamp = 'abc'; + expect(UiDate.isTimestampString(invalidTimestamp), false); + }); + }); + + group('normalFormat', () { + test('returns formatted date and time', () { + const dateTime = '2022-05-10T10:00:00Z'; + expect(UiDate.normalFormat(dateTime), '10-05-2022 15:45'); + }); + test('returns null if format is empty', () { + const dateTime = ''; + expect(UiDate.normalFormat(dateTime), null); + }); + + test('returns null if format is incorrect', () { + const dateTime = 'asdf'; + expect(UiDate.normalFormat(dateTime), null); + }); + }); + }); +} diff --git a/test/app/shared/extension/bigint_extension_test.dart b/test/app/shared/extension/bigint_extension_test.dart new file mode 100644 index 000000000..ed997ff8f --- /dev/null +++ b/test/app/shared/extension/bigint_extension_test.dart @@ -0,0 +1,27 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('BigIntExtension', () { + test('toBytes converts BigInt to byte list', () { + final bigInt = BigInt.from(16909060); // Example value: 0x01020304 + final bytes = bigInt.toBytes; + expect(bytes, [1, 2, 3, 4]); + }); + + test('toBytes returns empty list for zero', () { + final bigInt = BigInt.zero; + final bytes = bigInt.toBytes; + expect(bytes, []); + }); + + test('toBytes handles large BigInt values', () { + final bigInt = BigInt.parse('123456789012345678901234567890'); + final bytes = bigInt.toBytes; + expect( + bytes, + [1, 142, 233, 15, 246, 195, 115, 224, 238, 78, 63, 10, 210], + ); + }); + }); +} diff --git a/test/app/shared/extension/double_extension_test.dart b/test/app/shared/extension/double_extension_test.dart new file mode 100644 index 000000000..41aee422c --- /dev/null +++ b/test/app/shared/extension/double_extension_test.dart @@ -0,0 +1,41 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('DoubleExtension', () { + test('decimalNumber returns string with specified decimal places', () { + const value = 3.14159; + expect(value.decimalNumber(2), '3.14'); + }); + + test('decimalNumber handles values with fewer decimal places', () { + const value = 123.4512; + expect(value.decimalNumber(4), '123.4512'); + }); + + test('decimalNumber handles values with fewer decimal places with 0s', () { + const value = 123.4500; + expect(value.decimalNumber(4), '123.45'); + }); + + test('decimalNumber handles values with more decimal places', () { + const value = 0.123456789; + expect(value.decimalNumber(5), '0.12345'); + }); + + test('decimalNumber returns 0.00 for zero', () { + const value = 0.0; + expect(value.decimalNumber(2), '0.0'); + }); + + test('decimalNumber handles negative values', () { + const value = -12.3456; + expect(value.decimalNumber(3), '-12.346'); + }); + + test('decimalNumber handles large values', () { + const value = 987654321.987656321; + expect(value.decimalNumber(5), '987654321.98765'); + }); + }); +} diff --git a/test/app/shared/extension/iterable_extension_test.dart b/test/app/shared/extension/iterable_extension_test.dart new file mode 100644 index 000000000..fd160f163 --- /dev/null +++ b/test/app/shared/extension/iterable_extension_test.dart @@ -0,0 +1,37 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('IterableExtension', () { + test('firstWhereOrNull returns first element that satisfies the condition', + () { + final list = [1, 2, 3, 4, 5]; + expect(list.firstWhereOrNull((element) => element.isOdd), 1); + expect(list.firstWhereOrNull((element) => element.isEven), 2); + }); + + test('firstWhereOrNull returns null if no element satisfies the condition', + () { + final list = [1, 3, 5, 7, 9]; + expect(list.firstWhereOrNull((element) => element.isEven), null); + }); + + test('lastWhereOrNull returns last element that satisfies the condition', + () { + final list = [1, 2, 3, 4, 5]; + expect(list.lastWhereOrNull((element) => element.isOdd), 5); + expect(list.lastWhereOrNull((element) => element.isEven), 4); + }); + + test('lastWhereOrNull returns null if no element satisfies the condition', + () { + final list = [1, 3, 5, 7, 9]; + expect(list.lastWhereOrNull((element) => element.isEven), null); + }); + + test('lastWhereOrNull returns null for empty iterable', () { + final list = []; + expect(list.lastWhereOrNull((element) => true), null); + }); + }); +} diff --git a/test/app/shared/extension/string_extension_test.dart b/test/app/shared/extension/string_extension_test.dart new file mode 100644 index 000000000..9ce281833 --- /dev/null +++ b/test/app/shared/extension/string_extension_test.dart @@ -0,0 +1,55 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('StringExtension', () { + test('formatNumber formats numbers correctly', () { + expect('1000'.formatNumber, '1,000'); + expect('123456789'.formatNumber, '123,456,789'); + expect('12345.6789'.formatNumber, '12,345.6789'); + expect('0.12345'.formatNumber, '0.12345'); + expect('123'.formatNumber, '123'); + expect('abc'.formatNumber, 'abc'); + }); + + test('isValidEmail validates email addresses', () { + expect('email@example.com'.isValidEmail(), true); + expect('invalid.email@'.isValidEmail(), false); + expect('another.invalid.email@domain'.isValidEmail(), false); + }); + + test('char2Bytes converts string to hex bytes', () { + expect('hello'.char2Bytes, '68656c6c6f'); + expect(''.char2Bytes, ''); + }); + + test('isEVM identifies EVM-based currencies', () { + expect('ETH'.isEVM, true); + expect('MATIC'.isEVM, true); + expect('FTM'.isEVM, true); + expect('BNB'.isEVM, true); + expect('BTC'.isEVM, false); + }); + + test('decimalNumber formats decimal numbers correctly', () { + expect('123.456'.decimalNumber(2), '123.45'); + expect('123.456'.decimalNumber(4), '123.456'); + expect('123'.decimalNumber(3), '123'); + }); + + test('invalid decimalNumber throws FormatException', () { + expect(() => 'abc'.decimalNumber(2), throwsFormatException); + }); + + test('Characters getter returns correct characters', () { + const input = 'Hello, world!'; + final characters = input.characters; + + expect(characters.length, input.length); + + for (int i = 0; i < input.length; i++) { + expect(characters.elementAt(i), input[i]); + } + }); + }); +} diff --git a/test/app/shared/extension/unit8List_extension_test.dart b/test/app/shared/extension/unit8List_extension_test.dart new file mode 100644 index 000000000..9effdc86f --- /dev/null +++ b/test/app/shared/extension/unit8List_extension_test.dart @@ -0,0 +1,40 @@ +import 'dart:typed_data'; +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('Uint8ListExtension', () { + test( + 'filterPayload returns the original list if length is less than or equal to 6', + () { + final list = Uint8List.fromList([1, 2, 3]); + expect(list.filterPayload, list); + + final shortList = Uint8List.fromList([1, 2, 3, 4, 5, 6]); + expect(shortList.filterPayload, shortList); + }); + + test( + 'filterPayload returns the original list if the first two elements do not match the test list', + () { + final list = Uint8List.fromList([1, 2, 3, 4, 5, 6, 7, 8, 9]); + expect(list.filterPayload, list); + + final differentFirstElement = + Uint8List.fromList([6, 1, 3, 4, 5, 6, 7, 8, 9]); + expect(differentFirstElement.filterPayload, differentFirstElement); + + final differentSecondElement = + Uint8List.fromList([5, 5, 3, 4, 5, 6, 7, 8, 9]); + expect(differentSecondElement.filterPayload, differentSecondElement); + }); + + test( + 'filterPayload returns a sublist starting from index 6 if the first two elements match the test list', + () { + final list = Uint8List.fromList([5, 1, 3, 4, 5, 6, 7, 8, 9]); + final expected = Uint8List.fromList([7, 8, 9]); + expect(list.filterPayload, expected); + }); + }); +} diff --git a/test/app/shared/network/network_exception_test.dart b/test/app/shared/network/network_exception_test.dart index ec4acdd00..53a02734d 100644 --- a/test/app/shared/network/network_exception_test.dart +++ b/test/app/shared/network/network_exception_test.dart @@ -570,6 +570,37 @@ void main() { NetworkError.NETWORK_ERROR_NOT_FOUND.localise(context), ); }); + + testWidgets( + 'returns NetworkError.NETWORK_ERROR_PRECONDITION_FAILED for ' + 'NetworkException(message: NetworkError.NETWORK_ERROR_PRECONDITION_FAILED)', + (tester) async { + final MessageHandler messageHandler = NetworkException( + message: NetworkError.NETWORK_ERROR_PRECONDITION_FAILED, + ); + await tester.pumpApp(Container()); + final BuildContext context = tester.element(find.byType(Container)); + final String text = messageHandler.getMessage(context, messageHandler); + expect( + text, + NetworkError.NETWORK_ERROR_PRECONDITION_FAILED.localise(context), + ); + }); + + testWidgets( + 'returns NetworkError.NETWORK_ERROR_NOT_READY for ' + 'NetworkException(message: NetworkError.NETWORK_ERROR_NOT_READY)', + (tester) async { + final MessageHandler messageHandler = + NetworkException(message: NetworkError.NETWORK_ERROR_NOT_READY); + await tester.pumpApp(Container()); + final BuildContext context = tester.element(find.byType(Container)); + final String text = messageHandler.getMessage(context, messageHandler); + expect( + text, + NetworkError.NETWORK_ERROR_NOT_READY.localise(context), + ); + }); }); }); } From ba3ac3f3c7a71db7a74e456efa555e173d712261 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 10 May 2024 18:55:37 +0545 Subject: [PATCH 44/56] Add some enum test --- lib/app/shared/enum/credential_category.dart | 3 +- .../discover_credential_category_item.dart | 3 +- .../home_credential_category_item.dart | 3 +- .../shared/enum/credential_category_test.dart | 253 ++++++++++++++++++ .../shared/enum/polygon_id_network_test.dart | 22 ++ .../enum/status/mnemonic_status_test.dart | 19 ++ 6 files changed, 299 insertions(+), 4 deletions(-) create mode 100644 test/app/shared/enum/credential_category_test.dart create mode 100644 test/app/shared/enum/polygon_id_network_test.dart create mode 100644 test/app/shared/enum/status/mnemonic_status_test.dart diff --git a/lib/app/shared/enum/credential_category.dart b/lib/app/shared/enum/credential_category.dart index af7c4faed..1fd9c5455 100644 --- a/lib/app/shared/enum/credential_category.dart +++ b/lib/app/shared/enum/credential_category.dart @@ -80,8 +80,7 @@ extension CredentialCategoryX on CredentialCategory { } } - CredentialCategoryConfig config(BuildContext context) { - final l10n = context.l10n; + CredentialCategoryConfig config(AppLocalizations l10n) { switch (this) { case CredentialCategory.advantagesCards: return CredentialCategoryConfig( diff --git a/lib/dashboard/discover/widgets/discover_credential_category_item.dart b/lib/dashboard/discover/widgets/discover_credential_category_item.dart index 45265578a..47475725c 100644 --- a/lib/dashboard/discover/widgets/discover_credential_category_item.dart +++ b/lib/dashboard/discover/widgets/discover_credential_category_item.dart @@ -1,5 +1,6 @@ import 'package:altme/app/app.dart'; import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/l10n/l10n.dart'; import 'package:altme/theme/theme.dart'; import 'package:flutter/material.dart'; @@ -17,7 +18,7 @@ class DiscoverCredentialCategoryItem extends StatelessWidget { @override Widget build(BuildContext context) { - final credentialCategoryConfig = credentialCategory.config(context); + final credentialCategoryConfig = credentialCategory.config(context.l10n); //sort credentials by order dummyCredentials.sort( (a, b) => diff --git a/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_item.dart b/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_item.dart index 9589bdbd1..ec0f44211 100644 --- a/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_item.dart +++ b/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_item.dart @@ -1,5 +1,6 @@ import 'package:altme/app/app.dart'; import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/l10n/l10n.dart'; import 'package:altme/theme/theme.dart'; import 'package:flutter/material.dart'; @@ -29,7 +30,7 @@ class HomeCredentialCategoryItem extends StatelessWidget { ? 1 : 0, ); - final credentialCategoryConfig = credentialCategory.config(context); + final credentialCategoryConfig = credentialCategory.config(context.l10n); return Padding( padding: margin, child: Column( diff --git a/test/app/shared/enum/credential_category_test.dart b/test/app/shared/enum/credential_category_test.dart new file mode 100644 index 000000000..32a64652d --- /dev/null +++ b/test/app/shared/enum/credential_category_test.dart @@ -0,0 +1,253 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +class MockAppLocalizations extends Mock implements AppLocalizations { + final my = 'My'; + final get = 'Get'; + + final advantagesCards = 'A1'; + final advantagesCredentialHomeSubtitle = 'A2'; + final advantagesDiscoverCards = 'A3'; + final advantagesCredentialDiscoverSubtitle = 'A4'; + + final identityCards = 'A1'; + final identityCredentialHomeSubtitle = 'A2'; + final identityDiscoverCards = 'A3'; + final identityCredentialDiscoverSubtitle = 'A4'; + + final myProfessionalCards = 'A1'; + final myProfessionalrCardsSubtitle = 'A2'; + final myProfessionalCredentialDiscoverSubtitle = 'A3'; + + final contactInfoCredentials = 'A1'; + final contactInfoCredentialHomeSubtitle = 'A2'; + final contactInfoDiscoverCredentials = 'A3'; + final contactInfoCredentialDiscoverSubtitle = 'A4'; + + final blockchainAccounts = 'A1'; + final blockchainAccountsCredentialHomeSubtitle = 'A2'; + final blockchainCardsDiscoverTitle = 'A3'; + final blockchainCardsDiscoverSubtitle = 'A4'; + + final educationCredentials = 'A1'; + final educationCredentialHomeSubtitle = 'A2'; + final educationDiscoverCredentials = 'A3'; + final educationCredentialsDiscoverSubtitle = 'A4'; + + final otherCards = 'A1'; + final otherCredentialHomeSubtitle = 'A2'; + final otherCredentialDiscoverSubtitle = 'A4'; + + final financeCredentialsHomeTitle = 'A1'; + final financeCredentialsHomeSubtitle = 'A2'; + final financeCredentialsDiscoverTitle = 'A3'; + final financeCredentialsDiscoverSubtitle = 'A4'; + + final hummanityProofCredentialsHomeTitle = 'A1'; + final hummanityProofCredentialsHomeSubtitle = 'A2'; + final hummanityProofCredentialsDiscoverTitle = 'A3'; + final hummanityProofCredentialsDiscoverSubtitle = 'A4'; + + final socialMediaCredentialsHomeTitle = 'A1'; + final socialMediaCredentialsHomeSubtitle = 'A2'; + final socialMediaCredentialsDiscoverTitle = 'A3'; + final socialMediaCredentialsDiscoverSubtitle = 'A4'; + + final walletIntegrityCredentialsHomeTitle = 'A1'; + final walletIntegrityCredentialsHomeSubtitle = 'A2'; + final walletIntegrityCredentialsDiscoverTitle = 'A3'; + final walletIntegrityCredentialsDiscoverSubtitle = 'A4'; + + final polygonCredentialsHomeTitle = 'A1'; + final polygonCredentialsHomeSubtitle = 'A2'; + final polygonCredentialsDiscoverTitle = 'A3'; + final polygonCredentialsDiscoverSubtitle = 'A4'; + + final pendingCredentialsHomeTitle = 'A1'; + final pendingCredentialsHomeSubtitle = 'A2'; +} + +void main() { + test('getCredentialCategorySorted should return categories in sorted order', + () { + final sortedCategories = [ + CredentialCategory.identityCards, + CredentialCategory.professionalCards, + CredentialCategory.contactInfoCredentials, + CredentialCategory.educationCards, + CredentialCategory.financeCards, + CredentialCategory.humanityProofCards, + CredentialCategory.socialMediaCards, + CredentialCategory.walletIntegrity, + CredentialCategory.polygonidCards, + CredentialCategory.blockchainAccountsCards, + CredentialCategory.othersCards, + CredentialCategory.pendingCards, + CredentialCategory.advantagesCards, + ]; + + expect(getCredentialCategorySorted, sortedCategories); + }); + + group('CredentialCategoryExtension', () { + test('order should return correct order for each category', () { + expect(CredentialCategory.advantagesCards.order, 8); + expect(CredentialCategory.identityCards.order, 140); + expect(CredentialCategory.professionalCards.order, 135); + expect(CredentialCategory.contactInfoCredentials.order, 130); + expect(CredentialCategory.blockchainAccountsCards.order, 70); + expect(CredentialCategory.educationCards.order, 120); + expect(CredentialCategory.othersCards.order, 10); + expect(CredentialCategory.financeCards.order, 110); + expect(CredentialCategory.humanityProofCards.order, 100); + expect(CredentialCategory.socialMediaCards.order, 90); + expect(CredentialCategory.walletIntegrity.order, 80); + expect(CredentialCategory.polygonidCards.order, 75); + expect(CredentialCategory.pendingCards.order, 9); + }); + + test('showInHomeIfListEmpty should return correct value for each category', + () { + expect(CredentialCategory.identityCards.showInHomeIfListEmpty, true); + expect(CredentialCategory.professionalCards.showInHomeIfListEmpty, false); + expect(CredentialCategory.advantagesCards.showInHomeIfListEmpty, false); + expect(CredentialCategory.contactInfoCredentials.showInHomeIfListEmpty, + false); + expect(CredentialCategory.blockchainAccountsCards.showInHomeIfListEmpty, + false); + expect(CredentialCategory.educationCards.showInHomeIfListEmpty, false); + expect(CredentialCategory.othersCards.showInHomeIfListEmpty, false); + expect(CredentialCategory.financeCards.showInHomeIfListEmpty, false); + expect( + CredentialCategory.humanityProofCards.showInHomeIfListEmpty, false); + expect(CredentialCategory.socialMediaCards.showInHomeIfListEmpty, false); + expect(CredentialCategory.walletIntegrity.showInHomeIfListEmpty, false); + expect(CredentialCategory.polygonidCards.showInHomeIfListEmpty, false); + expect(CredentialCategory.pendingCards.showInHomeIfListEmpty, false); + }); + + test('config should return correct configuration for each category', () { + final localizations = MockAppLocalizations(); + + expect( + CredentialCategory.advantagesCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'My a1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.identityCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'My a1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.professionalCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'My a1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A3', + ), + ); + expect( + CredentialCategory.contactInfoCredentials.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'My a1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.blockchainAccountsCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'My a1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.educationCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'My a1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.othersCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'My a1', + homeSubTitle: 'A2', + discoverTitle: 'Get a1', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.financeCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'A1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.humanityProofCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'A1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.socialMediaCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'A1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.walletIntegrity.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'A1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.polygonidCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'A1', + homeSubTitle: 'A2', + discoverTitle: 'A3', + discoverSubTitle: 'A4', + ), + ); + expect( + CredentialCategory.pendingCards.config(localizations), + const CredentialCategoryConfig( + homeTitle: 'A1', + homeSubTitle: 'A2', + discoverTitle: '', + discoverSubTitle: '', + ), + ); + }); + }); +} diff --git a/test/app/shared/enum/polygon_id_network_test.dart b/test/app/shared/enum/polygon_id_network_test.dart new file mode 100644 index 000000000..54f309b20 --- /dev/null +++ b/test/app/shared/enum/polygon_id_network_test.dart @@ -0,0 +1,22 @@ +import 'package:altme/app/app.dart'; +import 'package:test/test.dart'; + +void main() { + group('PolygonIdNetwork Extension Tests', () { + test('name should return correct network name', () { + expect(PolygonIdNetwork.PolygonMainnet.name, 'Polygon Main'); + expect(PolygonIdNetwork.PolygonMumbai.name, 'Polygon Mumbai'); + }); + + test('tester should return correct tester string', () { + expect(PolygonIdNetwork.PolygonMainnet.tester, 'polygon:main'); + expect(PolygonIdNetwork.PolygonMumbai.tester, 'polygon:mumbai'); + }); + + test('oppositeNetwork should return correct opposite network', () { + expect( + PolygonIdNetwork.PolygonMainnet.oppositeNetwork, 'mumbai(testnet)'); + expect(PolygonIdNetwork.PolygonMumbai.oppositeNetwork, 'mainnet'); + }); + }); +} diff --git a/test/app/shared/enum/status/mnemonic_status_test.dart b/test/app/shared/enum/status/mnemonic_status_test.dart new file mode 100644 index 000000000..61c489ac7 --- /dev/null +++ b/test/app/shared/enum/status/mnemonic_status_test.dart @@ -0,0 +1,19 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('MnemonicStatus Extension Test', () { + test('showOrder should return correct value for each status', () { + expect(MnemonicStatus.unselected.showOrder, false); + expect(MnemonicStatus.selected.showOrder, true); + expect(MnemonicStatus.wrongSelection.showOrder, false); + }); + + test('color should return correct color for each status', () { + expect(MnemonicStatus.unselected.color, const Color(0xff86809D)); + expect(MnemonicStatus.selected.color, const Color(0xff6600FF)); + expect(MnemonicStatus.wrongSelection.color, const Color(0xffFF0045)); + }); + }); +} From 8fedb6a5f9f2dbcb5e439fde062863c4e50c6712 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 13 May 2024 19:04:27 +0545 Subject: [PATCH 45/56] Add some tests --- .../helper_functions/helper_functions.dart | 20 +- packages/oidc4vc/test/src/oidc4vc_test.dart | 2 - .../token_parameters_test.dart | 4 - ...redential_subject_type_extension_test.dart | 952 +++++++++++++++ .../credential_status_extension_test.dart | 19 + .../shared/enum/status/mnemonic_status.dart | 30 + .../enum/status/mnemonic_status_test.dart | 19 - .../enum/type/blockchain_type_test.dart | 153 +++ .../shared/enum/type/kyc_vc_type_test.dart | 18 + .../shared/enum/type/language_type_test.dart | 35 + .../shared/enum/type/oidc4vc_type_test.dart | 15 + .../enum/type/profile/did_key_type_test.dart | 24 + .../enum/type/profile/profile_type_test.dart | 15 + .../enum/type/wallet_provider_type_test.dart | 16 + .../helper_functions_test.dart | 1053 +++++++++++++++++ 15 files changed, 2343 insertions(+), 32 deletions(-) create mode 100644 test/app/shared/enum/credential_subject_type/credential_subject_type_extension_test.dart create mode 100644 test/app/shared/enum/status/credential_status_extension_test.dart create mode 100644 test/app/shared/enum/status/mnemonic_status.dart delete mode 100644 test/app/shared/enum/status/mnemonic_status_test.dart create mode 100644 test/app/shared/enum/type/blockchain_type_test.dart create mode 100644 test/app/shared/enum/type/kyc_vc_type_test.dart create mode 100644 test/app/shared/enum/type/language_type_test.dart create mode 100644 test/app/shared/enum/type/oidc4vc_type_test.dart create mode 100644 test/app/shared/enum/type/profile/did_key_type_test.dart create mode 100644 test/app/shared/enum/type/profile/profile_type_test.dart create mode 100644 test/app/shared/enum/type/wallet_provider_type_test.dart create mode 100644 test/app/shared/helper_functions/helper_functions_test.dart diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index 5956296a0..dde510ab0 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -75,11 +75,15 @@ KeyStoreModel getKeysFromSecretKey({required String secretKey}) { ); } -String stringToHexPrefixedWith05({required String payload}) { +String stringToHexPrefixedWith05({ + required String payload, + DateTime? dateTime, +}) { + dateTime ??= DateTime.now(); final String formattedInput = [ 'Tezos Signed Message:', 'altme.io', - DateTime.now().toString(), + dateTime.toString(), payload, ].join(' '); @@ -238,11 +242,13 @@ Future getStoragePermission() async { return false; } -String getDateTimeWithoutSpace() { - final dateTime = DateTime.fromMicrosecondsSinceEpoch( - DateTime.now().microsecondsSinceEpoch, +String getDateTimeWithoutSpace({DateTime? dateTime}) { + dateTime ??= DateTime.now(); + + final dateTimeString = DateTime.fromMicrosecondsSinceEpoch( + dateTime.microsecondsSinceEpoch, ).toString().replaceAll(' ', '-'); - return dateTime; + return dateTimeString; } int getIndexValue({ @@ -1177,7 +1183,7 @@ MessageHandler getMessageHandler(dynamic e) { 'error_description': 'Failed to extract header from jwt.', }, ); - } else if (stringException.contains('INVALID_TOKEN')) { + } else if (stringException.contains('INVALID_PAYLOAD')) { return ResponseMessage( data: { 'error': 'invalid_format', diff --git a/packages/oidc4vc/test/src/oidc4vc_test.dart b/packages/oidc4vc/test/src/oidc4vc_test.dart index 04413c91c..42ddd0db3 100644 --- a/packages/oidc4vc/test/src/oidc4vc_test.dart +++ b/packages/oidc4vc/test/src/oidc4vc_test.dart @@ -15,8 +15,6 @@ import 'package:http_mock_adapter/http_mock_adapter.dart'; import 'package:mocktail/mocktail.dart'; import 'package:oidc4vc/oidc4vc.dart'; -class MockDio extends Mock implements Dio {} - class MockPkcePair extends Mock implements PkcePair {} void main() { diff --git a/packages/oidc4vc/test/src/token_parameters/token_parameters_test.dart b/packages/oidc4vc/test/src/token_parameters/token_parameters_test.dart index 754426c9a..ebb4006fc 100644 --- a/packages/oidc4vc/test/src/token_parameters/token_parameters_test.dart +++ b/packages/oidc4vc/test/src/token_parameters/token_parameters_test.dart @@ -9,15 +9,11 @@ // ignore_for_file: lines_longer_than_80_chars -import 'package:dio/dio.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; import 'package:oidc4vc/oidc4vc.dart'; import 'token_parameters_class.dart'; -class MockDio extends Mock implements Dio {} - void main() { group('TokenParameters', () { final tokenParametersTest = TokenParameterTest(); diff --git a/test/app/shared/enum/credential_subject_type/credential_subject_type_extension_test.dart b/test/app/shared/enum/credential_subject_type/credential_subject_type_extension_test.dart new file mode 100644 index 000000000..df2f5615d --- /dev/null +++ b/test/app/shared/enum/credential_subject_type/credential_subject_type_extension_test.dart @@ -0,0 +1,952 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:flutter/material.dart'; +import 'package:oidc4vc/oidc4vc.dart'; +import 'package:test/test.dart'; + +void main() { + group('CredentialSubjectType Extension Tests', () { + test('CredentialSubjectType backgroundColor returns correct value', () { + final credentialModel = CredentialModel( + id: '', + credentialPreview: Credential.dummy(), + data: const {}, + image: '', + shareLink: '', + display: const Display(backgroundColor: '#FFFFFF'), + ); + final credentialModel2 = CredentialModel( + id: '', + credentialPreview: Credential.dummy(), + data: const {}, + image: '', + shareLink: '', + ); + + for (final value in CredentialSubjectType.values) { + expect(value.backgroundColor(credentialModel), + equals(const Color(0xFFFFFFFF))); + expect(value.backgroundColor(credentialModel2), + equals(value.defaultBackgroundColor)); + } + }); + + test('CredentialSubjectType defaultBackgroundColor returns correct value', + () { + expect( + CredentialSubjectType.defiCompliance.defaultBackgroundColor, + equals(const Color.fromARGB(255, 62, 15, 163)), + ); + + expect( + CredentialSubjectType.identityPass.defaultBackgroundColor, + equals(const Color(0xffCAFFBF)), + ); + + expect( + CredentialSubjectType + .professionalExperienceAssessment.defaultBackgroundColor, + equals(const Color(0xFFFFADAD)), + ); + + expect( + CredentialSubjectType + .professionalSkillAssessment.defaultBackgroundColor, + equals(const Color(0xffCAFFBF)), + ); + + expect( + CredentialSubjectType.residentCard.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.selfIssued.defaultBackgroundColor, + equals(const Color(0xffEFF0F6)), + ); + + expect( + CredentialSubjectType.defaultCredential.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.professionalStudentCard.defaultBackgroundColor, + equals(const Color(0xffCAFFBF)), + ); + + expect( + CredentialSubjectType.kycAgeCredential.defaultBackgroundColor, + equals(const Color(0xff8247E5)), + ); + + expect( + CredentialSubjectType.kycCountryOfResidence.defaultBackgroundColor, + equals(const Color(0xff8247E5)), + ); + + expect( + CredentialSubjectType.walletCredential.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.livenessCard.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.nationality.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.tezotopiaMembership.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.chainbornMembership.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.twitterCard.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.gender.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.tezosAssociatedWallet.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.verifiableIdCard.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.linkedInCard.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.over13.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.over15.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.over18.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.over21.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.over50.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.over65.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.passportFootprint.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.certificateOfEmployment.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.emailPass.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.ageRange.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.phonePass.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.learningAchievement.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.studentCard.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.voucher.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.tezVoucher.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.diplomaCard.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.aragoPass.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.aragoIdentityCard.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.aragoLearningAchievement.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.aragoEmailPass.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.aragoOver18.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.ethereumAssociatedWallet.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.fantomAssociatedWallet.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.polygonAssociatedWallet.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.binanceAssociatedWallet.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.ethereumPooAddress.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.fantomPooAddress.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.polygonPooAddress.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.binancePooAddress.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.tezosPooAddress.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.pcdsAgentCertificate.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.euDiplomaCard.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.euVerifiableId.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.proofOfTwitterStats.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.civicPassCredential.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.employeeCredential.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.legalPersonalCredential.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.identityCredential.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.eudiPid.defaultBackgroundColor, + equals(Colors.white), + ); + + expect( + CredentialSubjectType.pid.defaultBackgroundColor, + equals(Colors.white), + ); + }); + + test('CredentialSubjectType name returns correct value', () { + expect( + CredentialSubjectType.defiCompliance.name, equals('DefiCompliance')); + expect(CredentialSubjectType.livenessCard.name, equals('Liveness')); + expect(CredentialSubjectType.tezotopiaMembership.name, + equals('MembershipCard_1')); + expect(CredentialSubjectType.chainbornMembership.name, + equals('Chainborn_MembershipCard')); + expect(CredentialSubjectType.twitterCard.name, + equals('TwitterAccountProof')); + expect(CredentialSubjectType.ageRange.name, equals('AgeRange')); + expect(CredentialSubjectType.nationality.name, equals('Nationality')); + expect(CredentialSubjectType.gender.name, equals('Gender')); + expect(CredentialSubjectType.walletCredential.name, + equals('WalletCredential')); + expect(CredentialSubjectType.tezosAssociatedWallet.name, + equals('TezosAssociatedAddress')); + expect(CredentialSubjectType.ethereumAssociatedWallet.name, + equals('EthereumAssociatedAddress')); + expect(CredentialSubjectType.fantomAssociatedWallet.name, + equals('FantomAssociatedAddress')); + expect(CredentialSubjectType.polygonAssociatedWallet.name, + equals('PolygonAssociatedAddress')); + expect(CredentialSubjectType.binanceAssociatedWallet.name, + equals('BinanceAssociatedAddress')); + expect(CredentialSubjectType.ethereumPooAddress.name, + equals('EthereumPooAddress')); + expect(CredentialSubjectType.fantomPooAddress.name, + equals('FantomPooAddress')); + expect(CredentialSubjectType.polygonPooAddress.name, + equals('PolygonPooAddress')); + expect(CredentialSubjectType.binancePooAddress.name, + equals('BinancePooAddress')); + expect(CredentialSubjectType.tezosPooAddress.name, + equals('TezosPooAddress')); + expect(CredentialSubjectType.certificateOfEmployment.name, + equals('CertificateOfEmployment')); + expect(CredentialSubjectType.emailPass.name, equals('EmailPass')); + expect(CredentialSubjectType.identityPass.name, equals('IdentityPass')); + expect( + CredentialSubjectType.verifiableIdCard.name, equals('VerifiableId')); + expect(CredentialSubjectType.linkedInCard.name, equals('LinkedinCard')); + expect(CredentialSubjectType.learningAchievement.name, + equals('LearningAchievement')); + expect(CredentialSubjectType.over13.name, equals('Over13')); + expect(CredentialSubjectType.over15.name, equals('Over15')); + expect(CredentialSubjectType.over18.name, equals('Over18')); + expect(CredentialSubjectType.over21.name, equals('Over21')); + expect(CredentialSubjectType.over50.name, equals('Over50')); + expect(CredentialSubjectType.over65.name, equals('Over65')); + expect(CredentialSubjectType.passportFootprint.name, + equals('PassportNumber')); + expect(CredentialSubjectType.phonePass.name, equals('PhoneProof')); + expect(CredentialSubjectType.professionalExperienceAssessment.name, + equals('ProfessionalExperienceAssessment')); + expect(CredentialSubjectType.professionalSkillAssessment.name, + equals('ProfessionalSkillAssessment')); + expect(CredentialSubjectType.professionalStudentCard.name, + equals('ProfessionalStudentCard')); + expect(CredentialSubjectType.residentCard.name, equals('ResidentCard')); + expect(CredentialSubjectType.employeeCredential.name, + equals('EmployeeCredential')); + expect(CredentialSubjectType.legalPersonalCredential.name, + equals('LegalPersonCredential')); + expect(CredentialSubjectType.selfIssued.name, equals('SelfIssued')); + expect(CredentialSubjectType.studentCard.name, equals('StudentCard')); + expect(CredentialSubjectType.voucher.name, equals('Voucher')); + expect(CredentialSubjectType.tezVoucher.name, equals('TezVoucher_1')); + expect( + CredentialSubjectType.diplomaCard.name, equals('VerifiableDiploma')); + expect(CredentialSubjectType.aragoPass.name, equals('AragoPass')); + expect( + CredentialSubjectType.aragoEmailPass.name, equals('AragoEmailPass')); + expect( + CredentialSubjectType.aragoIdentityCard.name, equals('AragoIdCard')); + expect(CredentialSubjectType.aragoLearningAchievement.name, + equals('AragoLearningAchievement')); + expect(CredentialSubjectType.aragoOver18.name, equals('AragoOver18')); + expect(CredentialSubjectType.pcdsAgentCertificate.name, + equals('PCDSAgentCertificate')); + expect( + CredentialSubjectType.euDiplomaCard.name, + equals( + 'https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xbf78fc08a7a9f28f5479f58dea269d3657f54f13ca37d380cd4e92237fb691dd')); + expect( + CredentialSubjectType.euVerifiableId.name, + equals( + 'https://api-conformance.ebsi.eu/trusted-schemas-registry/v2/schemas/z22ZAMdQtNLwi51T2vdZXGGZaYyjrsuP1yzWyXZirCAHv')); + expect(CredentialSubjectType.kycAgeCredential.name, + equals('KYCAgeCredential')); + expect(CredentialSubjectType.kycCountryOfResidence.name, + equals('KYCCountryOfResidenceCredential')); + expect(CredentialSubjectType.proofOfTwitterStats.name, + equals('ProofOfTwitterStats')); + expect(CredentialSubjectType.civicPassCredential.name, + equals('CivicPassCredential')); + expect(CredentialSubjectType.identityCredential.name, + equals('IdentityCredential')); + expect(CredentialSubjectType.eudiPid.name, equals('EudiPid')); + expect(CredentialSubjectType.pid.name, equals('Pid')); + expect(CredentialSubjectType.defaultCredential.name, equals('')); + }); + + test('CredentialSubjectType checkForAIKYC returns correct value', () { + for (final value in CredentialSubjectType.values) { + if (value == CredentialSubjectType.over18 || + value == CredentialSubjectType.over13 || + value == CredentialSubjectType.over15 || + value == CredentialSubjectType.over21 || + value == CredentialSubjectType.over50 || + value == CredentialSubjectType.over65 || + value == CredentialSubjectType.ageRange || + value == CredentialSubjectType.defiCompliance || + value == CredentialSubjectType.livenessCard) { + expect(value.checkForAIKYC, isTrue); + } else { + expect(value.checkForAIKYC, isFalse); + } + } + }); + + test('CredentialSubjectType getKycVcType returns correct value', () { + for (final value in CredentialSubjectType.values) { + if (value == CredentialSubjectType.over18) { + expect(value.getKycVcType, equals(KycVcType.over18)); + } else if (value == CredentialSubjectType.over13) { + expect(value.getKycVcType, equals(KycVcType.over13)); + } else if (value == CredentialSubjectType.over15) { + expect(value.getKycVcType, equals(KycVcType.over15)); + } else if (value == CredentialSubjectType.over21) { + expect(value.getKycVcType, equals(KycVcType.over21)); + } else if (value == CredentialSubjectType.over50) { + expect(value.getKycVcType, equals(KycVcType.over50)); + } else if (value == CredentialSubjectType.over65) { + expect(value.getKycVcType, equals(KycVcType.over65)); + } else if (value == CredentialSubjectType.ageRange) { + expect(value.getKycVcType, equals(KycVcType.ageRange)); + } else if (value == CredentialSubjectType.defiCompliance) { + expect(value.getKycVcType, equals(KycVcType.defiCompliance)); + } else { + expect(value.getKycVcType, equals(KycVcType.verifiableId)); + } + } + }); + + test('CredentialSubjectType aiValidationUrl returns correct value', () { + for (final value in CredentialSubjectType.values) { + if (value == CredentialSubjectType.over13) { + expect(value.aiValidationUrl, equals(Urls.over13AIValidationUrl)); + } else if (value == CredentialSubjectType.over15) { + expect(value.aiValidationUrl, equals(Urls.over15AIValidationUrl)); + } else if (value == CredentialSubjectType.over18) { + expect(value.aiValidationUrl, equals(Urls.over18AIValidationUrl)); + } else if (value == CredentialSubjectType.over21) { + expect(value.aiValidationUrl, equals(Urls.over21AIValidationUrl)); + } else if (value == CredentialSubjectType.over50) { + expect(value.aiValidationUrl, equals(Urls.over50AIValidationUrl)); + } else if (value == CredentialSubjectType.over65) { + expect(value.aiValidationUrl, equals(Urls.over65AIValidationUrl)); + } else if (value == CredentialSubjectType.ageRange) { + expect(value.aiValidationUrl, equals(Urls.ageRangeAIValidationUrl)); + } else { + expect( + () => CredentialSubjectType.defaultCredential.aiValidationUrl, + throwsA( + predicate( + (e) => + e is ResponseMessage && + e.data['error'] == 'invalid_request', + ), + ), + ); + } + } + }); + + test('CredentialSubjectType byPassDeepLink returns correct value', () { + for (final value in CredentialSubjectType.values) { + if (value == CredentialSubjectType.tezotopiaMembership || + value == CredentialSubjectType.chainbornMembership || + value == CredentialSubjectType.twitterCard || + value == CredentialSubjectType.over13 || + value == CredentialSubjectType.over15 || + value == CredentialSubjectType.over18 || + value == CredentialSubjectType.over21 || + value == CredentialSubjectType.over50 || + value == CredentialSubjectType.over65 || + value == CredentialSubjectType.verifiableIdCard || + value == CredentialSubjectType.ageRange || + value == CredentialSubjectType.nationality || + value == CredentialSubjectType.gender || + value == CredentialSubjectType.passportFootprint || + value == CredentialSubjectType.linkedInCard) { + expect(value.byPassDeepLink, isTrue); + } else { + expect(value.byPassDeepLink, isFalse); + } + } + }); + + test('CredentialSubjectType isEbsiCard returns correct value', () { + for (final value in CredentialSubjectType.values) { + if (value == CredentialSubjectType.euDiplomaCard || + value == CredentialSubjectType.euVerifiableId) { + expect(value.isEbsiCard, isTrue); + } else { + expect(value.isEbsiCard, isFalse); + } + } + }); + + test('CredentialSubjectType isBlockchainAccount returns correct value', () { + for (final value in CredentialSubjectType.values) { + if (value == CredentialSubjectType.tezosAssociatedWallet || + value == CredentialSubjectType.ethereumAssociatedWallet || + value == CredentialSubjectType.binanceAssociatedWallet || + value == CredentialSubjectType.fantomAssociatedWallet || + value == CredentialSubjectType.polygonAssociatedWallet) { + expect(value.isBlockchainAccount, isTrue); + } else { + expect(value.isBlockchainAccount, isFalse); + } + } + }); + + test('CredentialSubjectType blockchainWidget returns correct value', () { + for (final value in CredentialSubjectType.values) { + if (value == CredentialSubjectType.tezosAssociatedWallet) { + expect(value.blockchainWidget, isA()); + } else if (value == CredentialSubjectType.ethereumAssociatedWallet) { + expect( + value.blockchainWidget, isA()); + } else if (value == CredentialSubjectType.polygonAssociatedWallet) { + expect(value.blockchainWidget, isA()); + } else if (value == CredentialSubjectType.binanceAssociatedWallet) { + expect(value.blockchainWidget, isA()); + } else if (value == CredentialSubjectType.fantomAssociatedWallet) { + expect(value.blockchainWidget, isA()); + } else { + expect(value.blockchainWidget, isNull); + } + } + }); + + test('CredentialSubjectType title returns correct value', () { + expect(CredentialSubjectType.defiCompliance.title, 'Defi Compliance'); + expect(CredentialSubjectType.livenessCard.title, 'Liveness'); + expect( + CredentialSubjectType.tezotopiaMembership.title, 'Membership Card'); + expect(CredentialSubjectType.chainbornMembership.title, 'Chainborn'); + expect(CredentialSubjectType.twitterCard.title, 'Twitter Account Proof'); + expect(CredentialSubjectType.ageRange.title, 'Age Range'); + expect(CredentialSubjectType.nationality.title, 'Nationality'); + expect(CredentialSubjectType.gender.title, 'Gender'); + expect(CredentialSubjectType.walletCredential.title, 'Wallet Credential'); + expect(CredentialSubjectType.tezosAssociatedWallet.title, + 'Tezos Associated Address'); + expect(CredentialSubjectType.ethereumAssociatedWallet.title, + 'Ethereum Associated Address'); + expect(CredentialSubjectType.fantomAssociatedWallet.title, + 'Fantom Associated Address'); + expect(CredentialSubjectType.polygonAssociatedWallet.title, + 'Polygon Associated Address'); + expect(CredentialSubjectType.binanceAssociatedWallet.title, + 'BNB Chain Associated Address'); + expect(CredentialSubjectType.ethereumPooAddress.title, + 'Ethereum Poo Address'); + expect( + CredentialSubjectType.fantomPooAddress.title, 'Fantom Poo Address'); + expect( + CredentialSubjectType.polygonPooAddress.title, 'Polygon Poo Address'); + expect(CredentialSubjectType.binancePooAddress.title, + 'BNB Chain Poo Address'); + expect(CredentialSubjectType.tezosPooAddress.title, 'Tezos Poo Address'); + expect(CredentialSubjectType.certificateOfEmployment.title, + 'Certificate of Employment'); + expect(CredentialSubjectType.emailPass.title, 'Email Pass'); + expect(CredentialSubjectType.identityPass.title, 'Identity Pass'); + expect(CredentialSubjectType.verifiableIdCard.title, 'VerifiableId'); + expect(CredentialSubjectType.linkedInCard.title, 'Linkedin Card'); + expect(CredentialSubjectType.learningAchievement.title, + 'Learning Achievement'); + expect(CredentialSubjectType.over13.title, 'Over13'); + expect(CredentialSubjectType.over15.title, 'Over15'); + expect(CredentialSubjectType.over18.title, 'Over18'); + expect(CredentialSubjectType.over21.title, 'Over18'); + expect(CredentialSubjectType.over50.title, 'Over18'); + expect(CredentialSubjectType.over65.title, 'Over18'); + expect(CredentialSubjectType.passportFootprint.title, 'Passport Number'); + expect(CredentialSubjectType.phonePass.title, 'Phone Proof'); + expect(CredentialSubjectType.professionalExperienceAssessment.title, + 'Professional Experience Assessment'); + expect(CredentialSubjectType.professionalSkillAssessment.title, + 'Professional Skill Assessment'); + expect(CredentialSubjectType.professionalStudentCard.title, + 'Professional Student Card'); + expect(CredentialSubjectType.residentCard.title, 'Resident Card'); + expect(CredentialSubjectType.selfIssued.title, 'Self Issued'); + expect(CredentialSubjectType.studentCard.title, 'Student Card'); + expect(CredentialSubjectType.voucher.title, 'Voucher'); + expect(CredentialSubjectType.tezVoucher.title, 'TezVoucher'); + expect(CredentialSubjectType.diplomaCard.title, 'Verifiable Diploma'); + expect(CredentialSubjectType.aragoPass.title, 'Arago Pass'); + expect(CredentialSubjectType.aragoEmailPass.title, 'Arago Email Pass'); + expect(CredentialSubjectType.aragoIdentityCard.title, 'Arago Id Card'); + expect(CredentialSubjectType.aragoLearningAchievement.title, + 'Arago Learning Achievement'); + expect(CredentialSubjectType.aragoOver18.title, 'Arago Over18'); + expect(CredentialSubjectType.pcdsAgentCertificate.title, + 'PCDS Agent Certificate'); + expect(CredentialSubjectType.euDiplomaCard.title, 'EU Diploma'); + expect(CredentialSubjectType.euVerifiableId.title, 'EU VerifiableID'); + expect( + CredentialSubjectType.kycAgeCredential.title, 'KYC Age Credential'); + expect(CredentialSubjectType.kycCountryOfResidence.title, + 'KYC Country of Residence'); + expect(CredentialSubjectType.proofOfTwitterStats.title, + 'Proof Of Twitter Stats'); + expect(CredentialSubjectType.civicPassCredential.title, + 'Civic Pass Credential'); + expect(CredentialSubjectType.employeeCredential.title, + 'Employee Credential'); + expect(CredentialSubjectType.legalPersonalCredential.title, + 'Legal Person Credential'); + expect(CredentialSubjectType.identityCredential.title, + 'Identity Credential'); + expect(CredentialSubjectType.eudiPid.title, 'EudiPid'); + expect(CredentialSubjectType.pid.title, 'Pid'); + expect(CredentialSubjectType.defaultCredential.title, ''); + }); + + test('CredentialSubjectType supportSingleOnly returns correct value', () { + expect(CredentialSubjectType.defiCompliance.supportSingleOnly, true); + expect(CredentialSubjectType.livenessCard.supportSingleOnly, true); + expect(CredentialSubjectType.tezotopiaMembership.supportSingleOnly, true); + expect(CredentialSubjectType.chainbornMembership.supportSingleOnly, true); + expect(CredentialSubjectType.ageRange.supportSingleOnly, true); + expect(CredentialSubjectType.nationality.supportSingleOnly, true); + expect(CredentialSubjectType.gender.supportSingleOnly, true); + expect(CredentialSubjectType.identityPass.supportSingleOnly, true); + expect(CredentialSubjectType.verifiableIdCard.supportSingleOnly, true); + expect(CredentialSubjectType.over13.supportSingleOnly, true); + expect(CredentialSubjectType.over15.supportSingleOnly, true); + expect(CredentialSubjectType.over18.supportSingleOnly, true); + expect(CredentialSubjectType.over21.supportSingleOnly, true); + expect(CredentialSubjectType.over50.supportSingleOnly, true); + expect(CredentialSubjectType.over65.supportSingleOnly, true); + expect(CredentialSubjectType.passportFootprint.supportSingleOnly, true); + expect(CredentialSubjectType.residentCard.supportSingleOnly, true); + expect(CredentialSubjectType.voucher.supportSingleOnly, true); + expect(CredentialSubjectType.tezVoucher.supportSingleOnly, true); + expect(CredentialSubjectType.diplomaCard.supportSingleOnly, true); + expect(CredentialSubjectType.twitterCard.supportSingleOnly, true); + expect( + CredentialSubjectType.tezosAssociatedWallet.supportSingleOnly, true); + expect(CredentialSubjectType.ethereumAssociatedWallet.supportSingleOnly, + true); + expect( + CredentialSubjectType.fantomAssociatedWallet.supportSingleOnly, true); + expect(CredentialSubjectType.polygonAssociatedWallet.supportSingleOnly, + true); + expect(CredentialSubjectType.binanceAssociatedWallet.supportSingleOnly, + true); + + expect(CredentialSubjectType.walletCredential.supportSingleOnly, false); + expect(CredentialSubjectType.tezosPooAddress.supportSingleOnly, false); + expect(CredentialSubjectType.ethereumPooAddress.supportSingleOnly, false); + expect(CredentialSubjectType.fantomPooAddress.supportSingleOnly, false); + expect(CredentialSubjectType.polygonPooAddress.supportSingleOnly, false); + expect(CredentialSubjectType.binancePooAddress.supportSingleOnly, false); + expect(CredentialSubjectType.certificateOfEmployment.supportSingleOnly, + false); + expect(CredentialSubjectType.defaultCredential.supportSingleOnly, false); + expect(CredentialSubjectType.emailPass.supportSingleOnly, false); + expect(CredentialSubjectType.linkedInCard.supportSingleOnly, false); + expect( + CredentialSubjectType.learningAchievement.supportSingleOnly, false); + expect(CredentialSubjectType.phonePass.supportSingleOnly, false); + expect( + CredentialSubjectType + .professionalExperienceAssessment.supportSingleOnly, + false); + expect( + CredentialSubjectType.professionalSkillAssessment.supportSingleOnly, + false); + expect(CredentialSubjectType.professionalStudentCard.supportSingleOnly, + false); + expect(CredentialSubjectType.selfIssued.supportSingleOnly, false); + expect(CredentialSubjectType.studentCard.supportSingleOnly, false); + expect(CredentialSubjectType.aragoPass.supportSingleOnly, false); + expect(CredentialSubjectType.aragoEmailPass.supportSingleOnly, false); + expect(CredentialSubjectType.aragoIdentityCard.supportSingleOnly, false); + expect(CredentialSubjectType.aragoLearningAchievement.supportSingleOnly, + false); + expect(CredentialSubjectType.aragoOver18.supportSingleOnly, false); + expect( + CredentialSubjectType.pcdsAgentCertificate.supportSingleOnly, false); + expect(CredentialSubjectType.euDiplomaCard.supportSingleOnly, false); + expect(CredentialSubjectType.euVerifiableId.supportSingleOnly, false); + expect(CredentialSubjectType.kycAgeCredential.supportSingleOnly, false); + expect( + CredentialSubjectType.kycCountryOfResidence.supportSingleOnly, false); + expect( + CredentialSubjectType.proofOfTwitterStats.supportSingleOnly, false); + expect( + CredentialSubjectType.civicPassCredential.supportSingleOnly, false); + expect(CredentialSubjectType.employeeCredential.supportSingleOnly, false); + expect(CredentialSubjectType.legalPersonalCredential.supportSingleOnly, + false); + expect(CredentialSubjectType.identityCredential.supportSingleOnly, false); + expect(CredentialSubjectType.eudiPid.supportSingleOnly, false); + expect(CredentialSubjectType.pid.supportSingleOnly, false); + }); + + test('CredentialSubjectType getVCFormatType returns correct value', () { + expect(CredentialSubjectType.ethereumAssociatedWallet.getVCFormatType, + VCFormatType.values); + expect(CredentialSubjectType.fantomAssociatedWallet.getVCFormatType, + VCFormatType.values); + expect(CredentialSubjectType.polygonAssociatedWallet.getVCFormatType, + VCFormatType.values); + expect(CredentialSubjectType.binanceAssociatedWallet.getVCFormatType, + VCFormatType.values); + expect(CredentialSubjectType.tezosAssociatedWallet.getVCFormatType, + VCFormatType.values); + + expect( + CredentialSubjectType.over13.getVCFormatType, [VCFormatType.ldpVc]); + expect( + CredentialSubjectType.over15.getVCFormatType, [VCFormatType.ldpVc]); + expect( + CredentialSubjectType.over21.getVCFormatType, [VCFormatType.ldpVc]); + expect( + CredentialSubjectType.over50.getVCFormatType, [VCFormatType.ldpVc]); + expect( + CredentialSubjectType.over65.getVCFormatType, [VCFormatType.ldpVc]); + expect( + CredentialSubjectType.gender.getVCFormatType, [VCFormatType.ldpVc]); + expect( + CredentialSubjectType.ageRange.getVCFormatType, [VCFormatType.ldpVc]); + expect(CredentialSubjectType.defiCompliance.getVCFormatType, + [VCFormatType.ldpVc]); + expect(CredentialSubjectType.tezotopiaMembership.getVCFormatType, + [VCFormatType.ldpVc]); + expect(CredentialSubjectType.chainbornMembership.getVCFormatType, + [VCFormatType.ldpVc]); + + expect(CredentialSubjectType.verifiableIdCard.getVCFormatType, [ + VCFormatType.ldpVc, + VCFormatType.jwtVcJson, + VCFormatType.vcSdJWT, + VCFormatType.jwtVc, + ]); + + expect(CredentialSubjectType.identityCredential.getVCFormatType, + [VCFormatType.vcSdJWT]); + expect(CredentialSubjectType.eudiPid.getVCFormatType, + [VCFormatType.vcSdJWT]); + expect(CredentialSubjectType.pid.getVCFormatType, [VCFormatType.vcSdJWT]); + + expect(CredentialSubjectType.over18.getVCFormatType, [ + VCFormatType.ldpVc, + VCFormatType.jwtVcJson, + ]); + + expect(CredentialSubjectType.phonePass.getVCFormatType, + [VCFormatType.ldpVc, VCFormatType.jwtVcJson]); + expect(CredentialSubjectType.livenessCard.getVCFormatType, + [VCFormatType.ldpVc, VCFormatType.jwtVcJson]); + expect(CredentialSubjectType.emailPass.getVCFormatType, + [VCFormatType.ldpVc, VCFormatType.jwtVcJson]); + + expect(CredentialSubjectType.nationality.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.identityPass.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.passportFootprint.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.residentCard.getVCFormatType, + [VCFormatType.jwtVc]); + expect( + CredentialSubjectType.voucher.getVCFormatType, [VCFormatType.jwtVc]); + expect(CredentialSubjectType.tezVoucher.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.diplomaCard.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.twitterCard.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.walletCredential.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.tezosPooAddress.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.ethereumPooAddress.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.fantomPooAddress.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.polygonPooAddress.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.binancePooAddress.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.certificateOfEmployment.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.defaultCredential.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.linkedInCard.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.learningAchievement.getVCFormatType, + [VCFormatType.jwtVc]); + expect( + CredentialSubjectType + .professionalExperienceAssessment.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.professionalSkillAssessment.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.professionalStudentCard.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.selfIssued.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.studentCard.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.aragoPass.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.aragoEmailPass.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.aragoIdentityCard.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.aragoLearningAchievement.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.aragoOver18.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.pcdsAgentCertificate.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.euDiplomaCard.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.euVerifiableId.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.kycAgeCredential.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.kycCountryOfResidence.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.proofOfTwitterStats.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.civicPassCredential.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.employeeCredential.getVCFormatType, + [VCFormatType.jwtVc]); + expect(CredentialSubjectType.legalPersonalCredential.getVCFormatType, + [VCFormatType.jwtVc]); + }); + + test('CredentialSubjectType order returns correct value', () { + expect(CredentialSubjectType.defiCompliance.order, 0); + expect(CredentialSubjectType.livenessCard.order, 75); + expect(CredentialSubjectType.tezotopiaMembership.order, 79); + expect(CredentialSubjectType.chainbornMembership.order, 72); + expect(CredentialSubjectType.ageRange.order, 94); + expect(CredentialSubjectType.nationality.order, 97.3); + expect(CredentialSubjectType.gender.order, 93); + expect(CredentialSubjectType.walletCredential.order, 0); + expect(CredentialSubjectType.tezosAssociatedWallet.order, 68); + expect(CredentialSubjectType.ethereumAssociatedWallet.order, 69); + expect(CredentialSubjectType.fantomAssociatedWallet.order, 67); + expect(CredentialSubjectType.polygonAssociatedWallet.order, 71); + expect(CredentialSubjectType.binanceAssociatedWallet.order, 70); + expect(CredentialSubjectType.tezosPooAddress.order, 0); + expect(CredentialSubjectType.ethereumPooAddress.order, 0); + expect(CredentialSubjectType.fantomPooAddress.order, 0); + expect(CredentialSubjectType.polygonPooAddress.order, 0); + expect(CredentialSubjectType.binancePooAddress.order, 0); + expect(CredentialSubjectType.certificateOfEmployment.order, 85); + expect(CredentialSubjectType.defaultCredential.order, 100); + expect(CredentialSubjectType.emailPass.order, 99); + expect(CredentialSubjectType.identityPass.order, 90); + expect(CredentialSubjectType.verifiableIdCard.order, 97.5); + expect(CredentialSubjectType.linkedInCard.order, 86); + expect(CredentialSubjectType.learningAchievement.order, 0); + expect(CredentialSubjectType.over13.order, 97.3); + expect(CredentialSubjectType.over15.order, 97.2); + expect(CredentialSubjectType.over18.order, 97.1); + expect(CredentialSubjectType.over21.order, 97); + expect(CredentialSubjectType.over50.order, 96); + expect(CredentialSubjectType.over65.order, 95); + expect(CredentialSubjectType.passportFootprint.order, 91); + expect(CredentialSubjectType.phonePass.order, 98); + expect(CredentialSubjectType.professionalExperienceAssessment.order, 0); + expect(CredentialSubjectType.professionalSkillAssessment.order, 0); + expect(CredentialSubjectType.professionalStudentCard.order, 87); + expect(CredentialSubjectType.residentCard.order, 0); + expect(CredentialSubjectType.selfIssued.order, 0); + expect(CredentialSubjectType.studentCard.order, 88); + expect(CredentialSubjectType.voucher.order, 81); + expect(CredentialSubjectType.tezVoucher.order, 80); + expect(CredentialSubjectType.diplomaCard.order, 89); + expect(CredentialSubjectType.aragoPass.order, 81); + expect(CredentialSubjectType.aragoEmailPass.order, 0); + expect(CredentialSubjectType.aragoIdentityCard.order, 0); + expect(CredentialSubjectType.aragoLearningAchievement.order, 0); + expect(CredentialSubjectType.aragoOver18.order, 0); + expect(CredentialSubjectType.pcdsAgentCertificate.order, 82); + expect(CredentialSubjectType.twitterCard.order, 83); + expect(CredentialSubjectType.euDiplomaCard.order, 67); + expect(CredentialSubjectType.euVerifiableId.order, 92); + expect(CredentialSubjectType.kycAgeCredential.order, 0); + expect(CredentialSubjectType.kycCountryOfResidence.order, 0); + expect(CredentialSubjectType.proofOfTwitterStats.order, 0); + expect(CredentialSubjectType.civicPassCredential.order, 0); + expect(CredentialSubjectType.employeeCredential.order, 0); + expect(CredentialSubjectType.legalPersonalCredential.order, 0); + expect(CredentialSubjectType.identityCredential.order, 0); + expect(CredentialSubjectType.eudiPid.order, 0); + expect(CredentialSubjectType.pid.order, 0); + }); + }); +} diff --git a/test/app/shared/enum/status/credential_status_extension_test.dart b/test/app/shared/enum/status/credential_status_extension_test.dart new file mode 100644 index 000000000..77fc84dd8 --- /dev/null +++ b/test/app/shared/enum/status/credential_status_extension_test.dart @@ -0,0 +1,19 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:test/test.dart'; + +void main() { + group('CredentialStatusExtension', () { + test('icon returns correct icon for each status', () { + expect(CredentialStatus.active.icon, Icons.check_circle); + expect(CredentialStatus.invalidStatus.icon, Icons.circle_outlined); + expect(CredentialStatus.expired.icon, Icons.circle_outlined); + expect(CredentialStatus.pending.icon, Icons.circle_outlined); + expect(CredentialStatus.unknown.icon, Icons.circle_outlined); + expect(CredentialStatus.invalidSignature.icon, Icons.circle_outlined); + expect(CredentialStatus.statusListInvalidSignature.icon, + Icons.circle_outlined); + expect(CredentialStatus.noStatus.icon, Icons.circle_outlined); + }); + }); +} diff --git a/test/app/shared/enum/status/mnemonic_status.dart b/test/app/shared/enum/status/mnemonic_status.dart new file mode 100644 index 000000000..47d3ae4a6 --- /dev/null +++ b/test/app/shared/enum/status/mnemonic_status.dart @@ -0,0 +1,30 @@ +import 'dart:ui'; + +enum MnemonicStatus { + unselected, + selected, + wrongSelection, +} + +extension MnemonicStatusX on MnemonicStatus { + bool get showOrder { + switch (this) { + case MnemonicStatus.unselected: + case MnemonicStatus.wrongSelection: + return false; + case MnemonicStatus.selected: + return true; + } + } + + Color get color { + switch (this) { + case MnemonicStatus.unselected: + return const Color(0xff86809D); + case MnemonicStatus.wrongSelection: + return const Color(0xffFF0045); + case MnemonicStatus.selected: + return const Color(0xff6600FF); + } + } +} diff --git a/test/app/shared/enum/status/mnemonic_status_test.dart b/test/app/shared/enum/status/mnemonic_status_test.dart deleted file mode 100644 index 61c489ac7..000000000 --- a/test/app/shared/enum/status/mnemonic_status_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:altme/app/app.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - group('MnemonicStatus Extension Test', () { - test('showOrder should return correct value for each status', () { - expect(MnemonicStatus.unselected.showOrder, false); - expect(MnemonicStatus.selected.showOrder, true); - expect(MnemonicStatus.wrongSelection.showOrder, false); - }); - - test('color should return correct color for each status', () { - expect(MnemonicStatus.unselected.color, const Color(0xff86809D)); - expect(MnemonicStatus.selected.color, const Color(0xff6600FF)); - expect(MnemonicStatus.wrongSelection.color, const Color(0xffFF0045)); - }); - }); -} diff --git a/test/app/shared/enum/type/blockchain_type_test.dart b/test/app/shared/enum/type/blockchain_type_test.dart new file mode 100644 index 000000000..8afe660a7 --- /dev/null +++ b/test/app/shared/enum/type/blockchain_type_test.dart @@ -0,0 +1,153 @@ +import 'dart:convert'; + +import 'package:altme/app/app.dart'; +import 'package:credential_manifest/credential_manifest.dart'; +import 'package:key_generator/key_generator.dart'; +import 'package:test/test.dart'; + +void main() { + group('BlockchainType Extension Tests', () { + test('BlockchainType icon returns correct value', () { + expect(BlockchainType.tezos.icon, equals(IconStrings.tezos)); + expect(BlockchainType.ethereum.icon, equals(IconStrings.ethereum)); + expect(BlockchainType.fantom.icon, equals(IconStrings.fantom)); + expect(BlockchainType.polygon.icon, equals(IconStrings.polygon)); + expect(BlockchainType.binance.icon, equals(IconStrings.binance)); + }); + + test('BlockchainType accountType returns correct value', () { + expect(BlockchainType.tezos.accountType, equals(AccountType.tezos)); + expect(BlockchainType.ethereum.accountType, equals(AccountType.ethereum)); + expect(BlockchainType.fantom.accountType, equals(AccountType.fantom)); + expect(BlockchainType.polygon.accountType, equals(AccountType.polygon)); + expect(BlockchainType.binance.accountType, equals(AccountType.binance)); + }); + + test('BlockchainType symbol returns correct value', () { + expect(BlockchainType.tezos.symbol, equals('XTZ')); + expect(BlockchainType.ethereum.symbol, equals('ETH')); + expect(BlockchainType.fantom.symbol, equals('FTM')); + expect(BlockchainType.polygon.symbol, equals('MATIC')); + expect(BlockchainType.binance.symbol, equals('BNB')); + }); + + test('BlockchainType chain returns correct value', () { + expect(() => BlockchainType.tezos.chain, throwsA(isA())); + expect( + BlockchainType.ethereum.chain, equals('${Parameters.NAMESPACE}:1')); + expect( + BlockchainType.fantom.chain, equals('${Parameters.NAMESPACE}:250')); + expect( + BlockchainType.polygon.chain, equals('${Parameters.NAMESPACE}:137')); + expect( + BlockchainType.binance.chain, equals('${Parameters.NAMESPACE}:56')); + }); + + test('BlockchainType chainId returns correct value', () { + expect( + () => BlockchainType.tezos.chainId, throwsA(isA())); + expect(BlockchainType.ethereum.chainId, equals(1)); + expect(BlockchainType.fantom.chainId, equals(250)); + expect(BlockchainType.polygon.chainId, equals(137)); + expect(BlockchainType.binance.chainId, equals(56)); + }); + + test('BlockchainType derivePathIndexKey returns correct value', () { + expect(BlockchainType.tezos.derivePathIndexKey, + equals(SecureStorageKeys.tezosDerivePathIndex)); + expect(BlockchainType.ethereum.derivePathIndexKey, + equals(SecureStorageKeys.ethereumDerivePathIndex)); + expect(BlockchainType.fantom.derivePathIndexKey, + equals(SecureStorageKeys.fantomDerivePathIndex)); + expect(BlockchainType.polygon.derivePathIndexKey, + equals(SecureStorageKeys.polygonDerivePathIndex)); + expect(BlockchainType.binance.derivePathIndexKey, + equals(SecureStorageKeys.binanceDerivePathIndex)); + }); + + test('BlockchainType credentialManifest returns correct value', () { + expect( + jsonEncode(BlockchainType.tezos.credentialManifest), + equals(jsonEncode(CredentialManifest.fromJson( + ConstantsJson.tezosAssociatedAddressCredentialManifestJson)))); + expect( + jsonEncode(BlockchainType.ethereum.credentialManifest), + equals(jsonEncode(CredentialManifest.fromJson( + ConstantsJson.ethereumAssociatedAddressCredentialManifestJson)))); + expect( + jsonEncode(BlockchainType.fantom.credentialManifest), + equals(jsonEncode(CredentialManifest.fromJson( + ConstantsJson.fantomAssociatedAddressCredentialManifestJson)))); + expect( + jsonEncode(BlockchainType.polygon.credentialManifest), + equals(jsonEncode(CredentialManifest.fromJson( + ConstantsJson.polygonAssociatedAddressCredentialManifestJson)))); + expect( + jsonEncode(BlockchainType.binance.credentialManifest), + equals(jsonEncode(CredentialManifest.fromJson( + ConstantsJson.binanceAssociatedAddressCredentialManifestJson)))); + }); + + test('BlockchainType filter returns correct value', () { + expect( + jsonEncode(BlockchainType.tezos.filter.toJson()), + equals(jsonEncode( + Filter(type: 'String', pattern: 'TezosAssociatedAddress') + .toJson()))); + expect( + jsonEncode(BlockchainType.ethereum.filter.toJson()), + equals(jsonEncode( + Filter(type: 'String', pattern: 'EthereumAssociatedAddress') + .toJson()))); + expect( + jsonEncode(BlockchainType.fantom.filter.toJson()), + equals(jsonEncode( + Filter(type: 'String', pattern: 'FantomAssociatedAddress') + .toJson()))); + expect( + jsonEncode(BlockchainType.polygon.filter.toJson()), + equals(jsonEncode( + Filter(type: 'String', pattern: 'PolygonAssociatedAddress') + .toJson()))); + expect( + jsonEncode(BlockchainType.binance.filter.toJson()), + equals(jsonEncode( + Filter(type: 'String', pattern: 'BinanceAssociatedAddress') + .toJson()))); + }); + + test('BlockchainType connectionBridge returns correct value', () { + expect(BlockchainType.tezos.connectionBridge, + equals(ConnectionBridgeType.beacon)); + expect(BlockchainType.ethereum.connectionBridge, + equals(ConnectionBridgeType.walletconnect)); + expect(BlockchainType.fantom.connectionBridge, + equals(ConnectionBridgeType.walletconnect)); + expect(BlockchainType.polygon.connectionBridge, + equals(ConnectionBridgeType.walletconnect)); + expect(BlockchainType.binance.connectionBridge, + equals(ConnectionBridgeType.walletconnect)); + }); + + test('BlockchainType networks returns correct value', () { + expect(BlockchainType.tezos.networks, + equals([TezosNetwork.mainNet(), TezosNetwork.ghostnet()])); + expect(BlockchainType.ethereum.networks, + equals([EthereumNetwork.mainNet(), EthereumNetwork.testNet()])); + expect(BlockchainType.fantom.networks, + equals([FantomNetwork.mainNet(), FantomNetwork.testNet()])); + expect(BlockchainType.polygon.networks, + equals([PolygonNetwork.mainNet(), PolygonNetwork.testNet()])); + expect(BlockchainType.binance.networks, + equals([BinanceNetwork.mainNet(), BinanceNetwork.testNet()])); + }); + + test('BlockchainType isDisabled returns correct value', () { + expect(BlockchainType.tezos.isDisabled, isFalse); + expect(BlockchainType.ethereum.isDisabled, isFalse); + expect(BlockchainType.fantom.isDisabled, isFalse); + expect(BlockchainType.polygon.isDisabled, isFalse); + expect(BlockchainType.binance.isDisabled, isFalse); + }); + }); +} diff --git a/test/app/shared/enum/type/kyc_vc_type_test.dart b/test/app/shared/enum/type/kyc_vc_type_test.dart new file mode 100644 index 000000000..53083c5bb --- /dev/null +++ b/test/app/shared/enum/type/kyc_vc_type_test.dart @@ -0,0 +1,18 @@ +import 'package:altme/app/app.dart'; +import 'package:test/test.dart'; + +void main() { + group('KycVcType Extension Tests', () { + test('KycVcType value returns correct value', () { + expect(KycVcType.verifiableId.value, equals('VerifiableId')); + expect(KycVcType.over13.value, equals('Over13')); + expect(KycVcType.over15.value, equals('Over15')); + expect(KycVcType.over18.value, equals('Over18')); + expect(KycVcType.over21.value, equals('Over21')); + expect(KycVcType.over50.value, equals('Over50')); + expect(KycVcType.over65.value, equals('Over65')); + expect(KycVcType.ageRange.value, equals('AgeRange')); + expect(KycVcType.defiCompliance.value, equals('DefiCompliance')); + }); + }); +} diff --git a/test/app/shared/enum/type/language_type_test.dart b/test/app/shared/enum/type/language_type_test.dart new file mode 100644 index 000000000..eaaa11216 --- /dev/null +++ b/test/app/shared/enum/type/language_type_test.dart @@ -0,0 +1,35 @@ +import 'package:altme/app/shared/enum/type/language_type.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +class MockAppLocalizations extends Mock implements AppLocalizations { + @override + String get phoneLanguage => 'Phone'; + + @override + String get catalan => 'Catalan'; + + @override + String get english => 'English'; + + @override + String get spanish => 'Spanish'; + + @override + String get french => 'French'; +} + +void main() { + group('LanguageType Extension Tests', () { + test('LanguageType getTitle returns correct value', () { + final l10n = MockAppLocalizations(); + expect( + LanguageType.phone.getTitle(l10n: l10n, name: ''), equals('Phone')); + expect(LanguageType.ca.getTitle(l10n: l10n, name: ''), equals('Catalan')); + expect(LanguageType.en.getTitle(l10n: l10n, name: ''), equals('English')); + expect(LanguageType.es.getTitle(l10n: l10n, name: ''), equals('Spanish')); + expect(LanguageType.fr.getTitle(l10n: l10n, name: ''), equals('French')); + }); + }); +} diff --git a/test/app/shared/enum/type/oidc4vc_type_test.dart b/test/app/shared/enum/type/oidc4vc_type_test.dart new file mode 100644 index 000000000..0cde1154c --- /dev/null +++ b/test/app/shared/enum/type/oidc4vc_type_test.dart @@ -0,0 +1,15 @@ +import 'package:altme/app/app.dart'; +import 'package:test/test.dart'; + +void main() { + group('OIDC4VCType Extension Tests', () { + test('OIDC4VCType isEnabled returns correct value', () { + expect(OIDC4VCType.DEFAULT.isEnabled, equals(true)); + expect(OIDC4VCType.GAIAX.isEnabled, equals(true)); + expect(OIDC4VCType.GREENCYPHER.isEnabled, equals(true)); + expect(OIDC4VCType.EBSIV3.isEnabled, equals(true)); + expect(OIDC4VCType.JWTVC.isEnabled, equals(false)); + expect(OIDC4VCType.HAIP.isEnabled, equals(true)); + }); + }); +} diff --git a/test/app/shared/enum/type/profile/did_key_type_test.dart b/test/app/shared/enum/type/profile/did_key_type_test.dart new file mode 100644 index 000000000..314a25fd1 --- /dev/null +++ b/test/app/shared/enum/type/profile/did_key_type_test.dart @@ -0,0 +1,24 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('DidKeyType Extension', () { + test('Formatted String', () { + expect(DidKeyType.edDSA.formattedString, 'did:key edDSA'); + expect(DidKeyType.secp256k1.formattedString, 'did:key secp256k1'); + expect(DidKeyType.p256.formattedString, 'did:key P-256'); + expect(DidKeyType.ebsiv3.formattedString, 'did:key EBSI-V3'); + expect(DidKeyType.jwkP256.formattedString, 'did:jwk P-256'); + expect(DidKeyType.jwtClientAttestation.formattedString, ''); + }); + + test('Support Crypto Credential', () { + expect(DidKeyType.edDSA.supportCryptoCredential, true); + expect(DidKeyType.secp256k1.supportCryptoCredential, true); + expect(DidKeyType.p256.supportCryptoCredential, true); + expect(DidKeyType.ebsiv3.supportCryptoCredential, false); + expect(DidKeyType.jwkP256.supportCryptoCredential, true); + expect(DidKeyType.jwtClientAttestation.supportCryptoCredential, true); + }); + }); +} diff --git a/test/app/shared/enum/type/profile/profile_type_test.dart b/test/app/shared/enum/type/profile/profile_type_test.dart new file mode 100644 index 000000000..08ba5c82d --- /dev/null +++ b/test/app/shared/enum/type/profile/profile_type_test.dart @@ -0,0 +1,15 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('ProfileType Extension', () { + test('Show Sponsered By', () { + expect(ProfileType.custom.showSponseredBy, false); + expect(ProfileType.ebsiV3.showSponseredBy, true); + expect(ProfileType.dutch.showSponseredBy, false); + expect(ProfileType.enterprise.showSponseredBy, true); + expect(ProfileType.owfBaselineProfile.showSponseredBy, true); + expect(ProfileType.defaultOne.showSponseredBy, false); + }); + }); +} diff --git a/test/app/shared/enum/type/wallet_provider_type_test.dart b/test/app/shared/enum/type/wallet_provider_type_test.dart new file mode 100644 index 000000000..a0ab74b83 --- /dev/null +++ b/test/app/shared/enum/type/wallet_provider_type_test.dart @@ -0,0 +1,16 @@ +import 'package:altme/app/app.dart'; +import 'package:test/test.dart'; + +void main() { + group('WalletProviderType Extension Tests', () { + test('WalletProviderType url returns correct value', () { + expect(WalletProviderType.Talao.url, equals(Urls.walletProvider)); + expect(WalletProviderType.Test.url, equals(Urls.walletTestProvider)); + }); + + test('WalletProviderType formattedString returns correct value', () { + expect(WalletProviderType.Talao.formattedString, equals('Talao')); + expect(WalletProviderType.Test.formattedString, equals('Test')); + }); + }); +} diff --git a/test/app/shared/helper_functions/helper_functions_test.dart b/test/app/shared/helper_functions/helper_functions_test.dart new file mode 100644 index 000000000..b2ed5fa68 --- /dev/null +++ b/test/app/shared/helper_functions/helper_functions_test.dart @@ -0,0 +1,1053 @@ +import 'dart:convert'; + +import 'package:altme/app/app.dart'; +import 'package:credential_manifest/credential_manifest.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:http_mock_adapter/http_mock_adapter.dart'; +import 'package:jwt_decode/jwt_decode.dart'; +import 'package:key_generator/key_generator.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:oidc4vc/oidc4vc.dart'; +import 'package:secure_storage/secure_storage.dart'; + +class MockSecureStorage extends Mock implements SecureStorageProvider {} + +void main() { + late SecureStorageProvider mockSecureStorage; + + final client = Dio(); + late DioAdapter dioAdapter; + late DioClient mockClient; + + setUp(() { + TestWidgetsFlutterBinding.ensureInitialized(); + mockSecureStorage = MockSecureStorage(); + + dioAdapter = + DioAdapter(dio: Dio(BaseOptions()), matcher: const UrlRequestMatcher()); + client.httpClientAdapter = dioAdapter; + mockClient = DioClient( + baseUrl: 'https://example.com/', + secureStorageProvider: mockSecureStorage, + dio: client, + ); + }); + + group('HelperFunctions', () { + group('generateDefaultAccountName', () { + test('Should generate default account name', () { + expect(generateDefaultAccountName(0, []), 'My account 1'); + expect(generateDefaultAccountName(1, []), 'My account 2'); + expect(generateDefaultAccountName(2, []), 'My account 3'); + }); + + test('Should generate unique default account name', () { + final accountNameList = ['My account 1', 'My account 2']; + expect(generateDefaultAccountName(0, accountNameList), 'My account 3'); + }); + + test('Should handle existing default account name', () { + final accountNameList = [ + 'My account 1', + 'My account 2', + 'My account 3' + ]; + expect(generateDefaultAccountName(0, accountNameList), 'My account 4'); + }); + }); + + group('Platform checks', () { + test('isAndroid should return true on Android platform', () { + expect(isAndroid, false); + }); + + test('isIOS should return true on iOS platform', () { + expect(isIOS, false); + }); + }); + + group('getIssuerDid', () { + test('Should return empty string if no issuer in URI', () { + final uri = Uri.parse('https://example.com'); + expect(getIssuerDid(uriToCheck: uri), ''); + }); + + test('Should return issuer DID if present in URI', () { + final uri = Uri.parse('https://example.com?issuer=did:example'); + expect(getIssuerDid(uriToCheck: uri), 'did:example'); + }); + + test('Should return last issuer DID if multiple issuers in URI', () { + final uri = Uri.parse( + 'https://example.com?issuer=did:example1&issuer=did:example2'); + expect(getIssuerDid(uriToCheck: uri), 'did:example2'); + }); + }); + + group('isValidPrivateKey', () { + test('Should return true for valid Ethereum private key', () { + const validKey = + '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; + expect(isValidPrivateKey(validKey), true); + }); + + test('Should return true for valid Tezos private key (edsk)', () { + const validKey = + 'edsk3nLLjZzUtwUmBzJbry8MZx8YmPfEzZaCFpSSKmCWUz1k5ehSJ8'; + expect(isValidPrivateKey(validKey), true); + }); + + test('Should return false for invalid private key', () { + const invalidKey = 'invalid_private_key'; + expect(isValidPrivateKey(invalidKey), false); + }); + }); + + test('stringToHexPrefixedWith05 returns correct value', () { + const payload = 'Bibash'; + expect( + stringToHexPrefixedWith05( + payload: payload, + dateTime: DateTime(2022, 1, 1, 0, 0, 0, 0), + ), + '05010031323254657a6f73205369676e6564204d6573736167653a20616c746d652e696f20323032322d30312d30312030303a30303a30302e30303020426962617368'); + }); + + test('getCredentialName returns correct credential name', () { + const constraints = { + 'fields': [ + { + 'path': r'[$.credentialSubject.type]', + 'filter': {'pattern': 'Bibash'} + }, + ], + }; + + final result = getCredentialName(jsonEncode(constraints)); + expect(result, equals('Bibash')); + }); + + test('getIssuersName returns correct issuer name', () { + const constraints = { + 'fields': [ + { + 'path': r'[$.issuer]', + 'filter': {'pattern': 'Bibash'} + }, + ], + }; + + final result = getIssuersName(jsonEncode(constraints)); + expect(result, equals('Bibash')); + }); + + test('getBlockchainType returns correct issuer name', () { + expect( + getBlockchainType(AccountType.tezos), equals(BlockchainType.tezos)); + expect(getBlockchainType(AccountType.ethereum), + equals(BlockchainType.ethereum)); + expect( + getBlockchainType(AccountType.fantom), equals(BlockchainType.fantom)); + expect(getBlockchainType(AccountType.polygon), + equals(BlockchainType.polygon)); + expect(getBlockchainType(AccountType.binance), + equals(BlockchainType.binance)); + expect(() => getBlockchainType(AccountType.ssi), + throwsA(isA())); + }); + + test('getCredTypeFromName returns correct type', () { + expect( + getCredTypeFromName('DefiCompliance'), + equals(CredentialSubjectType.defiCompliance), + ); + expect(getCredTypeFromName('afsd'), equals(isNull)); + }); + + test('timeFormatter formats time correctly', () { + expect(timeFormatter(timeInSecond: 65), equals('01 : 05')); + expect(timeFormatter(timeInSecond: 3600), equals('60 : 00')); + expect(timeFormatter(timeInSecond: 3665), equals('61 : 05')); + expect(timeFormatter(timeInSecond: 0), equals('00 : 00')); + }); + + test('getssiMnemonicsInList returns list of words', () async { + const mockMnemonic = + 'word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12'; + + when(() => mockSecureStorage.get(SecureStorageKeys.ssiMnemonic)) + .thenAnswer((_) => Future.value(mockMnemonic)); + + final result = await getssiMnemonicsInList(mockSecureStorage); + + expect( + result, + containsAll([ + 'word1', + 'word2', + 'word3', + 'word4', + 'word5', + 'word6', + 'word7', + 'word8', + 'word9', + 'word10', + 'word11', + 'word12' + ])); + }); + + test('getDateTimeWithoutSpace replaces spaces with dashes', () { + final formattedDateTime = + getDateTimeWithoutSpace(dateTime: DateTime(2022, 1, 1, 1, 1, 1, 1)); + expect(formattedDateTime, '2022-01-01-01:01:01.001'); + }); + + test('getIndexValue returns correct index for each DidKeyType', () { + expect( + getIndexValue(isEBSIV3: true, didKeyType: DidKeyType.secp256k1), 3); + expect( + getIndexValue(isEBSIV3: false, didKeyType: DidKeyType.secp256k1), 1); + + expect(getIndexValue(isEBSIV3: false, didKeyType: DidKeyType.p256), 4); + expect(getIndexValue(isEBSIV3: false, didKeyType: DidKeyType.ebsiv3), 5); + expect(getIndexValue(isEBSIV3: false, didKeyType: DidKeyType.jwkP256), 6); + expect(getIndexValue(isEBSIV3: false, didKeyType: DidKeyType.edDSA), 0); + expect( + getIndexValue( + isEBSIV3: false, didKeyType: DidKeyType.jwtClientAttestation), + 0); + }); + + group('getWalletAttestationP256Key', () { + test('returns existing key', () async { + const existingKey = 'existing_key'; + when(() => mockSecureStorage + .get(SecureStorageKeys.p256PrivateKeyForWallet)) + .thenAnswer((_) => Future.value(existingKey)); + + final result = await getWalletAttestationP256Key(mockSecureStorage); + + expect(result, existingKey.replaceAll('=', '')); + }); + + test('generates and returns new key', () async { + const newKey = 'new_key'; + when(() => mockSecureStorage + .get(SecureStorageKeys.p256PrivateKeyForWallet)) + .thenAnswer((_) => Future.value(null)); + + when(() => mockSecureStorage.set(any(), any())) + .thenAnswer((_) async {}); + + final result = await getWalletAttestationP256Key(mockSecureStorage); + final data = jsonDecode(result) as Map; + + expect(data['alg'], 'ES256'); + expect(data['crv'], 'P-256'); + expect(data['d'], isA()); + expect(data['kty'], 'EC'); + expect(data['use'], 'sig'); + expect(data['x'], isA()); + expect(data['y'], isA()); + }); + }); + + group('getP256KeyToGetAndPresentVC', () { + test('returns existing key', () async { + const existingKey = 'existing_key'; + when(() => mockSecureStorage + .get(SecureStorageKeys.p256PrivateKeyToGetAndPresentVC)) + .thenAnswer((_) => Future.value(existingKey)); + + final result = await getP256KeyToGetAndPresentVC(mockSecureStorage); + + expect(result, existingKey.replaceAll('=', '')); + }); + + test('generates and returns new key', () async { + const newKey = 'new_key'; + when(() => mockSecureStorage + .get(SecureStorageKeys.p256PrivateKeyToGetAndPresentVC)) + .thenAnswer((_) => Future.value(null)); + + when(() => mockSecureStorage.set(any(), any())) + .thenAnswer((_) async {}); + + final result = await getP256KeyToGetAndPresentVC(mockSecureStorage); + final data = jsonDecode(result) as Map; + + expect(data['alg'], 'ES256'); + expect(data['crv'], 'P-256'); + expect(data['d'], isA()); + expect(data['kty'], 'EC'); + expect(data['use'], 'sig'); + expect(data['x'], isA()); + expect(data['y'], isA()); + }); + }); + + test('generateRandomP256Key returns a valid P-256 key', () { + final key = generateRandomP256Key(); + + final data = jsonDecode(key) as Map; + + expect(data['alg'], 'ES256'); + expect(data['crv'], 'P-256'); + expect(data['d'], isA()); + expect(data['kty'], 'EC'); + expect(data['use'], 'sig'); + expect(data['x'], isA()); + expect(data['y'], isA()); + }); + + test('getDidKeyFromString returns correct enum value', () { + expect(getDidKeyFromString('DidKeyType.edDSA'), DidKeyType.edDSA); + expect(getDidKeyFromString('DidKeyType.secp256k1'), DidKeyType.secp256k1); + expect(getDidKeyFromString('DidKeyType.p256'), DidKeyType.p256); + expect(getDidKeyFromString('DidKeyType.ebsiv3'), DidKeyType.ebsiv3); + expect(getDidKeyFromString('DidKeyType.jwkP256'), DidKeyType.jwkP256); + expect(getDidKeyFromString('DidKeyType.jwtClientAttestation'), + DidKeyType.jwtClientAttestation); + expect(getDidKeyFromString('InvalidKeyType'), null); + expect(getDidKeyFromString(null), null); + }); + + group('JWT Decode Payload and Header', () { + final jwtDecode = JWTDecode(); + + const jwt = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFt' + 'ZSI6IkJpYmFzaCIsImlhdCI6MTUxNjIzOTAyMn0.ILWacv8Ed_PmWsLBEIK1mM-wOrt4w' + 'AU7_OUNLXQqtwI'; + + test('decodePayload correctly decodes a JWT token', () { + final decodedData = decodePayload(jwtDecode: jwtDecode, token: jwt); + final expectedData = { + 'sub': '1234567890', + 'name': 'Bibash', + 'iat': 1516239022, + }; + expect(decodedData, expectedData); + }); + + test('decodeHeader correctly decodes a JWT token', () { + final decodedData = decodeHeader(jwtDecode: jwtDecode, token: jwt); + final expectedData = { + 'alg': 'HS256', + 'typ': 'JWT', + }; + expect(decodedData, expectedData); + }); + + test('birthDateFormater formats the birth date correctly', () { + const birthData = 19900101; + final formattedBirthdate = birthDateFormater(birthData); + + expect(formattedBirthdate, '1990-01-01'); + }); + + test('getSignatureType returns correct signature type for circuitId', () { + expect(getSignatureType('credentialAtomicQuerySigV2'), 'BJJ Signature'); + expect(getSignatureType('credentialAtomicQuerySigV2OnChain'), + 'BJJ Signature'); + expect(getSignatureType('credentialAtomicQueryMTPV2'), 'SMT Signature'); + expect(getSignatureType('credentialAtomicQueryMTPV2OnChain'), + 'SMT Signature'); + expect(getSignatureType('unknownCircuitId'), ''); + }); + + test('splitUppercase splits PascalCase string correctly', () { + const input = 'BibashManShrestha'; + final result = splitUppercase(input); + expect(result, 'Bibash Man Shrestha'); + }); + + test('generateUriList returns list of URIs from "uri_list" parameter', + () { + const url = + 'https://example.com?uri_list=https%3A%2F%2Fexample.com%2Fpath1&uri_list=https%3A%2F%2Fexample.com%2Fpath2'; + final result = generateUriList(url); + expect( + result, ['https://example.com/path1', 'https://example.com/path2']); + }); + + test('sortedPublcJwk returns sorted public JWK without private key', () { + final privateKey = { + 'kty': 'EC', + 'use': 'sig', + 'crv': 'P-256K', + 'kid': '1234567890', + 'x': 'SjTww7i4eF-JKBYlShJqJ3lWQIVJF5y1g5uHY3gfAro', + 'y': '1bNb6uA0gKClEFhodSfgcW8FvfSHTgxE8WyFvSZ8bxc' + }; + final result = sortedPublcJwk(jsonEncode(privateKey)); + const expected = + '{"crv":"secp256k1","kid":"1234567890","kty":"EC","x":"SjTww7i4eF-JKBYlShJqJ3lWQIVJF5y1g5uHY3gfAro","y":"1bNb6uA0gKClEFhodSfgcW8FvfSHTgxE8WyFvSZ8bxc"}'; + expect(result, expected); + }); + + test('isPolygonIdUrl returns correct value for valid Polygon ID URLs', + () { + expect(isPolygonIdUrl('{"id":'), true); + expect(isPolygonIdUrl('{"body":{"'), true); + expect(isPolygonIdUrl('{"from": "did:polygonid:'), true); + expect(isPolygonIdUrl('{"to": "did:polygonid:'), true); + expect(isPolygonIdUrl('{"thid":'), true); + expect(isPolygonIdUrl('{"typ":'), true); + expect(isPolygonIdUrl('{"type":'), true); + }); + + test('isOIDC4VCIUrl returns true for valid OIDC4VCI URLs', () { + expect(isOIDC4VCIUrl(Uri.parse('openid://some/path')), true); + expect(isOIDC4VCIUrl(Uri.parse('haip://another/path')), true); + }); + + group('handleErrorForOID4VCI throws correct errors', () { + test('Test tokenEndpoint is null', () { + expect( + () async => handleErrorForOID4VCI( + url: 'example', + openIdConfiguration: const OpenIdConfiguration( + authorizationServer: 'example', + tokenEndpoint: null, + ), + authorizationServerConfiguration: const OpenIdConfiguration( + tokenEndpoint: null, + ), + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_issuer_metadata', + 'error_description': 'The issuer configuration is invalid. ' + 'The token_endpoint is missing.', + }), + ), + ); + }); + + test('Test credentialEndpoint is null', () { + expect( + () async => handleErrorForOID4VCI( + url: 'example', + openIdConfiguration: const OpenIdConfiguration( + authorizationServer: 'example', + tokenEndpoint: null, + credentialEndpoint: null, + ), + authorizationServerConfiguration: const OpenIdConfiguration( + tokenEndpoint: 'https://example.com/token', + ), + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_issuer_metadata', + 'error_description': 'The issuer configuration is invalid. ' + 'The credential_endpoint is missing.', + }), + ), + ); + }); + + test('Test credentialIssuer is null', () { + expect( + () async => handleErrorForOID4VCI( + url: 'example', + openIdConfiguration: const OpenIdConfiguration( + authorizationServer: 'example', + tokenEndpoint: null, + credentialEndpoint: 'https://example.com/cred', + credentialIssuer: null, + ), + authorizationServerConfiguration: const OpenIdConfiguration( + tokenEndpoint: 'https://example.com/token', + ), + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_issuer_metadata', + 'error_description': 'The issuer configuration is invalid. ' + 'The credential_issuer is missing.', + }), + ), + ); + }); + + test( + 'Test credentialsSupported and credentialConfigurationsSupported are null', + () { + expect( + () async => handleErrorForOID4VCI( + url: 'example', + openIdConfiguration: const OpenIdConfiguration( + authorizationServer: 'example', + tokenEndpoint: null, + credentialEndpoint: 'https://example.com/cred', + credentialIssuer: 'issuer', + credentialsSupported: null, + credentialConfigurationsSupported: null, + ), + authorizationServerConfiguration: const OpenIdConfiguration( + tokenEndpoint: 'https://example.com/token', + ), + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_issuer_metadata', + 'error_description': 'The issuer configuration is invalid. ' + 'The credentials_supported is missing.', + }), + ), + ); + }); + + test( + 'Test credentialsSupported and credentialConfigurationsSupported are null', + () { + expect( + () async => handleErrorForOID4VCI( + url: 'example', + openIdConfiguration: const OpenIdConfiguration( + authorizationServer: 'example', + tokenEndpoint: null, + credentialEndpoint: 'https://example.com/cred', + credentialIssuer: 'issuer', + credentialsSupported: null, + credentialConfigurationsSupported: 'asdf', + subjectSyntaxTypesSupported: ['asd'], + ), + authorizationServerConfiguration: const OpenIdConfiguration( + tokenEndpoint: 'https://example.com/token', + ), + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'subject_syntax_type_not_supported', + 'error_description': + 'The subject syntax type is not supported.', + }), + ), + ); + }); + }); + + group('getPresentationDefinition', () { + test('returns presentation definition from URI', () async { + final uri = Uri.parse( + "https://example.com?presentation_definition={'title':'Test'}"); + final presentationDefinition = + await getPresentationDefinition(uri: uri, client: mockClient); + + expect(presentationDefinition, {'title': 'Test'}); + }); + + test('returns null for invalid URI', () async { + final uri = Uri.parse('https://example.com'); + final presentationDefinition = + await getPresentationDefinition(uri: uri, client: mockClient); + + expect(presentationDefinition, isNull); + }); + + test( + 'returns presentation definition from URI with ' + 'presentation_definition_uri', () async { + final uri = Uri.parse( + 'https://example.com?presentation_definition_uri=https://example.com/presentation.com'); + + dioAdapter.onGet( + 'https://example.com/presentation.com', + (request) => request.reply(200, {'title': 'Test'}), + ); + + final presentationDefinition = + await getPresentationDefinition(uri: uri, client: mockClient); + + expect(presentationDefinition, {'title': 'Test'}); + }); + + test('returns null for invalid presentation_definition_uri', () async { + final uri = Uri.parse( + 'https://example.com?presentation_definition_uri=https://example.com/presentation.com'); + + dioAdapter.onGet( + 'https://example.com/presentation.com', + (request) => request.reply(200, 'asfd'), + ); + + final presentationDefinition = + await getPresentationDefinition(uri: uri, client: mockClient); + + expect(presentationDefinition, isNull); + }); + }); + + group('getClientMetada', () { + test('returns client metadata from URI', () async { + final uri = + Uri.parse("https://example.com?client_metadata={'title':'Test'}"); + final clientMetadata = + await getClientMetada(uri: uri, client: mockClient); + + expect(clientMetadata, {'title': 'Test'}); + }); + + test('returns null for invalid URI', () async { + final uri = Uri.parse('https://example.com'); + final clientMetadata = + await getClientMetada(uri: uri, client: mockClient); + + expect(clientMetadata, isNull); + }); + + test( + 'returns client metadata from URI with ' + 'client_metadata_uri', () async { + final uri = Uri.parse( + 'https://example.com?client_metadata_uri=https://example.com.com'); + + dioAdapter.onGet( + 'https://example.com.com', + (request) => request.reply(200, {'title': 'Test'}), + ); + + final clientMetadata = + await getClientMetada(uri: uri, client: mockClient); + + expect(clientMetadata, {'title': 'Test'}); + }); + + test('returns null for invalid client_metadata_uri', () async { + final uri = Uri.parse( + 'https://example.com?client_metadata_uri=https://example.com.com'); + + dioAdapter.onGet( + 'https://example.com.com', + (request) => request.reply(200, 'asfd'), + ); + + expect( + () async => getClientMetada(uri: uri, client: mockClient), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_request', + 'error_description': 'Client metaData is invalid', + }), + ), + ); + }); + }); + + group('getCredentialData', () { + test('getCredentialData returns credential if it is a String', () { + const credential = 'credentialData'; + final result = getCredentialData(credential); + expect(result, equals(credential)); + }); + + test('getCredentialData returns last credential type if it is a Map', + () { + final credential = { + 'types': ['type1', 'type2', 'type3'], + }; + final result = getCredentialData(credential); + expect(result, equals('type3')); + }); + + test('getCredentialData throws exception for invalid credential format', + () { + const credential = 123; + expect(() => getCredentialData(credential), throwsException); + }); + + test('getMessageHandler returns correct MessageHandler', () { + expect(getMessageHandler(MessageHandler), isA()); + expect( + getMessageHandler( + DioException( + requestOptions: RequestOptions(path: 'test/path'), + error: 'Test error', + response: Response( + data: 'Test data', + statusCode: 400, + requestOptions: RequestOptions(), + ), + ), + ), + isA(), + ); + expect( + getMessageHandler( + const FormatException('Test format exception', 'source'), + ), + isA().having((e) => e.data, '', { + 'error': 'unsupported_format', + 'error_description': 'Test format exception\n' + '\n' + 'source', + }), + ); + expect( + getMessageHandler(TypeError()), + isA().having((e) => e.data, '', { + 'error': 'unsupported_format', + 'error_description': + 'Some issue in the response from the server.', + }), + ); + expect( + getMessageHandler('Exception: CREDENTIAL_SUPPORT_DATA_ERROR'), + isA().having((e) => e.data, '', { + 'error': 'unsupported_credential_format', + 'error_description': + 'The credential support format has some issues.', + }), + ); + expect( + getMessageHandler('Exception: AUTHORIZATION_DETAIL_ERROR'), + isA().having((e) => e.data, '', { + 'error': 'unsupported_format', + 'error_description': 'Invalid token response format.', + }), + ); + expect( + getMessageHandler('Exception: INVALID_TOKEN'), + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'Failed to extract header from jwt.', + }), + ); + expect( + getMessageHandler('Exception: INVALID_PAYLOAD'), + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'Failed to extract payload from jwt.', + }), + ); + expect( + getMessageHandler('Exception: SSI_ISSUE'), + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'SSI does not support this process.', + }), + ); + expect( + getMessageHandler('Exception: OPENID-CONFIGURATION-ISSUE'), + isA().having((e) => e.data, '', { + 'error': 'unsupported_format', + 'error_description': 'Openid configuration response issue.', + }), + ); + expect( + getMessageHandler('Exception: NOT_A_VALID_OPENID_URL'), + isA().having((e) => e.data, '', { + 'error': 'unsupported_format', + 'error_description': + 'Not a valid openid url to initiate issuance.', + }), + ); + expect( + getMessageHandler('Exception: JWKS_URI_IS_NULL'), + isA().having((e) => e.data, '', { + 'error': 'unsupported_format', + 'error_description': 'The jwks_uri is null.', + }), + ); + expect( + getMessageHandler('Exception: Issue while getting'), + isA().having((e) => e.data, '', { + 'error': 'invalid_request', + 'error_description': 'Issue while getting', + }), + ); + expect( + getMessageHandler('Exception: SECURE_STORAGE_ISSUE'), + isA().having((e) => e.data, '', { + 'error': 'invalid_request', + 'error_description': 'Secure Storage issue with this device', + }), + ); + expect( + getMessageHandler('Exception: ISSUE_WHILE_ADDING_IDENTITY'), + isA().having((e) => e.data, '', { + 'error': 'invalid_request', + 'error_description': 'Issue while adding identity.', + }), + ); + expect( + getMessageHandler('Exception: ISSUE_WHILE_GETTING_CLAIMS'), + isA().having((e) => e.data, '', { + 'error': 'invalid_request', + 'error_description': 'Issue while getting claims.', + }), + ); + expect( + getMessageHandler('Exception: ISSUE_WHILE_RESTORING_CLAIMS'), + isA().having((e) => e.data, '', { + 'error': 'invalid_request', + 'error_description': 'Issue while restoring claims.', + }), + ); + expect( + getMessageHandler('Exception: PUBLICKEYJWK_EXTRACTION_ERROR'), + isA().having((e) => e.data, '', { + 'error': 'invalid_request', + 'error_description': 'Issue while restoring claims.', + }), + ); + expect( + getMessageHandler('Exception: random'), + isA(), + ); + }); + + test('getErrorResponseString returns correct ResponseString', () { + expect(getErrorResponseString('invalid_request'), + ResponseString.RESPONSE_STRING_invalidRequest); + expect(getErrorResponseString('invalid_request_uri'), + ResponseString.RESPONSE_STRING_invalidRequest); + expect(getErrorResponseString('invalid_request_object'), + ResponseString.RESPONSE_STRING_invalidRequest); + + expect(getErrorResponseString('unauthorized_client'), + ResponseString.RESPONSE_STRING_accessDenied); + expect(getErrorResponseString('access_denied'), + ResponseString.RESPONSE_STRING_accessDenied); + expect(getErrorResponseString('invalid_or_missing_proof'), + ResponseString.RESPONSE_STRING_accessDenied); + expect(getErrorResponseString('interaction_required'), + ResponseString.RESPONSE_STRING_accessDenied); + + expect(getErrorResponseString('unsupported_response_type'), + ResponseString.RESPONSE_STRING_thisRequestIsNotSupported); + expect(getErrorResponseString('invalid_scope'), + ResponseString.RESPONSE_STRING_thisRequestIsNotSupported); + expect(getErrorResponseString('request_not_supported'), + ResponseString.RESPONSE_STRING_thisRequestIsNotSupported); + expect(getErrorResponseString('request_uri_not_supported'), + ResponseString.RESPONSE_STRING_thisRequestIsNotSupported); + + expect(getErrorResponseString('unsupported_credential_type'), + ResponseString.RESPONSE_STRING_unsupportedCredential); + expect(getErrorResponseString('login_required'), + ResponseString.RESPONSE_STRING_aloginIsRequired); + expect(getErrorResponseString('account_selection_required'), + ResponseString.RESPONSE_STRING_aloginIsRequired); + + expect(getErrorResponseString('consent_required'), + ResponseString.RESPONSE_STRING_userConsentIsRequired); + + expect(getErrorResponseString('registration_not_supported'), + ResponseString.RESPONSE_STRING_theWalletIsNotRegistered); + + expect(getErrorResponseString('invalid_grant'), + ResponseString.RESPONSE_STRING_credentialIssuanceDenied); + expect(getErrorResponseString('invalid_client'), + ResponseString.RESPONSE_STRING_credentialIssuanceDenied); + expect(getErrorResponseString('invalid_token'), + ResponseString.RESPONSE_STRING_credentialIssuanceDenied); + + expect( + getErrorResponseString('unsupported_credential_format'), + ResponseString + .RESPONSE_STRING_thisCredentialFormatIsNotSupported); + + expect(getErrorResponseString('unsupported_format'), + ResponseString.RESPONSE_STRING_thisFormatIsNotSupported); + + expect(getErrorResponseString('invalid_issuer_metadata'), + ResponseString.RESPONSE_STRING_theCredentialOfferIsInvalid); + + expect(getErrorResponseString('server_error'), + ResponseString.RESPONSE_STRING_theServiceIsNotAvailable); + + expect( + getErrorResponseString('issuance_pending'), + ResponseString + .RESPONSE_STRING_theIssuanceOfThisCredentialIsPending); + + expect(getErrorResponseString('random'), + ResponseString.RESPONSE_STRING_thisRequestIsNotSupported); + }); + + test('isIDTokenOnly', () { + expect(isIDTokenOnly('id_token'), true); + expect(isIDTokenOnly('id_token vp_token'), false); + expect(isIDTokenOnly('vp_token'), false); + expect(isIDTokenOnly(''), false); + }); + + test('isVPTokenOnly', () { + expect(isVPTokenOnly('id_token'), false); + expect(isVPTokenOnly('vp_token'), true); + expect(isVPTokenOnly('id_token vp_token'), false); + expect(isVPTokenOnly(''), false); + }); + + test('isIDTokenAndVPToken', () { + expect(isIDTokenAndVPToken('id_token'), false); + expect(isIDTokenAndVPToken('vp_token'), false); + expect(isIDTokenAndVPToken('id_token vp_token'), true); + expect(isIDTokenAndVPToken(''), false); + }); + + test('hasIDToken', () { + expect(hasIDToken('id_token'), true); + expect(hasIDToken('vp_token'), false); + expect(hasIDToken('id_token vp_token'), true); + expect(hasIDToken(''), false); + }); + + test('hasVPToken', () { + expect(hasVPToken('id_token'), false); + expect(hasVPToken('vp_token'), true); + expect(hasVPToken('id_token vp_token'), true); + expect(hasVPToken(''), false); + }); + + test('hasIDTokenOrVPToken returns correct url', () { + expect(hasIDTokenOrVPToken('id_token'), true); + expect(hasIDTokenOrVPToken('vp_token'), true); + expect(hasIDTokenOrVPToken('id_token vp_token'), true); + expect(hasIDTokenOrVPToken(''), false); + }); + test('getUpdatedUrlForSIOPV2OIC4VP', () { + final uri = Uri.parse('https://example.com'); + final response = { + 'response_type': 'code', + 'redirect_uri': 'https://example.com/callback', + 'scope': 'openid profile', + 'response_uri': 'https://example.com/response', + 'response_mode': 'form_post', + 'nonce': '12345', + 'client_id': 'client123', + 'claims': { + 'id_token': { + 'email': {'essential': true} + } + }, + 'state': 'state123', + 'presentation_definition': { + 'id': 'cred-123', + 'format': 'vp', + 'input_descriptors': [] + }, + 'presentation_definition_uri': 'https://example.com/presentation', + 'registration': { + 'token_endpoint_auth_method': 'client_secret_basic' + }, + 'client_metadata': {'example_key': 'example_value'}, + 'client_metadata_uri': 'https://example.com/client_metadata' + }; + + final updatedUrl = + getUpdatedUrlForSIOPV2OIC4VP(uri: uri, response: response); + + expect( + updatedUrl.split('&'), + containsAll([ + 'scope=openid+profile', + 'client_id=client123', + 'redirect_uri=https%3A%2F%2Fexample.com%2Fcallback', + 'response_uri=https%3A%2F%2Fexample.com%2Fresponse', + 'response_mode=form_post', + 'nonce=12345', + 'state=state123', + 'response_type=code', + 'claims=%7B%27id_token%27%3A%7B%27email%27%3A%7B%27essential%27%3Atrue%7D%7D%7D', + 'presentation_definition=%7B%27id%27%3A%27cred-123%27%2C%27format%27%3A%27vp%27%2C%27input_descriptors%27%3A%5B%5D%7D', + 'presentation_definition_uri=https%3A%2F%2Fexample.com%2Fpresentation', + 'registration=%7B%22token_endpoint_auth_method%22%3A%22client_secret_basic%22%7D', + 'client_metadata=%7B%22example_key%22%3A%22example_value%22%7D', + 'client_metadata_uri=https%3A%2F%2Fexample.com%2Fclient_metadata' + ]), + ); + }); + + group('getPresentVCDetails', () { + test( + 'returns correct value when presentationDefinition ldp_vc formats', + () { + expect( + getPresentVCDetails( + vcFormatType: VCFormatType.ldpVc, + presentationDefinition: PresentationDefinition( + inputDescriptors: [], + format: Format.fromJson( + { + 'ldp_vc': { + 'proof_type': [], + }, + }, + ), + ), + clientMetaData: null, + ), + (true, false, false, false), + ); + }); + test( + 'throws ResponseMessage when presentationDefinition has no formats', + () { + final presentationDefinition = PresentationDefinition( + inputDescriptors: [], + format: Format.fromJson({}), + ); + + expect( + () => getPresentVCDetails( + vcFormatType: VCFormatType.ldpVc, + presentationDefinition: presentationDefinition, + clientMetaData: null, + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_request', + 'error_description': 'VC format is missing', + }), + ), + ); + }); + + test( + 'returns correct value when presentationDefinition.format' + ' and clientMetaData are null', () { + expect( + getPresentVCDetails( + vcFormatType: VCFormatType.jwtVc, + presentationDefinition: PresentationDefinition( + inputDescriptors: [], + format: null, + ), + clientMetaData: null, + ), + (false, true, false, false), + ); + }); + + test( + 'returns correct value when presentationDefinition.format is null' + ' and clientMetaData is provided', () { + expect( + getPresentVCDetails( + vcFormatType: VCFormatType.jwtVcJson, + presentationDefinition: PresentationDefinition( + inputDescriptors: [], + format: null, + ), + clientMetaData: { + 'vp_formats': { + 'jwt_vc_json': 'here', + }, + }, + ), + (false, false, true, false), + ); + }); + }); + }); + }); + }); +} From 5a2cf2851e7c4f2209fbdbbc789fff3c5592ef5a Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 14 May 2024 13:07:09 +0545 Subject: [PATCH 46/56] Added more helper functions test --- .../helper_functions/helper_functions.dart | 9 +- .../operation/cubit/operation_cubit.dart | 11 +- .../confirm_token_transaction_cubit.dart | 10 +- .../helper_functions_test.dart | 361 ++++++++++++++++++ 4 files changed, 383 insertions(+), 8 deletions(-) diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index dde510ab0..dfbbd2b8d 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -2156,7 +2156,10 @@ String? getWalletAddress(CredentialSubjectModel credentialSubjectModel) { return null; } -Future fetchRpcUrl(BlockchainNetwork blockchainNetwork) async { +Future fetchRpcUrl({ + required BlockchainNetwork blockchainNetwork, + required DotEnv dotEnv, +}) async { String rpcUrl = ''; if (blockchainNetwork is BinanceNetwork || @@ -2164,8 +2167,8 @@ Future fetchRpcUrl(BlockchainNetwork blockchainNetwork) async { rpcUrl = blockchainNetwork.rpcNodeUrl as String; } else { if (blockchainNetwork.networkname == 'Mainnet') { - await dotenv.load(); - final String infuraApiKey = dotenv.get('INFURA_API_KEY'); + await dotEnv.load(); + final String infuraApiKey = dotEnv.get('INFURA_API_KEY'); late String prefixUrl; diff --git a/lib/dashboard/connection/operation/cubit/operation_cubit.dart b/lib/dashboard/connection/operation/cubit/operation_cubit.dart index 2f1d4ce5b..a99c7ecef 100644 --- a/lib/dashboard/connection/operation/cubit/operation_cubit.dart +++ b/lib/dashboard/connection/operation/cubit/operation_cubit.dart @@ -208,8 +208,10 @@ class OperationCubit extends Cubit { walletConnectCubit.state.transaction!.value!; amount = MWeb3Client.formatEthAmount(amount: ethAmount.getInWei); - final web3RpcURL = - await fetchRpcUrl(manageNetworkCubit.state.network); + final web3RpcURL = await fetchRpcUrl( + blockchainNetwork: manageNetworkCubit.state.network, + dotEnv: dotenv, + ); log.i('web3RpcURL - $web3RpcURL'); final (_, _, feeData) = await MWeb3Client.estimateEVMFee( @@ -356,7 +358,10 @@ class OperationCubit extends Cubit { final EtherAmount ethAmount = walletConnectCubit.state.transaction!.value!; - final rpcUrl = await fetchRpcUrl(manageNetworkCubit.state.network); + final rpcUrl = await fetchRpcUrl( + blockchainNetwork: manageNetworkCubit.state.network, + dotEnv: dotenv, + ); log.i('rpcUrl - $rpcUrl'); diff --git a/lib/dashboard/home/tab_bar/tokens/confirm_token_transaction/cubit/confirm_token_transaction_cubit.dart b/lib/dashboard/home/tab_bar/tokens/confirm_token_transaction/cubit/confirm_token_transaction_cubit.dart index d0b3c1979..39d23e328 100644 --- a/lib/dashboard/home/tab_bar/tokens/confirm_token_transaction/cubit/confirm_token_transaction_cubit.dart +++ b/lib/dashboard/home/tab_bar/tokens/confirm_token_transaction/cubit/confirm_token_transaction_cubit.dart @@ -119,7 +119,10 @@ class ConfirmTokenTransactionCubit extends Cubit { final sender = credentials.address; final reciever = EthereumAddress.fromHex(state.withdrawalAddress); - final web3RpcURL = await fetchRpcUrl(manageNetworkCubit.state.network); + final web3RpcURL = await fetchRpcUrl( + blockchainNetwork: manageNetworkCubit.state.network, + dotEnv: dotenv, + ); final (maxGas, priceOfGas, feeData) = await MWeb3Client.estimateEVMFee( web3RpcURL: web3RpcURL, @@ -424,7 +427,10 @@ class ConfirmTokenTransactionCubit extends Cubit { } else { final selectedEthereumNetwork = manageNetworkCubit.state.network; - final chainRpcUrl = await fetchRpcUrl(manageNetworkCubit.state.network); + final chainRpcUrl = await fetchRpcUrl( + blockchainNetwork: manageNetworkCubit.state.network, + dotEnv: dotenv, + ); await _sendContractInvocationOperationEVM( tokenAmount: state.totalAmount, diff --git a/test/app/shared/helper_functions/helper_functions_test.dart b/test/app/shared/helper_functions/helper_functions_test.dart index b2ed5fa68..dd05497ca 100644 --- a/test/app/shared/helper_functions/helper_functions_test.dart +++ b/test/app/shared/helper_functions/helper_functions_test.dart @@ -1,8 +1,10 @@ import 'dart:convert'; import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/home/home.dart'; import 'package:credential_manifest/credential_manifest.dart'; import 'package:dio/dio.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http_mock_adapter/http_mock_adapter.dart'; import 'package:jwt_decode/jwt_decode.dart'; @@ -13,6 +15,8 @@ import 'package:secure_storage/secure_storage.dart'; class MockSecureStorage extends Mock implements SecureStorageProvider {} +class MockDotenv extends Mock implements DotEnv {} + void main() { late SecureStorageProvider mockSecureStorage; @@ -913,6 +917,7 @@ void main() { expect(hasIDTokenOrVPToken('id_token vp_token'), true); expect(hasIDTokenOrVPToken(''), false); }); + test('getUpdatedUrlForSIOPV2OIC4VP', () { final uri = Uri.parse('https://example.com'); final response = { @@ -988,6 +993,7 @@ void main() { (true, false, false, false), ); }); + test( 'throws ResponseMessage when presentationDefinition has no formats', () { @@ -1047,6 +1053,361 @@ void main() { ); }); }); + + group('checkX509', () { + test('throws error for x5c is null', () async { + final result = await checkX509( + clientId: '', + header: {}, + encodedData: '', + ); + expect(result, isNull); + }); + + test('throws error for invalid x5c format', () async { + expect( + () => checkX509( + clientId: '', + header: { + 'x5c': 'i am not list', + }, + encodedData: '', + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'x509_san_dns scheme error', + }), + ), + ); + }); + + test('throws error for invalid x5c is empty', () async { + expect( + () => checkX509( + clientId: '', + header: { + 'x5c': [], + }, + encodedData: '', + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'x509_san_dns scheme error', + }), + ), + ); + }); + }); + + group('checkVerifierAttestation', () { + final jwtDecode = JWTDecode(); + test('throws error if JWT is missing', () async { + expect( + () => checkVerifierAttestation( + clientId: '', + header: {}, + jwtDecode: jwtDecode, + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'verifier_attestation scheme error', + }), + ), + ); + }); + + test('throws error when sub is null', () async { + expect( + () => checkVerifierAttestation( + clientId: '', + header: { + 'jwt': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.hqWGSaFpvbrXkOWc6lrnffhNWR19W_S1YKFBx2arWBk', + }, + jwtDecode: jwtDecode, + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'verifier_attestation scheme error', + }), + ), + ); + }); + + test('throws error when sub is not equal to clientId', () async { + expect( + () => checkVerifierAttestation( + clientId: 'random', + header: { + 'jwt': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjQiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.EyF5bWaxNMFda_CRAOHu3aagShvHlGpnSWK7uFsj23Q', + }, + jwtDecode: jwtDecode, + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'verifier_attestation scheme error', + }), + ), + ); + }); + + test('throws error when sub cnf is null', () async { + expect( + () => checkVerifierAttestation( + clientId: '124', + header: { + 'jwt': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjQiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.EyF5bWaxNMFda_CRAOHu3aagShvHlGpnSWK7uFsj23Q', + }, + jwtDecode: jwtDecode, + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'verifier_attestation scheme error', + }), + ), + ); + }); + + test('throws error when cnf is not Map', () async { + expect( + () => checkVerifierAttestation( + clientId: '124', + header: { + 'jwt': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjQiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjIsImNuZiI6IjEyMyJ9.xZYbK4Oe2jGyQwyOiK5Zv0sHDtfjgY-sdS7WKs-aZYQ', + }, + jwtDecode: jwtDecode, + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'verifier_attestation scheme error', + }), + ), + ); + }); + + test('throws error when cnf does not contain jwk', () async { + expect( + () => checkVerifierAttestation( + clientId: '124', + header: { + 'jwt': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjQiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjIsImNuZiI6eyJ0ZXN0IjoidGVzdCJ9fQ.tnYvd00vYuDxjTtC7goSB5EQUNGtSFR1JBpY1CTRzD0', + }, + jwtDecode: jwtDecode, + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'verifier_attestation scheme error', + }), + ), + ); + }); + + test('throws error when jwk is not Map', () async { + expect( + () => checkVerifierAttestation( + clientId: '124', + header: { + 'jwt': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjQiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjIsImNuZiI6eyJqd2siOiJ0ZXN0In19.qjqntbtQTnRcR60UvveWyv8t3Y1dFMI0DLSyB_pwqBk', + }, + jwtDecode: jwtDecode, + ), + throwsA( + isA().having((e) => e.data, '', { + 'error': 'invalid_format', + 'error_description': 'verifier_attestation scheme error', + }), + ), + ); + }); + + test('return correct jwk', () async { + final result = await checkVerifierAttestation( + clientId: '124', + header: { + 'jwt': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjQiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjIsImNuZiI6eyJqd2siOnsibmFtZSI6IkJpYmFzaCJ9fX0.daqYrO5JtoW9o0ZEDlG2a6ctAgQxaNxTT0iYyVBIIkY', + }, + jwtDecode: jwtDecode, + ); + + expect(result, {'name': 'Bibash'}); + }); + }); + + test('returns correct wallet Address', () { + expect( + getWalletAddress( + TezosAssociatedAddressModel( + id: 'id', + type: 'type', + issuedBy: const Author('name'), + associatedAddress: 'tezosAddress', + ), + ), + 'tezosAddress', + ); + expect( + getWalletAddress( + EthereumAssociatedAddressModel( + id: 'id', + type: 'type', + issuedBy: const Author('name'), + associatedAddress: 'ethereumAddress', + ), + ), + 'ethereumAddress', + ); + expect( + getWalletAddress( + PolygonAssociatedAddressModel( + id: 'id', + type: 'type', + issuedBy: const Author('name'), + associatedAddress: 'polygonAddress', + ), + ), + 'polygonAddress', + ); + expect( + getWalletAddress( + BinanceAssociatedAddressModel( + id: 'id', + type: 'type', + issuedBy: const Author('name'), + associatedAddress: 'address', + ), + ), + 'address', + ); + expect( + getWalletAddress( + FantomAssociatedAddressModel( + id: 'id', + type: 'type', + issuedBy: const Author('name'), + associatedAddress: 'fantomAddress', + ), + ), + 'fantomAddress', + ); + expect( + getWalletAddress( + AgeRangeModel( + id: 'id', + type: 'type', + issuedBy: const Author('name'), + ), + ), + isNull, + ); + }); + + group('fetchRpcUrl', () { + late DotEnv mockDotenv; + + setUpAll(() { + mockDotenv = MockDotenv(); + }); + + test('returns rpcNodeUrl for BinanceNetwork.mainNet()', () async { + final result = await fetchRpcUrl( + blockchainNetwork: BinanceNetwork.mainNet(), + dotEnv: mockDotenv, + ); + expect(result, 'https://bsc-dataseed.binance.org/'); + }); + + test('returns rpcNodeUrl for BinanceNetwork.testNet()', () async { + final result = await fetchRpcUrl( + blockchainNetwork: BinanceNetwork.testNet(), + dotEnv: mockDotenv, + ); + expect(result, 'https://bsc-testnet.public.blastapi.io'); + }); + + test('returns rpcNodeUrl for FantomNetwork.mainNet()', () async { + final result = await fetchRpcUrl( + blockchainNetwork: FantomNetwork.mainNet(), + dotEnv: mockDotenv, + ); + expect(result, 'https://rpcapi.fantom.network/'); + }); + + test('returns rpcNodeUrl for FantomNetwork.testNet()', () async { + final result = await fetchRpcUrl( + blockchainNetwork: FantomNetwork.testNet(), + dotEnv: mockDotenv, + ); + expect(result, 'https://rpc.testnet.fantom.network'); + }); + + test('returns infura URL for PolygonNetwork.mainNet()', () async { + when(() => mockDotenv.load()).thenAnswer((_) async => {}); + when(() => mockDotenv.get('INFURA_API_KEY')).thenReturn('123'); + final result = await fetchRpcUrl( + blockchainNetwork: PolygonNetwork.mainNet(), + dotEnv: mockDotenv, + ); + expect(result, '${Parameters.POLYGON_INFURA_URL}123'); + }); + + test('returns infura URL for PolygonNetwork on Testnet', () async { + final result = await fetchRpcUrl( + blockchainNetwork: PolygonNetwork.testNet(), + dotEnv: mockDotenv, + ); + expect(result, 'https://rpc-mumbai.maticvigil.com'); + }); + + test('returns infura URL for EthereumNetwork.mainNet()', () async { + when(() => mockDotenv.load()).thenAnswer((_) async => {}); + when(() => mockDotenv.get('INFURA_API_KEY')).thenReturn('123'); + final result = await fetchRpcUrl( + blockchainNetwork: EthereumNetwork.mainNet(), + dotEnv: mockDotenv, + ); + expect(result, '${Parameters.web3RpcMainnetUrl}123'); + }); + + test('returns infura URL for EthereumNetwork.testNet()', () async { + final result = await fetchRpcUrl( + blockchainNetwork: EthereumNetwork.testNet(), + dotEnv: mockDotenv, + ); + expect(result, 'https://rpc.sepolia.dev'); + }); + + test('returns infura URL for TezosNetwork.mainNet()', () async { + when(() => mockDotenv.load()).thenAnswer((_) async => {}); + when(() => mockDotenv.get('INFURA_API_KEY')).thenReturn('123'); + final result = await fetchRpcUrl( + blockchainNetwork: TezosNetwork.mainNet(), + dotEnv: mockDotenv, + ); + expect(result, '${Parameters.web3RpcMainnetUrl}123'); + }); + + test('returns infura URL for TezosNetwork.ghostnet()', () async { + final result = await fetchRpcUrl( + blockchainNetwork: TezosNetwork.ghostnet(), + dotEnv: mockDotenv, + ); + expect(result, 'https://rpc.tzkt.io/ghostnet'); + }); + }); }); }); }); From 51423f5fa7043c99e8ed58075d297235b2a5294b Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 16 May 2024 15:09:15 +0545 Subject: [PATCH 47/56] solve app version test of splash cubit --- lib/splash/cubit/splash_cubit.dart | 14 +++++++++++--- test/splash/cubit/splash_cubit_test.dart | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/splash/cubit/splash_cubit.dart b/lib/splash/cubit/splash_cubit.dart index 66330314c..f9b2097d9 100644 --- a/lib/splash/cubit/splash_cubit.dart +++ b/lib/splash/cubit/splash_cubit.dart @@ -23,8 +23,9 @@ class SplashCubit extends Cubit { required this.altmeChatSupportCubit, required this.client, required this.profileCubit, + this.packageInfo, }) : super(const SplashState()) { - _getAppVersion(); + _getAppVersion(packageInfo); } final SecureStorageProvider secureStorageProvider; @@ -34,6 +35,7 @@ class SplashCubit extends Cubit { final AltmeChatSupportCubit altmeChatSupportCubit; final DioClient client; final ProfileCubit profileCubit; + final PackageInfo? packageInfo; Future initialiseApp() async { double counter = 0; @@ -71,8 +73,14 @@ class SplashCubit extends Cubit { }); } - Future _getAppVersion() async { - final PackageInfo packageInfo = await PackageInfo.fromPlatform(); + Future _getAppVersion(PackageInfo? packageInformation) async { + late PackageInfo packageInfo; + if (packageInformation == null) { + packageInfo = await PackageInfo.fromPlatform(); + } else { + packageInfo = packageInformation; + } + final String? savedVersion = await secureStorageProvider.get( SecureStorageKeys.version, ); diff --git a/test/splash/cubit/splash_cubit_test.dart b/test/splash/cubit/splash_cubit_test.dart index d472bec37..c77da64e6 100644 --- a/test/splash/cubit/splash_cubit_test.dart +++ b/test/splash/cubit/splash_cubit_test.dart @@ -12,6 +12,7 @@ import 'package:fake_async/fake_async.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'package:secure_storage/secure_storage.dart'; class MockSecureStorage extends Mock implements SecureStorageProvider {} @@ -77,6 +78,13 @@ void main() { late AltmeChatSupportCubit altmeChatSupportCubit; late ProfileCubit profileCubit; + final packageInfo = PackageInfo( + appName: 'testApp', + packageName: 'com.example.test', + version: '1.0.0', + buildNumber: '1', + ); + setUp(() { WidgetsFlutterBinding.ensureInitialized(); mockSecureStorage = MockSecureStorage(); @@ -85,6 +93,15 @@ void main() { walletCubit = MockWalletCubit(); altmeChatSupportCubit = MockAltmeChatSupportCubit(); profileCubit = MockProfileCubit(); + + when(() => mockSecureStorage.get(SecureStorageKeys.version)) + .thenAnswer((_) async => '1.0.0'); + when(() => mockSecureStorage.get(SecureStorageKeys.buildNumber)) + .thenAnswer((_) async => '1'); + when(() => mockSecureStorage.set(SecureStorageKeys.version, '1.0.0')) + .thenAnswer((_) async => {}); + when(() => mockSecureStorage.set(SecureStorageKeys.buildNumber, '1')) + .thenAnswer((_) async => {}); }); group('Splash Cubit', () { @@ -102,6 +119,7 @@ void main() { ), altmeChatSupportCubit: altmeChatSupportCubit, profileCubit: profileCubit, + packageInfo: packageInfo, ).state, const SplashState( status: SplashStatus.init, @@ -127,6 +145,7 @@ void main() { ), altmeChatSupportCubit: altmeChatSupportCubit, profileCubit: profileCubit, + packageInfo: packageInfo, ); fakeAsync((async) { splashCubit.initialiseApp(); @@ -173,6 +192,7 @@ void main() { ), altmeChatSupportCubit: altmeChatSupportCubit, profileCubit: profileCubit, + packageInfo: packageInfo, ); fakeAsync((async) { splashCubit.initialiseApp(); @@ -201,6 +221,7 @@ void main() { ), altmeChatSupportCubit: altmeChatSupportCubit, profileCubit: profileCubit, + packageInfo: packageInfo, ); fakeAsync((async) { splashCubit.initialiseApp(); @@ -229,6 +250,7 @@ void main() { ), altmeChatSupportCubit: altmeChatSupportCubit, profileCubit: profileCubit, + packageInfo: packageInfo, ); fakeAsync((async) { splashCubit.initialiseApp(); From d6fa196a064b9f93ceb705ca68a4a0ecf34d5953 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 16 May 2024 15:50:38 +0545 Subject: [PATCH 48/56] add some tests --- .../helper_functions_test.dart | 147 +++++++++++++++++- 1 file changed, 145 insertions(+), 2 deletions(-) diff --git a/test/app/shared/helper_functions/helper_functions_test.dart b/test/app/shared/helper_functions/helper_functions_test.dart index dd05497ca..7b7bcc304 100644 --- a/test/app/shared/helper_functions/helper_functions_test.dart +++ b/test/app/shared/helper_functions/helper_functions_test.dart @@ -1018,7 +1018,8 @@ void main() { }); test( - 'returns correct value when presentationDefinition.format' + 'returns correct value(VCFormatType.jwtVc) when' + ' presentationDefinition.format' ' and clientMetaData are null', () { expect( getPresentVCDetails( @@ -1034,7 +1035,42 @@ void main() { }); test( - 'returns correct value when presentationDefinition.format is null' + 'returns correct value(VCFormatType.jwtVcJson) when' + ' presentationDefinition.format' + ' and clientMetaData are null', () { + expect( + getPresentVCDetails( + vcFormatType: VCFormatType.jwtVcJson, + presentationDefinition: PresentationDefinition( + inputDescriptors: [], + format: null, + ), + clientMetaData: null, + ), + (false, false, true, false), + ); + }); + + test( + 'returns correct value(VCFormatType.vcSdJWT) when' + ' presentationDefinition.format' + ' and clientMetaData are null', () { + expect( + getPresentVCDetails( + vcFormatType: VCFormatType.vcSdJWT, + presentationDefinition: PresentationDefinition( + inputDescriptors: [], + format: null, + ), + clientMetaData: null, + ), + (false, false, false, true), + ); + }); + + test( + 'returns correct value(VCFormatType.jwtVcJson) when' + ' presentationDefinition.format is null' ' and clientMetaData is provided', () { expect( getPresentVCDetails( @@ -1052,6 +1088,113 @@ void main() { (false, false, true, false), ); }); + + test( + 'returns correct value(VCFormatType.vc+sd-jwt) when' + ' presentationDefinition.format is null' + ' and clientMetaData is provided', () { + expect( + getPresentVCDetails( + vcFormatType: VCFormatType.vcSdJWT, + presentationDefinition: PresentationDefinition( + inputDescriptors: [], + format: null, + ), + clientMetaData: { + 'vp_formats': { + 'vc+sd-jwt': 'here', + }, + }, + ), + (false, false, false, true), + ); + }); + }); + + group('collectSdValues', () { + test('returns an empty list when no _sd key is present', () { + final data = { + 'a': 1, + 'b': { + 'c': 2, + }, + }; + final result = collectSdValues(data); + expect(result, isEmpty); + }); + + test('collects values from _sd keys', () { + final data = { + '_sd': [1, 2, 3], + 'a': { + '_sd': [4, 5], + }, + 'b': { + 'c': { + '_sd': [6, 7], + }, + }, + }; + final result = collectSdValues(data); + expect(result, [1, 2, 3, 4, 5, 6, 7]); + }); + + test('collects values from ... keys within lists', () { + final data = { + 'a': [ + { + '...': 1, + }, + { + '...': 2, + }, + ], + 'c': [ + { + '...': 3, + }, + ], + }; + final result = collectSdValues(data); + expect(result, [1, 2, 3]); + }); + + test('handles complex nested structures', () { + final data = { + '_sd': [1], + 'a': { + '_sd': [2], + 'b': [ + { + '...': 3, + }, + ], + }, + 'd': [ + { + '...': 5, + }, + ], + }; + final result = collectSdValues(data); + expect(result, [1, 2, 3, 5]); + }); + + test('does not collect non-_sd or non-... values', () { + final data = { + 'a': 1, + 'b': { + 'c': 2, + 'd': [ + { + 'e': 3, + }, + ], + }, + }; + final result = collectSdValues(data); + expect(result, isEmpty); + }); }); group('checkX509', () { From 66e284b1ce8487d04c262eeb15f2017117c8e3f1 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 16 May 2024 15:54:32 +0545 Subject: [PATCH 49/56] bug fix in the code --- lib/app/shared/helper_functions/helper_functions.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index dfbbd2b8d..1617c70f7 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -1889,7 +1889,7 @@ List getStringCredentialsForToken({ presentJwtVc = false; presentJwtVcJson = true; presentVcSdJwt = false; - } else if (presentJwtVc && vcFormatType == VCFormatType.vcSdJWT) { + } else if (presentVcSdJwt && vcFormatType == VCFormatType.vcSdJWT) { presentLdpVc = false; presentJwtVc = false; presentJwtVcJson = false; From 47ecdb156bbe451624d133225a7c0a82de22b0eb Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 17 May 2024 13:47:31 +0545 Subject: [PATCH 50/56] Add some tests and remove notification code --- lib/app/shared/issuer/check_issuer.dart | 4 +- .../local_notification.dart | 82 --------- lib/app/shared/shared.dart | 1 - pubspec.yaml | 1 - test/app/shared/issuer/check_issuer_test.dart | 170 ++++++++++++++++++ .../app/shared/issuer/models/issuer_test.dart | 65 +++++++ .../issuer/models/organization_info_test.dart | 57 ++++++ .../app/shared/loading/loading_view_test.dart | 57 ++++++ 8 files changed, 351 insertions(+), 86 deletions(-) delete mode 100644 lib/app/shared/local_notification/local_notification.dart create mode 100644 test/app/shared/issuer/check_issuer_test.dart create mode 100644 test/app/shared/issuer/models/issuer_test.dart create mode 100644 test/app/shared/issuer/models/organization_info_test.dart create mode 100644 test/app/shared/loading/loading_view_test.dart diff --git a/lib/app/shared/issuer/check_issuer.dart b/lib/app/shared/issuer/check_issuer.dart index 7b4851735..e5a2308c8 100644 --- a/lib/app/shared/issuer/check_issuer.dart +++ b/lib/app/shared/issuer/check_issuer.dart @@ -28,8 +28,6 @@ class CheckIssuer { try { log.i('fetching issuer data'); - final dynamic response = - await client.get('$checkIssuerServerUrl/$didToTest'); if (checkIssuerServerUrl == Urls.checkIssuerEbsiUrl) { return Issuer( preferredName: '', @@ -44,6 +42,8 @@ class CheckIssuer { ); } + final dynamic response = + await client.get('$checkIssuerServerUrl/$didToTest'); final issuer = Issuer.fromJson(response['issuer'] as Map); diff --git a/lib/app/shared/local_notification/local_notification.dart b/lib/app/shared/local_notification/local_notification.dart deleted file mode 100644 index 65de789f9..000000000 --- a/lib/app/shared/local_notification/local_notification.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'package:altme/app/app.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'package:flutter_native_timezone/flutter_native_timezone.dart'; -import 'package:timezone/data/latest.dart' as tz; -import 'package:timezone/timezone.dart' as tz; - -class LocalNotification { - factory LocalNotification() { - return _localNotification; - } - - LocalNotification._internal(); - - static final LocalNotification _localNotification = - LocalNotification._internal(); - - final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = - FlutterLocalNotificationsPlugin(); - - Future init() async { - await _configureLocalTimeZone(); - const android = AndroidInitializationSettings('@mipmap/ic_launcher'); - const iOS = DarwinInitializationSettings(); - const initSettings = InitializationSettings(android: android, iOS: iOS); - - await flutterLocalNotificationsPlugin.initialize( - initSettings, - onDidReceiveNotificationResponse: - (NotificationResponse notificationResponse) { - switch (notificationResponse.notificationResponseType) { - case NotificationResponseType.selectedNotification: - case NotificationResponseType.selectedNotificationAction: - _onSelectNotification(notificationResponse.payload); - } - }, - ); - } - - Future _configureLocalTimeZone() async { - if (kIsWeb) { - return; - } - tz.initializeTimeZones(); - final String timeZoneName = await FlutterNativeTimezone.getLocalTimezone(); - tz.setLocalLocation(tz.getLocation(timeZoneName)); - } - - Future showNotification({ - String? link, - String? title, - String? message, - }) async { - const android = AndroidNotificationDetails( - 'channel id', - 'channel name', - channelDescription: 'channel description', - priority: Priority.high, - importance: Importance.max, - ); - const iOS = DarwinNotificationDetails(); - const platform = NotificationDetails(android: android, iOS: iOS); - - await flutterLocalNotificationsPlugin.show( - 0, // notification id - title, - message, - platform, - payload: link, - ); - } - - Future _onSelectNotification(String? link) async { - if (link != null) { - await LaunchUrl.launch(link); - } - } - - Future cancelAllNotifications() async { - await flutterLocalNotificationsPlugin.cancelAll(); - } -} diff --git a/lib/app/shared/shared.dart b/lib/app/shared/shared.dart index 342c58ab6..c43fa398d 100644 --- a/lib/app/shared/shared.dart +++ b/lib/app/shared/shared.dart @@ -9,7 +9,6 @@ export 'issuer/issuer.dart'; export 'launch_url/launch_url.dart'; export 'loading/loading.dart'; export 'local_auth/local_auth_api.dart'; -export 'local_notification/local_notification.dart'; export 'm_web3_client/m_web3_client.dart'; export 'message_handler/message_handler.dart'; export 'models/model.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index cad3059f0..65e199074 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,7 +55,6 @@ dependencies: flutter_dotenv: ^5.0.2 flutter_html: ^3.0.0-beta.1 flutter_image_compress: ^2.0.3 - flutter_local_notifications: ^16.3.0 flutter_localizations: sdk: flutter flutter_markdown: ^0.6.9 #flutter_markdown ^0.6.14 requires markdown ^7.0.0 diff --git a/test/app/shared/issuer/check_issuer_test.dart b/test/app/shared/issuer/check_issuer_test.dart new file mode 100644 index 000000000..8f1c68b42 --- /dev/null +++ b/test/app/shared/issuer/check_issuer_test.dart @@ -0,0 +1,170 @@ +import 'dart:convert'; + +import 'package:altme/app/app.dart'; +import 'package:altme/app/shared/issuer/models/organization_info.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:http_mock_adapter/http_mock_adapter.dart'; +import 'package:mockito/mockito.dart'; +import 'package:secure_storage/secure_storage.dart'; + +class MockSecureStorage extends Mock implements SecureStorageProvider {} + +void main() { + group('CheckIssuer', () { + late SecureStorageProvider mockSecureStorage; + + final client = Dio(); + late DioAdapter dioAdapter; + late DioClient mockClient; + + late CheckIssuer checkIssuer; + + const String checkIssuerServerUrl = 'https://example.com'; + final Uri uriToCheck = Uri.parse('https://example.com'); + + setUp(() { + TestWidgetsFlutterBinding.ensureInitialized(); + mockSecureStorage = MockSecureStorage(); + + dioAdapter = DioAdapter( + dio: Dio(BaseOptions()), matcher: const UrlRequestMatcher()); + client.httpClientAdapter = dioAdapter; + mockClient = DioClient( + baseUrl: 'https://example.com/', + secureStorageProvider: mockSecureStorage, + dio: client, + ); + checkIssuer = CheckIssuer( + mockClient, + checkIssuerServerUrl, + uriToCheck, + ); + }); + + test('should return empty issuer if checkIssuerServerUrl is empty', + () async { + final checkIssuer = CheckIssuer( + mockClient, + '', + uriToCheck, + ); + + final result = await checkIssuer.isIssuerInApprovedList(); + + expect( + jsonEncode(result), + equals(jsonEncode(Issuer.emptyIssuer(uriToCheck.host))), + ); + }); + + test('should return empty issuer if did does not start with did:ebsi', + () async { + final checkIssuer = CheckIssuer( + mockClient, + Urls.checkIssuerEbsiUrl, + Uri.parse('https://example.com'), + ); + + final result = await checkIssuer.isIssuerInApprovedList(); + + expect( + jsonEncode(result), + equals(jsonEncode(Issuer.emptyIssuer('example.com'))), + ); + }); + + test( + 'should return specific issuer for' + ' https://api.conformance.intebsi.xyz/trusted-issuers-registry/v2/issuers', + () async { + final checkIssuer = CheckIssuer( + mockClient, + 'https://api.conformance.intebsi.xyz/trusted-issuers-registry/v2/issuers', + Uri.parse('https://example.com?issuer=did:ebsi'), + ); + + final result = await checkIssuer.isIssuerInApprovedList(); + + final expected = Issuer( + preferredName: '', + did: [], + organizationInfo: OrganizationInfo( + legalName: 'sdf', + currentAddress: '', + id: '', + issuerDomain: [], + website: uriToCheck.host, + ), + ); + + expect( + jsonEncode(result), + equals(jsonEncode(expected)), + ); + }); + + test('should return valid issuer when issuer is in approved list', + () async { + final response = { + 'issuer': { + 'preferredName': 'Example Issuer', + 'did': ['did:example:123'], + 'organizationInfo': { + 'legalName': 'Example Org', + 'currentAddress': '123 Street', + 'id': 'org-123', + 'issuerDomain': ['example.com'], + 'website': 'example.com', + }, + }, + }; + + dioAdapter.onGet( + 'https://example.com/', + (request) => request.reply(200, response), + ); + + final result = await checkIssuer.isIssuerInApprovedList(); + + expect(result.preferredName, equals('Example Issuer')); + expect(result.organizationInfo.legalName, equals('Example Org')); + expect(result.organizationInfo.issuerDomain, contains('example.com')); + }); + + test( + 'should return empty issuer if organizationInfo.issuerDomain does not contain uriToCheck.host', + () async { + final response = { + 'issuer': { + 'preferredName': 'Example Issuer', + 'did': ['did:example:123'], + 'organizationInfo': { + 'legalName': 'Example Org', + 'currentAddress': '123 Street', + 'id': 'org-123', + 'issuerDomain': ['another.com'], + 'website': 'example.com', + }, + }, + }; + + dioAdapter.onGet( + 'https://example.com/', + (request) => request.reply(200, response), + ); + + final result = await checkIssuer.isIssuerInApprovedList(); + + expect(jsonEncode(result), + equals(jsonEncode(Issuer.emptyIssuer(uriToCheck.host)))); + }); + + test('should throw exception when an error occurs', () async { + expect( + () async => checkIssuer.isIssuerInApprovedList(), + throwsA(isA()), + ); + }); + }); +} diff --git a/test/app/shared/issuer/models/issuer_test.dart b/test/app/shared/issuer/models/issuer_test.dart new file mode 100644 index 000000000..86b8ca1ab --- /dev/null +++ b/test/app/shared/issuer/models/issuer_test.dart @@ -0,0 +1,65 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/app/shared/issuer/models/organization_info.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('Issuer', () { + test('Issuer fromJson should return a valid Issuer object', () { + final json = { + 'preferredName': 'Example Issuer', + 'did': ['did:example:123'], + 'organizationInfo': { + 'id': 'org-123', + 'legalName': 'Example Org', + 'currentAddress': '123 Street', + 'website': 'example.com', + 'issuerDomain': ['example.com'], + }, + }; + + final issuer = Issuer.fromJson(json); + + expect(issuer.preferredName, equals('Example Issuer')); + expect(issuer.did, equals(['did:example:123'])); + expect(issuer.organizationInfo.id, equals('org-123')); + expect(issuer.organizationInfo.legalName, equals('Example Org')); + expect(issuer.organizationInfo.currentAddress, equals('123 Street')); + expect(issuer.organizationInfo.website, equals('example.com')); + expect(issuer.organizationInfo.issuerDomain, equals(['example.com'])); + }); + + test('Issuer toJson should return a valid JSON map', () { + final organizationInfo = OrganizationInfo( + id: 'org-123', + legalName: 'Example Org', + currentAddress: '123 Street', + website: 'example.com', + issuerDomain: ['example.com'], + ); + + final issuer = Issuer( + preferredName: 'Example Issuer', + did: ['did:example:123'], + organizationInfo: organizationInfo, + ); + + final json = issuer.toJson(); + + expect(json['preferredName'], equals('Example Issuer')); + expect(json['did'], equals(['did:example:123'])); + expect(json['organizationInfo'], isA()); + }); + + test('Issuer.emptyIssuer should return an Issuer with default values', () { + final issuer = Issuer.emptyIssuer('example.com'); + + expect(issuer.preferredName, equals('')); + expect(issuer.did, isEmpty); + expect(issuer.organizationInfo.id, equals('')); + expect(issuer.organizationInfo.legalName, equals('')); + expect(issuer.organizationInfo.currentAddress, equals('')); + expect(issuer.organizationInfo.website, equals('example.com')); + expect(issuer.organizationInfo.issuerDomain, isEmpty); + }); + }); +} diff --git a/test/app/shared/issuer/models/organization_info_test.dart b/test/app/shared/issuer/models/organization_info_test.dart new file mode 100644 index 000000000..eb7d82165 --- /dev/null +++ b/test/app/shared/issuer/models/organization_info_test.dart @@ -0,0 +1,57 @@ +import 'package:altme/app/shared/issuer/models/organization_info.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('OrganizationInfo', () { + test( + 'OrganizationInfo fromJson should return a valid OrganizationInfo object', + () { + final json = { + 'id': 'org-123', + 'legalName': 'Example Org', + 'currentAddress': '123 Street', + 'website': 'example.com', + 'issuerDomain': ['example.com'], + }; + + final organizationInfo = OrganizationInfo.fromJson(json); + + expect(organizationInfo.id, equals('org-123')); + expect(organizationInfo.legalName, equals('Example Org')); + expect(organizationInfo.currentAddress, equals('123 Street')); + expect(organizationInfo.website, equals('example.com')); + expect(organizationInfo.issuerDomain, equals(['example.com'])); + }); + + test('OrganizationInfo toJson should return a valid JSON map', () { + final organizationInfo = OrganizationInfo( + id: 'org-123', + legalName: 'Example Org', + currentAddress: '123 Street', + website: 'example.com', + issuerDomain: ['example.com'], + ); + + final json = organizationInfo.toJson(); + + expect(json['id'], equals('org-123')); + expect(json['legalName'], equals('Example Org')); + expect(json['currentAddress'], equals('123 Street')); + expect(json['website'], equals('example.com')); + expect(json['issuerDomain'], equals(['example.com'])); + }); + + test( + 'OrganizationInfo.emptyOrganizationInfo should return an OrganizationInfo with default values', + () { + final organizationInfo = + OrganizationInfo.emptyOrganizationInfo('example.com'); + + expect(organizationInfo.id, equals('')); + expect(organizationInfo.legalName, equals('')); + expect(organizationInfo.currentAddress, equals('')); + expect(organizationInfo.website, equals('example.com')); + expect(organizationInfo.issuerDomain, isEmpty); + }); + }); +} diff --git a/test/app/shared/loading/loading_view_test.dart b/test/app/shared/loading/loading_view_test.dart new file mode 100644 index 000000000..e7bad840b --- /dev/null +++ b/test/app/shared/loading/loading_view_test.dart @@ -0,0 +1,57 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + +class MockProfileCubit extends Mock implements ProfileCubit { + @override + final state = ProfileState(model: ProfileModel.empty()); +} + +void main() { + group('LoadingView', () { + late ProfileCubit profileCubit; + + setUp(() { + profileCubit = MockProfileCubit(); + }); + + testWidgets('shows loading view correctly', (tester) async { + await tester.pumpWidget( + BlocProvider( + create: (context) => profileCubit, + child: MaterialApp( + home: Builder( + builder: (context) { + return Column( + children: [ + ElevatedButton( + onPressed: () { + LoadingView() + .show(context: context, text: 'Loading...'); + }, + child: const Text('Show Loading View'), + ), + ElevatedButton( + onPressed: () { + LoadingView().hide(); + }, + child: const Text('Hide Loading View'), + ), + ], + ); + }, + ), + ), + ), + ); + + await tester.pump(); + + expect(find.byType(LoadingView), findsNothing); + expect(find.text('Show Loading View'), findsOneWidget); + }); + }); +} From b89036dd93188987f36aecf42ad15b54a286b738 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 17 May 2024 13:49:14 +0545 Subject: [PATCH 51/56] remove some code of notification --- lib/bootstrap.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/bootstrap.dart b/lib/bootstrap.dart index 81fca4fd4..30398b6ae 100644 --- a/lib/bootstrap.dart +++ b/lib/bootstrap.dart @@ -8,7 +8,6 @@ import 'dart:async'; import 'dart:developer'; -import 'package:altme/app/app.dart'; import 'package:bloc/bloc.dart'; import 'package:dartez/dartez.dart'; import 'package:flutter/widgets.dart'; @@ -38,7 +37,6 @@ Future bootstrap(FutureOr Function() builder) async { () async { WidgetsFlutterBinding.ensureInitialized(); - await LocalNotification().init(); await initSecureStorage; /// Disable Http google font From 5b31de6d3a4f8bbc697ddbd90939f803c5fc4e69 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 17 May 2024 16:10:39 +0545 Subject: [PATCH 52/56] add more tests --- lib/app/shared/widget/default_dialog.dart | 4 +- .../blockchain_network_test.dart | 50 +++++++++++++++ .../tezos_network_test.dart | 50 +++++++++++++++ .../state_message/state_message_test.dart | 63 +++++++++++++++++++ .../shared/models/xtz_data/xtz_data_test.dart | 50 +++++++++++++++ test/app/shared/widget/copy_button_test.dart | 32 ++++++++++ .../widget/custom_listtile_card_test.dart | 55 ++++++++++++++++ .../shared/widget/default_dialog_test.dart | 55 ++++++++++++++++ .../widget/dialog_close_button_test.dart | 62 ++++++++++++++++++ test/app/shared/widget/error_view_test.dart | 30 +++++++++ .../shared/widget/grouped_section_test.dart | 29 +++++++++ 11 files changed, 478 insertions(+), 2 deletions(-) create mode 100644 test/app/shared/models/blockchain_network/blockchain_network_test.dart create mode 100644 test/app/shared/models/blockchain_network/tezos_network_test.dart create mode 100644 test/app/shared/models/state_message/state_message_test.dart create mode 100644 test/app/shared/models/xtz_data/xtz_data_test.dart create mode 100644 test/app/shared/widget/copy_button_test.dart create mode 100644 test/app/shared/widget/custom_listtile_card_test.dart create mode 100644 test/app/shared/widget/default_dialog_test.dart create mode 100644 test/app/shared/widget/dialog_close_button_test.dart create mode 100644 test/app/shared/widget/error_view_test.dart create mode 100644 test/app/shared/widget/grouped_section_test.dart diff --git a/lib/app/shared/widget/default_dialog.dart b/lib/app/shared/widget/default_dialog.dart index f60e08e43..9e0c95281 100644 --- a/lib/app/shared/widget/default_dialog.dart +++ b/lib/app/shared/widget/default_dialog.dart @@ -19,8 +19,8 @@ class DefaultDialog extends StatelessWidget { @override Widget build(BuildContext context) { return AlertDialog( - backgroundColor: Theme.of(context).colorScheme.popupBackground, - surfaceTintColor: Colors.transparent, + backgroundColor: Theme.of(context).colorScheme.popupBackground, + surfaceTintColor: Colors.transparent, contentPadding: const EdgeInsets.symmetric( horizontal: Sizes.spaceNormal, vertical: Sizes.spaceSmall, diff --git a/test/app/shared/models/blockchain_network/blockchain_network_test.dart b/test/app/shared/models/blockchain_network/blockchain_network_test.dart new file mode 100644 index 000000000..b484522cd --- /dev/null +++ b/test/app/shared/models/blockchain_network/blockchain_network_test.dart @@ -0,0 +1,50 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('BlockchainNetwork', () { + test('fromJson should create a BlockchainNetwork instance from JSON', () { + final json = { + 'networkname': 'TestNet', + 'apiUrl': 'https://example.com/api', + 'rpcNodeUrl': 'https://rpc.example.com', + 'title': 'Test Network', + 'subTitle': 'Subtitle', + 'type': 'ethereum', + 'apiKey': 'apikey', + }; + + final blockchainNetwork = BlockchainNetwork.fromJson(json); + + expect(blockchainNetwork.networkname, 'TestNet'); + expect(blockchainNetwork.apiUrl, 'https://example.com/api'); + expect(blockchainNetwork.rpcNodeUrl, 'https://rpc.example.com'); + expect(blockchainNetwork.title, 'Test Network'); + expect(blockchainNetwork.subTitle, 'Subtitle'); + expect(blockchainNetwork.type, BlockchainType.ethereum); + expect(blockchainNetwork.apiKey, 'apikey'); + }); + + test('toJson should convert a BlockchainNetwork instance to JSON', () { + const blockchainNetwork = BlockchainNetwork( + networkname: 'TestNet', + apiUrl: 'https://example.com/api', + rpcNodeUrl: 'https://rpc.example.com', + title: 'Test Network', + subTitle: 'Subtitle', + type: BlockchainType.ethereum, + apiKey: 'apikey', + ); + + final json = blockchainNetwork.toJson(); + + expect(json['networkname'], 'TestNet'); + expect(json['apiUrl'], 'https://example.com/api'); + expect(json['rpcNodeUrl'], 'https://rpc.example.com'); + expect(json['title'], 'Test Network'); + expect(json['subTitle'], 'Subtitle'); + expect(json['type'], 'ethereum'); + expect(json['apiKey'], 'apikey'); + }); + }); +} diff --git a/test/app/shared/models/blockchain_network/tezos_network_test.dart b/test/app/shared/models/blockchain_network/tezos_network_test.dart new file mode 100644 index 000000000..dab97499d --- /dev/null +++ b/test/app/shared/models/blockchain_network/tezos_network_test.dart @@ -0,0 +1,50 @@ +import 'package:altme/app/app.dart'; +import 'package:test/test.dart'; + +void main() { + group('TezosNetwork', () { + test('fromJson should create a TezosNetwork instance from JSON', () { + final json = { + 'networkname': 'TestNet', + 'apiUrl': 'https://example.com/api', + 'rpcNodeUrl': 'https://rpc.example.com', + 'title': 'Test Network', + 'subTitle': 'Subtitle', + 'type': 'tezos', + 'apiKey': 'apikey', + }; + + final tezosNetwork = TezosNetwork.fromJson(json); + + expect(tezosNetwork.networkname, 'TestNet'); + expect(tezosNetwork.apiUrl, 'https://example.com/api'); + expect(tezosNetwork.rpcNodeUrl, 'https://rpc.example.com'); + expect(tezosNetwork.title, 'Test Network'); + expect(tezosNetwork.subTitle, 'Subtitle'); + expect(tezosNetwork.type, BlockchainType.tezos); + expect(tezosNetwork.apiKey, 'apikey'); + }); + + test('toJson should convert a TezosNetwork instance to JSON', () { + const tezosNetwork = TezosNetwork( + networkname: 'TestNet', + apiUrl: 'https://example.com/api', + rpcNodeUrl: 'https://rpc.example.com', + title: 'Test Network', + subTitle: 'Subtitle', + type: BlockchainType.tezos, + apiKey: 'apikey', + ); + + final json = tezosNetwork.toJson(); + + expect(json['networkname'], 'TestNet'); + expect(json['apiUrl'], 'https://example.com/api'); + expect(json['rpcNodeUrl'], 'https://rpc.example.com'); + expect(json['title'], 'Test Network'); + expect(json['subTitle'], 'Subtitle'); + expect(json['type'], 'tezos'); + expect(json['apiKey'], 'apikey'); + }); + }); +} diff --git a/test/app/shared/models/state_message/state_message_test.dart b/test/app/shared/models/state_message/state_message_test.dart new file mode 100644 index 000000000..2467e27ba --- /dev/null +++ b/test/app/shared/models/state_message/state_message_test.dart @@ -0,0 +1,63 @@ +import 'package:test/test.dart'; +import 'package:altme/app/app.dart'; + +void main() { + group('StateMessage', () { + test('fromJson should create a StateMessage instance from JSON', () { + final json = { + 'type': 'error', + 'stringMessage': 'Error message', + 'showDialog': true, + 'duration': 1600, + }; + + final stateMessage = StateMessage.fromJson(json); + + expect(stateMessage.type, MessageType.error); + expect(stateMessage.stringMessage, 'Error message'); + expect(stateMessage.showDialog, isTrue); + expect(stateMessage.duration, const Duration(microseconds: 1600)); + }); + + test('toJson should convert a StateMessage instance to JSON', () { + const stateMessage = StateMessage( + type: MessageType.warning, + stringMessage: 'Warning message', + showDialog: false, + duration: Duration(microseconds: 2000), + ); + + final json = stateMessage.toJson(); + + expect(json['type'], 'warning'); + expect(json['stringMessage'], 'Warning message'); + expect(json['showDialog'], isFalse); + expect(json['duration'], 2000); + }); + + test('equality should compare StateMessage instances correctly', () { + const stateMessage1 = StateMessage( + type: MessageType.info, + stringMessage: 'Info message', + ); + const stateMessage2 = StateMessage( + type: MessageType.info, + stringMessage: 'Info message', + ); + const stateMessage3 = StateMessage( + type: MessageType.warning, + stringMessage: 'Warning message', + ); + + expect(stateMessage1, equals(stateMessage2)); + expect(stateMessage1, isNot(equals(stateMessage3))); + }); + + test('message types should have correct values', () { + expect(const StateMessage.error().type, MessageType.error); + expect(const StateMessage.warning().type, MessageType.warning); + expect(const StateMessage.info().type, MessageType.info); + expect(const StateMessage.success().type, MessageType.success); + }); + }); +} diff --git a/test/app/shared/models/xtz_data/xtz_data_test.dart b/test/app/shared/models/xtz_data/xtz_data_test.dart new file mode 100644 index 000000000..75cbfa95b --- /dev/null +++ b/test/app/shared/models/xtz_data/xtz_data_test.dart @@ -0,0 +1,50 @@ +import 'package:altme/app/app.dart'; +import 'package:test/test.dart'; + +void main() { + group('XtzData', () { + test('fromJson should create a XtzData instance from JSON', () { + final json = { + 'price': 3.5, + 'price24H': 3.7, + 'marketCap': 1000000000.0, + 'market24H': 900000000.0, + 'volume': 5000000.0, + 'volume24H': 6000000.0, + 'updated': '2023-05-17T15:25:00Z', + }; + + final xtzData = XtzData.fromJson(json); + + expect(xtzData.price, 3.5); + expect(xtzData.price24H, 3.7); + expect(xtzData.marketCap, 1000000000.0); + expect(xtzData.market24H, 900000000.0); + expect(xtzData.volume, 5000000.0); + expect(xtzData.volume24H, 6000000.0); + expect(xtzData.updated, DateTime.utc(2023, 5, 17, 15, 25, 0)); + }); + + test('toJson should convert a XtzData instance to JSON', () { + final xtzData = XtzData( + price: 3.5, + price24H: 3.7, + marketCap: 1000000000, + market24H: 900000000, + volume: 5000000, + volume24H: 6000000, + updated: DateTime.utc(2023, 5, 17, 15, 25, 0), + ); + + final json = xtzData.toJson(); + + expect(json['price'], 3.5); + expect(json['price24H'], 3.7); + expect(json['marketCap'], 1000000000.0); + expect(json['market24H'], 900000000.0); + expect(json['volume'], 5000000.0); + expect(json['volume24H'], 6000000.0); + expect(json['updated'], equals('2023-05-17T15:25:00.000Z')); + }); + }); +} diff --git a/test/app/shared/widget/copy_button_test.dart b/test/app/shared/widget/copy_button_test.dart new file mode 100644 index 000000000..ee810631c --- /dev/null +++ b/test/app/shared/widget/copy_button_test.dart @@ -0,0 +1,32 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + group('CopyButton', () { + testWidgets('CopyButton displays correctly', (tester) async { + await tester.pumpApp(const Scaffold(body: CopyButton())); + await tester.pumpAndSettle(); + expect(find.byType(Text), findsOneWidget); + expect(find.text('Copy'), findsOneWidget); + }); + + testWidgets('CopyButton responds to tap correctly', (tester) async { + bool triggerred = false; + await tester.pumpApp( + Scaffold( + body: CopyButton( + onTap: () { + triggerred = true; + }, + ), + ), + ); + await tester.tap(find.byType(InkWell)); + await tester.pumpAndSettle(); + expect(triggerred, isTrue); + }); + }); +} diff --git a/test/app/shared/widget/custom_listtile_card_test.dart b/test/app/shared/widget/custom_listtile_card_test.dart new file mode 100644 index 000000000..11a91f2df --- /dev/null +++ b/test/app/shared/widget/custom_listtile_card_test.dart @@ -0,0 +1,55 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('CustomListTileCard displays correctly and responds to tap', + (WidgetTester tester) async { + bool triggerred = false; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: CustomListTileCard( + title: 'Test Title', + subTitle: 'Test Subtitle', + imageAssetPath: 'assets/launcher_icon.png', + recommended: true, + onTap: () { + triggerred = true; + }, + ), + ), + ), + ); + + expect(find.text('Test Title'), findsOneWidget); + expect(find.text('Test Subtitle'), findsOneWidget); + expect(find.byType(Image), findsOneWidget); + expect(find.byType(Icon), findsOneWidget); + + expect(find.byIcon(Icons.thumb_up), findsOneWidget); + + await tester.tap(find.byType(ListTile)); + expect(triggerred, isTrue); + }); + + testWidgets( + 'CustomListTileCard does not display recommended icon when' + ' recommended is false', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: CustomListTileCard( + title: 'Test Title', + subTitle: 'Test Subtitle', + imageAssetPath: 'assets/launcher_icon.png', + recommended: false, + onTap: () {}, + ), + ), + ), + ); + + expect(find.byIcon(Icons.thumb_up), findsNothing); + }); +} diff --git a/test/app/shared/widget/default_dialog_test.dart b/test/app/shared/widget/default_dialog_test.dart new file mode 100644 index 000000000..3fe6488f1 --- /dev/null +++ b/test/app/shared/widget/default_dialog_test.dart @@ -0,0 +1,55 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:mockito/annotations.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + testWidgets('DefaultDialog displays title and description', + (WidgetTester tester) async { + const title = 'Test Title'; + const description = 'Test Description'; + + await tester.pumpApp( + const Scaffold( + body: DefaultDialog( + title: title, + description: description, + ), + ), + ); + + expect(find.text(title), findsOneWidget); + expect(find.text(description), findsOneWidget); + }); + + testWidgets( + 'DefaultDialog displays button with label and handles button click', + (WidgetTester tester) async { + bool triggerred = false; + const title = 'Test Title'; + const description = 'Test Description'; + const buttonLabel = 'Button'; + + await tester.pumpApp( + Scaffold( + body: DefaultDialog( + title: title, + description: description, + buttonLabel: buttonLabel, + onButtonClick: () { + triggerred = true; + }, + ), + ), + ); + + expect(find.byType(MyElevatedButton), findsOneWidget); + + await tester.tap(find.byType(MyElevatedButton)); + await tester.pumpAndSettle(); + expect(triggerred, isTrue); + }); +} diff --git a/test/app/shared/widget/dialog_close_button_test.dart b/test/app/shared/widget/dialog_close_button_test.dart new file mode 100644 index 000000000..6d1dc47d9 --- /dev/null +++ b/test/app/shared/widget/dialog_close_button_test.dart @@ -0,0 +1,62 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + testWidgets('DialogCloseButton displays text and icon', + (WidgetTester tester) async { + await tester.pumpApp( + const Scaffold(body: DialogCloseButton()), + ); + + expect(find.text('Close'), findsOneWidget); + expect(find.byIcon(Icons.close), findsOneWidget); + }); + + testWidgets('DialogCloseButton does not display text when showText is false', + (WidgetTester tester) async { + await tester.pumpApp( + const Scaffold(body: DialogCloseButton(showText: false)), + ); + + expect(find.text('Close'), findsNothing); + expect(find.byIcon(Icons.close), findsOneWidget); + }); + + testWidgets('DialogCloseButton closes the dialog when tapped', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (context) => Column( + children: [ + ElevatedButton( + onPressed: () { + showDialog( + context: context, + builder: (context) => const AlertDialog( + content: DialogCloseButton(), + ), + ); + }, + child: const Text('Open Dialog'), + ), + ], + ), + ), + ), + ); + + await tester.tap(find.text('Open Dialog')); + await tester.pumpAndSettle(); + + expect(find.byType(DialogCloseButton), findsOneWidget); + + await tester.tap(find.text('Close')); + await tester.pumpAndSettle(); + + expect(find.byType(DialogCloseButton), findsNothing); + }); +} diff --git a/test/app/shared/widget/error_view_test.dart b/test/app/shared/widget/error_view_test.dart new file mode 100644 index 000000000..49788ac30 --- /dev/null +++ b/test/app/shared/widget/error_view_test.dart @@ -0,0 +1,30 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + testWidgets('ErrorView displays message and try again button', + (WidgetTester tester) async { + const testMessage = 'An error occurred'; + bool wasButtonTapped = false; + + await tester.pumpApp( + ErrorView( + message: testMessage, + onTap: () { + wasButtonTapped = true; + }, + ), + ); + + expect(find.text(testMessage), findsOneWidget); + + expect(find.byType(MyOutlinedButton), findsOneWidget); + + await tester.tap(find.byType(MyOutlinedButton)); + await tester.pumpAndSettle(); + + expect(wasButtonTapped, isTrue); + }); +} diff --git a/test/app/shared/widget/grouped_section_test.dart b/test/app/shared/widget/grouped_section_test.dart new file mode 100644 index 000000000..00c38100e --- /dev/null +++ b/test/app/shared/widget/grouped_section_test.dart @@ -0,0 +1,29 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + testWidgets('GroupedSection renders children correctly', + (WidgetTester tester) async { + final testChildren = [ + const Text('Child 1'), + const Text('Child 2'), + const Text('Child 3'), + ]; + + await tester.pumpApp( + Scaffold( + body: GroupedSection( + children: testChildren, + ), + ), + ); + + // Verify the children are displayed + for (final child in testChildren) { + expect(find.byWidget(child), findsOneWidget); + } + }); +} From 2162f7ac54e46b9e1a194fc3c22c9af52f330d41 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 20 May 2024 18:12:22 +0545 Subject: [PATCH 53/56] Add some flutter tests --- lib/app/shared/translation/translation.dart | 1 + .../shared/translation/translation_test.dart | 51 ++++ .../wallet_address_validator_test.dart | 48 ++++ .../add_account/add_account_button_test.dart | 52 ++++ .../widget/base/otp_textfield_test.dart | 98 ++++++++ test/app/shared/widget/base/page_test.dart | 178 +++++++++++++- .../shared/widget/default_dialog_test.dart | 2 - test/app/shared/widget/imported_tag_test.dart | 19 ++ test/app/shared/widget/mnemonic_test.dart | 37 +++ test/app/shared/widget/my_rich_text_test.dart | 51 ++++ .../shared/widget/numeric_keyboard_test.dart | 162 +++++++++++++ .../shared/widget/powered_by_text_test.dart | 19 ++ test/app/shared/widget/share_button_test.dart | 36 +++ .../shared/widget/shimmer_widget_test.dart | 57 +++++ test/app/shared/widget/wallet_logo_test.dart | 222 ++++++++++++++++++ 15 files changed, 1024 insertions(+), 9 deletions(-) create mode 100644 test/app/shared/translation/translation_test.dart create mode 100644 test/app/shared/validators/wallet_address_validator_test.dart create mode 100644 test/app/shared/widget/add_account/add_account_button_test.dart create mode 100644 test/app/shared/widget/base/otp_textfield_test.dart create mode 100644 test/app/shared/widget/imported_tag_test.dart create mode 100644 test/app/shared/widget/mnemonic_test.dart create mode 100644 test/app/shared/widget/my_rich_text_test.dart create mode 100644 test/app/shared/widget/numeric_keyboard_test.dart create mode 100644 test/app/shared/widget/powered_by_text_test.dart create mode 100644 test/app/shared/widget/share_button_test.dart create mode 100644 test/app/shared/widget/shimmer_widget_test.dart create mode 100644 test/app/shared/widget/wallet_logo_test.dart diff --git a/lib/app/shared/translation/translation.dart b/lib/app/shared/translation/translation.dart index 81859b5f2..2a10e3731 100644 --- a/lib/app/shared/translation/translation.dart +++ b/lib/app/shared/translation/translation.dart @@ -9,6 +9,7 @@ class GetTranslation { String translation; final translated = translations.where((element) => element.language == l10n.localeName); + if (translated.isEmpty) { final List translationList = translations.where((element) => element.language == 'en').toList(); diff --git a/test/app/shared/translation/translation_test.dart b/test/app/shared/translation/translation_test.dart new file mode 100644 index 000000000..410ddf6ec --- /dev/null +++ b/test/app/shared/translation/translation_test.dart @@ -0,0 +1,51 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class MockAppLocalizations extends Mock implements AppLocalizations {} + +void main() { + group('GetTranslation', () { + late AppLocalizations l10n; + setUp(() { + l10n = MockAppLocalizations(); + }); + + test('returns translation for the locale if available', () { + final translations = [ + Translation('en', 'Hello'), + Translation('es', 'Hola'), + ]; + when(() => l10n.localeName).thenReturn('es'); + final result = GetTranslation.getTranslation(translations, l10n); + expect(result, 'Hola'); + }); + + test('falls back to English if locale translation is not available', () { + final translations = [ + Translation('en', 'Hello'), + Translation('es', 'Hola'), + ]; + when(() => l10n.localeName).thenReturn('fr'); + final result = GetTranslation.getTranslation(translations, l10n); + expect(result, 'Hello'); + }); + + test('returns empty string if no translations are available', () { + final translations = [ + Translation('fr', 'Bonjour'), + ]; + when(() => l10n.localeName).thenReturn('es'); + final result = GetTranslation.getTranslation(translations, l10n); + expect(result, ''); + }); + + test('returns empty string if translations list is empty', () { + final translations = []; + when(() => l10n.localeName).thenReturn('en'); + final result = GetTranslation.getTranslation(translations, l10n); + expect(result, ''); + }); + }); +} diff --git a/test/app/shared/validators/wallet_address_validator_test.dart b/test/app/shared/validators/wallet_address_validator_test.dart new file mode 100644 index 000000000..0fca3d1ae --- /dev/null +++ b/test/app/shared/validators/wallet_address_validator_test.dart @@ -0,0 +1,48 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +class WalletAddressValidatorImpl with WalletAddressValidator {} + +void main() { + group('WalletAddressValidator', () { + late WalletAddressValidatorImpl validator; + + setUp(() { + validator = WalletAddressValidatorImpl(); + }); + + test('returns false for null address', () { + expect(validator.validateWalletAddress(null), isFalse); + }); + + test('returns false for empty address', () { + expect(validator.validateWalletAddress(''), isFalse); + }); + + test('returns true for valid Ethereum address', () { + expect( + validator.validateWalletAddress( + '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'), + isTrue); + }); + + test('returns false for invalid Ethereum address', () { + expect(validator.validateWalletAddress('0x123'), isFalse); + }); + + test('returns true for valid Tezos address', () { + expect( + validator + .validateWalletAddress('tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb'), + isTrue); + }); + + test('returns false for invalid Tezos address', () { + expect(validator.validateWalletAddress('tz1short'), isFalse); + }); + + test('returns false for unsupported blockchain address', () { + expect(validator.validateWalletAddress('abc123'), isFalse); + }); + }); +} diff --git a/test/app/shared/widget/add_account/add_account_button_test.dart b/test/app/shared/widget/add_account/add_account_button_test.dart new file mode 100644 index 000000000..c54d24142 --- /dev/null +++ b/test/app/shared/widget/add_account/add_account_button_test.dart @@ -0,0 +1,52 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + group('AddAccountButton', () { + testWidgets('renders correctly', (tester) async { + await tester.pumpApp( + Scaffold( + body: AddAccountButton(onPressed: () {}), + ), + ); + + expect(find.byType(InkWell), findsOneWidget); + expect(find.byType(Container), findsOneWidget); + expect(find.byType(Column), findsOneWidget); + expect(find.byType(Row), findsOneWidget); + expect(find.byType(Image), findsOneWidget); + expect(find.byType(Text), findsNWidgets(2)); + }); + + testWidgets('displays correct text', (tester) async { + await tester.pumpApp( + Scaffold( + body: AddAccountButton(onPressed: () {}), + ), + ); + + expect(find.text('Add Account'), findsOneWidget); + expect(find.text('Create or import a new account.'), findsOneWidget); + }); + + testWidgets('triggers onPressed callback when tapped', (tester) async { + var click = false; + + await tester.pumpApp( + Scaffold( + body: AddAccountButton( + onPressed: () { + click = true; + }, + ), + ), + ); + + await tester.tap(find.byType(InkWell)); + expect(click, true); + }); + }); +} diff --git a/test/app/shared/widget/base/otp_textfield_test.dart b/test/app/shared/widget/base/otp_textfield_test.dart new file mode 100644 index 000000000..390068e64 --- /dev/null +++ b/test/app/shared/widget/base/otp_textfield_test.dart @@ -0,0 +1,98 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + group('OtpTextField', () { + late List controllers; + + setUp(() { + controllers = List.generate( + 6, + (index) => TextEditingController( + text: '', + ), + ); + }); + + testWidgets('renders correctly', (tester) async { + await tester.pumpApp( + Scaffold( + body: OtpTextField( + controllers: controllers, + index: 0, + autoFocus: false, + ), + ), + ); + + expect(find.byType(TextField), findsOneWidget); + }); + + testWidgets('autofocus works correctly', (tester) async { + await tester.pumpApp( + Scaffold( + body: OtpTextField( + controllers: controllers, + index: 0, + autoFocus: true, + ), + ), + ); + + await tester.pump(); + + final finder = find.byType(TextField); + expect(finder, findsOneWidget); + final textField = tester.widget(finder); + expect(textField.autofocus, true); + }); + + testWidgets('moves to next field when a digit is entered', (tester) async { + await tester.pumpApp( + Scaffold( + body: Row( + children: List.generate(6, (index) { + return OtpTextField( + controllers: controllers, + index: index, + autoFocus: index == 0, + ); + }), + ), + ), + ); + + await tester.enterText(find.byType(TextField).at(1), '1'); + await tester.pump(); + + expect(controllers[1].text, '1'); + expect( + FocusScope.of(tester.element(find.byType(TextField).at(1))).hasFocus, + true); + }); + + testWidgets('onTap moves cursor to end of text', (tester) async { + await tester.pumpApp( + Scaffold( + body: OtpTextField( + controllers: controllers, + index: 0, + autoFocus: true, + ), + ), + ); + await tester.tap(find.byType(TextField)); + await tester.pump(); + + expect( + controllers[0].selection, + TextSelection.fromPosition( + TextPosition(offset: controllers[0].text.length)), + ); + }); + }); +} diff --git a/test/app/shared/widget/base/page_test.dart b/test/app/shared/widget/base/page_test.dart index b71d975f4..c8800f802 100644 --- a/test/app/shared/widget/base/page_test.dart +++ b/test/app/shared/widget/base/page_test.dart @@ -21,6 +21,34 @@ void main() { expect(find.byType(CustomAppBar), findsNothing); }); + testWidgets( + 'does not renders CustomAppBar when title, titleTrailing and' + ' titleLeading are null and secure screen is true', (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + title: null, + titleTrailing: null, + titleLeading: null, + secureScreen: true, + ), + ); + expect(find.byType(CustomAppBar), findsNothing); + }); + + testWidgets( + 'renders CustomAppBar when title is provided and secure screen is true', + (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + title: 'I am title', + secureScreen: true, + ), + ); + expect(find.byType(CustomAppBar), findsOneWidget); + }); + testWidgets('renders CustomAppBar when title is provided', (tester) async { await tester.pumpApp(BasePage(body: Container(), title: 'I am title')); @@ -48,15 +76,151 @@ void main() { }); group('useSafeArea', () { - testWidgets('renders SafeArea when useSafeArea is true', (tester) async { - await tester.pumpApp(BasePage(body: Container(), useSafeArea: true)); - expect(find.byType(SafeArea), findsOneWidget); + group('renders SafeArea correctly when useSafeArea is true ', () { + testWidgets('navigation is provided', (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: true, + navigation: Container(), + ), + ); + expect(find.byType(SafeArea), findsNWidgets(2)); + }); + + testWidgets('scrollView is true', (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: true, + scrollView: true, + ), + ); + expect(find.byType(SafeArea), findsOneWidget); + }); + + testWidgets('scrollView is false', (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: true, + scrollView: false, + ), + ); + expect(find.byType(SafeArea), findsOneWidget); + }); + testWidgets('navigation is provided and secure screen is true', + (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: true, + secureScreen: true, + navigation: Container(), + ), + ); + expect(find.byType(SafeArea), findsNWidgets(2)); + }); + + testWidgets('scrollView is true and secure screen is true', + (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: true, + secureScreen: true, + scrollView: true, + ), + ); + expect(find.byType(SafeArea), findsOneWidget); + }); + + testWidgets('scrollView is false and secure screen is true', + (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: true, + scrollView: false, + secureScreen: true, + ), + ); + expect(find.byType(SafeArea), findsOneWidget); + }); }); - testWidgets('does not renders SafeArea when useSafeArea is false', - (tester) async { - await tester.pumpApp(BasePage(body: Container(), useSafeArea: false)); - expect(find.byType(SafeArea), findsNothing); + group('renders SafeArea correctly when useSafeArea is false ', () { + testWidgets(' navigation is provided', (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: false, + navigation: Container(), + ), + ); + expect(find.byType(SafeArea), findsNothing); + }); + + testWidgets('scrollView is true', (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: false, + scrollView: true, + ), + ); + expect(find.byType(SafeArea), findsNothing); + }); + + testWidgets('scrollView is false', (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: false, + scrollView: false, + ), + ); + expect(find.byType(SafeArea), findsNothing); + }); + + testWidgets('navigation is provided and secure screen is true', + (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: false, + secureScreen: true, + navigation: Container(), + ), + ); + expect(find.byType(SafeArea), findsNothing); + }); + + testWidgets('scrollView is true and secure screen is true', + (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: false, + secureScreen: true, + scrollView: true, + ), + ); + expect(find.byType(SafeArea), findsNothing); + }); + + testWidgets('scrollView is false and secure screen is true', + (tester) async { + await tester.pumpApp( + BasePage( + body: Container(), + useSafeArea: false, + scrollView: false, + secureScreen: true, + ), + ); + expect(find.byType(SafeArea), findsNothing); + }); }); }); }); diff --git a/test/app/shared/widget/default_dialog_test.dart b/test/app/shared/widget/default_dialog_test.dart index 3fe6488f1..b2081c46d 100644 --- a/test/app/shared/widget/default_dialog_test.dart +++ b/test/app/shared/widget/default_dialog_test.dart @@ -1,8 +1,6 @@ import 'package:altme/app/app.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:mockito/annotations.dart'; import '../../../helpers/helpers.dart'; diff --git a/test/app/shared/widget/imported_tag_test.dart b/test/app/shared/widget/imported_tag_test.dart new file mode 100644 index 000000000..139023b41 --- /dev/null +++ b/test/app/shared/widget/imported_tag_test.dart @@ -0,0 +1,19 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + group('ImportedTag', () { + testWidgets('renders importedTag', (tester) async { + await tester.pumpApp(const ImportedTag()); + expect(find.byType(Text), findsOneWidget); + }); + + testWidgets('renders value correctly', (tester) async { + await tester.pumpApp(const ImportedTag()); + expect(find.text('IMPORTED'), findsOneWidget); + }); + }); +} diff --git a/test/app/shared/widget/mnemonic_test.dart b/test/app/shared/widget/mnemonic_test.dart new file mode 100644 index 000000000..52f17dbed --- /dev/null +++ b/test/app/shared/widget/mnemonic_test.dart @@ -0,0 +1,37 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + testWidgets('MnemonicDisplay shows the correct words', + (WidgetTester tester) async { + final mnemonic = [ + 'apple', + 'banana', + 'cherry', + 'date', + 'elderberry', + 'fig', + 'grape', + 'honeydew', + 'kiwi', + 'lemon', + 'mango', + 'nectarine', + ]; + + await tester.pumpApp( + Scaffold( + body: MnemonicDisplay(mnemonic: mnemonic), + ), + ); + + await tester.pumpAndSettle(); + + for (int i = 0; i < mnemonic.length; i++) { + expect(find.text('${i + 1}. ${mnemonic[i]}'), findsOneWidget); + } + }); +} diff --git a/test/app/shared/widget/my_rich_text_test.dart b/test/app/shared/widget/my_rich_text_test.dart new file mode 100644 index 000000000..bdd263d26 --- /dev/null +++ b/test/app/shared/widget/my_rich_text_test.dart @@ -0,0 +1,51 @@ +import 'package:altme/app/app.dart'; +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + testWidgets('MyRichText displays the correct rich text', + (WidgetTester tester) async { + const textSpan = TextSpan( + text: 'Hello ', + children: [ + TextSpan( + text: 'World', + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], + ); + + await tester + .pumpApp(const Scaffold(body: MyRichText(text: textSpan, maxLines: 1))); + + await tester.pumpAndSettle(); + + expect(find.text('Hello World'), findsOneWidget); + }); + + testWidgets('MyRichText respects maxLines', (WidgetTester tester) async { + const longTextSpan = TextSpan( + text: 'This is a long text that should be truncated', + ); + + // Build the widget + await tester.pumpApp( + const Scaffold( + body: SizedBox( + width: 100, + child: MyRichText( + text: longTextSpan, + maxLines: 1, + ), + ), + ), + ); + + final richTextWidget = + tester.widget(find.byType(AutoSizeText)); + expect(richTextWidget.maxLines, 1); + }); +} diff --git a/test/app/shared/widget/numeric_keyboard_test.dart b/test/app/shared/widget/numeric_keyboard_test.dart new file mode 100644 index 000000000..4c44b452c --- /dev/null +++ b/test/app/shared/widget/numeric_keyboard_test.dart @@ -0,0 +1,162 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import '../../../helpers/helpers.dart'; + +class MockKeyboardTapCallback extends Mock { + void call(String text); +} + +void main() { + group('NumericKeyboard', () { + testWidgets('renders keyboard buttons correctly', (tester) async { + final mockCallback = MockKeyboardTapCallback(); + + await tester.pumpApp( + Scaffold( + body: NumericKeyboard( + keyboardUIConfig: const KeyboardUIConfig(), + onKeyboardTap: mockCallback.call, + allowAction: true, + ), + ), + ); + + expect(find.byType(KeyboardButton), findsNWidgets(10)); + }); + + testWidgets('tapping a keyboard button triggers the callback', + (tester) async { + final mockCallback = MockKeyboardTapCallback(); + + await tester.pumpApp( + Scaffold( + body: NumericKeyboard( + keyboardUIConfig: const KeyboardUIConfig(), + onKeyboardTap: mockCallback.call, + allowAction: true, + ), + ), + ); + + await tester.tap(find.text('1')); + verify(() => mockCallback.call('1')).called(1); + }); + }); + + group('KeyboardButton', () { + testWidgets('renders label correctly', (tester) async { + await tester.pumpApp( + Scaffold( + body: Scaffold( + body: KeyboardButton( + semanticsLabel: '1', + label: '1', + onTap: (_) {}, + allowAction: true, + ), + ), + ), + ); + + expect(find.text('1'), findsOneWidget); + }); + + testWidgets('renders icon correctly', (tester) async { + await tester.pumpApp( + Scaffold( + body: Scaffold( + body: KeyboardButton( + semanticsLabel: 'delete', + icon: const Icon(Icons.delete), + onTap: (_) {}, + allowAction: true, + ), + ), + ), + ); + + expect(find.byIcon(Icons.delete), findsOneWidget); + }); + + testWidgets('triggers onTap callback when tapped', (tester) async { + final mockCallback = MockKeyboardTapCallback(); + await tester.pumpApp( + Scaffold( + body: Scaffold( + body: KeyboardButton( + semanticsLabel: '1', + label: '1', + onTap: mockCallback.call, + allowAction: true, + ), + ), + ), + ); + + await tester.tap(find.text('1')); + verify(() => mockCallback.call('1')).called(1); + }); + + testWidgets('does not trigger onTap callback when disabled', + (tester) async { + final mockCallback = MockKeyboardTapCallback(); + await tester.pumpApp( + Scaffold( + body: Scaffold( + body: KeyboardButton( + semanticsLabel: '1', + label: '1', + onTap: mockCallback.call, + allowAction: false, + ), + ), + ), + ); + + await tester.tap(find.text('1')); + verifyNever(() => mockCallback.call(any())); + }); + + testWidgets('triggers onLongPress callback when long pressed', + (tester) async { + final mockCallback = MockKeyboardTapCallback(); + await tester.pumpApp( + Scaffold( + body: Scaffold( + body: KeyboardButton( + semanticsLabel: '1', + label: '1', + onLongPress: mockCallback.call, + allowAction: true, + ), + ), + ), + ); + + await tester.longPress(find.text('1')); + verify(() => mockCallback.call('1')).called(1); + }); + + testWidgets('does not trigger onLongPress callback when disabled', + (tester) async { + final mockCallback = MockKeyboardTapCallback(); + await tester.pumpApp( + Scaffold( + body: Scaffold( + body: KeyboardButton( + semanticsLabel: '1', + label: '1', + onLongPress: mockCallback.call, + allowAction: false, + ), + ), + ), + ); + + await tester.longPress(find.text('1')); + verifyNever(() => mockCallback.call(any())); + }); + }); +} diff --git a/test/app/shared/widget/powered_by_text_test.dart b/test/app/shared/widget/powered_by_text_test.dart new file mode 100644 index 000000000..a745ec7cb --- /dev/null +++ b/test/app/shared/widget/powered_by_text_test.dart @@ -0,0 +1,19 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + group('PoweredByText', () { + testWidgets('renders PoweredByText', (tester) async { + await tester.pumpApp(const PoweredByText()); + expect(find.byType(Text), findsOneWidget); + }); + + testWidgets('renders value correctly', (tester) async { + await tester.pumpApp(const PoweredByText()); + expect(find.text('Powered By ${Parameters.appName}'), findsOneWidget); + }); + }); +} diff --git a/test/app/shared/widget/share_button_test.dart b/test/app/shared/widget/share_button_test.dart new file mode 100644 index 000000000..af9532a79 --- /dev/null +++ b/test/app/shared/widget/share_button_test.dart @@ -0,0 +1,36 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + group('ShareButton', () { + testWidgets('ShareButton displays the correct icon and text', + (WidgetTester tester) async { + await tester.pumpApp(const Scaffold(body: ShareButton())); + + expect(find.byType(Image), findsOneWidget); + expect(find.text('Share'), findsOneWidget); + }); + + testWidgets('ShareButton responds to tap', (WidgetTester tester) async { + bool tapped = false; + + await tester.pumpApp( + Scaffold( + body: ShareButton( + onTap: () { + tapped = true; + }, + ), + ), + ); + + await tester.tap(find.byType(InkWell)); + await tester.pumpAndSettle(); + + expect(tapped, true); + }); + }); +} diff --git a/test/app/shared/widget/shimmer_widget_test.dart b/test/app/shared/widget/shimmer_widget_test.dart new file mode 100644 index 000000000..7781dd4e0 --- /dev/null +++ b/test/app/shared/widget/shimmer_widget_test.dart @@ -0,0 +1,57 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:shimmer/shimmer.dart'; +import '../../../helpers/helpers.dart'; + +void main() { + group('ShimmerWidget', () { + testWidgets('ShimmerWidget.rectangular displays correctly', + (WidgetTester tester) async { + await tester.pumpApp( + const Scaffold( + body: ShimmerWidget.rectangular(height: 100), + ), + ); + + expect(find.byType(Shimmer), findsOneWidget); + + final constraints = + tester.firstWidget(find.byType(Container)).constraints; + expect(constraints!.minWidth, double.infinity); + expect(constraints.maxWidth, double.infinity); + expect(constraints.minHeight, 100.0); + expect(constraints.maxHeight, 100.0); + + final container = tester.widget(find.byType(Container)); + + final shapeDecoration = container.decoration! as ShapeDecoration; + expect(shapeDecoration.shape, isA()); + final roundedRectBorder = shapeDecoration.shape as RoundedRectangleBorder; + expect( + roundedRectBorder.borderRadius, + const BorderRadius.all(Radius.circular(10)), + ); + }); + + testWidgets('ShimmerWidget.circular displays correctly', + (WidgetTester tester) async { + await tester.pumpApp( + const Scaffold(body: ShimmerWidget.circular(height: 100)), + ); + + expect(find.byType(Shimmer), findsOneWidget); + + final constraints = + tester.firstWidget(find.byType(Container)).constraints; + expect(constraints!.minWidth, double.infinity); + expect(constraints.maxWidth, double.infinity); + expect(constraints.minHeight, 100.0); + expect(constraints.maxHeight, 100.0); + + final container = tester.widget(find.byType(Container)); + final shapeDecoration = container.decoration! as ShapeDecoration; + expect(shapeDecoration.shape, isA()); + }); + }); +} diff --git a/test/app/shared/widget/wallet_logo_test.dart b/test/app/shared/widget/wallet_logo_test.dart new file mode 100644 index 000000000..5565c7fe9 --- /dev/null +++ b/test/app/shared/widget/wallet_logo_test.dart @@ -0,0 +1,222 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/flavor/flavor.dart'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +class MockFlavorCubit extends MockCubit implements FlavorCubit { + @override + final state = FlavorMode.development; +} + +void main() { + late FlavorCubit mockFlavorCubit; + + setUpAll(() { + mockFlavorCubit = MockFlavorCubit(); + }); + + group('WalletLogo widget', () { + testWidgets( + 'displays correct image for ProfileType.defaultOne in development', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (context) { + return BlocProvider( + create: (context) => mockFlavorCubit, + child: WalletLogo( + height: 100, + width: 100, + profileModel: ProfileModel.defaultOne( + polygonIdNetwork: PolygonIdNetwork.PolygonMainnet, + walletType: WalletType.personal, + walletProtectionType: WalletProtectionType.FA2, + isDeveloperMode: true, + clientId: 'clientId', + clientSecret: 'clientSecret', + ), + ), + ); + }, + ), + ), + ); + await tester.pumpAndSettle(); + + expect(find.byType(Image), findsOneWidget); + }); + + testWidgets('displays correct image for ProfileType.custom in development', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (context) { + return BlocProvider( + create: (context) => mockFlavorCubit, + child: WalletLogo( + height: 100, + width: 100, + profileModel: ProfileModel.empty(), + ), + ); + }, + ), + ), + ); + await tester.pumpAndSettle(); + + expect(find.byType(Image), findsOneWidget); + }); + + testWidgets('displays correct image for ProfileType.dutch in development', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (context) { + return BlocProvider( + create: (context) => mockFlavorCubit, + child: WalletLogo( + height: 100, + width: 100, + profileModel: ProfileModel.dutch( + polygonIdNetwork: PolygonIdNetwork.PolygonMainnet, + walletType: WalletType.personal, + walletProtectionType: WalletProtectionType.FA2, + isDeveloperMode: true, + clientId: 'clientId', + clientSecret: 'clientSecret', + ), + ), + ); + }, + ), + ), + ); + await tester.pumpAndSettle(); + + expect(find.byType(Image), findsOneWidget); + }); + + testWidgets('displays correct image for ProfileType.ebsiV3 in development', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (context) { + return BlocProvider( + create: (context) => mockFlavorCubit, + child: WalletLogo( + height: 100, + width: 100, + profileModel: ProfileModel.ebsiV3( + polygonIdNetwork: PolygonIdNetwork.PolygonMainnet, + walletType: WalletType.personal, + walletProtectionType: WalletProtectionType.FA2, + isDeveloperMode: true, + clientId: 'clientId', + clientSecret: 'clientSecret', + ), + ), + ); + }, + ), + ), + ); + await tester.pumpAndSettle(); + + expect(find.byType(Image), findsOneWidget); + }); + + testWidgets( + 'displays correct image for ProfileType.owfBaselineProfile in development', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (context) { + return BlocProvider( + create: (context) => mockFlavorCubit, + child: WalletLogo( + height: 100, + width: 100, + profileModel: ProfileModel.owfBaselineProfile( + polygonIdNetwork: PolygonIdNetwork.PolygonMainnet, + walletType: WalletType.personal, + walletProtectionType: WalletProtectionType.FA2, + isDeveloperMode: true, + clientId: 'clientId', + clientSecret: 'clientSecret', + ), + ), + ); + }, + ), + ), + ); + await tester.pumpAndSettle(); + + expect(find.byType(Image), findsOneWidget); + }); + + testWidgets( + 'displays correct image for ProfileType.enterprise in development', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (context) { + return BlocProvider( + create: (context) => mockFlavorCubit, + child: WalletLogo( + height: 100, + width: 100, + profileModel: ProfileModel( + polygonIdNetwork: PolygonIdNetwork.PolygonMainnet, + walletType: WalletType.personal, + walletProtectionType: WalletProtectionType.pinCode, + isDeveloperMode: false, + profileType: ProfileType.enterprise, + profileSetting: ProfileSetting( + blockchainOptions: BlockchainOptions.initial(), + discoverCardsOptions: DiscoverCardsOptions.initial(), + generalOptions: GeneralOptions( + walletType: WalletAppType.altme, + companyName: '', + companyWebsite: '', + companyLogo: 'https://www.demo.com', + tagLine: '', + splashScreenTitle: '', + profileName: '', + profileVersion: '', + published: DateTime.now(), + profileId: '', + customerPlan: '', + ), + helpCenterOptions: HelpCenterOptions.initial(), + selfSovereignIdentityOptions: + SelfSovereignIdentityOptions.initial(), + settingsMenu: SettingsMenu.initial(), + version: '', + walletSecurityOptions: WalletSecurityOptions.initial(), + ), + ), + ), + ); + }, + ), + ), + ); + await tester.pumpAndSettle(); + + expect(find.byType(CachedImageFromNetwork), findsOneWidget); + }); + }); +} From cb8c7939b6b9865e34cae0c75358d1159d2c262c Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 21 May 2024 14:13:47 +0545 Subject: [PATCH 54/56] Add dialog tests --- .../shared/widget/base/text_field_test.dart | 126 +++++++++++++++ .../widget/dialog/becareful_dialog_test.dart | 140 ++++++++++++++++ .../widget/dialog/confirm_dialog_test.dart | 150 ++++++++++++++++++ .../dialog/error_details_dialog_test.dart | 71 +++++++++ .../widget/dialog/error_dialog_test.dart | 56 +++++++ .../widget/dialog/text_field_dialog_test.dart | 54 +++++++ 6 files changed, 597 insertions(+) create mode 100644 test/app/shared/widget/base/text_field_test.dart create mode 100644 test/app/shared/widget/dialog/becareful_dialog_test.dart create mode 100644 test/app/shared/widget/dialog/confirm_dialog_test.dart create mode 100644 test/app/shared/widget/dialog/error_details_dialog_test.dart create mode 100644 test/app/shared/widget/dialog/error_dialog_test.dart create mode 100644 test/app/shared/widget/dialog/text_field_dialog_test.dart diff --git a/test/app/shared/widget/base/text_field_test.dart b/test/app/shared/widget/base/text_field_test.dart new file mode 100644 index 000000000..7cb47c1c9 --- /dev/null +++ b/test/app/shared/widget/base/text_field_test.dart @@ -0,0 +1,126 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + group('BaseTextField Widget Tests', () { + late TextEditingController controller; + + setUp(() { + controller = TextEditingController(); + }); + + testWidgets('renders BaseTextField with default properties', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: BaseTextField( + controller: controller, + ), + ), + ); + + expect(find.byType(TextFormField), findsOneWidget); + expect(find.byType(SizedBox), findsNWidgets(2)); + }); + + testWidgets('renders BaseTextField with label', + (WidgetTester tester) async { + const label = 'Test Label'; + + await tester.pumpApp( + Scaffold( + body: BaseTextField( + controller: controller, + label: label, + ), + ), + ); + + expect(find.text(label), findsOneWidget); + }); + + testWidgets('renders BaseTextField with hint', (WidgetTester tester) async { + const hint = 'Test Hint'; + + await tester.pumpApp( + Scaffold( + body: BaseTextField( + controller: controller, + hint: hint, + ), + ), + ); + + expect(find.text(hint), findsOneWidget); + }); + + testWidgets('renders BaseTextField with error text', + (WidgetTester tester) async { + const error = 'Test Error'; + + await tester.pumpApp( + Scaffold( + body: BaseTextField( + controller: controller, + error: error, + ), + ), + ); + + expect(find.text(error), findsOneWidget); + }); + + testWidgets('renders BaseTextField with prefix and suffix icons', + (WidgetTester tester) async { + const prefixIcon = Icon(Icons.email); + const suffixIcon = Icon(Icons.visibility); + + await tester.pumpApp( + Scaffold( + body: BaseTextField( + controller: controller, + prefixIcon: prefixIcon, + suffixIcon: suffixIcon, + ), + ), + ); + + expect(find.byIcon(Icons.email), findsOneWidget); + expect(find.byIcon(Icons.visibility), findsOneWidget); + }); + + testWidgets('input text updates the controller', + (WidgetTester tester) async { + const inputText = 'Hello, Flutter!'; + + await tester.pumpApp( + Scaffold( + body: BaseTextField( + controller: controller, + ), + ), + ); + + await tester.enterText(find.byType(TextFormField), inputText); + expect(controller.text, inputText); + }); + + testWidgets('obscureText property works correctly', + (WidgetTester tester) async { + await tester.pumpApp( + Scaffold( + body: BaseTextField( + controller: controller, + obscureText: true, + ), + ), + ); + + final TextField textField = tester.widget(find.byType(TextField)); + expect(textField.obscureText, isTrue); + }); + }); +} diff --git a/test/app/shared/widget/dialog/becareful_dialog_test.dart b/test/app/shared/widget/dialog/becareful_dialog_test.dart new file mode 100644 index 000000000..1afd7dc66 --- /dev/null +++ b/test/app/shared/widget/dialog/becareful_dialog_test.dart @@ -0,0 +1,140 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + group('BeCarefulDialog Widget Tests', () { + testWidgets('renders BeCarefulDialog with title', + (WidgetTester tester) async { + const title = 'Test Title'; + + await tester.pumpApp( + const Scaffold( + body: BeCarefulDialog( + title: title, + ), + ), + ); + + expect(find.text(title), findsOneWidget); + }); + + testWidgets('renders BeCarefulDialog with subtitle', + (WidgetTester tester) async { + const title = 'Test Title'; + const subtitle = 'Test Subtitle'; + + await tester.pumpApp( + const Scaffold( + body: BeCarefulDialog( + title: title, + subtitle: subtitle, + ), + ), + ); + + expect(find.text(title), findsOneWidget); + expect(find.text(subtitle), findsOneWidget); + }); + + testWidgets('renders BeCarefulDialog with yes and no buttons', + (WidgetTester tester) async { + const title = 'Test Title'; + const yesText = 'Yes'; + const noText = 'No'; + + await tester.pumpApp( + const Scaffold( + body: BeCarefulDialog( + title: title, + yes: yesText, + no: noText, + ), + ), + ); + + expect(find.text(yesText.toUpperCase()), findsOneWidget); + expect(find.text(noText.toUpperCase()), findsOneWidget); + }); + + testWidgets('clicking no button closes the dialog', + (WidgetTester tester) async { + const title = 'Test Title'; + const noText = 'No'; + + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (context) { + return ElevatedButton( + onPressed: () { + BeCarefulDialog.show( + context: context, + title: title, + no: noText, + ); + }, + child: const Text('Show Dialog'), + ); + }, + ), + ), + ); + + await tester.tap(find.text('Show Dialog')); + await tester.pumpAndSettle(); + + expect(find.text(title), findsOneWidget); + expect(find.text(noText.toUpperCase()), findsOneWidget); + + await tester.tap(find.text(noText.toUpperCase())); + await tester.pumpAndSettle(); + + expect(find.text(title), findsNothing); + }); + + testWidgets( + 'clicking yes button triggers onContinueClick and closes the dialog', + (WidgetTester tester) async { + const title = 'Test Title'; + const yesText = 'Yes'; + bool onContinueClicked = false; + + await tester.pumpApp( + Scaffold( + body: Builder( + builder: (context) { + return ElevatedButton( + onPressed: () { + BeCarefulDialog.show( + context: context, + title: title, + yes: yesText, + onContinueClick: () { + onContinueClicked = true; + }, + ); + }, + child: const Text('Show Dialog'), + ); + }, + ), + ), + ); + + await tester.tap(find.text('Show Dialog')); + await tester.pumpAndSettle(); + + expect(find.text(title), findsOneWidget); + expect(find.text(yesText.toUpperCase()), findsOneWidget); + + await tester.tap(find.text(yesText.toUpperCase())); + await tester.pumpAndSettle(); + + expect(find.text(title), findsNothing); + expect(onContinueClicked, isTrue); + }); + }); +} diff --git a/test/app/shared/widget/dialog/confirm_dialog_test.dart b/test/app/shared/widget/dialog/confirm_dialog_test.dart new file mode 100644 index 000000000..fbe07bd1f --- /dev/null +++ b/test/app/shared/widget/dialog/confirm_dialog_test.dart @@ -0,0 +1,150 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + group('ConfirmDialog Widget Tests', () { + testWidgets('renders ConfirmDialog with title', + (WidgetTester tester) async { + const title = 'Test Title'; + + await tester.pumpApp( + const ConfirmDialog( + title: title, + ), + ); + + expect(find.text(title), findsOneWidget); + }); + + testWidgets('renders ConfirmDialog with subtitle', + (WidgetTester tester) async { + const title = 'Test Title'; + const subtitle = 'Test Subtitle'; + + await tester.pumpApp( + const ConfirmDialog( + title: title, + subtitle: subtitle, + ), + ); + + expect(find.text(title), findsOneWidget); + expect(find.text(subtitle), findsOneWidget); + }); + + testWidgets('renders ConfirmDialog with yes and no buttons', + (WidgetTester tester) async { + const title = 'Test Title'; + const yesText = 'Yes'; + const noText = 'No'; + + await tester.pumpApp( + const ConfirmDialog( + title: title, + yes: yesText, + no: noText, + ), + ); + + expect(find.text(yesText.toUpperCase()), findsOneWidget); + expect(find.text(noText.toUpperCase()), findsOneWidget); + }); + + testWidgets('clicking no button closes the dialog with false', + (WidgetTester tester) async { + const title = 'Test Title'; + const noText = 'No'; + + await tester.pumpApp( + Builder( + builder: (context) { + return ElevatedButton( + onPressed: () { + showDialog( + context: context, + builder: (_) => const ConfirmDialog( + title: title, + no: noText, + ), + ); + }, + child: const Text('Show Dialog'), + ); + }, + ), + ); + + await tester.tap(find.text('Show Dialog')); + await tester.pumpAndSettle(); + + expect(find.text(title), findsOneWidget); + expect(find.text(noText.toUpperCase()), findsOneWidget); + + await tester + .tap(find.widgetWithText(MyOutlinedButton, noText.toUpperCase())); + await tester.pumpAndSettle(); + + expect(find.text(title), findsNothing); + }); + + testWidgets('clicking yes button closes the dialog with true', + (WidgetTester tester) async { + const title = 'Test Title'; + const yesText = 'Yes'; + bool? result; + + await tester.pumpApp( + Builder( + builder: (context) { + return ElevatedButton( + onPressed: () async { + result = await showDialog( + context: context, + builder: (_) => const ConfirmDialog( + title: title, + yes: yesText, + ), + ); + }, + child: const Text('Show Dialog'), + ); + }, + ), + ); + + await tester.tap(find.text('Show Dialog')); + await tester.pumpAndSettle(); + + expect(find.text(title), findsOneWidget); + expect(find.text(yesText.toUpperCase()), findsOneWidget); + + await tester + .tap(find.widgetWithText(MyElevatedButton, yesText.toUpperCase())); + await tester.pumpAndSettle(); + + expect(find.text(title), findsNothing); + expect(result, isTrue); + }); + + testWidgets( + 'ConfirmDialog shows only yes button when showNoButton is false', + (WidgetTester tester) async { + const title = 'Test Title'; + const yesText = 'Yes'; + const noText = 'No'; + + await tester.pumpApp(const ConfirmDialog( + title: title, + yes: yesText, + no: noText, + showNoButton: false, + )); + + expect(find.text(yesText.toUpperCase()), findsOneWidget); + expect(find.text(noText.toUpperCase()), findsNothing); + }); + }); +} diff --git a/test/app/shared/widget/dialog/error_details_dialog_test.dart b/test/app/shared/widget/dialog/error_details_dialog_test.dart new file mode 100644 index 000000000..9518cc48f --- /dev/null +++ b/test/app/shared/widget/dialog/error_details_dialog_test.dart @@ -0,0 +1,71 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + group('ErrorDetailsDialog Widget Tests', () { + testWidgets('renders ErrorDetailsDialog with error description', + (WidgetTester tester) async { + const errorDescription = 'An error occurred'; + + await tester.pumpApp( + const ErrorDetailsDialog( + erroDescription: errorDescription, + ), + ); + + expect(find.text(errorDescription), findsOneWidget); + }); + + testWidgets('renders ErrorDetailsDialog with more details link', + (WidgetTester tester) async { + const errorDescription = 'An error occurred'; + const errorUrl = 'https://example.com'; + + await tester.pumpApp( + const ErrorDetailsDialog( + erroDescription: errorDescription, + erroUrl: errorUrl, + ), + ); + + expect(find.text(errorDescription), findsOneWidget); + expect(find.text('More Details'), findsOneWidget); + }); + + testWidgets('clicking OK button closes the dialog', + (WidgetTester tester) async { + const errorDescription = 'An error occurred'; + + await tester.pumpApp( + Builder( + builder: (context) { + return ElevatedButton( + onPressed: () { + showDialog( + context: context, + builder: (_) => const ErrorDetailsDialog( + erroDescription: errorDescription, + ), + ); + }, + child: const Text('Show Dialog'), + ); + }, + ), + ); + + await tester.tap(find.text('Show Dialog')); + await tester.pumpAndSettle(); + + expect(find.text(errorDescription), findsOneWidget); + + await tester.tap(find.text('OK')); + await tester.pumpAndSettle(); + + expect(find.text(errorDescription), findsNothing); + }); + }); +} diff --git a/test/app/shared/widget/dialog/error_dialog_test.dart b/test/app/shared/widget/dialog/error_dialog_test.dart new file mode 100644 index 000000000..1e383c976 --- /dev/null +++ b/test/app/shared/widget/dialog/error_dialog_test.dart @@ -0,0 +1,56 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + group('ErrorDialog Widget Tests', () { + testWidgets( + 'displays the ErrorDialog with the correct title and description', + (WidgetTester tester) async { + const title = 'Error Title'; + const description = 'An error occurred'; + + await tester.pumpApp( + const Scaffold( + body: ErrorDialog( + title: title, + erroDescription: description, + ), + ), + ); + + expect(find.text(title), findsOneWidget); + expect(find.text('More Details'.toUpperCase()), findsOneWidget); + + await tester.tap(find.text('More Details'.toUpperCase())); + await tester.pumpAndSettle(); + + expect(find.byType(ErrorDetailsDialog), findsOneWidget); + expect(find.text(description), findsOneWidget); + }); + + testWidgets('Popup works correctly', (WidgetTester tester) async { + const title = 'Error Title'; + const description = 'An error occurred'; + + await tester.pumpApp( + const Scaffold( + body: ErrorDialog( + title: title, + erroDescription: description, + ), + ), + ); + + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('OK'), findsOneWidget); + + await tester.tap(find.text('OK')); + await tester.pumpAndSettle(); + + expect(find.byType(AlertDialog), findsNothing); + }); + }); +} diff --git a/test/app/shared/widget/dialog/text_field_dialog_test.dart b/test/app/shared/widget/dialog/text_field_dialog_test.dart new file mode 100644 index 000000000..267382bea --- /dev/null +++ b/test/app/shared/widget/dialog/text_field_dialog_test.dart @@ -0,0 +1,54 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + group('Text Field Dialog', () { + testWidgets('TextFieldDialog widget test', (WidgetTester tester) async { + await tester.pumpApp( + const TextFieldDialog( + title: 'Title', + label: 'Label', + subtitle: 'Subtitle', + initialValue: 'Initial Value', + yes: 'Yes', + no: 'No', + ), + ); + // Verify that the title, label, subtitle, and initial value are displayed. + expect(find.text('Title'), findsOneWidget); + expect(find.text('Label'), findsOneWidget); + expect(find.text('Subtitle'), findsOneWidget); + expect(find.text('Initial Value'), findsOneWidget); + + // Verify that the Yes and No buttons are displayed. + expect(find.text('Yes'.toUpperCase()), findsOneWidget); + expect(find.text('No'.toUpperCase()), findsOneWidget); + + // Tap on the Yes button and verify that the text is popped. + await tester.tap(find.text('Yes'.toUpperCase())); + await tester.pumpAndSettle(); + expect(find.text('Initial Value'), findsNothing); + }); + + testWidgets('Popup works correctly', (WidgetTester tester) async { + await tester.pumpApp( + const TextFieldDialog( + title: 'Title', + label: 'Label', + subtitle: 'Subtitle', + initialValue: 'Initial Value', + yes: 'Yes', + no: 'No', + ), + ); + + expect(find.text('No'.toUpperCase()), findsOneWidget); + + await tester.tap(find.text('No'.toUpperCase())); + await tester.pumpAndSettle(); + expect(find.text('No'.toUpperCase()), findsNothing); + }); + }); +} From a7083e83e5b736dea2a5ca9791f63de6712826ba Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 22 May 2024 15:33:24 +0545 Subject: [PATCH 55/56] add more tests --- .../m_webview/cubit/m_webview_cubit_test.dart | 28 +++++++ .../cubit/active_biometrics_cubit_test.dart | 77 +++++++++++++++++++ .../widgets/biometrics_switch_test.dart | 26 +++++++ .../cubit/onboarding_cubit_test.dart | 26 +++++++ .../tos/view/onboarding_tos_page_test.dart | 72 ++++++++++++++++- 5 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 test/app/shared/widget/m_webview/cubit/m_webview_cubit_test.dart create mode 100644 test/onboarding/activate_biometircs/cubit/active_biometrics_cubit_test.dart create mode 100644 test/onboarding/activate_biometircs/widgets/biometrics_switch_test.dart create mode 100644 test/onboarding/cubit/onboarding_cubit_test.dart diff --git a/test/app/shared/widget/m_webview/cubit/m_webview_cubit_test.dart b/test/app/shared/widget/m_webview/cubit/m_webview_cubit_test.dart new file mode 100644 index 000000000..c8c9953db --- /dev/null +++ b/test/app/shared/widget/m_webview/cubit/m_webview_cubit_test.dart @@ -0,0 +1,28 @@ +import 'package:altme/app/app.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('MWebViewCubit', () { + late MWebViewCubit cubit; + + setUp(() { + cubit = MWebViewCubit(); + }); + + tearDown(() { + cubit.close(); + }); + + test('initial state is true', () { + expect(cubit.state, true); + }); + + test('emits new state when setLoading is called', () { + expect(cubit.state, true); + cubit.setLoading(isLoading: false); + expect(cubit.state, false); + cubit.setLoading(isLoading: true); + expect(cubit.state, true); + }); + }); +} diff --git a/test/onboarding/activate_biometircs/cubit/active_biometrics_cubit_test.dart b/test/onboarding/activate_biometircs/cubit/active_biometrics_cubit_test.dart new file mode 100644 index 000000000..15a5c1ee7 --- /dev/null +++ b/test/onboarding/activate_biometircs/cubit/active_biometrics_cubit_test.dart @@ -0,0 +1,77 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/onboarding/onboarding.dart'; + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class MockProfileCubit extends MockCubit + implements ProfileCubit {} + +void main() { + group('ActiveBiometricsCubit', () { + late ActiveBiometricsCubit activeBiometricsCubit; + late MockProfileCubit mockProfileCubit; + + setUp(() { + mockProfileCubit = MockProfileCubit(); + + activeBiometricsCubit = + ActiveBiometricsCubit(profileCubit: mockProfileCubit); + }); + + test('initial state is false', () { + expect(activeBiometricsCubit.state, false); + }); + + blocTest( + 'load emits true if walletProtectionType is FA2 or biometrics', + build: () { + when(() => mockProfileCubit.state).thenReturn( + ProfileState( + model: ProfileModel( + polygonIdNetwork: PolygonIdNetwork.PolygonMainnet, + walletType: WalletType.personal, + walletProtectionType: WalletProtectionType.biometrics, + isDeveloperMode: false, + profileType: ProfileType.custom, + profileSetting: ProfileSetting.initial(), + ), + ), + ); + return activeBiometricsCubit; + }, + act: (cubit) => cubit.load(), + expect: () => [true], + ); + + blocTest( + 'load emits false if walletProtectionType is not FA2 or biometrics', + build: () { + when(() => mockProfileCubit.state).thenReturn( + ProfileState( + model: ProfileModel( + polygonIdNetwork: PolygonIdNetwork.PolygonMainnet, + walletType: WalletType.personal, + walletProtectionType: WalletProtectionType.pinCode, + isDeveloperMode: false, + profileType: ProfileType.custom, + profileSetting: ProfileSetting.initial(), + ), + ), + ); + return activeBiometricsCubit; + }, + act: (cubit) => cubit.load(), + expect: () => [false], + ); + + blocTest( + 'updateSwitch emits the provided value', + build: () => activeBiometricsCubit, + act: (cubit) => cubit.updateSwitch(value: true), + expect: () => [true], + ); + }); +} diff --git a/test/onboarding/activate_biometircs/widgets/biometrics_switch_test.dart b/test/onboarding/activate_biometircs/widgets/biometrics_switch_test.dart new file mode 100644 index 000000000..99b51d0e8 --- /dev/null +++ b/test/onboarding/activate_biometircs/widgets/biometrics_switch_test.dart @@ -0,0 +1,26 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/onboarding/onboarding.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + group('BiometricsSwitch', () { + testWidgets('renders value correctly', (tester) async { + await tester.pumpApp(const BiometricsSwitch(value: true)); + + expect( + find.byWidgetPredicate( + (widget) => + widget is Image && + widget.image is AssetImage && + (widget.image as AssetImage).assetName == + IconStrings.fingerprint2, + ), + findsOneWidget, + ); + expect(find.byType(CupertinoSwitch), findsOneWidget); + }); + }); +} diff --git a/test/onboarding/cubit/onboarding_cubit_test.dart b/test/onboarding/cubit/onboarding_cubit_test.dart new file mode 100644 index 000000000..374f128f9 --- /dev/null +++ b/test/onboarding/cubit/onboarding_cubit_test.dart @@ -0,0 +1,26 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/onboarding/cubit/onboarding_cubit.dart'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('OnboardingCubit', () { + test('initial state is correct', () { + expect(OnboardingCubit().state, const OnboardingState()); + }); + + blocTest( + 'emits [loading] when emitOnboardingProcessing is called', + build: OnboardingCubit.new, + act: (cubit) => cubit.emitOnboardingProcessing(), + expect: () => [const OnboardingState(status: AppStatus.loading)], + ); + + blocTest( + 'emits [success] when emitOnboardingDone is called', + build: OnboardingCubit.new, + act: (cubit) => cubit.emitOnboardingDone(), + expect: () => [const OnboardingState(status: AppStatus.success)], + ); + }); +} diff --git a/test/onboarding/tos/view/onboarding_tos_page_test.dart b/test/onboarding/tos/view/onboarding_tos_page_test.dart index f22ac1175..9e0050464 100644 --- a/test/onboarding/tos/view/onboarding_tos_page_test.dart +++ b/test/onboarding/tos/view/onboarding_tos_page_test.dart @@ -1,12 +1,26 @@ import 'package:altme/app/app.dart'; import 'package:altme/onboarding/onboarding.dart'; +import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; import '../../../helpers/helpers.dart'; +class MockOnBoardingTosCubit extends MockCubit + implements OnBoardingTosCubit {} + void main() { group('OnBoarding Terms Page', () { + late MockOnBoardingTosCubit onBoardingTosCubit; + + setUpAll(() { + onBoardingTosCubit = MockOnBoardingTosCubit(); + when(() => onBoardingTosCubit.state) + .thenReturn(const OnBoardingTosState()); + }); + testWidgets('is routable', (tester) async { await tester.pumpApp( Builder( @@ -25,9 +39,14 @@ void main() { }); testWidgets('renders OnBoardingTosPage', (tester) async { - await tester.pumpApp(const OnBoardingTosPage()); + await tester.pumpApp( + BlocProvider.value( + value: onBoardingTosCubit, + child: const OnBoardingTosPage(), + ), + ); await tester.pumpAndSettle(); - expect(find.byType(OnBoardingTosPage), findsOneWidget); + expect(find.byType(OnBoardingTosView), findsOneWidget); }); testWidgets('nothing happens when button is pressed', (tester) async { @@ -37,6 +56,32 @@ void main() { expect(find.byType(OnBoardingTosPage), findsOneWidget); }); + // testWidgets('checkboxes toggle state', (WidgetTester tester) async { + // when(() => onBoardingTosCubit.setAgreeTerms( + // agreeTerms: any(named: 'agreeTerms'))).thenAnswer((_) async {}); + // when(() => onBoardingTosCubit.setReadTerms( + // readTerms: any(named: 'readTerms'))).thenAnswer((_) async {}); + + // await tester.pumpApp( + // BlocProvider( + // create: (_) => onBoardingTosCubit, + // child: const OnBoardingTosPage(), + // ), + // ); + + // final agreeCheckbox = find.text('I agree to the terms and conditions.'); + // final readCheckbox = find.text('I have read the terms of use.'); + + // expect(agreeCheckbox, findsOneWidget); + // expect(readCheckbox, findsOneWidget); + + // await tester.tap(agreeCheckbox); + // await tester.pumpAndSettle(); + + // verify(() => onBoardingTosCubit.setAgreeTerms(agreeTerms: true)) + // .called(1); + // }); + testWidgets('blocks going back from OnBoardingTosPage start page', (tester) async { await tester.pumpApp(const OnBoardingTosPage()); @@ -46,6 +91,29 @@ void main() { expect(find.byType(OnBoardingTosPage), findsOneWidget); }); + testWidgets( + 'MyGradientButton press calls onAcceptancePressed', + (WidgetTester tester) async { + await tester.pumpApp( + BlocProvider.value( + value: onBoardingTosCubit, + child: const OnBoardingTosPage(), + ), + ); + + when(() => onBoardingTosCubit.state).thenReturn( + const OnBoardingTosState( + agreeTerms: true, + readTerms: true, + ), + ); + await tester.pump(); + + final button = find.text('Start'.toUpperCase()); + expect(button, findsOneWidget); + }, + ); + testWidgets('renders DisplayTerms', (tester) async { await tester.pumpApp(const OnBoardingTosPage()); await tester.pumpAndSettle(); From d6a8815255048400c2e7efb046db009787a877e1 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 22 May 2024 18:57:55 +0545 Subject: [PATCH 56/56] some onboarding tests --- .../view/onboarding_gen_phrase.dart | 2 +- .../cubit/onboarding_state_test.dart | 22 ++ .../onboarding_gen_phrase_cubit_test.dart | 63 ------ .../view/onboarding_gen_phrase_test.dart | 190 ++++++++++++++++++ 4 files changed, 213 insertions(+), 64 deletions(-) create mode 100644 test/onboarding/cubit/onboarding_state_test.dart delete mode 100644 test/onboarding/gen_phrase/cubit/onboarding_gen_phrase_cubit_test.dart create mode 100644 test/onboarding/gen_phrase/view/onboarding_gen_phrase_test.dart diff --git a/lib/onboarding/gen_phrase/view/onboarding_gen_phrase.dart b/lib/onboarding/gen_phrase/view/onboarding_gen_phrase.dart index 6ba772041..91014351a 100644 --- a/lib/onboarding/gen_phrase/view/onboarding_gen_phrase.dart +++ b/lib/onboarding/gen_phrase/view/onboarding_gen_phrase.dart @@ -175,7 +175,7 @@ class _OnBoardingGenPhraseViewState extends State { text: l10n.verifyNow, verticalSpacing: 18, onPressed: () { - Navigator.of(context).push( + Navigator.of(context).push( OnBoardingVerifyPhrasePage.route( mnemonic: mnemonic!, isFromOnboarding: true, diff --git a/test/onboarding/cubit/onboarding_state_test.dart b/test/onboarding/cubit/onboarding_state_test.dart new file mode 100644 index 000000000..7c49892f9 --- /dev/null +++ b/test/onboarding/cubit/onboarding_state_test.dart @@ -0,0 +1,22 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/onboarding/cubit/onboarding_cubit.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('OnboardingState', () { + test('can be instantiated from JSON', () { + final json = {'status': 'init'}; + + final onboardingState = OnboardingState.fromJson(json); + + expect(onboardingState.status, AppStatus.init); + }); + + test('can be converted to JSON', () { + const onboardingState = OnboardingState(status: AppStatus.init); + final json = onboardingState.toJson(); + + expect(json, {'status': 'init'}); + }); + }); +} diff --git a/test/onboarding/gen_phrase/cubit/onboarding_gen_phrase_cubit_test.dart b/test/onboarding/gen_phrase/cubit/onboarding_gen_phrase_cubit_test.dart deleted file mode 100644 index b54c63dae..000000000 --- a/test/onboarding/gen_phrase/cubit/onboarding_gen_phrase_cubit_test.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:key_generator/key_generator.dart'; - -Future main() async { - final keyGenerator = KeyGenerator(); - group('from mnemonic for ssi', () { - const String mnemonic = - '''brief hello carry loop squeeze unknown click abstract lounge figure logic oblige child ripple about vacant scheme magnet open enroll stuff valve hobby what'''; - - test('jwk', () async { - final jwk = await keyGenerator.jwkFromMnemonic( - mnemonic: mnemonic, - accountType: AccountType.ssi, - ); - const expectedJwk = - '''{"kty":"OKP","crv":"Ed25519","d":"xgGv1OK9734J-_INYW3Ff7m0Cpkfhucx2Tg1w3LUOKI=","x":"tZT6dwnPD87v2MCzAlzPsrT6l06_YyyUsk-Y-mnR0sU="}'''; - expect(jwk, equals(expectedJwk)); - }); - - test('address', () async { - final address = await keyGenerator.walletAddressFromMnemonic( - mnemonic: mnemonic, - accountType: AccountType.tezos, - ); - const expectedAddress = 'tz1guoPjyUSs5N6UWoMxESSyPyUTJwqDgS3d'; - expect(address, equals(expectedAddress)); - }); - - test('secret key', () async { - final secretKey = await keyGenerator.secretKeyFromMnemonic( - mnemonic: mnemonic, - accountType: AccountType.ethereum, - ); - const expectedSecretKey = - '''0xc9d610aaf2b4c20b805a1e877637433d63f03c5a0d68d744e9e524efdd7259fd'''; - expect(secretKey, equals(expectedSecretKey)); - }); - }); - group('from secretKey : Tezos', () { - const String secretKey = - '''edskRrmNgPfAAvbZyzTptfvTju9X7ooLR5VVN9u8sXA42hXdMBd8CgrhykP7sZQf8hWLCYuqfEoWUFzL6Us3aKtMD9NsELGkuP'''; - - test('jwk', () async { - final jwk = await keyGenerator.jwkFromSecretKey( - secretKey: secretKey, - accountType: AccountType.tezos, - ); - const expectedJwk = - '''{"kty":"OKP","crv":"Ed25519","d":"cMGD8eAmjDn6MqvJoscsaPoyAMrjG41xbLDfE-uQkYw=","x":"-PeGBkVyMz2-yketwH2lbQqiflneee3jmaTafMCsURE="}'''; - expect(jwk, equals(expectedJwk)); - }); - - test('address', () async { - final address = await keyGenerator.walletAddressFromSecretKey( - secretKey: secretKey, - accountType: AccountType.tezos, - ); - - const expectedAddress = 'tz1NvqicaUW7v6sEbM4UYi3Wes7GHDft4kqY'; - expect(address, equals(expectedAddress)); - }); - }); -} diff --git a/test/onboarding/gen_phrase/view/onboarding_gen_phrase_test.dart b/test/onboarding/gen_phrase/view/onboarding_gen_phrase_test.dart new file mode 100644 index 000000000..169d425eb --- /dev/null +++ b/test/onboarding/gen_phrase/view/onboarding_gen_phrase_test.dart @@ -0,0 +1,190 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/chat_room/chat_room.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/onboarding/onboarding.dart'; +import 'package:altme/splash/splash.dart'; +import 'package:altme/wallet/wallet.dart'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:did_kit/did_kit.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:key_generator/key_generator.dart'; +import 'package:mockingjay/mockingjay.dart'; +import 'package:secure_storage/secure_storage.dart'; + +import '../../../helpers/helpers.dart'; + +class MockSecureStorage extends Mock implements SecureStorageProvider {} + +class MockDIDKitProvider extends Mock implements DIDKitProvider {} + +class MockKeyGenerator extends Mock implements KeyGenerator {} + +class MockHomeCubit extends MockCubit implements HomeCubit { + @override + Future emitHasWallet() async {} +} + +class MockWalletCubit extends MockCubit implements WalletCubit { + @override + final state = WalletState( + cryptoAccount: CryptoAccount( + data: [ + CryptoAccountData( + name: '', + secretKey: '', + blockchainType: BlockchainType.tezos, + walletAddress: '', + ), + ], + ), + ); + + @override + Future createCryptoWallet({ + String? accountName, + required String mnemonicOrKey, + required bool isImported, + required bool isFromOnboarding, + BlockchainType? blockchainType, + bool showStatus = true, + void Function({ + required CryptoAccount cryptoAccount, + required MessageHandler messageHandler, + })? onComplete, + }) async {} +} + +class MockSplashCubit extends MockCubit implements SplashCubit {} + +class MockAltmeChatSupportCubit extends MockCubit + implements AltmeChatSupportCubit {} + +class MockProfileCubit extends MockCubit implements ProfileCubit { + @override + final state = ProfileState(model: ProfileModel.empty()); +} + +void main() { + late SecureStorageProvider mockSecureStorage; + late DIDKitProvider didKitProvider; + late KeyGenerator keyGenerator; + late HomeCubit homeCubit; + late WalletCubit walletCubit; + late SplashCubit splashCubit; + late AltmeChatSupportCubit altmeChatSupportCubit; + late ProfileCubit profileCubit; + + setUpAll(() { + WidgetsFlutterBinding.ensureInitialized(); + mockSecureStorage = MockSecureStorage(); + didKitProvider = MockDIDKitProvider(); + keyGenerator = MockKeyGenerator(); + homeCubit = MockHomeCubit(); + splashCubit = MockSplashCubit(); + walletCubit = MockWalletCubit(); + altmeChatSupportCubit = MockAltmeChatSupportCubit(); + profileCubit = MockProfileCubit(); + + when(() => mockSecureStorage.set(any(), any())).thenAnswer((_) async {}); + when(() => mockSecureStorage.get(any())).thenAnswer((_) async {}); + }); + + group('OnBoarding GenPhrase Page', () { + late OnBoardingGenPhraseCubit onBoardingGenPhraseCubit; + + late MockNavigator navigator; + + setUpAll(() { + onBoardingGenPhraseCubit = OnBoardingGenPhraseCubit( + secureStorageProvider: mockSecureStorage, + didKitProvider: didKitProvider, + keyGenerator: keyGenerator, + homeCubit: homeCubit, + walletCubit: walletCubit, + splashCubit: splashCubit, + altmeChatSupportCubit: altmeChatSupportCubit, + profileCubit: profileCubit, + ); + navigator = MockNavigator(); + when(navigator.canPop).thenReturn(true); + + when(() => navigator.push(any())).thenAnswer((_) async {}); + }); + + testWidgets('is routable', (tester) async { + await tester.pumpApp( + MockNavigatorProvider( + navigator: navigator, + child: Builder( + builder: (context) => Scaffold( + floatingActionButton: FloatingActionButton( + onPressed: () { + Navigator.of(context) + .push(OnBoardingVerifyPhrasePage.route( + isFromOnboarding: true, + mnemonic: [], + )); + }, + ), + ), + ), + ), + ); + await tester.tap(find.byType(FloatingActionButton)); + await tester.pumpAndSettle(); + + verify( + () => navigator.push( + any( + that: isRoute( + whereName: equals('/OnBoardingVerifyPhrasePage'), + ), + ), + ), + ).called(1); + }); + + testWidgets('renders UI correctly', (tester) async { + await tester.pumpApp( + BlocProvider.value( + value: onBoardingGenPhraseCubit, + child: const OnBoardingGenPhraseView(), + ), + ); + + expect(find.byType(BasePage), findsOneWidget); + expect(find.byType(MStepper), findsOneWidget); + expect(find.byType(MnemonicDisplay), findsOneWidget); + expect(find.byType(MyElevatedButton), findsOneWidget); + expect(find.byType(MyGradientButton), findsOneWidget); + }); + + testWidgets( + 'navigates to OnBoardingVerifyPhrasePage when Verify Now button' + ' is tapped', (tester) async { + await tester.pumpApp( + MockNavigatorProvider( + navigator: navigator, + child: BlocProvider.value( + value: onBoardingGenPhraseCubit, + child: const OnBoardingGenPhraseView(), + ), + ), + ); + + await tester.tap(find.text('Verify Now'.toUpperCase())); + + verify( + () => navigator.push( + any( + that: isRoute( + whereName: equals('/OnBoardingVerifyPhrasePage'), + ), + ), + ), + ).called(1); + }); + }); +}