Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion playwright/_impl/_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,9 @@ async def _inner_fetch(
if self._close_reason:
raise TargetClosedError(self._close_reason)
assert (
(1 if data else 0) + (1 if form else 0) + (1 if multipart else 0)
(0 if data is None else 1)
+ (0 if form is None else 1)
+ (0 if multipart is None else 1)
) <= 1, "Only one of 'data', 'form' or 'multipart' can be specified"
assert (
maxRedirects is None or maxRedirects >= 0
Expand Down
55 changes: 55 additions & 0 deletions tests/async/test_fetch_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,61 @@ async def test_should_serialize_request_data(
await request.dispose()


@pytest.mark.parametrize(
"data",
["", b"", 0, [], {}, False],
)
async def test_should_disallow_falsy_data_together_with_form_or_multipart(
playwright: Playwright, server: Server, data: Any
) -> None:
server.set_route("/echo", lambda req: (req.write(req.post_body), req.finish()))
request = await playwright.request.new_context()
try:
for body_option in ["form", "multipart"]:
with pytest.raises(AssertionError) as exc_info:
if body_option == "form":
await request.post(
server.PREFIX + "/echo", data=data, form={"name": "value"}
)
else:
await request.post(
server.PREFIX + "/echo",
data=data,
multipart={"name": "value"},
)
assert "Only one of 'data', 'form' or 'multipart' can be specified" in str(
exc_info
)
finally:
await request.dispose()


async def test_should_count_empty_form_and_multipart_as_specified(
playwright: Playwright, server: Server
) -> None:
# Mirrors Node.js semantics: an option counts as specified when it is
# not None, even if it is empty, so it still conflicts with data.
server.set_route("/echo", lambda req: (req.write(req.post_body), req.finish()))
request = await playwright.request.new_context()
try:
with pytest.raises(AssertionError) as exc_info:
await request.post(server.PREFIX + "/echo", data="payload", form={})
assert "Only one of 'data', 'form' or 'multipart' can be specified" in str(
exc_info
)
with pytest.raises(AssertionError) as exc_info:
await request.post(server.PREFIX + "/echo", data="payload", multipart={})
assert "Only one of 'data', 'form' or 'multipart' can be specified" in str(
exc_info
)
# Empty form/multipart on their own are allowed and send no fields.
response = await request.post(server.PREFIX + "/echo", form={})
assert response.status == 200
assert await response.text() == ""
finally:
await request.dispose()


async def test_should_retry_ECONNRESET(playwright: Playwright, server: Server) -> None:
request_count = 0

Expand Down
56 changes: 56 additions & 0 deletions tests/sync/test_fetch_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import json
from pathlib import Path
from typing import Any
from urllib.parse import urlparse

import pytest
Expand Down Expand Up @@ -334,6 +335,61 @@ def test_should_serialize_null_values_in_json(
request.dispose()


@pytest.mark.parametrize(
"data",
["", b"", 0, [], {}, False],
)
def test_should_disallow_falsy_data_together_with_form_or_multipart(
playwright: Playwright, server: Server, data: Any
) -> None:
server.set_route("/echo", lambda req: (req.write(req.post_body), req.finish()))
request = playwright.request.new_context()
try:
for body_option in ["form", "multipart"]:
with pytest.raises(AssertionError) as exc_info:
if body_option == "form":
request.post(
server.PREFIX + "/echo", data=data, form={"name": "value"}
)
else:
request.post(
server.PREFIX + "/echo",
data=data,
multipart={"name": "value"},
)
assert "Only one of 'data', 'form' or 'multipart' can be specified" in str(
exc_info
)
finally:
request.dispose()


def test_should_count_empty_form_and_multipart_as_specified(
playwright: Playwright, server: Server
) -> None:
# Mirrors Node.js semantics: an option counts as specified when it is
# not None, even if it is empty, so it still conflicts with data.
server.set_route("/echo", lambda req: (req.write(req.post_body), req.finish()))
request = playwright.request.new_context()
try:
with pytest.raises(AssertionError) as exc_info:
request.post(server.PREFIX + "/echo", data="payload", form={})
assert "Only one of 'data', 'form' or 'multipart' can be specified" in str(
exc_info
)
with pytest.raises(AssertionError) as exc_info:
request.post(server.PREFIX + "/echo", data="payload", multipart={})
assert "Only one of 'data', 'form' or 'multipart' can be specified" in str(
exc_info
)
# Empty form/multipart on their own are allowed and send no fields.
response = request.post(server.PREFIX + "/echo", form={})
assert response.status == 200
assert response.text() == ""
finally:
request.dispose()


def test_should_throw_when_fail_on_status_code_is_true(
playwright: Playwright, server: Server
) -> None:
Expand Down