- Print
- DarkLight
- PDF
Article summary
Did you find this summary helpful?
Thank you for your feedback!
Below is the C# code for my tests using Playwright.
using Azure;
using Azure.Monitor.Query.Models;
using IPB.LogicApp.Standard.Testing;
using IPB.LogicApp.Standard.Testing.Model.WorkflowRunActionDetails;
using Microsoft.Playwright;
using Microsoft.Playwright.MSTest;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Playwright.Tests
{
[TestClass]
public class CreateOrderTest : PageTest
{
private TestConfiguration? _config;
private AppInsightsHelper? _appInsightsHelper;
[TestInitialize]
public void TestInitialize()
{
_config = Settings.Configuration;
_appInsightsHelper = new AppInsightsHelper(_config.ApplicationInsights);
}
[TestMethod]
public async Task Create_Non_VIP_Order()
{
//Login to the application with entra id
await LoginToApplicationWithEntraID();
//Fill out the order form and submit
await FillOutWebPageAndSubmitOrder(quantity: "5", unitPrice: "1.99");
//extract order id from the response in the web page
var orderId = await Page.GetByTestId("order-id-display").InnerTextAsync();
Assert.IsTrue(Guid.Parse(orderId) != Guid.Empty, "The order id is not valid");
//Execute Log query to look up the log event for the order id
var serviceBusListenerQueryResults = await GetServiceBusListnerRun(orderId);
Assert.IsNotNull(serviceBusListenerQueryResults, "The service bus listener workflow has not logged a message");
var serviceBusListenerRunId = serviceBusListenerQueryResults.Rows[0].GetString("runId_");
var clientTrackingId = serviceBusListenerQueryResults.Rows[0].GetString("clientTrackingId_");
//Validate the run history for the service bus listener workflow
await ValidateServiceBusListenerWorkflow(serviceBusListenerRunId);
//Get the log entries for the other related workflows using the client tracking id
var workflowQueryResults = await GetWorkflowRunsMatchingClientTrackingId(clientTrackingId);
var processorWorkflow = workflowQueryResults.Rows.FirstOrDefault(x => x.GetString("workflowName_") == "Order_Processor");
Assert.IsNotNull(processorWorkflow, "There should be a log row for the order processor workflow");
var processorWorkflowRunID = processorWorkflow.GetString("runId_");
//Validate the run history for the order processor workflow
var expectedIsVip = false;
await ValidateOrderProcessorWorkflow(processorWorkflowRunID, expectedIsVip);
//I could do additional tests here that the message was in storage account if I want to
}
[TestMethod]
public async Task Create_VIP_Order()
{
//Login to the application with entra id
await LoginToApplicationWithEntraID();
//Fill out the order form and submit
await FillOutWebPageAndSubmitOrder(quantity: "5", unitPrice: "5000.99");
//extract order id from the response in the web page
var orderId = await Page.GetByTestId("order-id-display").InnerTextAsync();
Assert.IsTrue(Guid.Parse(orderId) != Guid.Empty, "The order id is not valid");
//Execute Log query to look up the log event for the order id
var serviceBusListenerQueryResults = await GetServiceBusListnerRun(orderId);
Assert.IsNotNull(serviceBusListenerQueryResults, "The service bus listener workflow has not logged a message");
var serviceBusListenerRunId = serviceBusListenerQueryResults.Rows[0].GetString("runId_");
var clientTrackingId = serviceBusListenerQueryResults.Rows[0].GetString("clientTrackingId_");
//Validate the run history for the service bus listener workflow
await ValidateServiceBusListenerWorkflow(serviceBusListenerRunId);
//Get the log entries for the other related workflows using the client tracking id
var workflowQueryResults = await GetWorkflowRunsMatchingClientTrackingId(clientTrackingId);
var processorWorkflow = workflowQueryResults.Rows.FirstOrDefault(x => x.GetString("workflowName_") == "Order_Processor");
Assert.IsNotNull(processorWorkflow, "There should be a log row for the order processor workflow");
var processorWorkflowRunID = processorWorkflow.GetString("runId_");
//Validate the run history for the order processor workflow
var expectedIsVip = false;
await ValidateOrderProcessorWorkflow(processorWorkflowRunID, expectedIsVip);
//I could do additional tests here that the message was in cosmos db if I want to
}
public async Task ValidateOrderProcessorWorkflow(string runId, bool expectedIsVip)
{
var logicAppTestManager = LogicAppTestManagerBuilder.Build("Order_Processor");
logicAppTestManager.LoadWorkflowRunHistory(runId);
Assert.AreEqual(expected: TriggerStatus.Succeeded,
actual: logicAppTestManager.GetTriggerStatus(),
message: "The workflow did not trigger successfully");
Assert.AreEqual(expected: ActionStatus.Succeeded,
actual: logicAppTestManager.GetActionStatus("Agent_Process_Order"),
message: "The workflow did not call the AI agent workflow successfully");
if(expectedIsVip)
{
//Check the order got written to cosmos db
Assert.AreEqual(expected: ActionStatus.Succeeded,
actual: logicAppTestManager.GetActionStatus("Create_or_update_item"),
message: "The order was not saved to cosmos db");
}
else
{
Assert.AreEqual(expected: ActionStatus.Succeeded,
actual: logicAppTestManager.GetActionStatus("Upload_blob_to_storage_container_based_on_a_URI"),
message: "The was not saved to the storage account");
}
}
public async Task ValidateServiceBusListenerWorkflow(string runId)
{
var logicAppTestManager = LogicAppTestManagerBuilder.Build("Order_ServiceBus_Listener");
logicAppTestManager.LoadWorkflowRunHistory(runId);
Assert.AreEqual(expected: TriggerStatus.Succeeded,
actual: logicAppTestManager.GetTriggerStatus(),
message: "The service bus listener workflow did not trigger successfully");
Assert.AreEqual(expected: ActionStatus.Succeeded,
actual: logicAppTestManager.GetActionStatus("Call_Order_Processor"),
message: "The service bus listener did not call the processor workflow successfully");
}
public async Task LoginToApplicationWithEntraID()
{
var entraLoginNavigationTask = Page.WaitForURLAsync($"{_config.WebApplicationSettings.EntraAuthUrl}/**", new() { Timeout = 30000 });
//Go to main page
await Page.GotoAsync(_config.WebApplicationSettings.AppUrl);
//allow redirect to entra login
await entraLoginNavigationTask;
//complete auth form
var appRedirectAfterLoginNavigationTask = Page.WaitForURLAsync($"{_config.WebApplicationSettings.AppUrl}/**", new() { Timeout = 30000 });
await Page.GetByRole(AriaRole.Textbox, new() { Name = "username@" }).ClickAsync();
await Page.GetByRole(AriaRole.Textbox, new() { Name = "username@" }).FillAsync(_config.WebApplicationSettings.Username);
await Page.GetByRole(AriaRole.Textbox, new() { Name = "username@" }).PressAsync("Enter");
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Enter the password for" }).ClickAsync();
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Enter the password for" }).FillAsync(_config.WebApplicationSettings.Password);
await Page.GetByRole(AriaRole.Button, new() { Name = "Sign in" }).ClickAsync();
//Click stay signed in and wait for redirect
await Page.GetByRole(AriaRole.Button, new() { Name = "Yes" }).ClickAsync();
await appRedirectAfterLoginNavigationTask;
// Additional wait for page to be fully loaded
await Page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
await Page.ScreenshotAsync(
new PageScreenshotOptions { Path = "screenshot.png" }
);
}
public async Task FillOutWebPageAndSubmitOrder(string quantity, string unitPrice)
{
//Complete order form
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Customer Name" }).ClickAsync();
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Customer Name" }).FillAsync("Test Customer");
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Customer Name" }).PressAsync("Tab");
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Customer Email" }).FillAsync("test@test.com");
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Customer Email" }).PressAsync("Tab");
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Product Name" }).FillAsync("Test Product");
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Product Name" }).PressAsync("Tab");
await Page.GetByRole(AriaRole.Spinbutton, new() { Name = "Quantity" }).FillAsync(quantity);
await Page.GetByRole(AriaRole.Spinbutton, new() { Name = "Quantity" }).PressAsync("Tab");
await Page.GetByRole(AriaRole.Spinbutton, new() { Name = "Unit Price" }).FillAsync(unitPrice);
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Order Notes (Optional)" }).ClickAsync();
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Order Notes (Optional)" }).FillAsync("test order");
//Submit order
await Page.GetByRole(AriaRole.Button, new() { Name = "Create Order" }).ClickAsync();
}
private async Task<LogsTable> GetWorkflowRunsMatchingClientTrackingId(string clientTrackingId)
{
var kqlQuery = $@"
AppTraces
| extend runId_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).resource)).runId)
| extend workflowName_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).resource)).workflowName)
| extend clientTrackingId_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).correlation)).clientTrackingId)
| extend EventName_ = tostring(Properties.EventName)
| extend logicAppName_ = tostring(Properties.prop__hostName)
| extend parentFlowId_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).correlation)).parentFlowId)
| extend parentRunId_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).correlation)).parentRunId)
| extend status_ = tostring(parse_json(tostring(Properties.prop__properties)).status)
| extend duration_ = tostring(Properties.prop__durationInMilliseconds)
| where EventName_ == 'WorkflowRunEnd'
| where clientTrackingId_ == '{clientTrackingId}'
| project TimeGenerated, logicAppName_, workflowName_, runId_, clientTrackingId_, status_, parentRunId_, duration_, parentFlowId_
| order by TimeGenerated desc
";
var kqlResult = await _appInsightsHelper.QueryLog(kqlQuery, TimeSpan.FromDays(2));
return kqlResult;
}
private async Task<LogsTable> GetServiceBusListnerRun(string orderId)
{
var serviceBusListenerKqlQuery = $@"
AppTraces
| extend orderId_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).trackedProperties)).orderId)
| extend actionName_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).resource)).actionName)
| extend runId_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).resource)).runId)
| extend workflowName_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).resource)).workflowName)
| extend actionTrackingId_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).correlation)).actionTrackingId)
| extend clientTrackingId_ = tostring(parse_json(tostring(parse_json(tostring(Properties.prop__properties)).correlation)).clientTrackingId)
| extend EventName_ = tostring(Properties.EventName)
| extend logicAppName_ = tostring(Properties.prop__hostName)
| where EventName_ == 'WorkflowActionEnd'
| where logicAppName_ == 'ms-blog-logicapp-testing.azurewebsites.net'
| where workflowName_ == 'Order_ServiceBus_Listener'
| where actionName_ == 'Compose_-_Message_Body'
| where orderId_ == '{orderId}'
| project TimeGenerated, logicAppName_, workflowName_, actionName_, runId_, actionTrackingId_, clientTrackingId_, orderId_
";
var kqlResult = await _appInsightsHelper.QueryLog(serviceBusListenerKqlQuery, TimeSpan.FromDays(5));
return kqlResult;
}
}
}
Was this article helpful?