Skip to content

TestClient doesn't merge urls in the same way as the httpx client, and I think it should. #2306

@Waghabond

Description

@Waghabond

Discussed in #2300

Originally posted by Waghabond October 12, 2023
The TestClient just delegates the url merging to the join method of the httpx.URL object.

This causes the base path configuration to be ignored in some cases.

eg.
This how the merge is done in the Starlette TestClient's request() method.

url = self.base_url.join(url)

It creates unintuitive behaviour in the following example (which i think is a common way to use the test client)

client = testclient.TestClient(app, base_url="http://testserver/api/v1/")

result = client.base_url.join("/this-should-append-onto-the-end-of-the-base-url")
# result in reality is URL('http://testserver/this-should-append-onto-the-end-of-the-base-url'), the /api/v1 has disappeared.
result = client.base_url.join("this-works-as-expected")
# result is URL('http://testserver/api/v1/this-works-as-expected'), 

the way that httpx performs this merge is via the following code (i've lifted it straight from the httpx source code):

def _merge_url(self, url: URLTypes) -> URL:
    """
    Merge a URL argument together with any 'base_url' on the client,
    to create the URL used for the outgoing request.
    """
    merge_url = URL(url)
    if merge_url.is_relative_url:
        # To merge URLs we always append to the base URL. To get this
        # behaviour correct we always ensure the base URL ends in a '/'
        # separator, and strip any leading '/' from the merge URL.
        #
        # So, eg...
        #
        # >>> client = Client(base_url="https://www.example.com/subpath")
        # >>> client.base_url
        # URL('https://www.example.com/subpath/')
        # >>> client.build_request("GET", "/path").url
        # URL('https://www.example.com/subpath/path')
        merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/")
        return self.base_url.copy_with(raw_path=merge_raw_path)
    return merge_url

Starlette should be doing this the same way.

Important

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions