Playwright Test Class
  • 17 Sep 2025
  • 8 Minutes to read
  • Contributors
  • Dark
    Light
  • PDF

Playwright Test Class

  • Dark
    Light
  • PDF

Article summary

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?