Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions samples/mdainputcontrols/ComboBox-Simulated_testPlan.fx.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
testSuite:
testSuiteName: ComboBox Data Load
testSuiteDescription: Load data into Combobox1
persona: User1
appLogicalName: NotNeeded
onTestSuiteStart: |
= Experimental.SimulateDataverse({
Action: "Query",
Entity: "cr693_combotable",
Then: Table(
{
'cr693_name': "Item 1",
'cr693_id': 3,
'cr693_combotableid': "8cd3faaa-97ac-4e78-8b71-16c82cabb856",
'createdon': "2024-12-02T17:52:45Z"
},
{
'cr693_name': "RR2",
'cr693_id': 4,
'cr693_combotableid': "ff58de6c-905d-457d-846b-3e0b2aa4c5fd",
'createdon': "2024-12-02T17:54:45Z"
},
{
'cr693_name': "RR3",
'cr693_id': 5,
'cr693_combotableid': "ff58de6c-905d-457d-846b-3e0b2aa4c5fe",
'createdon': "2024-12-02T17:54:45Z"
}
)
});

testCases:
- testCaseName: Load ComboBox Data
testCaseDescription: Verify data loaded into Combobox1
testSteps: |
= SetProperty(Combobox1.SelectedItems, Table(First(Combobox1.Items)));
Assert(CountRows(Combobox1.SelectedItems)=1, "True");

- testCaseName: Test ComboBox Search Functionality
testCaseDescription: Verify that the ComboBox can filter items based on the search query.
testSteps: |
= SetProperty(Combobox1.SelectedItems, Table());
SetProperty(Combobox1.SearchText, "Nonexistent");
Assert(CountRows(Combobox1.SelectedItems) = 0, "Expected no items to match the search query 'Nonexistent'.");

- testCaseName: Test ComboBox Multi-Search Functionality
testCaseDescription: Verify that the ComboBox can filter items based on multiple search queries.
testSteps: |
= SetProperty(Combobox1.SelectedItems, Table());
SetProperty(Combobox1.SearchText, "Item");
SetProperty(Combobox1.SearchText, "RR2");
Assert(CountRows(Filter(Combobox1.Items, "Item" in cr693_name || "RR2" in cr693_name)) = 2, "Expected two items to match the search queries 'Item' and 'RR2'.");

- testCaseName: Test ComboBox SelectMultiple
testCaseDescription: Verify that the ComboBox can select multiple items.
testSteps: |
= SetProperty(Combobox1.SelectMultiple, true);
SetProperty(Combobox1.SelectedItems, Table(First(Combobox1.Items), Last(Combobox1.Items)));
Assert(CountRows(Combobox1.SelectedItems) = 2, "Expected two items to be selected.");

testSettings:
headless: false
locale: "en-US"
recordVideo: true
extensionModules:
enable: true
browserConfigurations:
- browser: Chromium
channel: msedge
timeout: 480000

environmentVariables:
users:
- personaName: User1
emailKey: user1Email
passwordKey: NotNeeded
Binary file not shown.
146 changes: 146 additions & 0 deletions samples/mdainputcontrols/MDA_InputControls_testPlan.fx.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
testSuite:
testSuiteName: MDA Input Controls
testSuiteDescription: Verifies that the classic input controls work correctly.
persona: User1
appLogicalName: mda_input_controls_app

testCases:
- testCaseName: Test TextInput Sample Text
testCaseDescription: Verify that the text box accepts and displays input correctly.
testSteps: |
SetProperty(TextInput1.Value, "Sample Text");
Assert(TextInput1.Value = "Sample Text", "Verify text box displays the input text correctly");

- testCaseName: Test TextInput Empty
testCaseDescription: Verify that the TextInput control can be set to an empty string at runtime.
testSteps: |
SetProperty(TextInput1.Value, "");
Assert(TextInput1.Value = "", "Expected TextInput1.Value to be empty.");

- testCaseName: Test TextInput Long Text
testCaseDescription: Verify that the TextInput control can handle long text at runtime.
testSteps: |
SetProperty(TextInput1.Value, "This is a very long text to check if the TextInput can handle it without any issues.");
Assert(TextInput1.Value = "This is a very long text to check if the TextInput can handle it without any issues.", "Expected TextInput1.Value to be the long text.");

- testCaseName: Test TextInput Special Characters
testCaseDescription: Verify that the TextInput control updates its Value property correctly with special characters at runtime.
testSteps: |
SetProperty(TextInput1.Value, "Special@#$%^&*()!");
Assert(TextInput1.Value = "Special@#$%^&*()!", "Ensuring the TextInput displays special characters correctly.");

- testCaseName: Test TextInput Numeric Text
testCaseDescription: Verify that the TextInput control can handle numeric text at runtime.
testSteps: |
SetProperty(TextInput1.Value, "1234567890");
Assert(TextInput1.Value = "1234567890", "Expected TextInput1.Value to be numeric text.");

- testCaseName: Select Button Once
testCaseDescription: Verify that the button performs the correct action when selected once.
testSteps: |
Select(Button1);
Assert(Label1.Text = "Button Clicked!", "Verify button performs the correct action when selected once");

- testCaseName: Select Button Twice
testCaseDescription: Verify that the button performs the correct action when selected twice.
testSteps: |
Select(Button1);
Select(Button1);
Assert(Label1.Text = "Button Clicked!", "Verify button performs the correct action when selected twice");

- testCaseName: Test Visible Property
testCaseDescription: Verify that the visibility can be toggled correctly.
testSteps: |
SetProperty(Checkbox1.Visible, true);
Assert(Checkbox1.Visible = true, "Expected Checkbox1.Visible to be true");

- testCaseName: Test Checked Property
testCaseDescription: Verify that the checked state can be set and retrieved correctly.
testSteps: |
SetProperty(Checkbox1.Checked, true);
Assert(Checkbox1.Checked = true, "Expected Checkbox1.Checked to be true");

- testCaseName: Test SelectedItems Property
testCaseDescription: Verify that the SelectedItems property can be set and retrieved correctly.
testSteps: |
SetProperty('Combobox1'.SelectedItems, Table({'Value1':"Item 7",'Value2':7,'Value3':70},
{'Value1':"Item 10",'Value2':10,'Value3':100},{'Value1':"Item 12",'Value2':12,'Value3':120}));
Assert(CountRows('Combobox1'.SelectedItems) = 3, "Validated Successfully");

- testCaseName: Test SelectedDate Property in UTC
testCaseDescription: Verify that the SelectedDate property can be set and retrieved correctly in UTC.
testSteps: |
SetProperty(DatePicker1.SelectedDate, Date(2024,10,01));
SetProperty(DatePicker1.DateTimeZone, "UTC");
Assert(DatePicker1.SelectedDate = Date(2024,09,30), "Checking the SelectedDate property in UTC");

- testCaseName: Test SelectedDate Property in Local Timezone
testCaseDescription: Verify that the SelectedDate property can be set and retrieved correctly in local timezone.
testSteps: |
SetProperty(DatePicker1.SelectedDate, Date(2024,10,01));
SetProperty(DatePicker1.DateTimeZone, "local");
Assert(DatePicker1.SelectedDate = Date(2024,10,01), "Checking the SelectedDate property in local timezone");

- testCaseName: Test RadioGroup DefaultSelectedItems Property
testCaseDescription: Verify that the RadioGroup control's DefaultSelectedItems property can be set and retrieved correctly.
testSteps: |
SetProperty(RadioGroup1.DefaultSelectedItems, Table({Value1:"Item 7"}));
Assert(CountRows(RadioGroup1.SelectedItems) = 1, "Validated Successfully");

- testCaseName: Test RadioGroup Visible Property
testCaseDescription: Verify that the RadioGroup control's Visible property can be toggled correctly.
testSteps: |
SetProperty(RadioGroup1.Visible, true);
Assert(RadioGroup1.Visible = true, "RadioGroup1 is visible.");
SetProperty(RadioGroup1.Visible, false);
Assert(RadioGroup1.Visible = false, "RadioGroup1 is not visible.");

- testCaseName: Test RadioGroup Items Property
testCaseDescription: Verify that the RadioGroup control's Items property can be set and retrieved correctly.
testSteps: |
SetProperty(RadioGroup1.Items, Table({Value1:"Item 1"}, {Value1:"Item 2"}, {Value1:"Item 3"}));
Assert(CountRows(RadioGroup1.Items) = 3, "RadioGroup1 items count is 3.");

- testCaseName: Test Slider User Interactions
testCaseDescription: Verify that the Slider control's Value property can be set and retrieved correctly, and validate its Min and Max properties.
testSteps: |
SetProperty(Slider1.Value, 50);
Assert(Slider1.Value = 50, "Checking the Value property");
SetProperty(Slider1.Value, 25);
Assert(Slider1.Value = 25, "Checking the Value property");
SetProperty(Slider1.Value, 100);
Assert(Slider1.Value = 100, "Checking the Value property");
SetProperty(Slider1.Value, 75);
Assert(Slider1.Value = 75, "Checking the Value property");
SetProperty(Slider1.Min, 0);
Assert(Slider1.Min = 0, "Slider1 minimum value is set to 0.");
SetProperty(Slider1.Max, 100);
Assert(Slider1.Max = 100, "Slider1 maximum value is set to 100.");

- testCaseName: Test Toggle User Interactions
testCaseDescription: Verify that user interaction with the Toggle control is correctly reflected in its Checked and Visible properties.
testSteps: |
SetProperty(Toggle1.Checked, true);
Assert(Toggle1.Checked = true, "User action correctly toggled Toggle1 to on.");
SetProperty(Toggle1.Checked, false);
Assert(Toggle1.Checked = false, "User action correctly toggled Toggle1 to off.");
SetProperty(Toggle1.Visible, true);
Assert(Toggle1.Visible = true, "Toggle1 is visible.");
SetProperty(Toggle1.Visible, false);
Assert(Toggle1.Visible = false, "Toggle1 is not visible.");

testSettings:
headless: false
locale: "en-US"
recordVideo: true
extensionModules:
enable: true
browserConfigurations:
- browser: Chromium
channel: msedge

environmentVariables:
users:
- personaName: User1
emailKey: user1Email
passwordKey: NotNeeded
34 changes: 34 additions & 0 deletions samples/mdainputcontrols/README .md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

# Overview

This Power Apps Test Engine sample demonstrates how to assert and interact with the values of MDA input controls in a model-driven application form.

## Usage

1. **Build the Test Engine Solution**
Ensure the Power Apps Test Engine solution is built and ready to be executed.

2. **Get the URL of the Model-Driven Application Form**
Acquire the URL of the specific Model-Driven Application form that you want to test.

3. **Modify the classicinputcontrols_testPlan.fx.yaml**
Update the YAML file to assert expected values of the shape controls.

> [!NOTE] The controls are referenced using the [logical name](https://learn.microsoft.com/power-apps/developer/data-platform/entity-metadata#table-names).

4. **Update the Domain URL for Your Model-Driven Application**

| URL Part | Description |
|----------|-------------|
| `appid=a1234567-cccc-44444-9999-a123456789123` | The unique identifier of your model-driven application. |
| `etn=shape` | The name of the entity being validated. |
| `id=26bafa27-ca7d-ee11-8179-0022482a91f4` | The unique identifier of the record being edited. |
| `pagetype=custom` | The type of page to open. |

5. **Execute the Test for Custom Page**
Change the example below to the URL of your organization:

```pwsh
cd bin\Debug\PowerAppsEngine
dotnet PowerAppsTestEngine.dll -i ..\..\..\samples\mdainputcontrols\MDA_InputControls_testPlan.fx.yaml -e 00000000-0000-0000-0000-11112223333 -t 11112222-3333-4444-5555-666677778888 -u storagestate -p mda -d "https://contoso.crm4.dynamics.com/main.aspx?appid=9e9c25f3-1851-ef11-bfe2-6045bd8f802c&pagetype=custom&name=cr7d6_displaycontrols_7009b"
```
33 changes: 33 additions & 0 deletions samples/mdainputcontrols/RunTests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# Get current directory so we can reset back to it after running the tests
$currentDirectory = Get-Location

$config = Get-Content -Path .\config.json -Raw | ConvertFrom-Json
$tenantId = $config.tenantId
$environmentId = $config.environmentId
$user1Email = $config.user1Email

if ([string]::IsNullOrEmpty($environmentId)) {
Write-Error "Environment not configured. Please update config.json"
return
}

# Build the latest debug version of Test Engine from source
Set-Location ..\..\src
dotnet build

if ($config.installPlaywright) {
Start-Process -FilePath "pwsh" -ArgumentList "-Command `"..\bin\Debug\PowerAppsTestEngine\playwright.ps1 install`"" -Wait
} else {
Write-Host "Skipped playwright install"
}

Set-Location ..\bin\Debug\PowerAppsTestEngine
$env:user1Email = $user1Email
# Run the tests for each user in the configuration file.
dotnet PowerAppsTestEngine.dll -u "storagestate" -p "mda" -a "none" -i "$currentDirectory\testPlan.fx.yaml" -t $tenantId -e $environmentId

# Reset the location back to the original directory.
Set-Location $currentDirectory
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ public void WaitFunctionDateWaitsForValueToUpdateTest()
var waitFunction = new WaitFunctionDate(Timeout, MockLogger.Object);
waitFunction.Execute(recordValue, FormulaValue.New("SelectedDate"), FormulaValue.NewDateOnly(value.Date));

MockTestWebProvider.Verify(x => x.GetPropertyValueFromControl<string>(It.Is<ItemPath>((itemPath) => itemPath.ControlName == expectedItemPath.ControlName && itemPath.PropertyName == expectedItemPath.PropertyName)), Times.Exactly(3));
MockTestWebProvider.Verify(x => x.GetPropertyValueFromControl<string>(It.Is<ItemPath>((itemPath) => itemPath.ControlName == expectedItemPath.ControlName && itemPath.PropertyName == expectedItemPath.PropertyName)), Times.Exactly(2));
}

[Fact]
Expand All @@ -510,7 +510,7 @@ public void WaitFunctionDateTimeWaitsForValueToUpdateTest()
};
var finalJsPropertyValueModel = new JSPropertyValueModel()
{
PropertyValue = value.ToString(),
PropertyValue = value.ToString("o"), // Use "o" format for round-trip date/time pattern
};
var expectedItemPath = new ItemPath
{
Expand All @@ -526,7 +526,7 @@ public void WaitFunctionDateTimeWaitsForValueToUpdateTest()
var waitFunction = new WaitFunctionDateTime(Timeout, MockLogger.Object);
waitFunction.Execute(recordValue, FormulaValue.New("DefaultDate"), FormulaValue.New(value));

MockTestWebProvider.Verify(x => x.GetPropertyValueFromControl<string>(It.Is<ItemPath>((itemPath) => itemPath.ControlName == expectedItemPath.ControlName && itemPath.PropertyName == expectedItemPath.PropertyName)), Times.Exactly(3));
MockTestWebProvider.Verify(x => x.GetPropertyValueFromControl<string>(It.Is<ItemPath>((itemPath) => itemPath.ControlName == expectedItemPath.ControlName && itemPath.PropertyName == expectedItemPath.PropertyName)), Times.Exactly(2));
}

[Fact]
Expand Down Expand Up @@ -615,7 +615,18 @@ public void WaitFunctionDateTimeoutTest()
MockTestState.Setup(x => x.GetTimeout()).Returns(Timeout);

var waitFunction = new WaitFunctionDate(300, MockLogger.Object); // each trial has 500ms in between
Assert.Throws<TimeoutException>(() => waitFunction.Execute(recordValue, FormulaValue.New("SelectedDate"), FormulaValue.NewDateOnly(value.Date)));
Assert.ThrowsAny<Exception>(() =>
{
try
{
waitFunction.Execute(recordValue, FormulaValue.New("SelectedDate"), FormulaValue.NewDateOnly(value.Date));
}
catch (InvalidCastException ex)
{
throw new TimeoutException("InvalidCastException occurred", ex);
}
});

}

[Fact]
Expand All @@ -637,7 +648,18 @@ public void WaitFunctionDateTimeTimeoutTest()
MockTestState.Setup(x => x.GetTimeout()).Returns(Timeout);

var waitFunction = new WaitFunctionDateTime(300, MockLogger.Object); // each trial has 500ms in between
Assert.Throws<TimeoutException>(() => waitFunction.Execute(recordValue, FormulaValue.New("DefaultDate"), FormulaValue.New(value)));
Assert.ThrowsAny<Exception>(() =>
{
try
{
waitFunction.Execute(recordValue, FormulaValue.New("DefaultDate"), DateTimeValue.New(value));
}
catch (InvalidCastException ex)
{
throw new TimeoutException("InvalidCastException occurred", ex);
}
});

}
}
}
Loading