<?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: Mehak.</title>
    <description>The latest articles on DEV Community by Mehak. (@mehakb7).</description>
    <link>https://dev.to/mehakb7</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%2F2694144%2F836bb4e4-2482-4c32-a659-1d0c445d663d.png</url>
      <title>DEV Community: Mehak.</title>
      <link>https://dev.to/mehakb7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mehakb7"/>
    <language>en</language>
    <item>
      <title>Building Node.js CLI Tool.</title>
      <dc:creator>Mehak.</dc:creator>
      <pubDate>Mon, 10 Nov 2025 13:59:51 +0000</pubDate>
      <link>https://dev.to/mehakb7/building-nodejs-cli-tool-l4k</link>
      <guid>https://dev.to/mehakb7/building-nodejs-cli-tool-l4k</guid>
      <description>&lt;p&gt;Recently, while revising Node.js, I came across the project section &lt;a href="https://roadmap.sh/nodejs/projects" rel="noopener noreferrer"&gt;Node.js roadmap&lt;/a&gt; on roadmap.sh(&lt;a href="https://roadmap.sh" rel="noopener noreferrer"&gt;https://roadmap.sh&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;The first project challenge there is to &lt;strong&gt;create a CLI (Command-Line Interface) tool using Node.js&lt;/strong&gt;. So,I decided to build one to refresh my basics.&lt;/p&gt;

&lt;p&gt;This post explains how CLI tools actually work under the hood and how to build one yourself from scratch.  &lt;/p&gt;




&lt;h2&gt;
  
  
  How OS Executes Script Files
&lt;/h2&gt;

&lt;p&gt;Before creating any CLI, we must understand &lt;strong&gt;how operating systems execute scripts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Normally, when you run a Node.js file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it’s Node.js that runs the file — not your operating system.&lt;/p&gt;

&lt;p&gt;The OS doesn’t automatically know how to execute JavaScript — it just knows how to run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compiled binaries (bash, python, node, etc.)&lt;/li&gt;
&lt;li&gt;Or scripts that explicitly tell it which program should interpret them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want your script to be run directly (e.g., by typing mycli in the terminal), then the OS must know which program to use to interpret it.&lt;/p&gt;

&lt;p&gt;By default, if you make a file executable, the OS will assume it’s a shell script unless you specify otherwise.&lt;/p&gt;

&lt;p&gt;To tell the OS that your script should be run by Node.js, add this line at the top of your file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env node

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

&lt;/div&gt;



&lt;p&gt;This line is called a shebang, and it tells the OS:&lt;br&gt;
“Run this file using Node.js, wherever it’s installed.”&lt;/p&gt;


&lt;h2&gt;
  
  
  How npm Installs CLI Tools Globally
&lt;/h2&gt;

&lt;p&gt;When we install any package globally using npm install -g  npm do the following things: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installs the package in your system’s global node_modules directory(the path depends on your OS).&lt;/li&gt;
&lt;li&gt;Looks for the bin field inside the package’s package.json.&lt;/li&gt;
&lt;li&gt;Creates a symlink (symbolic link) between the CLI command and the script file defined in bin.
So, for example, if your package.json contains:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"bin": {
  "taskcli": "./bin/index.mjs"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;npm will create a command called taskcli that points to your script.&lt;/p&gt;


&lt;h2&gt;
  
  
  The bin Field in package.json
&lt;/h2&gt;

&lt;p&gt;The bin field defines which commands your package exposes and what files they execute.&lt;/p&gt;

&lt;p&gt;I like to keep all CLI entry files inside a bin/ folder for clarity.&lt;/p&gt;


&lt;h2&gt;
  
  
  Parsing Command-Line Arguments
&lt;/h2&gt;

&lt;p&gt;When we execute a script, Node exposes the arguments through process.argv.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node script.js add "Buy groceries"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;process.argv will contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  '/usr/bin/node',
  '/path/to/script.js',
  'add',
  'Buy groceries'
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we could manually parse this array, but that’s tedious.Instead, use a library like Commander.js,which gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Argument parsing&lt;/li&gt;
&lt;li&gt;Subcommands&lt;/li&gt;
&lt;li&gt;Automatic --help and --version support&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Making the Tool Work Locally — npm link
&lt;/h2&gt;

&lt;p&gt;Before publishing your CLI to npm, we can test it locally using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm link
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a symlink between your local project and your global npm binaries directory,so your command (taskcli) behaves like a globally installed CLI.&lt;/p&gt;

&lt;p&gt;Now you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;taskcli add "Learn Node.js"
taskcli list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No global installation needed and everything runs locally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Project
&lt;/h2&gt;

&lt;p&gt;Here’s my implementation:&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/MehakB7/task-cli" rel="noopener noreferrer"&gt;MehakB7/task-cli&lt;/a&gt;&lt;br&gt;
Roadmap.sh Submission: &lt;a href="https://roadmap.sh/projects/task-tracker/solutions?u=67a093ccd7c9b4cc8b6d9bf9" rel="noopener noreferrer"&gt;Task Tracker Project Solution&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This small project helped me understand:&lt;br&gt;
How the OS executes scripts&lt;br&gt;
How npm sets up CLI tools under the hood&lt;br&gt;
How to design structured, maintainable command-line apps&lt;/p&gt;

</description>
      <category>node</category>
      <category>npm</category>
      <category>cli</category>
      <category>backend</category>
    </item>
    <item>
      <title>Integrating Playwright with Next.js — The Complete Guide</title>
      <dc:creator>Mehak.</dc:creator>
      <pubDate>Thu, 16 Oct 2025 16:24:13 +0000</pubDate>
      <link>https://dev.to/mehakb7/integrating-playwright-with-nextjs-the-complete-guide-34io</link>
      <guid>https://dev.to/mehakb7/integrating-playwright-with-nextjs-the-complete-guide-34io</guid>
      <description>&lt;h2&gt;
  
  
  What is Playwright?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Playwright&lt;/strong&gt; is a modern automation and testing framework built by Microsoft. It allows you to write &lt;strong&gt;end-to-end (E2E)&lt;/strong&gt; tests for your web apps that run across &lt;strong&gt;multiple browsers and devices&lt;/strong&gt; — including Chromium, Firefox, and WebKit, both desktop and mobile.&lt;/p&gt;

&lt;p&gt;At its core, Playwright is designed for &lt;strong&gt;speed, reliability, and real-world testing&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Unlike older tools that rely on flaky DOM polling, Playwright takes a “&lt;strong&gt;web-first assertions&lt;/strong&gt;” approach — it automatically waits for elements to become visible before interacting with them.&lt;/p&gt;


&lt;h2&gt;
  
  
  How Playwright Works
&lt;/h2&gt;

&lt;p&gt;Playwright consists of two key parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Node Controller (Test Runner)&lt;/strong&gt; — This is where your test scripts live.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser Instance&lt;/strong&gt; — A new instance that Playwright launches for each test run.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;They communicate through a &lt;strong&gt;WebSocket connection&lt;/strong&gt;, allowing real-time, bi-directional messaging.&lt;br&gt;&lt;br&gt;
This architecture makes Playwright faster and more efficient than many other frameworks.&lt;/p&gt;

&lt;p&gt;When you run a test, the Node controller sends commands (like &lt;code&gt;click&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt;, or &lt;code&gt;goto&lt;/code&gt;) to the browser.&lt;br&gt;&lt;br&gt;
The browser executes those commands and returns the results.  &lt;/p&gt;

&lt;p&gt;Let's visualize this communication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Node Controller instructs the browser: "Click the 'Submit' button."&lt;/li&gt;
&lt;li&gt;The Browser responds: "Click registered. Initiating an API call to /api/login."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Node Controller, if configured with page.route(), can intercept that request and fulfill it with a mocked response, making the test fast and independent of backend services.&lt;/p&gt;


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

&lt;p&gt;From my experience, it comes down to a few critical features that eliminate common testing headaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parallel Execution:&lt;/strong&gt; Run your test suites significantly faster by executing tests concurrently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No More Flaky Tests:&lt;/strong&gt; Playwright's built-in smart assertions wait for elements to be ready, visible, and stable. Instead of adding arbitrary setTimeout calls everywhere.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Codegen — Write Tests Without Writing Them
&lt;/h2&gt;

&lt;p&gt;One of my favorite features is Playwright Codegen.&lt;br&gt;
You can open your app, interact with it, and Playwright will automatically generate the corresponding test code for you. Just one command and you can start interaction with the website and genetate test code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;npx playwright codegen&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Understanding Fixtures
&lt;/h2&gt;

&lt;p&gt;In testing, a fixture is a predefined state or environment that ensures your tests are consistent and repeatable. Think of it as a "setup" that gives the same answer every time it's requested.&lt;/p&gt;

&lt;p&gt;Playwright uses fixtures extensively. Here are a few powerful examples:&lt;/p&gt;

&lt;p&gt;Image Upload Fixture: Create a reusable fixture that provides a test image file, so every test that needs to upload a file doesn't have to manage the file path separately.&lt;/p&gt;

&lt;p&gt;API Interception Fixture: Intercept costly third-party API calls and return a predefined, reliable JSON response. This makes your tests fast, deterministic, and free from external service outages.&lt;/p&gt;


&lt;h2&gt;
  
  
  Integrating Playwright with Next.js
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1 : Installation&lt;/strong&gt; &lt;br&gt;
install Playwright in your Next.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -D @playwright/test
npx playwright init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The init command sets up the default configuration and creates the tests/ directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Configuration&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './e2e',      // Folder where your tests live
  timeout: 30000,          // Test will fail if it exceeds 30 seconds
  retries: 1,              // Retry failed tests once for CI stability
  workers: 4,              // Run tests in parallel with 4 workers

  use: {
    baseURL: 'http://localhost:3000', // Your Next.js dev server URL
    viewport: { width: 1280, height: 720 },
    // Record video only when retrying a failed test
  },

  // Define your browser and device matrix
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    // Uncomment to add mobile testing
    // { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } },
  ],
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Writing Your First Test&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;create a test inside e2e/home.spec.ts. Playwright's page fixture provides a clean, isolated browser context for each test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { test, expect } from '@playwright/test';

test('homepage has correct title and welcome message', async ({ page }) =&amp;gt; {
  // Navigate to the homepage
  await page.goto('/');

  // Assert that the page title contains "Next.js"
  await expect(page).toHaveTitle(/Next.js/);

  // Use a locator to find an element and assert its text
  const welcomeMessage = page.getByRole('heading', { name: 'Welcome to Our App' });
  await expect(welcomeMessage).toBeVisible();
});

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Running Tests in Different Modes
&lt;/h2&gt;

&lt;p&gt;You can run Playwright tests with different flags and modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Headed mode (UI):&lt;/strong&gt; Opens the Playwright UI to visualize test runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;npx playwright test --ui&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Headless mode:&lt;/strong&gt; Runs quietly without opening a browser window.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;`&lt;code&gt;npx playwright test&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Specify browser:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;npx playwright test --project=chromium&lt;br&gt;
npx playwright test --project=firefox&lt;/code&gt;  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can add these command in your package.json file based on your requirement. &lt;/p&gt;




&lt;h3&gt;
  
  
  ⚠️ Note on Mocking: MSW with Playwright vs Jest
&lt;/h3&gt;

&lt;p&gt;If you're coming from Jest and are used to mocking API calls with &lt;strong&gt;MSW (Mock Service Worker)&lt;/strong&gt;, there's a crucial architectural difference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In Jest&lt;/strong&gt;: Your tests run in a Node.js environment, and MSW operates at the Node level&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In Playwright&lt;/strong&gt;: API calls happen in the &lt;strong&gt;actual browser context&lt;/strong&gt;, while the test runner operates in Node.js&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This means your existing MSW handlers won't automatically work with Playwright.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To use MSW with Playwright, you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start MSW within the &lt;strong&gt;browser context&lt;/strong&gt; (web worker)&lt;/li&gt;
&lt;li&gt;Ensure your mock service worker is registered and active in the page&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Alternative&lt;/strong&gt;: Playwright provides built-in API mocking via &lt;code&gt;page.route()&lt;/code&gt; which is often simpler for E2E tests.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;If you want to see Playwright running in a real-world project&lt;br&gt;
check out this demo repo:&lt;br&gt;
&lt;a href="https://github.com/MehakB7/ai-studio" rel="noopener noreferrer"&gt; AI Studio (GitHub)&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>playwright</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Mock Service Worker (MSW) in Next.js – A Guide for API Mocking and Testing</title>
      <dc:creator>Mehak.</dc:creator>
      <pubDate>Mon, 28 Jul 2025 04:53:20 +0000</pubDate>
      <link>https://dev.to/mehakb7/mock-service-worker-msw-in-nextjs-a-guide-for-api-mocking-and-testing-e9m</link>
      <guid>https://dev.to/mehakb7/mock-service-worker-msw-in-nextjs-a-guide-for-api-mocking-and-testing-e9m</guid>
      <description>&lt;h2&gt;
  
  
  What is MSW?
&lt;/h2&gt;

&lt;p&gt;MSW (Mock Service Worker) is a framework-agnostic library that intercepts network requests at the network level, providing mock responses. This means it doesn’t care whether you use fetch, Axios, GraphQL, etc.—MSW works regardless.&lt;/p&gt;

&lt;p&gt;It achieves this using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Service Worker&lt;/strong&gt; in the browser&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Node-based interceptor&lt;/strong&gt; during testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures the mock lives closer to the actual request, mimicking real-world behavior without patching individual libraries.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Does MSW Work?
&lt;/h2&gt;

&lt;p&gt;MSW intercepts API calls at the network layer. This means:&lt;br&gt;
If a mock exists for an API endpoint, MSW will return the mocked response.&lt;/p&gt;

&lt;p&gt;If no mock is defined, the request proceeds to the real API.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Environment&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;MSW Mode&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;How it Intercepts&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;td&gt;Service Worker&lt;/td&gt;
&lt;td&gt;Runs a real service worker that intercepts requests from the browser in network layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;Node Interceptor&lt;/td&gt;
&lt;td&gt;Uses &lt;code&gt;node-request-interceptor&lt;/code&gt; to hook into HTTP/HTTPS  in process level&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


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

&lt;p&gt;&lt;strong&gt;True Isolation&lt;/strong&gt;&lt;br&gt;
Mocks network at lowest possible level - no need to modify application code&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Framework Agnostic Tests&lt;/strong&gt;&lt;br&gt;
Works with React Testing Library, Vue Test Utils, Svelte Testing Library, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Realistic Behavior&lt;/strong&gt;&lt;br&gt;
Simulates actual network conditions (latency, errors, headers) unlike jest.mock()&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-Library Support&lt;/strong&gt;&lt;br&gt;
Intercepts requests from ANY HTTP client automatically&lt;/p&gt;


&lt;h3&gt;
  
  
  MSW in the Browser
&lt;/h3&gt;

&lt;p&gt;To set up MSW in the browser for development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Install the Service Worker&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run the following command to install the service worker file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npx msw init public/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add the mockServiceWorker.js file to your public/ directory.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Create your mock handlers&lt;/strong&gt;
Create a handler file with your REST or GraphQL mocks:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  http, HttpResponse,
} from "msw";

export const handlers = [
  http.get(`/api/whoami`, () =&amp;gt; {
    return HttpResponse.json({
      status: 200,
      data: {
         user: "Jack Sparrow"
      },
    });
  }),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Set up broswer worker&lt;/strong&gt;
Create a browser.ts file to initialize the MSW browser worker:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { setupWorker } from 'msw';
import { handlers } from './handlers'
export const worker = setupWorker(...handlers);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also created a initMock file to start initiate the mock worker&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start the worker&lt;/strong&gt;
Instead of starting the worker in Rootlayout I prefer to do it by creating a Wrapper component.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client';

import { useEffect, useState } from 'react';

export function StartMockWorker({children}: {children: React.ReactNode}) {
  const [isMockReady, setMockReady] = useState(false);

  useEffect(() =&amp;gt; {
    async function enableMocks() {
      if (process.env.NODE_ENV === 'development') {
        const { initMocks } = await import('@/common/mock/initmock');
        await initMocks();
      }
      setMockReady(true);
    }

    enableMocks();
  }, []);

  if (!isMockReady) {
    return &amp;lt;div&amp;gt;Loading mocks...&amp;lt;/div&amp;gt;;
  }

  return &amp;lt;&amp;gt;{children}&amp;lt;/&amp;gt; ;
}

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  MSW with Jest for Testing
&lt;/h2&gt;

&lt;p&gt;Jest runs tests in a Node.js environment, not a real browser. This means:&lt;br&gt;
&lt;strong&gt;No Browser APIs Exist&lt;/strong&gt;&lt;br&gt;
Service Workers (which power MSW in browsers) are a browser-exclusive feature - they don't exist in Node.js.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JSDOM Isn't a Real Browser&lt;/strong&gt;&lt;br&gt;
While Jest uses JSDOM to simulate a browser, it's still just a Node.js process. Critical browser features like Service Workers aren't implemented.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a server&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { setupServer } from 'msw/node'
import { handlers } from './handlers'
export const server = setupServer(...handlers)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;In the jest setup file&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// jest.setup.ts
import '@testing-library/jest-dom';
import { server } from '@/common/mock/server';
beforeAll(() =&amp;gt; server.listen());
afterEach(() =&amp;gt; server.resetHandlers());
afterAll(() =&amp;gt; server.close());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It ensures that your tests run with network requests intercepted and mocked, and that the state is cleaned up between tests.&lt;/p&gt;
&lt;h2&gt;
  
  
  Polyfills Required for Node + JSDOM
&lt;/h2&gt;

&lt;p&gt;When running in jsdom with Jest, you might run into missing globals like:&lt;br&gt;
&lt;code&gt;Blob&lt;/code&gt;. &lt;code&gt;TextEncoder&lt;/code&gt;,&lt;code&gt;BroadcastChannel&lt;/code&gt; (added in MSW v2+), &lt;code&gt;MessagePort&lt;/code&gt; etc&lt;/p&gt;

&lt;p&gt;You’ll need to manually polyfill these in your Jest setup file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/* eslint-disable @typescript-eslint/no-require-imports */
// jest.polyfills.js


const {
  TextDecoder, TextEncoder,
} = require('node:util');

const { ReadableStream, TransformStream } = require('node:stream/web');

const { BroadcastChannel, MessagePort } = require("node:worker_threads")

Object.defineProperties(globalThis, {
  TextDecoder: { value: TextDecoder },
  TextEncoder: { value: TextEncoder },
  ReadableStream: { value: ReadableStream },
  TransformStream: { value: TransformStream },
  BroadcastChannel: { value: BroadcastChannel },
  MessagePort:{value:MessagePort}
})

const {
  Blob, File,

} = require('node:buffer')
const {
  fetch, Headers, FormData, Request, Response,

} = require('undici')

Object.assign(globalThis, {
  fetch,
  Headers,
  FormData,
  Request,
  Response,
  Blob,
  File,
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;MSW is powerful, developer-friendly, and works seamlessly in both the browser and Node environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Great for mocking real-world APIs in local dev.&lt;/li&gt;
&lt;li&gt;Essential for writing fast, reliable, and network-independent Jest tests.&lt;/li&gt;
&lt;li&gt;Framework-agnostic and works with any HTTP client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With proper setup and polyfills, it becomes your best friend in test and dev workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Full Setup
&lt;/h2&gt;

&lt;p&gt;You can find the complete setup, including all code examples and configurations, in this GitHub repo:&lt;br&gt;
👉 &lt;a href="https://github.com/MehakB7/msw-with-next-demo" rel="noopener noreferrer"&gt;msw-with-next&lt;/a&gt;&lt;/p&gt;

</description>
      <category>msw</category>
      <category>nextjs</category>
      <category>webdev</category>
      <category>learning</category>
    </item>
    <item>
      <title>Understanding Shadow DOM by Building a Poll Plugin</title>
      <dc:creator>Mehak.</dc:creator>
      <pubDate>Wed, 04 Jun 2025 17:16:49 +0000</pubDate>
      <link>https://dev.to/mehakb7/understanding-shadow-dom-by-building-a-poll-plugin-58h9</link>
      <guid>https://dev.to/mehakb7/understanding-shadow-dom-by-building-a-poll-plugin-58h9</guid>
      <description>&lt;h2&gt;
  
  
  🌐 What is Shadow DOM?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Shadow DOM&lt;/em&gt; is a browser feature that allows us to attach a separate DOM tree to an element, a tree that’s isolated from the rest of the page.&lt;/p&gt;

&lt;p&gt;Think of it as a "mini web page" inside an element, with its own HTML, CSS, and JS &lt;strong&gt;completely encapsulated&lt;/strong&gt; from the rest of the site.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔑 Key Concepts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shadow Host&lt;/strong&gt;: The DOM element where the Shadow DOM is attached.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadow Root&lt;/strong&gt;: The root of the shadow tree, created with &lt;code&gt;element.attachShadow(options)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadow Boundary&lt;/strong&gt;: The barrier between the shadow DOM and light DOM (regular DOM).
Styles and events generally don’t cross this boundary unless configured.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧵 Modes: &lt;code&gt;open&lt;/code&gt; vs &lt;code&gt;closed&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;You can attach a shadow root in two modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;open&lt;/code&gt;: The shadow root is accessible via &lt;code&gt;element.shadowRoot&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;closed&lt;/code&gt;: The shadow root is &lt;strong&gt;not&lt;/strong&gt; accessible from the outside.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;🛑 &lt;strong&gt;Note&lt;/strong&gt;: Even in &lt;code&gt;open&lt;/code&gt; mode, accessing shadow DOM externally is discouraged as it breaks encapsulation.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔁 Communicating with the Light DOM
&lt;/h2&gt;

&lt;p&gt;Since shadow DOM is isolated, direct interaction with outside elements is limited. The recommended way to communication is using Custom Events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const voteEvent = new CustomEvent('simplepoll-vote', {
  detail: { vote: 'React' },
  bubbles: true,
  composed: false // set true if event is dispatch within the shadow boundary.
});
host.dispatchEvent(voteEvent);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Without &lt;code&gt;composed: true&lt;/code&gt;&lt;/strong&gt;, the event will &lt;strong&gt;not&lt;/strong&gt; escape the shadow DOM and &lt;strong&gt;cannot&lt;/strong&gt; be listened to in the main document.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  📝 Important Clarification
&lt;/h3&gt;

&lt;p&gt;If you dispatch the event from the &lt;strong&gt;shadow root&lt;/strong&gt;, &lt;code&gt;composed: true&lt;/code&gt; is &lt;strong&gt;necessary&lt;/strong&gt; to make it cross the boundary.&lt;/p&gt;

&lt;p&gt;However, if you dispatch the event from the &lt;strong&gt;host element&lt;/strong&gt;, &lt;code&gt;composed&lt;/code&gt; is &lt;strong&gt;not needed&lt;/strong&gt; as it’s already outside the shadow tree.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Let's Build a Real Plugin: Poll Widget
&lt;/h2&gt;

&lt;p&gt;To reinforce our understanding, I built a simple poll plugin using Shadow DOM. This plugin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a styled voting widget inside a Shadow DOM&lt;/li&gt;
&lt;li&gt;Encapsulates its layout and logic&lt;/li&gt;
&lt;li&gt;Dispatches a custom event on vote&lt;/li&gt;
&lt;li&gt;Can be embedded into any website&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🗂 Folder Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;poll-plugin/
├── index.js          # Entry point (exports the class)
├── lib/
│   ├── dom.js        # DOM creation helpers
│   ├── template.js   # HTML content generator
│   ├── style.js      # CSS as JS string
│   └── logic.js      # Voting logic and event binding
├── index.html        # to test the plugin
├── vite.config.js    # build config
├── package.js 

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚙️ How It Works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const container = createContainer('poll-container');
const shadow = container.attachShadow({ mode: 'closed' });
shadow.appendChild(style);
shadow.appendChild(wrapper);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The poll UI is created inside the shadow root.&lt;/li&gt;
&lt;li&gt;Created the poll in closed mode so main dom cannot access it.&lt;/li&gt;
&lt;li&gt;Styles are injected with a style tag.&lt;/li&gt;
&lt;li&gt;The HTML is dynamically created from config.&lt;/li&gt;
&lt;li&gt;When a user votes, we emit a custom event which will listen by main dom.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💬 Listening for Poll Votes
&lt;/h2&gt;

&lt;p&gt;To listen event in the main dom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; document.addEventListener('vote-submitted', (e) =&amp;gt; {
        alert(`You voted: ${e.detail.vote}`);
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps your main app clean while the logic is self-contained.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠 Bundling with Vite
&lt;/h2&gt;

&lt;p&gt;To make this plugin usable in any website, I used Vite as it's a fast, modern frontend build tool that simplifies development and bundling.Vite allows us to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write modular, clean source code in separate files&lt;/li&gt;
&lt;li&gt;Use modern JavaScript or TypeScript&lt;/li&gt;
&lt;li&gt;Compile everything into a single minified JS file ready for production&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔗 How to Use It in Any Website
&lt;/h2&gt;

&lt;p&gt;After bundling the plugin we can easily embedd to any website using script tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;script src="./dist/poll.iife.js"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script&amp;gt;
      Poll.init({
        question: 'What is your favorite JS framework?',
        options: ['React', 'Vue', 'Svelte', 'Solid']
      });

      document.addEventListener('vote-submitted', (e) =&amp;gt; {
        alert(`You voted: ${e.detail.vote}`);
      });
    &amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works ansywhere without leaking styles or affecting the main page.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧾 Full Source Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.topoll-plugin"&gt;https://github.com/MehakB7/poll-plugin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>learning</category>
    </item>
    <item>
      <title>📬 Understanding GitHub Webhooks: Send Email Notifications on Pull Request Events Using Node.js</title>
      <dc:creator>Mehak.</dc:creator>
      <pubDate>Fri, 30 May 2025 11:34:12 +0000</pubDate>
      <link>https://dev.to/mehakb7/understanding-github-webhooks-send-email-notifications-on-pull-request-events-using-nodejs-54am</link>
      <guid>https://dev.to/mehakb7/understanding-github-webhooks-send-email-notifications-on-pull-request-events-using-nodejs-54am</guid>
      <description>&lt;p&gt;Recently, I became curious about how GitHub webhooks work. To deepen my understanding, I built a small Node.js project that sends an email notification every time a pull request (PR) is opened.&lt;/p&gt;

&lt;p&gt;Yes, GitHub already has a built-in notification system, but building your own gives you &lt;strong&gt;full control and a deeper understanding of the ecosystem&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔐 First, What’s HMAC?
&lt;/h2&gt;

&lt;p&gt;Before we dive into code, it’s important to understand how GitHub ensures that webhook events are secure.&lt;/p&gt;

&lt;p&gt;HMAC stands for &lt;strong&gt;Hash-based Message Authentication Code&lt;/strong&gt;. It’s a cryptographic technique used to verify &lt;strong&gt;both&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;integrity&lt;/strong&gt; of a message (that it hasn’t been tampered with)&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;authenticity&lt;/strong&gt; of the sender (that it’s really from GitHub)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub does this by hashing the body of the request with a shared secret you provide when creating the webhook. It then sends that signature along with the request using the &lt;code&gt;X-Hub-Signature-256&lt;/code&gt; header.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Webhook Levels
&lt;/h2&gt;

&lt;p&gt;Webhooks can be configured at three levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository level&lt;/strong&gt; – scoped to a single repo
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organization level&lt;/strong&gt; – applies to all repositories within an organization
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub App level&lt;/strong&gt; – used in GitHub Apps for deep integration across multiple repositories or organizations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this example, I used an &lt;strong&gt;organization-level webhook&lt;/strong&gt; so it applies to all repos in my org.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔎 Signature Verification
&lt;/h2&gt;

&lt;p&gt;To verify that the incoming request is really from GitHub, we need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Capture the raw request body before it’s parsed by Express.&lt;/li&gt;
&lt;li&gt;Recompute the HMAC signature using the same secret.&lt;/li&gt;
&lt;li&gt;Use a constant-time comparison to prevent timing attacks.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Here’s how I do it:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔸 Express Middleware
&lt;/h3&gt;

&lt;p&gt;We add a raw body parser to capture the exact payload:&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buf&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&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;This step is critical — HMAC must be calculated over the raw payload. If you parse it first, you’ll get a mismatch.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔸 Signature Verifier (&lt;code&gt;utils/verifier.js&lt;/code&gt;)
&lt;/h3&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;crypto&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&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="s1"&gt;./config.js&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;const&lt;/span&gt; &lt;span class="nx"&gt;verifySignature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-hub-signature-256&lt;/span&gt;&lt;span class="dl"&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&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;hmac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha-256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GIT_WEBHOOK_SECRET&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&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;expectedSignature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`sha256=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;expectedSignature&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;
  
  
  📬 Sending Email Notifications
&lt;/h2&gt;

&lt;p&gt;Once the signature is verified, I check if the action is &lt;code&gt;"opened"&lt;/code&gt; on a PR, and then send an email.&lt;/p&gt;

&lt;p&gt;I used &lt;strong&gt;Nodemailer&lt;/strong&gt; with Gmail as the SMTP service. Since my Gmail account uses 2FA, I generated an &lt;a href="https://myaccount.google.com/apppasswords" rel="noopener noreferrer"&gt;App Password&lt;/a&gt; to authenticate.Use the app password without spaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔸 Mailer (&lt;code&gt;services/emailService.js&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transporter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gmail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PASSWORD&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendPRrequestMail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recipents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&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;mailOption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;from&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;recipents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;transporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mailOption&lt;/span&gt;&lt;span class="p"&gt;,&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;result&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;error&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                 &lt;span class="nf"&gt;reject&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="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🚀 Exposing the Server for GitHub to Reach
&lt;/h2&gt;

&lt;p&gt;To allow GitHub to reach my local server, I had two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use a tunneling service like &lt;strong&gt;Ngrok&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Deploy to a cloud provider.
I chose to deploy to &lt;strong&gt;&lt;a href="https://render.com/" rel="noopener noreferrer"&gt;Render&lt;/a&gt;&lt;/strong&gt;, which has a generous free tier and makes deployment super easy. Once deployed, I used the Render URL as the webhook endpoint in GitHub.
---&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ul&gt;
&lt;li&gt;🔐 We used &lt;strong&gt;HMAC with a shared secret&lt;/strong&gt; to verify webhook authenticity.
&lt;/li&gt;
&lt;li&gt;📦 We used &lt;strong&gt;Nodemailer + Gmail&lt;/strong&gt; to send email notifications.
&lt;/li&gt;
&lt;li&gt;🌐 We deployed our app to &lt;strong&gt;Render&lt;/strong&gt; to make it accessible to GitHub.
&lt;/li&gt;
&lt;li&gt;🧠 And we learned that &lt;strong&gt;understanding webhooks at a low level&lt;/strong&gt; is a great way to grow as a developer.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;📂 &lt;strong&gt;Full Source Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can view the complete code for this project on GitHub:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://dev.togit-prrequest-mailer"&gt;https://github.com/Mehakb78/git-prrequest-mailer&lt;/a&gt;&lt;br&gt;
Feel free to clone it, experiment!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>javascript</category>
      <category>githubwebhooks</category>
    </item>
    <item>
      <title>Building Quizo: A Quiz App Using Kendo React Components and GenAI</title>
      <dc:creator>Mehak.</dc:creator>
      <pubDate>Sun, 23 Mar 2025 17:17:59 +0000</pubDate>
      <link>https://dev.to/mehakb7/building-quizo-a-quiz-app-using-kendo-react-components-and-genai-2dmm</link>
      <guid>https://dev.to/mehakb7/building-quizo-a-quiz-app-using-kendo-react-components-and-genai-2dmm</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/kendoreact"&gt;KendoReact Free Components Challenge&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built Quizo, a quiz application using Kendo React components. The app allows users to take quizzes on various subjects with a gamified experience. One of the standout features of Quizo is its GenAI-powered question generation, which enables users to generate questions dynamically on a selected topic. Initially, I also planned a PDF-to-Quiz feature, where uploading a PDF would extract text and generate questions. However, due to the cost of OpenAI’s API key, I had to put this feature on hold 😔.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;Website: &lt;a href="https://quiz-d1p7.vercel.app/" rel="noopener noreferrer"&gt;quizo-app&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/MehakB7/quiz" rel="noopener noreferrer"&gt;quizo-repo&lt;/a&gt;&lt;/p&gt;

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

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

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

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

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

&lt;h2&gt;
  
  
  KendoReact Experience
&lt;/h2&gt;

&lt;p&gt;Lets walks through the different Kendo React components I used, my implementation choices, and my overall experience.&lt;/p&gt;

&lt;h1&gt;
  
  
  Home page
&lt;/h1&gt;

&lt;p&gt;For the Home Page, I used the &lt;strong&gt;Card Component&lt;/strong&gt; from Kendo’s layout system. The Card component provides a flexible design structure, making it easy to display information in a visually appealing way.&lt;/p&gt;

&lt;h1&gt;
  
  
  Subject page
&lt;/h1&gt;

&lt;p&gt;On the  Subject Page, I utilized the following Kendo React components:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Breadcrumbs:&lt;/strong&gt; Used for easy navigation, allowing users to track their location within the app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SVG Icon Library&lt;/strong&gt;: Provided various SVG icons to improve the UI and enhance user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Grid&lt;/strong&gt;: This was one of the most impressive components. The Data Grid comes with various powerful features like resizing, filtering, and sorting. However, for my project, I used only a minimal set of these features.&lt;/p&gt;

&lt;h1&gt;
  
  
  Quiz page
&lt;/h1&gt;

&lt;p&gt;The Quiz Page required multiple components to handle different types of questions efficiently. Here’s how I structured it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Progress Bar&lt;/strong&gt;: Displays the user’s progress throughout the quiz.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Radio Button&lt;/strong&gt;: Used for single-choice questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checkbox&lt;/strong&gt; : Supports multi-choice questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;List Box&lt;/strong&gt;: Helps with sorting-based questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notification List&lt;/strong&gt;: Used to show real-time notifications to users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kendo Animation Library&lt;/strong&gt;: Implemented animation effects for smoother transitions and interactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  AIm to Impress
&lt;/h3&gt;

&lt;p&gt;For the GenAI-powered quiz generation, I used OpenAI to create quiz questions based on user-input topics. Users can either:&lt;br&gt;
Type a topic of their choice, and the AI will generate relevant questions.&lt;br&gt;
Select from predefined subjects, where the app fetches relevant questions accordingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Building Quizo was an exciting and rewarding journey!. I truly enjoyed every step of the process—from designing the UI to integrating AI-powered features. It was a fantastic opportunity to learn new things, including working with the OpenAI API, exploring its dashboard, and integrating its library into my project.&lt;/p&gt;

&lt;p&gt;One of the most impressive aspects was discovering the Kendo React component library. I was amazed by how it offers a component for almost every possible requirement, making development smoother and more efficient. Whether it was layout design, data presentation, or animations, Kendo React had a solution for everything, which made my experience even more enjoyable!&lt;/p&gt;

&lt;p&gt;I plan to revisit the PDF-to-Quiz feature in the future and explore more advanced AI capabilities. If you’re working on a similar project, I highly recommend exploring Kendo React for its rich component library!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>kendoreactchallenge</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Advent of spring</title>
      <dc:creator>Mehak.</dc:creator>
      <pubDate>Mon, 17 Feb 2025 11:56:15 +0000</pubDate>
      <link>https://dev.to/mehakb7/advent-of-spring-2bj4</link>
      <guid>https://dev.to/mehakb7/advent-of-spring-2bj4</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2025-02-12"&gt;Frontend Challenge - February Edition, CSS Art: February&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;p&gt;This is inspired by the early arrival of spring this February, bringing warmth and life sooner than expected. As I witnessed couples celebrating Valentine’s Week and older pairs setting beautiful relationship goals, I felt moved to capture this essence of love and renewal. The trees in bloom, the gentle falling leaves, and the serene atmosphere reflect the joy of love in all its forms—young and old, fleeting and everlasting. This piece is a tribute to the beauty of the season and the heartfelt moments it brings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&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%2Ffxbm75mtzhet6mqcz4n1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxbm75mtzhet6mqcz4n1.png" alt=" " width="800" height="301"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://codepen.io/MehakB77/pen/gbObybQ" rel="noopener noreferrer"&gt;https://codepen.io/MehakB77/pen/gbObybQ&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;Initially, I explored different ways to represent my idea in CSS, including creating a flip-book showcasing various events happening in February. However, I lastly decided to go with this scenic artwork, as it better captured the essence of the month.&lt;/p&gt;

&lt;p&gt;Most of the artwork is crafted using SVG, allowing for flexibility and clean visuals. A special shoutout to &lt;a href="//svgrepo.com"&gt; SVG Repo&lt;/a&gt;( for providing beautiful, freely available SVGs and to  &lt;a href="//mediamodifier.com/svg-editor"&gt;MediaModifier's SVG Editor&lt;/a&gt;, which helped me combine and modify SVGs effortlessly.&lt;/p&gt;

&lt;p&gt;By incorporating small animations and carefully placed elements, I aimed to depict the warmth of early spring, the joy of Valentine’s celebrations, and the beauty of love in all its forms.&lt;/p&gt;

</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>css</category>
      <category>html</category>
    </item>
    <item>
      <title>Pair Programming Redefined: My Journey with Copilot</title>
      <dc:creator>Mehak.</dc:creator>
      <pubDate>Sun, 19 Jan 2025 19:25:37 +0000</pubDate>
      <link>https://dev.to/mehakb7/air-programming-redefined-my-journey-with-copilot-1dh7</link>
      <guid>https://dev.to/mehakb7/air-programming-redefined-my-journey-with-copilot-1dh7</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github"&gt;GitHub Copilot Challenge &lt;/a&gt;: Fresh Starts&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I created the mini web version of the &lt;a href="https://play.google.com/store/apps/details?id=org.isoron.uhabits&amp;amp;hl=en_GB" rel="noopener noreferrer"&gt;habit&lt;/a&gt;.
&lt;/h2&gt;

&lt;p&gt;The application allows users to create, update, and delete habits, providing a structured way to monitor progress and achieve personal goals. The app is built using Next.js, Shadcn, Tailwind CSS, and TypeScript and use local storage to store user data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://habit-theta-three.vercel.app/" rel="noopener noreferrer"&gt;habit tracker&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zq23ah15mqw4k5x8m2h.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%2F2zq23ah15mqw4k5x8m2h.gif" alt=" " width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Repo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/MehakB7/habit" rel="noopener noreferrer"&gt;Habit tracker&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Copilot Experience
&lt;/h2&gt;

&lt;p&gt;After working with copilot i was able to complete task easy and learn new tricks to attend good productivity. Here is what I learn &lt;br&gt;
File Creation and Test Case Generation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Easily instruct Copilot to create new files or write comprehensive test cases for existing code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drag-and-Drop File Imports:&lt;br&gt;
Dragging and dropping files helps Copilot understand dependencies and automatically import the necessary components into the right places.&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: When asked to create a HabitContext, it provided files with all the required changes and imports.&lt;br&gt;
Code Creation from Links:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copilot can generate code based on shared links.&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: It created a ThemeProvider after analyzing the link provided.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Suggestions and Error Fixing:&lt;br&gt;
GitHub Copilot offers real-time suggestions and fixes errors in the code, which is extremely helpful and time-saving.&lt;br&gt;
Code, Extension, and Workspace Analysis:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Analyzes the entire codebase, extensions, and workspace to provide relevant results tailored to the context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code Summarization:&lt;br&gt;
Provides concise summaries of code functionality, making it easier to understand complex logic or unfamiliar files.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GitHub Models
&lt;/h2&gt;

&lt;p&gt;As I'm using the free version, I utilized the default Copilot model, GPT-35-Turbo, for my coding tasks. This model is incredibly efficient and provides reliable suggestions, making development faster and more manageable.. &lt;/p&gt;

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

&lt;p&gt;After using GitHub Copilot, I realized how easy it has become to complete small projects. Tasks that I previously abandoned because they took too much time or felt mundane can now be completed effortlessly with Copilot. It handles the repetitive work, allowing me to focus on the core and more creative aspects of development.&lt;/p&gt;

&lt;p&gt;P.S &lt;a href="https://play.google.com/store/apps/details?id=org.isoron.uhabits&amp;amp;hl=en_GB" rel="noopener noreferrer"&gt;habit&lt;/a&gt; is my favourite app if you want to create a habit you should try it.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Debugging 2024</title>
      <dc:creator>Mehak.</dc:creator>
      <pubDate>Sun, 12 Jan 2025 15:55:30 +0000</pubDate>
      <link>https://dev.to/mehakb7/debugging-2024-4kna</link>
      <guid>https://dev.to/mehakb7/debugging-2024-4kna</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/newyear"&gt;2025 New Year Writing challenge&lt;/a&gt;: Retro’ing and Debugging 2024.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As new year has started I'll refect to things happen in 2024, its high,low and everything in between. &lt;/p&gt;

&lt;h2&gt;
  
  
  What went well
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Healthwise&lt;/strong&gt;:&lt;br&gt;
2024  marked a significant improvement in my physical health. I managed to shed 5 kg, a result of better self-control and consciously addressing my overeating habits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Careerwise&lt;/strong&gt;:&lt;br&gt;
I began my journey as a Senior Frontend Developer at a new company. Connected with some awesome developers and learned many things.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Didn't went well
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Transition to Web3:&lt;/strong&gt;&lt;br&gt;
I had set a goal to transition into Web3, but I didn’t see it through.I didn't work hard and smart enough for this. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Doomscrolling:&lt;/strong&gt;&lt;br&gt;
I spent too much time mindlessly consuming content, which often left me unproductive and unmotivated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unfinished Projects:&lt;/strong&gt;&lt;br&gt;
Started side projects and abandoning them halfway.This habit of jumping between tasks diluted my focus and left me with a list of incomplete projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Health is a Lifestyle, Not a Goal&lt;/strong&gt;:&lt;br&gt;
Crash dieting or sporadic exercise won’t achieve lasting health. I’ve realized the importance of making fitness a lifestyle—walking 10,000 steps almost daily, eating mindfully, and staying consistent with my habits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Specific Goals Lead to Success:&lt;/strong&gt;&lt;br&gt;
Vague ambitions are ineffective. For instance, instead of saying “I want to learn a new framework,” I need a clear, actionable plan: decide which framework to learn, set a timeline, and identify resources to practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finish What I Start:&lt;/strong&gt;&lt;br&gt;
Jumping between tasks hinders progress. Before starting anything, &lt;em&gt;I need to ask:&lt;/em&gt;&lt;br&gt;
How will this improve my skills or life?&lt;br&gt;
What value will it add?&lt;br&gt;
By committing fully, I can avoid wasted time and see things through to completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step Out of My Comfort Zone:&lt;/strong&gt;&lt;br&gt;
Growth lies in discomfort. This year, I’m challenging myself to embrace situations and tasks I’d typically avoid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review Goals Regularly:&lt;/strong&gt;&lt;br&gt;
Weekly and monthly reviews are essential for tracking progress and identifying what’s not working. These checkpoints will help me course-correct and stay aligned with my larger objectives.&lt;/p&gt;

&lt;p&gt;PS: This is my first article, also something I would avoid in past. But it's time to grow.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>newyearchallenge</category>
      <category>career</category>
    </item>
  </channel>
</rss>
