From a59f94d75362f82cf7f85ae8dee1ba78cfd8791e Mon Sep 17 00:00:00 2001
From: Grant Archibald <31553604+Grant-Archibald-MS@users.noreply.github.com>
Date: Mon, 13 May 2024 15:52:30 -0700
Subject: [PATCH 01/40] Adding MEF Extensibility model to Test Engine (#322)
* Adding MEF module support
* Add module filter
* Update to read from assembly location by default
* BrowserContext in TestInfraFunctions for modules
* Diagnostics update
* Network Request module extension update
* Adding ability to extend BrowsernewContextOptions
* Update to Playwright 1.33
* Add Enable with Allow/Deny settings
* Adding assembly checks and docs for modules
* Update InstallSource
* Additional call checks
* Addition tests cases
* Adding support for Non Power Apps tests
* Unit test updates
* Change to Copy task
* Format updates
* Refactor IUserManager to a MEF plugin
* Adding support for Static Browser state
* Updated to add Certificate validation for MEF plugins for #1
* Adding ITestWebProvider with canvas apps implementation
* Adding Pause() and MEF docs
* Docs update
* Review update
* Docs update
* Adding Provider state
* Adding ability to specify provider
* Testing update
* Update README.md
---
.gitignore | 1 +
README.md | 24 +-
docs/Extensions/README.md | 74 +++
.../media/TestEngineOverview-E2E.svg | 1 +
docs/Extensions/media/TestEngineOverview.svg | 1 +
docs/Extensions/modules.md | 68 +++
docs/PowerFX/Pause.md | 9 +
docs/PowerFX/README.md | 49 ++
.../extensions/testPlan-denyCommand.fx.yaml | 28 ++
.../extensions/testPlan-denyModule.fx.yaml | 28 ++
.../testPlan-enableOnlyWriteLine.fx.yaml | 30 ++
samples/extensions/testPlan.fx.yaml | 26 +
samples/modules/testPlan.fx.yaml | 25 +
samples/pause/testPlan.fx.yaml | 27 ++
.../Config/TestStateTests.cs | 28 +-
.../Helpers/ExceptionHandlingHelperTest.cs | 4 +-
.../Helpers/LoggingHelpersTest.cs | 38 +-
.../Helpers/TestData.cs | 2 +-
...icrosoft.PowerApps.TestEngine.Tests.csproj | 2 +
.../TestEngineExtensionCheckerTests.cs | 226 +++++++++
.../Modules/TestEngineModuleMEFLoaderTests.cs | 82 ++++
.../PowerApps/PowerAppsUrlMapperTests.cs | 76 ---
.../PowerFx/Functions/AssertFunctionTests.cs | 2 +-
.../PowerFx/Functions/SelectFunctionTests.cs | 108 ++---
.../Functions/SetPropertyFunctionTests.cs | 76 +--
.../Functions/SomeOtherUntypedObject.cs | 2 +-
.../PowerFx/Functions/WaitFunctionTests.cs | 124 ++---
.../PowerFx/PowerFxEngineTests.cs | 299 ++++++++----
.../PowerFXModel/ControlRecordValueTests.cs | 42 +-
.../PowerFXModel/ControlTableSourceTests.cs | 10 +-
.../PowerFXModel/ControlTableValueTests.cs | 22 +-
.../PowerFXModel/TypeMappingTests.cs | 6 +-
.../Reporting/TestReporterTests.cs | 4 +-
.../SingleTestRunnerTests.cs | 159 +++---
.../TestEngineTests.cs | 6 +-
.../PlaywrightTestInfraFunctionTests.cs | 224 +++++----
.../Users/UserManagerTests.cs | 203 --------
.../Config/BrowserConfiguration.cs | 5 +
.../Config/ITestState.cs | 49 ++
.../Config/NetworkRequestMock.cs | 12 +
.../Config/TestSettingExtensionSource.cs | 21 +
.../Config/TestSettingExtensions.cs | 48 ++
.../Config/TestSettings.cs | 5 +
.../Config/TestState.cs | 95 ++++
.../Helpers/ExceptionHandlingHelper.cs | 2 +-
.../Helpers/LoggingHelper.cs | 10 +-
.../ISingleTestRunner.cs | 1 +
.../Microsoft.PowerApps.TestEngine.csproj | 12 +-
.../Modules/ITestEngineModule.cs | 19 +
.../Modules/MefComponents.cs | 26 +
.../Modules/TestEngineExtensionChecker.cs | 458 ++++++++++++++++++
.../Modules/TestEngineModuleMEFLoader.cs | 164 +++++++
.../Modules/TestEngineTrustSource.cs | 46 ++
.../PowerApps/IUrlMapper.cs | 18 -
.../PowerApps/PowerAppsUrlMapper.cs | 67 ---
.../Select/SelectOneParamFunction.cs | 12 +-
.../Select/SelectThreeParamsFunction.cs | 14 +-
.../Select/SelectTwoParamsFunction.cs | 14 +-
.../PowerFx/Functions/SetPropertyFunction.cs | 12 +-
.../PowerFx/Functions/WaitFunction.cs | 2 +-
.../PowerFx/IPowerFxEngine.cs | 11 +-
.../PowerFx/PowerFxEngine.cs | 89 +++-
.../Providers/ITestProviderState.cs | 11 +
.../ITestWebProvider.cs} | 48 +-
.../{PowerApps => Providers}/ItemPath.cs | 2 +-
.../JSControlModel.cs | 2 +-
.../{PowerApps => Providers}/JSObjectModel.cs | 2 +-
.../JSPropertyModel.cs | 2 +-
.../JSPropertyValueModel.cs | 2 +-
.../PowerFxModel/ControlRecordValue.cs | 20 +-
.../PowerFxModel/ControlTableRowSchema.cs | 2 +-
.../PowerFxModel/ControlTableSource.cs | 10 +-
.../PowerFxModel/ControlTableValue.cs | 10 +-
.../PowerFxModel/TypeMapping.cs | 2 +-
.../RecordValueObject.cs | 2 +-
.../SingleTestRunner.cs | 72 +--
.../TestEngine.cs | 20 +-
.../TestEngineEventHandler.cs | 2 +-
.../TestInfra/ITestInfraFunctions.cs | 26 +-
.../TestInfra/PlaywrightTestInfraFunctions.cs | 210 ++++----
.../Users/IUserManager.cs | 37 +-
.../Users/UserManager.cs | 106 ----
src/PowerAppsTestEngine.sln | 82 ++++
src/PowerAppsTestEngine/InputOptions.cs | 3 +
.../PowerAppsTestEngine.csproj | 1 +
src/PowerAppsTestEngine/Program.cs | 76 ++-
.../Properties/launchSettings.json | 8 +
.../PauseFunctionTests.cs | 102 ++++
.../PauseModuleTests.cs | 89 ++++
src/testengine.module.pause.tests/Usings.cs | 1 +
.../testengine.module.pause.tests.csproj | 36 ++
src/testengine.module.pause/PauseFunction.cs | 50 ++
src/testengine.module.pause/PauseModule.cs | 36 ++
.../testengine.module.pause.csproj | 51 ++
.../SampleFunction.cs | 18 +
src/testengine.module.sample/SampleModule.cs | 34 ++
.../testengine.module.sample.csproj | 43 ++
.../PowerAppFunctionsTest.cs | 110 ++++-
.../PowerAppsUrlMapperTests.cs | 28 ++
.../Usings.cs | 1 +
.../testengine.provider.canvas.tests.csproj | 33 ++
.../JS/CanvasAppSdk.js | 0
.../JS/PublishedAppTesting.js | 0
.../PowerAppFunctions.cs | 175 ++++---
.../testengine.provider.canvas.csproj | 48 ++
.../BrowserUserManagerModuleTests.cs | 70 +++
src/testengine.user.browser.tests/Usings.cs | 1 +
.../testengine.user.browser.tests.csproj | 37 ++
.../BrowserUserManagerModule.cs | 67 +++
.../testengine.user.browser.csproj | 26 +
.../EnvironmentUserManagerModuleTests.cs | 354 ++++++++++++++
.../Usings.cs | 1 +
.../testengine.user.environment.tests.csproj | 37 ++
.../EnvironmentUserManagerModule.cs | 219 +++++++++
.../testengine.user.environment.csproj | 26 +
115 files changed, 4450 insertions(+), 1349 deletions(-)
create mode 100644 docs/Extensions/README.md
create mode 100644 docs/Extensions/media/TestEngineOverview-E2E.svg
create mode 100644 docs/Extensions/media/TestEngineOverview.svg
create mode 100644 docs/Extensions/modules.md
create mode 100644 docs/PowerFX/Pause.md
create mode 100644 samples/extensions/testPlan-denyCommand.fx.yaml
create mode 100644 samples/extensions/testPlan-denyModule.fx.yaml
create mode 100644 samples/extensions/testPlan-enableOnlyWriteLine.fx.yaml
create mode 100644 samples/extensions/testPlan.fx.yaml
create mode 100644 samples/modules/testPlan.fx.yaml
create mode 100644 samples/pause/testPlan.fx.yaml
create mode 100644 src/Microsoft.PowerApps.TestEngine.Tests/Modules/TestEngineExtensionCheckerTests.cs
create mode 100644 src/Microsoft.PowerApps.TestEngine.Tests/Modules/TestEngineModuleMEFLoaderTests.cs
delete mode 100644 src/Microsoft.PowerApps.TestEngine.Tests/PowerApps/PowerAppsUrlMapperTests.cs
rename src/Microsoft.PowerApps.TestEngine.Tests/{PowerApps => Provider}/PowerFXModel/ControlRecordValueTests.cs (75%)
rename src/Microsoft.PowerApps.TestEngine.Tests/{PowerApps => Provider}/PowerFXModel/ControlTableSourceTests.cs (76%)
rename src/Microsoft.PowerApps.TestEngine.Tests/{PowerApps => Provider}/PowerFXModel/ControlTableValueTests.cs (75%)
rename src/Microsoft.PowerApps.TestEngine.Tests/{PowerApps => Provider}/PowerFXModel/TypeMappingTests.cs (97%)
delete mode 100644 src/Microsoft.PowerApps.TestEngine.Tests/Users/UserManagerTests.cs
create mode 100644 src/Microsoft.PowerApps.TestEngine/Config/TestSettingExtensionSource.cs
create mode 100644 src/Microsoft.PowerApps.TestEngine/Config/TestSettingExtensions.cs
create mode 100644 src/Microsoft.PowerApps.TestEngine/Modules/ITestEngineModule.cs
create mode 100644 src/Microsoft.PowerApps.TestEngine/Modules/MefComponents.cs
create mode 100644 src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
create mode 100644 src/Microsoft.PowerApps.TestEngine/Modules/TestEngineModuleMEFLoader.cs
create mode 100644 src/Microsoft.PowerApps.TestEngine/Modules/TestEngineTrustSource.cs
delete mode 100644 src/Microsoft.PowerApps.TestEngine/PowerApps/IUrlMapper.cs
delete mode 100644 src/Microsoft.PowerApps.TestEngine/PowerApps/PowerAppsUrlMapper.cs
create mode 100644 src/Microsoft.PowerApps.TestEngine/Providers/ITestProviderState.cs
rename src/Microsoft.PowerApps.TestEngine/{PowerApps/IPowerAppFunctions.cs => Providers/ITestWebProvider.cs} (66%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/ItemPath.cs (95%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/JSControlModel.cs (91%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/JSObjectModel.cs (87%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/JSPropertyModel.cs (81%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/JSPropertyValueModel.cs (88%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/PowerFxModel/ControlRecordValue.cs (90%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/PowerFxModel/ControlTableRowSchema.cs (91%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/PowerFxModel/ControlTableSource.cs (84%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/PowerFxModel/ControlTableValue.cs (69%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/PowerFxModel/TypeMapping.cs (98%)
rename src/Microsoft.PowerApps.TestEngine/{PowerApps => Providers}/RecordValueObject.cs (86%)
delete mode 100644 src/Microsoft.PowerApps.TestEngine/Users/UserManager.cs
create mode 100644 src/PowerAppsTestEngine/Properties/launchSettings.json
create mode 100644 src/testengine.module.pause.tests/PauseFunctionTests.cs
create mode 100644 src/testengine.module.pause.tests/PauseModuleTests.cs
create mode 100644 src/testengine.module.pause.tests/Usings.cs
create mode 100644 src/testengine.module.pause.tests/testengine.module.pause.tests.csproj
create mode 100644 src/testengine.module.pause/PauseFunction.cs
create mode 100644 src/testengine.module.pause/PauseModule.cs
create mode 100644 src/testengine.module.pause/testengine.module.pause.csproj
create mode 100644 src/testengine.module.sample/SampleFunction.cs
create mode 100644 src/testengine.module.sample/SampleModule.cs
create mode 100644 src/testengine.module.sample/testengine.module.sample.csproj
rename src/{Microsoft.PowerApps.TestEngine.Tests/PowerApps => testengine.provider.canvas.tests}/PowerAppFunctionsTest.cs (92%)
create mode 100644 src/testengine.provider.canvas.tests/PowerAppsUrlMapperTests.cs
create mode 100644 src/testengine.provider.canvas.tests/Usings.cs
create mode 100644 src/testengine.provider.canvas.tests/testengine.provider.canvas.tests.csproj
rename src/{Microsoft.PowerApps.TestEngine => testengine.provider.canvas}/JS/CanvasAppSdk.js (100%)
rename src/{Microsoft.PowerApps.TestEngine => testengine.provider.canvas}/JS/PublishedAppTesting.js (100%)
rename src/{Microsoft.PowerApps.TestEngine/PowerApps => testengine.provider.canvas}/PowerAppFunctions.cs (66%)
create mode 100644 src/testengine.provider.canvas/testengine.provider.canvas.csproj
create mode 100644 src/testengine.user.browser.tests/BrowserUserManagerModuleTests.cs
create mode 100644 src/testengine.user.browser.tests/Usings.cs
create mode 100644 src/testengine.user.browser.tests/testengine.user.browser.tests.csproj
create mode 100644 src/testengine.user.browser/BrowserUserManagerModule.cs
create mode 100644 src/testengine.user.browser/testengine.user.browser.csproj
create mode 100644 src/testengine.user.environment.tests/EnvironmentUserManagerModuleTests.cs
create mode 100644 src/testengine.user.environment.tests/Usings.cs
create mode 100644 src/testengine.user.environment.tests/testengine.user.environment.tests.csproj
create mode 100644 src/testengine.user.environment/EnvironmentUserManagerModule.cs
create mode 100644 src/testengine.user.environment/testengine.user.environment.csproj
diff --git a/.gitignore b/.gitignore
index a1f516cc8..1075530c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -354,3 +354,4 @@ MigrationBackup/
# Power Apps Test Engine files
/src/PowerAppsTestEngine/TestOutput
/src/PowerAppsTestEngine/config.dev.json
+**/TestOutput
\ No newline at end of file
diff --git a/README.md b/README.md
index b90334464..b1419722b 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ Power Apps Test Engine is an open source project with the aim of providing maker
- DOM abstraction - Tests are authored using references to control names that are defined at design-time. Test authors do not need to write JavaScript, and do not need to be familiar with the browser DOM of the app's rendered output.
- Connector mocking - Test authors can optionally create mocks of network calls, typically used when Power Apps make calls to connectors. This allows the app to be tested without modification to the app itself while avoiding any unwanted side-effects of the external APIs.
- Screenshot and video recording support - Test Engine can take screenshots at any point during your test execution, and records videos of the test run. This can be very helpful to diagnose failed tests and to understand what the actual experience of the failed test case was.
+- Managed Extensibility Framework (MEF) - Test Engine can take advantage of defined MEF interfaces to provide authetication, providers and Power FX actions using [extension](./docs/Extensions/README.md) assemblies.
Build this project using the instructions below. This will create a local executable that can be used to run tests from your machine.
@@ -38,7 +39,7 @@ Run the commands below in PowerShell. These commands will clone the repo to your
git clone https://github.com/microsoft/PowerApps-TestEngine.git
# Change to the PowerAppsTestEngine folder
-cd PowerApps-TestEngine\src\PowerAppsTestEngine
+cd PowerApps-TestEngine\src
# Build
dotnet build
@@ -102,9 +103,26 @@ For more information about the config and the inputs to the command, please view
### Set up user authentication
-This refers to the account that Test Engine will use to execute the test.
+This refers to the account that Test Engine will use to execute the test. Test Engine supports an [Extension Model](./docs/Extensions/README.md) to allow different methods to authenticate the test system account using the UserAuth configuration parameter.
-Test Engine does not support multi-factor authentication. Use an account that requires only a username and password to sign in for your tests.
+The default UserAuth provider is BrowserContext.
+
+#### Browser context authentication
+
+Test Engine using Browser context authentication can support multi-factor authentication. Usinbg this approach an interactive login is first required to successfully authenticate with the Power Platform.
+
+Once the BrowserContext folder with the authentication tokens is available. You ccan use the Pause sample to generate a **BrowserContext** folder that you can use to login for other tests
+
+```bash
+# Change to the compiled PowerAppsTestEngine folder
+cd bin\Debug\PowerAppsTestEngine
+# Run the pause sample
+dotnet PowerAppsTestEngine.dll -i ..\..\..\samples\pause\testPlan.fx.yaml -e 12345678-1111-2222-3333-444444444444 -t aaaaaaaa-1111-2222-3333-444444444444
+```
+
+#### Environment variable authentication
+
+Test Engine using the environment variable based login does not support multi-factor authentication. Use an account that requires only a username and password to sign in for your tests.
Test credentials cannot be stored in test plan files. Rather, they are stored in PowerShell environment variables. The test plan file contains references to which environment variables are used for credentials. For example, the following snippet indicates that the `user1Email` and `user1Password` environment variables will be used:
diff --git a/docs/Extensions/README.md b/docs/Extensions/README.md
new file mode 100644
index 000000000..1f95e30a6
--- /dev/null
+++ b/docs/Extensions/README.md
@@ -0,0 +1,74 @@
+# Overview
+
+Test Engine provides an extension model using [modules](./modules.md). Modules provide the following key benefits:
+
+- A "no cliffs" extensibility model that code first developer can implement to extend the functionality of the test engine
+- An extensible method of defining login credentials for the test session
+- A provider module that different web resources can implement to that Power Fx expressions can be used
+- An action model that allows new Power Fx test functions to be defined to simplify testing
+- A security model where extensions can be signed by a trusted certificate provider
+- A allow/deny security model that provides granular control on how actions are implemented
+
+## Architecture
+
+The extension model of test engine can be visualized in the following way
+
+
+
+### Security Checks
+
+Where a possible MEF extension does not meet the defined security checks, it will not be made available as part of test engine test runs.
+
+#### Signed Assemblies
+
+When using assemblies compiled in release mode the Test Engine will validate that:
+
+- Assemblies are signed by a trusted Root certificate provider
+- Assemblies and intermediate certificates are currently valid.
+
+#### Allow / Deny List
+
+As defined in [modules](./modules.md) optional allow deny lists can be used to control the following:
+
+- Which MEF modules to allow / deny
+- Which .Net namespaces are allow / deny
+- Which .Net methods and properties and allow / deny.
+
+Using these settings can provide a granular control of what modules are available and what code can be implemented in the a ITestEngineModule implementations.
+
+### MEF Extensions
+
+Test Engine will search the same folder as the Test Engine executables for the following MEF contracts
+
+- **[IUserManager](..\..\src\Microsoft.PowerApps.TestEngine\Users\IUserManager.cs)** provide implementations to interact with the provider to authenticate the test session.
+- **[ITestWebProvider](..\..\src\Microsoft.PowerApps.TestEngine\Providers\ITestWebProvider.cs)** allow extensions to build on the authenticated Playwright session to present the object model of the provider to and from the Power Fx test state.
+- **[ITestEngineModule](..\..\src\Microsoft.PowerApps.TestEngine\Modules\ITestEngineModule.cs)** allow extensions to interact with network calls and define Power Fx functions used in a test
+
+## No Cliffs Extensibility
+
+The MEF extensibility model provides a method of extending the range of scenarios that Test Engine can cover. By implementing the defined MEF interfaces .Net assemblies can be implemented that provide alternative user authentication and web based tests.
+
+The ITestEngineModule interface allows new Power FX functions to be defined that simplify testing by extending the provider or adding low code functions that are implemented in .Net.
+
+## Local Development and ALM Process
+
+
+
+The end to end process for test engine could be th following:
+
+1. **Local Development** - Develop tests on local PC. At this stage the permissions of the maker can be used.
+
+2. **Share Test Assets** - Share the Power Apps with test user account. Provide access to Managed Identity or Service principal to the definition of the Power Apps, Power Automate flows or Co-pilot.
+
+ The user account that is setup with User permissions only. The user account must have created connection id to the required connectors.
+
+3. **Commit Changes** - Save the changes to source control which will trigger build.
+
+4. **Run Tests** - For unit tests they should be run with least privilege. Verify that:
+
+ - User accounts only have permissions to start the application
+ - By default that all Dataverse and Custom Connectors are mocked so that they cannot update source systems
+
+### Test Types
+
+Typically the majority of tests should be unit tests. Integration tests should be a smaller percentage of tests as the take longer to create and need to manage the state of system and secure access to secure resources. Finally UI tests conducted manual should be the smalled amount of tests as they require the greatest amount of review and human intervention to run and validate test results.
diff --git a/docs/Extensions/media/TestEngineOverview-E2E.svg b/docs/Extensions/media/TestEngineOverview-E2E.svg
new file mode 100644
index 000000000..a19ecfe08
--- /dev/null
+++ b/docs/Extensions/media/TestEngineOverview-E2E.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/Extensions/media/TestEngineOverview.svg b/docs/Extensions/media/TestEngineOverview.svg
new file mode 100644
index 000000000..81cdf8771
--- /dev/null
+++ b/docs/Extensions/media/TestEngineOverview.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/Extensions/modules.md b/docs/Extensions/modules.md
new file mode 100644
index 000000000..b8dacb796
--- /dev/null
+++ b/docs/Extensions/modules.md
@@ -0,0 +1,68 @@
+# Test Engine Modules
+
+Test Engine extensibility modules are an experimental features that is being considered to allow extension of Test Engine tests by making use of [Managed Extensibility Framework (MEF)](https://learn.microsoft.com/en-us/dotnet/framework/mef/) to allow .Net libraries to be created to extend test execution.
+
+NOTE: This feature is subject to change and review and is very likely to change.
+
+## Execution
+
+Execution of any defined plugins is disabled by default and must be enabled in test settings. The extension sample [testPlan.fx.yaml](../../samples/extensions/testPlan.fx.yaml) demonstrates enable extensions to run the Sample PowerFx function.
+
+By convention testengine.module.*.dll files in the same folder as the Power Apps Test engine folder will be loaded is extenions modules are enabled. Using the [Test Settings Extensions](..\..\src\Microsoft.PowerApps.TestEngine\Config\TestSettingExtensions.cs) you can enable and control allowed plugins and namespaces with the plugins.
+
+## Getting Started
+
+To run the sample extension
+
+1. Ensure that you have compiled the solution. For example to build the debug version of the Test Engine
+
+```powershell
+cd src
+dotnet build
+```
+
+2. Ensure you have correct version of playwright installed
+
+```powershell
+cd ..\bin\PowerAppTestEngine
+.\playwright.ps1 install
+```
+
+3. Get the values for your environment and tenant id from the [Power Apps Portal](http://make.powerapps.com). See [Get the session ID for Power Apps](https://learn.microsoft.com/power-apps/maker/canvas-apps/get-sessionid#get-the-session-id-for-power-apps-makepowerappscom) for more information.
+
+4. Ensure you have the [button clicker solution](..\..\samples\buttonclicker\ButtonClicker_1_0_0_4.zip) imported into your environment
+
+5. Update the [config.dev.json](..\..\src\PowerAppsTestEngine\config.dev.json) environment id and tenant id
+
+5. Run the sample
+
+```powershell
+cd samples\pause
+dotnet ..\..\bin\Debug\PowerAppsTestEngine\PowerAppsTestEngine.dll -i testPlan.fx.yaml
+```
+
+## Exploring Samples
+
+To enable the Pause PowerFx function the testengine.module.pause library uses the [PauseModule](..\..\src\testengine.module.pause\PauseModule.cs) class to implement a MEF module to register the Power Fx function.
+
+## Configuring extensions
+
+The configuration settings allow you to have finer grained control of what modules/actions you want to allow or deny.
+
+### Deny Module Load
+
+Extensions have a number of test settings that can be provided to control which extensions can be executed. The [testPlan-denyModule.fx.yaml](..\..\samples\extensions\testPlan-denyModule.fx.yaml) example demonstrates how to deny loading the sample module. When this sample is run it will fail as the Sample() Power Fx function will not be loaded.
+
+### Deny .Net Namespace
+
+In some cases you may want to deny specific commands. The [testPlan-denyCommand.fx.yaml](..\..\samples\extensions\testPlan-denyModule.fx.yaml) example demonstrates load of modules that do not match the defined rule. When this sample is run it will fail as the Sample() Power Fx function will not be loaded as it uses System.Console.
+
+This example can also be extended to specific methods for example System.Conole::WriteLine as part of the namespace rules to deny (or allow) a specific method. The [testPlan-enableOnlyWriteLine.fx.yaml](..\..\samples\extensions\testPlan-enableOnlyWriteLine.fx.yaml) example demonstrates this configuration to to have a passing test.
+
+## Further Extensions
+
+Once you have explored Power Fx and Test Settings the following additional areas can be explored:
+
+- Extending the Network Mocking with a module using [RouteAsync](https://playwright.dev/dotnet/docs/api/class-browsercontext#browser-context-route) to Abort, Fulfill from a local file or Continue
+
+- Additional extensions could be considered by implementing the defined interfaces an making contributions and pull requests to increase use of Test Engine to cover additional test scenarios.
diff --git a/docs/PowerFX/Pause.md b/docs/PowerFX/Pause.md
new file mode 100644
index 000000000..599aff545
--- /dev/null
+++ b/docs/PowerFX/Pause.md
@@ -0,0 +1,9 @@
+# Pause
+
+`Pause()`
+
+This will open the interactive Playwright Inspector and wait for the user to resume execution.
+
+## Example
+
+`Pause()`
diff --git a/docs/PowerFX/README.md b/docs/PowerFX/README.md
index 7cdfa007d..76d6edc21 100644
--- a/docs/PowerFX/README.md
+++ b/docs/PowerFX/README.md
@@ -4,6 +4,55 @@ There are several specifically defined functions for the test framework.
- [Assert](./Assert.md)
- [Screenshot](./Screenshot.md)
+- [Pause](./Pause.md)
- [Select](./Select.md)
- [SetProperty](./SetProperty.md)
- [Wait](./Wait.md)
+
+## Naming
+
+When creating additional functions using [modules](../modules.md) for Power Fx in the Test Engine, it's important to follow naming standards to ensure consistency and readability.
+
+Here are some guidelines for naming your functions in Power Fx:
+
+1. Use descriptive names that accurately describe the function's purpose.
+2. Use PascalCase, where the first letter of each word is capitalized, for function names.
+3. Avoid using abbreviations or acronyms unless they are widely understood and commonly used.
+4. Use verbs at the beginning of function names to indicate what the function does.
+5. Use nouns at the end of function names to indicate what the function operates on.
+
+By following these naming standards, your Power Fx code will be easier to read and maintain, and other developers will be able to understand your code more easily.
+
+### Using Descriptive Names
+
+Using descriptive names is important because it makes it easier for others (and yourself) to understand what the function or service does. A good name should be concise but also convey the function's or service's purpose. For example, instead of naming a function "Calculate," you could name it "CalculateTotalCost" to make it clear what the function is doing.
+
+Anti-pattern: Using vague or ambiguous names that don't clearly convey the function's or service's purpose. For example, naming a function "ProcessData" doesn't give any indication of what the function actually does.
+
+### Use Pascal Case
+
+Using PascalCase is a convention that is widely used in many programming languages, and it helps make your code more readable and consistent. By capitalizing the first letter of each word, you can more easily distinguish between different words in the name. For example, instead of naming a function "calculateTotalcost," you could name it "CalculateTotalCost" to make it easier to read.
+
+Anti-pattern: Using inconsistent capitalization or other naming conventions. For example, naming a function "Calculate_total_cost" or "calculateTotalCost" would be inconsistent and harder to read.
+
+### Avoid Abbreviations
+
+Using abbreviations or acronyms can make it harder for others to understand what your code does, especially if they are not familiar with the specific terminology you are using. If you do use abbreviations or acronyms, make sure they are widely understood and commonly used in your field. For example, using "GUI" for "Graphical User Interface" is a widely understood and commonly used abbreviation.
+
+Anti-pattern: Using obscure or uncommon abbreviations or acronyms that are not widely understood. For example, using "NLP" for "Natural Language Processing" might be confusing for someone who is not familiar with that term.
+
+### Use Verbs at start
+
+Using verbs at the beginning of function names helps to make it clear what the function does. This is especially important when you have many functions that operate on similar data or perform similar tasks. For example, instead of naming a function simply "TotalCost," you could name it "CalculateTotalCost" to indicate that the function calculates the total cost.
+
+Good practice: Using clear and concise verbs that accurately describe what the function does. For example, using verbs like "calculate," "validate," "filter," or "sort" can help make the function's purpose clear.
+
+Anti-pattern: Using vague or misleading verbs that don't accurately describe what the function does. For example, using a verb like "execute" or "perform" doesn't give any indication of what the function actually does.
+
+### Use Nouns at end
+
+Using nouns at the end of function or service names helps to make it clear what the function or service operates on. For example, instead of naming a function "CalculateTotal" you could name it "CalculateTotalCost" to indicate that the function operates on cost data.
+
+Good practice: Using clear and concise nouns that accurately describe what the function or service operates on. For example, using nouns like "cost," "customer," "order," or "invoice" can help make the function or service's purpose clear.
+
+Anti-pattern: Using vague or misleading nouns that don't accurately describe what the function or service operates on. For example, using a noun like "data" or "information" doesn't give any indication of what the function or service actually operates on.
diff --git a/samples/extensions/testPlan-denyCommand.fx.yaml b/samples/extensions/testPlan-denyCommand.fx.yaml
new file mode 100644
index 000000000..2e3df4a12
--- /dev/null
+++ b/samples/extensions/testPlan-denyCommand.fx.yaml
@@ -0,0 +1,28 @@
+testSuite:
+ testSuiteName: Extension example
+ testSuiteDescription: Demonstrate the use of PowerFx extension
+ persona: User1
+ appLogicalName: new_buttonclicker_0a877
+
+ testCases:
+ - testCaseName: Run Sample
+ testCaseDescription: Test case will fail as the Sample command uses System.Console
+ testSteps: |
+ = Sample();
+
+testSettings:
+ locale: "en-US"
+ recordVideo: true
+ extensionModules:
+ enable: true
+ denyNamespaces:
+ - System.Console
+ browserConfigurations:
+ - browser: Chromium
+
+environmentVariables:
+ users:
+ - personaName: User1
+ emailKey: user1Email
+ passwordKey: user1Password
+
diff --git a/samples/extensions/testPlan-denyModule.fx.yaml b/samples/extensions/testPlan-denyModule.fx.yaml
new file mode 100644
index 000000000..ba767becf
--- /dev/null
+++ b/samples/extensions/testPlan-denyModule.fx.yaml
@@ -0,0 +1,28 @@
+testSuite:
+ testSuiteName: Extension example
+ testSuiteDescription: Demonstrate the use of PowerFx extension
+ persona: User1
+ appLogicalName: new_buttonclicker_0a877
+
+ testCases:
+ - testCaseName: Run Sample
+ testCaseDescription: Test case will fail as the Sample Power Fx function is not loaded
+ testSteps: |
+ = Sample();
+
+testSettings:
+ locale: "en-US"
+ recordVideo: true
+ extensionModules:
+ enable: true
+ denyModule:
+ - sample
+ browserConfigurations:
+ - browser: Chromium
+
+environmentVariables:
+ users:
+ - personaName: User1
+ emailKey: user1Email
+ passwordKey: user1Password
+
diff --git a/samples/extensions/testPlan-enableOnlyWriteLine.fx.yaml b/samples/extensions/testPlan-enableOnlyWriteLine.fx.yaml
new file mode 100644
index 000000000..514137bfb
--- /dev/null
+++ b/samples/extensions/testPlan-enableOnlyWriteLine.fx.yaml
@@ -0,0 +1,30 @@
+testSuite:
+ testSuiteName: Extension example
+ testSuiteDescription: Demonstrate the use of PowerFx extension
+ persona: User1
+ appLogicalName: new_buttonclicker_0a877
+
+ testCases:
+ - testCaseName: Run Sample
+ testCaseDescription: Test case will pass as WriteLine method has been allowed
+ testSteps: |
+ = Sample();
+
+testSettings:
+ locale: "en-US"
+ recordVideo: true
+ extensionModules:
+ enable: true
+ allowNamespaces:
+ - System.Console::WriteLine
+ denyNamespaces:
+ - System.Console
+ browserConfigurations:
+ - browser: Chromium
+
+environmentVariables:
+ users:
+ - personaName: User1
+ emailKey: user1Email
+ passwordKey: user1Password
+
diff --git a/samples/extensions/testPlan.fx.yaml b/samples/extensions/testPlan.fx.yaml
new file mode 100644
index 000000000..66389fb5c
--- /dev/null
+++ b/samples/extensions/testPlan.fx.yaml
@@ -0,0 +1,26 @@
+testSuite:
+ testSuiteName: Extension example
+ testSuiteDescription: Demonstrate the use of PowerFx extension
+ persona: User1
+ appLogicalName: new_buttonclicker_0a877
+
+ testCases:
+ - testCaseName: Run Sample
+ testCaseDescription: Run the Sample Command
+ testSteps: |
+ = Sample();
+
+testSettings:
+ locale: "en-US"
+ recordVideo: true
+ extensionModules:
+ enable: true
+ browserConfigurations:
+ - browser: Chromium
+
+environmentVariables:
+ users:
+ - personaName: User1
+ emailKey: user1Email
+ passwordKey: user1Password
+
diff --git a/samples/modules/testPlan.fx.yaml b/samples/modules/testPlan.fx.yaml
new file mode 100644
index 000000000..529ea81d8
--- /dev/null
+++ b/samples/modules/testPlan.fx.yaml
@@ -0,0 +1,25 @@
+testSuite:
+ testSuiteName: Button Clicker
+ testSuiteDescription: Verifies that counter increments when the button is clicked
+ persona: User1
+ appLogicalName: new_buttonclicker_0a877
+ onTestCaseStart: Screenshot("buttonclicker_onTestCaseStart.png");
+ onTestCaseComplete: Select(ResetButton);
+ onTestSuiteComplete: Screenshot("buttonclicker_onTestSuiteComplete.png");
+
+ testCases:
+ - testCaseName: Case1
+ testCaseDescription: Run sample action
+ testSteps: |
+ = Sample();
+
+testSettings:
+ locale: "en-US"
+ headless: false
+ recordVideo: true
+ enableExtensionModules: true
+ browserConfigurations:
+ - browser: Firefox
+
+environmentVariables:
+ filePath: ../../samples/environmentVariables.yaml
diff --git a/samples/pause/testPlan.fx.yaml b/samples/pause/testPlan.fx.yaml
new file mode 100644
index 000000000..2fe3d5a53
--- /dev/null
+++ b/samples/pause/testPlan.fx.yaml
@@ -0,0 +1,27 @@
+testSuite:
+ testSuiteName: Pause tests
+ testSuiteDescription: Pause the browser and open the Playwright Inspector inside the Power App using browser authentication method
+ persona: User1
+ appLogicalName: new_buttonclicker_0a877
+ onTestSuiteComplete: Screenshot("pause_onTestSuiteComplete.png");
+
+ testCases:
+ - testCaseName: Pause
+ testCaseDescription: Pause example
+ testSteps: |
+ = Pause();
+
+testSettings:
+ headless: false
+ locale: "en-US"
+ recordVideo: true
+ extensionModules:
+ enable: true
+ browserConfigurations:
+ - browser: Chromium
+
+environmentVariables:
+ users:
+ - personaName: User1
+ emailKey: NotNeeded
+ passwordKey: NotNeeded
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/Config/TestStateTests.cs b/src/Microsoft.PowerApps.TestEngine.Tests/Config/TestStateTests.cs
index 9b02594a1..94be9c184 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/Config/TestStateTests.cs
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/Config/TestStateTests.cs
@@ -211,7 +211,7 @@ public void ParseAndSetTestStateThrowsOnNoTestSuiteDefinition()
// Act and Arrange
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -230,7 +230,7 @@ public void ParseAndSetTestStateThrowsOnNoNameInTestSuiteDefinition(string testN
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -249,7 +249,7 @@ public void ParseAndSetTestStateThrowsOnNoPersonaInTestSuiteDefinition(string pe
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -271,7 +271,7 @@ public void ParseAndSetTestStateThrowsOnNoAppLogicalNameOrAppIdInTestSuiteDefini
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -307,7 +307,7 @@ public void ParseAndSetTestStateThrowsOnNoTestCaseInTestSuiteDefinition()
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -326,7 +326,7 @@ public void ParseAndSetTestStateThrowsOnNoTestCaseNameInTestCase(string testCase
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -345,7 +345,7 @@ public void ParseAndSetTestStateThrowsOnNoTestStepsInTestCase(string testSteps)
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -362,7 +362,7 @@ public void ParseAndSetTestStateThrowsOnNoTestSettings()
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -379,7 +379,7 @@ public void ParseAndSetTestStateThrowsOnNullBrowserConfigurationInTestSettings()
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -396,7 +396,7 @@ public void ParseAndSetTestStateThrowsOnNoBrowserConfigurationInTestSettings()
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -415,7 +415,7 @@ public void ParseAndSetTestStateThrowsOnNoBrowserInBrowserConfigurationInTestSet
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -439,7 +439,7 @@ public void ParseAndSetTestStateThrowsOnInvalidScreenConfigInBrowserConfiguratio
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
var ex = Assert.Throws(() => state.ParseAndSetTestState(testConfigFile, MockLogger.Object));
- Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
+ Assert.Equal(UserInputException.ErrorMapping.UserInputExceptionTestConfig.ToString(), ex.Message);
LoggingTestHelper.VerifyLogging(MockLogger, expectedErrorMessage, LogLevel.Error, Times.Once());
}
@@ -579,8 +579,8 @@ public void ParseAndSetTestStateThrowsOnMulitpleMissingValues()
// setting testcases to null
testPlanDefinition.TestSuite.TestCases = null;
testPlanDefinition.TestSettings = null;
- testPlanDefinition.TestSuite.Persona = Guid.NewGuid().ToString();
-
+ testPlanDefinition.TestSuite.Persona = Guid.NewGuid().ToString();
+
MockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny())).Returns(MockLogger.Object);
LoggingTestHelper.SetupMock(MockLogger);
MockTestConfigParser.Setup(x => x.ParseTestConfig(It.IsAny(), MockLogger.Object)).Returns(testPlanDefinition);
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/ExceptionHandlingHelperTest.cs b/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/ExceptionHandlingHelperTest.cs
index c3f6823c5..0cfc1daa1 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/ExceptionHandlingHelperTest.cs
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/ExceptionHandlingHelperTest.cs
@@ -18,9 +18,9 @@ public ExceptionHandlingHelperTest()
[Fact]
public void CheckIfOutDatedPublishedAppTrue()
{
- Exception exception= new Exception(ExceptionHandlingHelper.PublishedAppWithoutJSSDKErrorCode);
+ Exception exception = new Exception(ExceptionHandlingHelper.PublishedAppWithoutJSSDKErrorCode);
LoggingTestHelper.SetupMock(MockLogger);
- ExceptionHandlingHelper.CheckIfOutDatedPublishedApp(exception,MockLogger.Object);
+ ExceptionHandlingHelper.CheckIfOutDatedPublishedApp(exception, MockLogger.Object);
// Verify the message is logged in this case
LoggingTestHelper.VerifyLogging(MockLogger, ExceptionHandlingHelper.PublishedAppWithoutJSSDKMessage, LogLevel.Error, Times.Once());
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/LoggingHelpersTest.cs b/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/LoggingHelpersTest.cs
index a45f4b58d..18ed7c5ce 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/LoggingHelpersTest.cs
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/LoggingHelpersTest.cs
@@ -5,7 +5,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.PowerApps.TestEngine.Config;
using Microsoft.PowerApps.TestEngine.Helpers;
-using Microsoft.PowerApps.TestEngine.PowerApps;
+using Microsoft.PowerApps.TestEngine.Providers;
using Microsoft.PowerApps.TestEngine.System;
using Moq;
using Xunit;
@@ -15,16 +15,16 @@ namespace Microsoft.PowerApps.TestEngine.Tests.Helpers
public class LoggingHelpersTest
{
private Mock MockLogger;
- private Mock MockPowerAppFunctions;
+ private Mock MockTestWebProvider;
private Mock MockSingleTestInstanceState;
private Mock MockTestEngineEventHandler;
public LoggingHelpersTest()
- {
- MockPowerAppFunctions = new Mock(MockBehavior.Strict);
+ {
+ MockTestWebProvider = new Mock(MockBehavior.Strict);
MockLogger = new Mock(MockBehavior.Strict);
MockSingleTestInstanceState = new Mock(MockBehavior.Strict);
- MockSingleTestInstanceState.Setup(x => x.GetLogger()).Returns(MockLogger.Object);
+ MockSingleTestInstanceState.Setup(x => x.GetLogger()).Returns(MockLogger.Object);
MockTestEngineEventHandler = new Mock(MockBehavior.Strict);
LoggingTestHelper.SetupMock(MockLogger);
@@ -33,11 +33,11 @@ public LoggingHelpersTest()
[Fact]
public async Task DebugInfoNullSessionTest()
{
- MockPowerAppFunctions.Setup(x => x.GetDebugInfo()).Returns(Task.FromResult((object)null));
- var loggingHelper = new LoggingHelper(MockPowerAppFunctions.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
+ MockTestWebProvider.Setup(x => x.GetDebugInfo()).Returns(Task.FromResult((object)null));
+ var loggingHelper = new LoggingHelper(MockTestWebProvider.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
loggingHelper.DebugInfo();
- MockPowerAppFunctions.Verify(x => x.GetDebugInfo(), Times.Once());
+ MockTestWebProvider.Verify(x => x.GetDebugInfo(), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n Debug Info \n------------------------------", LogLevel.Information, Times.Never());
}
@@ -47,11 +47,11 @@ public async Task DebugInfoWithSessionTest()
var obj = new ExpandoObject();
obj.TryAdd("sessionId", "somesessionId");
- MockPowerAppFunctions.Setup(x => x.GetDebugInfo()).Returns(Task.FromResult((object)obj));
- var loggingHelper = new LoggingHelper(MockPowerAppFunctions.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
+ MockTestWebProvider.Setup(x => x.GetDebugInfo()).Returns(Task.FromResult((object)obj));
+ var loggingHelper = new LoggingHelper(MockTestWebProvider.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
loggingHelper.DebugInfo();
- MockPowerAppFunctions.Verify(x => x.GetDebugInfo(), Times.Once());
+ MockTestWebProvider.Verify(x => x.GetDebugInfo(), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n Debug Info \n------------------------------", LogLevel.Information, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "sessionId:\tsomesessionId", LogLevel.Information, Times.Once());
}
@@ -65,11 +65,11 @@ public async Task DebugInfoReturnDetailsTest()
obj.TryAdd("environmentId", "someEnvironmentId");
obj.TryAdd("sessionId", "someSessionId");
- MockPowerAppFunctions.Setup(x => x.GetDebugInfo()).Returns(Task.FromResult((object)obj));
- var loggingHelper = new LoggingHelper(MockPowerAppFunctions.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
+ MockTestWebProvider.Setup(x => x.GetDebugInfo()).Returns(Task.FromResult((object)obj));
+ var loggingHelper = new LoggingHelper(MockTestWebProvider.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
loggingHelper.DebugInfo();
- MockPowerAppFunctions.Verify(x => x.GetDebugInfo(), Times.Once());
+ MockTestWebProvider.Verify(x => x.GetDebugInfo(), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n Debug Info \n------------------------------", LogLevel.Information, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "appId:\tsomeAppId", LogLevel.Information, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "appVersion:\tsomeAppVersionId", LogLevel.Information, Times.Once());
@@ -86,12 +86,12 @@ public async Task DebugInfoWithNullValuesTest()
obj.TryAdd("environmentId", null);
obj.TryAdd("sessionId", "someSessionId");
- MockPowerAppFunctions.Setup(x => x.GetDebugInfo()).Returns(Task.FromResult((object)obj));
+ MockTestWebProvider.Setup(x => x.GetDebugInfo()).Returns(Task.FromResult((object)obj));
MockTestEngineEventHandler.Setup(x => x.EncounteredException(It.IsAny()));
- var loggingHelper = new LoggingHelper(MockPowerAppFunctions.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
+ var loggingHelper = new LoggingHelper(MockTestWebProvider.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
loggingHelper.DebugInfo();
- MockPowerAppFunctions.Verify(x => x.GetDebugInfo(), Times.Once());
+ MockTestWebProvider.Verify(x => x.GetDebugInfo(), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n Debug Info \n------------------------------", LogLevel.Information, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "appId:\tsomeAppId", LogLevel.Information, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "appVersion:\t", LogLevel.Information, Times.Once());
@@ -102,9 +102,9 @@ public async Task DebugInfoWithNullValuesTest()
[Fact]
public async Task DebugInfoThrowsTest()
{
- MockPowerAppFunctions.Setup(x => x.GetDebugInfo()).Throws(new Exception()); ;
+ MockTestWebProvider.Setup(x => x.GetDebugInfo()).Throws(new Exception()); ;
MockTestEngineEventHandler.Setup(x => x.EncounteredException(It.IsAny()));
- var loggingHelper = new LoggingHelper(MockPowerAppFunctions.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
+ var loggingHelper = new LoggingHelper(MockTestWebProvider.Object, MockSingleTestInstanceState.Object, MockTestEngineEventHandler.Object);
loggingHelper.DebugInfo();
// Verify UserAppException is passed to TestEngineEventHandler
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/TestData.cs b/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/TestData.cs
index 08e5e9fa3..7c81b725e 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/TestData.cs
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/Helpers/TestData.cs
@@ -6,7 +6,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using Microsoft.PowerApps.TestEngine.PowerApps;
+using Microsoft.PowerApps.TestEngine.Providers;
using Microsoft.PowerFx.Types;
namespace Microsoft.PowerApps.TestEngine.Tests.Helpers
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/Microsoft.PowerApps.TestEngine.Tests.csproj b/src/Microsoft.PowerApps.TestEngine.Tests/Microsoft.PowerApps.TestEngine.Tests.csproj
index 378ab16a2..e19ad1be6 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/Microsoft.PowerApps.TestEngine.Tests.csproj
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/Microsoft.PowerApps.TestEngine.Tests.csproj
@@ -11,9 +11,11 @@
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/Modules/TestEngineExtensionCheckerTests.cs b/src/Microsoft.PowerApps.TestEngine.Tests/Modules/TestEngineExtensionCheckerTests.cs
new file mode 100644
index 000000000..2aa458c60
--- /dev/null
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/Modules/TestEngineExtensionCheckerTests.cs
@@ -0,0 +1,226 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.X509Certificates;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Scripting;
+using Microsoft.CodeAnalysis.Scripting;
+using Microsoft.Extensions.Logging;
+using Microsoft.PowerApps.TestEngine.Config;
+using Microsoft.PowerApps.TestEngine.Modules;
+using Moq;
+using Xunit;
+using CertificateRequest = System.Security.Cryptography.X509Certificates.CertificateRequest;
+
+namespace Microsoft.PowerApps.TestEngine.Tests.Modules
+{
+ public class TestEngineExtensionCheckerTests
+ {
+ Mock MockLogger;
+ string _template;
+
+ public TestEngineExtensionCheckerTests()
+ {
+ MockLogger = new Mock();
+ _template = @"
+#r ""Microsoft.PowerFx.Interpreter.dll""
+#r ""System.ComponentModel.Composition.dll""
+#r ""Microsoft.PowerApps.TestEngine.dll""
+#r ""Microsoft.Playwright.dll""
+using System.Threading.Tasks;
+using Microsoft.PowerFx;
+using System.ComponentModel.Composition;
+using Microsoft.Extensions.Logging;
+using Microsoft.PowerApps.TestEngine.Config;
+using Microsoft.PowerApps.TestEngine.Modules;
+using Microsoft.PowerApps.TestEngine.Providers;
+using Microsoft.PowerApps.TestEngine.System;
+using Microsoft.PowerApps.TestEngine.TestInfra;
+using Microsoft.Playwright;
+%USING%
+
+[Export(typeof(ITestEngineModule))]
+public class SampleModule : ITestEngineModule
+{
+ public void ExtendBrowserContextOptions(BrowserNewContextOptions options, TestSettings settings)
+ {
+
+ }
+
+ public void RegisterPowerFxFunction(PowerFxConfig config, ITestInfraFunctions testInfraFunctions, ITestWebProvider webTestProvider, ISingleTestInstanceState singleTestInstanceState, ITestState testState, IFileSystem fileSystem)
+ {
+ var temp = new TestScript();
+ }
+
+ public async Task RegisterNetworkRoute(ITestState state, ISingleTestInstanceState singleTestInstanceState, IFileSystem fileSystem, IPage Page, NetworkRequestMock mock)
+ {
+ await Task.CompletedTask;
+ }
+}
+public class TestScript {
+ public TestScript() {
+ %CODE%
+ }
+
+}";
+ }
+
+ [Theory]
+ [InlineData("", "System.Console.WriteLine(\"Hello World\");", true, "", "", true)]
+ [InlineData("", "System.Console.WriteLine(\"Hello World\");", true, "", "System.", false)] // Deny all System namespace
+ [InlineData("using System;", "Console.WriteLine(\"Hello World\");", true, "System.Console::WriteLine", "System.Console", true)]
+ [InlineData("using System;", "Console.WriteLine(\"A\");", true, "System.Console::WriteLine(\"A\")", "System.Console::WriteLine", true)] // Allow System.Console.WriteLine only with a argument of A
+ [InlineData("using System;", "Console.WriteLine(\"B\");", true, "System.Console::WriteLine(\"A\")", "System.Console::WriteLine", false)] // Allow System.Console.WriteLine only with a argument of A - Deny
+ [InlineData("using System.IO;", @"File.Exists(""c:\\test.txt"");", true, "", "System.IO", false)] // Deny all System.IO
+ [InlineData("", @"IPage page = null; page.EvaluateAsync(""alert()"").Wait();", true, "", "Microsoft.Playwright.IPage::EvaluateAsync", false)] // Constructor code - deny
+ [InlineData("", @"} public string Foo { get { IPage page = null; page.EvaluateAsync(""alert()"").Wait(); return ""a""; }", true, "", "Microsoft.Playwright.IPage::EvaluateAsync", false)] // Get Property Code deny
+ [InlineData("", @"} private int _foo; public int Foo { set { IPage page = null; page.EvaluateAsync(""alert()"").Wait(); _foo = value; }", true, "", "Microsoft.Playwright.IPage::EvaluateAsync", false)] // Set property deny
+ [InlineData(@"using System; public class Other { private Action Foo {get;set; } = () => { IPage page = null; page.EvaluateAsync(""alert()"").Wait(); }; }", "", true, "", "Microsoft.Playwright.IPage::EvaluateAsync", false)] // Action deny property
+ [InlineData(@"using System; public class Other { private Action Foo = () => { IPage page = null; page.EvaluateAsync(""alert()"").Wait(); }; }", "", true, "", "Microsoft.Playwright.IPage::EvaluateAsync", false)] // Action deny field
+ [InlineData("using System; public class Other { private string Foo = String.Format(\"A\"); }", "", true, "", "System.String::Format", false)] // Action deny field - Inline Function
+ [InlineData(@"using System; public class Other { private static Action Foo {get;set; } = () => { IPage page = null; page.EvaluateAsync(""alert()"").Wait(); }; }", "", true, "", "Microsoft.Playwright.IPage::EvaluateAsync", false)] // Static Action deny property
+ [InlineData(@"using System; public class Other { private static Action Foo = () => { IPage page = null; page.EvaluateAsync(""alert()"").Wait(); }; }", "", true, "", "Microsoft.Playwright.IPage::EvaluateAsync", false)] // Static Action deny field
+ [InlineData(@"using System; public class Other { static Other() { page.EvaluateAsync(""alert()"").Wait(); } static readonly IPage page = null; }", "", true, "", "Microsoft.Playwright.IPage::EvaluateAsync", false)] // Static Constructor
+ public void IsValid(string usingStatements, string script, bool useTemplate, string allow, string deny, bool expected)
+ {
+ var assembly = CompileScript(useTemplate ? _template
+ .Replace("%USING%", usingStatements)
+ .Replace("%CODE%", script) : script);
+
+ var checker = new TestEngineExtensionChecker(MockLogger.Object);
+ checker.GetExtentionContents = (file) => assembly;
+
+ var settings = new TestSettingExtensions()
+ {
+ Enable = true,
+ AllowNamespaces = new List() { allow },
+ DenyNamespaces = new List() { deny }
+ };
+
+ var result = checker.Validate(settings, "testengine.module.test.dll");
+
+ Assert.Equal(expected, result);
+ }
+
+ [Theory]
+ [InlineData(false, true, false, "CN=Test", "CN=Test", 0, 1, true)]
+ [InlineData(false, false, false, "", "", 0, 1, true)]
+ [InlineData(true, true, true, "CN=Test", "CN=Test", -1, 1, true)] // Valid certificate
+ [InlineData(true, true, false, "CN=Test", "CN=Test", -1, 1, false)] // Valid certificate but with untrusted root
+ [InlineData(true, true, true, "CN=Test, O=Match", "CN=Test, O=Match", -1, 1, true)] // Valid certificate with O
+ [InlineData(true, true, true, "CN=Test, O=Match", "CN=Test, O=Other", -1, 1, false)] // Organization mismatch
+ [InlineData(true, true, true, "CN=Test, O=Match, S=WA", "CN=Test, O=Match, S=XX", -1, 1, false)] // State mismatch
+ [InlineData(true, true, true, "CN=Test, O=Match, S=WA, C=US", "CN=Test, O=Match, S=WA, C=XX", -1, 1, false)] // Country mismatch
+ [InlineData(true, true, true, "CN=Test", "CN=Test", -100, -1, false)] // Expired certificate
+ public void Verify(bool checkCertificates, bool sign, bool allowUntrustedRoot, string signWith, string trustedSource, int start, int end, bool expectedResult)
+ {
+ var assembly = CompileScript("var i = 1;");
+
+ byte[] dllBytes = assembly;
+ if (sign)
+ {
+ // Generate a key pair
+ X509Certificate2 certificate = GenerateSelfSignedCertificate(signWith, DateTime.Now.AddDays(start), DateTime.Now.AddDays(end));
+
+ // Create a ContentInfo object from the DLL bytes
+ ContentInfo contentInfo = new ContentInfo(dllBytes);
+
+ // Create a SignedCms object
+ SignedCms signedCms = new SignedCms(contentInfo);
+
+ // Create a CmsSigner object
+ CmsSigner cmsSigner = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificate);
+
+ // Sign the DLL bytes
+ signedCms.ComputeSignature(cmsSigner);
+
+ // Get the signed bytes
+ byte[] signedBytes = signedCms.Encode();
+
+ dllBytes = signedBytes;
+ }
+
+ var checker = new TestEngineExtensionChecker(MockLogger.Object);
+ checker.CheckCertificates = () => checkCertificates;
+ checker.GetExtentionContents = (file) => assembly;
+
+ var settings = new TestSettingExtensions()
+ {
+ Enable = true
+ };
+ if (!string.IsNullOrEmpty(trustedSource))
+ {
+ settings.Parameters.Add("TrustedSource", trustedSource);
+ }
+ if (allowUntrustedRoot)
+ {
+ settings.Parameters.Add("AllowUntrustedRoot", "True");
+ }
+
+ var valid = false;
+ try
+ {
+ var tempFile = $"test.deleteme.{Guid.NewGuid()}.dll";
+ File.WriteAllBytes(tempFile, dllBytes);
+ if (checker.Verify(settings, tempFile))
+ {
+ valid = true;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ Assert.Equal(expectedResult, valid);
+ }
+
+ // Method to generate a self-signed X509Certificate2
+ static X509Certificate2 GenerateSelfSignedCertificate(string subjectName, DateTime validFrom, DateTime validTo)
+ {
+ using (RSA rsa = RSA.Create(2048)) // Generate a 2048-bit RSA key
+ {
+ var certRequest = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+
+ // Set certificate properties
+ certRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
+ certRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment, false));
+ certRequest.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("1.3.6.1.5.5.7.3.3") }, false));
+ certRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certRequest.PublicKey, false));
+
+ // Create the self-signed certificate
+ X509Certificate2 certificate = certRequest.CreateSelfSigned(validFrom, validTo);
+
+ return certificate;
+ }
+ }
+
+ private byte[] CompileScript(string script)
+ {
+ SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(script);
+ ScriptOptions options = ScriptOptions.Default;
+ var roslynScript = CSharpScript.Create(script, options);
+ var compilation = roslynScript.GetCompilation();
+
+ compilation = compilation.WithOptions(compilation.Options
+ .WithOptimizationLevel(OptimizationLevel.Release)
+ .WithOutputKind(OutputKind.DynamicallyLinkedLibrary));
+
+ using (var assemblyStream = new MemoryStream())
+ {
+ var result = compilation.Emit(assemblyStream);
+ if (!result.Success)
+ {
+ var errors = string.Join(Environment.NewLine, result.Diagnostics.Select(x => x));
+ throw new Exception("Compilation errors: " + Environment.NewLine + errors);
+ }
+
+ GC.Collect();
+ return assemblyStream.ToArray();
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/Modules/TestEngineModuleMEFLoaderTests.cs b/src/Microsoft.PowerApps.TestEngine.Tests/Modules/TestEngineModuleMEFLoaderTests.cs
new file mode 100644
index 000000000..046d26704
--- /dev/null
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/Modules/TestEngineModuleMEFLoaderTests.cs
@@ -0,0 +1,82 @@
+using System.ComponentModel.Composition.Hosting;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Microsoft.Extensions.Logging;
+using Microsoft.PowerApps.TestEngine.Config;
+using Microsoft.PowerApps.TestEngine.Modules;
+using Moq;
+using Xunit;
+
+namespace Microsoft.PowerApps.TestEngine.Tests.Modules
+{
+ public class TestEngineModuleMEFLoaderTests
+ {
+ Mock MockLogger;
+
+ public TestEngineModuleMEFLoaderTests()
+ {
+ MockLogger = new Mock();
+ }
+
+ [Fact]
+ public void DisabledEmptyCatalog()
+ {
+ var setting = new TestSettingExtensions() { Enable = false };
+ var loader = new TestEngineModuleMEFLoader(MockLogger.Object);
+
+ var catalog = loader.LoadModules(setting);
+
+ Assert.NotNull(catalog);
+ Assert.Equal(0, catalog.Catalogs.Count);
+ }
+
+ [Theory]
+ [InlineData(false, false, "", "", "", "AssemblyCatalog")]
+ [InlineData(false, false, "*", "foo", "testengine.module.foo.dll", "AssemblyCatalog")]
+ [InlineData(false, false, "foo", "*", "testengine.module.foo.dll", "AssemblyCatalog")]
+ [InlineData(false, false, "Foo", "*", "testengine.module.foo.dll", "AssemblyCatalog")]
+ [InlineData(false, false, "*", "foo*", "testengine.module.foo1.dll", "AssemblyCatalog")]
+ [InlineData(true, false, "*", "", "testengine.module.foo.dll", "AssemblyCatalog")]
+ [InlineData(true, true, "*", "", "testengine.module.foo.dll", "AssemblyCatalog,AssemblyCatalog")]
+ public void ModuleMatch(bool checkAssemblies, bool checkResult, string allow, string deny, string files, string expected)
+ {
+ var setting = new TestSettingExtensions()
+ {
+ Enable = true,
+ CheckAssemblies = checkAssemblies
+ };
+ Mock mockChecker = new Mock();
+
+ var loader = new TestEngineModuleMEFLoader(MockLogger.Object);
+ loader.DirectoryGetFiles = (location, pattern) =>
+ {
+ var searchPattern = Regex.Escape(pattern).Replace(@"\*", ".*?");
+ return files.Split(",").Where(f => Regex.IsMatch(f, searchPattern)).ToArray();
+ };
+ // Use current test assembly as test
+ loader.LoadAssembly = (file) => new AssemblyCatalog(this.GetType().Assembly);
+ loader.Checker = mockChecker.Object;
+
+ if (checkAssemblies)
+ {
+ mockChecker.Setup(x => x.Validate(It.IsAny(), files)).Returns(checkResult);
+ }
+
+ if (!string.IsNullOrEmpty(allow))
+ {
+ setting.AllowModule.Add(allow);
+ }
+
+ if (!string.IsNullOrEmpty(deny))
+ {
+ setting.DenyModule.Add(deny);
+ }
+
+ var catalog = loader.LoadModules(setting);
+
+ Assert.NotNull(catalog);
+ Assert.Equal(expected, string.Join(",", catalog.Catalogs.Select(c => c.GetType().Name)));
+ }
+ }
+}
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/PowerApps/PowerAppsUrlMapperTests.cs b/src/Microsoft.PowerApps.TestEngine.Tests/PowerApps/PowerAppsUrlMapperTests.cs
deleted file mode 100644
index f4d042d11..000000000
--- a/src/Microsoft.PowerApps.TestEngine.Tests/PowerApps/PowerAppsUrlMapperTests.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-using System;
-using Microsoft.Extensions.Logging;
-using Microsoft.PowerApps.TestEngine.Config;
-using Microsoft.PowerApps.TestEngine.PowerApps;
-using Microsoft.PowerApps.TestEngine.Tests.Helpers;
-using Moq;
-using Xunit;
-
-namespace Microsoft.PowerApps.TestEngine.Tests.PowerApps
-{
- public class PowerAppsUrlMapperTests
- {
- private Mock MockTestState;
- private Mock MockSingleTestInstanceState;
- private Mock MockLogger;
-
- public PowerAppsUrlMapperTests()
- {
- MockTestState = new Mock(MockBehavior.Strict);
- MockSingleTestInstanceState = new Mock(MockBehavior.Strict);
- MockLogger = new Mock(MockBehavior.Strict);
- }
-
- [Theory]
- [InlineData("myEnvironment", "apps.powerapps.com", "myApp", "appId", "myTenant", "https://apps.powerapps.com/play/e/myEnvironment/an/myApp?tenantId=myTenant&source=testengine&enablePATest=true&patestSDKVersion=0.0.1", "&enablePATest=true&patestSDKVersion=0.0.1")]
- [InlineData("myEnvironment", "apps.powerapps.com", "myApp", "appId", "myTenant", "https://apps.powerapps.com/play/e/myEnvironment/an/myApp?tenantId=myTenant&source=testengine", "")]
- [InlineData("defaultEnvironment", "apps.test.powerapps.com", "defaultApp", "appId", "defaultTenant", "https://apps.test.powerapps.com/play/e/defaultEnvironment/an/defaultApp?tenantId=defaultTenant&source=testengine", "")]
- [InlineData("defaultEnvironment", "apps.powerapps.com", null, "appId", "defaultTenant", "https://apps.powerapps.com/play/e/defaultEnvironment/a/appId?tenantId=defaultTenant&source=testengine", "")]
- public void GenerateAppUrlTest(string environmentId, string domain, string appLogicalName, string appId, string tenantId, string expectedAppUrl, string queryParams)
- {
- MockTestState.Setup(x => x.GetEnvironment()).Returns(environmentId);
- MockTestState.Setup(x => x.GetDomain()).Returns(domain);
- MockSingleTestInstanceState.Setup(x => x.GetTestSuiteDefinition()).Returns(new TestSuiteDefinition() { AppLogicalName = appLogicalName, AppId = appId });
- MockTestState.Setup(x => x.GetTenant()).Returns(tenantId);
- var powerAppUrlMapper = new PowerAppsUrlMapper(MockTestState.Object, MockSingleTestInstanceState.Object);
- Assert.Equal(expectedAppUrl, powerAppUrlMapper.GenerateTestUrl(domain, queryParams));
- MockTestState.Verify(x => x.GetEnvironment(), Times.Once());
- MockSingleTestInstanceState.Verify(x => x.GetTestSuiteDefinition(), Times.Once());
- MockTestState.Verify(x => x.GetTenant(), Times.Once());
- }
-
- [Theory]
- [InlineData("", "appLogicalName", "appId","tenantId")]
- [InlineData(null, "appLogicalName", "appId", "tenantId")]
- [InlineData("environmentId", "", "", "tenantId")]
- [InlineData("environmentId", null, null, "tenantId")]
- [InlineData("environmentId", "appLogicalName", "appId", "")]
- [InlineData("environmentId", "appLogicalName", "appId", null)]
- public void GenerateLoginUrlThrowsOnInvalidSetupTest(string environmentId, string appLogicalName, string appId, string tenantId)
- {
- MockTestState.Setup(x => x.GetEnvironment()).Returns(environmentId);
- MockSingleTestInstanceState.Setup(x => x.GetTestSuiteDefinition()).Returns(new TestSuiteDefinition() { AppLogicalName = appLogicalName, AppId = appId });
- MockTestState.Setup(x => x.GetTenant()).Returns(tenantId);
- MockSingleTestInstanceState.Setup(x => x.GetLogger()).Returns(MockLogger.Object);
- LoggingTestHelper.SetupMock(MockLogger);
- var powerAppUrlMapper = new PowerAppsUrlMapper(MockTestState.Object, MockSingleTestInstanceState.Object);
- Assert.Throws(() => powerAppUrlMapper.GenerateTestUrl("", ""));
- }
-
- [Fact]
- public void GenerateLoginUrlThrowsOnInvalidTestDefinitionTest()
- {
- TestSuiteDefinition testDefinition = null;
- MockTestState.Setup(x => x.GetEnvironment()).Returns("environmentId");
- MockSingleTestInstanceState.Setup(x => x.GetTestSuiteDefinition()).Returns(testDefinition);
- MockTestState.Setup(x => x.GetTenant()).Returns("tenantId");
- MockSingleTestInstanceState.Setup(x => x.GetLogger()).Returns(MockLogger.Object);
- LoggingTestHelper.SetupMock(MockLogger);
- var powerAppUrlMapper = new PowerAppsUrlMapper(MockTestState.Object, MockSingleTestInstanceState.Object);
- Assert.Throws(() => powerAppUrlMapper.GenerateTestUrl("", ""));
- }
- }
-}
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/AssertFunctionTests.cs b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/AssertFunctionTests.cs
index 8a15a0913..19068fcfc 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/AssertFunctionTests.cs
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/AssertFunctionTests.cs
@@ -4,8 +4,8 @@
using System;
using Microsoft.Extensions.Logging;
using Microsoft.PowerApps.TestEngine.PowerFx.Functions;
-using Microsoft.PowerApps.TestEngine.Tests.Helpers;
using Microsoft.PowerApps.TestEngine.System;
+using Microsoft.PowerApps.TestEngine.Tests.Helpers;
using Microsoft.PowerFx.Types;
using Moq;
using Xunit;
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SelectFunctionTests.cs b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SelectFunctionTests.cs
index 337e3aad0..99f74d634 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SelectFunctionTests.cs
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SelectFunctionTests.cs
@@ -6,8 +6,8 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.PowerApps.TestEngine.Config;
-using Microsoft.PowerApps.TestEngine.PowerApps;
-using Microsoft.PowerApps.TestEngine.PowerApps.PowerFxModel;
+using Microsoft.PowerApps.TestEngine.Providers;
+using Microsoft.PowerApps.TestEngine.Providers.PowerFxModel;
using Microsoft.PowerApps.TestEngine.PowerFx;
using Microsoft.PowerApps.TestEngine.PowerFx.Functions;
using Microsoft.PowerApps.TestEngine.Tests.Helpers;
@@ -19,13 +19,13 @@ namespace Microsoft.PowerApps.TestEngine.Tests.PowerFx.Functions
{
public class SelectFunctionTests
{
- private Mock MockPowerAppFunctions;
+ private Mock MockTestWebProvider;
private Mock MockTestState;
private Mock MockLogger;
public SelectFunctionTests()
{
- MockPowerAppFunctions = new Mock(MockBehavior.Strict);
+ MockTestWebProvider = new Mock(MockBehavior.Strict);
MockTestState = new Mock(MockBehavior.Strict);
MockLogger = new Mock(MockBehavior.Strict);
}
@@ -33,9 +33,9 @@ public SelectFunctionTests()
[Fact]
public void SelectFunctionThrowsOnNullObjectTest()
{
- var selectOneParamFunction = new SelectOneParamFunction(MockPowerAppFunctions.Object, () => Task.CompletedTask, MockLogger.Object);
- var selectTwoParamsFunction = new SelectTwoParamsFunction(MockPowerAppFunctions.Object, () => Task.CompletedTask, MockLogger.Object);
- var selectThreeParamsFunction = new SelectThreeParamsFunction(MockPowerAppFunctions.Object, () => Task.CompletedTask, MockLogger.Object);
+ var selectOneParamFunction = new SelectOneParamFunction(MockTestWebProvider.Object, () => Task.CompletedTask, MockLogger.Object);
+ var selectTwoParamsFunction = new SelectTwoParamsFunction(MockTestWebProvider.Object, () => Task.CompletedTask, MockLogger.Object);
+ var selectThreeParamsFunction = new SelectThreeParamsFunction(MockTestWebProvider.Object, () => Task.CompletedTask, MockLogger.Object);
Assert.ThrowsAny(() => selectOneParamFunction.Execute(null));
Assert.ThrowsAny(() => selectTwoParamsFunction.Execute(null, null));
@@ -46,9 +46,9 @@ public void SelectFunctionThrowsOnNullObjectTest()
public void SelectFunctionThrowsOnNonPowerAppsRecordValuetTest()
{
var recordType = RecordType.Empty().Add("Text", FormulaType.String);
- var selectOneParamFunction = new SelectOneParamFunction(MockPowerAppFunctions.Object, () => Task.CompletedTask, MockLogger.Object);
- var selectTwoParamsFunction = new SelectTwoParamsFunction(MockPowerAppFunctions.Object, () => Task.CompletedTask, MockLogger.Object);
- var selectThreeParamsFunction = new SelectThreeParamsFunction(MockPowerAppFunctions.Object, () => Task.CompletedTask, MockLogger.Object);
+ var selectOneParamFunction = new SelectOneParamFunction(MockTestWebProvider.Object, () => Task.CompletedTask, MockLogger.Object);
+ var selectTwoParamsFunction = new SelectTwoParamsFunction(MockTestWebProvider.Object, () => Task.CompletedTask, MockLogger.Object);
+ var selectThreeParamsFunction = new SelectThreeParamsFunction(MockTestWebProvider.Object, () => Task.CompletedTask, MockLogger.Object);
var someOtherRecordValue = new SomeOtherRecordValue(recordType);
Assert.ThrowsAny(() => selectOneParamFunction.Execute(someOtherRecordValue));
@@ -59,23 +59,23 @@ public void SelectFunctionThrowsOnNonPowerAppsRecordValuetTest()
[Fact]
public void SelectOneParamFunctionTest()
{
- MockPowerAppFunctions.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(true));
LoggingTestHelper.SetupMock(MockLogger);
var recordType = RecordType.Empty().Add("Text", FormulaType.String);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Button1");
-
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Button1");
+
var updaterFunctionCallCount = 0;
var updaterFunction = () =>
{
updaterFunctionCallCount++;
return Task.CompletedTask;
};
- var selectFunction = new SelectOneParamFunction(MockPowerAppFunctions.Object, updaterFunction, MockLogger.Object);
-
+ var selectFunction = new SelectOneParamFunction(MockTestWebProvider.Object, updaterFunction, MockLogger.Object);
+
var result = selectFunction.Execute(recordValue);
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == recordValue.Name)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == recordValue.Name)), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n\n" + "Executing Select function.", LogLevel.Information, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "Successfully finished executing Select function.", LogLevel.Information, Times.Once());
Assert.Equal(1, updaterFunctionCallCount);
@@ -84,11 +84,11 @@ public void SelectOneParamFunctionTest()
[Fact]
public void SelectTwoParamFunctionTest()
{
- MockPowerAppFunctions.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(true));
LoggingTestHelper.SetupMock(MockLogger);
var recordType = RecordType.Empty().Add("Gallery1", RecordType.Empty());
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Gallery1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Gallery1");
var rowOrColumn = NumberValue.New(1.0);
var updaterFunctionCallCount = 0;
@@ -97,11 +97,11 @@ public void SelectTwoParamFunctionTest()
updaterFunctionCallCount++;
return Task.CompletedTask;
};
- var selectFunction = new SelectTwoParamsFunction(MockPowerAppFunctions.Object, updaterFunction, MockLogger.Object);
+ var selectFunction = new SelectTwoParamsFunction(MockTestWebProvider.Object, updaterFunction, MockLogger.Object);
var result = selectFunction.Execute(recordValue, rowOrColumn);
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == recordValue.Name)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == recordValue.Name)), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n\n" + "Executing Select function.", LogLevel.Information, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "Successfully finished executing Select function.", LogLevel.Information, Times.Once());
Assert.Equal(1, updaterFunctionCallCount);
@@ -110,14 +110,14 @@ public void SelectTwoParamFunctionTest()
[Fact]
public void SelectThreeParamFunctionTest()
{
- MockPowerAppFunctions.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(true));
LoggingTestHelper.SetupMock(MockLogger);
var parentRecordType = RecordType.Empty().Add("Gallery1", RecordType.Empty());
var childRecordType = RecordType.Empty().Add("Button1", RecordType.Empty());
- var parentValue = new ControlRecordValue(parentRecordType, MockPowerAppFunctions.Object, "Gallery1");
+ var parentValue = new ControlRecordValue(parentRecordType, MockTestWebProvider.Object, "Gallery1");
var rowOrColumn = NumberValue.New(1.0);
- var childValue = new ControlRecordValue(childRecordType, MockPowerAppFunctions.Object,"Button1");
+ var childValue = new ControlRecordValue(childRecordType, MockTestWebProvider.Object, "Button1");
var updaterFunctionCallCount = 0;
var updaterFunction = () =>
@@ -125,11 +125,11 @@ public void SelectThreeParamFunctionTest()
updaterFunctionCallCount++;
return Task.CompletedTask;
};
- var selectFunction = new SelectThreeParamsFunction(MockPowerAppFunctions.Object, updaterFunction, MockLogger.Object);
-
+ var selectFunction = new SelectThreeParamsFunction(MockTestWebProvider.Object, updaterFunction, MockLogger.Object);
+
var result = selectFunction.Execute(parentValue, rowOrColumn, childValue);
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == childValue.Name)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == childValue.Name)), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n\n" + "Executing Select function.", LogLevel.Information, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "Successfully finished executing Select function.", LogLevel.Information, Times.Once());
Assert.Equal(1, updaterFunctionCallCount);
@@ -139,22 +139,22 @@ public void SelectThreeParamFunctionTest()
public void SelectOneParamFunctionFailsTest()
{
LoggingTestHelper.SetupMock(MockLogger);
- MockPowerAppFunctions.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(false));
-
+ MockTestWebProvider.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(false));
+
var recordType = RecordType.Empty().Add("Text", FormulaType.String);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Button1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Button1");
var updaterFunctionCallCount = 0;
var updaterFunction = () =>
{
updaterFunctionCallCount++;
return Task.CompletedTask;
- };
- var selectFunction = new SelectOneParamFunction(MockPowerAppFunctions.Object, updaterFunction, MockLogger.Object);
+ };
+ var selectFunction = new SelectOneParamFunction(MockTestWebProvider.Object, updaterFunction, MockLogger.Object);
Assert.ThrowsAny(() => selectFunction.Execute(recordValue));
- MockPowerAppFunctions.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == recordValue.Name)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == recordValue.Name)), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n\n" + "Executing Select function.", LogLevel.Information, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "Control name: Button1", LogLevel.Trace, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "Unable to select control", LogLevel.Error, Times.Once());
@@ -164,11 +164,11 @@ public void SelectOneParamFunctionFailsTest()
[Fact]
public void SelectTwoParamFunctionFailsTest()
{
- MockPowerAppFunctions.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(false));
+ MockTestWebProvider.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(false));
LoggingTestHelper.SetupMock(MockLogger);
var recordType = RecordType.Empty().Add("Gallery1", RecordType.Empty());
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Gallery1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Gallery1");
var rowOrColumn = NumberValue.New(1.0);
var updaterFunctionCallCount = 0;
@@ -177,19 +177,19 @@ public void SelectTwoParamFunctionFailsTest()
updaterFunctionCallCount++;
return Task.CompletedTask;
};
- var selectFunction = new SelectTwoParamsFunction(MockPowerAppFunctions.Object, updaterFunction, MockLogger.Object);
+ var selectFunction = new SelectTwoParamsFunction(MockTestWebProvider.Object, updaterFunction, MockLogger.Object);
// Testing Scenarios where members(control, row or column) are null
Assert.ThrowsAny(() => selectFunction.Execute(null, rowOrColumn));
Assert.ThrowsAny(() => selectFunction.Execute(recordValue, null));
// Adding test where control names are null
- recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, null);
+ recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, null);
Assert.ThrowsAny(() => selectFunction.Execute(recordValue, rowOrColumn));
- recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Gallery1");
+ recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Gallery1");
Assert.ThrowsAny(() => selectFunction.Execute(recordValue, rowOrColumn));
- MockPowerAppFunctions.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == recordValue.Name)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == recordValue.Name)), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n\n" + "Executing Select function.", LogLevel.Information, Times.AtLeastOnce());
LoggingTestHelper.VerifyLogging(MockLogger, "Control name: Gallery1", LogLevel.Trace, Times.AtLeastOnce());
LoggingTestHelper.VerifyLogging(MockLogger, "Unable to select control", LogLevel.Error, Times.AtLeastOnce());
@@ -199,14 +199,14 @@ public void SelectTwoParamFunctionFailsTest()
[Fact]
public void SelectThreeParamFunctionFailsTest()
{
- MockPowerAppFunctions.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(false));
+ MockTestWebProvider.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(false));
LoggingTestHelper.SetupMock(MockLogger);
var parentRecordType = RecordType.Empty().Add("Gallery1", RecordType.Empty());
var childRecordType = RecordType.Empty().Add("Button1", RecordType.Empty());
- var parentValue = new ControlRecordValue(parentRecordType, MockPowerAppFunctions.Object, "Gallery1");
+ var parentValue = new ControlRecordValue(parentRecordType, MockTestWebProvider.Object, "Gallery1");
var rowOrColumn = NumberValue.New(1.0);
- var childValue = new ControlRecordValue(childRecordType, MockPowerAppFunctions.Object, "Button1");
+ var childValue = new ControlRecordValue(childRecordType, MockTestWebProvider.Object, "Button1");
var updaterFunctionCallCount = 0;
var updaterFunction = () =>
@@ -214,7 +214,7 @@ public void SelectThreeParamFunctionFailsTest()
updaterFunctionCallCount++;
return Task.CompletedTask;
};
- var selectFunction = new SelectThreeParamsFunction(MockPowerAppFunctions.Object, updaterFunction, MockLogger.Object);
+ var selectFunction = new SelectThreeParamsFunction(MockTestWebProvider.Object, updaterFunction, MockLogger.Object);
// Testing Scenarios where members(parent control, row or column and child control) are null
Assert.ThrowsAny(() => selectFunction.Execute(null, rowOrColumn, childValue));
@@ -222,14 +222,14 @@ public void SelectThreeParamFunctionFailsTest()
Assert.ThrowsAny(() => selectFunction.Execute(parentValue, rowOrColumn, null));
// Adding test where control names are null
- parentValue = new ControlRecordValue(parentRecordType, MockPowerAppFunctions.Object, null);
- childValue = new ControlRecordValue(childRecordType, MockPowerAppFunctions.Object, null);
+ parentValue = new ControlRecordValue(parentRecordType, MockTestWebProvider.Object, null);
+ childValue = new ControlRecordValue(childRecordType, MockTestWebProvider.Object, null);
Assert.ThrowsAny(() => selectFunction.Execute(parentValue, rowOrColumn, childValue));
- parentValue = new ControlRecordValue(parentRecordType, MockPowerAppFunctions.Object, "Gallery1");
- childValue = new ControlRecordValue(childRecordType, MockPowerAppFunctions.Object, "Button1");
+ parentValue = new ControlRecordValue(parentRecordType, MockTestWebProvider.Object, "Gallery1");
+ childValue = new ControlRecordValue(childRecordType, MockTestWebProvider.Object, "Button1");
Assert.ThrowsAny(() => selectFunction.Execute(parentValue, rowOrColumn, childValue));
- MockPowerAppFunctions.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == childValue.Name)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == childValue.Name)), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, "------------------------------\n\n" + "Executing Select function.", LogLevel.Information, Times.AtLeastOnce());
LoggingTestHelper.VerifyLogging(MockLogger, "Control name: Button1", LogLevel.Trace, Times.AtLeastOnce());
LoggingTestHelper.VerifyLogging(MockLogger, "Unable to select control", LogLevel.Error, Times.AtLeastOnce());
@@ -239,7 +239,7 @@ public void SelectThreeParamFunctionFailsTest()
[Fact]
public void SelectGalleryTest()
{
- MockPowerAppFunctions.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.SelectControlAsync(It.IsAny())).Returns(Task.FromResult(true));
LoggingTestHelper.SetupMock(MockLogger);
var parentRecordType = RecordType.Empty().Add("Gallery1", RecordType.Empty());
var childRecordType = RecordType.Empty().Add("Button1", RecordType.Empty());
@@ -269,23 +269,23 @@ public void SelectGalleryTest()
};
var recordType = RecordType.Empty().Add("Button1", RecordType.Empty());
- var powerAppControlModel = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Button1", parentItemPath);
+ var powerAppControlModel = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Button1", parentItemPath);
- var selectFunction = new SelectOneParamFunction(MockPowerAppFunctions.Object, updaterFunction, MockLogger.Object);
+ var selectFunction = new SelectOneParamFunction(MockTestWebProvider.Object, updaterFunction, MockLogger.Object);
var result = selectFunction.Execute(powerAppControlModel);
Assert.IsType(result);
// Select gallery item using threeparams select function
// `Select(Gallery1, 1, Button1);`
- var parentValue = new ControlRecordValue(parentRecordType, MockPowerAppFunctions.Object, "Gallery1");
+ var parentValue = new ControlRecordValue(parentRecordType, MockTestWebProvider.Object, "Gallery1");
var rowOrColumn = NumberValue.New(1.0);
- var childValue = new ControlRecordValue(childRecordType, MockPowerAppFunctions.Object, "Button1");
+ var childValue = new ControlRecordValue(childRecordType, MockTestWebProvider.Object, "Button1");
- var selectthreeParamsFunction = new SelectThreeParamsFunction(MockPowerAppFunctions.Object, updaterFunction, MockLogger.Object);
+ var selectthreeParamsFunction = new SelectThreeParamsFunction(MockTestWebProvider.Object, updaterFunction, MockLogger.Object);
result = selectthreeParamsFunction.Execute(parentValue, rowOrColumn, childValue);
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == childValue.Name)), Times.Exactly(2));
+ MockTestWebProvider.Verify(x => x.SelectControlAsync(It.Is((item) => item.ControlName == childValue.Name)), Times.Exactly(2));
Assert.Equal(2, updaterFunctionCallCount);
}
}
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SetPropertyFunctionTests.cs b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SetPropertyFunctionTests.cs
index b506dfde6..cb30d931b 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SetPropertyFunctionTests.cs
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SetPropertyFunctionTests.cs
@@ -6,8 +6,8 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.PowerApps.TestEngine.Config;
-using Microsoft.PowerApps.TestEngine.PowerApps;
-using Microsoft.PowerApps.TestEngine.PowerApps.PowerFxModel;
+using Microsoft.PowerApps.TestEngine.Providers;
+using Microsoft.PowerApps.TestEngine.Providers.PowerFxModel;
using Microsoft.PowerApps.TestEngine.PowerFx.Functions;
using Microsoft.PowerApps.TestEngine.Tests.Helpers;
using Microsoft.PowerFx.Types;
@@ -18,13 +18,13 @@ namespace Microsoft.PowerApps.TestEngine.Tests.PowerFx.Functions
{
public class SetPropertyFunctionTests
{
- private Mock MockPowerAppFunctions;
+ private Mock MockTestWebProvider;
private Mock MockTestState;
private Mock MockLogger;
public SetPropertyFunctionTests()
{
- MockPowerAppFunctions = new Mock(MockBehavior.Strict);
+ MockTestWebProvider = new Mock(MockBehavior.Strict);
MockTestState = new Mock(MockBehavior.Strict);
MockLogger = new Mock(MockBehavior.Strict);
}
@@ -33,7 +33,7 @@ public SetPropertyFunctionTests()
public void SetPropertyFunctionThrowsOnNonPowerAppsRecordValueTest()
{
var recordType = RecordType.Empty().Add("Text", FormulaType.String);
- var SetPropertyFunctionString = new SetPropertyFunction(MockPowerAppFunctions.Object, MockLogger.Object);
+ var SetPropertyFunctionString = new SetPropertyFunction(MockTestWebProvider.Object, MockLogger.Object);
var someOtherRecordValue = new SomeOtherRecordValue(recordType);
Assert.ThrowsAny(() => SetPropertyFunctionString.Execute(someOtherRecordValue, StringValue.New("Test"), StringValue.New("10")));
@@ -42,16 +42,16 @@ public void SetPropertyFunctionThrowsOnNonPowerAppsRecordValueTest()
[Fact]
public void SetPropertyFunctionFailsTest()
{
- MockPowerAppFunctions.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(false));
+ MockTestWebProvider.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(false));
LoggingTestHelper.SetupMock(MockLogger);
var recordType = RecordType.Empty().Add("Text", FormulaType.String);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Button1");
- var setPropertyFunctionString = new SetPropertyFunction(MockPowerAppFunctions.Object, MockLogger.Object);
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Button1");
+ var setPropertyFunctionString = new SetPropertyFunction(MockTestWebProvider.Object, MockLogger.Object);
// This tests the SetPropertyAsync returning false and hence throwing exception
Assert.ThrowsAny(() => setPropertyFunctionString.Execute(recordValue, StringValue.New("Text"), StringValue.New("5")));
- MockPowerAppFunctions.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(stringVal => stringVal.Value == "5")), Times.Once());
+ MockTestWebProvider.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(stringVal => stringVal.Value == "5")), Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, (string)"Error occurred on DataType of type Microsoft.PowerFx.Types.StringValue", LogLevel.Debug, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, (string)"Property name: Text", LogLevel.Trace, Times.Once());
LoggingTestHelper.VerifyLogging(MockLogger, (string)"Unable to set property with SetProperty function.", LogLevel.Error, Times.Once());
@@ -60,84 +60,84 @@ public void SetPropertyFunctionFailsTest()
[Fact]
public void SetPropertyStringFunctionTest()
{
- MockPowerAppFunctions.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
LoggingTestHelper.SetupMock(MockLogger);
// Make setPropertyFunction contain a text component called Button1
var recordType = RecordType.Empty().Add("Text", FormulaType.String);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Button1");
- var setPropertyFunctionString = new SetPropertyFunction(MockPowerAppFunctions.Object, MockLogger.Object);
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Button1");
+ var setPropertyFunctionString = new SetPropertyFunction(MockTestWebProvider.Object, MockLogger.Object);
// Set the value of Button1's 'Text' property to 5
var result = setPropertyFunctionString.Execute(recordValue, StringValue.New("Text"), StringValue.New("5"));
// check to see if the value of Button1's 'Text' property is 5
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(stringVal => stringVal.Value == "5")), Times.Once());
+ MockTestWebProvider.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(stringVal => stringVal.Value == "5")), Times.Once());
// Set the value of Button1's 'Text' property to 10
result = setPropertyFunctionString.Execute(recordValue, StringValue.New("Text"), StringValue.New("10"));
// check to see if the value of Button1's 'Text' property is 10
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(stringVal => stringVal.Value == "10")), Times.Once());
+ MockTestWebProvider.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(stringVal => stringVal.Value == "10")), Times.Once());
// Set the value of Button1's 'Text' property to 'abc'
result = setPropertyFunctionString.Execute(recordValue, StringValue.New("Text"), StringValue.New("abc"));
// check to see if the value of Button1's 'Text' property is abc
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(stringVal => stringVal.Value == "abc")), Times.Once());
+ MockTestWebProvider.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(stringVal => stringVal.Value == "abc")), Times.Once());
}
[Fact]
public void SetPropertyNumberFunctionTest()
{
- MockPowerAppFunctions.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
LoggingTestHelper.SetupMock(MockLogger);
// Make setPropertyFunction contain a component called Rating1
var recordType = RecordType.Empty().Add("Value", FormulaType.Number);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Rating1");
- var setPropertyFunction = new SetPropertyFunction(MockPowerAppFunctions.Object, MockLogger.Object);
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Rating1");
+ var setPropertyFunction = new SetPropertyFunction(MockTestWebProvider.Object, MockLogger.Object);
// Set the value of Rating1's 'Value' property to 5
var result = setPropertyFunction.Execute(recordValue, StringValue.New("Value"), NumberValue.New(5d));
// check to see if the value of Rating1's 'Value' property is 5
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(numVal => numVal.Value == 5)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(numVal => numVal.Value == 5)), Times.Once());
}
[Fact]
public void SetPropertyBooleanFunctionTest()
{
- MockPowerAppFunctions.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
LoggingTestHelper.SetupMock(MockLogger);
// Make setPropertyFunction contain a component called Toggle1
var recordType = RecordType.Empty().Add("Value", FormulaType.Boolean);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Toggle1");
- var setPropertyFunction = new SetPropertyFunction(MockPowerAppFunctions.Object, MockLogger.Object);
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Toggle1");
+ var setPropertyFunction = new SetPropertyFunction(MockTestWebProvider.Object, MockLogger.Object);
// Set the value of Toggle1's 'Value' property to true
var result = setPropertyFunction.Execute(recordValue, StringValue.New("Value"), BooleanValue.New(true));
// check to see if the value of Toggle1's 'Value' property is true
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(boolVal => boolVal.Value == true)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(boolVal => boolVal.Value == true)), Times.Once());
}
[Fact]
public void SetPropertyDateFunctionTest()
{
- MockPowerAppFunctions.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
LoggingTestHelper.SetupMock(MockLogger);
// Make setPropertyFunction contain a component called DatePicker1
var recordType = RecordType.Empty().Add("Value", FormulaType.Date);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "DatePicker1");
- var setPropertyFunction = new SetPropertyFunction(MockPowerAppFunctions.Object, MockLogger.Object);
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "DatePicker1");
+ var setPropertyFunction = new SetPropertyFunction(MockTestWebProvider.Object, MockLogger.Object);
// Set the value of DatePicker1's 'Value' property to the datetime (01/01/2030)
var dt = new DateTime(2030, 1, 1, 0, 0, 0);
@@ -145,19 +145,19 @@ public void SetPropertyDateFunctionTest()
// check to see if the value of DatePicker1's 'Value' property is the correct datetime (01/01/2030)
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(dateVal => dateVal.GetConvertedValue(null) == dt)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(dateVal => dateVal.GetConvertedValue(null) == dt)), Times.Once());
}
[Fact]
public void SetPropertyRecordFunctionTest()
{
- MockPowerAppFunctions.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
LoggingTestHelper.SetupMock(MockLogger);
// Make setPropertyFunction contain a component called Dropdown1
var recordType = RecordType.Empty().Add("Selected", RecordType.Empty());
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Dropdown1");
- var setPropertyFunction = new SetPropertyFunction(MockPowerAppFunctions.Object, MockLogger.Object);
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Dropdown1");
+ var setPropertyFunction = new SetPropertyFunction(MockTestWebProvider.Object, MockLogger.Object);
// Set the value of Dropdown1's 'Selected' property to {"Value":"2"}
var pair = new KeyValuePair("Value", StringValue.New("2"));
@@ -166,18 +166,18 @@ public void SetPropertyRecordFunctionTest()
// check to see if the value of Dropdown1's 'Selected' property is "2"
Assert.IsType(result);
- MockPowerAppFunctions.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(recordVal => ((StringValue)recordVal.GetField("Value")).Value == "2")), Times.Once());
+ MockTestWebProvider.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(recordVal => ((StringValue)recordVal.GetField("Value")).Value == "2")), Times.Once());
}
[Fact]
public void SetPropertyTableFunctionTest()
{
- MockPowerAppFunctions.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
- MockPowerAppFunctions.Setup(x => x.GetItemCount(It.IsAny())).Returns(2);
+ MockTestWebProvider.Setup(x => x.SetPropertyAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(true));
+ MockTestWebProvider.Setup(x => x.GetItemCount(It.IsAny())).Returns(2);
LoggingTestHelper.SetupMock(MockLogger);
- var setPropertyFunction = new SetPropertyFunction(MockPowerAppFunctions.Object, MockLogger.Object);
+ var setPropertyFunction = new SetPropertyFunction(MockTestWebProvider.Object, MockLogger.Object);
var control1Name = Guid.NewGuid().ToString();
var control2Name = Guid.NewGuid().ToString();
var control1Type = RecordType.Empty().Add("Value", FormulaType.String);
@@ -190,14 +190,14 @@ public void SetPropertyTableFunctionTest()
};
var recordType = tableType.ToRecord();
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "ComboBox1");
- var tableSource = new ControlTableSource(MockPowerAppFunctions.Object, itemPath, recordType);
- var tableValue = new ControlTableValue(recordType, tableSource, MockPowerAppFunctions.Object);
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "ComboBox1");
+ var tableSource = new ControlTableSource(MockTestWebProvider.Object, itemPath, recordType);
+ var tableValue = new ControlTableValue(recordType, tableSource, MockTestWebProvider.Object);
var result = setPropertyFunction.Execute(recordValue, StringValue.New("SelectedItems"), tableValue);
Assert.IsType(result);
Assert.Equal(2, tableSource.Count);
- MockPowerAppFunctions.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(tableVal => tableVal.Count() == 2)), Times.Once());
+ MockTestWebProvider.Verify(x => x.SetPropertyAsync(It.Is((item) => item.ControlName == recordValue.Name), It.Is(tableVal => tableVal.Count() == 2)), Times.Once());
}
}
}
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SomeOtherUntypedObject.cs b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SomeOtherUntypedObject.cs
index e281b3c91..b6a68f992 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SomeOtherUntypedObject.cs
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/SomeOtherUntypedObject.cs
@@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
+using System.Collections.Generic;
using Microsoft.PowerFx.Types;
using NotImplementedException = System.NotImplementedException;
-using System.Collections.Generic;
namespace Microsoft.PowerApps.TestEngine.Tests.PowerFx.Functions
{
diff --git a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/WaitFunctionTests.cs b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/WaitFunctionTests.cs
index 060c5aad0..8fadc932b 100644
--- a/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/WaitFunctionTests.cs
+++ b/src/Microsoft.PowerApps.TestEngine.Tests/PowerFx/Functions/WaitFunctionTests.cs
@@ -6,8 +6,8 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.PowerApps.TestEngine.Config;
-using Microsoft.PowerApps.TestEngine.PowerApps;
-using Microsoft.PowerApps.TestEngine.PowerApps.PowerFxModel;
+using Microsoft.PowerApps.TestEngine.Providers;
+using Microsoft.PowerApps.TestEngine.Providers.PowerFxModel;
using Microsoft.PowerApps.TestEngine.PowerFx.Functions;
using Microsoft.PowerApps.TestEngine.Tests.Helpers;
using Microsoft.PowerFx.Types;
@@ -19,7 +19,7 @@ namespace Microsoft.PowerApps.TestEngine.Tests.PowerFx.Functions
{
public class WaitFunctionTests
{
- private Mock MockPowerAppFunctions;
+ private Mock MockTestWebProvider;
private Mock MockTestState;
private Mock MockLogger;
@@ -28,7 +28,7 @@ public class WaitFunctionTests
public WaitFunctionTests()
{
Timeout = 30000;
- MockPowerAppFunctions = new Mock(MockBehavior.Strict);
+ MockTestWebProvider = new Mock(MockBehavior.Strict);
MockTestState = new Mock(MockBehavior.Strict);
MockLogger = new Mock(MockBehavior.Strict);
}
@@ -39,7 +39,7 @@ public void WaitFunctionStringThrowsOnInvalidArgumentsTest()
LoggingTestHelper.SetupMock(MockLogger);
var recordType = RecordType.Empty().Add("Text", FormulaType.String);
var waitFunction = new WaitFunctionString(Timeout, MockLogger.Object);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Label1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Label1");
Assert.Throws(() => waitFunction.Execute(null, FormulaValue.New("Text"), FormulaValue.New("1")));
Assert.Throws(() => waitFunction.Execute(new SomeOtherRecordValue(recordType), null, FormulaValue.New("1")));
Assert.Throws(() => waitFunction.Execute(new SomeOtherRecordValue(recordType), FormulaValue.New("Text"), null));
@@ -52,7 +52,7 @@ public void WaitFunctionNumberThrowsOnInvalidArgumentsTest()
LoggingTestHelper.SetupMock(MockLogger);
var recordType = RecordType.Empty().Add("Text", FormulaType.Number);
var waitFunction = new WaitFunctionNumber(Timeout, MockLogger.Object);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Label1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Label1");
Assert.Throws(() => waitFunction.Execute(null, FormulaValue.New("Text"), FormulaValue.New(1d)));
Assert.Throws(() => waitFunction.Execute(new SomeOtherRecordValue(recordType), null, FormulaValue.New(1d)));
Assert.Throws(() => waitFunction.Execute(new SomeOtherRecordValue(recordType), FormulaValue.New("Text"), null));
@@ -65,7 +65,7 @@ public void WaitFunctionBooleanThrowsOnInvalidArgumentsTest()
LoggingTestHelper.SetupMock(MockLogger);
var recordType = RecordType.Empty().Add("Text", FormulaType.Boolean);
var waitFunction = new WaitFunctionBoolean(Timeout, MockLogger.Object);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Label1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Label1");
Assert.Throws(() => waitFunction.Execute(null, FormulaValue.New("Text"), FormulaValue.New(false)));
Assert.Throws(() => waitFunction.Execute(new SomeOtherRecordValue(recordType), null, FormulaValue.New(false)));
Assert.Throws(() => waitFunction.Execute(new SomeOtherRecordValue(recordType), FormulaValue.New("Text"), null));
@@ -79,7 +79,7 @@ public void WaitFunctionDateThrowsOnInvalidArgumentsTest()
var value = new DateTime(1970, 1, 1, 0, 0, 0);
var recordType = RecordType.Empty().Add("Text", FormulaType.Date);
var waitFunction = new WaitFunctionDate(Timeout, MockLogger.Object);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Label1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Label1");
Assert.Throws(() => waitFunction.Execute(null, FormulaValue.New("Text"), FormulaValue.NewDateOnly(value.Date)));
Assert.Throws(() => waitFunction.Execute(new SomeOtherRecordValue(recordType), null, FormulaValue.NewDateOnly(value.Date)));
Assert.Throws(() => waitFunction.Execute(new SomeOtherRecordValue(recordType), FormulaValue.New("Text"), null));
@@ -92,7 +92,7 @@ public void WaitFunctionStringSucceedsTest()
LoggingTestHelper.SetupMock(MockLogger);
var valueToWaitFor = "1";
var recordType = RecordType.Empty().Add("Text", FormulaType.String);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Label1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Label1");
var jsPropertyValueModel = new JSPropertyValueModel()
{
PropertyValue = valueToWaitFor,
@@ -102,14 +102,14 @@ public void WaitFunctionStringSucceedsTest()
ControlName = "Label1",
PropertyName = "Text"
};
- MockPowerAppFunctions.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
+ MockTestWebProvider.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
.Returns(JsonConvert.SerializeObject(jsPropertyValueModel));
MockTestState.Setup(x => x.GetTimeout()).Returns(Timeout);
var waitFunction = new WaitFunctionString(Timeout, MockLogger.Object);
waitFunction.Execute(recordValue, FormulaValue.New("Text"), FormulaValue.New(valueToWaitFor));
- MockPowerAppFunctions.Verify(x => x.GetPropertyValueFromControl(It.Is((itemPath) => itemPath.ControlName == expectedItemPath.ControlName && itemPath.PropertyName == expectedItemPath.PropertyName)), Times.Exactly(2));
+ MockTestWebProvider.Verify(x => x.GetPropertyValueFromControl(It.Is((itemPath) => itemPath.ControlName == expectedItemPath.ControlName && itemPath.PropertyName == expectedItemPath.PropertyName)), Times.Exactly(2));
}
[Fact]
@@ -118,7 +118,7 @@ public void WaitFunctionImproperValueForStringTest()
LoggingTestHelper.SetupMock(MockLogger);
var valueToWaitFor = true;
var recordType = RecordType.Empty().Add("Value", FormulaType.Boolean);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Toggle1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Toggle1");
var jsPropertyValueModel = new JSPropertyValueModel()
{
PropertyValue = valueToWaitFor.ToString(),
@@ -128,7 +128,7 @@ public void WaitFunctionImproperValueForStringTest()
ControlName = "Toggle1",
PropertyName = "Value"
};
- MockPowerAppFunctions.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
+ MockTestWebProvider.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
.Returns(JsonConvert.SerializeObject(jsPropertyValueModel));
MockTestState.Setup(x => x.GetTimeout()).Returns(Timeout);
@@ -144,7 +144,7 @@ public void WaitFunctionNumberSucceedsTest()
var valueToWaitFor = 1d;
var recordType = RecordType.Empty().Add("Text", FormulaType.Number);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Label1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Label1");
var jsPropertyValueModel = new JSPropertyValueModel()
{
PropertyValue = valueToWaitFor.ToString("G"),
@@ -154,14 +154,14 @@ public void WaitFunctionNumberSucceedsTest()
ControlName = "Label1",
PropertyName = "Text"
};
- MockPowerAppFunctions.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
+ MockTestWebProvider.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
.Returns(JsonConvert.SerializeObject(jsPropertyValueModel));
MockTestState.Setup(x => x.GetTimeout()).Returns(Timeout);
var waitFunction = new WaitFunctionNumber(Timeout, MockLogger.Object);
waitFunction.Execute(recordValue, FormulaValue.New("Text"), FormulaValue.New(valueToWaitFor));
- MockPowerAppFunctions.Verify(x => x.GetPropertyValueFromControl(It.Is((itemPath) => itemPath.ControlName == expectedItemPath.ControlName && itemPath.PropertyName == expectedItemPath.PropertyName)), Times.Exactly(2));
+ MockTestWebProvider.Verify(x => x.GetPropertyValueFromControl(It.Is((itemPath) => itemPath.ControlName == expectedItemPath.ControlName && itemPath.PropertyName == expectedItemPath.PropertyName)), Times.Exactly(2));
}
[Fact]
@@ -170,7 +170,7 @@ public void WaitFunctionImproperValueForNumberTest()
LoggingTestHelper.SetupMock(MockLogger);
var valueToWaitFor = true;
var recordType = RecordType.Empty().Add("Value", FormulaType.Boolean);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Toggle1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Toggle1");
var jsPropertyValueModel = new JSPropertyValueModel()
{
PropertyValue = valueToWaitFor.ToString(),
@@ -180,7 +180,7 @@ public void WaitFunctionImproperValueForNumberTest()
ControlName = "Toggle1",
PropertyName = "Value"
};
- MockPowerAppFunctions.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
+ MockTestWebProvider.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
.Returns(JsonConvert.SerializeObject(jsPropertyValueModel));
MockTestState.Setup(x => x.GetTimeout()).Returns(Timeout);
@@ -193,7 +193,7 @@ public void WaitFunctionBooleanSucceedsTest()
{
var valueToWaitFor = false;
var recordType = RecordType.Empty().Add("Text", FormulaType.Boolean);
- var recordValue = new ControlRecordValue(recordType, MockPowerAppFunctions.Object, "Label1");
+ var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Label1");
var jsPropertyValueModel = new JSPropertyValueModel()
{
PropertyValue = valueToWaitFor.ToString(),
@@ -203,7 +203,7 @@ public void WaitFunctionBooleanSucceedsTest()
ControlName = "Label1",
PropertyName = "Text"
};
- MockPowerAppFunctions.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
+ MockTestWebProvider.Setup(x => x.GetPropertyValueFromControl(It.IsAny()))
.Returns(JsonConvert.SerializeObject(jsPropertyValueModel));
MockTestState.Setup(x => x.GetTimeout()).Returns(Timeout);
LoggingTestHelper.SetupMock(MockLogger);
@@ -211,7 +211,7 @@ public void WaitFunctionBooleanSucceedsTest()
var waitFunction = new WaitFunctionBoolean(Timeout, MockLogger.Object);
waitFunction.Execute(recordValue, FormulaValue.New("Text"), BooleanValue.New(valueToWaitFor));
- MockPowerAppFunctions.Verify(x => x.GetPropertyValueFromControl