Practical Automation Examples

Introduction

The Decorator Pattern is widely used in automation frameworks to add extra functionality to existing functions without modifying their original implementation. This is commonly achieved using function wrappers, where a new function surrounds the original function and performs additional tasks before or after it executes.

In automation testing, many features such as logging, screenshots, retries, execution timing, authentication, validation, reporting, and exception handling are implemented using the Decorator Pattern.

Instead of writing the same code repeatedly in every test case, decorators allow you to reuse these common behaviors across multiple automation scripts.

Modern Node.js automation frameworks such as Playwright, Puppeteer, WebdriverIO, and custom automation frameworks frequently use this design pattern to create clean, reusable, and maintainable test code.

In this tutorial, you’ll explore practical automation examples of the Decorator Pattern.


Why Use the Decorator Pattern in Automation?

The Decorator Pattern helps automation engineers:

  • Add reusable functionality.

  • Avoid duplicate code.

  • Improve test maintainability.

  • Separate utility logic from test logic.

  • Simplify debugging.

  • Improve reporting.

  • Follow clean coding practices.


Example 1: Logging Test Execution

Add logging before and after a test runs.

function executeTest() {

    console.log(

        "Executing login test."

    );

}

function logger(func) {

    return function () {

        console.log(

            "Test started."

        );

        func();

        console.log(

            "Test completed."

        );

    };

}

const test =

    logger(executeTest);

test();

Sample Output

Test started.
Executing login test.
Test completed.

Example 2: Browser Launch Wrapper

Add logging during browser launch.

function launchBrowser() {

    console.log(

        "Browser launched."

    );

}

function browserLogger(func) {

    return function () {

        console.log(

            "Launching browser..."

        );

        func();

    };

}

browserLogger(

    launchBrowser

)();

Sample Output

Launching browser...
Browser launched.

Example 3: Screenshot Decorator

Automatically capture a screenshot after verification.

function verifyHomePage() {

    console.log(

        "Home page verified."

    );

}

function screenshot(func) {

    return function () {

        func();

        console.log(

            "Screenshot captured."

        );

    };

}

screenshot(

    verifyHomePage

)();

Sample Output

Home page verified.
Screenshot captured.

Example 4: Retry Decorator

Automatically retry a failed operation.

function executeApiTest() {

    console.log(

        "API request executed."

    );

}

function retry(func) {

    return function () {

        console.log(

            "Retry mechanism enabled."

        );

        func();

    };

}

retry(

    executeApiTest

)();

Sample Output

Retry mechanism enabled.
API request executed.

Example 5: Execution Timer

Measure execution time.

function generateReport() {

    console.log(

        "Generating report."

    );

}

function timer(func) {

    return function () {

        console.time(

            "Execution"

        );

        func();

        console.timeEnd(

            "Execution"

        );

    };

}

timer(

    generateReport

)();

Sample Output

Generating report.
Execution: <execution time>

Playwright Automation Example

Add logging before every browser action.

function clickLogin() {

    console.log(

        "Clicked Login button."

    );

}

function logger(func) {

    return function () {

        console.log(

            "Performing browser action..."

        );

        func();

    };

}

logger(

    clickLogin

)();

Sample Output

Performing browser action...
Clicked Login button.

Selenium Automation Example

Automatically capture a screenshot after test execution.

function runTest() {

    console.log(

        "Selenium test completed."

    );

}

function screenshot(func) {

    return function () {

        func();

        console.log(

            "Screenshot saved."

        );

    };

}

screenshot(

    runTest

)();

Sample Output

Selenium test completed.
Screenshot saved.

Cypress Automation Example

Measure page verification time.

function verifyDashboard() {

    console.log(

        "Dashboard verified."

    );

}

timer(

    verifyDashboard

)();

Sample Output

Dashboard verified.
Execution: <execution time>

API Testing Example

Validate API responses before processing.

function processResponse() {

    console.log(

        "Response processed."

    );

}

function validate(func) {

    return function () {

        console.log(

            "Response validated."

        );

        func();

    };

}

validate(

    processResponse

)();

Sample Output

Response validated.
Response processed.

Data-Driven Testing Example

Validate test data before execution.

function executeTest(data) {

    console.log(

        "Executing",

        data

    );

}

function validate(func) {

    return function (data) {

        if (!data) {

            console.log(

                "Invalid test data."

            );

            return;

        }

        func(data);

    };

}

const run =

    validate(executeTest);

run("TC001");

run("");

Sample Output

Executing TC001
Invalid test data.

Real-World Automation Uses

The Decorator Pattern is commonly used for:

  • Browser launch logging.

  • Screenshot capture.

  • Retry mechanisms.

  • Test reporting.

  • Authentication.

  • Authorization.

  • API validation.

  • Performance monitoring.

  • Error handling.

  • Data validation.


Benefits in Automation Frameworks

  • Improves code reuse.

  • Keeps test scripts clean.

  • Reduces duplicate code.

  • Makes maintenance easier.

  • Separates utility logic from business logic.

  • Simplifies debugging.

  • Supports modular automation architecture.


Common Mistakes

Modifying the Original Test Function

Always wrap the original function instead of editing it directly.


Combining Too Many Responsibilities

Each decorator should focus on one specific enhancement.


Forgetting to Return the Wrapped Function

Decorator functions should always return the enhanced function.


Best Practices

  • Keep decorators reusable.

  • Give wrappers meaningful names.

  • Add only one responsibility per decorator.

  • Combine decorators when necessary.

  • Keep test logic independent from utility logic.

  • Test decorators separately.

  • Reuse decorators across automation projects.


Conclusion

The Decorator Pattern is an excellent way to extend automation scripts without modifying their original implementation. By wrapping functions with reusable enhancements such as logging, retries, screenshots, validation, and timing, automation engineers can create cleaner and more maintainable test frameworks.

Whether you’re building browser automation with Playwright, web testing with Selenium, end-to-end tests with Cypress, or API testing in Node.js, decorators help reduce duplicate code while improving flexibility and scalability. Mastering this pattern is an important step toward designing professional automation frameworks.


Frequently Asked Questions (FAQs)

Why is the Decorator Pattern useful in automation?

It allows reusable features like logging, screenshots, retries, and reporting to be added without changing existing test code.


What is a function wrapper?

A function wrapper is a function that surrounds another function and adds extra behavior before or after its execution.


Can multiple decorators be combined?

Yes. Multiple decorators can be layered together to provide several enhancements.


Is the original function modified?

No. The original function remains unchanged, and the decorator extends its behavior.


Which automation frameworks benefit from decorators?

Playwright, Selenium, Cypress, Puppeteer, WebdriverIO, and custom Node.js automation frameworks commonly use the Decorator Pattern.


Key Takeaways

  • The Decorator Pattern extends functionality without modifying existing code.

  • Function wrappers are the most common JavaScript implementation of decorators.

  • Decorators improve code reuse and maintainability.

  • Automation frameworks use decorators for logging, retries, screenshots, reporting, and validation.

  • Each decorator should have a single responsibility.

  • Decorators keep test logic separate from utility logic.

  • Multiple decorators can be combined to build powerful automation workflows.

  • The Decorator Pattern supports scalable and modular automation frameworks.

  • Wrappers make automation scripts cleaner and easier to maintain.

  • Mastering the Decorator Pattern is valuable for professional Node.js and automation development.