Skip to content

Component

createComponent makes it possible to describe a reusable interface fragment.
A component defines where it is located, which elements it exposes, which methods it provides, and which sub-components it embeds.

In practice, it is the basic building block to avoid repeating selectors and helpers everywhere in the tests.

Simple example

ts
import { Actions, 
createComponent
,
createWebsite
, type Website } from "@duplojs/playwright";
import
test
from "playwright/test";
interface TestFixtures {
website
: Website;
} const
testClient
=
test
.
extend
<TestFixtures>({
async
website
({
page
,
context
},
use
) {
const
website
=
createWebsite
({
playwrightPage
:
page
,
playwrightBrowserContext
:
context
,
envConfig
: {
baseUrl
: "https://example.com",
}, }); await
use
(
website
);
}, }); const
searchForm
=
createComponent
(
"searchForm", {
getMainElement
({
body
}) {
return
body
.
locator
("[data-search-form]");
},
getElements
({
mainElement
}) {
return {
input
:
mainElement
.
locator
("input"),
submitButton
:
mainElement
.
locator
("button[type='submit']"),
}; },
getMethods
({
elements
}) {
return { async
fillSearch
(
value
: string) {
await
elements
.
input
.
fill
(
value
);
}, }; }, }, );
testClient
("component example", async({
website
}) => {
const
component
=
searchForm
(
website
);
await
component
.
methods
.
fillSearch
("duplojs");
await Actions.
click
(
component
, "submitButton");
});

What is happening here

  • the example shows an extended Playwright client, then the component definition.
  • createComponent(...) describes a searchForm component.
  • getMainElement(...) defines its root element.
  • getElements(...) exposes reusable named locators.
  • getMethods(...) makes it possible to group a simple business action in the component.

Parameters

  • name - the public name of the component in the test model.
  • params.getMainElement - returns the root locator of the component.
  • params.getElements? - exposes named elements from the component.
  • params.getMethods? - exposes methods built from the component context.
  • params.components? - registers sub-components accessible from the component.

Syntax

ts
interface CreateComponentParams {
	getMainElement(params: {
		body: Locator;
	}): Locator;
	getElements?(params: {
		mainElement: Locator;
		body: Locator;
	}): Record<string, Locator>;
	getMethods?(params: {
		mainElement: Locator;
		body: Locator;
		elements: Record<string, Locator> | undefined;
		website: Website;
	}): Record<string, (...args: any[]) => any>;
	components?: ComponentEngine[];
}

type ComponentEngine = (website: Website) => Component;

interface Component {
	name: string;
	mainElement: Locator;
	elements: Record<string, Locator> | undefined;
	methods: Record<string, (...args: any[]) => any> | undefined;
	iWantToSeeComponent(componentName: string): Promise<Component>;
}

What is it for?

Component is used to centralize in the same place:

  • the selectors of an interface block
  • small reusable business actions
  • composition between several interface fragments

In other words, it makes it possible to write more readable and more stable tests when the same interface area appears often.

See also

  • Website - to instantiate a component in a test context.
  • Page - to build a page on the same model as a component, with makePath(...) in addition.
  • Component Interaction - to create reusable interactions on a component's elements.
  • Actions - for ready-to-use actions on components.
  • Assertions - for ready-to-use assertions on components.

Released under the MIT license.