import { render } from '@testing-library/react';
import '@testing-library/jest-dom';
import { OrganizationSchema, WebsiteSchema, ServiceSchema, ProductSchema, FAQSchema, BreadcrumbSchema, LocalBusinessSchema } from './structured-data';
import { COMPANY_INFO } from '@/lib/constants';
describe('StructuredData', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('OrganizationSchema', () => {
it('should render organization schema', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
expect(script).toBeInTheDocument();
});
it('should contain organization name', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.name).toBe(COMPANY_INFO.name);
});
it('should contain organization type', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema['@type']).toBe('Organization');
});
it('should contain URL', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.url).toBe('https://www.novalon.cn');
});
});
describe('WebsiteSchema', () => {
it('should render website schema', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
expect(script).toBeInTheDocument();
});
it('should contain website type', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema['@type']).toBe('WebSite');
});
it('should contain website name', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.name).toBe(COMPANY_INFO.name);
});
it('should contain SearchAction potentialAction', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.potentialAction).toBeDefined();
expect(schema.potentialAction['@type']).toBe('SearchAction');
});
});
describe('ServiceSchema', () => {
it('should render with default props', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema['@type']).toBe('Service');
expect(schema.name).toBe('企业数字化转型服务');
expect(schema.provider.name).toBe(COMPANY_INFO.name);
});
it('should render with custom name and description', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.name).toBe('技术咨询');
expect(schema.description).toBe('专业的技术咨询服务');
});
it('should render with custom areaServed', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.areaServed.name).toBe('US');
});
it('should include offer catalog', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.hasOfferCatalog).toBeDefined();
expect(schema.hasOfferCatalog.itemListElement).toHaveLength(6);
});
});
describe('ProductSchema', () => {
const requiredProps = { name: 'Test Product', description: 'A test product description' };
it('should render with required props', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema['@type']).toBe('SoftwareApplication');
expect(schema.name).toBe('Test Product');
expect(schema.description).toBe('A test product description');
});
it('should use default category when not provided', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.applicationCategory).toBe('BusinessApplication');
});
it('should use custom category when provided', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.applicationCategory).toBe('GameApplication');
});
it('should include image when provided', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.image).toBe('https://www.novalon.cn/images/product.png');
});
it('should not include image when not provided', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.image).toBeUndefined();
});
it('should include offers and provider', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.offers).toBeDefined();
expect(schema.offers.priceCurrency).toBe('CNY');
expect(schema.provider.name).toBe(COMPANY_INFO.name);
});
});
describe('FAQSchema', () => {
const items = [
{ question: 'Q1?', answer: 'A1' },
{ question: 'Q2?', answer: 'A2' },
];
it('should render FAQ schema', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema['@type']).toBe('FAQPage');
});
it('should contain questions and answers', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.mainEntity).toHaveLength(2);
expect(schema.mainEntity[0].name).toBe('Q1?');
expect(schema.mainEntity[0].acceptedAnswer.text).toBe('A1');
expect(schema.mainEntity[1].name).toBe('Q2?');
expect(schema.mainEntity[1].acceptedAnswer.text).toBe('A2');
});
it('should render with empty items array', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.mainEntity).toHaveLength(0);
});
});
describe('BreadcrumbSchema', () => {
const items = [
{ name: 'Home', href: '/' },
{ name: 'Products', href: '/products' },
{ name: 'ERP', href: '/products/erp' },
];
it('should render breadcrumb schema', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema['@type']).toBe('BreadcrumbList');
});
it('should contain correct number of items', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.itemListElement).toHaveLength(3);
});
it('should have correct position values', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.itemListElement[0].position).toBe(1);
expect(schema.itemListElement[1].position).toBe(2);
expect(schema.itemListElement[2].position).toBe(3);
});
it('should have correct item URLs', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.itemListElement[0].item).toBe('https://www.novalon.cn/');
expect(schema.itemListElement[1].item).toBe('https://www.novalon.cn/products');
});
it('should render with single item', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.itemListElement).toHaveLength(1);
expect(schema.itemListElement[0].name).toBe('Home');
});
});
describe('LocalBusinessSchema', () => {
it('should render local business schema', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema['@type']).toBe('LocalBusiness');
});
it('should contain business name', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.name).toBe(COMPANY_INFO.name);
});
it('should contain address with geo coordinates', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.address).toBeDefined();
expect(schema.address.addressLocality).toBe('成都市');
expect(schema.geo).toBeDefined();
expect(schema.geo.latitude).toBe(30.5728);
});
it('should contain opening hours', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.openingHoursSpecification).toHaveLength(1);
expect(schema.openingHoursSpecification[0].dayOfWeek).toContain('Monday');
});
it('should contain area served', () => {
const { container } = render();
const script = container.querySelector('script[type="application/ld+json"]');
const schema = JSON.parse(script?.textContent || '{}');
expect(schema.areaServed).toHaveLength(3);
expect(schema.areaServed[0].name).toBe('成都');
});
});
});