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('成都'); }); }); });