Django食谱应用Selenium测试报错:Element无法滚动到视图
问题:Django食谱应用Selenium测试报错ElementNotInteractableException
我正在开发一个基于Django的简易食谱应用,要实现按原产国排序食谱的功能,目前在练习测试驱动开发(TDD),用Selenium做测试。
测试时碰到个奇怪的错误:数据库里明明只有1条食谱数据,测试却会调用不存在的第二条食谱。本地跑python manage.py runserver后能正常和食谱卡片交互,但测试就报错。
错误信息:
ElementNotInteractableException: Message: Element
<a class="recipe-card" href="/recipes/2/">could not be scrolled into view
补充:后来我试着加了第二条食谱测试,结果又提示/recipes/3/无法滚动到视图。
相关代码
Selenium测试代码
class RecipesTest(LiveServerTestCase): def setUp(self): self.browser = WebDriver() self.browser.implicitly_wait(5) self.continent = Continent.objects.create(name='test_continent') self.country_1 = Country.objects.create(name='test country 1', continent = self.continent) self.country_2 = Country.objects.create(name='test country 2', continent = self.continent) self.recipe_1 = Recipe.objects.create(name='test recipe 1', country = self.country_1) def tearDown(self): self.browser.quit() def test_recipes(self): self.browser.get('%s%s' % (self.live_server_url, '/countries/1/')) recipe = self.browser.find_element(by=By.CLASS_NAME, value="recipe-card") recipe.click()
HTML模板(recipe_list.html)
{% extends 'core/base.html' %} {% block content %} {% for recipe in recipes %} <a href="{% url 'recipes:recipe_detail' recipe.id %}" class="recipe-card"> <div> <h1>{{recipe.name}}</h1> </div> </a> {% endfor %} {% endblock %}
Views.py
def recipe_list(request, pk): recipes = list(Recipe.objects.all()) return render(request, 'countries/recipe_list.html', { 'recipes': recipes, })
Urls.py
urlpatterns = [ path('', views.country_list, name='country_list'), path('<int:pk>/', views.recipe_list, name='recipe_list'), ]
修复方案
问题核心出在视图逻辑错误,再加上Selenium的交互等待问题,具体修复步骤如下:
1. 修正视图逻辑,过滤对应国家的食谱
当前recipe_list视图直接返回所有食谱,完全忽略了URL传入的国家ID(pk),导致无论访问哪个国家页面,都会显示系统中所有食谱(包括测试残留或意外生成的)。修改视图,只返回当前国家的食谱:
def recipe_list(request, pk): # 过滤出属于当前国家的食谱,而非所有食谱 recipes = Recipe.objects.filter(country_id=pk) return render(request, 'countries/recipe_list.html', { 'recipes': recipes, })
2. 优化Selenium测试的交互逻辑
ElementNotInteractableException通常是元素未完全加载、在视图外或被遮挡导致的,可通过两种方式解决:
方法一:用显式等待确保元素可点击
替换隐式等待为显式等待,确保元素完全加载并可交互:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def test_recipes(self): self.browser.get(f'{self.live_server_url}/countries/1/') # 等待元素可点击,超时时间10秒 recipe = WebDriverWait(self.browser, 10).until( EC.element_to_be_clickable((By.CLASS_NAME, "recipe-card")) ) recipe.click()
方法二:强制滚动到元素位置
如果元素在页面下方,先执行滚动操作再点击:
def test_recipes(self): self.browser.get(f'{self.live_server_url}/countries/1/') recipe = self.browser.find_element(by=By.CLASS_NAME, value="recipe-card") # 滚动到元素所在位置 self.browser.execute_script("arguments[0].scrollIntoView();", recipe) recipe.click()
3. 额外检查项
- 确认模板中没有重复渲染
recipe-card元素的逻辑 - 检查CSS样式,确保
recipe-card没有被设置为display: none或被其他元素遮挡
内容的提问来源于stack exchange,提问作者Christopher Benner
相关产品推荐
相关产品推荐

