Using naming conventions to improve the readability and maintenability of your Playwright Testing framework
How we decided to try naming conventions in our Playwright testing framework
While building out our new Playwright test automation framework, we are aiming to:
- Have as much as possible be reusable
- Have code that is easy to read, follow and debug
- Have a low barrier to entry, meaning test structure can be easily picked up by new starters
- Be able to review PRs quickly and effectively
As we grew our automated testing suite using the Page Object Model, we encountered a few issues:
- It got difficult to find whether an element you need is already in another page object
- PRs were getting more complex to review, you’d need to follow through and decipher the elements, functions, setup etc.
- Occasionally we’d repeat elements that already exist in the code, as said above they were hard to find
- Barrier to entry for the framework seemed high, as each POM would follow its own way of naming locators, functions etc.
Having naming conventions could help with all of the above.
Benefits of having naming conventions
*Improves reusability - functions/ locators / shared steps / other test code can be easily reused. It is straightforward for someone working on a test to find the functions and elements they need. Leading to less duplication and the need to rework once a code review has started
*Eases reviews - code can be reviewed quicker. It reduces the mental load of reviewing code as you can easily figure out what the test code is doing
*Quicker onboarding - naming conventions help new starters get onboarded quickly and feel comfortable contributing to the codebase
Our Playwright framework naming conventions
Variables
Declare in camelCase
Booleans
Start name with ‘is’, ‘has’, ‘are’, ‘have’. This helps spot that this is a boolean while skimming the code. Still declared in camelCase
let isTurnedOn = false
Page Objects / Classes
Declare in PascalCase
Use descriptive naming, which can help the reader quickly identify what page or page component this is covering. Use as much context as needed from your product to make the name meaningful.
export class AddPropertyModal
Locators
Use descriptive naming, which can help the reader quickly identify what element the locator is targetting.
Use a naming structure that contains “action / name of element” + “type of element”.
Defining type of element: These are your basic element types, they’ll be likely defined and named in the design system. Example: checkbox, tickbox, button, tooltip
Defining action / name: Think about what action this element will perform when interacted with. Or any existing name/text of the element
//This element is a save button which sits within the context of properties
readonly savePropertyButton: Locator;
Function names
Always start function names with a “verb”, followed by the “component context” that the function is interacting with
getWorksOrder()
printTransactions()
deleteProperty()
Arrange, Act, Assert
While here we are talking motly about naming convention, it is also worth noting a simple structure that all tests can follow. Because that too can help with readability and maintenability. Follow the AAA (Arrange, Act, Assert) pattern when structuring the tests. Including comments defining each section to ease readability
// arrange, create a let property
await createProperty()
// act, raise a charge
await raiseCharge()
// assert, confirm charge has been raised
expect(charge).ToBe('raised')