diff --git a/.env.test.example b/.env.test.example new file mode 100644 index 00000000..15e66b8f --- /dev/null +++ b/.env.test.example @@ -0,0 +1,16 @@ +# Test Environment Variables +# Copy this file to .env.test and fill in your values + +# WordPress API Configuration +WORDPRESS_API_URL=https://wp.keploy.io/graphql +NEXT_PUBLIC_WORDPRESS_API_URL=https://wp.keploy.io/graphql + +# Test Configuration +# Base URL for the application under test +BASE_URL=http://localhost:3000/blog + +# Timeouts (milliseconds) +TEST_TIMEOUT=30000 +TEST_EXPECT_TIMEOUT=10000 +TEST_ACTION_TIMEOUT=15000 +TEST_NAVIGATION_TIMEOUT=30000 diff --git a/.github/scripts/lighthouse-report.js b/.github/scripts/lighthouse-report.js deleted file mode 100644 index 037110ae..00000000 --- a/.github/scripts/lighthouse-report.js +++ /dev/null @@ -1,70 +0,0 @@ -const fs = require('fs'); -const path = require('path'); - -const dir = '.lighthouseci'; -const files = fs.readdirSync(dir).filter(file => file.endsWith('.report.json')); - -if (files.length < 2) { - console.error('❌ Not enough Lighthouse reports found.'); - process.exit(1); -} - -let mainReport = ''; -let prReport = ''; - -for (const file of files) { - const json = JSON.parse(fs.readFileSync(path.join(dir, file), 'utf8')); - const url = json.finalUrl; - - if (url.includes('3000')) mainReport = json; - else if (url.includes('3001')) prReport = json; -} - -function extract(report) { - return { - performance: report.categories.performance.score * 100, - accessibility: report.categories.accessibility.score * 100, - bestPractices: report.categories['best-practices'].score * 100, - seo: report.categories.seo.score * 100, - }; -} - -const main = extract(mainReport); -const pr = extract(prReport); - -const md = ` -**🔍 Lighthouse Scores** - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Metric⚡ PR Branch📦 Main Branch
Performance${pr.performance}${main.performance}
Accessibility${pr.accessibility}${main.accessibility}
Best Practices${pr.bestPractices}${main.bestPractices}
SEO${pr.seo}${main.seo}
-`; - - -fs.writeFileSync('lighthouse-comment.md', md); -console.log('✅ Comments written to lighthouse-comment.md'); - \ No newline at end of file diff --git a/.github/workflows/lighthouse_comment.yml b/.github/workflows/lighthouse_comment.yml index 403ac4e7..fb1fbb58 100644 --- a/.github/workflows/lighthouse_comment.yml +++ b/.github/workflows/lighthouse_comment.yml @@ -1,29 +1,51 @@ -name: Lighthouse – Comment +name: Lighthouse CI on: - workflow_run: - workflows: ["Lighthouse – Run"] - types: - - completed + workflow_dispatch: permissions: - issues: write + contents: read pull-requests: write + issues: write jobs: - comment: + lighthouse: runs-on: ubuntu-latest steps: - - name: Download Lighthouse comment artifact - uses: actions/download-artifact@v4 + # 1. Checkout code + - name: Checkout repo + uses: actions/checkout@v4 + + # 2. Setup Node + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 18 + + # 3. Install dependencies (if needed) + - name: Install dependencies + run: npm install + + # 4. Build project (if React/Vite) + - name: Build project + run: npm run build + + # 5. Run Lighthouse CI + - name: Run Lighthouse CI + uses: treosh/lighthouse-ci-action@v11 with: - name: lighthouse-comment - path: . + urls: | + https://your-live-site-url.com + uploadArtifacts: true - - name: Ensure comment file exists - run: test -f lighthouse-comment.md + # 6. Generate comment file + - name: Create Lighthouse comment + run: | + echo "## 🚀 Lighthouse Report" > lighthouse-comment.md + echo "Check performance report in artifacts." >> lighthouse-comment.md + # 7. Post comment on PR - name: Post Lighthouse comment uses: peter-evans/create-or-update-comment@v4 with: diff --git a/.github/workflows/lighthouse_runner.yml b/.github/workflows/lighthouse_runner.yml index 9ca7247e..2309cadd 100644 --- a/.github/workflows/lighthouse_runner.yml +++ b/.github/workflows/lighthouse_runner.yml @@ -72,11 +72,4 @@ jobs: http://localhost:3000/blog uploadArtifacts: true - - name: Generate Lighthouse comment - run: node .github/scripts/lighthouse-report.js - - name: Upload Lighthouse comment artifact - uses: actions/upload-artifact@v4 - with: - name: lighthouse-comment - path: lighthouse-comment.md diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 00000000..793f17da --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,54 @@ +name: Playwright E2E Tests + +on: + pull_request: + branches: [ main, master ] + push: + branches: [ main, master ] + +jobs: + test: + name: E2E Tests (chromium) + timeout-minutes: 20 + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Install Playwright Browsers + run: npx playwright install --with-deps chromium + + - name: Run Playwright tests + run: npm run test:e2e -- --project=chromium + env: + CI: true + BASE_URL: http://localhost:3000/blog + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-results-chromium + path: test-results/ + retention-days: 7 + + - name: Upload test report + if: failure() + uses: actions/upload-artifact@v4 + with: + name: playwright-report-chromium + path: playwright-report/ + retention-days: 7 + diff --git a/.gitignore b/.gitignore index 53a5bbb9..621ad352 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,9 @@ yarn-debug.log* yarn-error.log* # local env files -.env* +.env +.env*.local +.env.test # vercel .vercel @@ -37,3 +39,11 @@ yarn-error.log* next-env.d.ts .early.coverage + +# Playwright +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +/playwright/.auth/ diff --git a/components/AuthorCard.tsx b/components/AuthorCard.tsx index 8a130d49..5ee31e5d 100644 --- a/components/AuthorCard.tsx +++ b/components/AuthorCard.tsx @@ -71,6 +71,7 @@ const AuthorCard: React.FC = ({ return (
diff --git a/components/BlogSidebar.tsx b/components/BlogSidebar.tsx index 15b197bd..894b3b05 100644 --- a/components/BlogSidebar.tsx +++ b/components/BlogSidebar.tsx @@ -1,5 +1,6 @@ import React, { useState } from "react"; import Link from "next/link"; +import Image from "next/image"; import { useRouter } from "next/router"; import { FaFacebook, @@ -103,46 +104,62 @@ function SidebarShare() { /* ── Ad / CTA Banner ── */ function SidebarAdBanner() { + // Image size (adjust as needed) + // Remove fixed width/height from container, let image set size + const [imgError, setImgError] = React.useState(false); return (
-

- Try Keploy for free -

- -

- Generate test cases and data mocks with one click. Reduce unit test development time by 90%. -

- - - Sign up - + {!imgError ? ( + + Keploy Ad Banner setImgError(true)} + /> + + ) : ( +
+

+ Try Keploy for free +

+

+ Generate test cases and data mocks with one click. Reduce unit test development time by 90%. +

+ + Sign up + +
+ )}
); } diff --git a/components/NotFoundPage.tsx b/components/NotFoundPage.tsx index e2bd2731..2456c468 100644 --- a/components/NotFoundPage.tsx +++ b/components/NotFoundPage.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useMemo } from "react"; import Header from "./header"; import Container from "./container"; import Image from "next/image"; @@ -48,18 +48,21 @@ const NotFoundPage = ({ latestPosts, communityPosts, technologyPosts }: NotFound setSearchTerm(event.target.value); }; - const allPosts = [ + const allPosts = useMemo(() => [ ...(latestPosts?.edges || []), ...(communityPosts?.edges || []), ...(technologyPosts?.edges || []) - ].filter((post, index, self) => + ].filter((post, index, self) => index === self.findIndex(p => p.node.slug === post.node.slug) - ); + ), [latestPosts, communityPosts, technologyPosts]); - const filteredAllPosts = allPosts.filter(({ node }) => - node.title.toLowerCase().includes(searchTerm.toLowerCase()) || - node.excerpt.toLowerCase().includes(searchTerm.toLowerCase()) - ); + const filteredAllPosts = useMemo(() => { + const term = searchTerm.toLowerCase(); + return allPosts.filter(({ node }) => + (node.title || '').toLowerCase().includes(term) || + (node.excerpt || '').toLowerCase().includes(term) + ); + }, [allPosts, searchTerm]); return ( <> diff --git a/components/ScrollToTop.tsx b/components/ScrollToTop.tsx index 8311c511..c88ba0c3 100644 --- a/components/ScrollToTop.tsx +++ b/components/ScrollToTop.tsx @@ -72,6 +72,7 @@ const ScrollToTop = () => { return (
) : ( -