Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
83 lines
3.3 KiB
TypeScript
83 lines
3.3 KiB
TypeScript
import { existsSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
import { aboutPage } from '@/content/aboutPage'
|
|
import { contactPage } from '@/content/publicPages'
|
|
import { FAQ_PAGE_SEO } from '@/lib/seo/faqPage'
|
|
import { HOST_GUIDE_SEO } from '@/lib/seo/hostGuidePage'
|
|
import { LEGAL_PAGE_SEO } from '@/lib/seo/legalPages'
|
|
import { buildCanonicalUrl, DEFAULT_OG_IMAGE_PATH, resolveOgImage, SITE_URL } from '@/lib/seo/metadata'
|
|
import { buildPublicPageMetadata } from '@/lib/seo/publicPageMetadata'
|
|
|
|
const TITLE_SUFFIX = ' | قبیله'
|
|
|
|
describe('SEO metadata policy', () => {
|
|
it('uses the production canonical origin without a trailing slash', () => {
|
|
expect(SITE_URL).toBe('https://ghabilee.ir')
|
|
expect(buildCanonicalUrl('/city/mashhad')).toBe('https://ghabilee.ir/city/mashhad')
|
|
expect(buildCanonicalUrl('category/art')).toBe('https://ghabilee.ir/category/art')
|
|
})
|
|
|
|
it('ships the default Open Graph image referenced by metadata', () => {
|
|
expect(DEFAULT_OG_IMAGE_PATH).toBe('/og-default.jpg')
|
|
expect(resolveOgImage()).toBe('https://ghabilee.ir/og-default.jpg')
|
|
expect(existsSync(join(process.cwd(), 'public', DEFAULT_OG_IMAGE_PATH))).toBe(true)
|
|
})
|
|
|
|
it('prefers a page-specific Open Graph image', () => {
|
|
expect(resolveOgImage('', null, 'https://cdn.example.com/category.png')).toBe('https://cdn.example.com/category.png')
|
|
})
|
|
|
|
it('keeps public static page titles and descriptions in SERP bounds', () => {
|
|
const legalPages = Object.values(LEGAL_PAGE_SEO)
|
|
const absoluteTitlePages = [aboutPage, FAQ_PAGE_SEO, HOST_GUIDE_SEO, ...legalPages]
|
|
const pages = [...absoluteTitlePages, contactPage]
|
|
|
|
for (const page of pages) {
|
|
const isAbsoluteTitlePage = absoluteTitlePages.includes(page as (typeof absoluteTitlePages)[number])
|
|
|
|
if (isAbsoluteTitlePage) {
|
|
expect(page.metaTitle.length).toBeLessThanOrEqual(60)
|
|
} else {
|
|
expect(page.metaTitle.length + TITLE_SUFFIX.length).toBeLessThanOrEqual(60)
|
|
}
|
|
expect(page.metaDescription.length).toBeGreaterThanOrEqual(70)
|
|
expect(page.metaDescription.length).toBeLessThanOrEqual(160)
|
|
}
|
|
})
|
|
|
|
it('builds absolute Open Graph URLs for public static pages', () => {
|
|
const metadata = buildPublicPageMetadata({
|
|
path: '/faq',
|
|
metaTitle: 'سؤالات متداول رزرو و میزبانی رویداد',
|
|
metaDescription: 'پاسخ سؤالات متداول درباره رزرو رویداد، پرداخت، لغو رزرو، بازگشت وجه و میزبانی در قبیله را اینجا بخوانید.',
|
|
})
|
|
|
|
expect(metadata.alternates).toMatchObject({ canonical: '/faq' })
|
|
expect(metadata.openGraph).toMatchObject({
|
|
url: 'https://ghabilee.ir/faq',
|
|
locale: 'fa_IR',
|
|
type: 'website',
|
|
})
|
|
expect(metadata.twitter).toMatchObject({ card: 'summary_large_image' })
|
|
})
|
|
|
|
it('makes relative public-page Open Graph images absolute', () => {
|
|
const metadata = buildPublicPageMetadata({
|
|
path: '/terms',
|
|
metaTitle: LEGAL_PAGE_SEO.terms.metaTitle,
|
|
metaDescription: LEGAL_PAGE_SEO.terms.metaDescription,
|
|
ogImage: '/images/public/terms-hero.avif',
|
|
})
|
|
|
|
expect(metadata.openGraph?.images).toEqual([
|
|
{
|
|
url: 'https://ghabilee.ir/images/public/terms-hero.avif',
|
|
alt: LEGAL_PAGE_SEO.terms.metaTitle,
|
|
},
|
|
])
|
|
})
|
|
})
|