Skip to content
Open
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
118 changes: 118 additions & 0 deletions samples/entitylist/testPlan.fx.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
testSuite:
testSuiteName: Employee Entity Form Automation
testSuiteDescription: Verifies that the Employee Entity controls work correctly.
persona: User1
appLogicalName: Entity_controls_app

testCases:

# 1. Insert Employee
- testCaseName: Insert Employee
testCaseDescription: Inserts a new employee record and asserts the table contains 4 records after insertion.
testSteps: |
Collect(
cr693_employee5,
{
cr693_employeename: "Ra Ra",
cr693_empoyeeid: "E006",
cr693_dob: DateTime(1991,05,15,00,0,0)
}
);
Assert(CountRows(cr693_employee5) = 4, "The employee table should contain 4 records after insertion");

# 2. Sort Employee IDs
- testCaseName: Sort Employee IDs
testCaseDescription: Sorts the employee list by Employee ID in descending order.
testSteps: |
Sort(cr693_employee5, cr693_empoyeeid, SortOrder.Descending);

# 3. Delete Employee with ID E006
- testCaseName: Delete Employee with ID E006
testCaseDescription: Deletes the employee record with ID 'E006' and asserts it no longer exists.
testSteps: |
Refresh(cr693_employee5);
Remove(
cr693_employee5,
LookUp(cr693_employee5, cr693_empoyeeid = "E007")
);
Assert(
IsBlank(LookUp(cr693_employee5, cr693_empoyeeid = "E007")),
"The record with employee ID 'E006' should no longer exist in the employee table"
);

# 4. Update Employee
- testCaseName: Update Employee
testCaseDescription: Updates the name of the first employee record and asserts the update.
testSteps: |
Patch(
cr693_employee5,
First(cr693_employee5),
{
cr693_employeename: "RR2"
}
);
Assert(First(cr693_employee5).cr693_employeename = "RR2", "The employee name should be updated to 'RR2'");

# 5. Verify Employee Record Count
- testCaseName: Verify Employee Record Count
testCaseDescription: Asserts that the employee table displays exactly 3 employee records.
testSteps: |
Assert(CountRows(cr693_employee5) = 3, "Checking if Table displays correct number of items");

# 6. Verify Employee List Filtering by Name
- testCaseName: Verify Employee List Filtering by Name
testCaseDescription: Asserts that filtering the employee list by name returns 1 record starting with 'uu'.
testSteps: |
Assert(CountRows(Filter(cr693_employee5, StartsWith(cr693_employeename, "uu"))) = 1, "The employee list should contain 1 record with a name starting with 'Test'");

# 7. Verify Employee Name Field
- testCaseName: Verify Employee Name Field
testCaseDescription: Asserts that the Employee Name for ID 'E001' is 'Alice Smith'.
testSteps: |
Assert(LookUp(cr693_employee5, cr693_empoyeeid = "E001").cr693_employeename = "RR2", "The Employee Name for ID 'E001' should be 'RR2'");

# 8. Click New Record button on the Command Bar Button
- testCaseName: Click New Record button on the Command Bar Button
testCaseDescription: Automates clicking the New Record button, entering details, and saving the new employee.
testSteps: |
Assert(NavigateToRecord("cr693_employee5", "entityrecord", 1));
SetProperty(cr693_empoyeeid.Text, "E007");
SetProperty(cr693_employeename.Text, "RR Test_Create");
SetDOBFields("04/09/1976", "11:30 PM");
SelectDropdownOption("IT");
CommandBarAction(SaveAndClose());
Assert(NavigateToRecord("cr693_employee5", "entitylist", 1));

# 9. Test SelectGridRowCheckbox
- testCaseName: Test SelectGridRowCheckbox
testCaseDescription: Selects the checkbox of the first grid row.
testSteps: |
SelectGridRowCheckbox(1);

# 10. Click Edit Record button on the Command Bar Button
- testCaseName: Click Edit Record button on the Command Bar Button
testCaseDescription: Automates editing the first record, updating all fields, and saving.
testSteps: |
Assert(NavigateToRecord("cr693_employee5", "entityrecord", 1));
SetProperty(cr693_employeename.Text, "John 20 Updated");
SetProperty(cr693_empoyeeid.Text, "E020 Updated");
SetDOBFields("04/09/1976", "12:30 PM");
SelectDropdownOption("Finance");
CommandBarAction(SaveAndClose());
Assert(NavigateToRecord("cr693_employee5", "entitylist", 1));

# 11. Delete Record
- testCaseName: Delete Record
testCaseDescription: Automates deleting the first record from the list and verifies navigation.
testSteps: |
SelectGridRowCheckbox(1);
Assert(NavigateToRecord("cr693_employee5", "entityrecord", 1));
DeleteRecord();
Assert(NavigateToRecord("cr693_employee5", "entitylist", 1));

testSettings:
filePath: ./testSettings.yaml
environmentVariables:
users:
- personaName: User1
emailKey: user1Email
34 changes: 34 additions & 0 deletions samples/entitylist/testSettings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
locale: "en-US"
headless: false
recordVideo: true
extensionModules:
enable: true
parameters:
enableDataverseFunctions: true
allowPowerFxNamespaces:
- Preview
timeout: 1200000
browserConfigurations:
- browser: Chromium
channel: msedge

testFunctions:
- description: Get Identifier of save comamnd bar item
code: |
SaveForm(): Boolean = Preview.SaveForm();
- description: Get Identifier of New command bar item
code: |
NewRecord(): Text = "New";
- description: Get Identifier of save and close command bar item
code: |
SaveAndClose(): Text = "Save & Close";
- description: Save and close the form using Document Object Model (DOM) selector for command bar
code: |
CommandBarAction(name: Text): Void =
Preview.PlaywrightAction(Concatenate("//*[@aria-label='", name, "']"), "click");

- description: Delete the current record using Power Fx control from MDA
code: |
DeleteRecord(): Boolean = Preview.DeleteRecord();


Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Playwright;
using Microsoft.PowerApps.TestEngine.PowerFx.Functions;
using Microsoft.PowerApps.TestEngine.Providers;
using Microsoft.PowerApps.TestEngine.TestInfra;
using Microsoft.PowerFx.Types;
using Moq;
using Newtonsoft.Json.Linq;
using Xunit;

namespace Microsoft.PowerApps.TestEngine.Tests.PowerFx.Functions
{
public class NavigateToRecordFunctionTests
{
[Fact]
public async Task ExecuteAsync_NavigatesToExistingRecord_ReturnsTrue()
{
// Arrange
var mockWebProvider = new Mock<ITestWebProvider>();
var mockTestInfra = new Mock<ITestInfraFunctions>();
var mockLogger = new Mock<ILogger>();
var mockPage = new Mock<IPage>();
var mockContext = new Mock<IBrowserContext>();

mockWebProvider.SetupGet(x => x.TestInfraFunctions).Returns(mockTestInfra.Object);
mockTestInfra.Setup(x => x.GetContext()).Returns(mockContext.Object);
mockContext.Setup(x => x.Pages).Returns(new[] { mockPage.Object });

// Simulate entityId found
mockPage.Setup(x => x.EvaluateAsync<string>(It.IsAny<string>(), null))
.ReturnsAsync("entity123");

mockPage.Setup(x => x.EvaluateAsync<bool>(It.IsAny<string>(), null))
.ReturnsAsync(true);

bool updateModelCalled = false;
Task UpdateModel() { updateModelCalled = true; return Task.CompletedTask; }

var func = new NavigateToRecordFunction(
mockWebProvider.Object,
UpdateModel,
mockLogger.Object);

// Act
var result = await func.ExecuteAsync(
FormulaValue.New("account") as StringValue,
FormulaValue.New("entityrecord") as StringValue,
NumberValue.New(1.0));

// Assert
Assert.True(((BooleanValue)result).Value);
Assert.True(updateModelCalled);
mockLogger.Verify(l => l.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Navigating to existing record")),
(Exception)null,
It.IsAny<Func<It.IsAnyType, Exception, string>>()), Times.Once);
}

[Fact]
public async Task ExecuteAsync_NavigatesToNewRecord_ReturnsTrue()
{
// Arrange
var mockWebProvider = new Mock<ITestWebProvider>();
var mockTestInfra = new Mock<ITestInfraFunctions>();
var mockLogger = new Mock<ILogger>();
var mockPage = new Mock<IPage>();
var mockContext = new Mock<IBrowserContext>();

mockWebProvider.SetupGet(x => x.TestInfraFunctions).Returns(mockTestInfra.Object);
mockTestInfra.Setup(x => x.GetContext()).Returns(mockContext.Object);
mockContext.Setup(x => x.Pages).Returns(new[] { mockPage.Object });

// Simulate no entityId found
mockPage.Setup(x => x.EvaluateAsync<string>(It.IsAny<string>(), null))
.ReturnsAsync(string.Empty);

mockPage.Setup(x => x.EvaluateAsync<bool>(It.IsAny<string>(), null))
.ReturnsAsync(true);

bool updateModelCalled = false;
Task UpdateModel() { updateModelCalled = true; return Task.CompletedTask; }

var func = new NavigateToRecordFunction(
mockWebProvider.Object,
UpdateModel,
mockLogger.Object);

// Act
var result = await func.ExecuteAsync(
FormulaValue.New("contact") as StringValue,
FormulaValue.New("entityrecord") as StringValue,
NumberValue.New(1.0));

// Assert
Assert.True(((BooleanValue)result).Value);
Assert.True(updateModelCalled);
mockLogger.Verify(l => l.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("No selected entity found")),
(Exception)null,
It.IsAny<Func<It.IsAnyType, Exception, string>>()), Times.Once);
}

[Fact]
public void Execute_CallsAsyncSynchronously()
{
// Arrange
var mockWebProvider = new Mock<ITestWebProvider>();
var mockTestInfra = new Mock<ITestInfraFunctions>();
var mockLogger = new Mock<ILogger>();
var mockPage = new Mock<IPage>();
var mockContext = new Mock<IBrowserContext>();

mockWebProvider.SetupGet(x => x.TestInfraFunctions).Returns(mockTestInfra.Object);
mockTestInfra.Setup(x => x.GetContext()).Returns(mockContext.Object);
mockContext.Setup(x => x.Pages).Returns(new[] { mockPage.Object });

mockPage.Setup(x => x.EvaluateAsync<string>(It.IsAny<string>(), null))
.ReturnsAsync("entity456");
mockPage.Setup(x => x.EvaluateAsync<bool>(It.IsAny<string>(), null))
.ReturnsAsync(true);

var func = new NavigateToRecordFunction(
mockWebProvider.Object,
() => Task.CompletedTask,
mockLogger.Object);

// Act
var result = func.Execute(
FormulaValue.New("lead") as StringValue,
FormulaValue.New("entityrecord") as StringValue,
NumberValue.New(1.0));

// Assert
Assert.True(((BooleanValue)result).Value);
}
}
}
Loading
Loading