Part 4 - Master the Basics of TypeScript for Effective Playwright Automation - Functions
- Anuradha Agarwal
- Feb 10
- 5 min read
Updated: Apr 22
Let's say we are building automation tests for our Demo Store. During testing, we often repeat the same steps again and again:
• search for products
• login user
• calculate total price
• validate order success message
• format product text
• verify product category
• process API responses

If we write the same code repeatedly, our script becomes:
• repetitive
• harder to maintain
• difficult to scale
• error-prone
For example, if the login logic changes, we would need to update it everywhere in the code.
This is where functions help us.
A function allows us to group reusable logic into a single block, so we can reuse it multiple times. Instead of writing the same logic repeatedly, we write it once inside a function and call it whenever needed. This makes automation frameworks like Playwright clean, modular, and scalable.
A function is a reusable block of code that performs a specific task.
Think of a function like a small machine:
Input → Processing → Output

Suppose our Demo Store sells both organic and non-organic products.
While writing automation tests, we may need to verify whether a product belongs to the Organic category. Instead of writing the same validation logic in multiple test cases, we create a reusable function.
function isOrganicProduct(productTitle: string): boolean {
return productTitle.toLowerCase().includes("organic");
}Calling the function:
console.log(isOrganicProduct("Organic Apple Juice")); console.log(isOrganicProduct("Chocolate Cake"));Output:
true
false
Now we can reuse this function in multiple automation tests.
Understanding functions becomes easier if we see the two main stages.
Function Definition
This is where we define behaviour.
function openDemoShop() {
console.log("Opening Demo Shop");
}Function Calling
This is where we execute behaviour.
openDemoShop();Without calling the function, nothing happens.
Function Basic Syntax

Basic Function
When our automation test starts, we may want to log that the website has loaded successfully.
Instead of writing console log repeatedly in every test file, we create a reusable function.
function welcomeMessage() {
console.log("Welcome to DemoStore");
}
welcomeMessage();Function with Parameter
Our test automation needs to search for multiple products:
• organic tea
• honey
• green coffee
Instead of creating separate functions for each product, we create one function that accepts a product name dynamically.
function searchProduct(productName: string) {
console.log("Searching product:", productName);
}
searchProduct("Tea");
searchProduct("Coffee");
searchProduct("Honey");Function Returning Value
During checkout testing, we must verify whether the price calculation is correct.
Instead of calculating manually in each test case, we create a reusable function, e.g. Use cases in automation:
Verify cart total, validate invoice value, compare UI vs API price
function calculateTotal(price: number, tax: number): number {
return price + tax;
}
let total = calculateTotal(100, 20);console.log(total);Use Default Parameter
Suppose our Demo Store applies a default 10% discount if no discount value is provided.
Instead of checking for missing values everywhere, we define a default parameter.
function applyDiscount(price: number, discount: number = 10): number {
return price - discount;
}
applyDiscount(100);Use case:
default tax, default discount, default timeout value
Function with Multiple Parameters
While verifying product details, we display both the product name and price together.
Instead of combining values manually everywhere, we create reusable logic.
function createProductLabel(name: string, price: number): string {
return name + " costs $" + price;
}
console.log(createProductLabel("Tea", 10));Rest Parameter (Variable Inputs)
A shopping cart may contain multiple items. Sometimes 2 products, sometimes 10.
Instead of limiting the function to fixed inputs, we allow a flexible number of inputs.
function calculateCartTotal(...prices: number[]): number {
let total = 0; for (let p of prices) {
total += p;
}
return total;
}
calculateCartTotal(100, 200, 300);Passing an Array to a Function
API often returns a list of products. Automation test may need to validate each product name.
function printProducts(products: string[]): void {
for (let product of products) {
console.log(product);
}}
printProducts(["tea", "coffee"]);Use case:
loop through search results, validate product list
Passing an Object to a Function
Product usually contains multiple fields:
name price category
Instead of passing each value separately, we pass object.
type Product = { name: string price: number};
function printProduct(product: Product): void {
console.log(product.name);
}
printProduct({ name: "Tea", price: 100});Common in API responses.
Calling Function Inside Function
Complex automation logic is often built using smaller, reusable steps.
Format product name before validation.
function formatProductName(name: string): string {
return name.toUpperCase();
}Now reuse inside another function.
function processProduct(name: string): void {
console.log("Processing product");
let formatted = formatProductName(name);
console.log(formatted);
}
processProduct("tea");Arrow Function (Modern Function Syntax)
When building automation tests for our Demo Store, we often need to standardise text before validation.For example, product categories in the UI may appear in different formats:
Organic
ORGANIC
organic
Organic Food
ORGANIC FOODIf our automation script compares text exactly as displayed, tests may fail due to case differences. To avoid this problem, we convert text into a consistent format before comparison. This is where a small reusable function helps.
const formatCategory = (category: string): string => {
return category.toLowerCase();
};Usage:
console.log(formatCategory("ORGANIC"));
console.log(formatCategory("Organic"));
console.log(formatCategory("organic"));Output:
organic
organic
organicNow our automation script can reliably compare values.
Suppose our test verifies the category label displayed on the product page:
UI text:
"ORGANIC"Expected value:
"organic"Without formatting, comparison fails. With arrow function:
let actualCategory = "ORGANIC";
if(formatCategory(actualCategory) === "organic"){
console.log("Category validation passed");
}Why Arrow Functions are Popular
Arrow functions provide shorter and cleaner syntax. They are widely used in modern frameworks. They make code: more readable, less verbose, easier to maintain
Compare Normal Function vs Arrow Function
Normal function
function formatCategory(category: string): string {
return category.toLowerCase();
}Arrow function
const formatCategory = (category: string): string => {
return category.toLowerCase();
};Short Arrow Function (Single Line)
When logic is very short, arrow functions can be written on a single line.
const doublePrice = (price: number): number => price * 2;Callback Function (Dynamic Behaviour)
Sometimes behaviour should change based on test scenario. Example:
One test may convert the product name to uppercase. Another may trim spaces.
Instead of fixing logic inside a function, we allow the caller to decide the behaviour.
function processProduct(name: string, action: Function): void { console.log(name);
action();
}
processProduct("Tea", function () { console.log("processed");
});This is a callback using a normal (anonymous) function
Same example using arrow function (callback + arrow)
processProduct("Tea", () => { console.log("processed");});
Callback Returning Value
Suppose pricing logic changes for different customers.Example:
discount logic, tax logic. We want flexible pricing calculation.
function processPrice(price: number, operation: Function): void {
let result = operation(price);
console.log(result);
}
processPrice(100, function(p:number){
return p * 0.9;
});Note that function processPrice(...): void means:
👉 This function does not return anything to the outside world
The return value is coming from the callback function, not from the main function.
If you want the main function to return a value
Then change:
function processPrice(price: number, operation: Function): number {
return operation(price);
}Now:
let finalPrice = processPrice(100, p => p * 0.9);console.log(finalPrice); // 90✔ Now value is returned outside
example
processPrice(price, applyDiscount)
processPrice(price, applyTax)
processPrice(price, applyCoupon)Same function, different logic.
Callback with Parameter
We may want to perform different actions on a product name, like:
• convert to uppercase
• validate text
• format output
Instead of writing multiple functions, we pass the logic as a callback.
function processProduct(name: string, action: (product:string)=>void): void {
action(name);
}
processProduct("Tea", function(product){
console.log(product.toUpperCase());
});Here:
• "Tea" is passed to processProduct
• processProduct calls action(name)
• Callback receives "Tea" as product
• Output → TEA
Arrow Function Version
processProduct("Tea", product => console.log(product.toUpperCase()));👉 Main function sends data
👉 Callback receives data and decides what to do
A callback with parameter lets you pass data from one function to another for flexible and reusable logic.

Function Scope
Temporary variables used inside a function should not affect global code.
function example() {
let message = "hello";
}Protects data integrity.
Nested Function (Closure)
Sometimes inner logic needs access to outer data.
Example:
store configuration settings.
function outerFunction() {
let storeName = "DemoStore";
function innerFunction() {
console.log(storeName);
}
innerFunction();
}Self Invoking Function (IIFE)
When the application loads, initialization logic runs automatically.
(function () {
console.log("Store initialized");
})();Recursive Function
Some calculations repeat until a condition is met.
function factorial(n: number): number {
if (n == 1) {
return 1;
}
return n * factorial(n - 1);
}



Comments