手动获取数据到 Django 视图,但不使用 Selenium。为什么?
Fetching data to Django view working manually but not with Selenium. Why?
我正在使用 Selenium 测试我创建的 Django 应用程序。
以下代码工作正常 'manually' 但不适用于 Selenium。
为什么 ?
## dummy.html ##
{% extends 'main.html' %}
{% load static %}
{% block title %}
Dummy page
{% endblock title %}
{% block meta %}
<meta name="robots" content="noindex">
{% endblock meta %}
{% block content %}
<div class="container">
<div class="row">
<div class="col d-flex justify-content-center align-items-center">
<h1 class="text-primary font-handwriting">Dummy page</h1>
</div>
</div>
<br>
<div class="row">
<div class="col d-flex justify-content-center align-items-center">
<h2 class="text-primary font-heading">THIS IS A DUMMY PAGE</h2>
</div>
</div>
<br>
<div class="row">
<button id="trigger-dummy-button" type="button"
class="btn btn-primary text-white font-base fw-bold text-uppercase"
title="Trigger dummy button">Trigger dummy button</button>
</div>
</div>
<script>
var someDummyURL = "{% url 'home_page:another_dummy_view' %}";
</script>
<script type="module" src="{% static '/js/dummy.js' %}"> </script>
{% endblock content %}
## dummy.js ##
'use strict';
var newValue;
async function postDummyFunction(request) {
var response = await fetch(request);
if (response.ok) {
var updatedReturnedValue = await response.json();
newValue = updatedReturnedValue.returnedValue;
alert('-- postDummyFunction -- | newValue = ' + newValue);
// When the script is triggered manually by clicking, response.ok = true and newValue = "Hello World OK !"
return newValue;
} else {
// When the script is triggered by Selenium, response.ok = false
alert('-- postDummyFunction -- | response.ok ? ' + response.ok);
return false;
}
};
document.addEventListener("DOMContentLoaded", function () {
var triggerDummyButton = document.getElementById("trigger-dummy-button");
var someDummyVariable = "Hello World ";
var toPostURL = someDummyURL;
triggerDummyButton.onclick = (e) => {
var data = {"dummyValue": someDummyVariable};
var request = new Request(toPostURL, {
method: "POST",
mode: "same-origin",
headers: {
"Content-Type": "application/json",
'X-Requested-With':'XMLHttpRequest',
"Accept": "application/json",
'X-CSRFToken': csrftoken
},
body: JSON.stringify(data),
});
// Works with Selenium
// if alert(data.dummyValue), browser correctly displays "Hello World "
postDummyFunction(request);
}
});
## views.py ##
import json
from django.shortcuts import render, redirect
from django.http import JsonResponse
def dev_dummy_script(request):
context = {}
return render(request, "dummy.html", context)
def another_dummy_view(request):
if request.method == "POST":
post_data = json.loads(request.body.decode("utf-8"))
posted_value = post_data["dummyValue"]
value_to_return = posted_value + " " + "OK !"
response = JsonResponse({"returnedValue": value_to_return})
return response
## test_selenium.py ##
import time
import os
from decimal import Decimal
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from core.settings import BASE_DIR
PATH_TO_WEBDRIVER_CHROME = os.path.join(
BASE_DIR, "test", "webdrivers", "chromedriver.exe"
)
PATH_TO_WEBDRIVER_FIREFOX = os.path.join(BASE_DIR, "test", "webdrivers", "geckodriver")
SHORT_TIME = 2.5
LONG_TIME = 6
DEFAULT_WAIT_TIME = 10
class FooTest(StaticLiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox(executable_path=PATH_TO_WEBDRIVER_FIREFOX)
def tearDown(self):
self.browser.close()
def testfoo(self):
self.browser.get(("%s%s" % (self.live_server_url, "/dev/dummy_script/")))
elem_trigger_btn = WebDriverWait(self.browser, DEFAULT_WAIT_TIME).until(
EC.element_to_be_clickable((By.ID, "trigger-dummy-button"))
)
elem_trigger_btn.click()
time.sleep(LONG_TIME)
self.browser.close()
版本
- Django==3.2
- 硒==3.141.0
- 火狐 96.0.3
如果我触发 python manage.py runserver
,手动前往 dummy_script 并单击按钮,它工作正常,即警报 window 弹出并显示“Hello World OK!”。
如果我用 pytest 和 selenium 触发脚本,代码会被执行,但从 fetch 返回的响应是 ko。
编辑
main.html
<!DOCTYPE html>
{% load static %}
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{% static 'css/main.css' %}" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
<script src="{% static 'js/bootstrap.js' %}"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4"
crossorigin="anonymous"></script>
<script type="text/javascript">
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
</script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<title>
{% block title %}
{% endblock title %}
</title>
{% block meta %}
{% endblock meta %}
</head>
<body class="mt-sm-5 mt-md-5 mt-lg-5 mt-xl-5">
<section class="page-content py-3" id="page-content">
{% block content %}
{% endblock content %}
</section>
<script type="module" src="{% static '/js/main.js' %}"> </script>
</body>
</html>
我意识到当我使用 Selenium 时,函数 getCookie return csrftoken = null。结果,无法将数据提取到 django 视图。
为了能够仅在测试模式下使用 Selenium,我在 'another_dummy_view' 之前添加了以下条件装饰器。
views.py
def conditional_decorator(dec, condition):
def decorator(func):
if not condition:
# Return the function unchanged, not decorated.
return func
return dec(func)
return decorator
def dev_dummy_script(request):
context = {}
return render(request, "dummy_2.html", context)
@conditional_decorator(csrf_exempt, DEBUG)
def another_dummy_view(request):
if request.method == "POST":
post_data = json.loads(request.body.decode("utf-8"))
posted_value = post_data["dummyValue"]
value_to_return = posted_value + " " + "OK !"
response = JsonResponse({"returnedValue": value_to_return})
return response
我正在使用 Selenium 测试我创建的 Django 应用程序。
以下代码工作正常 'manually' 但不适用于 Selenium。
为什么 ?
## dummy.html ##
{% extends 'main.html' %}
{% load static %}
{% block title %}
Dummy page
{% endblock title %}
{% block meta %}
<meta name="robots" content="noindex">
{% endblock meta %}
{% block content %}
<div class="container">
<div class="row">
<div class="col d-flex justify-content-center align-items-center">
<h1 class="text-primary font-handwriting">Dummy page</h1>
</div>
</div>
<br>
<div class="row">
<div class="col d-flex justify-content-center align-items-center">
<h2 class="text-primary font-heading">THIS IS A DUMMY PAGE</h2>
</div>
</div>
<br>
<div class="row">
<button id="trigger-dummy-button" type="button"
class="btn btn-primary text-white font-base fw-bold text-uppercase"
title="Trigger dummy button">Trigger dummy button</button>
</div>
</div>
<script>
var someDummyURL = "{% url 'home_page:another_dummy_view' %}";
</script>
<script type="module" src="{% static '/js/dummy.js' %}"> </script>
{% endblock content %}
## dummy.js ##
'use strict';
var newValue;
async function postDummyFunction(request) {
var response = await fetch(request);
if (response.ok) {
var updatedReturnedValue = await response.json();
newValue = updatedReturnedValue.returnedValue;
alert('-- postDummyFunction -- | newValue = ' + newValue);
// When the script is triggered manually by clicking, response.ok = true and newValue = "Hello World OK !"
return newValue;
} else {
// When the script is triggered by Selenium, response.ok = false
alert('-- postDummyFunction -- | response.ok ? ' + response.ok);
return false;
}
};
document.addEventListener("DOMContentLoaded", function () {
var triggerDummyButton = document.getElementById("trigger-dummy-button");
var someDummyVariable = "Hello World ";
var toPostURL = someDummyURL;
triggerDummyButton.onclick = (e) => {
var data = {"dummyValue": someDummyVariable};
var request = new Request(toPostURL, {
method: "POST",
mode: "same-origin",
headers: {
"Content-Type": "application/json",
'X-Requested-With':'XMLHttpRequest',
"Accept": "application/json",
'X-CSRFToken': csrftoken
},
body: JSON.stringify(data),
});
// Works with Selenium
// if alert(data.dummyValue), browser correctly displays "Hello World "
postDummyFunction(request);
}
});
## views.py ##
import json
from django.shortcuts import render, redirect
from django.http import JsonResponse
def dev_dummy_script(request):
context = {}
return render(request, "dummy.html", context)
def another_dummy_view(request):
if request.method == "POST":
post_data = json.loads(request.body.decode("utf-8"))
posted_value = post_data["dummyValue"]
value_to_return = posted_value + " " + "OK !"
response = JsonResponse({"returnedValue": value_to_return})
return response
## test_selenium.py ##
import time
import os
from decimal import Decimal
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from core.settings import BASE_DIR
PATH_TO_WEBDRIVER_CHROME = os.path.join(
BASE_DIR, "test", "webdrivers", "chromedriver.exe"
)
PATH_TO_WEBDRIVER_FIREFOX = os.path.join(BASE_DIR, "test", "webdrivers", "geckodriver")
SHORT_TIME = 2.5
LONG_TIME = 6
DEFAULT_WAIT_TIME = 10
class FooTest(StaticLiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox(executable_path=PATH_TO_WEBDRIVER_FIREFOX)
def tearDown(self):
self.browser.close()
def testfoo(self):
self.browser.get(("%s%s" % (self.live_server_url, "/dev/dummy_script/")))
elem_trigger_btn = WebDriverWait(self.browser, DEFAULT_WAIT_TIME).until(
EC.element_to_be_clickable((By.ID, "trigger-dummy-button"))
)
elem_trigger_btn.click()
time.sleep(LONG_TIME)
self.browser.close()
版本
- Django==3.2
- 硒==3.141.0
- 火狐 96.0.3
如果我触发 python manage.py runserver
,手动前往 dummy_script 并单击按钮,它工作正常,即警报 window 弹出并显示“Hello World OK!”。
如果我用 pytest 和 selenium 触发脚本,代码会被执行,但从 fetch 返回的响应是 ko。
编辑
main.html
<!DOCTYPE html>
{% load static %}
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{% static 'css/main.css' %}" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
<script src="{% static 'js/bootstrap.js' %}"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4"
crossorigin="anonymous"></script>
<script type="text/javascript">
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
</script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<title>
{% block title %}
{% endblock title %}
</title>
{% block meta %}
{% endblock meta %}
</head>
<body class="mt-sm-5 mt-md-5 mt-lg-5 mt-xl-5">
<section class="page-content py-3" id="page-content">
{% block content %}
{% endblock content %}
</section>
<script type="module" src="{% static '/js/main.js' %}"> </script>
</body>
</html>
我意识到当我使用 Selenium 时,函数 getCookie return csrftoken = null。结果,无法将数据提取到 django 视图。
为了能够仅在测试模式下使用 Selenium,我在 'another_dummy_view' 之前添加了以下条件装饰器。
views.py
def conditional_decorator(dec, condition):
def decorator(func):
if not condition:
# Return the function unchanged, not decorated.
return func
return dec(func)
return decorator
def dev_dummy_script(request):
context = {}
return render(request, "dummy_2.html", context)
@conditional_decorator(csrf_exempt, DEBUG)
def another_dummy_view(request):
if request.method == "POST":
post_data = json.loads(request.body.decode("utf-8"))
posted_value = post_data["dummyValue"]
value_to_return = posted_value + " " + "OK !"
response = JsonResponse({"returnedValue": value_to_return})
return response