The page object model (POM) keeps the details of each page in one class and the test logic in another. When a developer changes the login button's ID, you update one line in one class instead of every test that logs in.
A login page object in Python, described line by line:
- A class LoginPage takes the driver when it is created.
- It stores its locators as class constants, such as USERNAME = (By.ID, "username"), PASSWORD = (By.ID, "password") and SUBMIT = (By.CSS_SELECTOR, "button[type='submit']").
- A method login(user, password) types into both fields and clicks submit.
- A method error_text() returns the text of the error message, waiting explicitly for it to appear.
The test then reads like a sentence: create LoginPage, call login with a wrong password, assert that error_text() contains "Invalid". It contains no locators at all.
Two rules that make page objects work: page objects return information or other page objects, but they do not contain assertions; and the tests contain assertions but no locators. Mixing the two is the most common reason a POM framework ends up as hard to maintain as the scripts it replaced.
In Java the same structure is used, often with the PageFactory and @FindBy annotations to declare the elements.