DEV Community

Tharun Reddy
Tharun Reddy

Posted on

1 1

From Natural Language to Automated Tests: Simplifying UI Workflows with AI

In today’s fast-paced world of software development, testing complex web applications can be a significant bottleneck. Manually writing test cases for every user flow and edge case is time-consuming and error-prone. But what if you could streamline the process by describing your test scenarios in plain English and letting an AI-driven framework handle the execution?

This article explores how to automate UI testing for complex workflows using a LangChain-inspired approach combined with Playwright, a powerful browser automation tool. We’ll use Amazon.com as our target application to demonstrate how natural language prompts can generate and execute test cases efficiently.

Understanding LangChain

LangChain is a framework designed to facilitate the use of language models for various workflows, including automation. By leveraging its core principles, we can easily translate human-readable commands into structured actions, making it ideal for creating a flexible, natural language-driven UI testing framework.

Limitations of GitHub Copilot in Complex Workflows

GitHub Copilot is an excellent tool for generating code snippets and speeding up development. However, it has limitations when it comes to orchestrating complex workflows. For example:

  • Copilot can't natively integrate with testing frameworks like Playwright or Cypress.

  • It lacks the ability to chain multiple actions together seamlessly.

  • It requires manual intervention to handle edge cases and dynamic workflows.

A LangChain-inspired approach solves these challenges by mapping natural language prompts to predefined test functions. This allows you to describe entire workflows in plain English and execute them automatically.

Automating Test Case Generation with LangChain for UI Testing

Let’s build a test automation framework using Playwright and a LangChain-inspired approach. We’ll simulate real-world scenarios on Amazon.com, such as searching for products, adding items to the cart, and verifying results.

Step 1: Define UI Test Functions

First, we’ll create utility functions for common UI actions on Amazon.com. These functions will be wrapped in a LangChain-inspired system to enable natural language prompts.

// uiTestFunctions.js
const { chromium } = require('playwright');

async function openAmazon(page) {
  await page.goto('https://www.amazon.com');
  await page.waitForSelector('#nav-logo-sprites');
  return "Amazon homepage loaded successfully!";
}

async function searchForProduct(page, query) {
  await page.fill('#twotabsearchtextbox', query);
  await page.click('#nav-search-submit-button');
  await page.waitForSelector('.s-main-slot');
  return `Search for "${query}" completed!`;
}

async function addFirstProductToCart(page) {
  const productLink = await page.$('.s-main-slot .s-title a');
  if (!productLink) {
    throw new Error("No products found in search results.");
  }
  await productLink.click();
  await page.waitForSelector('#add-to-cart-button');
  await page.click('#add-to-cart-button');
  await page.waitForSelector('#sw-gtc'); // Wait for "Go to Cart" button
  return "First product added to cart!";
}

async function verifyCartContainsItems(page) {
  const cartCount = await page.textContent('#nav-cart-count');
  return parseInt(cartCount) > 0 ? "Cart contains items!" : "Cart is empty!";
}

async function verifyNoSearchResults(page) {
  const noResultsMessage = await page.$('.s-no-outline'); // Amazon's "no results" message
  return noResultsMessage ? "No results found!" : "Results are displayed.";
}

module.exports = { openAmazon, searchForProduct, addFirstProductToCart, verifyCartContainsItems, verifyNoSearchResults };

Enter fullscreen mode Exit fullscreen mode

Step 2: Wrap Functions Using LangChain-Inspired Tools

Next, we’ll create a runPrompt function that maps natural language prompts to the appropriate test functions.

// langchainTools.js
const { chromium } = require('playwright');
const { openAmazon, searchForProduct, addFirstProductToCart, verifyCartContainsItems, verifyNoSearchResults } = require('./uiTestFunctions');

async function runPrompt(prompt) {
  const browser = await chromium.launch({ headless: false }); // Run in non-headless mode for visibility
  const page = await browser.newPage();

  let result = "Unknown command.";

  try {
    if (prompt.includes("open Amazon")) {
      result = await openAmazon(page);
    } else if (prompt.includes("search for")) {
      const query = prompt.split('search for ')[1].replace(/"/g, ''); // Extract search query
      result = await searchForProduct(page, query);
    } else if (prompt.includes("add first product to cart")) {
      result = await addFirstProductToCart(page);
    } else if (prompt.includes("verify cart contains items")) {
      result = await verifyCartContainsItems(page);
    } else if (prompt.includes("verify no results")) {
      result = await verifyNoSearchResults(page);
    }
  } catch (error) {
    result = `Error: ${error.message}`;
  } finally {
    await browser.close();
  }

  return result;
}

module.exports = { runPrompt };
Enter fullscreen mode Exit fullscreen mode

Step 3: Executing Tests with Natural Language Prompts

Finally, we’ll create a testRunner script to execute test cases using natural language prompts.

// testRunner.js
const { runPrompt } = require('./langchainTools');

async function runTests() {
  const testCase1 = "Open Amazon.";
  const testCase2 = 'Search for "wireless headphones".';
  const testCase3 = "Add first product to cart.";
  const testCase4 = "Verify cart contains items.";
  const testCase5 = 'Search for "nonexistentProduct" and verify no results.';

  console.log(await runPrompt(testCase1)); // Open Amazon
  console.log(await runPrompt(testCase2)); // Search for "wireless headphones"
  console.log(await runPrompt(testCase3)); // Add first product to cart
  console.log(await runPrompt(testCase4)); // Verify cart contains items
  console.log(await runPrompt(testCase5)); // Search for "nonexistentProduct" and verify no results
}

runTests();
Enter fullscreen mode Exit fullscreen mode

Generating Edge Cases Automatically

Here are some practical examples of how this approach can be used to test Amazon.com:

Example 1: Search and Add to Cart

Prompt: await runPrompt("Search for 'laptop', add the first product to the cart, and verify the cart contains items.")

Example 2: Edge Case: No Search Results

Prompt: await runPrompt("Search for 'nonexistentProduct' and verify no results are displayed.")

Example 3: Multi-Step Workflow

Prompt: await runPrompt("Open Amazon, search for 'smartwatch', add the first product to the cart, and verify the cart contains items.")

By chaining these prompts together, you can easily generate comprehensive tests that cover common and edge-case scenarios.

Benefits of This Approach

  • Efficiency: Write test cases in natural language, reducing the need for manual scripting.
  • Flexibility: Add or modify tests by simply changing the natural language prompt.
  • Reusability: Common functions like searchForProduct and addFirstProductToCart can be reused across multiple test scenarios.
  • Edge Case Handling: This approach is especially useful for testing edge cases, which are often the most difficult and time-consuming to account for manually. For example, you can easily test scenarios where no search results are returned or when the cart is empty. However, keep in mind that the framework’s ability to handle dynamic UI changes depends on the consistency of the target web page. For highly dynamic or complex applications, additional configuration might be needed to ensure the tests run smoothly, such as managing different page load times or handling unexpected pop-ups.
  • Integration with Existing Tools: Leverage the full power of tools like Cypress, Playwright, and Puppeteer, while benefiting from higher-level orchestration.

Conclusion:

By combining natural language prompts with Playwright and a LangChain-inspired approach, we can automate complex UI workflows with minimal effort. This method not only speeds up test case creation but also ensures comprehensive coverage of edge cases and user flows. As AI-driven tools continue to evolve, we can expect even more seamless integration of natural language processing in test automation, further reducing manual effort and increasing test reliability. Keep an eye on these developments, and try implementing this approach in your next project to see how it transforms your testing workflow!

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (1)

Collapse
 
jamesw99 profile image
James W

thank you for putting this together - it’s truly excellent!

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay