Skip to content

Commit

Permalink
Adding Experimental.SelectControl() for MDA custom pages
Browse files Browse the repository at this point in the history
  • Loading branch information
Grant-Archibald-MS committed Oct 22, 2024
1 parent be09349 commit 07270dc
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 7 deletions.
4 changes: 1 addition & 3 deletions samples/coe-kit-setup-wizard/RunTests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ if ([string]::IsNullOrEmpty($appId)) {

$mdaUrl = "$environmentUrl/main.aspx?appid=$appId&pagetype=custom&name=admin_initialsetuppage_d45cf"

$mdaUrl

# Build the latest debug version of Test Engine from source
Set-Location ..\..\src
dotnet build
Expand All @@ -62,7 +60,7 @@ if ($config.installPlaywright) {

Set-Location ..\bin\Debug\PowerAppsTestEngine
# Run the tests for each user in the configuration file.
dotnet PowerAppsTestEngine.dll -u "browser" -p "mda" -a "none" -i "$currentDirectory\testPlan.fx.yaml" -t $tenantId -e $environmentId -d "$mdaUrl"
dotnet PowerAppsTestEngine.dll -u "browser" -p "mda" -a "none" -i "$currentDirectory\testPlan.fx.yaml" -t $tenantId -e $environmentId -d "$mdaUrl" -l Trace

# Reset the location back to the original directory.
Set-Location $currentDirectory
16 changes: 12 additions & 4 deletions samples/coe-kit-setup-wizard/testPlan.fx.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@ testSuite:
appLogicalName: NotNeeded

testCases:
- testCaseName: Verify
testCaseDescription: Verify setup and upgrade Wizard of the CoE Starter Kit
- testCaseName: Step 1 - Confirm Pre-requisites
testCaseDescription: Verify pre-requistes in place
testSteps: |
=
TestEngine.ConsentDialog(Table({Text: "Center of Excellence Setup Wizard"}));
TestEngine.Pause();
Set(configStep, 1);
Assert(configStep=1);
TestEngine.Pause()
Select(btnNext);
- testCaseName: Step 2 - Configure communication methods
testCaseDescription: Verify communication methods setup
testSteps: |
=
Assert(configStep=2);
Assert(CountRows(colCommunicate)=3);
Experimental.SelectControl(Button3,1);
TestEngine.Pause();
testSettings:
headless: false
locale: "en-US"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,14 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
return false;
}

#if DEBUG
// Add Experimenal namespaes in Debug compile it it has not been added in allow list
if (!settings.AllowPowerFxNamespaces.Contains("Experimental"))
{
settings.AllowPowerFxNamespaces.Add("Experimental");
}
#endif

if ((settings.DenyPowerFxNamespaces.Contains("*") && (
!settings.AllowPowerFxNamespaces.Contains(name) ||
(!settings.AllowPowerFxNamespaces.Contains(name) && name != "TestEngine")
Expand Down
54 changes: 54 additions & 0 deletions src/testengine.module.mda.tests/SelectControlTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using Microsoft.Extensions.Logging;
using Microsoft.Playwright;
using Microsoft.PowerApps.TestEngine.Config;
using Microsoft.PowerApps.TestEngine.Providers;
using Microsoft.PowerApps.TestEngine.Providers.PowerFxModel;
using Microsoft.PowerApps.TestEngine.TestInfra;
using Microsoft.PowerFx.Types;
using Moq;

namespace testengine.module
{
public class SelectControlFunctionTests
{
private Mock<ITestInfraFunctions> MockTestInfraFunctions;
private Mock<ITestState> MockTestState;
private Mock<IPage> MockPage;
private Mock<ITestWebProvider> MockTestWebProvider;
private Mock<ILogger> MockLogger;
private Mock<ILocator> MockLocator;

public SelectControlFunctionTests()
{
MockTestInfraFunctions = new Mock<ITestInfraFunctions>(MockBehavior.Strict);
MockTestState = new Mock<ITestState>(MockBehavior.Strict);
MockPage = new Mock<IPage>(MockBehavior.Strict);
MockTestWebProvider = new Mock<ITestWebProvider>(MockBehavior.Strict);
MockLogger = new Mock<ILogger>();
MockLocator = new Mock<ILocator>();
}

[Fact]
public async Task HappyPathMatchIsFound()
{
// Arrange
var function = new SelectControlFunction(MockTestInfraFunctions.Object, MockTestState.Object, MockLogger.Object);

MockTestInfraFunctions.SetupGet(x => x.Page).Returns(MockPage.Object);
MockPage.Setup(x => x.Locator("[data-control-name='Button1']", null)).Returns(MockLocator.Object);

MockLocator.Setup(x => x.Nth(0)).Returns(MockLocator.Object);

MockLocator.Setup(x => x.ClickAsync(null)).Returns(Task.CompletedTask);

var recordType = RecordType.Empty().Add("Text", FormulaType.String);
var recordValue = new ControlRecordValue(recordType, MockTestWebProvider.Object, "Button1");

// Act & Assert
function.Execute(recordValue, NumberValue.New((float)1.0));
}
}
}
3 changes: 3 additions & 0 deletions src/testengine.module.mda/ModelDrivenApplicationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public void RegisterPowerFxFunction(PowerFxConfig config, ITestInfraFunctions te
ILogger logger = singleTestInstanceState.GetLogger();
config.AddFunction(new ConsentDialogFunction(testInfraFunctions, testState, logger));
logger.LogInformation("Registered ConsentDialog()");

config.AddFunction(new SelectControlFunction(testInfraFunctions, testState, logger));
logger.LogInformation("Registered Experimental.SelectControlFunction()");
}

public async Task RegisterNetworkRoute(ITestState state, ISingleTestInstanceState singleTestInstanceState, IFileSystem fileSystem, IPage Page, NetworkRequestMock mock)
Expand Down
72 changes: 72 additions & 0 deletions src/testengine.module.mda/SelectControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System;
using Microsoft.Extensions.Logging;
using Microsoft.Playwright;
using Microsoft.PowerApps.TestEngine.Config;
using Microsoft.PowerApps.TestEngine.Providers;
using Microsoft.PowerApps.TestEngine.Providers.PowerFxModel;
using Microsoft.PowerApps.TestEngine.TestInfra;
using Microsoft.PowerFx;
using Microsoft.PowerFx.Core.Utils;
using Microsoft.PowerFx.Types;

namespace testengine.module
{
/// <summary>
/// This will check the custom pages of a model driven app looking for a consent dialog
/// </summary>
public class SelectControlFunction : ReflectionFunction
{
private readonly ITestInfraFunctions _testInfraFunctions;
private readonly ITestState _testState;
private readonly ILogger _logger;

private static TableType SearchType = TableType.Empty()
.Add(new NamedFormulaType("Text", FormulaType.String, displayName: "Text"));

public SelectControlFunction(ITestInfraFunctions testInfraFunctions, ITestState testState, ILogger logger)
: base(DPath.Root.Append(new DName("Experimental")), "SelectControl", FormulaType.Blank, RecordType.Empty(), FormulaType.Number)
{
_testInfraFunctions = testInfraFunctions;
_testState = testState;
_logger = logger;
}

public BlankValue Execute(RecordValue control, NumberValue index)
{
_logger.LogInformation("------------------------------\n\n" +
"Executing Experimental.SelectControl() function.");

ExecuteAsync(control, index).Wait();

return FormulaValue.NewBlank();
}

private async Task ExecuteAsync(RecordValue obj, NumberValue index)
{
_logger.LogInformation("------------------------------\n\n" +
"Executing Select function.");

if (obj == null)
{
_logger.LogError($"Object cannot be null.");
throw new ArgumentException();
}

var powerAppControlModel = (ControlRecordValue)obj;

var itemPath = powerAppControlModel.GetItemPath();
itemPath.Index = (int)index.Value;

// Experimental support allow selection control using data-control-name DOM element
var match = _testInfraFunctions.Page.Locator($"[data-control-name='{powerAppControlModel.Name}']").Nth((int)index.Value - 1);

await match.ClickAsync();

_logger.LogInformation("Successfully finished executing SelectControl function.");
}
}
}

0 comments on commit 07270dc

Please sign in to comment.