feat: add /compare and /guides/quick-start SEO pages
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 9m51s

- Compare page: SnapAPI vs ScreenshotOne, URLBox, ApiFlash, CaptureKit, GetScreenshot
- Quick-start guide: 5-step developer tutorial with cURL, GET, SDK examples
- Both pages: dark theme, JSON-LD, OG tags, canonical URLs, mobile responsive
- Added clean URL redirects in routing
- Updated sitemap.xml and index.html nav
- Added seo-pages.test.ts (10 tests, all passing)
This commit is contained in:
Hoid 2026-03-02 12:07:08 +01:00
parent e9ee3a6c2c
commit 9d1170fb9a
6 changed files with 547 additions and 0 deletions

View file

@ -135,6 +135,10 @@ for (const page of ["social-media-previews", "website-monitoring", "pdf-reports"
app.get(`/use-cases/${page}`, (_req, res) => res.redirect(301, `/use-cases/${page}.html`));
}
// Clean URLs for SEO pages
app.get("/compare", (_req, res) => res.redirect(301, "/compare.html"));
app.get("/guides/quick-start", (_req, res) => res.redirect(301, "/guides/quick-start.html"));
// Static files (landing page)
app.use(express.static(path.join(__dirname, "../public"), { etag: true }));

View file

@ -0,0 +1,107 @@
import { describe, it, expect } from 'vitest'
import request from 'supertest'
import express from 'express'
import path from 'path'
import { fileURLToPath } from 'url'
import fs from 'fs'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const publicDir = path.join(__dirname, '../../../public')
function createApp() {
const app = express()
// Clean URL redirects matching index.ts
app.get('/compare', (_req, res) => res.redirect(301, '/compare.html'))
app.get('/guides/quick-start', (_req, res) => res.redirect(301, '/guides/quick-start.html'))
app.use(express.static(publicDir, { etag: true }))
return app
}
describe('Compare Page', () => {
const app = createApp()
it('GET /compare.html returns 200', async () => {
const res = await request(app).get('/compare.html')
expect(res.status).toBe(200)
expect(res.headers['content-type']).toContain('text/html')
})
it('GET /compare redirects 301 to .html', async () => {
const res = await request(app).get('/compare')
expect(res.status).toBe(301)
expect(res.headers.location).toBe('/compare.html')
})
it('contains required SEO elements', async () => {
const res = await request(app).get('/compare.html')
const html = res.text
expect(html).toMatch(/<title>.+<\/title>/)
expect(html).toMatch(/<meta name="description" content=".+"/)
expect(html).toMatch(/<meta property="og:title"/)
expect(html).toMatch(/<meta property="og:description"/)
expect(html).toMatch(/<meta property="og:type" content="website"/)
expect(html).toMatch(/<link rel="canonical"/)
expect(html).toMatch(/<meta name="twitter:card"/)
expect(html).toContain('"@type":"WebPage"')
})
it('mentions competitors factually', async () => {
const res = await request(app).get('/compare.html')
const html = res.text
for (const competitor of ['ScreenshotOne', 'URLBox', 'ApiFlash', 'CaptureKit', 'GetScreenshot']) {
expect(html).toContain(competitor)
}
})
})
describe('Quick-Start Guide', () => {
const app = createApp()
it('GET /guides/quick-start.html returns 200', async () => {
const res = await request(app).get('/guides/quick-start.html')
expect(res.status).toBe(200)
expect(res.headers['content-type']).toContain('text/html')
})
it('GET /guides/quick-start redirects 301 to .html', async () => {
const res = await request(app).get('/guides/quick-start')
expect(res.status).toBe(301)
expect(res.headers.location).toBe('/guides/quick-start.html')
})
it('contains required SEO elements', async () => {
const res = await request(app).get('/guides/quick-start.html')
const html = res.text
expect(html).toMatch(/<title>.+<\/title>/)
expect(html).toMatch(/<meta name="description" content=".+"/)
expect(html).toMatch(/<meta property="og:title"/)
expect(html).toMatch(/<meta property="og:description"/)
expect(html).toMatch(/<link rel="canonical"/)
expect(html).toMatch(/<meta name="twitter:card"/)
expect(html).toContain('"@type":"HowTo"')
})
it('contains step-by-step content', async () => {
const res = await request(app).get('/guides/quick-start.html')
const html = res.text
expect(html).toContain('curl')
expect(html).toContain('API key')
expect(html).toContain('GET')
})
})
describe('Sitemap & Index updates', () => {
it('sitemap contains new URLs', () => {
const sitemap = fs.readFileSync(path.join(publicDir, 'sitemap.xml'), 'utf-8')
expect(sitemap).toContain('https://snapapi.eu/compare')
expect(sitemap).toContain('https://snapapi.eu/guides/quick-start')
})
it('index.html has links to new pages', () => {
const index = fs.readFileSync(path.join(publicDir, 'index.html'), 'utf-8')
expect(index).toContain('/compare')
expect(index).toContain('/guides/quick-start')
})
})