<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Terence Pan</title>
    <description>The latest articles on Forem by Terence Pan (@terencepan).</description>
    <link>https://forem.com/terencepan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F935245%2Fbdaf5028-7d4c-4749-b5fb-5a67f5966074.jpg</url>
      <title>Forem: Terence Pan</title>
      <link>https://forem.com/terencepan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/terencepan"/>
    <language>en</language>
    <item>
      <title>Set up Cucumber reports with screenshots</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Tue, 05 Dec 2023 19:04:01 +0000</pubDate>
      <link>https://forem.com/terencepan/set-up-cucumber-reports-with-screenshots-4j9o</link>
      <guid>https://forem.com/terencepan/set-up-cucumber-reports-with-screenshots-4j9o</guid>
      <description>&lt;h3&gt;
  
  
  Maven setup Surefire plugin &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Below pom.xml configuration will generate a html and json report. The reports will have a screenshot when tests fail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-compiler-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.11.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-surefire-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${maven.surefire.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;configurationParameters&amp;gt;&lt;/span&gt;
                            cucumber.plugin=pretty,html:target/site/TestRun.html,json:target/site/TestRun.json
                            cucumber.publish.quiet=true
                            cucumber.publish.enabled=false
                        &lt;span class="nt"&gt;&amp;lt;/configurationParameters&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cucumber After method &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@After&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Scenario&lt;/span&gt; &lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isFailed&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt;
            &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;screenshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;screenshot&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ScreenshotOptions&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"screenshot.png"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
            &lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;attach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;screenshot&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"image/png"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scenario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;browserContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are checking if the scenario is failed and if so, it will attach a screenshot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intentionally create test failure &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;  &lt;span class="kn"&gt;Scenario Outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; User is able to request a Demo
    &lt;span class="nf"&gt;Given &lt;/span&gt;User navigates to PHPTRAVELS Demo Page
    &lt;span class="nf"&gt;When &lt;/span&gt;User fills in Demo Request Form &lt;span class="nv"&gt;&amp;lt;firstName&amp;gt;&lt;/span&gt;, &lt;span class="nv"&gt;&amp;lt;lastName&amp;gt;&lt;/span&gt;, &lt;span class="nv"&gt;&amp;lt;businessName&amp;gt;&lt;/span&gt;, &lt;span class="nv"&gt;&amp;lt;email&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;When &lt;/span&gt;User calculates and fills wrong result
    &lt;span class="nf"&gt;When &lt;/span&gt;User clicks submit
    &lt;span class="nf"&gt;Then &lt;/span&gt;Verify thank you text
    &lt;span class="nn"&gt;Examples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;firstName&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;businessName&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;email&lt;/span&gt;               &lt;span class="p"&gt;|&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"ABC"&lt;/span&gt;     &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"DEF"&lt;/span&gt;    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"Main&lt;/span&gt; &lt;span class="n"&gt;Inc."&lt;/span&gt;  &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"whatever@main.com"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here on the register.feature file, we intentionally filled out the wrong result causing the test to fail. &lt;/p&gt;

&lt;p&gt;run: mvn clean install&lt;/p&gt;

&lt;p&gt;check report path as noted in pom.xml: target/site/TestRun.html&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QrJmsb2N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/brhpyhadg1q3jmk9woxa.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QrJmsb2N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/brhpyhadg1q3jmk9woxa.JPG" alt="Image description" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As always code is on available on &lt;a href="https://github.com/terencenmnpan/TestAutomation/tree/main/PlaywrightCucumberExample"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploy Spring Boot App to Render</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Wed, 30 Aug 2023 18:25:36 +0000</pubDate>
      <link>https://forem.com/terencepan/deploy-spring-boot-app-to-render-3lm9</link>
      <guid>https://forem.com/terencepan/deploy-spring-boot-app-to-render-3lm9</guid>
      <description>&lt;h2&gt;
  
  
  Render.com
&lt;/h2&gt;

&lt;p&gt;Render is an alternative to Heroku with a free tier. We can deploy a Spring Boot app here with a Dockerfile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dockerfile contents
&lt;/h2&gt;

&lt;p&gt;(place at root of repo, change according to artifact name, version and jdk versions)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#
# Build stage
#
FROM maven:3.8.3-openjdk-17 AS build
COPY . .
RUN mvn clean install

#
# Package stage
#
FROM eclipse-temurin:17-jdk
COPY --from=build /target/demo-0.0.1-SNAPSHOT.jar demo.jar
# ENV PORT=8080
EXPOSE 8080
ENTRYPOINT ["java","-jar","demo.jar"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Render instructions
&lt;/h2&gt;

&lt;p&gt;New -&amp;gt; New Web Service -&amp;gt; Connect Github or Gitlab -&amp;gt; Pick Docker runtime -&amp;gt; Create Web Service&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aYBh6CEv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1v6pb3horyo50oo4kwl.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aYBh6CEv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1v6pb3horyo50oo4kwl.JPG" alt="Image description" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>docker</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Why use Spring Constructor Dependency Injection instead of @Autowired</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Tue, 04 Oct 2022 22:58:46 +0000</pubDate>
      <link>https://forem.com/terencepan/why-use-spring-constructor-dependency-injection-instead-of-autowired-51oh</link>
      <guid>https://forem.com/terencepan/why-use-spring-constructor-dependency-injection-instead-of-autowired-51oh</guid>
      <description>&lt;h2&gt;
  
  
  Autowired
&lt;/h2&gt;

&lt;p&gt;Most Spring developers I have seen are still using the @Autowired syntax for injecting dependencies into their classes. This is not recommended anymore and Intellij even gives you a warning when you try to use it.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhppw6h7v46emlx05iyfv.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhppw6h7v46emlx05iyfv.JPG" alt="Image description" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today we'll go over one reason why not to use dependency injection in this manner. I have also seen this cause a production incident as well before. Having @Autowired on the field allows the field to be potentially mutable and harder to test. Having the injected field be mutable can interfere with how Spring proxies these injected classes through the use of the CGLIB library.&lt;/p&gt;
&lt;h2&gt;
  
  
  Set up DTO
&lt;/h2&gt;

&lt;p&gt;In the test project we are setting up a DTO that is supposed to be Session Scoped to the user. So each user should only see the instance of the bean relating their session.&lt;/p&gt;

&lt;p&gt;UserDataDto.java class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.SessionScope;

@Component
@SessionScope
public class UserDataDto {
    private String userName;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set up Spring Security config
&lt;/h2&gt;

&lt;p&gt;We also have some Spring Security set up as well to initialize both user instances we are using for testing here.&lt;/p&gt;

&lt;p&gt;SecurityConfig.class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {
        UserDetails user1 = User.withUsername("user1")
                .password(passwordEncoder.encode("password"))
                .roles("ADMIN")
                .build();
        UserDetails user2 = User.withUsername("user2")
                .password(passwordEncoder.encode("password"))
                .roles("ADMIN")
                .build();
        return new InMemoryUserDetailsManager(user1, user2);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .httpBasic()
                .and()
                .authorizeRequests()
                .antMatchers("/**")
                .hasRole("ADMIN")
                .anyRequest()
                .authenticated();
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder()
    {
        return new BCryptPasswordEncoder();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set up Controller class
&lt;/h2&gt;

&lt;p&gt;And finally here's the controller class.&lt;br&gt;
UserController.class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController("/")
public class UserController {
    @Autowired
    UserDataDto userDataDto;

    @PostMapping("/saveUserName")
    public void saveUserName(@RequestBody String userName){
        userDataDto.setUserName(userName);
    }

    @PostMapping("/saveUserNameReplaceInstance")
    public void saveUserNameReplaceInstance(@RequestBody String userName){
        UserDataDto userDataDto = new UserDataDto();
        userDataDto.setUserName(userName);
        this.userDataDto = userDataDto;
    }

    @GetMapping("/getUserName")
    public String getUserName(){
        return userDataDto.getUserName();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test intended effect
&lt;/h2&gt;

&lt;p&gt;Ok now let's run the Spring Boot application and get started with testing!&lt;br&gt;
I will use Postman to POST to the /saveUserName endpoint with the user1&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmd3u9vu5ujbl9c7391d.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmd3u9vu5ujbl9c7391d.JPG" alt="Image description" width="800" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fenv14l9z8rr226s9ipq7.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fenv14l9z8rr226s9ipq7.JPG" alt="Image description" width="800" height="344"&gt;&lt;/a&gt;&lt;br&gt;
And now to use a separate Chrome incognito window to try to GET from the /getUserName endpoint with the user2. Nothing shows, good!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4qlsx89749yqdgr4yvw.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4qlsx89749yqdgr4yvw.JPG" alt="Image description" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnp4d9gojm2br39r2i5u4.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnp4d9gojm2br39r2i5u4.JPG" alt="Image description" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Overwrite Session Scope bean into Singleton
&lt;/h2&gt;

&lt;p&gt;Now lets intentionally cause a problem with a new endpoint /saveUserNameReplaceInstance that will replace the Autowired bean.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @PostMapping("/saveUserNameReplaceInstance")
    public void saveUserNameReplaceInstance(@RequestBody String userName){
        UserDataDto userDataDto = new UserDataDto();
        userDataDto.setUserName(userName);
        this.userDataDto = userDataDto;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time we will send the same thing through Postman using the new endpoint with user1&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1b3chp2jdewprhalxs49.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1b3chp2jdewprhalxs49.JPG" alt="Image description" width="800" height="356"&gt;&lt;/a&gt;&lt;br&gt;
And in Chrome with user2 I now see user1's data!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvjvxs2tzz5xpc4xs13z.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvjvxs2tzz5xpc4xs13z.JPG" alt="Image description" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh NO!! Big problems here, we essentially turned a SessionScope bean into a singleton that is shared between all instances!&lt;/p&gt;
&lt;h2&gt;
  
  
  Constructor Injection
&lt;/h2&gt;

&lt;p&gt;Now how does constructor injection prevent this? Intellij will refactor Autowired code for you automagically if you click on the @Autowired annotation, hit Alt-Enter on windows and click Create constructor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5i9bd8888y2sqaj6aulv.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5i9bd8888y2sqaj6aulv.JPG" alt="Image description" width="515" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But for convenience I did this in another class.&lt;br&gt;
ConstructorInjectionController.java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
public class ConstructorInjectionController {
    final
    UserDataDto userDataDto;

    public ConstructorInjectionController(UserDataDto userDataDto) {
        this.userDataDto = userDataDto;
    }

    @PostMapping("/saveUserNameCi")
    public void saveUserName(@RequestBody String userName){
        userDataDto.setUserName(userName);
    }

    @PostMapping("/saveUserNameReplaceInstanceCi")
    public void saveUserNameReplaceInstance(@RequestBody String userName){
        UserDataDto userDataDto = new UserDataDto();
        userDataDto.setUserName(userName);
        //this.userDataDto = userDataDto;
    }

    @GetMapping("/getUserNameCi")
    public String getUserName(){
        return userDataDto.getUserName();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;try to uncomment the line with the mapping saveUserNameReplaceInstanceCi and the IDE will prevent you from causing a huge mistake. This allows you to declare the injected field as final and immutable after instantiation of the controller class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0l57he9xaok6qur36d48.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0l57he9xaok6qur36d48.JPG" alt="Image description" width="717" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As always code is on &lt;a href="https://github.com/terencenmnpan/SpringConstructorInjection" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>saas</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Playwright with Cucumber/JUnit 5 - JUnit 5 test suite and maven clean install</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Mon, 03 Oct 2022 16:00:02 +0000</pubDate>
      <link>https://forem.com/terencepan/playwright-with-cucumberjunit-5-junit-5-test-suite-and-maven-clean-install-26bn</link>
      <guid>https://forem.com/terencepan/playwright-with-cucumberjunit-5-junit-5-test-suite-and-maven-clean-install-26bn</guid>
      <description>&lt;h2&gt;
  
  
  JUnit 5 Test Suite
&lt;/h2&gt;

&lt;p&gt;In previous JUnit versions there was the TestRunner classes to run tests. &lt;/p&gt;

&lt;p&gt;In JUnit5, this is now done through Test Suites. If you followed the other posts in the series and now tried to run the maven command: mvn clean install and find out tests aren't run at all, this might be why. Maven install with the Surefire plug in will look for test classes matching the patterns:&lt;br&gt;
-"&lt;strong&gt;/Test*.java" - includes all of its subdirectories and all Java filenames that start with "Test".&lt;br&gt;
-"&lt;/strong&gt;/&lt;em&gt;Test.java" - includes all of its subdirectories and all Java filenames that end with "Test".&lt;br&gt;
-"&lt;/em&gt;&lt;em&gt;/*Tests.java" - includes all of its subdirectories and all Java filenames that end with "Tests".&lt;br&gt;
-"&lt;/em&gt;*/*TestCase.java" - includes all of its subdirectories and all Java filenames that end with "TestCase".&lt;/p&gt;

&lt;p&gt;To include support for JUnit5 Test suites, pom.xml would need the junit-platform-suite dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit.platform&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit-platform-suite&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to support other class names that have to be matched aside from the above, just include them in the Surefire configuration in your pom.xml such as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;includes&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;include&amp;gt;&lt;/span&gt;example.java&lt;span class="nt"&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;include&amp;gt;&lt;/span&gt;**/*IT.java&lt;span class="nt"&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;include&amp;gt;&lt;/span&gt;**/*EndToEnd.java&lt;span class="nt"&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/includes&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my example I will be creating a test suite named DemoRequestTests. All we have to do is include annotations here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/suite"&gt;@suite&lt;/a&gt;: JUnit5 test suite class&lt;/li&gt;
&lt;li&gt;@SuiteDisplayName("Test Use Cases"): name of the test suite is Test Use Cases&lt;/li&gt;
&lt;li&gt;@IncludeEngines("cucumber"): run this test suite using Cucumber&lt;/li&gt;
&lt;li&gt;@SelectClasspathResource("Features"): where the feature files are located, in this case under test/resources/Features&lt;/li&gt;
&lt;li&gt;@ConfigurationParameter: not used but if your steps are located in a directory that's not automatically picked up by the cucumber engine, then you will want to set the package path to your stepdefinition glue classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you can run mvn clean install and any test suites you created will run automatically&lt;/p&gt;

&lt;p&gt;Code for DemoRequestTests.java&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;io.tpan.suites&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.platform.suite.api.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cucumber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;junit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GLUE_PROPERTY_NAME&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Suite&lt;/span&gt;
&lt;span class="nd"&gt;@SuiteDisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test Use Cases"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@IncludeEngines&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cucumber"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@SelectClasspathResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Features"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;//@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "steps")&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoRequestTests&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As always code is on available on &lt;a href="https://github.com/terencenmnpan/TestAutomation/tree/main/PlaywrightCucumberExample"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>testing</category>
      <category>cucumber</category>
      <category>junit5</category>
    </item>
    <item>
      <title>Playwright with Cucumber/JUnit 5 - @BeforeAll @AfterAll @Before @After</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Mon, 03 Oct 2022 00:27:34 +0000</pubDate>
      <link>https://forem.com/terencepan/playwright-with-cucumberjunit-5-beforeall-afterall-before-after-14fb</link>
      <guid>https://forem.com/terencepan/playwright-with-cucumberjunit-5-beforeall-afterall-before-after-14fb</guid>
      <description>&lt;h3&gt;
  
  
  @BeforeAll @AfterAll @Before @After
&lt;/h3&gt;

&lt;p&gt;In the TestContext class we have a method annotated with @BeforeAll, this method will be called before any of the tests are run. These are things we want to do that are resource and time intensive and only want to do once. In this case we are initializing Playwright and the Browser classes on the computer to set up the framework and the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@BeforeAll&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;beforeAll&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;playwright&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Playwright&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;playwright&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chromium&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;launch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BrowserType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LaunchOptions&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// or firefox, webkit&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setHeadless&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSlowMo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Method marked as @AfterAll is called after all the tests are run, and in this case we would like to close the Browser and Playwright so that they do not continue to use up resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@AfterAll&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;playwright&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Method marked as @Before is called before every test. In this case we want to open a new browser context for each test. Browser Contexts provide a way to operate multiple independent browser sessions. A page is a session in a browser context and we are creating one for each test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;createContextAndPage&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;browserContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newContext&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browserContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newPage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Method marked as @After is called after every test. In this case we want to close the browser context after each test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@After&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;closeContext&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;browserContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As always code is on available on &lt;a href="https://github.com/terencenmnpan/TestAutomation/tree/main/PlaywrightCucumberExample"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>testing</category>
      <category>cucumber</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Playwright with Cucumber/JUnit 5 - Dependency Injection with PicoContainer</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Mon, 03 Oct 2022 00:25:35 +0000</pubDate>
      <link>https://forem.com/terencepan/playwright-with-cucumberjunit-5-dependency-injection-154l</link>
      <guid>https://forem.com/terencepan/playwright-with-cucumberjunit-5-dependency-injection-154l</guid>
      <description>&lt;h3&gt;
  
  
  Dependency Injection
&lt;/h3&gt;

&lt;p&gt;This project uses dependency injection to put the instance of TestContext into the step definition class. In a larger test project you would have multiple step definitions and you want an easy way to create common instances of things like the Playwright instance and BrowserContext. This also allows you to share data between steps in the same scenario like when we get and set the alert text.&lt;/p&gt;

&lt;p&gt;This is implemented by including the maven dependency for pico-container earlier in the series and injecting this class through the Constructor of the step classes needing this class.&lt;/p&gt;

&lt;p&gt;Constructor code in DemoSteps.java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DemoSteps&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TestContext&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;testContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBrowser&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code using dependency injection to store alert text between steps in the same scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User clicks submit"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;userClicksSubmit&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DemoPage&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DemoPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clickSubmit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAlertText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Verify alert {string}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;verifyAlertToFillInResultIsShown&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAlertText&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full &lt;strong&gt;TestContext.java&lt;/strong&gt; class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;io.tpan.steps&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.microsoft.playwright.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.cucumber.java.AfterAll&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.cucumber.java.BeforeAll&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestContext&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Playwright&lt;/span&gt; &lt;span class="n"&gt;playwright&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Browser&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;BrowserContext&lt;/span&gt; &lt;span class="n"&gt;browserContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@BeforeAll&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;beforeAll&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;playwright&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Playwright&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;playwright&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chromium&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;launch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BrowserType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LaunchOptions&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// or firefox, webkit&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setHeadless&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSlowMo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@AfterAll&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;playwright&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Browser&lt;/span&gt; &lt;span class="nf"&gt;getBrowser&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getAlertText&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setAlertText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;alertText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As always code is on available on &lt;a href="https://github.com/terencenmnpan/TestAutomation/tree/main/PlaywrightCucumberExample"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cucumber</category>
      <category>java</category>
      <category>testing</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Playwright with Cucumber/JUnit 5 - Page Object</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Mon, 03 Oct 2022 00:14:08 +0000</pubDate>
      <link>https://forem.com/terencepan/playwright-with-cucumberjunit-5-page-object-86m</link>
      <guid>https://forem.com/terencepan/playwright-with-cucumberjunit-5-page-object-86m</guid>
      <description>&lt;h3&gt;
  
  
  Page Object &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In Page Object Model for UI testing, you organize pages into their own classes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page&lt;/strong&gt; field here represents the browser session we will use to grab page elements with. We also will pass page from the step to the page object when we initialize it through the Constructor.&lt;/p&gt;

&lt;p&gt;The page elements are defined as fields and the constructor initializes those fields. &lt;br&gt;
The below block represents the input for the first name field. Note there is not an id, but we can use the name attribute to find it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"first_name"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"first_name input mb1"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"First Name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the constructor we can use the name attribute of the element to locate it. If id is not available, then try to use other easy attributes to locate, otherwise you may have to resort to xpath.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[name='first_name']"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also have methods that the step definitions can call to perform actions through Playwright. The method below will navigate to the page the page object represents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;navigate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://phptravels.com/demo"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
java&lt;br&gt;
The fillRegistrationInfo method will fill in the first name, last name, business name and email fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void fillRegistrationInfo(String firstName, String lastName, String businessName, String email){
        this.firstName.fill(firstName);
        this.lastName.fill(lastName);
        this.businessName.fill(businessName);
        this.email.fill(email);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Complete &lt;strong&gt;DemoPage.java&lt;/strong&gt; class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;io.tpan.pages&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.microsoft.playwright.Locator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.microsoft.playwright.Page&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.tpan.steps.TestContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoPage&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;businessName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;numberOne&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;numberTwo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DemoPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[name='first_name']"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[name='last_name']"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;businessName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[name='business_name']"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[name='email']"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id=demo"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id=number"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;numberOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id=numb1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;numberTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id=numb2"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;navigate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://phptravels.com/demo"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fillRegistrationInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;businessName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;businessName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;businessName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fillResult&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numberOne&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;textContent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numberTwo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;textContent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;num2&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fillWrongResult&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numberOne&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;textContent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numberTwo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;textContent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;clickSubmit&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onDialog&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dialog&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dialog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;dialog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="n"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As always code is on available on &lt;a href="https://github.com/terencenmnpan/TestAutomation/tree/main/PlaywrightCucumberExample"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>playwright</category>
      <category>testing</category>
      <category>cucumber</category>
    </item>
    <item>
      <title>Playwright with Cucumber/JUnit 5 - Step Definition</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Sun, 02 Oct 2022 23:53:16 +0000</pubDate>
      <link>https://forem.com/terencepan/playwright-with-cucumberjunit-5-step-definition-ccc</link>
      <guid>https://forem.com/terencepan/playwright-with-cucumberjunit-5-step-definition-ccc</guid>
      <description>&lt;h3&gt;
  
  
  Step Definition &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The Step Definition file is where you create steps that map to the Gherkin steps in the feature file. In Java, I am using the annotation method for mapping the steps. There is also a Java 8 Lambda style syntax which I am not covering here. &lt;/p&gt;

&lt;p&gt;When &lt;strong&gt;Given&lt;/strong&gt; User navigates to PHPTRAVELS Demo Page is called, userNavigatesToPHPTRAVELSDemoPage method is called and the browser will navigate to the page to be tested.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Given&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User navigates to PHPTRAVELS Demo Page"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;userNavigatesToPHPTRAVELSDemoPage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DemoPage&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DemoPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;demoPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;navigate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the step &lt;strong&gt;When&lt;/strong&gt; User clicks submit is run, the method userClicksSubmit is called, which in this case clicks the submit button and stores the alert text for later verification if it pops up. This data state storing uses dependency injection which we will cover later in the series.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User clicks submit"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;userClicksSubmit&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DemoPage&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DemoPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clickSubmit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAlertText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is a &lt;strong&gt;Then&lt;/strong&gt; that can be called to verify the alert text if it shows up. We are using JUnit5 Assertions.assertEquals method to check to make sure alert text is as expected. The first argument is the expected String and the second argument is the actual displayed String.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Verify alert {string}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;verifyAlertToFillInResultIsShown&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAlertText&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full &lt;strong&gt;DemoSteps.java&lt;/strong&gt; code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;io.tpan.steps&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.microsoft.playwright.Browser&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.microsoft.playwright.BrowserContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.microsoft.playwright.Locator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.microsoft.playwright.Page&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.cucumber.java.After&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.cucumber.java.Before&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.cucumber.java.en.Given&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.cucumber.java.en.Then&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.cucumber.java.en.When&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.tpan.pages.DemoPage&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.Assertions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoSteps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TestContext&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Browser&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BrowserContext&lt;/span&gt; &lt;span class="n"&gt;browserContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DemoSteps&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TestContext&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;testContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBrowser&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;createContextAndPage&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;browserContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newContext&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browserContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newPage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@After&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;closeContext&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;browserContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Given&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User navigates to PHPTRAVELS Demo Page"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;userNavigatesToPHPTRAVELSDemoPage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DemoPage&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DemoPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;demoPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;navigate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User fills in Demo Request Form {string}, {string}, {string}, {string}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;userFillsInDemoRequestForm&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;businessName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DemoPage&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DemoPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;demoPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fillRegistrationInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;businessName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Verify thank you text"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;verifyThis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;thankYouText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text=' Thank you!'"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;thankYouText&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;waitFor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;completionText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text='We have sent your demo credentials to your email please check your email to test demo website. if message not found inbox please check spam folder'"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;completionText&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isVisible&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User calculates and fills result"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;userCalculatesAndFillsResult&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DemoPage&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DemoPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;demoPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fillResult&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User calculates and fills wrong result"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;userCalculatesAndFillsWrongResult&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DemoPage&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DemoPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;demoPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fillWrongResult&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User clicks submit"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;userClicksSubmit&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DemoPage&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DemoPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demoPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clickSubmit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAlertText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Verify alert {string}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;verifyAlertToFillInResultIsShown&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alertText&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;testContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAlertText&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As always code is on available on &lt;a href="https://github.com/terencenmnpan/TestAutomation/tree/main/PlaywrightCucumberExample"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>playwright</category>
      <category>cucumber</category>
      <category>testing</category>
    </item>
    <item>
      <title>Playwright with Cucumber/JUnit 5 - Feature File</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Sun, 02 Oct 2022 23:48:12 +0000</pubDate>
      <link>https://forem.com/terencepan/playwright-with-cucumberjunit-5-feature-file-3dmn</link>
      <guid>https://forem.com/terencepan/playwright-with-cucumberjunit-5-feature-file-3dmn</guid>
      <description>&lt;h3&gt;
  
  
  Feature File &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Cucumber steps are actions that a user can be imagined to take. Given is what actions are used to set up the test. When is what actions are taken to do the testing. Then is what result you want to see. For the 3rd example, we are intentionally filling out the form with the wrong result and expecting a certain error message to show up.&lt;/p&gt;

&lt;p&gt;Cucumber allows annotations to tag what grouping you want your tests to belong to. This allows easier searching when you generate your reports later on.&lt;/p&gt;

&lt;p&gt;Scenario outlines allow the same scenario to be run multiple times using the Examples section as a dataset.&lt;/p&gt;

&lt;p&gt;In the below example we are testing a happy path. The user starts off navigating to the page using the &lt;strong&gt;Given&lt;/strong&gt; step. The user then fills in the form with the When step. The site requires the user to make a calculation to prove they are not a robot so we calculate it, fill in the sum and hit submit. These are implemented with &lt;strong&gt;When&lt;/strong&gt; steps. The &lt;strong&gt;Then&lt;/strong&gt; step is to verify the submission was successful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kd"&gt;Feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Register for Demo Request
  @HappyPath
  &lt;span class="kn"&gt;Scenario Outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; User is able to request a Demo
    &lt;span class="nf"&gt;Given &lt;/span&gt;User navigates to PHPTRAVELS Demo Page
    &lt;span class="nf"&gt;When &lt;/span&gt;User fills in Demo Request Form &lt;span class="nv"&gt;&amp;lt;firstName&amp;gt;&lt;/span&gt;, &lt;span class="nv"&gt;&amp;lt;lastName&amp;gt;&lt;/span&gt;, &lt;span class="nv"&gt;&amp;lt;businessName&amp;gt;&lt;/span&gt;, &lt;span class="nv"&gt;&amp;lt;email&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;When &lt;/span&gt;User calculates and fills result
    &lt;span class="nf"&gt;When &lt;/span&gt;User clicks submit
    &lt;span class="nf"&gt;Then &lt;/span&gt;Verify thank you text
    &lt;span class="nn"&gt;Examples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;firstName&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;businessName&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;email&lt;/span&gt;               &lt;span class="p"&gt;|&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"ABC"&lt;/span&gt;     &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"DEF"&lt;/span&gt;    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"Main&lt;/span&gt; &lt;span class="n"&gt;Inc."&lt;/span&gt;  &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"whatever@main.com"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now for the below step, it's almost the exact same except we are intentionally not filling out the calculation. In this case we are testing the page's validation. The &lt;strong&gt;Then&lt;/strong&gt; step in this case is verifying the correct alert is displayed to the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;  &lt;span class="nt"&gt;@Validation&lt;/span&gt;
  &lt;span class="kn"&gt;Scenario Outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; User is able to request a Demo but does not fill out result
    &lt;span class="nf"&gt;Given &lt;/span&gt;User navigates to PHPTRAVELS Demo Page
    &lt;span class="nf"&gt;When &lt;/span&gt;User fills in Demo Request Form &lt;span class="nv"&gt;&amp;lt;firstName&amp;gt;&lt;/span&gt;, &lt;span class="nv"&gt;&amp;lt;lastName&amp;gt;&lt;/span&gt;, &lt;span class="nv"&gt;&amp;lt;businessName&amp;gt;&lt;/span&gt;, &lt;span class="nv"&gt;&amp;lt;email&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;When &lt;/span&gt;User clicks submit
    &lt;span class="nf"&gt;Then &lt;/span&gt;Verify alert &lt;span class="s"&gt;"Please input result number"&lt;/span&gt;
    &lt;span class="nn"&gt;Examples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;firstName&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;businessName&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;email&lt;/span&gt;               &lt;span class="p"&gt;|&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"ABC"&lt;/span&gt;     &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"DEF"&lt;/span&gt;    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"Main&lt;/span&gt; &lt;span class="n"&gt;Inc."&lt;/span&gt;  &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;"whatever@main.com"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As always code is on available on &lt;a href="https://github.com/terencenmnpan/TestAutomation/tree/main/PlaywrightCucumberExample"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cucumber</category>
      <category>testing</category>
      <category>playwright</category>
      <category>java</category>
    </item>
    <item>
      <title>Playwright with Cucumber/JUnit 5 - Maven setup with pom.xml</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Sun, 02 Oct 2022 23:43:53 +0000</pubDate>
      <link>https://forem.com/terencepan/playwright-with-cucumberjunit-5-maven-setup-with-pomxml-19l8</link>
      <guid>https://forem.com/terencepan/playwright-with-cucumberjunit-5-maven-setup-with-pomxml-19l8</guid>
      <description>&lt;h3&gt;
  
  
  Maven setup with pom.xml &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In the pom.xml I am using BOMs(Bill of Materials) to manage versions of Junit 5 and Cucumber. This ensures that linked versions of those libraries are all compatible. For example, we are using Cucumber 7.3.4 here, so Gherkin 23.0.1 is the version that was developed with 7.3.4 and will be brought in automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit-bom&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${junit5.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.cucumber&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;cucumber-bom&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${cucumber.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Descriptions of dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Playwright: UI testing framework&lt;/li&gt;
&lt;li&gt;junit-jupiter-api: JUnit 5 testing framework which provides testing methods through classes such as Assertions, Assumptions&lt;/li&gt;
&lt;li&gt;junit-platform-suite: allows us to create JUnit 5 test suites to create test suite classes to organize features we can run&lt;/li&gt;
&lt;li&gt;Cucumber: software tool that supports behavior-driven development (BDD)&lt;/li&gt;
&lt;li&gt;cucumber-junit-platform-engine: used as engine for Junit5&lt;/li&gt;
&lt;li&gt;cucumber-picocontainer: used for dependency injection to share state and singletons within a scenario through steps&lt;/li&gt;
&lt;li&gt;gherkin: used to parse Cucumber features written in the Gherkin language to glue code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Description of plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;maven-compiler-plugin: used to compile sources for code&lt;/li&gt;
&lt;li&gt;maven-surefire-plugin: used to run tests and test configurations such as reports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;pom.xml contents&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0"&lt;/span&gt;
         &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
         &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.tpan&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;PlaywrightCucumberExample&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;maven.compiler.source&amp;gt;&lt;/span&gt;11&lt;span class="nt"&gt;&amp;lt;/maven.compiler.source&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;maven.compiler.target&amp;gt;&lt;/span&gt;11&lt;span class="nt"&gt;&amp;lt;/maven.compiler.target&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;cucumber.version&amp;gt;&lt;/span&gt;7.3.4&lt;span class="nt"&gt;&amp;lt;/cucumber.version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;maven.surefire.version&amp;gt;&lt;/span&gt;3.0.0-M7&lt;span class="nt"&gt;&amp;lt;/maven.surefire.version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;playwright.version&amp;gt;&lt;/span&gt;1.25.0&lt;span class="nt"&gt;&amp;lt;/playwright.version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;junit5.version&amp;gt;&lt;/span&gt;5.9.0&lt;span class="nt"&gt;&amp;lt;/junit5.version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit-bom&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${junit5.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.cucumber&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;cucumber-bom&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${cucumber.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.microsoft.playwright&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;playwright&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${playwright.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit.jupiter&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit-jupiter-api&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit.platform&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit-platform-suite&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.cucumber&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;cucumber-java&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.cucumber&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;cucumber-junit-platform-engine&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.cucumber&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;cucumber-picocontainer&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.cucumber&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;gherkin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-compiler-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.8.1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-surefire-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${maven.surefire.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;configurationParameters&amp;gt;&lt;/span&gt;
                            cucumber.plugin=pretty,html:target/site/TestRun.html,json:target/site/TestRun.json
                            cucumber.publish.quiet=true
                            cucumber.publish.enabled=false
                        &lt;span class="nt"&gt;&amp;lt;/configurationParameters&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As always code is on available on &lt;a href="https://github.com/terencenmnpan/TestAutomation/tree/main/PlaywrightCucumberExample"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>playwright</category>
      <category>java</category>
      <category>maven</category>
    </item>
    <item>
      <title>Playwright with Cucumber/JUnit 5 - Intro</title>
      <dc:creator>Terence Pan</dc:creator>
      <pubDate>Sun, 02 Oct 2022 23:43:05 +0000</pubDate>
      <link>https://forem.com/terencepan/playwright-with-cucumberjunit-5-intro-47bd</link>
      <guid>https://forem.com/terencepan/playwright-with-cucumberjunit-5-intro-47bd</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I recently had to evaluate a bunch of old TestNG/Selenium UI test automation projects that were not maintained at all. We figured it would be a good idea to evaluate a bunch of different options to migrate the tests to an easier to maintain framework. Playwright was one option we considered. This series is to document example code of how our projects were setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playwright
&lt;/h2&gt;

&lt;p&gt;Playwright like Selenium WebDriver is cross platform, cross browser and available in different languages. But the setup is much easier, you do not have to download web driver binaries and maintain those versions like in Selenium WebDriver. &lt;/p&gt;

&lt;p&gt;Playwright many conveniences as compared to Selenium WebDriver. By default Playwright will auto-wait before performing an action like click. On many sites, it may take a few seconds to wait and with Selenium WebDriver, the code may try to click immediately after the site is navigated to. This would cause an exception where the element is not found. Playwright will wait for the element to appear before clicking. Selectors also pierce Shadow DOM which will help with interacting with Shadow DOM elements like Chrome's print dialog or settings navigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cucumber
&lt;/h2&gt;

&lt;p&gt;We also would like to make these tests understandable by business analysts and other nontechnical staff as well. So we can incorporate the Cucumber framework as well to organize the tests. Cucumber is a Behavior Driven Development testing tool which aims to allow tests to be written in plain language and parsed to run test code. The Cucumber tests use Steps which represent user actions and are directly linked to code, in this case Java Playwright code. This has the advantage of allowing nontechnical staff to more easily understand the test deck, possibly make changes and add test scenarios without having to use up developer time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;For this tutorial it is expected you have an IDE like Intellij or Eclipse. For Eclipse, it is recommended you use a plugin: &lt;a href="https://marketplace.eclipse.org/content/cucumber-eclipse-plugin"&gt;Cucumber Eclipse Plugin&lt;/a&gt;. This plugin is maintained by the Cucumber developers. This allows you to step through features to the code and run features through Eclipse. Intellij Ultimate has the plugin installed and enabled by default. If you are using community edition, you will need to install the &lt;a href="https://www.jetbrains.com/help/idea/enabling-cucumber-support-in-project.html#cucumber-plugin"&gt;Cucumber plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So let's get started, I wanted to cover as much ground as I can for what you may need to know for an actual work project so this will be a series. This tutorial covers Intellij and Chrome, but you can easily use Eclipse and Firefox or Edge instead.&lt;/p&gt;

&lt;p&gt;As always code is on available on &lt;a href="https://github.com/terencenmnpan/TestAutomation/tree/main/PlaywrightCucumberExample"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>playwright</category>
      <category>cucumber</category>
      <category>java</category>
    </item>
  </channel>
</rss>
