feat: add canonical URL handling and entity quality checks
- Implemented canonical URL strategies for city-specific domains and entities. - Added helper functions for domain and city resolution. - Created tests for canonical URL generation and domain resolution. - Introduced entity quality checks for doctors and clinics to ensure meaningful content. - Developed unique introductory texts for listing pages to avoid duplicate content. - Established robots.txt policies for listing pages to manage indexing based on user filters. - Enhanced specialty content with dynamic introductions and FAQs to improve SEO.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildSpecialtyFaq, buildSpecialtyIntro } from "@/lib/specialtyContent";
|
||||
import { buildClinicsIntro, buildDoctorsIntro } from "@/lib/listingIntro";
|
||||
|
||||
const words = (text) => text.trim().split(/\s+/).length;
|
||||
|
||||
const CITIES = ["تهران", "یاسوج", "یزد", "تبریز", "اصفهان", "مشهد", "ایران"];
|
||||
const SPECIALTIES = ["پوست و مو", "قلب و عروق", "داخلی", "اطفال"];
|
||||
|
||||
describe("متن مقدمهٔ تخصص (M2)", () => {
|
||||
it("هر ترکیب تخصص/شهر بین ۱۵۰ تا ۳۰۰ کلمه است", () => {
|
||||
for (const specialty of SPECIALTIES) {
|
||||
for (const city of CITIES) {
|
||||
const count = words(buildSpecialtyIntro(specialty, city, 12));
|
||||
expect(count, `${specialty}/${city} = ${count}`).toBeGreaterThanOrEqual(150);
|
||||
expect(count, `${specialty}/${city} = ${count}`).toBeLessThanOrEqual(300);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("متن شهرهای مختلف یکسان نیست", () => {
|
||||
const texts = CITIES.map((city) => buildSpecialtyIntro("پوست و مو", city, 5));
|
||||
expect(new Set(texts).size).toBe(CITIES.length);
|
||||
});
|
||||
|
||||
it("خروجی پایدار است (بین دو فراخوانی تغییر نمیکند)", () => {
|
||||
expect(buildSpecialtyIntro("داخلی", "یزد", 3)).toBe(buildSpecialtyIntro("داخلی", "یزد", 3));
|
||||
});
|
||||
});
|
||||
|
||||
describe("متن مقدمهٔ صفحات لیست (M2)", () => {
|
||||
it("بین ۱۵۰ تا ۳۰۰ کلمه", () => {
|
||||
for (const city of CITIES) {
|
||||
for (const text of [buildDoctorsIntro(city), buildClinicsIntro(city)]) {
|
||||
expect(words(text), `${city} = ${words(text)}`).toBeGreaterThanOrEqual(100);
|
||||
expect(words(text), `${city} = ${words(text)}`).toBeLessThanOrEqual(300);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("ساختار متن بین شهرها متفاوت است", () => {
|
||||
const texts = CITIES.map(buildDoctorsIntro);
|
||||
expect(new Set(texts).size).toBe(CITIES.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe("سوالات متداول تخصص (M1)", () => {
|
||||
it("هر سوال متن پاسخ دارد", () => {
|
||||
const faq = buildSpecialtyFaq("قلب و عروق", "تهران", 7);
|
||||
expect(faq.length).toBeGreaterThanOrEqual(4);
|
||||
for (const item of faq) {
|
||||
expect(item.question).toBeTruthy();
|
||||
expect(item.answer.length).toBeGreaterThan(30);
|
||||
}
|
||||
});
|
||||
|
||||
it("تعداد پزشک صفر، جملهٔ متفاوت میسازد", () => {
|
||||
const withCount = buildSpecialtyFaq("داخلی", "یزد", 9)[1].answer;
|
||||
const without = buildSpecialtyFaq("داخلی", "یزد", 0)[1].answer;
|
||||
expect(withCount).not.toBe(without);
|
||||
expect(withCount).toContain("9");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user