<?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>DEV Community: Vinh Nhan</title>
    <description>The latest articles on DEV Community by Vinh Nhan (@vinhyan).</description>
    <link>https://dev.to/vinhyan</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%2F1084526%2Fa418c33f-d4cb-403d-96cf-86ccfa7ded41.jpeg</url>
      <title>DEV Community: Vinh Nhan</title>
      <link>https://dev.to/vinhyan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vinhyan"/>
    <language>en</language>
    <item>
      <title>Contributing to Open Source: Part 3 - Adopting a New Project and Final Reflections</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Wed, 11 Dec 2024 19:36:44 +0000</pubDate>
      <link>https://dev.to/vinhyan/contributing-to-open-source-part-3-adopting-a-new-project-and-final-reflections-37e3</link>
      <guid>https://dev.to/vinhyan/contributing-to-open-source-part-3-adopting-a-new-project-and-final-reflections-37e3</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;If you are new here, be sure to check out the &lt;a href="https://dev.to/vinhyan/contributing-to-open-source-part-1-the-planning-stage-300o"&gt;first&lt;/a&gt; and &lt;a href="https://dev.to/vinhyan/contributing-to-open-source-part-2-progress-update-22je"&gt;second&lt;/a&gt; blog of this series, where I discuss the planning stages and progress updates of my open source project contributions.&lt;/p&gt;

&lt;p&gt;After facing several hurdles with my initial project, &lt;em&gt;Clean and Green Philly&lt;/em&gt;, I’ve decided to pivot to another exciting open-source initiative: &lt;em&gt;&lt;a href="https://github.com/NirmalScaria/le-git-graph" rel="noopener noreferrer"&gt;Le Git Graph&lt;/a&gt;&lt;/em&gt;. This change was inspired by my friend Peter Wan, and I’m thrilled to document my contributions to this new project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview: Le Git Graph
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Le Git Graph&lt;/strong&gt; is a browser extension that adds a "Commits" tab to GitHub’s navigation bar, displaying a colorful commit history graph for any repository. As a developer and visual learner, this tool resonates with me—it provides an intuitive way to track a project’s progress and workflow.&lt;/p&gt;

&lt;p&gt;What excites me most is that this is my first time working on a browser extension. It’s a great opportunity to expand my technical skill set and contribute to a tool that enhances the developer experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/NirmalScaria/le-git-graph/issues/81" rel="noopener noreferrer"&gt;Issue 81&lt;/a&gt;: Disappearing Commit Button
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt;&lt;br&gt;
The "Commits" button, added by the extension, disappears after navigating to certain subsections of GitHub (e.g., creating a new issue). To make it reappear, users must refresh the page, disrupting their workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Investigation and Solution
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Initial Findings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code in &lt;code&gt;main.js&lt;/code&gt;, which adds the "Commits" button, executes only on the initial page load.&lt;/li&gt;
&lt;li&gt;GitHub operates as a Single Page Application (SPA), so navigating within the site doesn’t trigger a full page reload. This causes the button to disappear as the URL changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Proposed Solution:&lt;/strong&gt;&lt;br&gt;
To ensure the button remains visible and functional, I implemented a solution to dynamically observe URL changes and re-add the button when necessary.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observing URL Changes:&lt;/strong&gt;&lt;br&gt;
I used a &lt;code&gt;MutationObserver&lt;/code&gt; to detect DOM changes and identify when the URL changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reattaching Click Events:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The button’s click event wasn’t working after navigation because new events were being added without removing the old ones, causing conflicts.&lt;/li&gt;
&lt;li&gt;I fixed this by removing any existing click events before reattaching them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fallback for Missing Elements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Certain GitHub tabs, like "Actions" and "Wiki," don’t contain the &lt;code&gt;clearfix&lt;/code&gt; element used in the original code.&lt;/li&gt;
&lt;li&gt;I added a fallback using the &lt;code&gt;PageLayout&lt;/code&gt; class, ensuring compatibility across all tabs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Handling Browser Back Button:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The back button posed a unique challenge. Although the button remained visible, its event listener wasn’t reattached.&lt;/li&gt;
&lt;li&gt;I resolved this by clearing the button’s attributes and events before reinitializing it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Results and Reflections
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Achieving My Goals
&lt;/h3&gt;

&lt;p&gt;Although my original plans with &lt;em&gt;Clean and Green Philly&lt;/em&gt; didn’t materialize due to delays and lack of updates, transitioning to &lt;em&gt;Le Git Graph&lt;/em&gt; allowed me to stay productive and achieve meaningful contributions. This experience highlights the importance of having a backup project to pivot to when initial plans don’t go as expected. Flexibility and adaptability are critical in open-source work.&lt;/p&gt;

&lt;p&gt;With &lt;em&gt;Le Git Graph&lt;/em&gt;, I achieved my goal of addressing a significant usability issue and making the extension more robust. My contributions ensure that the "Commits" button behaves consistently across various GitHub tabs and scenarios, providing a smoother user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I Built the Solution
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technical Features:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Utilized &lt;code&gt;MutationObserver&lt;/code&gt; to monitor DOM changes dynamically.&lt;/li&gt;
&lt;li&gt;Implemented logic to clear existing event listeners and attributes to avoid conflicts when reattaching events.&lt;/li&gt;
&lt;li&gt;Added fallback mechanisms for missing elements to ensure cross-tab compatibility.&lt;/li&gt;
&lt;li&gt;Accounted for browser back button behavior to reinitialize the button seamlessly.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Methods:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Incremental debugging and testing.&lt;/li&gt;
&lt;li&gt;Researching GitHub’s DOM structure and understanding SPA challenges.&lt;/li&gt;
&lt;li&gt;Iterative improvements to refine the solution.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Here's a demo of my solution:&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%2Fuixnc0cpqxplbbvq26w2.gif" 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%2Fuixnc0cpqxplbbvq26w2.gif" alt="lgg-pr-88" width="600" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out my pull request &lt;a href="https://github.com/NirmalScaria/le-git-graph/pull/88" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technical Growth:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Working on a browser extension introduced me to tools and concepts I hadn’t used before, such as handling SPAs and dynamic DOM updates.&lt;/li&gt;
&lt;li&gt;Debugging in a live environment required a meticulous approach and patience.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Problem-Solving Approach:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Breaking down issues into smaller tasks made them manageable and less overwhelming.&lt;/li&gt;
&lt;li&gt;Adapting to unforeseen challenges strengthened my problem-solving skills.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Importance of Backup Plans:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Having a secondary project ensured I could continue contributing without losing momentum when obstacles arose with the first project.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Leveraging the Community
&lt;/h3&gt;

&lt;p&gt;Engaging with the open-source community was invaluable. I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reviewed existing issues and discussions to gain context.&lt;/li&gt;
&lt;li&gt;Shared my findings and sought feedback from maintainers and other contributors.&lt;/li&gt;
&lt;li&gt;Learned from similar issues and solutions in other projects, broadening my knowledge base.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;Working on &lt;em&gt;Le Git Graph&lt;/em&gt; has been a rewarding experience. Moving forward, I plan to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Continue refining the extension and exploring other open issues.&lt;/li&gt;
&lt;li&gt;Leverage this experience to contribute to more browser extension projects.&lt;/li&gt;
&lt;li&gt;Share what I’ve learned to inspire others to explore open-source contributions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This blog also wraps up my series on open source contributions. If you’ve made it this far, thank you! ✌️&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Contributing to Open Source: Part 2 - Progress Update</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Wed, 11 Dec 2024 18:58:19 +0000</pubDate>
      <link>https://dev.to/vinhyan/contributing-to-open-source-part-2-progress-update-22je</link>
      <guid>https://dev.to/vinhyan/contributing-to-open-source-part-2-progress-update-22je</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;Check out the first blog of this series &lt;a href="https://dev.to/vinhyan/contributing-to-open-source-part-1-the-planning-stage-300o"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the second part of my open source journey, I’ll provide an update on my contributions to &lt;em&gt;&lt;a href="https://github.com/CodeForPhilly/clean-and-green-philly" rel="noopener noreferrer"&gt;Clean and Green Philly&lt;/a&gt;&lt;/em&gt;. This post covers my progress, challenges, and lessons learned so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/CodeForPhilly/clean-and-green-philly/issues/1024" rel="noopener noreferrer"&gt;Issue 1024&lt;/a&gt;: Filter Scrolling Bug
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; When applying a filter, the interface scrolls to the top of the filter list, breaking user concentration. Users should remain in their previous scroll position for a smoother experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Investigation and Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After investigating, I found that React’s re-rendering behavior (triggered by state updates) causes the scroll position to reset.&lt;/li&gt;
&lt;li&gt;My approach was to save the previous scroll position (&lt;code&gt;scrollTop&lt;/code&gt;) when a filter is applied and restore it after the component re-renders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This solution works but has a minor drawback: the UI briefly scrolls to the top before returning to the saved position, creating a flashy effect. To address this, I’m considering implementing a smoother animation using Framer Motion, as it’s already part of the project’s toolset.&lt;/p&gt;

&lt;p&gt;Here's a demo of what my solution looks like:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1kggt3oy7b4d8hodz18b.gif" 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%2F1kggt3oy7b4d8hodz18b.gif" alt="issue-1024-solution" width="600" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Current Challenge:&lt;/strong&gt;&lt;br&gt;
While attempting to commit and push my changes, I encountered a separate issue (Issue 1038) that has blocked my progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/CodeForPhilly/clean-and-green-philly/issues/1038" rel="noopener noreferrer"&gt;Issue 1038&lt;/a&gt;: Dependency Vulnerability
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; A cross-spawn vulnerability in the dependency tree prevents code commits. Specifically, the project uses &lt;code&gt;@semantic-release/npm&lt;/code&gt;, which has a dependency on an outdated version of &lt;code&gt;npm&lt;/code&gt; that includes &lt;code&gt;cross-spawn@7.0.3&lt;/code&gt;, a vulnerable package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Investigation and Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The root cause lies in the &lt;code&gt;package-lock.json&lt;/code&gt; file, which locks the vulnerable version of &lt;code&gt;cross-spawn&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;My proposed solution is to update all dependencies and regenerate the lockfile. Since manually editing the lockfile is not recommended, I attempted it cautiously, confirming that &lt;code&gt;npm&lt;/code&gt; is the only dependency of &lt;code&gt;@semantic-release/npm&lt;/code&gt;. This workaround allowed me to resolve the issue locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Current Challenge:&lt;/strong&gt;&lt;br&gt;
I’ve shared my findings and proposed solution with the maintainers, but I’m awaiting feedback to confirm the best course of action before proceeding.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/CodeForPhilly/clean-and-green-philly/issues/927" rel="noopener noreferrer"&gt;Issue 927&lt;/a&gt;: Creating a Stakeholder Outreach Page
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; External stakeholders need an efficient way to reach out to the team. The proposed solution is a contact page that collects data via a Google Form linked to a Google Sheet. This eliminates the need for a backend.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;The UX/UI team is working on mockups for the page.&lt;/li&gt;
&lt;li&gt;Despite my follow-ups over the past three weeks, I’ve not yet received the final mockups. The most recent update from the team was last weekend (Dec 7-8), but no tangible progress has been shared so far.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Reflections and Lessons Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technical Challenges:&lt;/strong&gt; Investigating bugs and dependency issues has deepened my understanding of React’s rendering behavior and dependency management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration:&lt;/strong&gt; The delay in receiving mockups underscores the importance of clear communication and realistic timelines when collaborating with cross-functional teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Interaction:&lt;/strong&gt; While awaiting responses from maintainers, I’ve realized the value of patience and persistence in open-source contributions.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Despite the hurdles, I’m determined to meet my goals. In the next post, I’ll share how I adapt my approach to overcome these challenges and reflect on the overall experience of contributing to &lt;em&gt;Clean and Green Philly&lt;/em&gt;. Stay tuned for Part 3!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Contributing to Open Source: Part 1 - The Planning Stage</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Wed, 04 Dec 2024 22:13:38 +0000</pubDate>
      <link>https://dev.to/vinhyan/contributing-to-open-source-part-1-the-planning-stage-300o</link>
      <guid>https://dev.to/vinhyan/contributing-to-open-source-part-1-the-planning-stage-300o</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;As I embark on my journey of contributing to open-source projects, I’m excited to document my experience in this three-part blog series. This first post focuses on choosing a meaningful project, planning my contributions, setting clear goals, and laying out a roadmap for success. I’ll be working with &lt;em&gt;&lt;a href="https://github.com/CodeForPhilly/clean-and-green-philly" rel="noopener noreferrer"&gt;Clean and Green Philly&lt;/a&gt;&lt;/em&gt;, an initiative dedicated to transforming Philadelphia by greening and cleaning vacant and abandoned parcels—a powerful strategy to reduce gun violence and foster community well-being.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Plan to Do
&lt;/h2&gt;

&lt;p&gt;My primary goal for this phase is to address front-end bugs or enhancements in the project. Specifically, I’ll:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Investigate and resolve existing issues:&lt;/strong&gt; Dive into the GitHub repository to identify front-end problems that require attention.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Work on new feature requests:&lt;/strong&gt; One notable feature request is creating an &lt;a href="https://github.com/CodeForPhilly/clean-and-green-philly/issues/927" rel="noopener noreferrer"&gt;outreach/contact us page&lt;/a&gt;, which will streamline communication between stakeholders and the project team. This page will make it easier for community members and partners to connect with the initiative.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why I Am Choosing This Work and Project
&lt;/h2&gt;

&lt;p&gt;I’ve chosen this project because it aligns with my values and offers a meaningful opportunity to contribute to social impact. The work being done by &lt;em&gt;Clean and Green Philly&lt;/em&gt; goes beyond technology—it’s about fostering safer neighbourhoods and creating spaces that inspire hope and resilience. Being part of such a transformative initiative motivates me to bring my best effort to this contribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Will Approach It
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identify opportunities:&lt;/strong&gt; I’ll regularly check the project’s GitHub repository for open issues, enhancements, or new proposals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thorough investigation:&lt;/strong&gt; For each issue or feature request, I’ll take time to understand the problem deeply by reviewing documentation, code, and stakeholder feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration:&lt;/strong&gt; Since the contact us page involves cross-functional teams such as UX/UI designers, I’ll communicate and coordinate with relevant departments, and gather requirements to ensure the final product meets expectations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterative development:&lt;/strong&gt; I’ll adopt an agile mindset, delivering smaller milestones and gathering feedback throughout the process to refine the work.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What I Hope to Achieve
&lt;/h2&gt;

&lt;p&gt;Through this phase, I aim to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhance my technical skills by working on real-world front-end development challenges.&lt;/li&gt;
&lt;li&gt;Develop soft skills such as collaboration and project management by engaging with different teams.&lt;/li&gt;
&lt;li&gt;Make a tangible contribution to a project that improves lives and communities in Philadelphia.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By setting clear goals and committing to a structured approach, I’m setting myself up for success. I’m eager to see the positive difference I can make through my work and look forward to the learning experiences along the way.&lt;/p&gt;




&lt;p&gt;If you made it this far, thank you! And stay tuned for part 2 and 3! ✌️&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Fixing Sorting and Visibility Issues: A Development Diary in Open Source Projects</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Fri, 29 Nov 2024 23:49:47 +0000</pubDate>
      <link>https://dev.to/vinhyan/fixing-sorting-and-visibility-issues-a-development-diary-in-open-source-projects-8ai</link>
      <guid>https://dev.to/vinhyan/fixing-sorting-and-visibility-issues-a-development-diary-in-open-source-projects-8ai</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/FreiFahren/FreiFahren" rel="noopener noreferrer"&gt;Freifahren&lt;/a&gt; and &lt;a href="https://github.com/numerique-gouv/impress" rel="noopener noreferrer"&gt;Impress&lt;/a&gt; are two exciting projects I’ve been working on. Recently, I had the opportunity to address two critical issues: sorting station names in the ReportForm for Freifahren and reordering visibility options in the dropdown menu for Impress. Below is a breakdown of the challenges, solutions, and lessons learned along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Freifahren: Fix Sorting Order of Stations in ReportForm
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;In the ReportForm, station names were being sorted alphabetically by their IDs, rather than by their names. This caused confusion, as station names are a more intuitive way for users to locate entries. &lt;a href="https://github.com/FreiFahren/FreiFahren/issues/300" rel="noopener noreferrer"&gt;Issue 300&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenges Encountered
&lt;/h3&gt;

&lt;p&gt;During the process, I faced a few challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Missing Environment Variables&lt;/strong&gt;: The &lt;code&gt;RISK_API_URL&lt;/code&gt; was required during backend setup, but its purpose wasn’t clearly documented.&lt;/p&gt;

&lt;p&gt;After consulting with the maintainer, I learned that the variable is related to a microservice for calculating risk. Since it wasn’t necessary for this task, I could safely ignore it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Content Moderation Microservice&lt;/strong&gt;: Submitting a report involved hate speech detection using the &lt;code&gt;CONTENT_MODERATION_SERVICE_URL&lt;/code&gt;. Without it, the &lt;code&gt;PostInspector&lt;/code&gt; route returned an Internal Server Error.&lt;/p&gt;

&lt;p&gt;The maintainer clarified that I could access the service at &lt;code&gt;http://88.99.56.234:9090&lt;/code&gt; or run it locally using the provided &lt;a href="https://github.com/FreiFahren/FreiFahren/tree/main/packages/hate_speech_filter" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Misunderstanding the Issue&lt;/strong&gt;: Initially, I thought the sorting issue was in the ReportsModal, but the maintainer clarified it was actually in the ReportForm.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;Once I was set up, I implemented the following changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pre-Sorted Stations&lt;/strong&gt;: The &lt;code&gt;possibleStations&lt;/code&gt; list in the ReportForm is now pre-sorted by name using &lt;code&gt;sortedAllStations&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Sorting&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Stations under a selected &lt;code&gt;currentLine&lt;/code&gt; are now sorted dynamically from &lt;code&gt;allLines&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Searches and selections from &lt;code&gt;currentEntity&lt;/code&gt; use the pre-sorted &lt;code&gt;sortedAllStations&lt;/code&gt; list.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These changes ensure that stations are displayed in a user-friendly order, improving the report submission experience.&lt;/p&gt;

&lt;p&gt;The fix was submitted in &lt;a href="https://github.com/FreiFahren/FreiFahren/pull/320" rel="noopener noreferrer"&gt;Pull Request #320&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Impress: Reorder Visibility Options in Dropdown Menu
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;In Impress, the visibility options in a dropdown menu were not ordered logically, which made the selection process unintuitive. Users expected a progression from the most restrictive to the least restrictive option. &lt;a href="https://github.com/numerique-gouv/impress/issues/397" rel="noopener noreferrer"&gt;Issue 397&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Proposed Solution
&lt;/h3&gt;

&lt;p&gt;The expected order was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Restricted&lt;/li&gt;
&lt;li&gt;Authenticated&lt;/li&gt;
&lt;li&gt;Public&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This change was implemented in the &lt;code&gt;LinkReach&lt;/code&gt; component, located at &lt;code&gt;src/frontend/apps/impress/src/features/docs/doc-management/types.tsx&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;By reordering the options in the type definition, the dropdown menu’s display order was updated across the application. This simple change greatly improved the usability of the menu.&lt;/p&gt;

&lt;p&gt;The updated logic was submitted in &lt;a href="https://github.com/suitenumerique/docs/pull/441" rel="noopener noreferrer"&gt;Pull Request #441&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clear Documentation is Crucial&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Having clear, comprehensive, and well-organized documentation can significantly streamline the development process. It helps new contributors quickly get up to speed and reduces the potential for misunderstandings or delays.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Communication is Key&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Regular discussions with project maintainers ensured that I was aligned with the team’s goals and expectations, making the development process smoother.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Small Changes Have a Big Impact&lt;/strong&gt;:&lt;br&gt;
Fixes like sorting station names and reordering dropdown options may seem minor, but they have a significant effect on user experience and interface intuitiveness.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;These updates in both Freifahren and Impress demonstrate how small changes can have a big impact on usability. The process highlighted the importance of clear documentation and effective communication within open-source communities. By addressing these issues, we've made the systems more intuitive and easier to use, paving the way for smoother interactions in the future.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Choosing npm for Release Management</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Sat, 23 Nov 2024 04:43:43 +0000</pubDate>
      <link>https://dev.to/vinhyan/choosing-npm-for-release-management-5047</link>
      <guid>https://dev.to/vinhyan/choosing-npm-for-release-management-5047</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;When it came time to choose a release tool and package registry for my project, I opted for &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;npm&lt;/a&gt;. Its ubiquity, ease of use, and integration with modern CI/CD workflows made it the ideal choice for my needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Release: Step-by-Step Process
&lt;/h2&gt;

&lt;p&gt;Here’s a detailed breakdown of the steps I took to create a release with npm for my project &lt;a href="https://github.com/vinhyan/barrierless" rel="noopener noreferrer"&gt;Barrierless&lt;/a&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Set Up an npm Account and Token
&lt;/h3&gt;

&lt;p&gt;First, I created an account on &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;npm&lt;/a&gt;. After logging into my account, I generated an npm token from my profile settings. This token is crucial for authenticating with npm during the release process.&lt;/p&gt;

&lt;p&gt;I then stored this token in my project’s GitHub repository under &lt;strong&gt;Settings &amp;gt; Secrets and variables &amp;gt; Actions &amp;gt; New repository secret&lt;/strong&gt;, using the key &lt;code&gt;NPM_TOKEN&lt;/code&gt;. This ensures that my GitHub Actions workflows can securely access the token without exposing it publicly.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Configure a GitHub CD Pipeline
&lt;/h3&gt;

&lt;p&gt;Next, I created a GitHub Actions pipeline file, &lt;code&gt;cd.yml&lt;/code&gt;, in the &lt;code&gt;.github/workflows/&lt;/code&gt; directory. This file automates the release process. Here's a simplified example of what the pipeline might look like:&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CD Pipeline&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;created&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&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;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&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;Set up Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;16'&lt;/span&gt;
          &lt;span class="na"&gt;registry-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://registry.npmjs.org/'&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;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&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;Publish to npm&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;NODE_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.NPM_TOKEN }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm publish&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Prepare the Release
&lt;/h3&gt;

&lt;p&gt;After making updates to my project, I:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Staged and committed my changes:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git add &lt;span class="nb"&gt;.&lt;/span&gt;
   git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Prepare for release"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Created a new version tag using npm:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;p&gt;This automatically updates the version in &lt;code&gt;package.json&lt;/code&gt; and creates a corresponding Git tag.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pushed everything to the remote repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git push origin main &lt;span class="nt"&gt;--tags&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Create a GitHub Release
&lt;/h3&gt;

&lt;p&gt;On GitHub, I navigated to &lt;strong&gt;Releases&lt;/strong&gt;, clicked &lt;strong&gt;Draft a new release&lt;/strong&gt;, and selected the tag for the latest version. After providing a description, I published the release. This action triggered the CD pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Verify the Release
&lt;/h3&gt;

&lt;p&gt;Once the pipeline completed successfully, my package was published to npm and ready for users to install.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Aha!" Moment: Missing &lt;code&gt;NPM_TOKEN&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Initially, my pipeline failed with an error stating that &lt;code&gt;NPM_TOKEN&lt;/code&gt; was missing. This was because I hadn’t set up the GitHub secret correctly. Once I added the secret, the pipeline ran smoothly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iteration and Debugging
&lt;/h3&gt;

&lt;p&gt;I had to iterate several times to get the process right. Determining the correct order of steps and ensuring all dependencies were properly configured took some trial and error. For example, I forgot to remove extraneous &lt;code&gt;console.log&lt;/code&gt; statements from test cases during my first release, which caused confusion during user testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  User Testing
&lt;/h2&gt;

&lt;p&gt;I asked my buddy, &lt;a href="https://github.com/peterdanwan" rel="noopener noreferrer"&gt;Peter Wan&lt;/a&gt;, to test my CLI tool by installing it directly from the npm registry. Initially, he encountered unexpected &lt;code&gt;console.log&lt;/code&gt; outputs. After fixing this issue and publishing a new release, Peter successfully tested the updated version.&lt;/p&gt;

&lt;p&gt;This exercise reinforced the importance of thorough testing and cleanup before publishing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing and Using the Project
&lt;/h2&gt;

&lt;p&gt;Now that the project is released, users can install it directly from npm. Here’s how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the package globally:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; barrierless
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Use the CLI tool:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Setting Up a GitHub Actions CI Workflow</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Thu, 14 Nov 2024 19:27:42 +0000</pubDate>
      <link>https://dev.to/vinhyan/setting-up-a-github-actions-ci-workflow-206i</link>
      <guid>https://dev.to/vinhyan/setting-up-a-github-actions-ci-workflow-206i</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;When it comes to managing code quality and testing in a collaborative project, setting up Continuous Integration (CI) can be a game changer. GitHub Actions is one of the most popular choices for CI, offering simplicity, flexibility, and direct integration with GitHub repos. Here, I’ll walk you through my experience setting up a CI workflow with GitHub Actions, compare it with my partner’s setup, and share some insights on the challenges and benefits I encountered along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step: My CI Workflow on GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Setting up the CI workflow directly on GitHub was straightforward, thanks to the well-documented interface and ease of YAML configuration. In my setup, I configured the CI to run on every Pull Request or Push to &lt;strong&gt;all branches&lt;/strong&gt;. This means that any code change, whether it's a quick patch or a feature branch, is automatically tested as part of the CI workflow.&lt;/p&gt;

&lt;p&gt;My workflow consists of two main jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ESLint&lt;/strong&gt; - Linting helps catch syntax and formatting errors early, so the code is clean and consistent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unit Tests&lt;/strong&gt; - This job runs all unit tests to make sure that any new changes or additions do not break existing functionality.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/vinhyan/barrierless/blob/main/.github/workflows/node.js.yml" rel="noopener noreferrer"&gt;Here&lt;/a&gt;’s an example of what the YAML configuration for my CI workflow looks like.&lt;/p&gt;

&lt;p&gt;In this configuration, GitHub Actions triggers both ESLint and unit test jobs every time there’s a push or a pull request. The &lt;code&gt;eslint&lt;/code&gt; job makes sure that code follows our style guidelines, while &lt;code&gt;tests&lt;/code&gt; ensures that all tests pass successfully before the code is merged.&lt;/p&gt;

&lt;h2&gt;
  
  
  How My Partner's CI Workflow Differs
&lt;/h2&gt;

&lt;p&gt;While my setup triggers the CI on all branches, my partner &lt;strong&gt;brokoli777&lt;/strong&gt;'s &lt;a href="https://github.com/brokoli777/RefactorCode/blob/main/.github/workflows/node.js.yml" rel="noopener noreferrer"&gt;CI&lt;/a&gt;, has a different approach. His CI workflow only triggers on the &lt;strong&gt;main branch&lt;/strong&gt; and runs &lt;strong&gt;only unit tests&lt;/strong&gt;. This setup is a bit more selective, ensuring that CI runs only when pushing final code to production. This approach could make sense for certain workflows, as it minimizes the frequency of CI runs, which could save resources and time. However, it also means that potential issues might go undetected on feature branches until they’re merged into the main branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Tests for a Partner’s Project
&lt;/h2&gt;

&lt;p&gt;Writing tests for a project I didn’t create had its challenges and rewards. Not being familiar with the full context of my partner’s code required me to spend more time understanding the existing structure and functionality. However, this experience also gave me a new perspective. Testing another person’s code helped me think critically about edge cases and develop a broader sense of good test coverage. It’s a valuable exercise in improving both collaboration skills and the quality of my own code as I apply similar scrutiny to my work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reflections on CI with GitHub Actions
&lt;/h3&gt;

&lt;p&gt;Setting up CI has been a highly educational process. Seeing my workflow in action, especially with the ESLint addition (one of the optional challenges), highlighted just how useful CI can be for improving code quality and maintaining consistency across contributions. When I first implemented ESLint, many of my pushes and PRs failed because of minor errors like unused variables. While this was frustrating initially, it underscored the value of having a tool that catches these issues early. By enforcing linting through CI, all contributors are encouraged to follow a unified coding style, making the codebase more cohesive and easier to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: The Value of CI
&lt;/h2&gt;

&lt;p&gt;Implementing a CI workflow with GitHub Actions has been a transformative step in my development process. Not only does it help ensure that all code adheres to quality standards before merging, but it also reduces the potential for human error. From handling new feature branches to enforcing code consistency with ESLint, CI has become an essential part of my workflow, and I look forward to leveraging it even more in future projects.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Guide to Setting Up Jest for JavaScript Testing with ESM</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Tue, 12 Nov 2024 19:48:58 +0000</pubDate>
      <link>https://dev.to/vinhyan/a-guide-to-setting-up-jest-for-javascript-testing-with-esm-22m6</link>
      <guid>https://dev.to/vinhyan/a-guide-to-setting-up-jest-for-javascript-testing-with-esm-22m6</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;In this blog, I’ll walk through why I chose Jest as my testing framework, the detailed setup process, handling ESM module challenges, mocking, and environment variable management. By the end of this guide, you’ll have a clear approach to setting up Jest in projects using JavaScript with ESM.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My project repository: &lt;a href="https://github.com/vinhyan/barrierless" rel="noopener noreferrer"&gt;Barrierless&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Commit for testing: &lt;a href="https://github.com/vinhyan/barrierless/commit/4b8f1ddc1b65df213b665bab5db288c51ca025ff" rel="noopener noreferrer"&gt;4b8f1dd&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Jest?
&lt;/h2&gt;

&lt;p&gt;For JavaScript projects, &lt;strong&gt;&lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;Jest&lt;/a&gt;&lt;/strong&gt; is a robust testing framework, known for its rich feature set and smooth developer experience. Jest integrates well with JavaScript and Node.js applications, making it easy to write tests with features like automatic mocking and code coverage.&lt;/p&gt;

&lt;p&gt;Since Jest is one of the most popular testing frameworks for JavaScript, it has an active community, strong documentation, and compatibility with other popular tools. This support makes Jest an ideal choice for my project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Jest for an ESM-Based Project
&lt;/h2&gt;

&lt;p&gt;Setting up Jest for a project using ECMAScript Modules (ESM) presented some unique challenges. Jest was primarily designed for CommonJS (CJS), so a few additional steps are necessary to make it work smoothly with ESM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Install Jest
&lt;/h3&gt;

&lt;p&gt;To start, install Jest as a development dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Configure Jest for ESM
&lt;/h3&gt;

&lt;p&gt;Since Jest’s ESM support is still evolving, we need to use a special command to run Jest in ESM mode:&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;--experimental-vm-modules&lt;/span&gt; node_modules/jest/bin/jest.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Set Up &lt;code&gt;jest.config.js&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Next, create a &lt;code&gt;jest.config.js&lt;/code&gt; file to define Jest’s configuration. This setup cleans up mocks between tests, collects coverage data, and configures environment variables specifically for testing.&lt;/p&gt;

&lt;p&gt;Here’s my &lt;code&gt;jest.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** @type {import('jest').Config} */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;clearMocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;collectCoverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;coverageDirectory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;coverage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;setupFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;rootDir&amp;gt;/jest.setup.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// path to a setup module to configure the testing environment before each test&lt;/span&gt;
  &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="na"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;clearMocks&lt;/code&gt;&lt;/strong&gt;: Automatically resets all mocks between tests, ensuring a fresh state for each test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;collectCoverage&lt;/code&gt;&lt;/strong&gt;: Enables code coverage tracking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;coverageDirectory&lt;/code&gt;&lt;/strong&gt;: Specifies the output directory for coverage reports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;setupFiles&lt;/code&gt;&lt;/strong&gt;: Loads a setup file before tests, which is useful for setting environment variables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;verbose&lt;/code&gt;&lt;/strong&gt;: Provides detailed test output, helpful for debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Set Up Environment Variables for Tests
&lt;/h3&gt;

&lt;p&gt;To avoid using production environment variables in tests, I created a separate &lt;code&gt;env.jest&lt;/code&gt; file for testing environment variables. Then, I used &lt;code&gt;dotenv&lt;/code&gt; in Jest’s setup file to load these variables.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;env.jest&lt;/code&gt;&lt;/strong&gt; (for test environment variables):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   GROQ_API_KEY=
   GEMINI_API_KEY=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;jest.setup.js&lt;/code&gt;&lt;/strong&gt; (loads the variables):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;env.jest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling ESM-Specific Mocking Challenges in Jest
&lt;/h2&gt;

&lt;p&gt;Jest’s documentation primarily covers CommonJS, so ESM-specific details can be a bit sparse. Instead of &lt;code&gt;jest.mock()&lt;/code&gt;, ESM uses &lt;code&gt;jest.unstable_mockModule()&lt;/code&gt;, which requires a factory function to create mocks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Mocking a Module in ESM
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unstable_mockModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;groq-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Insight: Dynamic Imports for ESM
&lt;/h3&gt;

&lt;p&gt;Since ESM evaluates import statements before other code, static imports load modules before Jest has a chance to apply mocks (read more about it &lt;a href="https://jestjs.io/docs/ecmascript-modules#module-mocking-in-esm" rel="noopener noreferrer"&gt;here&lt;/a&gt;). To ensure that the mock implementation is applied, dynamically import the module after the mock setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unstable_mockModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;groq-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Groq&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;groq-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// using await to dynamically import the module&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mocking a Class Using Jest (ESM)
&lt;/h2&gt;

&lt;p&gt;In my project, I needed to mock the &lt;code&gt;Groq&lt;/code&gt; class from the &lt;code&gt;groq-sdk&lt;/code&gt; module. Here’s how I created a mock that accepts an API key object and checks the validity of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unstable_mockModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;groq-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// we put the class's constructor implementation inside the factory function&lt;/span&gt;
  &lt;span class="na"&gt;Groq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;apiKeyObj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiKeyObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;MOCKED_GROQ_API_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mockCreate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;401: Unauthorized. Invalid API key.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s an example of how I tested the &lt;code&gt;Groq&lt;/code&gt; class with Jest and ESM.&lt;/p&gt;

&lt;p&gt;My original source code creates a &lt;code&gt;Groq&lt;/code&gt; instance by passing the API key from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Groq&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;groq-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node:process&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GROQ_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GROQ_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getGroqChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;fileContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;targetLang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;providerModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groq&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;Groq&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GROQ_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a test, a &lt;code&gt;Groq&lt;/code&gt; object can be instantiated using the mocked &lt;code&gt;Groq&lt;/code&gt; class above, like how it would be done realistically. For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GROQ API key is invalid, throw error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groq&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;Groq&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dummy_key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;401: Unauthorized. Invalid API key.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling Environment Variables in Jest
&lt;/h2&gt;

&lt;p&gt;To work with environment variables dynamically during tests, I adjusted them before each test and imported the testing module afterward. This approach lets the module reference the updated variable, rather than the original value from &lt;code&gt;env.jest&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node:process&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MOCKED_GROQ_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getGroqChatCompletion() tests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resetModules&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// clears the cache&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;originalEnv&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalEnv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ensure original values are restored after all tests&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;valid arguments, return translated content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;originalEnv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;GROQ_API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MOCKED_GROQ_API_KEY&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// set new value to GROQ_API_KEY&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getGroqChatCompletion&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../src/ai/groq_ai.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// import the testing module that uses the new GROQ_API_KEY&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getGroqChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;english&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "123" is used here, as opposed to the value from env.jest&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mocked response: Hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mocking Array Modules
&lt;/h2&gt;

&lt;p&gt;For some modules, such as &lt;code&gt;iso-639-3&lt;/code&gt;, I had to mock the module as an array to simulate its actual structure.&lt;/p&gt;

&lt;p&gt;Source code &lt;code&gt;utils.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;lang6393&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;iso-639-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getIso639LanguageCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ....&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;language6393&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lang6393&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iso6393&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My first attempt of mocking &lt;code&gt;iso6393&lt;/code&gt; was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// wrong implementation&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockFind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unstable_mockModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;iso-639-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mockFind&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;iso6393&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;iso-639-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getIso639LanguageCode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./utils.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this would not not work, with the error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;TypeError: lang6393.iso6393.find is not a &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To understand the module, I referred to the source code of &lt;code&gt;iso-639-3&lt;/code&gt; (under &lt;code&gt;node_modules/iso-639-3/iso6393.js&lt;/code&gt;), and learned that &lt;code&gt;iso6393&lt;/code&gt; is an array of objects. Therefore, the modified mock implementation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unstable_mockModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;iso-639-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;__esModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;iso6393&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Zulu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;living&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;individual&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;iso6393&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aaa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;iso6393&lt;/code&gt; array mocked properly, the &lt;code&gt;find()&lt;/code&gt; method can be called on &lt;code&gt;ios6393&lt;/code&gt;. I could then test functions that depend on this module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language is not found from ISO 639-1, return ISO 639-3 language code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Zulu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getIso639LanguageCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aaa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Understanding Module Structures&lt;/strong&gt;: Knowing the actual structure of each module greatly simplifies the mocking process. For instance, &lt;code&gt;iso-639-3&lt;/code&gt; is an array of objects, which I initially tried to mock incorrectly. Looking at the module’s source helped me identify the correct format.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamically Importing Modules&lt;/strong&gt;: In ESM, dynamic imports after mock setup ensure that Jest’s mocks apply correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing with Environment Variables&lt;/strong&gt;: It’s essential to reset environment variables and cache between tests to ensure consistent results.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Reflections on Testing with Jest
&lt;/h2&gt;

&lt;p&gt;Testing with Jest for ESM projects is challenging, especially due to limited support and extra steps for module mocking and import management. But testing reveals valuable insights, highlights bugs, and forces logical refinements. Now that I’ve worked with Jest’s more advanced features, I look forward to implementing it more in future projects.&lt;/p&gt;




&lt;p&gt;With this guide, I hope you can set up Jest effectively for ESM-based JavaScript projects, streamline your testing process, and handle challenges with module mocking and environment management. Testing with Jest is invaluable for ensuring code quality and stability, and the skills you gain here will benefit all your future development efforts.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding Static Analysis Tools to the Barrierless Project</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Fri, 01 Nov 2024 23:54:41 +0000</pubDate>
      <link>https://dev.to/vinhyan/adding-static-analysis-tools-to-the-barrierless-project-3837</link>
      <guid>https://dev.to/vinhyan/adding-static-analysis-tools-to-the-barrierless-project-3837</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;As I continue to improve the &lt;a href="https://github.com/vinhyan/barrierless" rel="noopener noreferrer"&gt;Barrierless&lt;/a&gt; project, I recognized the need to enhance code quality and ensure consistency across all contributions. Adding a source code formatter and linter would enforce a uniform style and prevent common errors, streamlining the development process and making it more efficient for all contributors. Here’s a breakdown of my process and the decisions I made to add Prettier and ESLint to the project.&lt;/p&gt;

&lt;p&gt;(Check out the commit for this update &lt;a href="https://github.com/vinhyan/barrierless/commit/84a20014c01d7470a1de37e8397211ee441aee8d" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; File
&lt;/h2&gt;

&lt;p&gt;To make the development process more accessible for contributors, I generated a &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; file using &lt;a href="https://generator.contributing.md/" rel="noopener noreferrer"&gt;CONTRIBUTING.md Generator&lt;/a&gt;. This document provides guidance for contributors on setting up the development environment, coding standards, and submitting changes. By having clear contribution guidelines, I hope to create a more organized and structured experience for future contributors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose a Source Code Formatter – Prettier
&lt;/h2&gt;

&lt;p&gt;Since Barrierless is primarily built in JavaScript, I decided to use &lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt; as the project’s source code formatter. Prettier is a popular choice in the JavaScript community, known for enforcing a consistent code style automatically. With Prettier, formatting rules are predefined and eliminate the need for contributors to focus on stylistic details, allowing them to focus on the code logic itself.&lt;/p&gt;

&lt;p&gt;To add Prettier, I installed it as a dev dependency and configured a &lt;code&gt;.prettierrc&lt;/code&gt; file in the project. This file allows us to customize formatting rules and keep them consistent across the project. I also added a &lt;code&gt;.prettierignore&lt;/code&gt; to avoid formatting unnecessary files. Then, I created a &lt;code&gt;format&lt;/code&gt; script in &lt;code&gt;package.json&lt;/code&gt; to make it easy for contributors to run Prettier with a single command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose a Linter – ESLint
&lt;/h2&gt;

&lt;p&gt;To catch common coding issues and enforce best practices, I chose &lt;a href="https://eslint.org/" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt; as the linter for the Barrierless project. ESLint is highly configurable, and it integrates well with JavaScript projects, identifying potential errors, bad practices, and non-standard code.&lt;/p&gt;

&lt;p&gt;After installing ESLint as a dev dependency, I created a &lt;code&gt;lint&lt;/code&gt; script in &lt;code&gt;package.json&lt;/code&gt; so that contributors can easily run ESLint from the command line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix Errors and Inconsistencies
&lt;/h2&gt;

&lt;p&gt;With these scripts in place, contributors can now use &lt;code&gt;npm run format&lt;/code&gt; to format their code and &lt;code&gt;npm run lint&lt;/code&gt; to check for any linting issues before submitting a pull request.&lt;/p&gt;

&lt;p&gt;After running Prettier and ESLint on the project for the first time, I was surprised by the number of inconsistencies and potential issues they flagged. Many of these were minor syntax and formatting issues, but there were also errors that could have easily gone unnoticed without these tools. Addressing these issues not only improved the code’s readability but also helped to catch small mistakes that could have caused bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrate Formatting and Linting with Editor Configuration
&lt;/h2&gt;

&lt;p&gt;To make it easier for contributors to integrate Prettier and ESLint with their editor, I added configuration files under the &lt;code&gt;.vscode&lt;/code&gt; folder. These configurations ensure that code is formatted and linted automatically in editors like VS Code, making the development experience seamless and consistent.&lt;/p&gt;

&lt;p&gt;Here’s an example of the &lt;code&gt;.vscode/settings.json&lt;/code&gt; file configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.insertSpaces"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.tabSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.detectIndentation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.formatOnSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.codeActionsOnSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"source.fixAll"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"explicit"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"files.eol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"files.insertFinalNewline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these settings, VS Code will automatically format and lint code upon saving, minimizing the manual steps required by contributors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Document Instructions in &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Finally, I documented all the setup and usage instructions for Prettier and ESLint in the &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; file. This documentation explains how to run the scripts, and configure the editor to integrate with these tools. By including these details in &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;, I hope to make it straightforward for contributors to follow the same standards without hassle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Adding Prettier and ESLint to the Barrierless project was a valuable step in improving code quality and consistency. These tools not only help maintain a uniform code style but also prevent potential issues, creating a smoother development experience for both current and future contributors. I’m excited to see the impact this has on our collaborative efforts, and I encourage anyone interested to check out the project and contribute!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hacktoberfest 2024 - Last Week + Final Thoughts: Resolving Mobile Navigation Overflow Issues for Clean and Green Philly</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Wed, 30 Oct 2024 03:10:15 +0000</pubDate>
      <link>https://dev.to/vinhyan/hacktoberfest-2024-last-week-final-thoughts-resolving-mobile-navigation-overflow-issues-for-clean-and-green-philly-4j0n</link>
      <guid>https://dev.to/vinhyan/hacktoberfest-2024-last-week-final-thoughts-resolving-mobile-navigation-overflow-issues-for-clean-and-green-philly-4j0n</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;In the last week of Hacktoberfest, I tackled an issue with the mobile navigation dropdown for the &lt;a href="https://github.com/CodeForPhilly/clean-and-green-philly" rel="noopener noreferrer"&gt;Clean and Green Philly&lt;/a&gt; project. This project, developed to support sustainable interventions to reduce gun violence in Philadelphia, had a minor yet significant problem on mobile devices: the &lt;strong&gt;Donate option in the dropdown menu was not fully visible&lt;/strong&gt; when the screen width was reduced, making it difficult to access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue #976: Donate Option Hidden in Mobile Nav
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bug Overview:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
When users navigate on smaller screens, the navigation bar switches to a hamburger menu. The “Donate” option, located at the bottom of this dropdown, was barely visible and difficult to click without scrolling due to the dropdown’s limited &lt;code&gt;height&lt;/code&gt;. (&lt;a href="https://github.com/CodeForPhilly/clean-and-green-philly/issues/976" rel="noopener noreferrer"&gt;Issue #976&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: PR #985 – Adjusting the Mobile Navigation Dropdown &lt;code&gt;max-height&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;My solution was to &lt;strong&gt;increase the max-height of the mobile dropdown menu&lt;/strong&gt; to make sure all items were visible without the need to scroll. This adjustment allows users to access the "Donate" option with ease, improving the accessibility and user experience on mobile devices. (&lt;a href="https://github.com/CodeForPhilly/clean-and-green-philly/pull/985" rel="noopener noreferrer"&gt;PR #985&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical Challenges Faced:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Understanding the Codebase:&lt;/strong&gt; Being new to the project, I first had to get familiar with its layout and structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling Libraries:&lt;/strong&gt; The project uses Next-UI and Tailwind CSS, which were both new to me. I had to quickly get up to speed with Tailwind’s styling conventions to locate and fix the dropdown’s CSS properties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Locating the Issue:&lt;/strong&gt; After investigation, I found that the &lt;code&gt;.mobileIconLinkNav&lt;/code&gt; class in &lt;code&gt;global.css&lt;/code&gt; controlled the height. This class was custom-designed for the mobile nav, and increasing its &lt;code&gt;max-height&lt;/code&gt; resolved the issue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Following Contribution Guidelines:&lt;/strong&gt; I initially submitted my PR to the &lt;code&gt;main&lt;/code&gt; branch, overlooking the instruction to submit to the &lt;code&gt;staging&lt;/code&gt; branch. The reviewer helped guide me in switching the PR to the correct branch, emphasizing the importance of following contribution protocols.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Closing Thoughts
&lt;/h3&gt;

&lt;p&gt;This week was a rewarding learning experience that taught me how to quickly adapt to new styling frameworks while making meaningful contributions to a live project. Overall, it was another productive week of Hacktoberfest, and I look forward to tackling more challenges like this in the future!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hacktoberfest 2024 Wrap-Up
&lt;/h2&gt;

&lt;p&gt;After four weeks of Hacktoberfest, I’m wrapping up with a mix of accomplishment and growth. Each project and pull request has been an opportunity to learn new tools, dive into unfamiliar codebases, and apply my problem-solving skills to real-world issues. Along the way, I’ve expanded my understanding of diverse tech stacks—from navigating Tailwind and Next-UI in Clean and Green Philly to handling GitHub API limitations and exploring effective UI handling techniques.&lt;/p&gt;

&lt;p&gt;Hacktoberfest has been more than just about completing PRs; it’s been a hands-on journey into open source collaboration. I’ve gained valuable insights into the importance of clear communication, thorough documentation, and the small but impactful improvements that make a difference in the user experience. Working with different teams has also reminded me how supportive the open-source community can be, with reviewers and maintainers offering constructive feedback and guidance.&lt;/p&gt;

&lt;p&gt;Looking back, each week presented new challenges, but each contribution left me more confident in my skills. Hacktoberfest 2024 has not only strengthened my technical abilities but has also reinforced my passion for contributing to projects that create meaningful change. I’m excited to carry this momentum forward, knowing that the experiences I’ve gained this month will benefit future collaborations and contributions. Here’s to many more Hacktoberfests to come!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hacktoberfest 2024 - Week 3: Fixing Document Title Updates in Impress</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Sun, 27 Oct 2024 15:01:57 +0000</pubDate>
      <link>https://dev.to/vinhyan/hacktoberfest-2024-week-3-fixing-document-title-updates-in-impress-3iec</link>
      <guid>https://dev.to/vinhyan/hacktoberfest-2024-week-3-fixing-document-title-updates-in-impress-3iec</guid>
      <description>&lt;p&gt;Hello!! 👋&lt;/p&gt;

&lt;p&gt;This week, I contributed to &lt;a href="https://github.com/numerique-gouv/impress" rel="noopener noreferrer"&gt;Impress&lt;/a&gt;, a document-editing app, where I worked on a bug related to how users interact with placeholder text in the title field (&lt;a href="https://github.com/numerique-gouv/impress/issues/328" rel="noopener noreferrer"&gt;Issue #328&lt;/a&gt;). Here’s a breakdown of the intended functionality, the specific issue, and the steps I took to resolve it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expected Behavior
&lt;/h2&gt;

&lt;p&gt;In Impress, the document title field has specific styling to guide users. When the title text is grey, it serves as a placeholder ("Untitled Document"). Once the user edits the title, it should turn black, indicating the update has been successfully saved. The expected behavior is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clicking on the placeholder text should activate the text box for editing.
&lt;/li&gt;
&lt;li&gt;If the title remains unedited, the grey placeholder should persist.&lt;/li&gt;
&lt;li&gt;If the title is edited, the new text should display in black.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Actual Behavior
&lt;/h2&gt;

&lt;p&gt;While the title update generally worked, a bug appeared when users selected and edited the placeholder text in certain ways. If users highlighted the placeholder text by double-clicking or dragged the mouse outside the text box area, they could end up modifying the placeholder text instead of starting with a blank title.&lt;/p&gt;

&lt;p&gt;In these scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The placeholder text could be altered while still appearing grey.&lt;/li&gt;
&lt;li&gt;After confirming the edit (e.g., by clicking elsewhere or pressing Enter), a success notification would appear, yet the title remained grey, as if it were still the default placeholder, instead of becoming black.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Problem Analysis
&lt;/h2&gt;

&lt;p&gt;In Impress’s &lt;code&gt;DocTitle.tsx&lt;/code&gt;, I discovered that &lt;code&gt;handleTitleSubmit&lt;/code&gt; was not correctly updating the &lt;code&gt;titleDisplay&lt;/code&gt; state when users edited the placeholder text. As a result, the &lt;code&gt;isUntitled&lt;/code&gt; flag remained &lt;code&gt;true&lt;/code&gt;, keeping the title styled in grey even after an edit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;To fix this, I modified &lt;code&gt;handleTitleSubmit&lt;/code&gt; to ensure it updated both &lt;code&gt;updateDoc&lt;/code&gt; with the new title and &lt;code&gt;titleDisplay&lt;/code&gt; with the edited value. This change updated the &lt;code&gt;isUntitled&lt;/code&gt; flag to &lt;code&gt;false&lt;/code&gt;, allowing the title to display in black once edited, providing the user with immediate visual confirmation.&lt;/p&gt;

&lt;p&gt;With this approach, the title now correctly turns black after any edits, enhancing the user experience by signaling that their updates have been successfully applied (&lt;a href="https://github.com/numerique-gouv/impress/pull/370" rel="noopener noreferrer"&gt;PR #370&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;This task presented several challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Familiarity&lt;/strong&gt;: A significant amount of time went into understanding the codebase and setting up the project’s frontend and backend for local development. Grasping the relationships between different components was key to diagnosing the issue effectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exploring Alternatives&lt;/strong&gt;: My initial solution focused on preventing interactions like double-clicking or dragging on the placeholder text. However, this approach introduced additional bugs and felt like a "band-aid" solution. Refocusing on &lt;code&gt;handleTitleSubmit&lt;/code&gt; led to a more sustainable fix.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pull Request Requirements&lt;/strong&gt;: During the pull request process, several CI tests failed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;CHANGELOG.md&lt;/code&gt; entry was required to document the fix, but this wasn’t mentioned in &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;, so I initially missed it.&lt;/li&gt;
&lt;li&gt;My commit message format didn’t align with the project’s CI standards.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I addressed these issues in a subsequent commit by adding the required change log entry and reformatting my commit message to match the guidelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflections
&lt;/h2&gt;

&lt;p&gt;Working on Impress has been a rewarding experience, reinforcing the value of thorough code understanding and the impact of thoughtful, comprehensive solutions. Hacktoberfest continues to be a fantastic opportunity for growth, and I look forward to more contributions this month!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hacktoberfest 2024 - Week 2: Fixing Makefile Errors in Mikochi</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Sun, 13 Oct 2024 21:40:00 +0000</pubDate>
      <link>https://dev.to/vinhyan/hacktoberfest-2024-week-2-fixing-makefile-errors-in-mikochi-25gd</link>
      <guid>https://dev.to/vinhyan/hacktoberfest-2024-week-2-fixing-makefile-errors-in-mikochi-25gd</guid>
      <description>&lt;p&gt;Hello! 👋&lt;/p&gt;

&lt;p&gt;Following my successful contribution in the &lt;a href="https://dev.to/vinhyan/hacktoberfest-2024-week-1-handling-github-api-rate-limits-in-gitexplorer-9ej"&gt;first week of Hacktoberfest&lt;/a&gt; , I was eager to continue my journey into open-source development. This week, I focused on the &lt;strong&gt;&lt;a href="https://github.com/zer0tonin/Mikochi" rel="noopener noreferrer"&gt;Mikochi&lt;/a&gt;&lt;/strong&gt; project, addressing &lt;a href="https://github.com/zer0tonin/Mikochi/issues/21" rel="noopener noreferrer"&gt;issue #21&lt;/a&gt; related to errors in the &lt;strong&gt;Makefile&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Issue at Hand
&lt;/h4&gt;

&lt;p&gt;While working on the project, I attempted to launch the development environment using the command &lt;code&gt;make dev&lt;/code&gt;, only to be met with the following error:&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="nb"&gt;ls &lt;/span&gt;backend | &lt;span class="nb"&gt;grep &lt;/span&gt;__debug_bin | gxargs &lt;span class="nt"&gt;-I&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="nb"&gt;rm &lt;/span&gt;backend/&lt;span class="o"&gt;{}&lt;/span&gt;
/bin/sh: gxargs: &lt;span class="nb"&gt;command &lt;/span&gt;not found
make: &lt;span class="k"&gt;***&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;down] Error 127
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue stemmed from a minor typo in the &lt;strong&gt;Makefile&lt;/strong&gt;: the command &lt;code&gt;gxargs&lt;/code&gt; was incorrectly used instead of &lt;code&gt;xargs&lt;/code&gt;. Although it seemed like a small mistake, it significantly disrupted the workflow.&lt;/p&gt;

&lt;h4&gt;
  
  
  Preparing for the Fix
&lt;/h4&gt;

&lt;p&gt;To resolve the issue, I needed to dive into the &lt;strong&gt;Makefile&lt;/strong&gt; to understand its structure and how the commands were executed. Familiarizing myself with this file was essential for implementing the fix correctly.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Code Fix
&lt;/h4&gt;

&lt;p&gt;The specific line that required modification was as follows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="err"&gt;ls&lt;/span&gt; &lt;span class="err"&gt;backend&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;grep&lt;/span&gt; &lt;span class="err"&gt;__debug_bin&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;gxargs&lt;/span&gt; &lt;span class="err"&gt;-I&lt;/span&gt; &lt;span class="err"&gt;{}&lt;/span&gt; &lt;span class="err"&gt;rm&lt;/span&gt; &lt;span class="err"&gt;backend/{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="err"&gt;ls&lt;/span&gt; &lt;span class="err"&gt;backend&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;grep&lt;/span&gt; &lt;span class="err"&gt;__debug_bin&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;xargs&lt;/span&gt; &lt;span class="err"&gt;-I&lt;/span&gt; &lt;span class="err"&gt;{}&lt;/span&gt; &lt;span class="err"&gt;rm&lt;/span&gt; &lt;span class="err"&gt;backend/{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By simply replacing &lt;code&gt;gxargs&lt;/code&gt; with &lt;code&gt;xargs&lt;/code&gt;, I ensured that the command would execute properly without throwing an error.&lt;/p&gt;

&lt;h4&gt;
  
  
  Challenges and Research
&lt;/h4&gt;

&lt;p&gt;One challenge I faced was distinguishing between standard and non-standard command-line tools. To prepare for the fix, I researched how &lt;code&gt;xargs&lt;/code&gt; works and its intended purpose, which helped clarify the root of the issue.&lt;/p&gt;

&lt;h4&gt;
  
  
  Interaction with Project Maintainers
&lt;/h4&gt;

&lt;p&gt;After submitting my pull request, which you can view &lt;a href="https://github.com/zer0tonin/Mikochi/pull/22" rel="noopener noreferrer"&gt;here&lt;/a&gt;, I had a constructive interaction with the project maintainers. They informed me that &lt;code&gt;gxargs&lt;/code&gt; was a non-standard executable that was being used. However, they agreed that using &lt;code&gt;xargs&lt;/code&gt; would provide a more universally compatible solution, leading to the approval of my pull request.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;This second week of Hacktoberfest has deepened my understanding of open-source contributions and the importance of clear communication with project maintainers. Each issue I tackle not only enhances my technical skills but also builds connections within the developer community. I encourage anyone considering participation in Hacktoberfest to take the leap—you'll gain invaluable experience and make meaningful contributions!&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Refactor: How I Improve My Barrierless Project</title>
      <dc:creator>Vinh Nhan</dc:creator>
      <pubDate>Sat, 12 Oct 2024 05:43:44 +0000</pubDate>
      <link>https://dev.to/vinhyan/refactor-how-i-improve-barrierless-project-1m64</link>
      <guid>https://dev.to/vinhyan/refactor-how-i-improve-barrierless-project-1m64</guid>
      <description>&lt;p&gt;Hello! 👋&lt;/p&gt;

&lt;p&gt;After reading through the refactoring walk-through example in class, it was time to apply those lessons to my own project: &lt;strong&gt;&lt;a href="https://github.com/vinhyan/barrierless" rel="noopener noreferrer"&gt;Barrierless&lt;/a&gt;&lt;/strong&gt;. The goal was to improve the code’s structure, readability, modularity, and maintainability. Refactoring helps set the stage for long-term success by making code easier to read, debug, and expand, especially with automated testing on the horizon. Here’s how my refactoring journey went.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Branching Out
&lt;/h3&gt;

&lt;p&gt;The first step was creating a dedicated refactoring branch from my &lt;code&gt;main&lt;/code&gt; branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; refactoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensured that any mistakes I made during the refactoring process wouldn’t affect the stability of my &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Finding the Issues
&lt;/h3&gt;

&lt;p&gt;I reviewed my code and identified three key areas that needed improvement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Separate Concerns: Modularizing My Code&lt;/strong&gt;
Initially, my code handled command-line arguments, file parsing, AI management, and output all in the same space in &lt;code&gt;index.js&lt;/code&gt;, making it harder to manage. I decided to separate these responsibilities into different modules:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;One module for command-line arguments and options: &lt;code&gt;/src/cli&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Two modules for input and output file handling: &lt;code&gt;/src/input&lt;/code&gt;&amp;amp; &lt;code&gt;/src/output&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A separate one for AI translation management &lt;code&gt;/src/translation&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This refactoring increased the modularity and maintainability of the code, allowing each part to be more focused and reusable. At the same time, I also added a logic to validate the language option specified by the user, based on the IOS639-1 and 3 standard. Then, I created the first commit for this refactor after testing the separation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"modularize code into input, output, translation, cli. Add IOS639-1 and 3 language standard validation"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Eliminate Global Variables&lt;/strong&gt;
I noticed that some global variables were used in &lt;code&gt;index.js&lt;/code&gt;, which could lead to unexpected behavior as the project scales. To fix this, I encapsulated the necessary variables within the respective modules, ensuring that no global variables were needed in index.js. This enhanced the code's reliability and reduced the risk of bugs in that specific file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"remove global variables in index.js"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Switching from &lt;code&gt;require&lt;/code&gt; to &lt;code&gt;import&lt;/code&gt;&lt;/strong&gt;
Since I'm working in a modern JavaScript environment with ES6 modules, I replaced &lt;code&gt;require&lt;/code&gt; statements with &lt;code&gt;import&lt;/code&gt; statements for &lt;code&gt;os&lt;/code&gt; and &lt;code&gt;fs&lt;/code&gt; in &lt;code&gt;src/utils.js&lt;/code&gt;. This not only makes the code more modern but also aligns it with the rest of the current code and the latest JavaScript standards:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"changed 'require' to 'import' for os and fs"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Commit and Test
&lt;/h3&gt;

&lt;p&gt;After each refactor, I made sure to thoroughly test the code to ensure I hadn’t introduced any breaking changes. My workflow looked like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Refactor a section of the code.&lt;/li&gt;
&lt;li&gt;Test the functionality manually.&lt;/li&gt;
&lt;li&gt;Commit the changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I was careful to follow the rule of one problem, one commit, which kept each commit focused and easy to follow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Interactive Git Rebase
&lt;/h3&gt;

&lt;p&gt;Once I was happy with the refactoring, I performed an interactive rebase to squash all of the refactoring commits into a single commit. This makes the history cleaner and easier to understand. The process was straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I marked the commits I wanted to squash, and when everything was ready, I used an amended commit message to add the bullet points to the current commit messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Merging the Refactor Branch
&lt;/h3&gt;

&lt;p&gt;With the rebase completed and all tests passing, I merged the refactor branch back into &lt;code&gt;main&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
git merge &lt;span class="nt"&gt;--ff-only&lt;/span&gt; refactoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I pushed the updated &lt;code&gt;main&lt;/code&gt; branch to GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Rebase:&lt;/strong&gt; This was a great tool to clean up my commit history. It was my first time using it for squashing commits, and it made the refactoring process feel polished.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modularization:&lt;/strong&gt; Breaking up the responsibilities into separate modules made the code easier to read and reason about. It also made debugging and testing more focused.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Global Variables:&lt;/strong&gt; By removing global variables, the code is less prone to hard-to-find bugs and is better organized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switching to ES6 Imports:&lt;/strong&gt; This step brought my project up to modern standards, ensuring better compatibility with future projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I didn’t encounter any significant bugs during the refactor, but I did notice that some parts of my code were more fragile than I had realized. Refactoring exposed those areas, making it easier to address them in the future. The overall process was smooth, and the improved organization will make future changes easier to implement.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
