-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable PowerApps MDA Classic Input controls for Custom Pages with Test Engine Support #501
base: integration
Are you sure you want to change the base?
Changes from 4 commits
672cd30
1ffef27
1a55580
2539ba0
7cf753c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
testSuite: | ||
testSuiteName: Classic Input Controls | ||
testSuiteDescription: Verifies that the classic input controls work correctly. | ||
persona: User1 | ||
appLogicalName: classic_input_controls_app | ||
|
||
testCases: | ||
- testCaseName: Test Label Property | ||
testCaseDescription: Verify that the label's Text property can be set and retrieved correctly. | ||
testSteps: | | ||
SetProperty(Label1.Text, "Check it"); | ||
Assert(Label1.Text = "Check it", "Expected Label1.Text to be 'Check it'"); | ||
|
||
- testCaseName: Test Label Empty Text | ||
testCaseDescription: Verify that the label's Text property can be set to an empty string. | ||
testSteps: | | ||
SetProperty(Label1.Text, ""); | ||
Assert(Label1.Text = "", "Expected Label1.Text to be empty"); | ||
|
||
- testCaseName: Test Label Long Text | ||
testCaseDescription: Verify that the label's Text property can handle long text. | ||
testSteps: | | ||
SetProperty(Label1.Text, "This is a very long text to check if the label can handle it without any issues."); | ||
Assert(Label1.Text = "This is a very long text to check if the label can handle it without any issues.", "Expected Label1.Text to be the long text"); | ||
|
||
- testCaseName: Test Label Numeric Text | ||
testCaseDescription: Verify that the label's Text property can handle numeric text. | ||
testSteps: | | ||
SetProperty(Label1.Text, "1234567890"); | ||
Assert(Label1.Text = "1234567890", "Expected Label1.Text to be numeric text"); | ||
|
||
- testCaseName: Test Label Special Characters | ||
testCaseDescription: Verify the Label control updates its Text property correctly with special characters at runtime. | ||
testSteps: | | ||
SetProperty(Label1.Text, "Hello@#$%^&*!"); | ||
Assert(Label1.Text = "Hello@#$%^&*!", "Ensuring the Label displays special characters correctly."); | ||
|
||
- 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 | ||
testCaseDescription: Verify that the SelectedDate property can be set and retrieved correctly. | ||
testSteps: | | ||
SetProperty(DatePicker1.SelectedDate, Date(2024,10,01)); | ||
Assert(DatePicker1.SelectedDate = Date(2024,10,01), "Checking the SelectedDate property"); | ||
|
||
- 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 |
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 |
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 classic 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\mdaclassicinputcontrols\classicinputcontrols_testPlan.fx.yaml -e 00000000-0000-0000-0000-11112223333 -t 11112222-3333-4444-5555-666677778888 -u browser -p mda -d "https://contoso.crm4.dynamics.com/main.aspx?appid=9e9c25f3-1851-ef11-bfe2-6045bd8f802c&pagetype=custom&name=cr7d6_displaycontrols_7009b" | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -208,11 +208,17 @@ public string CheckTestEngineObject | |
{ | ||
case "disabled": | ||
case "visible": | ||
case "checked": | ||
return (T)(object)("{PropertyValue: " + value.ToString().ToLower() + "}"); | ||
default: | ||
switch (value.GetType().ToString()) | ||
{ | ||
case "System.String": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if nameof(System.String) works properly here instead. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The nameof(System.String) approach won't work here because it evaluates to "String" instead of the fully qualified type name "System.String". Since value.GetType().ToString() returns the fully qualified type name, using nameof would cause a mismatch. Consider using value is string for a cleaner and more type-safe approach. |
||
var stringValue = value.ToString(); | ||
if (string.IsNullOrEmpty(stringValue)) | ||
{ | ||
return (T)(object)("{\"PropertyValue\": \"\"}"); | ||
} | ||
return (T)(object)("{PropertyValue: '" + value.ToString() + "'}"); | ||
default: | ||
return (T)(object)("{PropertyValue: " + value.ToString() + "}"); | ||
|
@@ -479,7 +485,7 @@ public async Task<bool> SetPropertyDateAsync(ItemPath itemPath, DateValue value) | |
// TODO - Set the Xrm SDK Value and update state for any JS to run | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this // TODO comment still valid. Or can we remove it. This type of TODO comments (Tasks), is usually not useful, and I would prefer to have a work-item if something is missing to implement here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created work item #519 |
||
|
||
// Date.parse() parses the date to unix timestamp | ||
var expression = $"PowerAppsTestEngine.setPropertyValue({itemPathString},{{{propertyNameString}:Date.parse(\"{recordValue}\")}})"; | ||
var expression = $"PowerAppsTestEngine.setPropertyValue({itemPathString},Date.parse(\"{recordValue}\"))"; | ||
|
||
return await TestInfraFunctions.RunJavascriptAsync<bool>(expression); | ||
} | ||
|
@@ -504,7 +510,7 @@ public async Task<bool> SetPropertyRecordAsync(ItemPath itemPath, RecordValue va | |
checkVal = FormatValue(value); | ||
} | ||
|
||
var expression = $"PowerAppsTestEngine.setPropertyValue({itemPathString},{{{propertyNameString}:{checkVal}}})"; | ||
var expression = $"PowerAppsTestEngine.setPropertyValue({itemPathString},{checkVal})"; | ||
|
||
return await TestInfraFunctions.RunJavascriptAsync<bool>(expression); | ||
} | ||
|
@@ -723,5 +729,5 @@ private static string GetQueryParametersForTestUrl(string tenantId, string addit | |
{ | ||
return $"?tenantId={tenantId}&source=testengine{additionalQueryParams}"; | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove commented out line. Since seems like it is not needed, and this variable has been defined and initialized one line above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done