admin/lib/seo/JsonLd.test.ts
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

122 lines
3.6 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { ORGANIZATION_ID, WEBSITE_ID, eventSchema, faqPage, organizationSchema, webSiteSchema } from '@/lib/seo/JsonLd'
const eventSchemaBase = {
name: 'رویداد نمونه',
description: null,
startDate: '2026-08-01T10:00:00Z',
endDate: '2026-08-01T12:00:00Z',
url: 'https://ghabilee.ir/e/sample',
isFree: false,
price: 250_000,
}
describe('SEO structured data', () => {
it('converts stored toman prices to rial for IRR offers', () => {
const schema = eventSchema({
...eventSchemaBase,
address: 'خیابان ولیعصر',
cityName: 'تهران',
})
expect(schema.offers).toMatchObject({ price: 2_500_000, priceCurrency: 'IRR' })
expect(schema).toMatchObject({ url: eventSchemaBase.url })
})
it('emits PostalAddress for a public street address', () => {
const schema = eventSchema({
...eventSchemaBase,
address: 'خیابان ولیعصر، پلاک ۱۲',
cityName: 'تهران',
})
expect(schema.location).toEqual({
'@type': 'Place',
name: 'تهران',
address: {
'@type': 'PostalAddress',
streetAddress: 'خیابان ولیعصر، پلاک ۱۲',
addressLocality: 'تهران',
addressCountry: 'IR',
},
})
})
it('uses generalArea when the exact address is hidden from crawlers', () => {
const schema = eventSchema({
...eventSchemaBase,
address: null,
generalArea: 'خیابان هفت‌تیر',
cityName: 'مشهد',
})
expect(schema.location.address).toEqual({
'@type': 'PostalAddress',
streetAddress: 'خیابان هفت‌تیر',
addressLocality: 'مشهد',
addressCountry: 'IR',
})
expect(JSON.stringify(schema.location)).not.toContain('null')
})
it('still emits addressLocality when only the city is public', () => {
const schema = eventSchema({
...eventSchemaBase,
address: null,
cityName: 'اصفهان',
})
expect(schema.location.address).toEqual({
'@type': 'PostalAddress',
addressLocality: 'اصفهان',
addressCountry: 'IR',
})
})
it('treats blank address strings as missing and does not leak them', () => {
const schema = eventSchema({
...eventSchemaBase,
address: ' ',
generalArea: 'محدوده ونک',
cityName: 'تهران',
})
expect(schema.location.address.streetAddress).toBe('محدوده ونک')
})
it('emits FAQPage entities for evergreen landing content', () => {
const schema = faqPage([{ question: 'چطور ثبت‌نام کنم؟', answer: 'از صفحه رویداد.' }])
expect(schema).toMatchObject({
'@type': 'FAQPage',
mainEntity: [{ '@type': 'Question', name: 'چطور ثبت‌نام کنم؟' }],
})
})
it('uses stable IDs to connect the website and its organization', () => {
const organization = organizationSchema({
url: 'https://ghabilee.ir',
logo: 'https://ghabilee.ir/logo.svg',
telephone: '+985100000000',
address: { locality: 'مشهد', streetAddress: 'نمونه' },
})
expect(organization).toMatchObject({
'@id': ORGANIZATION_ID,
alternateName: 'Ghabilee',
sameAs: ['https://www.instagram.com/Ghabilee_support/', 'https://t.me/Ghabilee_support'],
contactPoint: {
'@type': 'ContactPoint',
telephone: '+985100000000',
contactType: 'customer support',
areaServed: 'IR',
},
})
expect(webSiteSchema('https://ghabilee.ir')).toMatchObject({
'@id': WEBSITE_ID,
publisher: { '@id': ORGANIZATION_ID },
})
})
})