Thank you for your videos. You are the best explainer on RUclips. The approach you explained in this video definitely helped me in my work. The only thing I am wondering about is: does class inheritance work the same way as import?
Thank you for the support! - No they are different, however your usually going to import to use class inheritance. Inheritance allows you to reuse the functionality of an existing class without rewriting it. The child class can extend the functionality of the parent class by adding new methods or overriding existing ones. To use class inheritance you would use the extends keyword. Imports in TS are used to bring in functionality from external modules or files into the current file. They allow you to access variables, functions, classes, or other constructs defined in other files or modules.
Is there any particular reason you don't import the Locator and then and under the class do addComputerButton: Locator; and then under constructor do this.addComputerButton = this.page.getByText("Add a new computer"); ? I have seen both used and am not sure which instance one would be preferred over the other.
Do you know if it's possible to use page object models with Playwright's codegen feature? We find codegen to be great for writing tests quickly, but it can result in some ugly code. It would be great if you could record tests and have it use the page object model you define.
is not dangerous use the methods of playwright indeed your own methods? What happend if tomorrow playwright change the name of "page.locator()" ? it's a question because selenium for example when we use selenium's methods we create a BasePage to contain all the methods( what we usually use) like a wrapper class to prevent errors in the future to new release of selenium for example. Are those good practices?
Hi Jarad, I really like your tutorials about playwright can u plan in future to add video about cookies and local storage with playwright, how to setup and use them with login process ? Thank you.
A great series - its been very easy to get my project off the ground. I am struggling with something though. I have two (some times 3) systems that I need to open in tabs and jump between them. There is allot of code out there showing this - but I am missing how to achieve this using page / fixtures pattern you have here. Any advice greatly appreciated!
Thank you! Funnily enough I have a multi tabbing video going live today. If that doesn't answer your questions, let me know and I can do a follow up video
Amazing explanation of the POM. Could you please explain on how to implement before and after hooks in this approach? Example : having a common file with hooks to extend in the test cases maybe?
This Hooks video may help: ruclips.net/video/LZ88M0j65ls/видео.html Typically you would scope your hooks into the same class as the tests, however if you want to encapsulate your hooks, the best bet is to turn them into fixtures (heres a video for that example, explaining the benefits of using fixtures over hooks): ruclips.net/video/1wd5fJVD5jE/видео.html
This is a great question. I am a big fan of BDD, if done correctly in a company. I really see the benefits of using tools like cucumber to aid BDD, however many times I have seen BDD tools being used, but no real BDD process being implemented properly, which ends up leading to an overhead of maintaining gherkin (feature files) that no one reads. I have set up frameworks with cucumber and playwright and the main issue I found was I much prefer playwright test as the test runner, everything you get out of the box and the configuration was so much more beneficial to me than using the cucumber runner, I do plan on videos in the future with cucumber and playwright, however personally I now try to stick to using playwright test and only implement bdd tools if a client / project really want to work using BDD as a process
Hi! In the video when importing the class you say "these could all be stored in index files as well so you don't have to import them each time like this". Could you please explain that a bit more or let me know if that happens to be on another video?
I dont currently have a video on this, however this will definitely be something I can cover when I create a typescript tutorial series. It will apply to any test tool used
and there is any sense to create private fields in pages class and set locators in constructor? Besides constructor in the class there are only page object, locator private fields and actions methods.
Good question, For my large projects I order everything by Pages and sections - So inside the Page Object Model folder I have a Pages folder and a Sections folder. I order my sections based on logical grouping on the page (This will change depending on what website you work on). Another way is by working by pages, but instead of having sections, you could have a components folder and any pages that make use of a given component import that into their page. Its the same steps as what we went through in this video, but a different way to organise your POM
Im curious, is there an advantage/disadvantage to making the selectors/locators functions vs initializing them in the construct via this. and calling them in other functions?
The reason is stick to creating them as methods is for consistency. There are times I will pass through a parameter and build the locators using the params. I use this a lot in my projects so I keep it consistent.
@@CommitQuality That makes sense, thanks. I feel like you see most PoM examples initialize them in the constructor. I guess that reduces maybe the class length but I can see where it limits potential functionality. Sidenote: Do you have any example repo's of larger PoM setups for playwright?
@@CommitQuality In addition, I would say page objects enable proper reusability of your functions and keeps all the little waits, checks, loops, extra logging and other shenanigans that you may need in your non-responsive real-user-real-hardware scenarios out of the test spec ;-)
Good question. I personally believe that it depends on what you are doing and how you name your methods. There are definitely cases where you shouldn't have assertions inside your POM classes, the main reason is if it makes your tests harder to understand. Additionally, If you have a method called ClickButtonX, and that has an assertion inside it, I would be concerned that it's not visible to the reader that some expect is being performed. On the other hand, if you name methods correctly explaining what's happening and have an assertion that you are repeating multiple times, having that inside a method could keep your code cleaner, maybe you want to parameterise values to assert to check the count of validation messages etc.. of course, this is all subjective and it's always useful to have things like this discussed within your teams and have coding standards for these.
Thank you so much for the video! I wonder how to validate page's URL after click on "Create this computer". I know it's possible in PlayWright by ".toHaveURL", but the question is - how to validate URL with POM? Is there any locator for page's URL? Is it even possible in POM?
Hi, great tutorials. Will you be doing any API specific tutorials in the future, how you handle intercepting requests / mocking API calls in your tests?
Hello.. Great tutorial. Thank you I have one question about creating objects of page classes in our tests. Is there a way that we can avoid creating objects of page classes every time we write a test? We can directly access the page class location & methods by using page class name ?
Let's learn POM. It's simpel they say. Im only even more confused now. All I learned from this video is that you can have 1 simple file with 8 lines of code that almost evry1 can understand. But with POM u can do the same with 6 lines, 2 maps, 4 other files with in each file 20-30 lines of code. Yah made the code "better" 🎉 And yaya blah blah its for bigger files and this and that. No thnx 😒
sorry but ur setting a bad example for working with elements. Wrapping everything into a function is not good. Especially a single action functions like .click() you will end up with a function for every possible action for an element. (click, double click, hover etc)
Yeah maybe not single actions, if I said that then that would be a maintenance nightmare, but other commands grouped together e.g. adding a computer should be wrapped because it's likely you will use it more than once in a real e2e example. Of course it depends on your scenarios.
Interesting point, but I don't think I agree Roman. For me there should be separate function for every user behaviour. If there is a particular behaviour your application your application implements on double click or hover, you want those to be separate function calls. For example, if single click adds a computer, but displays a tooltip of on hover, I would expect to write ` await computersPage.clickCreateNewComputer() await computersPage.assertComputerAdded() ... await computersPage.hoverCreateNewComputer() await comptuerPage.assertTooltipShown() ` That said, I am sure there might be a better way, could you provide an example of what you mean?
Great content, Thank you!! I'm totally new to typescript. So could you please explain why we define locators as an arrow function and not as a variable? `myLocator = () => this.page.locator("#id");` // calling -> this.myLocator().fill("Hello"); vs `myLocator = this.page.locator("#id");` //calling -> this.myLocator.fill("Hello");
You can use variables and that will be completely fine too. I like to keep consistent and not change my approach so I ensure I declare the property as a function as it gives us more flexibility. There are many cases I will want to pass parameters through to my locators and make them reusable that way
Great tutorial expecting for a full framework video with fixtures and other configurations
Thank you for your videos. You are the best explainer on RUclips. The approach you explained in this video definitely helped me in my work. The only thing I am wondering about is: does class inheritance work the same way as import?
Thank you for the support! - No they are different, however your usually going to import to use class inheritance.
Inheritance allows you to reuse the functionality of an existing class without rewriting it. The child class can extend the functionality of the parent class by adding new methods or overriding existing ones. To use class inheritance you would use the extends keyword.
Imports in TS are used to bring in functionality from external modules or files into the current file. They allow you to access variables, functions, classes, or other constructs defined in other files or modules.
That sections idea sounds good
Is there any particular reason you don't import the Locator and then and under the class do addComputerButton: Locator; and then under constructor do this.addComputerButton = this.page.getByText("Add a new computer"); ? I have seen both used and am not sure which instance one would be preferred over the other.
Great video! Thank you so much!
Do you know if it's possible to use page object models with Playwright's codegen feature? We find codegen to be great for writing tests quickly, but it can result in some ugly code. It would be great if you could record tests and have it use the page object model you define.
is not dangerous use the methods of playwright indeed your own methods? What happend if tomorrow playwright change the name of "page.locator()" ? it's a question because selenium for example when we use selenium's methods we create a BasePage to contain all the methods( what we usually use) like a wrapper class to prevent errors in the future to new release of selenium for example. Are those good practices?
Hi Jarad, I really like your tutorials about playwright can u plan in future to add video about cookies and local storage with playwright, how to setup and use them with login process ?
Thank you.
Thank you very much! Yes of course no problem. I will add it to the list and get one created :)
many thanks to your tutorials!
A great series - its been very easy to get my project off the ground. I am struggling with something though. I have two (some times 3) systems that I need to open in tabs and jump between them. There is allot of code out there showing this - but I am missing how to achieve this using page / fixtures pattern you have here.
Any advice greatly appreciated!
Thank you! Funnily enough I have a multi tabbing video going live today. If that doesn't answer your questions, let me know and I can do a follow up video
@@CommitQuality - utterly serendipitous! I will be keeping an eye out for it.
Amazing explanation of the POM.
Could you please explain on how to implement before and after hooks in this approach? Example : having a common file with hooks to extend in the test cases maybe?
This Hooks video may help:
ruclips.net/video/LZ88M0j65ls/видео.html
Typically you would scope your hooks into the same class as the tests, however if you want to encapsulate your hooks, the best bet is to turn them into fixtures (heres a video for that example, explaining the benefits of using fixtures over hooks):
ruclips.net/video/1wd5fJVD5jE/видео.html
how to find multiple elements using python? which locator or selector should i need?
Use all to get them all playwright.dev/python/docs/api/class-locator#locator-all
Can you share the code to take look on github or something?
I have just created a new repo with the code for you - github.com/CommitQuality/Playwright-PageObjectModel-Example
What are your thoughts of gherkin cucumber and playwright please? Are there any issues which i need to look out for please?
This is a great question. I am a big fan of BDD, if done correctly in a company. I really see the benefits of using tools like cucumber to aid BDD, however many times I have seen BDD tools being used, but no real BDD process being implemented properly, which ends up leading to an overhead of maintaining gherkin (feature files) that no one reads.
I have set up frameworks with cucumber and playwright and the main issue I found was I much prefer playwright test as the test runner, everything you get out of the box and the configuration was so much more beneficial to me than using the cucumber runner, I do plan on videos in the future with cucumber and playwright, however personally I now try to stick to using playwright test and only implement bdd tools if a client / project really want to work using BDD as a process
Hi! In the video when importing the class you say "these could all be stored in index files as well so you don't have to import them each time like this". Could you please explain that a bit more or let me know if that happens to be on another video?
I dont currently have a video on this, however this will definitely be something I can cover when I create a typescript tutorial series. It will apply to any test tool used
@@CommitQuality great, thanks!
Hello! I have a question. There is the way to implement POM nad Singleton in the same project? Is it worth or not and why?
and there is any sense to create private fields in pages class and set locators in constructor? Besides constructor in the class there are only page object, locator private fields and actions methods.
Thank you. How would you recommend to split the huge Page Object ?
Good question, For my large projects I order everything by Pages and sections - So inside the Page Object Model folder I have a Pages folder and a Sections folder. I order my sections based on logical grouping on the page (This will change depending on what website you work on). Another way is by working by pages, but instead of having sections, you could have a components folder and any pages that make use of a given component import that into their page. Its the same steps as what we went through in this video, but a different way to organise your POM
Very similar syntax to test cafe. Looking to learn playwright and doesn’t seem to difficult if I already know testcafe
Yeah it's a great framework. It was built by the team who created puppeteer, a lot has been taken from that too.
Im curious, is there an advantage/disadvantage to making the selectors/locators functions vs initializing them in the construct via this. and calling them in other functions?
The reason is stick to creating them as methods is for consistency. There are times I will pass through a parameter and build the locators using the params. I use this a lot in my projects so I keep it consistent.
@@CommitQuality That makes sense, thanks. I feel like you see most PoM examples initialize them in the constructor. I guess that reduces maybe the class length but I can see where it limits potential functionality. Sidenote: Do you have any example repo's of larger PoM setups for playwright?
@@CommitQuality In addition, I would say page objects enable proper reusability of your functions and keeps all the little waits, checks, loops, extra logging and other shenanigans that you may need in your non-responsive real-user-real-hardware scenarios out of the test spec ;-)
hey) great tutorials! maybe you know, how to avoid of RangeError: Maximum call stack size exceeded when running playwright test?
Great explanation! But I have a question. Using expect() inside the class isn’t bad practice?
Good question. I personally believe that it depends on what you are doing and how you name your methods. There are definitely cases where you shouldn't have assertions inside your POM classes, the main reason is if it makes your tests harder to understand. Additionally, If you have a method called ClickButtonX, and that has an assertion inside it, I would be concerned that it's not visible to the reader that some expect is being performed. On the other hand, if you name methods correctly explaining what's happening and have an assertion that you are repeating multiple times, having that inside a method could keep your code cleaner, maybe you want to parameterise values to assert to check the count of validation messages etc.. of course, this is all subjective and it's always useful to have things like this discussed within your teams and have coding standards for these.
Thank you so much for the video!
I wonder how to validate page's URL after click on "Create this computer". I know it's possible in PlayWright by ".toHaveURL", but the question is - how to validate URL with POM? Is there any locator for page's URL? Is it even possible in POM?
You would likely just want to create a method that does an assertion and then you could call that method that lives inside your Page object file
@@CommitQualitythank you so much!
Hi, great tutorials. Will you be doing any API specific tutorials in the future, how you handle intercepting requests / mocking API calls in your tests?
Thank you! Yes they are definitely on my list of future videos. They will be coming :)
Thank you. Can you upload video about Page Object Model with Fixture?
Yes, certainly. It's the next video to be uploaded I just need to edit and upload it (should be within the next few days)
Hello.. Great tutorial. Thank you
I have one question about creating objects of page classes in our tests. Is there a way that we can avoid creating objects of page classes every time we write a test?
We can directly access the page class location & methods by using page class name ?
Thank you! Yes, you could do that via creating fixtures for each page. ruclips.net/video/AvmK35LQrb0/видео.html this video should explain that for you
Good one
thanks
Let's learn POM. It's simpel they say.
Im only even more confused now.
All I learned from this video is that you can have 1 simple file with 8 lines of code that almost evry1 can understand.
But with POM u can do the same with 6 lines, 2 maps, 4 other files with in each file 20-30 lines of code.
Yah made the code "better" 🎉
And yaya blah blah its for bigger files and this and that.
No thnx 😒
sorry but ur setting a bad example for working with elements. Wrapping everything into a function is not good. Especially a single action functions like .click() you will end up with a function for every possible action for an element. (click, double click, hover etc)
Yeah maybe not single actions, if I said that then that would be a maintenance nightmare, but other commands grouped together e.g. adding a computer should be wrapped because it's likely you will use it more than once in a real e2e example. Of course it depends on your scenarios.
Interesting point, but I don't think I agree Roman. For me there should be separate function for every user behaviour. If there is a particular behaviour your application your application implements on double click or hover, you want those to be separate function calls. For example, if single click adds a computer, but displays a tooltip of on hover, I would expect to write
`
await computersPage.clickCreateNewComputer()
await computersPage.assertComputerAdded()
...
await computersPage.hoverCreateNewComputer()
await comptuerPage.assertTooltipShown()
`
That said, I am sure there might be a better way, could you provide an example of what you mean?
Great content, Thank you!!
I'm totally new to typescript. So could you please explain why we define locators as an arrow function and not as a variable?
`myLocator = () => this.page.locator("#id");` // calling -> this.myLocator().fill("Hello");
vs
`myLocator = this.page.locator("#id");` //calling -> this.myLocator.fill("Hello");
You can use variables and that will be completely fine too. I like to keep consistent and not change my approach so I ensure I declare the property as a function as it gives us more flexibility. There are many cases I will want to pass parameters through to my locators and make them reusable that way