feat: add 3 SEO use case pages with clean URLs, sitemap, and index section
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 10m32s
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 10m32s
This commit is contained in:
parent
195a656a7d
commit
e9ee3a6c2c
8 changed files with 729 additions and 2 deletions
|
|
@ -130,6 +130,11 @@ for (const page of ["privacy", "terms", "impressum", "status", "usage"]) {
|
|||
app.get(`/${page}`, (_req, res) => res.redirect(301, `/${page}.html`));
|
||||
}
|
||||
|
||||
// Clean URLs for use case pages
|
||||
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`));
|
||||
}
|
||||
|
||||
// Static files (landing page)
|
||||
app.use(express.static(path.join(__dirname, "../public"), { etag: true }));
|
||||
|
||||
|
|
|
|||
84
src/routes/__tests__/use-cases.test.ts
Normal file
84
src/routes/__tests__/use-cases.test.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { describe, it, expect, vi } 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')
|
||||
|
||||
// Build a minimal app that mirrors index.ts routing
|
||||
function createApp() {
|
||||
const app = express()
|
||||
|
||||
// Clean URLs for use-case pages
|
||||
const useCasePages = ['social-media-previews', 'website-monitoring', 'pdf-reports']
|
||||
for (const page of useCasePages) {
|
||||
app.get(`/use-cases/${page}`, (_req, res) => res.redirect(301, `/use-cases/${page}.html`))
|
||||
}
|
||||
|
||||
app.use(express.static(publicDir, { etag: true }))
|
||||
return app
|
||||
}
|
||||
|
||||
const useCases = [
|
||||
{ slug: 'social-media-previews', title: 'OG Images', keywords: ['og image', 'social media preview'] },
|
||||
{ slug: 'website-monitoring', title: 'Website Monitoring', keywords: ['website screenshot monitoring', 'visual regression'] },
|
||||
{ slug: 'pdf-reports', title: 'Reports', keywords: ['thumbnail', 'web page preview'] },
|
||||
]
|
||||
|
||||
describe('Use Case Pages', () => {
|
||||
const app = createApp()
|
||||
|
||||
for (const uc of useCases) {
|
||||
describe(uc.slug, () => {
|
||||
it(`GET /use-cases/${uc.slug}.html returns 200`, async () => {
|
||||
const res = await request(app).get(`/use-cases/${uc.slug}.html`)
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.headers['content-type']).toContain('text/html')
|
||||
})
|
||||
|
||||
it(`GET /use-cases/${uc.slug} redirects 301 to .html`, async () => {
|
||||
const res = await request(app).get(`/use-cases/${uc.slug}`)
|
||||
expect(res.status).toBe(301)
|
||||
expect(res.headers.location).toBe(`/use-cases/${uc.slug}.html`)
|
||||
})
|
||||
|
||||
it('contains required SEO elements', async () => {
|
||||
const res = await request(app).get(`/use-cases/${uc.slug}.html`)
|
||||
const html = res.text
|
||||
|
||||
// Title tag
|
||||
expect(html).toMatch(/<title>.+<\/title>/)
|
||||
// Meta description
|
||||
expect(html).toMatch(/<meta name="description" content=".+"/)
|
||||
// OG tags
|
||||
expect(html).toMatch(/<meta property="og:title"/)
|
||||
expect(html).toMatch(/<meta property="og:description"/)
|
||||
expect(html).toMatch(/<meta property="og:type" content="article"/)
|
||||
// JSON-LD
|
||||
expect(html).toContain('"@type":"Article"')
|
||||
// H1
|
||||
expect(html).toMatch(/<h1[^>]*>.+<\/h1>/)
|
||||
// Canonical
|
||||
expect(html).toMatch(/<link rel="canonical"/)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
it('sitemap contains all use case URLs', () => {
|
||||
const sitemap = fs.readFileSync(path.join(publicDir, 'sitemap.xml'), 'utf-8')
|
||||
for (const uc of useCases) {
|
||||
expect(sitemap).toContain(`https://snapapi.eu/use-cases/${uc.slug}`)
|
||||
}
|
||||
})
|
||||
|
||||
it('index.html contains use cases section', () => {
|
||||
const index = fs.readFileSync(path.join(publicDir, 'index.html'), 'utf-8')
|
||||
expect(index).toContain('id="use-cases"')
|
||||
for (const uc of useCases) {
|
||||
expect(index).toContain(`/use-cases/${uc.slug}`)
|
||||
}
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue