cover the new paths, especially the ones that fail silently
خطاهای این پروژه خاموشاند: نامِ اشتباهِ collection یا فیلترِ نخورده نتیجهی خالی میدهد نه استثنا، و دستیار فقط بدتر جواب میدهد. این تستها نگهبانِ همانجاهایند. TextbookLayoutTests بررسی میکند رشتهی هر فصل بینِ ingest و retrieval یکی باشد و بازهی صفحهها پیوسته بماند. IngestBookResumeTests مطمئن میشود صفحهی بیمسئله دوبار پول نمیگیرد، صفحهی خطادار در اجرای بعد دوباره سراغش میروند، و upsertِ شکستخورده rollback میشود. LessonContextResolutionTests نگهبانِ نرمالسازیِ «پایه نهم» → «ریاضی نهم» است و اینکه مسیرِ gradeId و مسیرِ lessonId به یک collection برسند. GradeAwarePromptTests جلوی برگشتنِ لحنِ دبستانی برای پایههای بالا را میگیرد. FollowUpStaysGroundedTests پیامِ دومِ یک گفتگو را هم مستند نگه میدارد. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -712,3 +712,70 @@ class ReadThrottleTests(TestCase):
|
||||
f'/api/home?grade={self.grade.id}',
|
||||
HTTP_AUTHORIZATION=f'Bearer {self.token}').status_code)
|
||||
self.assertIn(429, codes)
|
||||
|
||||
|
||||
class HomeGradeFallbackTests(TestCase):
|
||||
"""
|
||||
/api/home باید در نبودِ ?grade= از پایهی ذخیرهشدهی خودِ کاربر استفاده کند.
|
||||
|
||||
پیشتر اینطور نبود و نتیجهاش در اپ این میشد: کاربر در صفحهی آشنایی پایه
|
||||
را انتخاب میکرد و بعد صفحهی خانه خالی میآمد.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
_django_cache.clear()
|
||||
self.client = APIClient()
|
||||
self.user = User.objects.create(device_id='dev-home-fallback', is_guest=True, name='')
|
||||
self.token = issue_access_token(self.user.id)
|
||||
|
||||
self.grade = Grade.objects.create(title='پایه نهم', icon='grade-9', color='#FF9800')
|
||||
unit = Unit.objects.create(grade=self.grade, title='فصل ۱', order=1)
|
||||
node = Node.objects.create(unit=unit, title='درس ۱', order=1)
|
||||
Lesson.objects.create(node=node, title='توان صحیح', intro_text='.')
|
||||
|
||||
def tearDown(self):
|
||||
_django_cache.clear()
|
||||
|
||||
def _home(self, query=''):
|
||||
return self.client.get(f'/api/home{query}', HTTP_AUTHORIZATION=f'Bearer {self.token}')
|
||||
|
||||
def test_uses_the_saved_grade_when_no_param_is_given(self):
|
||||
self.user.grade_id = self.grade.id
|
||||
self.user.save(update_fields=['grade_id'])
|
||||
|
||||
response = self._home()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.data['units']), 1)
|
||||
self.assertEqual(response.data['units'][0]['title'], 'فصل ۱')
|
||||
|
||||
def test_explicit_param_wins_over_the_saved_grade(self):
|
||||
other = Grade.objects.create(title='پایه دهم', icon='grade-10', color='#E91E63')
|
||||
unit = Unit.objects.create(grade=other, title='فصل مثلثات', order=1)
|
||||
node = Node.objects.create(unit=unit, title='درس ۱', order=1)
|
||||
Lesson.objects.create(node=node, title='سینوس', intro_text='.')
|
||||
self.user.grade_id = self.grade.id
|
||||
self.user.save(update_fields=['grade_id'])
|
||||
|
||||
response = self._home(f'?grade={other.id}')
|
||||
|
||||
self.assertEqual(response.data['units'][0]['title'], 'فصل مثلثات')
|
||||
|
||||
def test_user_without_a_grade_gets_an_empty_map_not_an_error(self):
|
||||
response = self._home()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data['units'], [])
|
||||
|
||||
def test_unknown_explicit_grade_is_still_404(self):
|
||||
self.assertEqual(self._home('?grade=999999').status_code, 404)
|
||||
|
||||
def test_a_deleted_saved_grade_degrades_to_an_empty_map(self):
|
||||
# پایهای که کاربر ذخیره کرده حذف شده — این خطای کاربر نیست.
|
||||
self.user.grade_id = 999999
|
||||
self.user.save(update_fields=['grade_id'])
|
||||
|
||||
response = self._home()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data['units'], [])
|
||||
|
||||
Reference in New Issue
Block a user