<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nathan Araújo</title>
    <description>The latest articles on DEV Community by Nathan Araújo (@araujosnathan).</description>
    <link>https://dev.to/araujosnathan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1452106%2F1226e707-7f27-4a02-8d10-b89b937fdbe3.jpeg</url>
      <title>DEV Community: Nathan Araújo</title>
      <link>https://dev.to/araujosnathan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/araujosnathan"/>
    <language>en</language>
    <item>
      <title>Streamline Your Test Automation with Azure Test Track VS Code Extension</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Thu, 23 Oct 2025 13:08:58 +0000</pubDate>
      <link>https://dev.to/araujosnathan/streamline-your-test-automation-with-azure-test-track-vs-code-extension-1en0</link>
      <guid>https://dev.to/araujosnathan/streamline-your-test-automation-with-azure-test-track-vs-code-extension-1en0</guid>
      <description>&lt;h2&gt;
  
  
  Why This Process Matters: Microsoft's Automation Status Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Hidden Challenge with Azure DevOps Automation Status
&lt;/h3&gt;

&lt;p&gt;Here's something most QAs don't realize: &lt;strong&gt;You cannot manually set the "Automation Status" field to "Automated" in Azure DevOps&lt;/strong&gt;. The dropdown only shows "Not Automated" and "Planned" options. So how do test cases get the "Automated" status? Here's the secret:&lt;/p&gt;

&lt;h4&gt;
  
  
  Microsoft's Intelligent Design Philosophy
&lt;/h4&gt;

&lt;p&gt;Microsoft designed Azure DevOps with a specific workflow in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Associated Automation Tab = Source of Truth&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The "Associated Automation" tab should contain the actual automation details&lt;/li&gt;
&lt;li&gt;This tab represents the &lt;strong&gt;real connection&lt;/strong&gt; between test cases and automated tests&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automation Status = Calculated Field&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The "Automation Status" field is designed to be &lt;strong&gt;automatically triggered&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;When you populate the "Associated Automation" tab, Microsoft's internal triggers update the status&lt;/li&gt;
&lt;li&gt;This ensures the status reflects &lt;strong&gt;actual automation&lt;/strong&gt;, not manual changes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Why Manual Updates Don't Work&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The "Automation Status" dropdown &lt;strong&gt;only has "Not Automated" and "Planned"&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Automated" is not a selectable option&lt;/strong&gt; - it only appears when triggered by the system&lt;/li&gt;
&lt;li&gt;You cannot manually mark a test case as "Automated" even if you want to&lt;/li&gt;
&lt;li&gt;The only way to get "Automated" status is through proper automation association&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Real Challenge
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;How do you actually get a test case to show "Automated" status?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ &lt;strong&gt;Try to select "Automated"&lt;/strong&gt;: Not possible - option doesn't exist in dropdown&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Leave as "Not Automated"&lt;/strong&gt;: Doesn't reflect reality of your automation efforts&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Populate Associated Automation&lt;/strong&gt;: The ONLY way to trigger "Automated" status&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Microsoft's Recommended Workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📝 Write Automated Test
    ↓
🔗 Populate Associated Automation Tab  
    ↓
⚙️  Microsoft Triggers Update Status
    ↓ 
✅ Automation Status = 'Automated'
    ↓
📋 Full Traceability Maintained
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What This Extension Solves
&lt;/h3&gt;

&lt;p&gt;By automatically populating the &lt;strong&gt;Associated Automation tab&lt;/strong&gt;, we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Follow Microsoft's intended workflow&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Trigger the automated status update correctly&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Maintain complete traceability&lt;/strong&gt; from code to test case&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Ensure accuracy&lt;/strong&gt; - status reflects real automation&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Enable verification&lt;/strong&gt; - anyone can see the actual test details&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;: This isn't just about saving time - it's about following Microsoft's design pattern to ensure your automation status is &lt;strong&gt;trustworthy, verifiable, and properly integrated&lt;/strong&gt; with Azure DevOps' automation tracking system.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Problem Every QA Faces
&lt;/h2&gt;

&lt;p&gt;As QA professionals, we often struggle with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manual test case association&lt;/strong&gt; in Azure DevOps taking hours&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lost traceability&lt;/strong&gt; between automated tests and test cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outdated automation status&lt;/strong&gt; in ADO that doesn't reflect reality&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-consuming manual updates&lt;/strong&gt; every time we add new tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What if there was a better way?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introducing Azure Test Track Extension
&lt;/h2&gt;

&lt;p&gt;The Azure Test Track VS Code Extension revolutionizes how you manage test automation by &lt;strong&gt;automatically linking your automated tests to Azure DevOps Test Cases&lt;/strong&gt; with just a simple comment.&lt;/p&gt;

&lt;h3&gt;
  
  
  What It Does
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatically associates&lt;/strong&gt; automated tests with ADO Test Cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updates automation status&lt;/strong&gt; to "Automated" in Azure DevOps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Populates Associated Automation tab&lt;/strong&gt; with all relevant details&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supports multiple languages&lt;/strong&gt;: JavaScript, TypeScript, Python, and Gherkin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual indicators&lt;/strong&gt; show which tests are linked vs unlinked&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Add ADO_IDs Comment
&lt;/h3&gt;

&lt;p&gt;Simply add a comment above your test with the test case IDs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ADO_IDs: TC_1234, TC_5678&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User can login with valid credentials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Your test code here&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Run the Association Command
&lt;/h3&gt;

&lt;p&gt;Use VS Code Command Palette (&lt;code&gt;Ctrl+Shift+P&lt;/code&gt;) and run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Associate IDs from Comments&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: See the Magic in Azure DevOps!
&lt;/h3&gt;




&lt;h2&gt;
  
  
  See It In Action
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before: Manual Test Case Management
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8u8t6254suvskjftzxue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8u8t6254suvskjftzxue.png" alt="Before - Manual Process" width="800" height="274"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Traditional manual process of updating test cases one by one&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Azure DevOps Integration Results
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. Associated Automation Tab - Populated Automatically
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmakycbtrl6ml0jvvlcem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmakycbtrl6ml0jvvlcem.png" alt="ADO Associated Automation Tab" width="800" height="251"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Associated Automation tab is automatically filled with test details&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Automation Status Changed to "Automated"
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ac03r8cl6kdv4ccyrrk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ac03r8cl6kdv4ccyrrk.png" alt="ADO Automation Status" width="800" height="69"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  VS Code Integration
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. Visual Indicators in Your Code
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6b2y3l2jd3xts32kx1ml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6b2y3l2jd3xts32kx1ml.png" alt="VS Code Decorations" width="800" height="116"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvgl3upn9va0seic7xtx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvgl3upn9va0seic7xtx.png" alt="VS Code Decorations" width="783" height="130"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Green checkmarks show associated tests, red X shows unassociated tests&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Quick Start Guide
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Installation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install from VS Code Extensions Marketplace&lt;/span&gt;
&lt;span class="c"&gt;# Search for "Azure Test Track"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Setup Environment Variables Globally
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Required ADO configuration&lt;/span&gt;
&lt;span class="nv"&gt;ADO_ORGANIZATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-organization
&lt;span class="nv"&gt;ADO_PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-project
&lt;span class="nv"&gt;ADO_PERSONAL_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-pat-token
&lt;span class="nv"&gt;ADO_COMPANY_EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-email@company.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  3. Start Using
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;For JavaScript/TypeScript:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ADO_IDs: TC_1001&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API returns user data correctly&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Test implementation&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For Python:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ADO_IDs: TC_2001
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_user_authentication&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Test implementation
&lt;/span&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For Gherkin (.feature files):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="c"&gt;# ADO_IDs: TC_3001&lt;/span&gt;
&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; User can complete checkout process
  &lt;span class="nf"&gt;Given &lt;/span&gt;user has items in cart
  &lt;span class="nf"&gt;When &lt;/span&gt;user proceeds to checkout
  &lt;span class="nf"&gt;Then &lt;/span&gt;order should be created successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Pro Tips for QA Teams
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Batch Processing
&lt;/h3&gt;

&lt;p&gt;Associate all tests in a file at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use "Associate IDs from Comments" command&lt;/span&gt;
&lt;span class="c"&gt;# Processes entire file automatically&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Visual Verification
&lt;/h3&gt;

&lt;p&gt;Use the decoration feature to see association status:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Green&lt;/strong&gt;: Test is associated with ADO&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Red&lt;/strong&gt;: Test needs association&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Multiple Test Cases
&lt;/h3&gt;

&lt;p&gt;One test can cover multiple test cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ADO_IDs: TC_1001, TC_1002, TC_1003&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Complete user registration flow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Covers validation, creation, and confirmation&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Real Impact on QA Productivity
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Quality Improvements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;100% accurate&lt;/strong&gt; test case associations&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Real-time sync&lt;/strong&gt; between code and ADO&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Zero manual errors&lt;/strong&gt; in test case updates&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Complete traceability&lt;/strong&gt; from requirement to test&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Enterprise Ready
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Security &amp;amp; Compliance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Uses Azure DevOps PAT tokens (secure authentication)&lt;/li&gt;
&lt;li&gt;✅ Respects organization permissions&lt;/li&gt;
&lt;li&gt;✅ No data stored outside your environment&lt;/li&gt;
&lt;li&gt;✅ Works with enterprise Azure DevOps instances&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Team Collaboration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Consistent test case association across team&lt;/li&gt;
&lt;li&gt;✅ Standardized ADO_IDs format&lt;/li&gt;
&lt;li&gt;✅ Visual indicators for code reviews&lt;/li&gt;
&lt;li&gt;✅ Automated documentation updates&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Need Help?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;📖 &lt;strong&gt;Documentation&lt;/strong&gt;: &lt;a href="//README.md"&gt;README.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💡 &lt;strong&gt;Examples&lt;/strong&gt;: &lt;a href="//EXAMPLE_CODE.md"&gt;Code Examples&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐛 &lt;strong&gt;Issues&lt;/strong&gt;: &lt;a href="https://github.com/TheCollegeHub/azure-test-track-vscode-extension" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📧 &lt;strong&gt;Contact&lt;/strong&gt;: Support team&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔗 Quick Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=araujosnathan.azure-test-track" rel="noopener noreferrer"&gt;Download Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//README.md"&gt;Full Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//EXAMPLE_CODE.md"&gt;Code Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/TheCollegeHub/azure-test-track-vscode-extension" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>vscode</category>
      <category>tooling</category>
      <category>automation</category>
    </item>
    <item>
      <title>[Playwright] Element is outside of the viewport" in Playwright — why it happens and how to fix it</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Fri, 26 Sep 2025 11:32:39 +0000</pubDate>
      <link>https://dev.to/araujosnathan/playwright-element-is-outside-of-the-viewport-in-playwright-why-it-happens-and-how-to-fix-it-hhp</link>
      <guid>https://dev.to/araujosnathan/playwright-element-is-outside-of-the-viewport-in-playwright-why-it-happens-and-how-to-fix-it-hhp</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;You have a checkbox in the DOM, for example, with &lt;code&gt;id="AcceptedTermsOfUse"&lt;/code&gt;, that is &lt;strong&gt;outside of the visible area of the page (viewport)&lt;/strong&gt;, for example with very large negative &lt;code&gt;x&lt;/code&gt; coordinates like &lt;code&gt;x = -9459&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;When you try to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#AcceptedTermsOfUse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Playwright throws an error like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Error: locator.click: Test timeout ...&lt;/code&gt;&lt;br&gt;&lt;br&gt;
“element is outside of the viewport”&lt;br&gt;&lt;br&gt;
or&lt;br&gt;
"Call log:&lt;br&gt;
      - waiting for locator('input[type="checkbox"][name="AcceptedTermsOfUse"]') &lt;br&gt;
        - locator resolved to "&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means: the element exists, it is “visible” in terms of CSS (not &lt;code&gt;display:none&lt;/code&gt;, not &lt;code&gt;visibility:hidden&lt;/code&gt;), but &lt;strong&gt;it is not in a position where a user could physically click it&lt;/strong&gt;, because it’s positioned or hidden off‑screen.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this happens
&lt;/h2&gt;

&lt;p&gt;Common causes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Off‑screen styling&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   The input is styled with &lt;code&gt;position: absolute&lt;/code&gt; (or similar), using &lt;code&gt;left: -xxxxx&lt;/code&gt; or &lt;code&gt;transform&lt;/code&gt; that pushes it outside the viewport.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styled label + hidden input&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   Many UI frameworks hide the real  off-screen and use only a label plus pseudo-elements (::before, ::after) to render the visible checkbox square. This allows them to style a “fancy checkbox” without relying on the browser’s native styling. The user clicks on the label, which propagates the click to the hidden input. So the input is technically visible (not display:none), but &lt;code&gt;positioned outside the viewport&lt;/code&gt; so the user never interacts with it directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Playwright actionability checks&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   Before performing &lt;code&gt;locator.click()&lt;/code&gt;, Playwright ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the element is visible
&lt;/li&gt;
&lt;li&gt;enabled
&lt;/li&gt;
&lt;li&gt;stable (not moving/animating)
&lt;/li&gt;
&lt;li&gt;within the viewport or can be scrolled into it
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of these fail, Playwright won’t click.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Known tricky cases&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Sometimes elements are technically visible but still unreachable due to layout/CSS. This is common with checkboxes hidden for custom styling.&lt;/p&gt;


&lt;h2&gt;
  
  
  Real example
&lt;/h2&gt;

&lt;p&gt;In this case, the checkbox was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visible in CSS terms
&lt;/li&gt;
&lt;li&gt;Enabled
&lt;/li&gt;
&lt;li&gt;But with &lt;code&gt;boundingBox().x = -9459&lt;/code&gt; — far to the left
&lt;/li&gt;
&lt;li&gt;Absolutely positioned
&lt;/li&gt;
&lt;li&gt;No scrollable parent to bring it into view&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  So Playwright couldn’t click because it wasn’t physically actionable.
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Possible solution
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Use &lt;code&gt;page.evaluate&lt;/code&gt; with &lt;code&gt;element.click()&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkbox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AcceptedTermsOfUse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This works even if the input is off‑screen, because it fires a DOM click programmatically.&lt;/p&gt;


&lt;h3&gt;
  
  
  2. Manually set &lt;code&gt;checked&lt;/code&gt; and dispatch events
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkbox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AcceptedTermsOfUse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;bubbles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Forces the state and triggers a &lt;code&gt;change&lt;/code&gt; event.&lt;/p&gt;


&lt;h2&gt;
  
  
  Investigation
&lt;/h2&gt;

&lt;p&gt;You can investigate this behavior directly in the browser console. For example, open DevTools and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AcceptedTermsOfUse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll notice the checkbox gets checked and any attached event listeners fire — even if the element is off-screen.  &lt;/p&gt;




&lt;h3&gt;
  
  
  Why &lt;code&gt;document.getElementById("AcceptedTermsOfUse").click()&lt;/code&gt; works off-screen, but Playwright’s &lt;code&gt;locator.click()&lt;/code&gt; does not?
&lt;/h3&gt;

&lt;p&gt;When you call &lt;code&gt;element.click()&lt;/code&gt; in the browser (either in the console or inside &lt;code&gt;page.evaluate()&lt;/code&gt;), the browser’s DOM engine executes &lt;code&gt;HTMLElement.prototype.click()&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;This method &lt;strong&gt;programmatically triggers all associated events&lt;/strong&gt; (&lt;code&gt;mousedown&lt;/code&gt;, &lt;code&gt;mouseup&lt;/code&gt;, &lt;code&gt;click&lt;/code&gt;, &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;change&lt;/code&gt;, depending on the element) and updates the element state. Importantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The browser &lt;strong&gt;does not require the element to be inside the viewport&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;The DOM allows simulating a click even if the element is positioned off-screen.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Playwright behaves differently
&lt;/h2&gt;

&lt;p&gt;Playwright aims to &lt;strong&gt;simulate real user interaction&lt;/strong&gt;, not just fire DOM events. When you call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#AcceptedTermsOfUse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Playwright performs &lt;strong&gt;actionability checks&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The element must be visible, enabled, stable (not moving), and not covered by other elements.
&lt;/li&gt;
&lt;li&gt;The element must be within the viewport, or Playwright will attempt to scroll it into view.
&lt;/li&gt;
&lt;li&gt;If Playwright cannot make the element actionable, it throws: &lt;code&gt;"element is outside of the viewport"&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These checks exist so tests mimic how a real user would interact with the page — for example, preventing clicks through invisible or off-screen elements.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>testing</category>
      <category>frontend</category>
      <category>automation</category>
    </item>
    <item>
      <title>Exploring Azure Functions for Synthetic Monitoring with Playwright: A Complete Guide - Part 5</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Mon, 15 Sep 2025 15:37:18 +0000</pubDate>
      <link>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-5-14f0</link>
      <guid>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-5-14f0</guid>
      <description>&lt;p&gt;Over the past few days, I’ve been diving into using Azure Functions to implement synthetic monitoring with Playwright. The goal was simple: run browser automation tests every 30 minutes or 1 hour to monitor critical system functionalities. However, as with many cloud adventures, there were some surprises along the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Choosing the Right Plan&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first dilemma was: &lt;strong&gt;&lt;em&gt;Consumption Plan or Premium Plan?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Consumption Plan is cheap but does not support running browsers like Playwright because of strict sandbox limitations.&lt;/p&gt;

&lt;p&gt;The Premium Plan eliminates cold starts, offers dedicated CPU/RAM, and allows running browsers — essential for automation tasks.&lt;/p&gt;

&lt;p&gt;Within the Premium Plan, there are different SKUs: EP1, EP2, and EP3. For a proof of concept (POC) running tests every 30 minutes or 1 hour, EP1 (1 vCPU / 3.5 GB RAM) is enough and much cheaper (~$130–150/month). Heavier workloads require EP2 or EP3 with more CPU and memory.&lt;/p&gt;

&lt;p&gt;I opted for EP1. This ensures Playwright runs stably, even when opening headless browsers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Deployment Structure and “No Functions Found”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Initially, I deployed my Function App via .zip using Azure Pipeline and Release, including dist/, host.json, and other project folders. However, the logs showed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;0 functions found&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I discovered that Azure Functions requires the function folder to be at the root of the deployment or correctly configured. In modern Functions (v4, JavaScript/TypeScript), each function file must use @azure/functions and host.json needs to be at the root.&lt;/p&gt;

&lt;p&gt;To maintain my project structure (dist/functions, dist/support, dist/tests), the solution was to point the deployment to the root of dist and ensure host.json and .js function files were correctly located.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Playwright and Browsers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the biggest challenges was running Playwright on Azure.&lt;/p&gt;

&lt;p&gt;Chromium works fine ✅&lt;/p&gt;

&lt;p&gt;Firefox and WebKit fail ❌&lt;/p&gt;

&lt;p&gt;Typical error:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Error: browserType.launch: spawn UNKNOWN&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This happens because the Azure Functions Windows sandbox doesn’t provide all system dependencies Firefox/WebKit require.&lt;/p&gt;

&lt;p&gt;Possible Solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Chromium only – works reliably and is sufficient for synthetic monitoring.&lt;/li&gt;
&lt;li&gt;Deploy via Linux Function App + --with-deps – installs necessary system libraries.&lt;/li&gt;
&lt;li&gt;Custom Container – a Docker image based on mcr.microsoft.com/playwright comes with Chromium, Firefox, and WebKit pre-installed with dependencies. This is ideal for production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Environment Variables and Paths&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To make Playwright locate the browser, I had to set:&lt;/p&gt;

&lt;p&gt;PLAYWRIGHT_BROWSERS_PATH = 0&lt;/p&gt;

&lt;p&gt;This ensures the Azure Function looks for browsers in the correct location in &lt;code&gt;node_modules&lt;/code&gt;. If you install browsers in the pipeline with npx playwright install chromium, the &lt;code&gt;node_modules&lt;/code&gt; folder must be included all browsers that you need and with PLAYWRIGHT_BROWSERS_PATH = 0 Playwright will look at for the right location.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After going through all of this, I finally succeeded in getting the Azure Function TimerTrigger to run reliably. The execution traces were sent to Application Insights, allowing me to monitor each run in real time. Additionally, the errors that occurred during the tests helped me realize that the reports were being stored in Azure Blob Storage, providing a reliable way to analyze test results and gain insights for further improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/" rel="noopener noreferrer"&gt;Azure Functions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview" rel="noopener noreferrer"&gt;Application Insights Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/" rel="noopener noreferrer"&gt;Azure Blob Storage Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/azurearchitectureblog/synthetic-monitoring-in-application-insights-using-playwright-a-game-changer/4400509" rel="noopener noreferrer"&gt;Synthetic Monitoring - Microsoft Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/araujosnathan/synthetic-monitoring-tests" rel="noopener noreferrer"&gt;My Github Project - synthetic-monitoring-tests &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>monitoring</category>
      <category>serverless</category>
      <category>testing</category>
      <category>azure</category>
    </item>
    <item>
      <title>Exploring Azure Functions for Synthetic Monitoring with Playwright: A Complete Guide - Part 4</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Fri, 12 Sep 2025 13:15:01 +0000</pubDate>
      <link>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-4-481f</link>
      <guid>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-4-481f</guid>
      <description>&lt;h2&gt;
  
  
  Azure Functions Deployment
&lt;/h2&gt;

&lt;p&gt;Deploy your Synthetic Monitoring solution to Azure in 4 simple phases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: Create Azure Resources
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create Function App
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Azure Portal&lt;/strong&gt; → &lt;strong&gt;Create Resource&lt;/strong&gt; → &lt;strong&gt;Function App&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;synthetic-monitoring-func-prod&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Runtime: Node.js 18&lt;/li&gt;
&lt;li&gt;Plan: &lt;strong&gt;Functions Premium&lt;/strong&gt; (production)&lt;/li&gt;
&lt;li&gt;Storage: Create new&lt;/li&gt;
&lt;li&gt;Application Insights: Enable&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq10gm9enz5o72c5i8xkc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq10gm9enz5o72c5i8xkc.png" alt="Azure Function Creation" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create Storage Account (for artifacts)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Azure Portal&lt;/strong&gt; → &lt;strong&gt;Storage Accounts&lt;/strong&gt; → &lt;strong&gt;Create&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;syntheticartifacts[suffix]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Performance: Standard&lt;/li&gt;
&lt;li&gt;Create container: &lt;code&gt;test-artifacts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Get Connection Strings
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application Insights&lt;/strong&gt;: Properties → Connection String&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage Account&lt;/strong&gt;: Access Keys → Connection String&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Phase 2: Configure Function App
&lt;/h2&gt;

&lt;p&gt;Add these variables in &lt;strong&gt;Function App → Settings → Environment Variables&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;APPLICATIONINSIGHTS_CONNECTION_STRING&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;App Insights Connection String]
&lt;span class="nv"&gt;AZURE_STORAGE_CONNECTION_STRING&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;Storage Account Connection String]
&lt;span class="nv"&gt;BLOB_CONTAINER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;test-artifacts
&lt;span class="nv"&gt;baseUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://your-target-application.com
&lt;span class="nv"&gt;SYNTHETIC_MONITOR_SCHEDULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="k"&gt;*&lt;/span&gt;/5 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;
... others &lt;span class="nb"&gt;env &lt;/span&gt;variables
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Phase 3: Setup Azure DevOps Pipeline
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create Build Pipeline
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;azure-pipelines.yml&lt;/code&gt; in your repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest'&lt;/span&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodeTool@0&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;versionSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18.x'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dependencies'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx playwright install --with-deps chromium&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Playwright'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;TypeScript'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ArchiveFiles@2&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;archiveFile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(Build.ArtifactStagingDirectory)/function-app.zip'&lt;/span&gt;
    &lt;span class="na"&gt;includeRootFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublishBuildArtifacts@1&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;artifactName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;function-app'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or classic mode&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F474qlq2ez19ta1zv94a6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F474qlq2ez19ta1zv94a6.png" alt="Pipeline Creation" width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create Release Pipeline
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pipelines&lt;/strong&gt; → &lt;strong&gt;Releases&lt;/strong&gt; → &lt;strong&gt;New Pipeline&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add Artifact&lt;/strong&gt;: Link to build pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add Stage&lt;/strong&gt;: Deploy to Function App&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Task&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Azure Function App Deploy&lt;/li&gt;
&lt;li&gt;App Service name: &lt;code&gt;synthetic-monitoring-func-prod&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Package: &lt;code&gt;$(System.DefaultWorkingDirectory)/_[BuildName]/function-app/function-app.zip&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fee4pe80d4ven21er5ny9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fee4pe80d4ven21er5ny9.png" alt="Release Creation" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 3: Deploy and Monitor
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Deploy
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Commit code&lt;/strong&gt; → &lt;strong&gt;Build runs automatically&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Release pipeline&lt;/strong&gt; → &lt;strong&gt;Deploy to Function App&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify&lt;/strong&gt; function is running in Azure Portal&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Monitor
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application Insights&lt;/strong&gt; → &lt;strong&gt;Live Metrics&lt;/strong&gt; (real-time monitoring)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function App&lt;/strong&gt; → &lt;strong&gt;Monitoring&lt;/strong&gt; → &lt;strong&gt;Log Stream&lt;/strong&gt; (logs in real time)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function App&lt;/strong&gt; → &lt;strong&gt;Functions&lt;/strong&gt; → &lt;strong&gt;syntheticMonitorFunctionName&lt;/strong&gt; (execution history)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage Account&lt;/strong&gt; → &lt;strong&gt;test-artifacts&lt;/strong&gt; (uploaded reports on failures)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Function App created with Application Insights&lt;/li&gt;
&lt;li&gt;[ ] Storage Account created with container&lt;/li&gt;
&lt;li&gt;[ ] Connection strings configured in Function App&lt;/li&gt;
&lt;li&gt;[ ] Build pipeline runs successfully&lt;/li&gt;
&lt;li&gt;[ ] Release pipeline deploys to Function App&lt;/li&gt;
&lt;li&gt;[ ] Function executes and sends telemetry&lt;/li&gt;
&lt;li&gt;[ ] Test artifacts upload on failures&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/" rel="noopener noreferrer"&gt;Azure Functions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview" rel="noopener noreferrer"&gt;Application Insights Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/" rel="noopener noreferrer"&gt;Azure Blob Storage Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/azurearchitectureblog/synthetic-monitoring-in-application-insights-using-playwright-a-game-changer/4400509" rel="noopener noreferrer"&gt;Synthetic Monitoring - Microsoft Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/araujosnathan/synthetic-monitoring-tests" rel="noopener noreferrer"&gt;My Github Project - synthetic-monitoring-tests &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>monitoring</category>
      <category>serverless</category>
      <category>testing</category>
      <category>azure</category>
    </item>
    <item>
      <title>Exploring Azure Functions for Synthetic Monitoring with Playwright: A Complete Guide - Part 3</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Thu, 11 Sep 2025 12:54:10 +0000</pubDate>
      <link>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-3-2a6i</link>
      <guid>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-3-2a6i</guid>
      <description>&lt;h1&gt;
  
  
  Running Synthetic Monitoring with Azurite and Local Testing
&lt;/h1&gt;

&lt;p&gt;Developing and testing synthetic monitoring solutions locally is crucial for rapid development cycles and debugging. This article demonstrates how to run your Azure Functions + Playwright synthetic monitoring solution locally using &lt;strong&gt;Azurite&lt;/strong&gt; (Azure Storage Emulator) for blob storage and local Application Insights configuration.&lt;/p&gt;

&lt;p&gt;This setup allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test your monitoring solution without Azure costs&lt;/li&gt;
&lt;li&gt;Debug issues in a controlled environment&lt;/li&gt;
&lt;li&gt;Validate changes before deploying to production&lt;/li&gt;
&lt;li&gt;Develop offline or with limited internet connectivity&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Local Development Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Azure Timer   │    │  Azure Function │    │   Playwright    │
│   Trigger       │───▶│   (Runtime)     │───▶│   Test Runner   │
│  (Azurite)      │    │                 │    │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                                                        │
                                                        ▼
                                              ┌─────────────────┐
                                              │  Test Results   │
                                              │   Processing    │
                                              └─────────────────┘
                                                        │
                                              ┌─────────┴─────────┐
                                              ▼                   ▼
                                     ┌─────────────────┐ ┌─────────────────┐
                                     │ Application     │ │   Azure Blob    │
                                     │ Insights        │ │   Storage       │
                                     │ (Telemetry)     │ │ (Artifacts)     │
                                     └─────────────────┘ └─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, ensure you have installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node.js 18+&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Functions Core Tools v4&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azurite&lt;/strong&gt; (Azure Storage Emulator)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure Storage Explorer&lt;/strong&gt; (optional, for GUI access)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install Azure Functions Core Tools&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; azure-functions-core-tools@4 &lt;span class="nt"&gt;--unsafe-perm&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# Install Azurite globally&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; azurite

&lt;span class="c"&gt;# Or install as dev dependency in your project&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; azurite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up Azurite for Local Blob Storage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Azurite Installation and Configuration
&lt;/h3&gt;

&lt;p&gt;Azurite emulates Azure Blob Storage, Queue Storage, and Table Storage locally.&lt;/p&gt;

&lt;h4&gt;
  
  
  Global Installation Method:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install globally&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; azurite

&lt;span class="c"&gt;# Start Azurite with default settings&lt;/span&gt;
azurite &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; ./azurite &lt;span class="nt"&gt;--debug&lt;/span&gt; ./azurite/debug.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Azurite Configuration Options
&lt;/h3&gt;

&lt;p&gt;Create an azurite configuration for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start Azurite with custom configuration&lt;/span&gt;
azurite &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--blobHost&lt;/span&gt; 127.0.0.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--blobPort&lt;/span&gt; 10000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--queueHost&lt;/span&gt; 127.0.0.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--queuePort&lt;/span&gt; 10001 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tableHost&lt;/span&gt; 127.0.0.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tablePort&lt;/span&gt; 10002 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt; ./azurite &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--debug&lt;/span&gt; ./azurite/debug.log &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--silent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configuration Parameters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--location&lt;/code&gt;: Directory where Azurite stores data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--debug&lt;/code&gt;: Debug log file location&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--silent&lt;/code&gt;: Reduces console output&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--blobPort&lt;/code&gt;: Port for blob storage (default: 10000)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--loose&lt;/code&gt;: Enables loose mode for compatibility&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Local Environment Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Local Settings Configuration
&lt;/h3&gt;

&lt;p&gt;Create or update your &lt;code&gt;local.settings.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"IsEncrypted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AzureWebJobsStorage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"FUNCTIONS_WORKER_RUNTIME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AZURE_STORAGE_CONNECTION_STRING"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-storage-account-connection-string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"BLOB_CONTAINER_NAME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test-artifacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"APPLICATIONINSIGHTS_CONNECTION_STRING"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-appinsights-connection-string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"SYNTHETIC_MONITOR_SCHEDULE"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0 */5 * * * *"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Configuration Points:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AzureWebJobsStorage&lt;/strong&gt;: Required by Azure Functions runtime&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AZURE_STORAGE_CONNECTION_STRING&lt;/strong&gt;: Used by your blob storage functions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APPLICATIONINSIGHTS_CONNECTION_STRIN&lt;/strong&gt;: Used by your appInsights functions to report the test status&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BLOB_CONTAINER_NAME&lt;/strong&gt;: Container for storing test artifacts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SYNTHETIC_MONITOR_SCHEDULE&lt;/strong&gt;: Set to run every minute for local testing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Complete Local Development Workflow
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Terminal 1 - Start Azurite:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# manually:&lt;/span&gt;
azurite &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; ./azurite &lt;span class="nt"&gt;--debug&lt;/span&gt; ./azurite/debug.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Terminal 2 - Build and Start Azure Functions:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build TypeScript&lt;/span&gt;
npm run build

&lt;span class="c"&gt;# Start Azure Functions locally&lt;/span&gt;
func start &lt;span class="nt"&gt;--typescript&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Terminal 3 - Run Tests Manually (Optional):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run Playwright tests directly&lt;/span&gt;
npx playwright &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Setting up a local development environment with Azurite enables rapid development and testing of your synthetic monitoring solution. This approach provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast Development Cycles&lt;/strong&gt;: No need to deploy to Azure for every change&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Savings&lt;/strong&gt;: No Azure storage costs during development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging Capabilities&lt;/strong&gt;: Full control over the local environment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The combination of Azurite for storage emulation and local Azure Functions runtime creates a robust development environment that closely mirrors production behavior while providing the flexibility needed for effective development and testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/" rel="noopener noreferrer"&gt;Azure Functions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview" rel="noopener noreferrer"&gt;Application Insights Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/" rel="noopener noreferrer"&gt;Azure Blob Storage Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/azurearchitectureblog/synthetic-monitoring-in-application-insights-using-playwright-a-game-changer/4400509" rel="noopener noreferrer"&gt;Synthetic Monitoring - Microsoft Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/araujosnathan/synthetic-monitoring-tests" rel="noopener noreferrer"&gt;My Github Project - synthetic-monitoring-tests &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>monitoring</category>
      <category>serverless</category>
      <category>testing</category>
      <category>azure</category>
    </item>
    <item>
      <title>Exploring Azure Functions for Synthetic Monitoring with Playwright: A Complete Guide - Part 2</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Wed, 10 Sep 2025 19:23:59 +0000</pubDate>
      <link>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-2-46n0</link>
      <guid>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-2-46n0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the first article, we explored how to build a synthetic monitoring solution with Azure Functions and Playwright. Now, we'll dive deep into the &lt;strong&gt;reporting mechanism&lt;/strong&gt; - the crucial component that transforms test results into actionable insights by sending telemetry to Application Insights and storing test artifacts in Azure Blob Storage.&lt;/p&gt;

&lt;p&gt;This article focuses on the &lt;strong&gt;Test Results Processing&lt;/strong&gt; layer of our architecture, explaining how the custom Playwright reporter works, when and how it sends data to Azure services, and best practices for monitoring and troubleshooting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reporting Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────┐
│   Playwright    │
│   Test Runner   │
│                 │
└─────────────────┘
          │
          ▼
┌─────────────────┐
│  Test Results   │ ◄── Custom Reporter Implementation
│   Processing    │
└─────────────────┘
          │
┌─────────┴─────────┐
▼                   ▼
┌─────────────────┐ ┌─────────────────┐
│ Application     │ │   Azure Blob    │
│ Insights        │ │   Storage       │
│ (Telemetry)     │ │ (Artifacts)     │
└─────────────────┘ └─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding Playwright Reporters
&lt;/h2&gt;

&lt;p&gt;Playwright reporters are plugins that process test results during and after test execution. Our custom reporter implements the &lt;code&gt;Reporter&lt;/code&gt; interface with key lifecycle methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;onTestEnd()&lt;/code&gt;&lt;/strong&gt; - Called when each individual test completes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;onEnd()&lt;/code&gt;&lt;/strong&gt; - Called when the entire test run finishes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring the Custom Reporter in Playwright
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Playwright Configuration Setup
&lt;/h3&gt;

&lt;p&gt;The custom reporter is integrated into the Playwright configuration file (&lt;code&gt;playwright.config.ts&lt;/code&gt;). Here's how it's configured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ... other configuration options&lt;/span&gt;

  &lt;span class="na"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;outputFolder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;htmlReportPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;never&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;     &lt;span class="c1"&gt;// Built-in HTML reporter&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;junit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;outputFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;junit-report.xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="c1"&gt;// JUnit XML&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;                                                     &lt;span class="c1"&gt;// Console list reporter&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/support/reporter/appinsights-reporter.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;           &lt;span class="c1"&gt;// Our custom reporter&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="c1"&gt;// ... rest of configuration&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Reporter Loading and Instantiation
&lt;/h3&gt;

&lt;p&gt;When Playwright loads the custom reporter, it follows this process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// appinsights-reporter.ts - Export function that returns reporter instance&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Reporter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AppInsightsReporter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Points:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file path is relative to the project root&lt;/li&gt;
&lt;li&gt;The exported function is called once per test run&lt;/li&gt;
&lt;li&gt;Multiple reporters can run simultaneously&lt;/li&gt;
&lt;li&gt;Each reporter receives the same test events&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Reporter Lifecycle Integration
&lt;/h3&gt;

&lt;p&gt;The Playwright engine automatically calls our reporter methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Test Execution Flow:
┌─────────────────┐
│ Playwright CLI  │
└─────────────────┘
          │
          ▼
┌─────────────────┐
│ Load Reporters  │ ◄── Our custom reporter loaded here
└─────────────────┘
          │
          ▼
┌─────────────────┐
│   Run Tests     │
└─────────────────┘
          │
          ▼ (for each test)
┌─────────────────┐
│ onTestEnd()     │ ◄── Individual test telemetry sent
└─────────────────┘
          │
          ▼ (after all tests)
┌─────────────────┐
│ onEnd()         │ ◄── Artifacts uploaded, telemetry flushed
└─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Custom Reporter Implementation Breakdown
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Core Reporter Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Reporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TestResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FullResult&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test/reporter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppInsightsReporter&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Reporter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;runTimestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Called for each test completion&lt;/span&gt;
  &lt;span class="nf"&gt;onTestEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Process individual test results&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Called when all tests complete&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;onEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FullResult&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Process final results and upload artifacts&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Individual Test Processing (&lt;code&gt;onTestEnd&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This method handles &lt;strong&gt;real-time telemetry&lt;/strong&gt; for each test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;onTestEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Generate unique timestamp for this test run&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runTimestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;:.&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Reporter] onTestEnd called for test: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; with status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Handle retry logic - only report final attempts&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isLastRetry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;retry&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testPassed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;passed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldSendTrace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;testPassed&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;isLastRetry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;shouldSendTrace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Reporter] Skipping report for intermediate retry: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (retry &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Send availability telemetry to Application Insights&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;passed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;appInsightsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackAvailability&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;runLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Azure Function - Playwright Synthetic Monitoring&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;success&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test passed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Test failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runTimestamp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Key Features:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Retry Handling&lt;/strong&gt;: Only sends telemetry for the final retry attempt to avoid duplicate data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability Tracking&lt;/strong&gt;: Uses Application Insights availability telemetry for uptime monitoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich Context&lt;/strong&gt;: Includes test duration, success status, and error messages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unique Identification&lt;/strong&gt;: Each test run gets a timestamp-based identifier&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Final Results Processing (&lt;code&gt;onEnd&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This method handles &lt;strong&gt;artifact storage&lt;/strong&gt; and &lt;strong&gt;telemetry flushing&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;onEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FullResult&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldUpload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Reporter] onEnd called. Test status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Should upload: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shouldUpload&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Upload artifacts only on failure&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shouldUpload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uploadTestArtifacts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Reporter] Failed to zip or upload report:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Ensure all telemetry is sent&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;flushTelemetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[AppInsights] Error during flush:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Key Features:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Conditional Upload&lt;/strong&gt;: Only uploads artifacts when tests fail&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt;: Graceful handling of upload failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telemetry Flushing&lt;/strong&gt;: Ensures all data reaches Application Insights before function ends&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Application Insights Integration Deep Dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Client Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;appInsights&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;applicationinsights&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connectionString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APPLICATIONINSIGHTS_CONNECTION_STRING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;appInsights&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSendLiveMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                    &lt;span class="c1"&gt;// Real-time monitoring&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDistributedTracingMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appInsights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DistributedTracingModes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI_AND_W3C&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAutoDependencyCorrelation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;// Correlate related requests&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAutoCollectRequests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="c1"&gt;// HTTP requests&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAutoCollectPerformance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;// Performance counters&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAutoCollectExceptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;              &lt;span class="c1"&gt;// Unhandled exceptions&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAutoCollectDependencies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c1"&gt;// External dependencies&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAutoCollectConsole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                 &lt;span class="c1"&gt;// Console logs&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setUseDiskRetryCaching&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="c1"&gt;// Retry failed sends&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInternalLogging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;             &lt;span class="c1"&gt;// Debug information&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appInsightsClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;appInsights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Telemetry Types and Usage
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Availability Telemetry
&lt;/h4&gt;

&lt;p&gt;Perfect for synthetic monitoring as it tracks uptime and response times:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;appInsightsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trackAvailability&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login Flow Test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// Test identifier&lt;/span&gt;
  &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                        &lt;span class="c1"&gt;// Pass/fail status&lt;/span&gt;
  &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2543&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                       &lt;span class="c1"&gt;// Response time in ms&lt;/span&gt;
  &lt;span class="na"&gt;runLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Azure Function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// Where test ran&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test passed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// Additional context&lt;/span&gt;
  &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;                    &lt;span class="c1"&gt;// When test ran&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unique-test-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;                 &lt;span class="c1"&gt;// Correlation ID&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Telemetry Flushing
&lt;/h3&gt;

&lt;p&gt;Critical for Azure Functions to ensure data is sent before function terminates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;flushTelemetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Telemetry flush timeout after &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;appInsightsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[AppInsights] Telemetry flushed successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to flush telemetry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Azure Blob Storage Integration Deep Dive
&lt;/h2&gt;

&lt;p&gt;Azure Blob Storage serves as the repository for test artifacts, including HTML reports, screenshots, videos, and traces. This section explains in detail how the storage functions work and what they accomplish.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Storage Client Setup and Initialization
&lt;/h3&gt;

&lt;p&gt;The blob storage client is initialized once and reused throughout the application lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BlobServiceClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ContainerClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/storage-blob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connectionString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AZURE_STORAGE_CONNECTION_STRING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;containerName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BLOB_CONTAINER_NAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-artifacts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;containerClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContainerClient&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blobServiceClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BlobServiceClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;containerClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;blobServiceClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContainerClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containerName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[BlobStorage] Connection string not provided.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;containerClient&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connection Management&lt;/strong&gt;: Establishes a connection to Azure Storage using the connection string&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container Reference&lt;/strong&gt;: Gets a reference to the specific container where artifacts will be stored&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt;: Gracefully handles missing configuration without breaking the application&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Singleton Pattern&lt;/strong&gt;: Creates one client instance that's reused across the application&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Artifact Upload Process - Detailed Breakdown
&lt;/h3&gt;

&lt;p&gt;The upload process involves several critical steps, each with specific purposes:&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Report Compression Function
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;zipReportFolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;folderPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zipName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;zipPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tmpdir&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;zipName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.zip`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createWriteStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zipPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;archive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;archiver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;zlib&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Maximum compression&lt;/span&gt;

    &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[ZIP] Report successfully zipped at: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;zipPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;archive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nx"&gt;archive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;archive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;folderPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Include all files in folder&lt;/span&gt;
    &lt;span class="nx"&gt;archive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;zipPath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Detailed Function Analysis:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;File Path Generation&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a unique zip file path in the system's temporary directory&lt;/li&gt;
&lt;li&gt;Uses the provided &lt;code&gt;zipName&lt;/code&gt; to ensure uniqueness across test runs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stream Setup&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;createWriteStream&lt;/code&gt;: Creates a writable stream to the zip file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;archiver('zip', { zlib: { level: 9 } })&lt;/code&gt;: Creates a zip archiver with maximum compression&lt;/li&gt;
&lt;li&gt;Level 9 compression reduces file size but takes more CPU time&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Content Processing&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;archive.directory(folderPath, false)&lt;/code&gt;: Adds entire directory contents to zip&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;false&lt;/code&gt; parameter means don't include the parent directory in the zip structure&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;archive.finalize()&lt;/code&gt;: Completes the archiving process&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;What Gets Compressed&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML test report files&lt;/li&gt;
&lt;li&gt;CSS stylesheets for report formatting&lt;/li&gt;
&lt;li&gt;JavaScript files for interactive features&lt;/li&gt;
&lt;li&gt;Test artifacts (screenshots, videos, traces)&lt;/li&gt;
&lt;li&gt;Any additional files in the report directory&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 2: Blob Upload Function - Deep Analysis
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadFileToBlobStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blobName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;containerClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[BlobStorage] Container client not initialized.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Ensure container exists&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[BlobStorage] Checking/Creating container if not exists...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;containerClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIfNotExists&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Get blob client for specific file&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blockBlobClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;containerClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBlockBlobClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blobName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Read and upload file&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[BlobStorage] Reading file...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[BlobStorage] Uploading data...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;blockBlobClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uploadData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;blobHTTPHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;blobContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;uploadedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playwright-synthetic-monitoring&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[BlobStorage] Upload completed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;blobName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Detailed Function Breakdown:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pre-flight Validation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checks if &lt;code&gt;containerClient&lt;/code&gt; is initialized&lt;/li&gt;
&lt;li&gt;Gracefully exits if storage isn't configured (non-blocking failure)&lt;/li&gt;
&lt;li&gt;Prevents runtime errors in environments without blob storage&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Container Management&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;createIfNotExists()&lt;/code&gt;: Ensures the storage container exists&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What this does&lt;/strong&gt;: Creates the container if it doesn't exist, ignores if it does&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it's important&lt;/strong&gt;: Handles first-time deployments and container deletion scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permissions&lt;/strong&gt;: Requires storage account contributor permissions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Blob Client Creation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;getBlockBlobClient(blobName)&lt;/code&gt;: Creates a client for the specific blob&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block Blob&lt;/strong&gt;: Optimized for streaming large files and parallel uploads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Types&lt;/strong&gt;: Page blobs (for VHDs), Append blobs (for logs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Naming&lt;/strong&gt;: Uses the provided &lt;code&gt;blobName&lt;/code&gt; which includes timestamp and test info&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;File Processing&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fs.readFileSync(filePath)&lt;/code&gt;: Reads the entire file into memory&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous Read&lt;/strong&gt;: Simpler but blocks the thread&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Considerations&lt;/strong&gt;: Entire file loaded into RAM (consider streaming for large files)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Buffer&lt;/strong&gt;: Binary representation ready for upload&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Upload Operation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;uploadData(fileBuffer, options)&lt;/code&gt;: Uploads the file data to Azure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP Headers&lt;/strong&gt;: Sets content type as 'application/zip' for proper handling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata&lt;/strong&gt;: Adds custom metadata for tracking and organization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata Fields&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;uploadedAt&lt;/code&gt;: Timestamp for retention policies and debugging&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;source&lt;/code&gt;: Identifies the origin system for multi-tenant scenarios&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;What Happens in Azure&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File is stored in the specified container with the given name&lt;/li&gt;
&lt;li&gt;Metadata is indexed and searchable&lt;/li&gt;
&lt;li&gt;Content type enables proper browser handling when downloaded&lt;/li&gt;
&lt;li&gt;Azure automatically handles redundancy and durability&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Storage Organization and Naming Strategy
&lt;/h3&gt;

&lt;p&gt;The blob naming follows a structured pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example blob names generated:&lt;/span&gt;
&lt;span class="c1"&gt;// report-2025-09-09T10-30-45-123Z.zip&lt;/span&gt;
&lt;span class="c1"&gt;// report-2025-09-09T14-15-22-456Z.zip&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;:.&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blobName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`report-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.zip`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefits of this naming strategy:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chronological Sorting&lt;/strong&gt;: Files sort naturally by creation time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uniqueness&lt;/strong&gt;: Timestamp ensures no naming conflicts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readability&lt;/strong&gt;: Easy to identify when tests ran&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation Friendly&lt;/strong&gt;: Parseable for cleanup scripts and analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Complete Upload Workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;onEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FullResult&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldUpload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shouldUpload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// 1. Get report path&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;htmlReportPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PLAYWRIGHT_HTML_REPORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; 
                           &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tmpdir&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playwright-html-report&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// 2. Generate unique name with timestamp&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runTimestamp&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;:.&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;zipName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`report-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// 3. Compress report folder&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;zipPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;zipReportFolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;htmlReportPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zipName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Reporter] Zipped report at: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;zipPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// 4. Upload to blob storage&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;uploadFileToBlobStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zipPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;zipName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.zip`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Reporter] Upload complete.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// 5. Cleanup local file (optional)&lt;/span&gt;
      &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zipPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Reporter] Failed to zip or upload report:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The custom Playwright reporter is the bridge between your test execution and monitoring infrastructure. By understanding how it processes results, sends telemetry to Application Insights, and uploads artifacts to Blob Storage, you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Monitor effectively&lt;/strong&gt; with rich telemetry data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debug efficiently&lt;/strong&gt; with comprehensive artifacts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale reliably&lt;/strong&gt; with optimized error handling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintain visibility&lt;/strong&gt; into your synthetic monitoring health&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This reporting mechanism transforms raw test results into actionable insights, enabling proactive monitoring and rapid issue resolution in your applications.&lt;/p&gt;

&lt;p&gt;The key to success is balancing comprehensive reporting with performance, ensuring your monitoring doesn't become a bottleneck while providing the visibility needed to maintain application reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/" rel="noopener noreferrer"&gt;Azure Functions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview" rel="noopener noreferrer"&gt;Application Insights Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/" rel="noopener noreferrer"&gt;Azure Blob Storage Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/azurearchitectureblog/synthetic-monitoring-in-application-insights-using-playwright-a-game-changer/4400509" rel="noopener noreferrer"&gt;Synthetic Monitoring - Microsoft Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/araujosnathan/synthetic-monitoring-tests" rel="noopener noreferrer"&gt;My Github Project - synthetic-monitoring-tests &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




</description>
    </item>
    <item>
      <title>Exploring Azure Functions for Synthetic Monitoring with Playwright: A Complete Guide - Part 1</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Tue, 09 Sep 2025 16:04:46 +0000</pubDate>
      <link>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-1-3b8c</link>
      <guid>https://dev.to/araujosnathan/exploring-azure-functions-for-synthetic-monitoring-with-playwright-a-complete-guide-part-1-3b8c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Synthetic monitoring is a proactive approach to monitoring web applications by simulating user interactions and measuring performance from the end-user perspective. This article demonstrates how to build a robust synthetic monitoring solution using &lt;strong&gt;Azure Functions&lt;/strong&gt; and &lt;strong&gt;Playwright&lt;/strong&gt; that can automatically test your web applications, report results to Azure Application Insights, and store test artifacts in Azure Blob Storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Synthetic Monitoring Matters
&lt;/h2&gt;

&lt;p&gt;Traditional monitoring only tells you when something is already broken. Synthetic monitoring helps you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Detect issues before users do&lt;/strong&gt; by continuously running automated tests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor critical user journeys&lt;/strong&gt; like login, checkout, or key workflows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate deployments&lt;/strong&gt; by ensuring core functionality works after releases&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Our solution combines several Azure services to create a comprehensive monitoring system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Azure Timer   │    │  Azure Function │    │   Playwright    │
│   Trigger       │───▶│   (Runtime)     │───▶│   Test Runner   │
│  (Scheduled)    │    │                 │    │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                                                        │
                                                        ▼
                                              ┌─────────────────┐
                                              │  Test Results   │
                                              │   Processing    │
                                              └─────────────────┘
                                                        │
                                              ┌─────────┴─────────┐
                                              ▼                   ▼
                                     ┌─────────────────┐ ┌─────────────────┐
                                     │ Application     │ │   Azure Blob    │
                                     │ Insights        │ │   Storage       │
                                     │ (Telemetry)     │ │ (Artifacts)     │
                                     └─────────────────┘ └─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js 18+&lt;/strong&gt; installed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure CLI&lt;/strong&gt; installed and configured&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Functions Core Tools v4&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Azure subscription&lt;/strong&gt; with:

&lt;ul&gt;
&lt;li&gt;Application Insights instance&lt;/li&gt;
&lt;li&gt;Storage Account&lt;/li&gt;
&lt;li&gt;Function App (Premium or Dedicated plan recommended)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Initialize the Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create project directory&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;synthetic-monitoring
&lt;span class="nb"&gt;cd &lt;/span&gt;synthetic-monitoring

&lt;span class="c"&gt;# Initialize Node.js project&lt;/span&gt;
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Install core dependencies&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @azure/functions @playwright/test playwright
npm &lt;span class="nb"&gt;install&lt;/span&gt; @azure/storage-blob applicationinsights archiver dotenv

&lt;span class="c"&gt;# Install development dependencies&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; typescript @types/node @types/archiver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Project Structure
&lt;/h3&gt;

&lt;p&gt;Create the following directory structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;synthetic-monitoring/
├── src/
│   ├── functions/
│   │   └── synthetic-monitor.ts      # Timer-triggered function
│   ├── support/
│   │   ├── azure/
│   │   │   ├── app-insights-client.ts
│   │   │   ├── app-insights.ts
│   │   │   ├── blob-storage-client.ts
│   │   │   └── blob-storage.ts
│   │   ├── logger/
│   │   │   └── logger.ts
│   │   ├── pages/                    # Page Object Models
│   │   ├── reporter/
│   │   │   ├── appinsights-reporter.ts
│   │   │   └── utils.ts
│   │   └── services/                 # Authentication services
│   ├── tests/
│   │   └── marketplace-integration.spec.ts
│   └── index.ts                      # Main entry point
├── host.json                         # Azure Functions configuration
├── local.settings.json              # Local environment variables
├── package.json
├── playwright.config.ts             # Playwright configuration
└── tsconfig.json                    # TypeScript configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Core Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Azure Function Timer Trigger
&lt;/h3&gt;

&lt;p&gt;Create the main timer-triggered function (&lt;code&gt;src/functions/synthetic-monitor.ts&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;InvocationContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Timer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;runPlaywrightTests&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;syntheticMonitor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SYNTHETIC_MONITOR_SCHEDULE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;|| &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,
  handler: async (myTimer: Timer, context: InvocationContext) =&amp;gt; {
    try {
      context.log("🚀 Executing synthetic monitoring tests...");
      await runPlaywrightTests(context);
      context.log("✅ Synthetic monitoring tests completed successfully!");
    } catch (error) {
      context.log("❌ Error in synthetic monitoring tests:", error);
      throw error; // Ensure the function fails for monitoring purposes
    } finally {
      context.log("🔄 Synthetic monitoring cycle completed.");
    }
  }
});
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Main Test Runner
&lt;/h3&gt;

&lt;p&gt;Implement the core test execution logic (&lt;code&gt;src/index.ts&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;spawn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setLoggerContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./support/logger/logger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;InvocationContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Import the function to register it&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./functions/synthetic-monitor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runPlaywrightTests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InvocationContext&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setLoggerContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;▶️ Running Playwright tests via CLI...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Use full path to playwright binary&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;playwrightPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.bin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playwright.cmd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{playwrightPath}" test&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;;

    context.log(&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;📍 Using command: &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{command}&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;);
    const child = spawn(command, { 
      shell: true,
      env: {
        ...process.env,
        // Add any environment variables your tests need
        NODE_ENV: 'production'
      }
    });

    child.stdout.on('data', (data) =&amp;gt; {
      context.log(data.toString());
    });

    child.stderr.on('data', (data) =&amp;gt; {
      context.log(data.toString());
    });

    child.on('error', (error) =&amp;gt; {
      context.log(&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;❌ Playwright tests failed: &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{error.message}&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;);
      reject(error);
    });

    child.on('close', (code) =&amp;gt; {
      if (code === 0) {
        context.log('✅ Playwright tests completed.');
        resolve();
      } else {
        context.log(&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;❌ Playwright tests exited with code &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{code}&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;);
        reject(new Error(&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;Playwright tests failed with code &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{code}&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;));
      }
    });
  });
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Playwright Configuration
&lt;/h3&gt;

&lt;p&gt;Configure Playwright for Azure Functions (&lt;code&gt;playwright.config.ts&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;devices&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;os&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tmpDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tmpdir&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outputPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PLAYWRIGHT_OUTPUT_DIR&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playwright-artifacts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;htmlReportPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PLAYWRIGHT_HTML_REPORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playwright-html-report&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Ensure directories exist&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;recursive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;htmlReportPath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;htmlReportPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;recursive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;testDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/tests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 3 minutes per test&lt;/span&gt;
  &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// Retry failed tests once&lt;/span&gt;
  &lt;span class="na"&gt;fullyParallel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// Adjust based on your Azure Function plan&lt;/span&gt;
  &lt;span class="na"&gt;outputDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Always run headless in Azure Functions&lt;/span&gt;
    &lt;span class="na"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;only-on-failure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;retain-on-failure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;actionTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;outputFolder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;htmlReportPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;never&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;junit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;outputFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;junit-report.xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/support/reporter/appinsights-reporter.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// Custom reporter&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="na"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chromium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;devices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Desktop Chrome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Azure Functions Configuration
&lt;/h3&gt;

&lt;p&gt;Configure the function app (&lt;code&gt;host.json&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"applicationInsights"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"samplingSettings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"isEnabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"excludedTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Request"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"logLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Information"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extensionBundle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Microsoft.Azure.Functions.ExtensionBundle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[4.*, 5.0.0)"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sample Test Implementation
&lt;/h2&gt;

&lt;p&gt;Create a comprehensive test (&lt;code&gt;src/tests/do-somethinng.spec.ts&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BrowserContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aadUsername&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aadPassword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;baseUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BrowserContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bro&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Init all pages here&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt; 

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User should be able to do somethinng&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@some-tag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// All the test implemention here&lt;/span&gt;

    &lt;span class="c1"&gt;//Arrange&lt;/span&gt;
    &lt;span class="c1"&gt;//Act&lt;/span&gt;
    &lt;span class="c1"&gt;//Assert&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment and Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Environment Variables
&lt;/h3&gt;

&lt;p&gt;Set up your environment variables in Azure Function App settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"AzureWebJobsStorage"&lt;/span&gt;: &lt;span class="s2"&gt;"DefaultEndpointsProtocol=https;AccountName=&amp;lt;storage&amp;gt;;AccountKey=&amp;lt;key&amp;gt;"&lt;/span&gt;,
  &lt;span class="s2"&gt;"FUNCTIONS_WORKER_RUNTIME"&lt;/span&gt;: &lt;span class="s2"&gt;"node"&lt;/span&gt;,
  &lt;span class="s2"&gt;"FUNCTIONS_EXTENSION_VERSION"&lt;/span&gt;: &lt;span class="s2"&gt;"~4"&lt;/span&gt;,

  //ScheduleTime
   &lt;span class="s2"&gt;"SYNTHETIC_MONITOR_SCHEDULE"&lt;/span&gt;: &lt;span class="s2"&gt;"0 */10 * * * *"&lt;/span&gt;,

  // Test Configuration
  &lt;span class="s2"&gt;"username"&lt;/span&gt;: &lt;span class="s2"&gt;"&amp;lt;test-user-email&amp;gt;"&lt;/span&gt;,
  &lt;span class="s2"&gt;"password"&lt;/span&gt;: &lt;span class="s2"&gt;"&amp;lt;test-user-password&amp;gt;"&lt;/span&gt;,
  &lt;span class="s2"&gt;"baseUrl"&lt;/span&gt;: &lt;span class="s2"&gt;"&amp;lt;base-url&amp;gt;"&lt;/span&gt;,

  // Azure Services
  &lt;span class="s2"&gt;"APPLICATIONINSIGHTS_CONNECTION_STRING"&lt;/span&gt;: &lt;span class="s2"&gt;"&amp;lt;app-insights-connection&amp;gt;"&lt;/span&gt;,
  &lt;span class="s2"&gt;"APPINSIGHTS_INSTRUMENTATIONKEY"&lt;/span&gt;: &lt;span class="s2"&gt;"&amp;lt;app-insights-key&amp;gt;"&lt;/span&gt;,
  &lt;span class="s2"&gt;"AZURE_BLOB_CONNECTION_STRING"&lt;/span&gt;: &lt;span class="s2"&gt;"&amp;lt;blob-storage-connection&amp;gt;"&lt;/span&gt;,
  &lt;span class="s2"&gt;"AZURE_BLOB_CONTAINER_NAME"&lt;/span&gt;: &lt;span class="s2"&gt;"&amp;lt;container-name&amp;gt;"&lt;/span&gt;,
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Package.json Scripts
&lt;/h3&gt;

&lt;p&gt;Configure build and deployment scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"func start --typescript"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test:local"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx playwright test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"install:browsers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx playwright install"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implementing synthetic monitoring with Azure Functions and Playwright provides a powerful, scalable solution for proactive application monitoring. This approach offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated testing&lt;/strong&gt; on a schedule&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive reporting&lt;/strong&gt; via Application Insights&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Artifact storage&lt;/strong&gt; for debugging failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost-effective scaling&lt;/strong&gt; with Azure Functions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real user simulation&lt;/strong&gt; with Playwright&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key to success is choosing the right Azure Function plan, optimizing Playwright configuration for cloud execution, and implementing robust error handling and monitoring.&lt;/p&gt;

&lt;p&gt;With this foundation, you can expand your monitoring to cover critical user journeys, API endpoints, performance metrics, and multi-region testing to ensure your applications deliver optimal user experiences around the clock.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/" rel="noopener noreferrer"&gt;Azure Functions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview" rel="noopener noreferrer"&gt;Application Insights Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/" rel="noopener noreferrer"&gt;Azure Blob Storage Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/azurearchitectureblog/synthetic-monitoring-in-application-insights-using-playwright-a-game-changer/4400509" rel="noopener noreferrer"&gt;Synthetic Monitoring - Microsoft Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/araujosnathan/synthetic-monitoring-tests" rel="noopener noreferrer"&gt;My Github Project - synthetic-monitoring-tests &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This implementation is based on a real-world production synthetic monitoring system that monitors applications and critical user workflows.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>monitoring</category>
      <category>serverless</category>
      <category>testing</category>
      <category>azure</category>
    </item>
    <item>
      <title>Filtering vs. Locating Elements by Text in Playwright: What’s the Difference?</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Wed, 02 Apr 2025 19:56:33 +0000</pubDate>
      <link>https://dev.to/araujosnathan/filtering-vs-locating-elements-by-text-in-playwright-whats-the-difference-7km</link>
      <guid>https://dev.to/araujosnathan/filtering-vs-locating-elements-by-text-in-playwright-whats-the-difference-7km</guid>
      <description>&lt;p&gt;When writing automated tests with Playwright, selecting elements efficiently is crucial to ensure reliable and maintainable test scripts. A common scenario is selecting an element that contains specific text inside a table. Playwright provides two approaches for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;.filter({ hasText: 'TEXT' })&lt;/strong&gt; - filters elements that contain the specified text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.locator('text=TEXT')&lt;/strong&gt; - finds elements that match the exact text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both methods can be useful, but understanding their differences will help you write more robust selectors. Let’s dive into a practical example.&lt;/p&gt;

&lt;p&gt;Example Scenario: Selecting a Button in a Table Row&lt;/p&gt;

&lt;p&gt;Imagine you have the following table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;table&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;Processing&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;button&amp;gt;Retry&amp;lt;/button&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;COMPLETED&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;button&amp;gt;View&amp;lt;/button&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;Pending&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;button&amp;gt;Retry&amp;lt;/button&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want to select the View button that belongs to the row where the status is COMPLETED.&lt;/p&gt;

&lt;h5&gt;
  
  
  Using &lt;strong&gt;.filter({ hasText })&lt;/strong&gt;
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await expect(
        page.locator('tr')
            .filter({hasText:'COMPLETED'})
            .locator('button'))
      .toHaveText('View')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Why is this approach better?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It first selects all &lt;code&gt;&amp;lt;tr&amp;gt;&lt;/code&gt;elements in the table.&lt;/li&gt;
&lt;li&gt;Then, it filters the rows that contain the text COMPLETED.&lt;/li&gt;
&lt;li&gt;Finally, it finds the &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; inside the filtered row&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Using &lt;strong&gt;.locator('text=')&lt;/strong&gt;
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await expect(
         page.locator('tr')
            .locator('text=COMPLETED')
            .locator('button'))
      .toHaveText('View');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ What’s the issue here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;.locator('text=COMPLETED') tries to find any element containing COMPLETED, even if it’s deep inside another nested element.&lt;/li&gt;
&lt;li&gt;It may return unexpected results if there are multiple matching elements inside different rows.&lt;/li&gt;
&lt;li&gt;The search is not restricted to the row (tr) but instead looks for any match in the selected context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔥 Key Takeaways&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Approach&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Behavior&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Best Use Case&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.filter({ hasText: 'TEXT' })&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filters elements that contain the specified text&lt;/td&gt;
&lt;td&gt;Selecting elements within a parent scope (e.g., table rows)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.locator('text=TEXT')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Locates any element that exactly matches the text&lt;/td&gt;
&lt;td&gt;Quick selection when structure is simple&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ When to Use &lt;strong&gt;.filter({ hasText })&lt;/strong&gt;?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When dealing with structured elements (tables, lists, div containers, etc.).&lt;/li&gt;
&lt;li&gt;When the text is part of a larger element (like a row containing multiple elements).&lt;/li&gt;
&lt;li&gt;When you need precision and don’t want to match unintended elements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ When &lt;strong&gt;.locator('text=')&lt;/strong&gt; Can Cause Issues?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the text appears multiple times on the page, you may get unexpected matches.&lt;/li&gt;
&lt;li&gt;If the element you’re targeting is deeply nested, Playwright may not find it reliably.&lt;/li&gt;
&lt;li&gt;It doesn’t work well when the text is inside an element with other dynamic content.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🚀 So
&lt;/h2&gt;

&lt;p&gt;If you’re working with structured elements like tables or lists, prefer using &lt;strong&gt;.filter({ hasText })&lt;/strong&gt;. It ensures you only interact with elements that are within the expected scope.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;.locator('text=')&lt;/strong&gt; carefully, as it may return unexpected elements depending on the page structure.&lt;/p&gt;




&lt;p&gt;Follow me on &lt;a href="https://www.instagram.com/araujosnathan/" rel="noopener noreferrer"&gt;Instagran&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/araujosnathan" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See more in &lt;a href="https://bythecollege.com/" rel="noopener noreferrer"&gt;TheCollege&lt;/a&gt;&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>automation</category>
      <category>testing</category>
    </item>
    <item>
      <title>[Cypress] Precisa fazer uma instrução condicional baseado se um elemento existe?</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Tue, 21 May 2024 16:53:16 +0000</pubDate>
      <link>https://dev.to/araujosnathan/cypress-precisa-fazer-uma-instrucao-condicional-baseado-se-um-elemento-existe-36kn</link>
      <guid>https://dev.to/araujosnathan/cypress-precisa-fazer-uma-instrucao-condicional-baseado-se-um-elemento-existe-36kn</guid>
      <description>&lt;p&gt;Tentamos ao máximo evitar que nossos testes precisem de instruções de condições, por quê? Porque se temos condicionais significa que em algum aspecto temos comportamentos que estão acontecendo que não temos o controle e isso pode ser ruim para a automação que necessita de estabilidade. &lt;/p&gt;

&lt;p&gt;Imagina você trabalhar na sua automação com alguns dados e caso você não tenha o controle da manipulação desses dados, se esperar por um dado específico mas ele não aparecer, pois você não produziu a sua massa de dados para aquele teste, assim se garantiu que o que existia na base seria ideal, mas se provou que não é.&lt;/p&gt;

&lt;p&gt;Eu coloco esse exemplo pois, da mesma maneira pode acontecer com alguns elementos que queremos que eles estejam presente na página, mas acabam não estando porque o estado atual da massa de dados é outro.&lt;/p&gt;

&lt;p&gt;Por exemplo, você tem um teste que precisa verificar se um ususário é adicionado a uma lista, todos os usuários adicionados trazem seu avatar. Se você não está manipulando os dados dessa lista de usuários, você pode começar seu teste com alguns usuários ou até mesmo nenhum e você precisa saber a quantidade exata de usuários para quando adicionar o novo usuário fazer a validação do total final.&lt;br&gt;
Dessa forma, a única forma de você saber a quantidade de usuários iniciais seria verificar a quantidade de elementos da lista na página, verificando assim quantos avatares aparecem antes de adicionar, correto? &lt;/p&gt;

&lt;p&gt;Lembrando, é claro que existem outros meios para se fazer isso, o exemplo que estou dando é para quando temos um contexto que não conseguimos manipular os dados por uma API ou diretamente no banco de dados antes dos testes e temos que solucionar através da UI.&lt;/p&gt;

&lt;p&gt;Sendo assim, você precisa antes de adicionar, verificar a quantidade desses avatares (sabendo que temos o mesmo componente que representa os avatares com um locator genérico para os mesmos), mas aí que surge um problema, se você apenas se usar de &lt;code&gt;cy.get(avatarLocator).its('length')&lt;/code&gt;, o comando irá falhar caso o **avatarLocator **não exista, e você não quer que falhe, pois sabe que isso pode acontecer, pois pode não ter nenhum usuário na lista.&lt;/p&gt;

&lt;p&gt;Então, como realizar essa condicional para verificar se existe o elemento ou não? Pois se não existir você saberá que a lista está fazia e poderá continuar com as próximas instruções sem seu teste falhar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxufuahglzulcoggfm9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxufuahglzulcoggfm9o.png" alt="cypress-tips" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perceba que com esse código podemos criar condições para aqueles comportamentos que não conseguimos gerenciar através de alguma manipulação de dados e evitamos que o teste falhe quando não deveria. A tomada de decisão é baseado se um elemento existe ou não. Eu dei esse exemplo, mas com certeza se pode utilizar dessa mesma lógica para outros exemplos que tiver enfrentando, como aqueles cenários onde determinado botão só aparece caso um dado estado do usuário seja atendido. Já passou por isso?&lt;/p&gt;

&lt;p&gt;E aí, gostou? Deu para destravar aí nos seus testes?&lt;br&gt;
Tem outras ideias? Compartilha com a gente!&lt;/p&gt;

&lt;p&gt;Quer saber mais sobre mim, acesso aqui: &lt;a href="https://araujosnathan.com/"&gt;Nathan Araujo&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>[Cypress] Encontrando o valor que não está vísivel dentro do componente ao inspecionar</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Tue, 14 May 2024 17:07:54 +0000</pubDate>
      <link>https://dev.to/araujosnathan/cypress-encontrando-o-valor-que-nao-esta-visivel-dentro-do-componente-ao-inspecionar-254j</link>
      <guid>https://dev.to/araujosnathan/cypress-encontrando-o-valor-que-nao-esta-visivel-dentro-do-componente-ao-inspecionar-254j</guid>
      <description>&lt;p&gt;Já pegou um cenário onde você precisa buscar o valor de um elemento, você está vendo que o valor está renderizado na página, mas quando executa o comando, por exemplo, em cypress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cy.get(locator).should('have.text', text)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;acontece um erro e diz que o elemento não tem esse valor, mesmo você vendo esse valor na sua cara? =/&lt;/p&gt;

&lt;p&gt;Alguns componentes não podem estar trazendo esse valor, e se você inspecionar você pode encontrar o elemento mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input id="campo-id" minlength="1" name="campo-id" required="" type="number" class="form-input ng-valid" placeholder="Informe o valor da compra"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No elemento em si não é mostrado o valor, mas ele é mostrado para o usuário, como então conseguir buscar esse valor desse input pra fazer sua validação.&lt;/p&gt;

&lt;p&gt;Você pode usar o commando para buscar esse valor com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cy.get(locator).invoke('val').then(valor =&amp;gt; {
  // Fazer suas ações/validações com esse valor
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ou&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cy.get(locator).invoke('val').should('contain', valor);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora esse valor estará disponivel pra você.&lt;/p&gt;

&lt;p&gt;Esse ocultamento pode ser por alguns motivos, desde como o componente está sendo desenvolvido, no qual o CSS que está sendo usado está mascaradno esse valor ou questão de atualização assíncrona do estado ou autalização do DOM.&lt;/p&gt;

&lt;p&gt;Tente entender com seu time o real motivo, mas nesse meio tempo, já agora não deve ser um problema pra você, visto que consegues recuperar esse valor.&lt;/p&gt;

&lt;p&gt;E aí, já tinha visto isso acontecer? Tem outra solução?&lt;br&gt;
Se não, já salva a dica para quando enfrentar esse comportamento.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Debugando elementos que desaparem rapidamente da página.</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Tue, 07 May 2024 16:58:53 +0000</pubDate>
      <link>https://dev.to/araujosnathan/debugando-elementos-que-desaparem-rapidamente-da-pagina-56i7</link>
      <guid>https://dev.to/araujosnathan/debugando-elementos-que-desaparem-rapidamente-da-pagina-56i7</guid>
      <description>&lt;p&gt;Eu já sofri com isso no passado, ao tentar inspecionar um elemento em uma página da web, ele desaparece rapidamente antes que você possa examiná-lo completamente. Isso torna difícil depurar problemas ou entender a estrutura da página que a gente quer automatizar.&lt;/p&gt;

&lt;p&gt;Você está lá querendo identificar os elementos de forma correta, ver os atributos e de repente você se depara com uma &lt;strong&gt;tooltip&lt;/strong&gt; que está desaparecendo, no qual só aparece quando você coloca o mouse em cima, mas logo desaparece quando remove o mouse ou é aquela lista que quando tenta inspecionar um elemento, ela some automaticamente. E você fica pensando, mas e agora, &lt;strong&gt;como que vou inspecionar esse elemento que estou precisando?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fazendo uma nota rápida aqui:&lt;/strong&gt;&lt;br&gt;
Visto os exemplos iniciais que comentei (Apenas para elucidar o problema que quero ajudar a resolver no seu dia-a-dia), alguém pode dizer, mas de repente esse teste aí não seja para você automatizar nessa camada de UI, deveria ser um unitário ou componente. Não quero entrar nesse discussão agora, porque uma coisa é que talvez de fato não deveria, outra é, beleza, não deveria, mas no momento eu preciso automatizar, e quando essa  realidade bate a porta, não vou mostrar como pode ser feito? Seria no mínimo ridículo, não é? haha Mas tem muita gente falando tanto de melhores práticas e estratégias que descolam da realidade do cotidiano de algum QA por aí, jogam as "melhores práticas" e não dão alguma solução provisória enquanto o contexto do projeto não muda. Percebe?&lt;/p&gt;

&lt;p&gt;Mas voltemos aqui para entender como podemos debugar esse bendito elemento que some. Felizmente, você pode usar uma técnica simples no console das Ferramentas de Desenvolvedor &lt;strong&gt;(DevTools)&lt;/strong&gt; do seu navegador para superar esse problema. Aqui está como fazer isso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Abra as Ferramentas de Desenvolvedor do seu navegador (normalmente acessíveis pressionando F12 ou clicando com o botão direito do mouse em uma página e selecionando "Inspecionar" ou "Inspeção").&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Na barra de ferramentas das Ferramentas de Desenvolvedor &lt;strong&gt;(DevTools)&lt;/strong&gt;, navegue até a aba &lt;strong&gt;Console&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Digite o seguinte comando no console e pressione Enter:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setTimeout(function() {
  debugger;
}, 5000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso define um temporizador para 5000 milissegundos &lt;strong&gt;(5 segundos)&lt;/strong&gt;. Depois desse intervalo, o comando &lt;strong&gt;debugger&lt;/strong&gt; será executado.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Após executar o comando, execute a ação que faz com que o elemento que você deseja inspecionar apareça na página (por exemplo, passe o mouse sobre um elemento, clique em um botão, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quando o temporizador expirar, a execução do código será interrompida e você entrará no modo de depuração do console. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agora você pode inspecionar o elemento e sua estrutura, mesmo que ele tenha desaparecido rapidamente anteriormente.&lt;/p&gt;

&lt;p&gt;Essa técnica pode ser uma ferramenta útil ao trabalhar com páginas da web dinâmicas ou com elementos que desaparecem rapidamente. Experimente ajustar o tempo limite e usar outras técnicas de depuração para obter uma compreensão mais profunda da página que está inspecionando.&lt;/p&gt;

&lt;p&gt;E aí, tava sofrendo pra inspecionar seu elemento?&lt;br&gt;
Essa é uma das formas. Você sabe outras? &lt;br&gt;
Compartilha aí para que mais pessoas possam ser ajudadas!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>[Cypress] Melhorando suas esperas para diminuir aqueles flaky tests.</title>
      <dc:creator>Nathan Araújo</dc:creator>
      <pubDate>Thu, 02 May 2024 13:48:16 +0000</pubDate>
      <link>https://dev.to/araujosnathan/cypress-melhorando-suas-esperas-para-diminuir-aqueles-flaky-tests-5a97</link>
      <guid>https://dev.to/araujosnathan/cypress-melhorando-suas-esperas-para-diminuir-aqueles-flaky-tests-5a97</guid>
      <description>&lt;p&gt;Todos nós já passamos por momentos que testes ficam falhando, rodamos em nossas máquinas locais e tudo parace funcionar como deveria, mas quando começamos executá-los em uma pipeline, alguns testes começam a quebrar e pensamos: por que meu pai? por que está quebrando? Affs!&lt;/p&gt;

&lt;p&gt;Existem motivos para que seus testes estejam quebrando quando não deveriam, ou seja, as regras de negócio estão corretas, nada de estranho para estar na aplicação que está sendo testada. Costumamos chamar essas intermitências de Flaky Tests. Afinal, nesse primeiro momento, não sabemos porque estão falhando, mas se rodarmos novamente, "misteriosamente" eles passam, ai ficam nessa indecisão de passar e falhar.&lt;/p&gt;

&lt;p&gt;Quero hoje te ajudar com um dos motivos que podem estar causando esses Flaky Tests, um deles acontece porque hora os elementos são carregados mais rápidos e outra hora não, e como não estamos controlando isso, acabam que podem passar ou não dependendo da estabilidade da internet ou até mesmo da performance da sua aplicação.&lt;/p&gt;

&lt;p&gt;Isso pode ser tratado de duas maneiras, sem se utilizar da má prática de se ter &lt;strong&gt;Implicit Waits&lt;/strong&gt;, ou seja, sabe quando forçamos nossos testes esperarem um tempo definido, como: &lt;code&gt;cy.wait(5000)&lt;/code&gt;? Seria isso. Não importa o que aconteceça, a automação terá que esperar esse tempo, mas não queremos isso.&lt;/p&gt;

&lt;p&gt;A primeira opção que podemos aplicar para tentar corrigir esse Flaky Test que pode estar sendo causado por um elemento que ainda não apareceu, é aumentar o timeout do elemento que estamos procurando. O cypress automaticamente já possui um &lt;strong&gt;Explicit Wait&lt;/strong&gt;, ou seja, ele sempre fica esperando que o elemento esteja visível e que consigamos interagir com o mesmo, mas o timeout default é de 4 segundos e pode ser pouco dependendo do nosso cenário, então, caso precise aumentar o timeout, basta adicionar o parâmetro de timeout quando buscar o seu elmento que está caausando o Flaky Test, dessa forma:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbd7wlmrmr9v6qcnnpgz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbd7wlmrmr9v6qcnnpgz7.png" alt="waits" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Assim, você não precisará colocar um &lt;em&gt;cy.wait()&lt;/em&gt; e fica melhor a solução.&lt;/p&gt;

&lt;p&gt;Mas pode ser que esse timeout ainda não esteja sendo suficiente porque afinal os elementos na tela só vão ser renderizados quando determinada request terminar.&lt;br&gt;
Se esse for o caso, temos uma segunda solução, se você perceber que uma request ainda está em processamento e seu script de automação está prosseguir, sem esperar a resposta, e que isto está causando seu Flaky Test, você pode esperar até que a request finalize, dessa forma: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkaza77diagbzypp8ta8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkaza77diagbzypp8ta8.png" alt="waits" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas lembre de aumentar o &lt;strong&gt;responseTimeout&lt;/strong&gt; na configuração do cypress se quiser de forma global:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F201ykbchyvg6z9f51k0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F201ykbchyvg6z9f51k0f.png" alt="waits" width="800" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ou se preferir, podes especificar o timeout direto no seu comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cy.wait('@getModules', { responseTimeout: 60000 });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com essas duas soluções você pode diminuir mais seus Flaky Tests, caso sejam por problemas de que elementos não estão visíveis, aplicando assim melhores esperas seja pelo próprio elemento ou pela espera da finalização de alguma request.&lt;/p&gt;

&lt;p&gt;Faz sentido para você? Tem sofrido com Flaky Test?&lt;br&gt;
Espero que esse post possa te ajudar pelo menos com alguns deles!&lt;br&gt;
Lembre-se, o exemplo pode ser em Cypress, mas se você entender o princípio disso, perceberá que vale para outros frameworks de automação também! Guarde isso!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
