Skip to content

Commit 10e29aa

Browse files
authored
Implementation Notes & PageFactory (Minor Fixes) (#1394)
* Add syntax highlighting for code examples in Implementation notes * Remove mentions of PageFactory (discouraged) * Minor text and comment improvements * Add emphasis on important points * Update relevant pages - JA, PT-BR, ZH-CN [deploy site]
1 parent b29e45b commit 10e29aa

File tree

4 files changed

+68
-88
lines changed

4 files changed

+68
-88
lines changed

Diff for: website_and_docs/content/documentation/test_practices/encouraged/page_object_models.en.md

+17-22
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,15 @@ requests from the test.
198198

199199
## Page Component Objects
200200
A page object does not necessarily need to represent all the parts of a
201-
page itself. The same principles used for page objects can be used to
202-
create "Page _Component_ Objects" that represent discrete chunks of the
203-
page and can be included in page objects. These component objects can
201+
page itself. This was [noted by Martin Fowler](https://martinfowler.com/bliki/PageObject.html#footnote-panel-object) in the early days, while first coining the term "panel objects".
202+
203+
The same principles used for page objects can be used to
204+
create "Page _Component_ Objects", as it was later called, that represent discrete chunks of the
205+
page and **can be included in page objects**. These component objects can
204206
provide references to the elements inside those discrete chunks, and
205-
methods to leverage the functionality provided by them.
207+
methods to leverage the functionality or behavior provided by them.
206208

207-
For example, a Product page has multiple products.
209+
For example, a Products page has multiple products.
208210

209211
```html
210212
<!-- Products Page -->
@@ -242,7 +244,7 @@ Each product is a component of the Products page.
242244
</div>
243245
```
244246

245-
The Product page HAS-A list of products. This relationship is called Composition. In simpler terms, something is _composed of_ another thing.
247+
The Products page HAS-A list of products. This object relationship is called Composition. In simpler terms, something is _composed of_ another thing.
246248

247249
```java
248250
public abstract class BasePage {
@@ -325,7 +327,7 @@ So now, the products test would use the page object and the page component objec
325327
public class ProductsTest {
326328
@Test
327329
public void testProductInventory() {
328-
var productsPage = new ProductsPage(driver);
330+
var productsPage = new ProductsPage(driver); // page object
329331
var products = productsPage.getProducts();
330332
assertEquals(6, products.size()); // expected, actual
331333
}
@@ -336,7 +338,7 @@ public class ProductsTest {
336338

337339
// Pass a lambda expression (predicate) to filter the list of products
338340
// The predicate or "strategy" is the behavior passed as parameter
339-
var backpack = productsPage.getProduct(p -> p.getName().equals("Backpack"));
341+
var backpack = productsPage.getProduct(p -> p.getName().equals("Backpack")); // page component object
340342
var bikeLight = productsPage.getProduct(p -> p.getName().equals("Bike Light"));
341343

342344
assertEquals(new BigDecimal("29.99"), backpack.getPrice());
@@ -354,8 +356,7 @@ components used throughout the site (e.g. a navigation bar), then it
354356
may improve maintainability and reduce code duplication.
355357

356358
## Other Design Patterns Used in Testing
357-
There are other design patterns that also may be used in testing. Some use a
358-
Page Factory for instantiating their page objects. Discussing all of these is
359+
There are other design patterns that also may be used in testing. Discussing all of these is
359360
beyond the scope of this user guide. Here, we merely want to introduce the
360361
concepts to make the reader aware of some of the things that can be done. As
361362
was mentioned earlier, many have blogged on this topic and we encourage the
@@ -366,11 +367,11 @@ reader to search for blogs on these topics.
366367

367368
PageObjects can be thought of as facing in two directions simultaneously. Facing toward the developer of a test, they represent the **services** offered by a particular page. Facing away from the developer, they should be the only thing that has a deep knowledge of the structure of the HTML of a page (or part of a page) It's simplest to think of the methods on a Page Object as offering the "services" that a page offers rather than exposing the details and mechanics of the page. As an example, think of the inbox of any web-based email system. Amongst the services it offers are the ability to compose a new email, choose to read a single email, and list the subject lines of the emails in the inbox. How these are implemented shouldn't matter to the test.
368369

369-
Because we're encouraging the developer of a test to try and think about the services they're interacting with rather than the implementation, PageObjects should seldom expose the underlying WebDriver instance. To facilitate this, methods on the PageObject should return other PageObjects. This means we can effectively model the user's journey through our application. It also means that should the way that pages relate to one another change (like when the login page asks the user to change their password the first time they log into a service when it previously didn't do that), simply changing the appropriate method's signature will cause the tests to fail to compile. Put another way; we can tell which tests would fail without needing to run them when we change the relationship between pages and reflect this in the PageObjects.
370+
Because we're encouraging the developer of a test to try and think about the services they're interacting with rather than the implementation, PageObjects should seldom expose the underlying WebDriver instance. To facilitate this, **methods on the PageObject should return other PageObjects**. This means we can effectively model the user's journey through our application. It also means that should the way that pages relate to one another change (like when the login page asks the user to change their password the first time they log into a service when it previously didn't do that), simply changing the appropriate method's signature will cause the tests to fail to compile. Put another way; we can tell which tests would fail without needing to run them when we change the relationship between pages and reflect this in the PageObjects.
370371

371372
One consequence of this approach is that it may be necessary to model (for example) both a successful and unsuccessful login; or a click could have a different result depending on the app's state. When this happens, it is common to have multiple methods on the PageObject:
372373

373-
```
374+
```java
374375
public class LoginPage {
375376
public HomePage loginAs(String username, String password) {
376377
// ... clever magic happens here
@@ -388,7 +389,7 @@ public class LoginPage {
388389

389390
The code presented above shows an important point: the tests, not the PageObjects, should be responsible for making assertions about the state of a page. For example:
390391

391-
```
392+
```java
392393
public void testMessagesAreReadOrUnread() {
393394
Inbox inbox = new Inbox(driver);
394395
inbox.assertMessageWithSubjectIsUnread("I like cheese");
@@ -398,7 +399,7 @@ public void testMessagesAreReadOrUnread() {
398399

399400
could be re-written as:
400401

401-
```
402+
```java
402403
public void testMessagesAreReadOrUnread() {
403404
Inbox inbox = new Inbox(driver);
404405
assertTrue(inbox.isMessageWithSubjectIsUnread("I like cheese"));
@@ -421,7 +422,7 @@ Finally, a PageObject need not represent an entire page. It may represent a sect
421422

422423
## Example
423424

424-
```
425+
```java
425426
public class LoginPage {
426427
private final WebDriver driver;
427428

@@ -490,10 +491,4 @@ public class LoginPage {
490491
return submitLogin();
491492
}
492493
}
493-
494-
```
495-
496-
497-
## Support in WebDriver
498-
499-
There is a PageFactory in the support package that provides support for this pattern and helps to remove some boiler-plate code from your Page Objects at the same time.
494+
```

Diff for: website_and_docs/content/documentation/test_practices/encouraged/page_object_models.ja.md

+17-22
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,15 @@ requests from the test.
199199

200200
## Page Component Objects
201201
A page object does not necessarily need to represent all the parts of a
202-
page itself. The same principles used for page objects can be used to
203-
create "Page _Component_ Objects" that represent discrete chunks of the
204-
page and can be included in page objects. These component objects can
202+
page itself. This was [noted by Martin Fowler](https://martinfowler.com/bliki/PageObject.html#footnote-panel-object) in the early days, while first coining the term "panel objects".
203+
204+
The same principles used for page objects can be used to
205+
create "Page _Component_ Objects", as it was later called, that represent discrete chunks of the
206+
page and **can be included in page objects**. These component objects can
205207
provide references to the elements inside those discrete chunks, and
206-
methods to leverage the functionality provided by them.
208+
methods to leverage the functionality or behavior provided by them.
207209

208-
For example, a Product page has multiple products.
210+
For example, a Products page has multiple products.
209211

210212
```html
211213
<!-- Products Page -->
@@ -243,7 +245,7 @@ Each product is a component of the Products page.
243245
</div>
244246
```
245247

246-
The Product page HAS-A list of products. This relationship is called Composition. In simpler terms, something is _composed of_ another thing.
248+
The Products page HAS-A list of products. This object relationship is called Composition. In simpler terms, something is _composed of_ another thing.
247249

248250
```java
249251
public abstract class BasePage {
@@ -326,7 +328,7 @@ So now, the products test would use the page object and the page component objec
326328
public class ProductsTest {
327329
@Test
328330
public void testProductInventory() {
329-
var productsPage = new ProductsPage(driver);
331+
var productsPage = new ProductsPage(driver); // page object
330332
var products = productsPage.getProducts();
331333
assertEquals(6, products.size()); // expected, actual
332334
}
@@ -337,7 +339,7 @@ public class ProductsTest {
337339

338340
// Pass a lambda expression (predicate) to filter the list of products
339341
// The predicate or "strategy" is the behavior passed as parameter
340-
var backpack = productsPage.getProduct(p -> p.getName().equals("Backpack"));
342+
var backpack = productsPage.getProduct(p -> p.getName().equals("Backpack")); // page component object
341343
var bikeLight = productsPage.getProduct(p -> p.getName().equals("Bike Light"));
342344

343345
assertEquals(new BigDecimal("29.99"), backpack.getPrice());
@@ -355,8 +357,7 @@ components used throughout the site (e.g. a navigation bar), then it
355357
may improve maintainability and reduce code duplication.
356358

357359
## Other Design Patterns Used in Testing
358-
There are other design patterns that also may be used in testing. Some use a
359-
Page Factory for instantiating their page objects. Discussing all of these is
360+
There are other design patterns that also may be used in testing. Discussing all of these is
360361
beyond the scope of this user guide. Here, we merely want to introduce the
361362
concepts to make the reader aware of some of the things that can be done. As
362363
was mentioned earlier, many have blogged on this topic and we encourage the
@@ -367,11 +368,11 @@ reader to search for blogs on these topics.
367368

368369
PageObjects can be thought of as facing in two directions simultaneously. Facing toward the developer of a test, they represent the **services** offered by a particular page. Facing away from the developer, they should be the only thing that has a deep knowledge of the structure of the HTML of a page (or part of a page) It's simplest to think of the methods on a Page Object as offering the "services" that a page offers rather than exposing the details and mechanics of the page. As an example, think of the inbox of any web-based email system. Amongst the services it offers are the ability to compose a new email, choose to read a single email, and list the subject lines of the emails in the inbox. How these are implemented shouldn't matter to the test.
369370

370-
Because we're encouraging the developer of a test to try and think about the services they're interacting with rather than the implementation, PageObjects should seldom expose the underlying WebDriver instance. To facilitate this, methods on the PageObject should return other PageObjects. This means we can effectively model the user's journey through our application. It also means that should the way that pages relate to one another change (like when the login page asks the user to change their password the first time they log into a service when it previously didn't do that), simply changing the appropriate method's signature will cause the tests to fail to compile. Put another way; we can tell which tests would fail without needing to run them when we change the relationship between pages and reflect this in the PageObjects.
371+
Because we're encouraging the developer of a test to try and think about the services they're interacting with rather than the implementation, PageObjects should seldom expose the underlying WebDriver instance. To facilitate this, **methods on the PageObject should return other PageObjects**. This means we can effectively model the user's journey through our application. It also means that should the way that pages relate to one another change (like when the login page asks the user to change their password the first time they log into a service when it previously didn't do that), simply changing the appropriate method's signature will cause the tests to fail to compile. Put another way; we can tell which tests would fail without needing to run them when we change the relationship between pages and reflect this in the PageObjects.
371372

372373
One consequence of this approach is that it may be necessary to model (for example) both a successful and unsuccessful login; or a click could have a different result depending on the app's state. When this happens, it is common to have multiple methods on the PageObject:
373374

374-
```
375+
```java
375376
public class LoginPage {
376377
public HomePage loginAs(String username, String password) {
377378
// ... clever magic happens here
@@ -389,7 +390,7 @@ public class LoginPage {
389390

390391
The code presented above shows an important point: the tests, not the PageObjects, should be responsible for making assertions about the state of a page. For example:
391392

392-
```
393+
```java
393394
public void testMessagesAreReadOrUnread() {
394395
Inbox inbox = new Inbox(driver);
395396
inbox.assertMessageWithSubjectIsUnread("I like cheese");
@@ -399,7 +400,7 @@ public void testMessagesAreReadOrUnread() {
399400

400401
could be re-written as:
401402

402-
```
403+
```java
403404
public void testMessagesAreReadOrUnread() {
404405
Inbox inbox = new Inbox(driver);
405406
assertTrue(inbox.isMessageWithSubjectIsUnread("I like cheese"));
@@ -422,7 +423,7 @@ Finally, a PageObject need not represent an entire page. It may represent a sect
422423

423424
## Example
424425

425-
```
426+
```java
426427
public class LoginPage {
427428
private final WebDriver driver;
428429

@@ -491,10 +492,4 @@ public class LoginPage {
491492
return submitLogin();
492493
}
493494
}
494-
495-
```
496-
497-
498-
## Support in WebDriver
499-
500-
There is a PageFactory in the support package that provides support for this pattern and helps to remove some boiler-plate code from your Page Objects at the same time.
495+
```

0 commit comments

Comments
 (0)