You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 00:34:50