├── .editorconfig ├── .github ├── FUNDING.yml └── workflows │ ├── build.yaml │ └── publish.yml ├── .gitignore ├── .idea └── .idea.Xamarin.Forms.TestingLibrary │ └── .idea │ ├── .gitignore │ ├── indexLayout.xml │ ├── misc.xml │ └── vcs.xml ├── LICENSE ├── README.md ├── Xamarin.Forms.TestingLibrary.sln ├── build.cake ├── build.ps1 ├── build.sh ├── samples └── Xamarin.Forms.TestingLibrary.SampleApp │ ├── Xamarin.Forms.TestingLibrary.SampleApp.Android │ ├── Assets │ │ └── AboutAssets.txt │ ├── MainActivity.cs │ ├── Properties │ │ ├── AndroidManifest.xml │ │ └── AssemblyInfo.cs │ ├── Resources │ │ ├── AboutResources.txt │ │ ├── Resource.designer.cs │ │ ├── layout │ │ │ ├── Tabbar.axml │ │ │ └── Toolbar.axml │ │ └── values │ │ │ ├── colors.xml │ │ │ └── styles.xml │ └── Xamarin.Forms.TestingLibrary.SampleApp.Android.csproj │ ├── Xamarin.Forms.TestingLibrary.SampleApp.Tests │ ├── UnitTest1.cs │ └── Xamarin.Forms.TestingLibrary.SampleApp.Tests.csproj │ ├── Xamarin.Forms.TestingLibrary.SampleApp.iOS │ ├── AppDelegate.cs │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Entitlements.plist │ ├── Info.plist │ ├── Main.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Resources │ │ ├── LaunchScreen.storyboard │ │ └── image1.png │ └── Xamarin.Forms.TestingLibrary.SampleApp.iOS.csproj │ └── Xamarin.Forms.TestingLibrary.SampleApp │ ├── App.xaml │ ├── App.xaml.cs │ ├── Controls │ └── CustomStackLayout.cs │ ├── Converters │ └── IsNullOrEmptyConverter.cs │ ├── MainPageViewModel.cs │ ├── Pages │ ├── EmptyPage.xaml │ ├── EmptyPage.xaml.cs │ ├── Example1Page.xaml │ ├── Example1Page.xaml.cs │ ├── MainPage.xaml │ └── MainPage.xaml.cs │ ├── ViewModels │ └── Example1PageViewModel.cs │ └── Xamarin.Forms.TestingLibrary.SampleApp.csproj ├── src └── Xamarin.Forms.TestingLibrary │ ├── .idea │ └── .idea.Xamarin.Forms.TestingLibrary │ │ └── .idea │ │ ├── .gitignore │ │ ├── indexLayout.xml │ │ ├── misc.xml │ │ └── vcs.xml │ ├── Diagnostics │ ├── DebugElement.cs │ ├── IDebugElement.cs │ ├── Tree.cs │ └── TreeNode.cs │ ├── Extensions │ ├── BindableObjectExtensions.cs │ └── ViewExtensions.cs │ ├── FormsProxies │ ├── BindableContextAttributes.cs │ └── LocalValueEntry.cs │ ├── Options │ └── DebugOptions.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Renderer.cs │ ├── Screen.cs │ ├── TestingLibraryOptions.cs │ ├── TreeFormatters │ ├── ITreeFormatter.cs │ └── SimpleTextFormatter.cs │ ├── ValueFormatters │ ├── ColorValueFormatter.cs │ ├── DefaultValueFormatter.cs │ ├── EnumerableValueFormatter.cs │ ├── IValueFormatter.cs │ ├── LayoutOptionsValueFormatter.cs │ ├── StringValueFormatter.cs │ └── ThicknessValueFormatter.cs │ └── Xamarin.Forms.TestingLibrary.csproj ├── test └── Xamarin.Forms.TestingLibrary.Tests │ ├── Specs │ ├── Extensions │ │ └── ViewExtensionsTests.cs │ ├── RendererTests.cs │ └── ScreenTests.cs │ ├── Stubs │ └── TestViewModel.cs │ └── Xamarin.Forms.TestingLibrary.Tests.csproj └── tools └── packages.config /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | max_line_length = 120 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.cs] 15 | # New line preferences 16 | csharp_new_line_before_open_brace = all 17 | csharp_new_line_before_else = true 18 | csharp_new_line_before_catch = true 19 | csharp_new_line_before_finally = true 20 | csharp_new_line_before_members_in_object_initializers = true 21 | csharp_new_line_before_members_in_anonymous_types = true 22 | csharp_new_line_between_query_expression_clauses = true 23 | 24 | # Indentation preferences 25 | csharp_indent_block_contents = true 26 | csharp_indent_braces = false 27 | csharp_indent_case_contents = true 28 | csharp_indent_switch_labels = true 29 | csharp_indent_labels = flush_left 30 | 31 | # avoid this. unless absolutely necessary 32 | dotnet_style_qualification_for_field = false:suggestion 33 | dotnet_style_qualification_for_property = false:suggestion 34 | dotnet_style_qualification_for_method = false:suggestion 35 | dotnet_style_qualification_for_event = false:suggestion 36 | 37 | # only use var when it's obvious what the variable type is 38 | csharp_style_var_for_built_in_types = true:suggestion 39 | csharp_style_var_when_type_is_apparent = true:suggestion 40 | csharp_style_var_elsewhere = true:suggestion 41 | 42 | # use language keywords instead of BCL types 43 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 44 | dotnet_style_predefined_type_for_member_access = true:suggestion 45 | 46 | # generic capitalization styles 47 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 48 | dotnet_naming_style.camel_case_style.capitalization = camel_case 49 | 50 | # private/protected const symbols 51 | dotnet_naming_symbols.constant_fields.applicable_accessibilities = private, protected 52 | dotnet_naming_symbols.constant_fields.applicable_kinds = field 53 | dotnet_naming_symbols.constant_fields.required_modifiers = const 54 | # name all private/protected const fields using camelCase 55 | dotnet_naming_rule.constant_fields_should_be_camel_case.symbols = constant_fields 56 | dotnet_naming_rule.constant_fields_should_be_camel_case.style = camel_case_style 57 | dotnet_naming_rule.constant_fields_should_be_camel_case.severity = suggestion 58 | 59 | # parameter symbols 60 | dotnet_naming_symbols.parameter_symbols.applicable_kinds = parameter 61 | # name all parameter symbols using camelCase 62 | dotnet_naming_rule.parameter_symbols_should_be_camel_case.symbols = parameter_symbols 63 | dotnet_naming_rule.parameter_symbols_should_be_camel_case.style = camel_case_style 64 | dotnet_naming_rule.parameter_symbols_should_be_camel_case.severity = suggestion 65 | 66 | # public symbols 67 | dotnet_naming_symbols.public_symbols.applicable_accessibilities = public 68 | # name all public symbols using PascalCase 69 | dotnet_naming_rule.public_symbols_should_be_pascal_case.symbols = public_symbols 70 | dotnet_naming_rule.public_symbols_should_be_pascal_case.style = pascal_case_style 71 | dotnet_naming_rule.public_symbols_should_be_pascal_case.severity = suggestion 72 | 73 | # async style 74 | dotnet_naming_style.async_suffix_style.required_suffix = Async 75 | dotnet_naming_style.async_suffix_style.capitalization = pascal_case 76 | # async method symbols 77 | dotnet_naming_symbols.async_methods.required_modifiers = async 78 | dotnet_naming_symbols.async_methods.applicable_kinds = method 79 | dotnet_naming_symbols.async_methods.applicable_accessibilities = * 80 | # name all async methods using async suffix 81 | dotnet_naming_rule.async_methods_should_end_with_async.symbols = async_methods 82 | dotnet_naming_rule.async_methods_should_end_with_async.style = async_suffix_style 83 | dotnet_naming_rule.async_methods_should_end_with_async.severity = suggestion 84 | 85 | # underscore camel case style 86 | dotnet_naming_style.underscore_camel_case_style.capitalization = camel_case 87 | dotnet_naming_style.underscore_camel_case_style.required_prefix = _ 88 | # private/protected fields symbols 89 | dotnet_naming_symbols.private_field_symbols.applicable_kinds = field 90 | dotnet_naming_symbols.private_field_symbols.applicable_accessibilities = private 91 | # name all private and protected field symbols using camelCase 92 | dotnet_naming_rule.private_field_symbols_should_be_camel_case.symbols = private_field_symbols 93 | dotnet_naming_rule.private_field_symbols_should_be_camel_case.severity = suggestion 94 | dotnet_naming_rule.private_field_symbols_should_be_camel_case.style = underscore_camel_case_style 95 | 96 | # Code style defaults 97 | dotnet_sort_system_directives_first = false 98 | csharp_preserve_single_line_blocks = true 99 | csharp_preserve_single_line_statements = false 100 | 101 | # Expression-level preferences 102 | dotnet_style_object_initializer = true:suggestion 103 | dotnet_style_collection_initializer = true:suggestion 104 | dotnet_style_explicit_tuple_names = true:warning 105 | dotnet_style_coalesce_expression = true:suggestion 106 | dotnet_style_null_propagation = true:suggestion 107 | 108 | # Expression-bodied members 109 | csharp_style_expression_bodied_methods = true:suggestion 110 | csharp_style_expression_bodied_constructors = true:suggestion 111 | csharp_style_expression_bodied_operators = true:suggestion 112 | csharp_style_expression_bodied_properties = true:suggestion 113 | csharp_style_expression_bodied_indexers = true:suggestion 114 | csharp_style_expression_bodied_accessors = true:suggestion 115 | 116 | # Pattern matching 117 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 118 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 119 | csharp_style_inlined_variable_declaration = true:suggestion 120 | 121 | # Null checking preferences 122 | csharp_style_throw_expression = true:suggestion 123 | csharp_style_conditional_delegate_call = true:suggestion 124 | 125 | # Space preferences 126 | csharp_space_after_cast = false 127 | csharp_space_after_colon_in_inheritance_clause = true 128 | csharp_space_after_comma = true 129 | csharp_space_after_dot = false 130 | csharp_space_after_keywords_in_control_flow_statements = true 131 | csharp_space_after_semicolon_in_for_statement = true 132 | csharp_space_around_binary_operators = before_and_after 133 | csharp_space_around_declaration_statements = do_not_ignore 134 | csharp_space_before_colon_in_inheritance_clause = true 135 | csharp_space_before_comma = false 136 | csharp_space_before_dot = false 137 | csharp_space_before_open_square_brackets = false 138 | csharp_space_before_semicolon_in_for_statement = false 139 | csharp_space_between_empty_square_brackets = false 140 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 141 | csharp_space_between_method_call_name_and_opening_parenthesis = false 142 | csharp_space_between_method_call_parameter_list_parentheses = false 143 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 144 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 145 | csharp_space_between_method_declaration_parameter_list_parentheses = false 146 | csharp_space_between_parentheses = false 147 | csharp_space_between_square_brackets = false 148 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: akamud 2 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: [main] 9 | 10 | jobs: 11 | build: 12 | env: 13 | DOTNET_CLI_TELEMETRY_OPTOUT: 1 14 | name: Build 15 | runs-on: macos-latest 16 | 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v2 20 | 21 | - name: Build 22 | run: dotnet build test/Xamarin.Forms.TestingLibrary.Tests/Xamarin.Forms.TestingLibrary.Tests.csproj --configuration Release 23 | 24 | - name: Test 25 | run: dotnet test ./test/Xamarin.Forms.TestingLibrary.Tests/Xamarin.Forms.TestingLibrary.Tests.csproj /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput='./../../coverage/' /p:Exclude=\"[*SampleApp*]*\" 26 | 27 | - name: Upload coverage to Codecov 28 | uses: codecov/codecov-action@v1.2.1 29 | with: 30 | token: ${{ secrets.CODECOV_TOKEN }} 31 | directory: ./coverage/ 32 | flags: unittests 33 | name: codecov-umbrella 34 | fail_ci_if_error: true 35 | gcov_path_exclude: 'samples/**/*' 36 | path_to_write_report: ./coverage/codecov_report.txt 37 | verbose: true 38 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish-on-release 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | 7 | jobs: 8 | publish: 9 | name: build, pack & publish 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Setup .NET Core 16 | uses: actions/setup-dotnet@v1 17 | with: 18 | dotnet-version: 5.0.103 19 | 20 | - name: publish Xamarin.Forms.TestingLibrary 21 | id: publish_nuget_common 22 | uses: rohith/publish-nuget@v2 23 | with: 24 | PROJECT_FILE_PATH: src/Xamarin.Forms.TestingLibrary/Xamarin.Forms.TestingLibrary.csproj 25 | PACKAGE_NAME: Xamarin.Forms.TestingLibrary 26 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 27 | TAG_COMMIT: false 28 | VERSION_REGEX: ^\s*(.*)<\/Version>\s*$ 29 | INCLUDE_SYMBOLS: true 30 | 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Autosave files 2 | *~ 3 | 4 | # build 5 | [Oo]bj/ 6 | [Bb]in/ 7 | packages/ 8 | TestResults/ 9 | 10 | # globs 11 | Makefile.in 12 | *.DS_Store 13 | *.sln.cache 14 | *.suo 15 | *.cache 16 | *.pidb 17 | *.userprefs 18 | *.usertasks 19 | config.log 20 | config.make 21 | config.status 22 | aclocal.m4 23 | install-sh 24 | autom4te.cache/ 25 | *.user 26 | *.tar.gz 27 | tarballs/ 28 | test-results/ 29 | Thumbs.db 30 | 31 | # Mac bundle stuff 32 | *.dmg 33 | *.app 34 | 35 | # resharper 36 | *_Resharper.* 37 | *.Resharper 38 | 39 | # dotCover 40 | *.dotCover 41 | TestResult.xml 42 | 43 | # CAKE 44 | tools/* 45 | !tools/packages.config 46 | 47 | # MFractor 48 | .droidres/ 49 | .mfractor/ 50 | 51 | # fastlane specific 52 | fastlane/report.xml 53 | 54 | # deliver temporary files 55 | fastlane/Preview.html 56 | 57 | # snapshot generated screenshots 58 | fastlane/screenshots 59 | 60 | # scan temporary files 61 | fastlane/test_output 62 | 63 | .vs/ 64 | Apks/ 65 | **/*/Properties/AndroidManifest-*.xml 66 | 67 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 68 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 69 | 70 | # User-specific stuff 71 | .idea/**/workspace.xml 72 | .idea/**/tasks.xml 73 | .idea/**/usage.statistics.xml 74 | .idea/**/dictionaries 75 | .idea/**/shelf 76 | 77 | # Generated files 78 | .idea/**/contentModel.xml 79 | 80 | # Sensitive or high-churn files 81 | .idea/**/dataSources/ 82 | .idea/**/dataSources.ids 83 | .idea/**/dataSources.local.xml 84 | .idea/**/sqlDataSources.xml 85 | .idea/**/dynamic.xml 86 | .idea/**/uiDesigner.xml 87 | .idea/**/dbnavigator.xml 88 | 89 | # Gradle 90 | .idea/**/gradle.xml 91 | .idea/**/libraries 92 | 93 | # Gradle and Maven with auto-import 94 | # When using Gradle or Maven with auto-import, you should exclude module files, 95 | # since they will be recreated, and may cause churn. Uncomment if using 96 | # auto-import. 97 | .idea/artifacts 98 | .idea/compiler.xml 99 | .idea/jarRepositories.xml 100 | .idea/modules.xml 101 | .idea/*.iml 102 | .idea/modules 103 | *.iml 104 | *.ipr 105 | 106 | # CMake 107 | cmake-build-*/ 108 | 109 | # Mongo Explorer plugin 110 | .idea/**/mongoSettings.xml 111 | 112 | # File-based project format 113 | *.iws 114 | 115 | # IntelliJ 116 | out/ 117 | 118 | # mpeltonen/sbt-idea plugin 119 | .idea_modules/ 120 | 121 | # JIRA plugin 122 | atlassian-ide-plugin.xml 123 | 124 | # Cursive Clojure plugin 125 | .idea/replstate.xml 126 | 127 | # Crashlytics plugin (for Android Studio and IntelliJ) 128 | com_crashlytics_export_strings.xml 129 | crashlytics.properties 130 | crashlytics-build.properties 131 | fabric.properties 132 | 133 | # Editor-based Rest Client 134 | .idea/httpRequests 135 | 136 | # Android studio 3.1+ serialized cache file 137 | .idea/caches/build_file_checksums.ser 138 | 139 | coverage-results/ 140 | coverage/ 141 | 142 | # End of https://www.gitignore.io/api/rider 143 | 144 | node_modules/ 145 | !fontello/config.json 146 | fontello/ 147 | fontello-*/ 148 | 149 | # visual studio code 150 | .vscode/* 151 | !.vscode/settings.json 152 | !.vscode/tasks.json 153 | !.vscode/launch.json 154 | !.vscode/extensions.json 155 | 156 | # HotReload 157 | !tools/Xamarin.Forms.HotReload.Observer.exe 158 | -------------------------------------------------------------------------------- /.idea/.idea.Xamarin.Forms.TestingLibrary/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /contentModel.xml 7 | /projectSettingsUpdater.xml 8 | /.idea.Xamarin.Forms.TestingLibrary.iml 9 | # Datasource local storage ignored files 10 | /dataSources/ 11 | /dataSources.local.xml 12 | # Editor-based HTTP Client requests 13 | /httpRequests/ 14 | -------------------------------------------------------------------------------- /.idea/.idea.Xamarin.Forms.TestingLibrary/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/.idea.Xamarin.Forms.TestingLibrary/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/.idea.Xamarin.Forms.TestingLibrary/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Mahmoud Ali 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xamarin.Forms.TestingLibrary 2 | 3 | ![Build](https://github.com/akamud/Xamarin.Forms.TestingLibrary/workflows/Build/badge.svg) 4 | [![codecov](https://codecov.io/gh/akamud/Xamarin.Forms.TestingLibrary/branch/main/graph/badge.svg?token=ZSOS6JW6D4)](https://codecov.io/gh/akamud/Xamarin.Forms.TestingLibrary) 5 | [![CodeFactor](https://www.codefactor.io/repository/github/akamud/xamarin.forms.testinglibrary/badge?s=bc6f084fefbb510c0c74058c3bfcfe6354559dff)](https://www.codefactor.io/repository/github/akamud/xamarin.forms.testinglibrary) 6 | 7 | A testing library to make components testing for Xamarin.Forms easier, inspired by [Testing Library](https://testing-library.com/), [Flutter's Widget Testing](https://flutter.dev/docs/cookbook/testing/widget/introduction) and others. 8 | 9 | **This is in pre-release, the public APIs *may* change until the first 1.0 release.** 10 | 11 | ## Getting Started 12 | 13 | You must add this **only** to your Test project. It does not depend on any testing framework, so it doesn't matter if you are using nUnit, xUnit, or any other framework. 14 | 15 | [![NuGet](https://img.shields.io/nuget/v/Xamarin.Forms.TestingLibrary.svg?style=flat)](https://img.shields.io/nuget/v/Xamarin.Forms.TestingLibrary.svg?style=flat) 16 | 17 | [NuGet package](https://www.nuget.org/packages/Xamarin.Forms.TestingLibrary/) available: 18 | ``` 19 | PM> Install-Package Xamarin.Forms.TestingLibrary -Version 0.1.0-pre 20 | ``` 21 | 22 | Writing your first test is easy, you just need to create a `Renderer` for your Xamarin.Forms App and render a Xamarin.Forms Page: 23 | 24 | ```csharp 25 | [Test] 26 | public void MyFirstTestingLibraryTest() 27 | { 28 | var renderer = new Renderer(); 29 | // Sets the App's main page to the page you passed and tries to render it. 30 | var screen = renderer.Render(); 31 | 32 | // Here your page will be rendered with all the triggers, 33 | // converters and bindings working as the real app would be. 34 | var loginButton = screen.GetByText