<?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: Melia Log</title>
    <description>The latest articles on Forem by Melia Log (@melialog).</description>
    <link>https://forem.com/melialog</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%2F1729626%2Ffee6121c-cffd-4153-92e0-c7a10fe59fbc.jpeg</url>
      <title>Forem: Melia Log</title>
      <link>https://forem.com/melialog</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/melialog"/>
    <language>en</language>
    <item>
      <title>I left Windows for Ubuntu. Here’s everything I configured and what I learned</title>
      <dc:creator>Melia Log</dc:creator>
      <pubDate>Fri, 09 Jan 2026 22:29:29 +0000</pubDate>
      <link>https://forem.com/melialog/i-left-windows-for-ubuntu-heres-everything-i-configured-and-what-i-learned-4bk0</link>
      <guid>https://forem.com/melialog/i-left-windows-for-ubuntu-heres-everything-i-configured-and-what-i-learned-4bk0</guid>
      <description>&lt;h2&gt;
  
  
  I left Windows for Ubuntu. Here’s everything I configured and what I learned
&lt;/h2&gt;

&lt;p&gt;I recently decided to leave Windows and switch to &lt;strong&gt;Ubuntu&lt;/strong&gt; for my development environment.&lt;/p&gt;

&lt;p&gt;Not because Windows is &lt;em&gt;bad&lt;/em&gt;, but because I wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more control&lt;/li&gt;
&lt;li&gt;a cleaner dev workflow&lt;/li&gt;
&lt;li&gt;and to really understand what’s happening under the hood&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article is &lt;strong&gt;not a tutorial from someone who knows everything&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
It’s a &lt;strong&gt;real dev journey&lt;/strong&gt;: things I discovered &lt;em&gt;while doing&lt;/em&gt;, tools I didn’t even know existed before, and why Ubuntu honestly surprised me (in a good way).&lt;/p&gt;


&lt;h2&gt;
  
  
  What I configured after installing Ubuntu
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Installing and configuring Git
&lt;/h3&gt;

&lt;p&gt;First thing first: Git.&lt;/p&gt;
&lt;h4&gt;
  
  
  Install Git
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Configure global variables
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"your_name"&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email &lt;span class="s2"&gt;"your_email"&lt;/span&gt;

&lt;span class="c"&gt;# Check configuration&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="nt"&gt;--list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At this point, Git is ready.&lt;/p&gt;


&lt;h3&gt;
  
  
  Java setup with SDKMAN (my first discovery)
&lt;/h3&gt;

&lt;p&gt;Before Ubuntu, I had no idea that something like &lt;strong&gt;SDKMAN&lt;/strong&gt; existed.&lt;/p&gt;
&lt;h4&gt;
  
  
  What SDKMAN allows you to do :
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install multiple JDK versions (8, 11, 17, 21…)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Switch versions globally or per project&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose different distributions (Temurin, Zulu, Oracle, GraalVM…)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Install SDKMAN
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://get.sdkman.io"&lt;/span&gt; | bash
&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.sdkman/bin/sdkman-init.sh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Check installation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sdk version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  List available Java versions
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sdk list java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Install Java 21 (example)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sdk &lt;span class="nb"&gt;install &lt;/span&gt;java 21.0.9-tem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Switch Java version
&lt;/h4&gt;

&lt;p&gt;For current session :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sdk use java 21.0.9-tem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set as default :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sdk default java 21.0.9-tem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-version&lt;/span&gt;
&lt;span class="c"&gt;#Or&lt;/span&gt;
javac &lt;span class="nt"&gt;-version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Mind blow moment :
&lt;/h4&gt;

&lt;p&gt;I didn't know switching Java versions could be this clean and simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node.js with NVM (another discovery)
&lt;/h2&gt;

&lt;p&gt;Same story here.&lt;br&gt;
I &lt;em&gt;here&lt;/em&gt; about NVM before... but never really used it properly.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is NVM?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;NVM = Node Version Manager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It allows you to :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install multiple Node.js versions&lt;/li&gt;
&lt;li&gt;Switch between them per project&lt;/li&gt;
&lt;li&gt;Avoid breaking old projects&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Why it matters (real case)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Angular 20 -&amp;gt;requires Node ≥ 20&lt;/li&gt;
&lt;li&gt;Older projects -&amp;gt;Node 18 or 16&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without NVM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;uninstall / reinstall Node &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;risk breaking projects &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With NVM :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm use 18
&lt;span class="c"&gt;#or&lt;/span&gt;
nvm use 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;No conflict&lt;/li&gt;
&lt;li&gt;No sudo&lt;/li&gt;
&lt;li&gt;No system break&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install NVM
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-o-&lt;/span&gt; https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Close and reopen terminal, then :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Node 20
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm &lt;span class="nb"&gt;install &lt;/span&gt;20
nvm use 20
nvm &lt;span class="nb"&gt;alias &lt;/span&gt;default 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;-v&lt;/span&gt;
npm &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  PostgreSQL server + client
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install PostgreSQL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;postgresql-18 postgresql-client-18 postgresql-contrib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check service
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status postgresql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change postgres password
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres psql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside PostgreSQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ALTER USER postgres WITH PASSWORD &lt;span class="s1"&gt;'your_new_password'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  PgAdmin 4
&lt;/h2&gt;

&lt;p&gt;Installed directly via &lt;strong&gt;Ubuntu App Center&lt;/strong&gt;.&lt;br&gt;
Simple. Clean. No headache.&lt;/p&gt;
&lt;h2&gt;
  
  
  Postman via Snap
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;snap &lt;span class="nb"&gt;install &lt;/span&gt;postman
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Launch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;postman
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Login all my collections synced automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  SSH Keys (BIG learning moment)
&lt;/h2&gt;

&lt;p&gt;Before Ubuntu, I used to clone repos using HTTPS URLs.&lt;/p&gt;

&lt;p&gt;Then I tried to &lt;strong&gt;clone my own repository&lt;/strong&gt;, and GitHub asked for authorization.&lt;/p&gt;

&lt;p&gt;That’s when I discovered &lt;strong&gt;SSH keys&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create SSH key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"your_github_email"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Start SSH agent and add key
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ssh-agent &lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
ssh-add ~/.ssh/id_ed25519
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Copy public key
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_ed25519.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Add key to GitHub
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GitHub -&amp;gt; Settings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SSH and GPG keys&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;New SSH key&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Paste key&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Test connection
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-T&lt;/span&gt; git@github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hi username! You've successfully authenticated...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;SSH works&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now I clone repositories &lt;strong&gt;without any access issues&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  IDEs and account sync
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;IntelliJ IDEA -&amp;gt; App Center&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;VS Code -&amp;gt; App Center&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitHub account sync -&amp;gt; plugins, settings, themes restored automatically.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;What really surprised me is how &lt;strong&gt;simple everything feels&lt;/strong&gt; on Ubuntu.&lt;/p&gt;

&lt;p&gt;With:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;a few commands&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;clear tools&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;no weird installers&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Things that used to take &lt;strong&gt;a lot of time on Windows&lt;/strong&gt; were done in minutes.&lt;/p&gt;

&lt;p&gt;And most importantly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I understood what I was installing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This transition didn’t just change my OS&lt;br&gt;
it changed how I see my dev environment.&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>devjournal</category>
      <category>node</category>
      <category>java</category>
    </item>
    <item>
      <title>My Docker Adventure: A Journey to Containerization</title>
      <dc:creator>Melia Log</dc:creator>
      <pubDate>Thu, 12 Jun 2025 14:04:43 +0000</pubDate>
      <link>https://forem.com/melialog/my-docker-adventure-a-journey-to-containerization-mpp</link>
      <guid>https://forem.com/melialog/my-docker-adventure-a-journey-to-containerization-mpp</guid>
      <description>&lt;h2&gt;
  
  
  My Docker Adventure: A Journey to Containerization
&lt;/h2&gt;

&lt;p&gt;Yesterday I said to myself, "What if I stopped using traditional software? What if I stopped installing XAMPP every time I started a new project? What if I used Docker instead?"&lt;/p&gt;

&lt;p&gt;So there, no intense thinking - straight to Google "How to install properly Docker?" and off I went on my Docker adventure!&lt;/p&gt;

&lt;p&gt;I installed WSL 2 on my Windows and off I went! But there was more to come. I said to myself, "What if I stop using MySQL and use Postgres?" Yes, I know, a lot of "what ifs" in a short space of time!&lt;/p&gt;

&lt;p&gt;I had always used MySQL by default because it’s what tools like XAMPP and many tutorials use. But I started wondering: what’s the real difference between MySQL and PostgreSQL? They’re both relational database systems, they both use SQL... So why do some developers swear by Postgres?&lt;/p&gt;

&lt;p&gt;I was especially curious because I saw Postgres used in a lot of modern full-stack tutorials, especially with Spring Boot or Node.js. Plus, I had read that it handled things like UUIDs more natively — and I like the idea of having those unique, unguessable IDs for security and scalability.&lt;/p&gt;

&lt;p&gt;So I did a bit of digging, and here’s what I discovered:&lt;/p&gt;

&lt;h2&gt;
  
  
  Why PostgreSQL and not MySQL?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Better handling of complex data types&lt;/strong&gt;: PostgreSQL supports types like JSON, XML, UUIDs, arrays, and even custom data types. Super useful when you need more flexibility in how you store data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closer compliance with SQL standards&lt;/strong&gt;: PostgreSQL is known for sticking closely to SQL standards, making it more reliable for complex queries or scalable projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility&lt;/strong&gt;: You can easily add functions, operators, or extensions in Postgres. It’s built to be modular and customizable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native UUID support&lt;/strong&gt;: Unlike MySQL, which often requires workarounds or plugins, PostgreSQL has built-in support for UUIDs—perfect for generating secure, unique identifiers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Great performance with large datasets&lt;/strong&gt;: Benchmarks often show that PostgreSQL performs really well, especially when dealing with lots of relational data or complex operations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I said to myself "Okay, let's go!"&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Image
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; container_name &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mypassword &lt;span class="nt"&gt;-p&lt;/span&gt; 5432:5432 &lt;span class="nt"&gt;-d&lt;/span&gt; postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, the big question: how do I connect my Spring Boot API with this image? I asked ChatGPT (my virtual mentor of the moment), who advised me to create an application.yml file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:postgresql://localhost:5432/postgres&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mypassword&lt;/span&gt;
  &lt;span class="na"&gt;jpa&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hibernate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ddl-auto&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;update&lt;/span&gt;
    &lt;span class="na"&gt;show-sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, panic! Error message: "Connection failed". My heart skips a beat! I go back to ChatGPT to find out what's wrong. He kindly explains that the problem lies in the application.properties file, which is selected by default.&lt;/p&gt;

&lt;p&gt;Being the cautious beginner that I am, I was afraid of breaking everything by deleting it. As a compromise solution, I renamed it to system.properties.&lt;/p&gt;

&lt;p&gt;And now the YAML file looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;application&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;project_name&lt;/span&gt;
  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:postgresql://localhost:5432/database_name&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my_password&lt;/span&gt;
    &lt;span class="na"&gt;driver-class-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.postgresql.Driver&lt;/span&gt;

  &lt;span class="na"&gt;jpa&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hibernate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ddl-auto&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;update&lt;/span&gt;
    &lt;span class="na"&gt;show-sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;database-platform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.hibernate.dialect.PostgreSQLDialect&lt;/span&gt;

  &lt;span class="na"&gt;jpa.properties.hibernate.format_sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I run the application again and get another error message: &lt;code&gt;database not found&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Alright, I realize I need to create the database first. After checking some YouTube tutorials, I'm ready to try these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Connect to postgres&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;name or container_id&lt;span class="o"&gt;)&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres
&lt;span class="c"&gt;# Create database&lt;/span&gt;
CREATE DATABASE my_database&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c"&gt;# List existing databases&lt;/span&gt;
&lt;span class="se"&gt;\l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I check the database and see it was created successfully, so I restart the run.&lt;/p&gt;

&lt;p&gt;And then... BOOM! It works! My thirty-two teeth are so visible that I'm smiling (yes, even the wisdom teeth). What do you expect? I'm alone, with no mentor, just a dev trying to learn with an AI, YouTube and Google as my companions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table check
&lt;/h2&gt;

&lt;p&gt;The run works, no errors, but are my tables created? How do I check? After some research, here are the magic commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; container_id psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; database_name
&lt;span class="se"&gt;\d&lt;/span&gt;t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At 1 a.m., seeing my tables well created, I finally decide to go to sleep. But my dev brain can't help but think: "Tomorrow, I'm trying to figure out Dockerfile, because all this manual image creation, it could be automated!"&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources That Helped Me Along the Way
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;📺 &lt;a href="https://www.youtube.com/watch?v=ZyBBv1JmnWQ&amp;amp;ab_channel=CodeBear" rel="noopener noreferrer"&gt;This YouTube video&lt;/a&gt; that clearly explained how to install and use Docker on Windows.&lt;/li&gt;
&lt;li&gt;📄 &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/install" rel="noopener noreferrer"&gt;Microsoft's official documentation on installing WSL 2&lt;/a&gt; — essential for getting Docker Desktop to work smoothly on Windows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be continued in my next Docker adventures...&lt;/p&gt;

</description>
      <category>docker</category>
      <category>containers</category>
      <category>containerization</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Relationships in JPA: Creating Entities Without Dependency</title>
      <dc:creator>Melia Log</dc:creator>
      <pubDate>Mon, 11 Nov 2024 12:40:18 +0000</pubDate>
      <link>https://forem.com/melialog/relationships-in-jpa-creating-entities-without-dependency-2hmd</link>
      <guid>https://forem.com/melialog/relationships-in-jpa-creating-entities-without-dependency-2hmd</guid>
      <description>&lt;h2&gt;
  
  
  Relationships in JPA: Creating Entities Without Dependency
&lt;/h2&gt;

&lt;p&gt;When creating a backend API, it's common to work with entity relationships to organize data. Typically, in courses or tutorials, we mostly see bidirectional relationships. But what if you want one entity to exist independently of the other? In this article, we’ll explore how to use a unidirectional relationship with JPA/Hibernate to achieve this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Context and Problem&lt;/li&gt;
&lt;li&gt;Entity Modeling&lt;/li&gt;
&lt;li&gt;
Scenarios for Saving Data

&lt;ul&gt;
&lt;li&gt;Creating a Student without a ThesisSchedule&lt;/li&gt;
&lt;li&gt;Updating the Student to Associate with a ThesisSchedule&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Advantages of Managing the Relationship on Student's Side&lt;/li&gt;

&lt;li&gt;Alternative: Managing the Relationship on the ThesisSchedule Side&lt;/li&gt;

&lt;li&gt;Choosing the Right Configuration for Your Needs&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context and Problem:
&lt;/h2&gt;

&lt;p&gt;Imagine you have two entities: Student and ThesisSchedule. The relationship between Student and ThesisSchedule is "many-to-one," meaning that a student can be associated with a thesis schedule, and each schedule can include multiple students.&lt;/p&gt;

&lt;p&gt;In this case, our goal is to allow the creation of a Student without requiring a ThesisSchedule to be defined first. This independence is helpful, for instance, when adding students to the database before creating thesis schedules.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Problem encountered: With a bidirectional or poorly configured relationship, creating a Student may fail if a ThesisSchedule hasn’t been created yet, even with the annotation nullable = true. Let’s see how to solve this with a unidirectional relationship.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Entity Modeling
&lt;/h2&gt;

&lt;p&gt;We’ll create Student and ThesisSchedule classes using a unidirectional "many-to-one" relationship from Student to ThesisSchedule.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Student&lt;/code&gt; entity code:&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%2Fevq0a66qmfewsyk1qaws.png" 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%2Fevq0a66qmfewsyk1qaws.png" alt="Image of the Student entity code" width="800" height="782"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ThesisShedule&lt;/code&gt; entity code:&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%2Feb60ge996w79ge4nd0zk.png" 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%2Feb60ge996w79ge4nd0zk.png" alt="Image of the ThesisShedule entity code" width="800" height="835"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we have a unidirectional relationship from Student to ThesisSchedule, indicated by the @ManyToOne annotation in the Student class. By specifying nullable = true, we allow a Student to be created without necessarily being associated with a ThesisSchedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenarios for Saving Data
&lt;/h2&gt;

&lt;p&gt;Let’s see how this setup translates to the database and how data can be saved through an API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Student without a ThesisSchedule
&lt;/h3&gt;

&lt;p&gt;With this setup, we can create a student without providing a ThesisSchedule.&lt;/p&gt;

&lt;p&gt;POST request to create a Student (without ThesisSchedule):&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%2Fw3o7fop0gjtttco7zupo.png" 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%2Fw3o7fop0gjtttco7zupo.png" alt="Image of the POST request to create a Student " width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This creates a new entry in the Student table with a null value for the thesis_schedule_id column.&lt;/p&gt;

&lt;p&gt;Result:&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%2Fc86ymsozfirmp8dwvf2a.png" 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%2Fc86ymsozfirmp8dwvf2a.png" alt="Image of result" width="800" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the Student to Associate with a ThesisSchedule
&lt;/h3&gt;

&lt;p&gt;Once a ThesisSchedule is created, we can update the Student record to associate with it.&lt;/p&gt;

&lt;p&gt;Creating a ThesisSchedule:&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%2Foq8oxztnkircowc02wrn.png" 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%2Foq8oxztnkircowc02wrn.png" alt="Image of Creating a ThesisSchedule" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newly created ThesisSchedule might have an ID of 1.&lt;/p&gt;

&lt;p&gt;Updating the student with ThesisSchedule:&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%2F7odmxlycc1rgyg2salu5.png" 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%2F7odmxlycc1rgyg2salu5.png" alt="Image of Updating the student with ThesisSchedule" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Result: &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%2Fmexe0qayd67b9uh7pq21.png" 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%2Fmexe0qayd67b9uh7pq21.png" alt="Image of result" width="800" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, Larose is associated with the newly created ThesisSchedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of Managing the Relationship on Student's side:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Creation Flexibility: We can create a Student independently of a ThesisSchedule, allowing for independent entity creation.&lt;/li&gt;
&lt;li&gt;Simplicity of Structure: A unidirectional relationship simplifies interactions, as ThesisSchedule doesn’t need to be aware of the relationship with Student.&lt;/li&gt;
&lt;li&gt;Scalability: If we later need to make this relationship bidirectional, we can update the ThesisSchedule class to include a collection of Student.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Alternative: Managing the Relationship on the ThesisSchedule Side
&lt;/h2&gt;

&lt;p&gt;In some cases, it may be more appropriate to manage the relationship from the ThesisSchedule side. This approach is useful if we want the thesis schedule to manage its associated students, keeping track of those participating in a specific schedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entity Modeling
&lt;/h2&gt;

&lt;p&gt;In this setup, ThesisSchedule holds a collection of Student to represent a "one-to-many" relationship, while Student doesn’t maintain a reference to ThesisSchedule.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ThesisSchedule&lt;/code&gt; entity code:&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%2F2109g9f4wm7t2mscy1xq.png" 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%2F2109g9f4wm7t2mscy1xq.png" alt="Image of ThesisSchedule entity code" width="800" height="961"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Student&lt;/code&gt; entity code:&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%2F8f6bdsmch9u96x12zuac.png" 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%2F8f6bdsmch9u96x12zuac.png" alt="Image of Student entity code" width="800" height="785"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this configuration, ThesisSchedule contains a list of Student through the @OneToMany annotation. Consequently, students can be added or removed from ThesisSchedule without requiring a direct link in Student.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of Managing the Relationship on ThesisSchedule’s Side:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Data Centralization: All information about students associated with a thesis schedule is centralized in ThesisSchedule, making it easier to access relevant data.&lt;/li&gt;
&lt;li&gt;Increased Control: ThesisSchedule can manage its students, simplifying the handling of groups of students participating in the same schedule.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Choosing the Right Configuration for Your Needs:
&lt;/h2&gt;

&lt;p&gt;In conclusion, whether to manage the relationship on the Student or ThesisSchedule side depends on your application's specific needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relationship Managed by Student: Use this setup if you want to create students independently of a thesis schedule and optionally link a schedule to a student later.&lt;/li&gt;
&lt;li&gt;Relationship Managed by ThesisSchedule: This option is preferable if the thesis schedule should manage its students, making it the core of the relationship between entities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both configurations provide flexibility and allow for well-organized backend APIs based on the desired data relationships. By applying best practices to structure entity relationships, you can effectively model your database to meet your application’s specific needs.&lt;/p&gt;

&lt;p&gt;Unidirectional relationships are a powerful option for managing optional dependencies between entities in a backend API.&lt;/p&gt;

&lt;p&gt;I hope this solution helps other developers better understand and use unidirectional relationships in JPA/Hibernate.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>jpa</category>
      <category>relationshipsinjpa</category>
    </item>
    <item>
      <title>Write Good Commit Messages</title>
      <dc:creator>Melia Log</dc:creator>
      <pubDate>Wed, 16 Oct 2024 17:06:19 +0000</pubDate>
      <link>https://forem.com/melialog/write-good-commit-messages-2l05</link>
      <guid>https://forem.com/melialog/write-good-commit-messages-2l05</guid>
      <description>&lt;h2&gt;
  
  
  Write Good Commit Messages!
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Introduction: Why Commit Messages Matter
&lt;/h2&gt;

&lt;p&gt;Commit messages are often overlooked by developers, but they play a crucial role in collaborative project management. A good commit message helps your team—and your future self—understand the changes made without having to read every line of code. Unfortunately, many beginner developers (just like me by the way 😁) make the mistake of using vague messages like "fix" or "done," which makes the Git history impossible to follow.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem with Bad Commit Messages
&lt;/h2&gt;

&lt;p&gt;Here are some common examples of bad commit messages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"fix"&lt;/li&gt;
&lt;li&gt;"done"&lt;/li&gt;
&lt;li&gt;"update"&lt;/li&gt;
&lt;li&gt;"test"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These messages don’t explain what actually changed in the code. When you have dozens of commits like these in your history, it becomes very difficult to track the project's evolution. It also makes it harder for your team if they need to backtrack to a specific bug or change.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why is this a Problem?
&lt;/h2&gt;

&lt;p&gt;Vague commit messages present several issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lack of clarity:&lt;/strong&gt; They provide no information about what was changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unusable Git history:&lt;/strong&gt; When you want to roll back or review the project’s progress, you’re lost in a sea of meaningless messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Harder collaboration:&lt;/strong&gt; Your teammates also don’t know what you did, making collaboration more difficult.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Solution: Use "Badges" to Structure Your Commits
&lt;/h2&gt;

&lt;p&gt;To make your commit messages clearer, use "badges" or specific keywords at the beginning of the message. This helps quickly identify the nature of the change. Here are a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;[fix]&lt;/strong&gt; for bug fixes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[feat]&lt;/strong&gt; for new features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[docs]&lt;/strong&gt; for documentation updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[style]&lt;/strong&gt; for style or formatting changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[refactor]&lt;/strong&gt; for code reorganizations without feature changes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-Life Examples of Good Commit Messages
&lt;/h2&gt;

&lt;p&gt;To illustrate the difference between a bad and a good commit message, here are a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bad:&lt;/strong&gt; "fix"&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt; &lt;code&gt;[fix] Fixed login page bug&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt; "update"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt; &lt;code&gt;[feat] Added share button to articles page&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These examples clearly show the difference. The first example doesn’t tell much about what was fixed, while the second explicitly explains which bug was fixed. Similarly, for adding a feature, the good message explains exactly what was added.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus: Tips for Writing Clear Commits
&lt;/h2&gt;

&lt;p&gt;Here are some best practices for writing effective commit messages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Be clear and concise:&lt;/strong&gt; Your message should describe exactly what you did without being too long.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the imperative form:&lt;/strong&gt; Write your commit messages as commands. Example: "Add search functionality" instead of "Adding search functionality."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask yourself this question:&lt;/strong&gt; "What does this commit change in the project?" If your message answers this clearly, you're on the right track.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Good commit messages help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep a clean and understandable Git history.&lt;/li&gt;
&lt;li&gt;Improve team collaboration.&lt;/li&gt;
&lt;li&gt;Make project maintenance easier in the long run.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now that you know how to structure your commit messages, it's time to put these tips into practice! Start writing clear and meaningful commit messages today. And if you've seen funny or confusing commit messages, share them in the comments!&lt;/p&gt;

&lt;p&gt;Don’t forget to share this article with other developers and follow for more development tips!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Explication de SeleniumWebDriver : Automatisez votre Flux de Tests Web</title>
      <dc:creator>Melia Log</dc:creator>
      <pubDate>Wed, 10 Jul 2024 15:53:18 +0000</pubDate>
      <link>https://forem.com/melialog/explication-de-seleniumwebdriver-automatisez-votre-flux-de-tests-web-e88</link>
      <guid>https://forem.com/melialog/explication-de-seleniumwebdriver-automatisez-votre-flux-de-tests-web-e88</guid>
      <description>&lt;p&gt;Salut à tous, &lt;/p&gt;

&lt;p&gt;Aujourd'hui, je vais vous parler de Selenium WebDriver, une nouvelle notion que je viens d'apprendre. Dans cet article, nous nous concentrerons principalement sur la théorie afin de comprendre ce qu'est Selenium WebDriver, son utilité et bien d'autres concepts associés.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table des matières
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Qu'est ce que Selenium?&lt;/li&gt;
&lt;li&gt;
Composants de Selenium

&lt;ul&gt;
&lt;li&gt;Selenium IDE&lt;/li&gt;
&lt;li&gt;Selenium RC&lt;/li&gt;
&lt;li&gt;Selenium WebDriver&lt;/li&gt;
&lt;li&gt;Selenium Grid&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Avantages et limites de Selenium WebDriver&lt;/li&gt;

&lt;li&gt;Architecture du Framework Selenium WebDriver&lt;/li&gt;

&lt;li&gt;Processus d'exécution d'un test&lt;/li&gt;

&lt;li&gt;Comment utiliser Selenium WebDriver avec Java ?&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Qu'est ce que Selenium ?
&lt;/h2&gt;

&lt;p&gt;Selenium est un ensemble open-source d'outils et de bibliothèques qui permet d'effectuer des tests multi-navigateurs pour vérifier si le site web fonctionne de manière cohérente sur différents navigateurs Il est largement utilisé pour les tests automatisés des applications Web.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compatibilité :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Selenium est compatible avec les langages C#, Java, Python, JavaScript, Ruby, Python et PHP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remarque :&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Les testeurs sont libres de choisir le langage dans lequel concevoir les cas de test, ce qui rend Selenium très avantageux.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Il n'est pas obligatoire d'écrire le code Selenium dans le même langage que l'application. Par exemple, pour une application écrite en PHP, le script du test peut être écrit en Java.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Composants de Selenium
&lt;/h2&gt;

&lt;p&gt;La suite des tests Selenium comprend quatre composants principaux:&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%2F70cpbudv6mpj9q1m3x6c.webp" 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%2F70cpbudv6mpj9q1m3x6c.webp" alt="composants du selenium" width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Selenium IDE:
&lt;/h2&gt;

&lt;p&gt;Selenium IDE pour &lt;code&gt;Integrated Development Environement&lt;/code&gt;, est un outil d'enregistrement/d'exécution pour les tests fonctionnels (&lt;code&gt;functionnal testing&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB :&lt;/strong&gt; Vous n'avez pas besoin d'apprendre un langage de script pour créer le test fonctionnel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Selenium RC:
&lt;/h2&gt;

&lt;p&gt;Selenium RC, pour &lt;code&gt;Remote Controller&lt;/code&gt; nécessite des connaissances dans au moins un langage de programmation. Ses bibliothèques principaux sont :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serveur&lt;/li&gt;
&lt;li&gt;Client&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NB :&lt;/strong&gt; Architecture complexe et ayant des limites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Selenium WebDriver
&lt;/h2&gt;

&lt;p&gt;C'est un Framework permettant d'exécuter des tests multi-navigateurs et c'est une version améliorée du Selenium RC. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB :&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bien qu'il soit une version améliorée de Selenium RC, son architecture est complément différente.&lt;/li&gt;
&lt;li&gt;Il faut tout même connaitre un langage de programmation pour l'utiliser.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Selenium Grid
&lt;/h2&gt;

&lt;p&gt;Pour l'exécution simultanée de cas de test sur différents navigateurs, machines et système d'exploitation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB :&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Facilite les tests de compatibilités entre navigateurs.&lt;/li&gt;
&lt;li&gt;Deux versions : Grid 1 (ancienne version) et Grid 2 ( nouvelle version).&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Avantages et limites de Selenium WebDriver
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Avantages de Selenium WebDriver
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Support Multinavigateur :&lt;br&gt;
Selenium WebDriver supporte de nombreux navigateurs tels que Chrome, Firefox, Safari, Edge, etc. Cela permet de tester les applications web sur différents environnements de navigation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contrôle Direct du Navigateur :&lt;br&gt;
WebDriver interagit directement avec le navigateur, ce qui assure une meilleure précision et fiabilité des tests par rapport à d'autres outils qui utilisent des scripts injectés.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support Multi-langage :&lt;br&gt;
Selenium WebDriver permet d'écrire des scripts de test dans plusieurs langages de programmation tels que Java, Python, C#, Ruby, JavaScript, etc., offrant une grande flexibilité aux développeurs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;API Flexible et Puissante :&lt;br&gt;
L'API de Selenium WebDriver est riche et permet de réaliser des tests complexes incluant des interactions avancées avec les éléments web, la gestion des cookies, des sessions, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open Source et Gratuit :&lt;br&gt;
Selenium est un outil open source, ce qui signifie qu'il est gratuit et que la communauté contribue constamment à son amélioration et à son évolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compatibilité avec Divers Outils de Test :&lt;br&gt;
Selenium WebDriver peut être intégré avec des frameworks de tests populaires comme TestNG, JUnit, NUnit, ainsi qu'avec des outils de CI/CD comme Jenkins, Maven, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tests Répartis et Parallèles :&lt;br&gt;
Avec Selenium Grid, il est possible d'exécuter des tests en parallèle sur plusieurs machines et navigateurs, ce qui réduit le temps total d'exécution des tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Offre une compatibilité avec IphoneDriver, HtmlUnitDriver et AndroidDriver&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fmedia.licdn.com%2Fdms%2Fimage%2FC4E12AQF2iKl5F-hSXw%2Farticle-inline_image-shrink_1000_1488%2F0%2F1584834889636%3Fe%3D1722470400%26v%3Dbeta%26t%3D0OBtjmfKoGv0qgVb7wO4emPRJwrJnhEbHqgvV1jNCHI" 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%2Fmedia.licdn.com%2Fdms%2Fimage%2FC4E12AQF2iKl5F-hSXw%2Farticle-inline_image-shrink_1000_1488%2F0%2F1584834889636%3Fe%3D1722470400%26v%3Dbeta%26t%3D0OBtjmfKoGv0qgVb7wO4emPRJwrJnhEbHqgvV1jNCHI" alt="BrowserStack" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limites de Selenium WebDriver
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Limitation aux Tests Web :&lt;br&gt;
Selenium WebDriver ne peut être utilisé que pour tester des applications web. Il ne supporte pas les applications desktop ou les applications mobiles natives.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gestion des Pop-ups et des Fenêtres :&lt;br&gt;
Selenium peut rencontrer des difficultés à gérer certaines pop-ups et fenêtres modales, surtout celles générées par le système d'exploitation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dépendance aux Sélecteurs de Page :&lt;br&gt;
Les scripts de Selenium dépendent fortement de la structure et des sélecteurs des pages web (ID, nom, classes, etc.). Si l'interface utilisateur change fréquemment, les scripts de test doivent être constamment mis à jour.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Absence de Support pour Capturer les Erreurs Visuelles :&lt;br&gt;
Selenium WebDriver ne peut pas détecter les erreurs visuelles telles que les problèmes d'alignement ou les couleurs incorrectes. Des outils supplémentaires comme Applitools Eyes peuvent être nécessaires pour les tests visuels.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Courbe d'Apprentissage :&lt;br&gt;
Bien que Selenium soit puissant, il peut être complexe à maîtriser pour les débutants en raison de la nécessité de comprendre la programmation, l'automatisation des tests et l'API de Selenium.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance :&lt;br&gt;
Les tests Selenium peuvent être plus lents que ceux exécutés par certains outils d'automatisation headless (sans interface utilisateur), surtout lorsque des captures d'écran ou des vidéos des tests sont nécessaires.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Maintenance des Tests :&lt;br&gt;
En raison de la nature dynamique des applications web modernes, les tests Selenium nécessitent une maintenance régulière pour s'assurer qu'ils restent fonctionnels face aux changements de l'application.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Architecture du Framework Selenium WebDriver
&lt;/h2&gt;

&lt;p&gt;L'architecture Webdriver est composée de quatre composants principaux :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Client Librairies (Bibliothèques Clients)&lt;br&gt;
Les bibliothèques clientes sont des API fournies par Selenium pour différents langages de programmation. Les principales bibliothèques clientes sont disponibles pour :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;C#&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;JavaScript (Node.js)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JSON Wire Protocol over HTTP (Protocole JSON Wire)&lt;br&gt;
Le JSON Wire Protocol est un protocole standardisé utilisé par Selenium WebDriver pour envoyer des commandes aux navigateurs. Ce protocole définit une API RESTful qui permet de communiquer avec les navigateurs en utilisant des requêtes HTTP. Les bibliothèques clientes envoient des requêtes HTTP contenant les commandes Selenium aux serveurs WebDriver via ce protocole.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Browser Drivers (Drivers de Navigateur)&lt;br&gt;
Chaque navigateur a son propre driver qui agit comme un pont entre Selenium WebDriver et le navigateur. Les drivers de navigateur reçoivent les commandes en JSON Wire Protocol des bibliothèques clientes et les traduisent en actions spécifiques au navigateur.&lt;br&gt;
Les drivers de navigateur comprennent :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ChromeDriver&lt;/strong&gt; pour Google Chrome&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GeckoDriver&lt;/strong&gt; pour Mozilla Firefox&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IEDriver&lt;/strong&gt;pour Internet Explorer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EdgeDriver&lt;/strong&gt; pour Microsoft Edge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SafariDriver&lt;/strong&gt; pour Safari&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Browsers (Navigateurs)&lt;br&gt;
Les navigateurs sont les applications web réelles avec lesquelles Selenium interagit. Les drivers de navigateur lancent et contrôlent les instances des navigateurs pour exécuter les scripts de test. Les navigateurs peuvent être exécutés en mode graphique ou headless (sans interface utilisateur) pour des tests plus rapides.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fioklrfwqp8p718cdzniu.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%2Fioklrfwqp8p718cdzniu.jpg" alt="Selenium WebDriver Framework Architecture" width="755" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Processus d'exécution d'un test
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Écriture du Script : Le testeur écrit des scripts de test en utilisant les bibliothèques clientes de Selenium dans le langage de programmation choisi.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Envoi de Commandes : Les bibliothèques clientes envoient des commandes en utilisant le JSON Wire Protocol via des requêtes HTTP au driver de navigateur correspondant.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interprétation des Commandes : Le driver de navigateur interprète les commandes et les traduit en actions spécifiques au navigateur.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exécution des Actions : Le navigateur exécute les actions (comme cliquer sur un bouton, entrer du texte, etc.) et retourne les résultats via le driver de navigateur.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Retour des Résultats : Les résultats des actions sont renvoyés via le driver de navigateur aux bibliothèques clientes, qui les traitent et génèrent des rapports de test.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Comment utiliser Selenium WebDriver avec Java?
&lt;/h2&gt;

&lt;p&gt;Pour cette section de pratique, je vous invite a lire cette article &lt;a href="https://dev.to/laroseikitama/introduction-pratique-aux-tests-dapplications-web-avec-selenium-webdriver-et-java-23ml"&gt;Introduction pratique aux tests d'applications Web avec Selenium WebDriver et Java.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>selenium</category>
      <category>testing</category>
      <category>learning</category>
    </item>
    <item>
      <title>Practical Introduction to Web Application Testing with Selenium WebDriver and Java.</title>
      <dc:creator>Melia Log</dc:creator>
      <pubDate>Wed, 10 Jul 2024 15:46:02 +0000</pubDate>
      <link>https://forem.com/melialog/introduction-pratique-aux-tests-dapplications-web-avec-selenium-webdriver-et-java-23ml</link>
      <guid>https://forem.com/melialog/introduction-pratique-aux-tests-dapplications-web-avec-selenium-webdriver-et-java-23ml</guid>
      <description>&lt;h1&gt;
  
  
  A Practical Introduction to Web Application Testing with Selenium WebDriver and Java.
&lt;/h1&gt;

&lt;p&gt;Hello everyone,&lt;/p&gt;

&lt;p&gt;Today, I want to share with you a practical introduction to testing web applications with Selenium WebDriver. We'll look at how to write a simple test script in Java, using two mini-projects I recently completed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Environment
&lt;/h2&gt;

&lt;p&gt;Before we start writing our test script, we need to prepare our development environment. Here’s what we need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Java JDK:&lt;/strong&gt; Ensure that you have the Java Development Kit (JDK) installed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IntelliJ IDEA:&lt;/strong&gt; We'll use IntelliJ IDEA as our IDE.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Selenium WebDriver:&lt;/strong&gt; We'll add the necessary libraries to the project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Google Chrome:&lt;/strong&gt; We will use the Google Chrome browser.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ChromeDriver:&lt;/strong&gt; You’ll need to download the ChromeDriver that matches your version of Google Chrome.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Installing Selenium WebDriver
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Download Selenium WebDriver for Java.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to the official Selenium WebDriver site by clicking this link &lt;a href="https://www.selenium.dev/downloads/" rel="noopener noreferrer"&gt;https://www.selenium.dev/downloads/&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scroll down to the section &lt;code&gt;Selenium Clients and WebDriver Language Bindings&lt;/code&gt; and download the &lt;code&gt;Selenium WebDriver Java&lt;/code&gt; client. The download will be a ZIP file containing the libraries and the Selenium Java drivers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Visit &lt;a href="https://sites.google.com/chromium.org/driver/downloads" rel="noopener noreferrer"&gt;https://sites.google.com/chromium.org/driver/downloads&lt;/a&gt; to find out which version of &lt;code&gt;ChromeDriver&lt;/code&gt; to download based on your Google Chrome version.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How to check your Google Chrome version:&lt;/strong&gt; In the URL bar of your Google Chrome browser, type: &lt;code&gt;chrome://version&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new Java project with Maven in IntelliJ IDEA. In this case, we'll call it &lt;code&gt;SeleniumTestLogiciels&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Add Selenium Libraries to the Project.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Extract the downloaded ZIP file to a folder on your computer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In IntelliJ IDEA, click on &lt;code&gt;File &amp;gt; Project Structure&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Project Structure window, click on &lt;code&gt;Libraries&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the &lt;code&gt;Libraries&lt;/code&gt; window, click the &lt;code&gt;+&lt;/code&gt; icon on the right for (New Project Library) and then choose &lt;code&gt;Java&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Select &lt;code&gt;Library Files&lt;/code&gt; window, navigate to the folder where you extracted Selenium WebDriver and select all the files inside it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick selection tip:&lt;/strong&gt; Click the first item in the folder, hold down the &lt;code&gt;shift&lt;/code&gt; key, and then, without releasing the key, use the mouse to go to the bottom of the list and click on the last item. Voila! :).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Apply&lt;/code&gt; and then &lt;code&gt;Close&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Verify the Installation
&lt;/h2&gt;

&lt;p&gt;Let’s create a simple test script to verify that Selenium WebDriver has been installed correctly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a new class named &lt;code&gt;NewsletterSignUpTest&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the newly created class file, write a simple Selenium WebDriver test. Here’s an example script that opens one of my frontend projects in a web browser.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.WebDriver&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.openqa.selenium.chrome.ChromeDriver&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;NewsletterSignUpTest&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;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&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="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Setup WebDriver&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"webdriver.chrome.driver"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"C:\\Selenium WebDriver Chrome\\chromedriver-win64\\chromedriver.exe"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&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;ChromeDriver&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Navigate to the page&lt;/span&gt;
        &lt;span class="n"&gt;driver&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;"https://time-tracking-dashboard-challenge-sooty.vercel.app/"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Maximize the browser window&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;window&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;fullscreen&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;


        &lt;span class="c1"&gt;// Wait for 4 seconds before closing the browser&lt;/span&gt;
        &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;//close the browser&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quit&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; In the script above, replace &lt;code&gt;C:\\Selenium WebDriver Chrome\\chromedriver-win64\\chromedriver.exe&lt;/code&gt; with the path to the ChromeDriver executable on your machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Run the test script.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; If everything is set up correctly, this script should open a webpage in the Chrome browser and then close it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Writing the Test Script for the &lt;code&gt;NewsletterSignUp&lt;/code&gt; website
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository Link:&lt;/strong&gt; &lt;a href="https://github.com/ikitamalarose/newsletter-sign-up-with-success-message-challenge.git" rel="noopener noreferrer"&gt;NewsletterSignUp_Repository&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Below is the code for the &lt;code&gt;NewsletterSignUpTest&lt;/code&gt; class we created earlier:&lt;/strong&gt;&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;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.By&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.openqa.selenium.WebDriver&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.openqa.selenium.WebElement&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.openqa.selenium.chrome.ChromeDriver&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;java.util.logging.Level&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;java.util.logging.Logger&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;NewsletterSignUpTest&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;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&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="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// Initialize logger for logging test results&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="no"&gt;LOGGER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NewsletterSignUpTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&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="c1"&gt;// Setup WebDriver&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"webdriver.chrome.driver"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"C:\\Selenium WebDriver Chrome\\chromedriver-win64\\chromedriver.exe"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&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;ChromeDriver&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Navigate to the page&lt;/span&gt;
            &lt;span class="n"&gt;driver&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;"https://newsletter-sign-up-with-success-message-challenge-tau.vercel.app/"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Maximize the browser window&lt;/span&gt;
            &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;window&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;fullscreen&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

            &lt;span class="c1"&gt;// Wait for 5 seconds to observe the initial state&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Find the email input field and submit button&lt;/span&gt;
            &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;emailInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;submitButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"btnSubmit"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

            &lt;span class="c1"&gt;// Test invalid email submission&lt;/span&gt;
            &lt;span class="n"&gt;emailInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid-email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;submitButton&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="c1"&gt;// Wait for 4 seconds to observe the error message&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Verify the error message is displayed&lt;/span&gt;
            &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;errorEmailMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error-email"&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errorEmailMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getText&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="s"&gt;"Email is not in a valid format"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid email test passed!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;severe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid email test failed! Error message: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Test valid email submission&lt;/span&gt;
            &lt;span class="n"&gt;emailInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;emailInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validemail@example.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;submitButton&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="c1"&gt;// Wait for 4 seconds to observe the success message&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Verify the success message is displayed&lt;/span&gt;
            &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;successMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"card-success-message"&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;successMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisplayed&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Valid email test passed!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;severe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Valid email test failed!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;


            &lt;span class="c1"&gt;// Verify the success email is correct&lt;/span&gt;
            &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;successEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user-email"&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;displayedEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;successEmail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getText&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="s"&gt;"validemail@example.com"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;displayedEmail&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Success email test passed!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;severe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Success email test failed! Displayed email: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;displayedEmail&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;


            &lt;span class="c1"&gt;// Test dismissing the success message&lt;/span&gt;
            &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;dismissButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"btnDismissMessage"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;dismissButton&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="c1"&gt;// Wait for 4 seconds to observe the state after dismissing the success message&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Verify the sign-up form is displayed again&lt;/span&gt;
            &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;signUpForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"card-sign-up"&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;signUpForm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisplayed&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dismiss message test passed!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;severe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dismiss message test failed!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;


            &lt;span class="c1"&gt;// Wait for 6 seconds before closing the browser&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Log interrupted exception&lt;/span&gt;
            &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Level&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SEVERE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Interrupted exception occurred"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Close the browser&lt;/span&gt;
            &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quit&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;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; In the script above, replace &lt;code&gt;C:\\Selenium WebDriver Chrome\\chromedriver-win64\\chromedriver.exe&lt;/code&gt; with the path to the ChromeDriver executable on your machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Explanation of the Test Script for the &lt;code&gt;NewsletterSignUp&lt;/code&gt; Website
&lt;/h2&gt;

&lt;p&gt;To better understand how the Selenium WebDriver test script for the newsletter sign-up form works, we will examine each part of the code and explain its role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebDriver Initialization and Configuration&lt;/strong&gt;&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="c1"&gt;// Setup WebDriver&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"webdriver.chrome.driver"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C:\\Selenium WebDriver Chrome\\chromedriver-win64\\chromedriver.exe"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&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;ChromeDriver&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This part of the code initializes and configures the WebDriver to use ChromeDriver.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;java System.setProperty&lt;/code&gt; sets the path to the ChromeDriver executable on your machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;WebDriver driver = new ChromeDriver();&lt;/code&gt; creates a new instance of ChromeDriver, which is used to interact with the Chrome browser.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bloc Try-Catch&lt;/strong&gt;&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;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Selenium test code&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle interrupted exceptions&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Level&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SEVERE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Interrupted exception occurred"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle other unexpected exceptions&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Level&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SEVERE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"An unexpected exception occurred"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Close the browser at the end of the test&lt;/span&gt;
    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quit&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;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;try-catch&lt;/code&gt;block surrounds the Selenium test code. It captures and handles exceptions that may occur during the test execution. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;InterruptedException&lt;/code&gt; is specifically handled for interruptions during the use of &lt;code&gt;Thread.sleep()&lt;/code&gt;, while &lt;code&gt;Exception&lt;/code&gt; handles all other unexpected exceptions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;finally&lt;/code&gt; block ensures that the browser is closed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Navigation and Interaction with Page Elements&lt;/strong&gt;&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="c1"&gt;// Navigate to the form page&lt;/span&gt;
&lt;span class="n"&gt;driver&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;"https://newsletter-sign-up-with-success-message-challenge-tau.vercel.app/"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Maximize the browser window&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;window&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;fullscreen&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;driver.get()&lt;/code&gt;Navigates to the specified URL where the newsletter sign-up form is located.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;driver.manage().window().fullscreen()&lt;/code&gt;Maximizes the browser window for better visibility and interaction during testing&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Locate page elements&lt;/span&gt;
&lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;emailInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;submitButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"btnSubmit"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;driver.findElement(By.id("email"))&lt;/code&gt; and &lt;code&gt;driver.findElement(By.id("btnSubmit"))&lt;/code&gt; locate the page elements with the IDs &lt;code&gt;email&lt;/code&gt; (email input field) et &lt;code&gt;btnSubmit&lt;/code&gt; (form submission button).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Submitting Invalid Email&lt;/strong&gt;&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="c1"&gt;//Submit invalid email&lt;/span&gt;
&lt;span class="n"&gt;emailInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid-email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;submitButton&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;emailInput.sendKeys("invalid-email")&lt;/code&gt; enters an invalid email into the email field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;submitButton.click()&lt;/code&gt; clicks the Submit button to submit the form with the invalid email.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verifying Messages&lt;/strong&gt;&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="c1"&gt;// Check for the error message display&lt;/span&gt;
&lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;errorEmailMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error-email"&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errorEmailMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getText&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="s"&gt;"Email is not in a valid format"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid email test passed!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;severe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid email test failed! Error message: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;errorMessage&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;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;driver.findElement(By.id("error-email"))&lt;/code&gt; locates the page element that displays the error message for an invalid email.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;errorEmailMessage.getText()&lt;/code&gt; retrieves the text of the error message. The test checks if the expected error message is displayed and logs the result.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GitHub Project
&lt;/h2&gt;

&lt;p&gt;For more practice, here’s the GitHub project that contains test scripts for the mini-projects written in JavaScript:.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Newsletter sign-up form with success message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Time tracking dashboard.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Repository URL
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/ikitamalarose/SeliniumWebDriverTestsLogiciels.git" rel="noopener noreferrer"&gt;Selinium_WebDriver_TestLogiciels_GitHub_Repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Please read the &lt;code&gt;README.md&lt;/code&gt; file for details about this project.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>java</category>
      <category>selenium</category>
      <category>testing</category>
    </item>
    <item>
      <title>Petite historique du langage Java</title>
      <dc:creator>Melia Log</dc:creator>
      <pubDate>Thu, 04 Jul 2024 13:50:49 +0000</pubDate>
      <link>https://forem.com/melialog/petite-historique-du-langage-java-3l9a</link>
      <guid>https://forem.com/melialog/petite-historique-du-langage-java-3l9a</guid>
      <description>&lt;p&gt;EN 1991, des ingénieurs de &lt;code&gt;Sun Microsystems&lt;/code&gt;, regroupés en une équipe appelée &lt;code&gt;équipe verte&lt;/code&gt; composée de:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;James Gosling&lt;/li&gt;
&lt;li&gt;Mike Sheridan&lt;/li&gt;
&lt;li&gt;Patrick Naughton&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;décident de créer Java mais, sous forme d'un projet nommé "Oak" mais celui-ci fut un échec.&lt;br&gt;
Par la suite Bill Joy ( cofondateur de la firme &lt;code&gt;Sun Microsystems&lt;/code&gt;) propose une nouvelle version appelée &lt;code&gt;Java&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Pourquoi?:&lt;br&gt;
Les ingénieurs cherchaient a concevoir un langage applicable à des petits appareils électriques ( on parle là de &lt;code&gt;code embarqué&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Procédé:&lt;br&gt;
Ils se sont basés sur une syntaxe proche du langage C++, en reprenant le concept de la machine virtuelle déjà exploité auparavant par le Pascal UCSD.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Idée:&lt;br&gt;
L'idée consistait d'abord à traduire un programme source, non pas directement en langage machine mais, dans un pseudo langage universel disposant des fonctionnalités communes à toutes les machines ( notion de &lt;code&gt;portabilité&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ce code intermédiaire, appelé &lt;code&gt;bytecode&lt;/code&gt;, se trouve ainsi compact et portable sur n'importe quelle machine, à condition que celle-ci dispose d'un programme approprié (machine virtuelle) permettant de l'interpréter dans un langage compréhensible par la machine concernée.&lt;/p&gt;

&lt;h2&gt;
  
  
  Définitions de mots clés:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sun Microsystems&lt;/strong&gt;:&lt;br&gt;
Était un constructeur d'ordinateurs et éditeur de logiciels américain, racheté par Oracle Corporation le &lt;code&gt;20 Avril 2009&lt;/code&gt; pour 7,4 milliards de dollars.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Notion de portabilité&lt;/strong&gt;:&lt;br&gt;
La portabilité d'un langage de programmation signifie que le code écrit dans ce langage peut être exécuté sur différentes plateformes et architectures sans nécessiter de modifications majeures.&lt;br&gt;
C'est un aspect essentiel des langages de haut niveau comme le C, Java ou Python qui permettent aux développeurs de créer des applications multiplateformes plus facilement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bytecode&lt;/strong&gt;:&lt;br&gt;
Le bytecode est une représentation intermédiaire d'un programme source, souvent générée par des langages de programmation comme Java ou Python.&lt;br&gt;
Contrairement au code source écrit par le développeur, le bytecode n'est pas directement exécutable par le processeur de l'ordinateur. &lt;br&gt;
Il est plutôt destiné à être exécuté par une &lt;strong&gt;machine virtuelle&lt;/strong&gt; (VM), telle que la Java Virtual Machine (JVM) pour Java ou la Python Virtual Machine (PVM) pour Python.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Quelques points supplémentaires pour l'exactitude historique et la clarté :
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Java a été officiellement lancé par Sun Microsystems en 1995.&lt;/li&gt;
&lt;li&gt;Oak a été renommé Java en raison d'un conflit de nom avec une autre technologie existante.&lt;/li&gt;
&lt;li&gt;Java a été conçu avec la philosophie "&lt;strong&gt;&lt;em&gt;write once, run anywhere&lt;/em&gt;&lt;/strong&gt;" (écrire une fois, exécuter partout).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>java</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
