Framework Design Examples

Introduction

One of the biggest advantages of abstraction is its ability to simplify the design of large applications and automation frameworks. Instead of exposing complex implementation details, abstraction provides simple, reusable methods that developers can use throughout the application.

In automation testing, framework design relies heavily on abstraction. Common tasks such as launching browsers, navigating pages, clicking buttons, sending API requests, reading test data, generating reports, and taking screenshots are hidden inside reusable classes and methods.

This allows test scripts to focus on what needs to be tested instead of how the task is performed.

In this tutorial, you’ll learn how abstraction is applied in real-world automation framework design using Node.js.


Why Use Abstraction in Framework Design?

Abstraction helps developers:

  • Hide implementation details.

  • Reduce duplicate code.

  • Improve code readability.

  • Increase code reusability.

  • Simplify maintenance.

  • Build scalable automation frameworks.

  • Create reusable components.


Framework Structure Example

A typical automation framework may have the following structure:

AutomationFramework/

│── pages/

│     ├── BasePage.js

│     ├── LoginPage.js

│     └── DashboardPage.js

│

│── api/

│     ├── BaseApi.js

│     └── UserApi.js

│

│── utils/

│     ├── BrowserUtils.js

│     ├── WaitUtils.js

│     └── ScreenshotUtils.js

│

│── tests/

│     └── LoginTest.js

Notice how common functionality is placed in reusable base classes and utility files.


Example 1: Base Page Class

class BasePage {

    open(url) {

        console.log(
            "Opening: " + url
        );

    }

}

class LoginPage extends BasePage {

}

const page =
    new LoginPage();

page.open(
    "https://example.com"
);

Sample Output

Opening: https://example.com

Example 2: Reusable Browser Class

class Browser {

    launch() {

        console.log(
            "Launching browser."
        );

    }

    close() {

        console.log(
            "Closing browser."
        );

    }

}

class ChromeBrowser extends Browser {

}

const browser =
    new ChromeBrowser();

browser.launch();

browser.close();

Sample Output

Launching browser.
Closing browser.

Example 3: Base API Class

class BaseApi {

    sendRequest() {

        console.log(
            "Sending API request."
        );

    }

}

class UserApi extends BaseApi {

}

const api =
    new UserApi();

api.sendRequest();

Sample Output

Sending API request.

Example 4: Utility Class

class ScreenshotUtils {

    takeScreenshot() {

        console.log(
            "Screenshot captured."
        );

    }

}

const utility =
    new ScreenshotUtils();

utility.takeScreenshot();

Sample Output

Screenshot captured.

Example 5: Login Test Using Abstraction

class LoginPage {

    login() {

        console.log(
            "Logging into application."
        );

    }

}

class LoginTest {

    execute() {

        const page =
            new LoginPage();

        page.login();

    }

}

const test =
    new LoginTest();

test.execute();

Sample Output

Logging into application.

The test only calls the login() method. The implementation details remain hidden inside the LoginPage class.


Automation Testing Example

Abstraction is used extensively in modern automation frameworks.

Playwright Framework

Create a reusable base page.

class BasePage {

    click(locator) {

        console.log(
            "Clicking element."
        );

    }

}

class HomePage extends BasePage {

}

const page =
    new HomePage();

page.click("#login");

Selenium Framework

Create reusable browser methods.

class BaseDriver {

    maximizeWindow() {

        console.log(
            "Maximizing browser."
        );

    }

}

class ChromeDriver extends BaseDriver {

}

const driver =
    new ChromeDriver();

driver.maximizeWindow();

Cypress Framework

Create reusable page commands.

class BaseCommands {

    visit(url) {

        console.log(
            "Visiting " + url
        );

    }

}

class DashboardPage extends BaseCommands {

}

const dashboard =
    new DashboardPage();

dashboard.visit(
    "https://example.com"
);

API Testing Framework

Create reusable request methods.

class BaseApi {

    get(endpoint) {

        console.log(
            "GET " + endpoint
        );

    }

}

class ProductApi extends BaseApi {

}

const api =
    new ProductApi();

api.get("/products");

Data-Driven Framework

Create reusable data utilities.

class TestData {

    loadData() {

        console.log(
            "Loading test data."
        );

    }

}

class LoginData extends TestData {

}

const data =
    new LoginData();

data.loadData();

Benefits of Framework Design Using Abstraction

Frameworks that use abstraction provide several advantages:

  • Cleaner test scripts.

  • Better code organization.

  • Higher code reusability.

  • Easier maintenance.

  • Faster framework development.

  • Reduced duplication.

  • Improved scalability.


Common Mistakes

Writing Duplicate Logic

Avoid implementing the same functionality in multiple classes. Move common code to a base class or utility class.


Exposing Internal Framework Logic

Test scripts should use simple methods instead of interacting directly with browser or API implementation details.


Creating Overly Large Base Classes

Keep base classes focused on shared functionality. Split unrelated features into separate utility classes.


Best Practices

  • Create reusable base classes.

  • Keep implementation details hidden.

  • Organize framework components into logical folders.

  • Reuse utility methods across the framework.

  • Keep test scripts simple and readable.

  • Follow the Page Object Model (POM) pattern for UI automation.

  • Design modular and scalable frameworks.


Conclusion

Abstraction is a key design principle for building professional automation frameworks. By hiding complex implementation details and exposing simple, reusable methods, developers can create frameworks that are easier to understand, maintain, and extend.

For automation engineers, abstraction is the foundation of Page Object Models, browser utilities, API clients, reporting modules, and reusable helper classes. It allows test scripts to focus on business logic while the framework manages the underlying implementation.

Mastering framework design using abstraction will help you build scalable, maintainable, and reusable Node.js automation frameworks.


Frequently Asked Questions (FAQs)

Why is abstraction important in framework design?

It hides implementation details, reduces complexity, and improves code reusability.


What is a base class in an automation framework?

A base class contains common functionality that can be inherited by multiple classes.


What is the role of utility classes?

Utility classes provide reusable helper methods such as logging, waiting, screenshots, and file handling.


Why do automation frameworks use abstraction?

It makes test scripts simpler, cleaner, and easier to maintain by hiding complex implementation details.


Which automation frameworks commonly use abstraction?

Playwright, Selenium, Cypress, WebdriverIO, Appium, and API automation frameworks all rely heavily on abstraction.


Key Takeaways

  • Abstraction is essential for automation framework design.

  • It hides implementation details behind simple methods.

  • Base classes provide reusable functionality.

  • Utility classes reduce duplicate code.

  • Test scripts become cleaner and easier to maintain.

  • Page Object Model (POM) is a practical example of abstraction.

  • Abstraction improves scalability and maintainability.

  • Modern automation frameworks heavily rely on abstraction.

  • Reusable framework components improve productivity.

  • Well-designed frameworks are modular, organized, and easy to extend.