or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

events.mdindex.mdpagefactory.mdutilities.mdwaiting.md

pagefactory.mddocs/

0

# Page Object Factory

1

2

The Page Factory provides a comprehensive implementation of the Page Object Model pattern, offering annotations for element location, automatic element initialization, and flexible locator strategies. It simplifies page object creation by automatically initializing WebElement fields with proxies that locate elements dynamically.

3

4

## Core Factory Methods

5

6

```java { .api }

7

public class PageFactory {

8

/**

9

* Create and initialize a new page object instance

10

*/

11

public static <T> T initElements(WebDriver driver, Class<T> pageClassToProxy);

12

13

/**

14

* Initialize an existing page object instance with element proxies

15

*/

16

public static void initElements(WebDriver driver, Object page);

17

18

/**

19

* Initialize page object with custom element locator factory

20

*/

21

public static void initElements(ElementLocatorFactory factory, Object page);

22

23

/**

24

* Initialize page object with custom field decorator

25

*/

26

public static void initElements(FieldDecorator decorator, Object page);

27

}

28

```

29

30

### Usage Examples

31

32

```java

33

// Create and initialize new page object

34

LoginPage loginPage = PageFactory.initElements(driver, LoginPage.class);

35

36

// Initialize existing page object

37

LoginPage loginPage = new LoginPage();

38

PageFactory.initElements(driver, loginPage);

39

40

// Initialize with custom timeout for AJAX elements

41

AjaxElementLocatorFactory factory = new AjaxElementLocatorFactory(driver, 15);

42

PageFactory.initElements(factory, loginPage);

43

```

44

45

## Element Location Annotations

46

47

### @FindBy Annotation

48

49

```java { .api }

50

@Retention(RetentionPolicy.RUNTIME)

51

@Target({ElementType.FIELD, ElementType.TYPE})

52

public @interface FindBy {

53

/**

54

* Location strategy to use

55

*/

56

How how() default How.UNSET;

57

58

/**

59

* Value to use with the location strategy

60

*/

61

String using() default "";

62

63

/**

64

* Locate by ID attribute

65

*/

66

String id() default "";

67

68

/**

69

* Locate by name attribute

70

*/

71

String name() default "";

72

73

/**

74

* Locate by CSS class name

75

*/

76

String className() default "";

77

78

/**

79

* Locate by CSS selector

80

*/

81

String css() default "";

82

83

/**

84

* Locate by HTML tag name

85

*/

86

String tagName() default "";

87

88

/**

89

* Locate by exact link text

90

*/

91

String linkText() default "";

92

93

/**

94

* Locate by partial link text

95

*/

96

String partialLinkText() default "";

97

98

/**

99

* Locate by XPath expression

100

*/

101

String xpath() default "";

102

}

103

```

104

105

### @FindBys Annotation (AND Logic)

106

107

```java { .api }

108

@Retention(RetentionPolicy.RUNTIME)

109

@Target({ElementType.FIELD, ElementType.TYPE})

110

public @interface FindBys {

111

/**

112

* Array of @FindBy annotations to chain together (all must match)

113

*/

114

FindBy[] value();

115

}

116

```

117

118

### @FindAll Annotation (OR Logic)

119

120

```java { .api }

121

@Retention(RetentionPolicy.RUNTIME)

122

@Target({ElementType.FIELD, ElementType.TYPE})

123

public @interface FindAll {

124

/**

125

* Array of @FindBy annotations (any can match)

126

*/

127

FindBy[] value();

128

}

129

```

130

131

### @CacheLookup Annotation

132

133

```java { .api }

134

@Retention(RetentionPolicy.RUNTIME)

135

@Target(ElementType.FIELD)

136

public @interface CacheLookup {

137

// Marker annotation - element lookups will be cached after first access

138

}

139

```

140

141

### Location Strategy Enum

142

143

```java { .api }

144

public enum How {

145

CLASS_NAME, CSS, ID, ID_OR_NAME, LINK_TEXT, NAME,

146

PARTIAL_LINK_TEXT, TAG_NAME, XPATH, UNSET;

147

148

/**

149

* Build a By locator for this strategy with the given value

150

*/

151

public abstract By buildBy(String value);

152

}

153

```

154

155

## Page Object Examples

156

157

### Basic Page Object

158

159

```java

160

import org.openqa.selenium.WebElement;

161

import org.openqa.selenium.support.FindBy;

162

import org.openqa.selenium.support.PageFactory;

163

164

public class LoginPage {

165

@FindBy(id = "username")

166

private WebElement usernameField;

167

168

@FindBy(name = "password")

169

private WebElement passwordField;

170

171

@FindBy(css = "button[type='submit']")

172

private WebElement submitButton;

173

174

@FindBy(xpath = "//div[@class='error-message']")

175

private WebElement errorMessage;

176

177

public LoginPage(WebDriver driver) {

178

PageFactory.initElements(driver, this);

179

}

180

181

public void login(String username, String password) {

182

usernameField.clear();

183

usernameField.sendKeys(username);

184

passwordField.clear();

185

passwordField.sendKeys(password);

186

submitButton.click();

187

}

188

189

public String getErrorMessage() {

190

return errorMessage.getText();

191

}

192

}

193

```

194

195

### Advanced Locator Strategies

196

197

```java

198

public class AdvancedPage {

199

// Using How enum with using attribute

200

@FindBy(how = How.CSS, using = ".submit-btn")

201

private WebElement submitButton;

202

203

// Chained locators (AND logic) - both conditions must match

204

@FindBys({

205

@FindBy(className = "form-group"),

206

@FindBy(tagName = "input")

207

})

208

private WebElement nestedInput;

209

210

// Multiple possible locators (OR logic) - any condition can match

211

@FindAll({

212

@FindBy(id = "submit"),

213

@FindBy(name = "submit"),

214

@FindBy(xpath = "//input[@type='submit']")

215

})

216

private WebElement submitByAny;

217

218

// Cached lookup - element located once and reused

219

@CacheLookup

220

@FindBy(id = "static-header")

221

private WebElement header;

222

223

// List of elements

224

@FindBy(className = "menu-item")

225

private List<WebElement> menuItems;

226

}

227

```

228

229

## Element Locator Infrastructure

230

231

### ElementLocator Interface

232

233

```java { .api }

234

public interface ElementLocator {

235

/**

236

* Find a single element

237

*/

238

WebElement findElement();

239

240

/**

241

* Find multiple elements

242

*/

243

List<WebElement> findElements();

244

}

245

```

246

247

### ElementLocatorFactory Interface

248

249

```java { .api }

250

public interface ElementLocatorFactory {

251

/**

252

* Create an ElementLocator for the given field

253

*/

254

ElementLocator createLocator(Field field);

255

}

256

```

257

258

### DefaultElementLocator

259

260

```java { .api }

261

public class DefaultElementLocator implements ElementLocator {

262

public DefaultElementLocator(SearchContext searchContext, Field field);

263

public DefaultElementLocator(SearchContext searchContext, AbstractAnnotations annotations);

264

265

public WebElement findElement();

266

public List<WebElement> findElements();

267

protected boolean shouldCache();

268

}

269

```

270

271

### AjaxElementLocator

272

273

```java { .api }

274

public class AjaxElementLocator extends DefaultElementLocator {

275

/**

276

* Element locator that waits for elements to appear (for AJAX content)

277

*/

278

public AjaxElementLocator(SearchContext context, int timeOutInSeconds, AbstractAnnotations annotations);

279

public AjaxElementLocator(SearchContext searchContext, Field field, int timeOutInSeconds);

280

281

public WebElement findElement();

282

public List<WebElement> findElements();

283

protected long sleepFor();

284

protected boolean isElementUsable(WebElement element);

285

}

286

```

287

288

### AjaxElementLocatorFactory

289

290

```java { .api }

291

public class AjaxElementLocatorFactory implements ElementLocatorFactory {

292

/**

293

* Factory for creating AjaxElementLocator instances with timeout

294

*/

295

public AjaxElementLocatorFactory(SearchContext searchContext, int timeOutInSeconds);

296

297

public ElementLocator createLocator(Field field);

298

}

299

```

300

301

## Field Decoration

302

303

### FieldDecorator Interface

304

305

```java { .api }

306

public interface FieldDecorator {

307

/**

308

* Decorate a field with a proxy or return null if field should not be decorated

309

*/

310

Object decorate(ClassLoader loader, Field field);

311

}

312

```

313

314

### DefaultFieldDecorator

315

316

```java { .api }

317

public class DefaultFieldDecorator implements FieldDecorator {

318

public DefaultFieldDecorator(ElementLocatorFactory factory);

319

320

public Object decorate(ClassLoader loader, Field field);

321

protected boolean isDecoratableList(Field field);

322

protected WebElement proxyForLocator(ClassLoader loader, ElementLocator locator);

323

protected List<WebElement> proxyForListLocator(ClassLoader loader, ElementLocator locator);

324

}

325

```

326

327

## Advanced Locator Classes

328

329

### ByAll (OR Logic)

330

331

```java { .api }

332

public class ByAll extends By {

333

/**

334

* Locator that finds elements matching any of multiple By instances

335

*/

336

public ByAll(By... bys);

337

338

public WebElement findElement(SearchContext context);

339

public List<WebElement> findElements(SearchContext context);

340

}

341

```

342

343

### ByChained (AND Logic)

344

345

```java { .api }

346

public class ByChained extends By {

347

/**

348

* Locator that finds elements using chained lookups

349

*/

350

public ByChained(By... bys);

351

352

public WebElement findElement(SearchContext context);

353

public List<WebElement> findElements(SearchContext context);

354

}

355

```

356

357

## Annotation Processing

358

359

### AbstractAnnotations

360

361

```java { .api }

362

public abstract class AbstractAnnotations {

363

/**

364

* Build a By locator from field annotations

365

*/

366

public abstract By buildBy();

367

368

/**

369

* Check if element lookup should be cached

370

*/

371

public abstract boolean isLookupCached();

372

}

373

```

374

375

### Annotations

376

377

```java { .api }

378

public class Annotations extends AbstractAnnotations {

379

/**

380

* Standard implementation for processing Page Object annotations

381

*/

382

public Annotations(Field field);

383

384

public boolean isLookupCached();

385

public By buildBy();

386

protected Field getField();

387

protected By buildByFromDefault();

388

protected void assertValidAnnotations();

389

}

390

```

391

392

### AbstractFindByBuilder

393

394

```java { .api }

395

public abstract class AbstractFindByBuilder {

396

/**

397

* Abstract base class for building By instances from annotations

398

*/

399

public abstract By buildIt(Object annotation, Field field);

400

401

protected By buildByFromFindBy(FindBy findBy);

402

protected By buildByFromShortFindBy(FindBy findBy);

403

protected By buildByFromLongFindBy(FindBy findBy);

404

protected void assertValidFindBy(FindBy findBy);

405

protected void assertValidFindBys(FindBys findBys);

406

protected void assertValidFindAll(FindAll findAll);

407

}

408

```

409

410

## Usage Patterns

411

412

### AJAX-Enabled Page Objects

413

414

```java

415

public class DynamicPage {

416

private WebDriver driver;

417

418

public DynamicPage(WebDriver driver) {

419

this.driver = driver;

420

// Use AjaxElementLocatorFactory for dynamic content

421

AjaxElementLocatorFactory factory = new AjaxElementLocatorFactory(driver, 15);

422

PageFactory.initElements(factory, this);

423

}

424

425

@FindBy(id = "dynamic-content")

426

private WebElement dynamicContent;

427

428

@FindBy(className = "async-loaded")

429

private List<WebElement> asyncElements;

430

}

431

```

432

433

### Inheritance and Page Object Hierarchies

434

435

```java

436

public abstract class BasePage {

437

@FindBy(id = "header")

438

protected WebElement header;

439

440

@FindBy(id = "footer")

441

protected WebElement footer;

442

443

public BasePage(WebDriver driver) {

444

PageFactory.initElements(driver, this);

445

}

446

}

447

448

public class HomePage extends BasePage {

449

@FindBy(id = "welcome-message")

450

private WebElement welcomeMessage;

451

452

public HomePage(WebDriver driver) {

453

super(driver);

454

}

455

}

456

```