I enjoy reading, specially now when temperatures are in the mid-80s. It's so nice to relax by the pool with a good book. When a book is well-written, it's easy to read, and I can spend hours turning those pages, letting my imagination create scenes and characters... The same applies to code actually. When the code is well-written, I easily understand what a test/check does by reading it, just like with a book. I try my best to write readable code: from meaningful variable names to adding spaces between lines when it logically makes sense ("spaghetti code" is something I just can't look at).
Playwright makes it easy to write readable expectations. Here are some examples:
Here is a link to the generic value assertions.
But what should you do if you expect a string and you don't really care about the value but want to check the type? Unfortunately, there is nothing out of the box, so I end up writing it this way:
// how I used to check strings let framework = "playwright" expect(typeof framework).toBe("string");
I am not saying it's not readable, but I would rather see the code written like this:
// how I check strings now let framework = "playwright" expect(framework).toBeString();
If you read the code comments in the block above (another way to make the code readable), you may have already guessed that it's possible to write your own expects. You came to this page to expand your knowledge, and now we are going to extend your expects!
To make the
toBeString() check work, you need to add the following to your
Explanation: we extend our expect by adding the
toBeString() matcher. Even though it seems like the matcher takes a parameter, it actually doesn't.
received is the value that goes in the first parenthesis of
expect(value). Then we check if the received value is
typeof the string, and if it is, the check passes. If it's not, we fail the check and have an excellent opportunity to make our code more readable by adding a custom message.
Let's see how it works.
value is obviously not a string in this example I expect it to fail. And indeed, it fails with the custom message we added.
I have also added
.toBeBoolean()to my toolkit.
A few weeks ago, I wrote
.toBeOneOfValues(), and it's been a game changer. I use it when I can't predict the exact value, but I know it should be one of the known ones. I mostly use it for writing API checks for GET requests. For example, when I have a charge parameter returned and it can be "pending", "failed" or "successful", and I just want to check that every single charge returned has a value that is one of the expected ones.
Again, it's going to fail with the custom message I prepared.
Here is the source code that needs to be added to
The most important takeaway here is to realize that you can come up with custom matchers that your automation repository might need to improve readability. What helps me is looking at the value I am checking and saying in my head "I want this value to...." and then completing the sentence in English. There you have your pseudocode.
This article was written based on this documentation. If you are using TypeScript, there is an additional step required for custom matchers to work, which involves adding a
global.d.ts file. Here's how mine looks for the two expects mentioned above.
I hope you find this useful, and if you did, please ❤️ and subscribe below to receive more useful tips. If you want to reach out to me personally, feel free to connect or message on LinkedIn.