scrapy/tests/test_http_request_json.py

190 lines
6.2 KiB
Python

from __future__ import annotations
import json
import warnings
from unittest import mock
import pytest
from scrapy.http import JsonRequest
from scrapy.utils.python import to_bytes
from tests.test_http_request import TestRequest
class TestJsonRequest(TestRequest):
request_class = JsonRequest
default_method = "GET"
default_headers = {
b"Content-Type": [b"application/json"],
b"Accept": [b"application/json, text/javascript, */*; q=0.01"],
}
def test_data(self):
r1 = self.request_class(url="http://www.example.com/")
assert r1.body == b""
body = b"body"
r2 = self.request_class(url="http://www.example.com/", body=body)
assert r2.body == body
data = {
"name": "value",
}
r3 = self.request_class(url="http://www.example.com/", data=data)
assert r3.body == to_bytes(json.dumps(data))
# empty data
r4 = self.request_class(url="http://www.example.com/", data=[])
assert r4.body == to_bytes(json.dumps([]))
def test_data_method(self):
# data is not passed
r1 = self.request_class(url="http://www.example.com/")
assert r1.method == "GET"
body = b"body"
r2 = self.request_class(url="http://www.example.com/", body=body)
assert r2.method == "GET"
data = {
"name": "value",
}
r3 = self.request_class(url="http://www.example.com/", data=data)
assert r3.method == "POST"
# method passed explicitly
r4 = self.request_class(url="http://www.example.com/", data=data, method="GET")
assert r4.method == "GET"
r5 = self.request_class(url="http://www.example.com/", data=[])
assert r5.method == "POST"
def test_body_data(self):
"""passing both body and data should result a warning"""
body = b"body"
data = {
"name": "value",
}
with pytest.warns(UserWarning, match="data will be ignored"):
r5 = self.request_class(url="http://www.example.com/", body=body, data=data)
assert r5.body == body
assert r5.method == "GET"
def test_empty_body_data(self):
"""passing any body value and data should result a warning"""
data = {
"name": "value",
}
with pytest.warns(UserWarning, match="data will be ignored"):
r6 = self.request_class(url="http://www.example.com/", body=b"", data=data)
assert r6.body == b""
assert r6.method == "GET"
def test_body_none_data(self):
data = {
"name": "value",
}
with warnings.catch_warnings():
warnings.filterwarnings(
"error", category=UserWarning, message="Both body and data passed"
)
r7 = self.request_class(url="http://www.example.com/", body=None, data=data)
assert r7.body == to_bytes(json.dumps(data))
assert r7.method == "POST"
def test_body_data_none(self):
with warnings.catch_warnings():
warnings.filterwarnings(
"error", category=UserWarning, message="Both body and data passed"
)
r8 = self.request_class(url="http://www.example.com/", body=None, data=None)
assert r8.method == "GET"
def test_dumps_sort_keys(self):
"""Test that sort_keys=True is passed to json.dumps by default"""
data = {
"name": "value",
}
with mock.patch("json.dumps", return_value=b"") as mock_dumps:
self.request_class(url="http://www.example.com/", data=data)
kwargs = mock_dumps.call_args[1]
assert kwargs["sort_keys"] is True
def test_dumps_kwargs(self):
"""Test that dumps_kwargs are passed to json.dumps"""
data = {
"name": "value",
}
dumps_kwargs = {
"ensure_ascii": True,
"allow_nan": True,
}
with mock.patch("json.dumps", return_value=b"") as mock_dumps:
self.request_class(
url="http://www.example.com/", data=data, dumps_kwargs=dumps_kwargs
)
kwargs = mock_dumps.call_args[1]
assert kwargs["ensure_ascii"] is True
assert kwargs["allow_nan"] is True
def test_replace_data(self):
data1 = {
"name1": "value1",
}
data2 = {
"name2": "value2",
}
r1 = self.request_class(url="http://www.example.com/", data=data1)
r2 = r1.replace(data=data2)
assert r2.body == to_bytes(json.dumps(data2))
def test_replace_sort_keys(self):
"""Test that replace provides sort_keys=True to json.dumps"""
data1 = {
"name1": "value1",
}
data2 = {
"name2": "value2",
}
r1 = self.request_class(url="http://www.example.com/", data=data1)
with mock.patch("json.dumps", return_value=b"") as mock_dumps:
r1.replace(data=data2)
kwargs = mock_dumps.call_args[1]
assert kwargs["sort_keys"] is True
def test_replace_dumps_kwargs(self):
"""Test that dumps_kwargs are provided to json.dumps when replace is called"""
data1 = {
"name1": "value1",
}
data2 = {
"name2": "value2",
}
dumps_kwargs = {
"ensure_ascii": True,
"allow_nan": True,
}
r1 = self.request_class(
url="http://www.example.com/", data=data1, dumps_kwargs=dumps_kwargs
)
with mock.patch("json.dumps", return_value=b"") as mock_dumps:
r1.replace(data=data2)
kwargs = mock_dumps.call_args[1]
assert kwargs["ensure_ascii"] is True
assert kwargs["allow_nan"] is True
def test_replacement_both_body_and_data_warns(self):
"""Test that we get a warning if both body and data are passed"""
body1 = None
body2 = b"body"
data1 = {
"name1": "value1",
}
data2 = {
"name2": "value2",
}
r1 = self.request_class(url="http://www.example.com/", data=data1, body=body1)
with pytest.warns(UserWarning, match="data will be ignored"):
r1.replace(data=data2, body=body2)