gendesign/tradein-mvp/backend/tests/test_avito_relative_date.py
Light1YT cad3b77171 fix(tradein): Avito scraper now extracts listing_date для всех форматов
Real production state: **0/9302 (100%)** Avito listings имели NULL
listing_date. Audit показал regex matched только relative numeric
("5 дней назад") — Avito SERP сейчас использует:
- Keyword shortcuts «сегодня в 12:30», «вчера в 18:45», «позавчера», «только что»
- Absolute «18 мая», «5 июня в 12:30» (year inferred — current, или
  rollback к прошлому году если month в будущем больше чем на 30d)

Changes:
- Expand _parse_relative_date():
  * keyword check first (без \d+ regex match)
  * relative numeric (existing) — без изменений
  * absolute date regex с _RU_MONTHS dict + roll-back на prev year heuristic

Tests: 10/10 pass (4 existing + 6 new). Ruff clean.

Impact: 9302 Avito listings + new daily scrapes теперь будут иметь
listing_date. Это **прямо повысит linkage rate в /sales-vs-listings**
(PR K) с current ~5% до 30%+ (теоретически до 80% при listing_date
плотности).

Existing 9302 NULL — будут пересобраны при следующем full sweep после
deploy. Backfill detail page для each — отдельный operation скрипт
(out of scope, можно через docker exec ad-hoc).

Refs #564 (linkage rate improvement).
2026-05-27 17:55:01 +05:00

69 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import date, timedelta
from app.services.scrapers.avito import _parse_relative_date
def test_days_ago():
assert _parse_relative_date("5 дней назад") == date.today() - timedelta(days=5)
def test_week_ago():
assert _parse_relative_date("2 недели назад") == date.today() - timedelta(days=14)
def test_hour_ago_is_today():
assert _parse_relative_date("3 часа назад") == date.today()
def test_none_passthrough():
assert _parse_relative_date(None) is None
assert _parse_relative_date("") is None
assert _parse_relative_date("random text") is None
# Keyword shortcuts — без \d+ (Avito SERP формат для свежих cards)
def test_today_keyword():
assert _parse_relative_date("сегодня в 12:30") == date.today()
def test_yesterday_keyword():
assert _parse_relative_date("вчера в 18:45") == date.today() - timedelta(days=1)
def test_day_before_yesterday():
assert _parse_relative_date("позавчера") == date.today() - timedelta(days=2)
def test_just_now():
assert _parse_relative_date("только что") == date.today()
# Absolute dates — «18 мая», «5 июня в 12:30»
def test_absolute_date_recent():
today = date.today()
# Take a day-month combo near current (last month) — gradening для CI stability
if today.month >= 2:
target = date(today.year, today.month - 1, 15)
else:
target = date(today.year - 1, 12, 15)
ru_months = {
1: "января", 2: "февраля", 3: "марта", 4: "апреля",
5: "мая", 6: "июня", 7: "июля", 8: "августа",
9: "сентября", 10: "октября", 11: "ноября", 12: "декабря",
}
text = f"{target.day} {ru_months[target.month]} в 12:30"
assert _parse_relative_date(text) == target
def test_absolute_date_future_month_rolls_back():
"""Если today январь, а текст «5 декабря» — это прошлый год."""
today = date.today()
if today.month == 1:
# Today already January, «декабря» → previous year December
result = _parse_relative_date("5 декабря")
assert result == date(today.year - 1, 12, 5)
else:
# Skip when not January — would change semantics
result = _parse_relative_date("5 января")
# Either matches current year January (если уже прошло) или previous
assert result is not None and result.month == 1 and result.day == 5