"""
Binance Spot WebSocket API

OpenAPI Specifications for the Binance Spot WebSocket API

API documents:
  - [Github web-socket-api documentation file](https://github.com/binance/binance-spot-api-docs/blob/master/web-socket-api.md)
  - [General API information for web-socket-api on website](https://developers.binance.com/docs/binance-spot-api-docs/web-socket-api/general-api-information)

The version of the OpenAPI document: 1.0.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
"""

import pytest

from unittest.mock import AsyncMock, MagicMock

from binance_common.models import WebsocketApiResponse
from binance_common.utils import parse_ws_rate_limit_headers
from binance_common.errors import RequiredError
from binance_sdk_spot.websocket_api.api import MarketApi


from binance_sdk_spot.websocket_api.models import DepthSymbolStatusEnum
from binance_sdk_spot.websocket_api.models import KlinesIntervalEnum
from binance_sdk_spot.websocket_api.models import TickerTypeEnum
from binance_sdk_spot.websocket_api.models import TickerWindowSizeEnum
from binance_sdk_spot.websocket_api.models import TickerSymbolStatusEnum
from binance_sdk_spot.websocket_api.models import Ticker24hrTypeEnum
from binance_sdk_spot.websocket_api.models import Ticker24hrSymbolStatusEnum
from binance_sdk_spot.websocket_api.models import TickerBookSymbolStatusEnum
from binance_sdk_spot.websocket_api.models import TickerPriceSymbolStatusEnum
from binance_sdk_spot.websocket_api.models import TickerTradingDayTypeEnum
from binance_sdk_spot.websocket_api.models import TickerTradingDaySymbolStatusEnum
from binance_sdk_spot.websocket_api.models import UiKlinesIntervalEnum
from binance_sdk_spot.websocket_api.models import AvgPriceResponse
from binance_sdk_spot.websocket_api.models import DepthResponse
from binance_sdk_spot.websocket_api.models import KlinesResponse
from binance_sdk_spot.websocket_api.models import TickerResponse
from binance_sdk_spot.websocket_api.models import Ticker24hrResponse
from binance_sdk_spot.websocket_api.models import TickerBookResponse
from binance_sdk_spot.websocket_api.models import TickerPriceResponse
from binance_sdk_spot.websocket_api.models import TickerTradingDayResponse
from binance_sdk_spot.websocket_api.models import TradesAggregateResponse
from binance_sdk_spot.websocket_api.models import TradesHistoricalResponse
from binance_sdk_spot.websocket_api.models import TradesRecentResponse
from binance_sdk_spot.websocket_api.models import UiKlinesResponse


class TestWebSocketMarketApi:
    @pytest.fixture(autouse=True)
    def setup_method(self):
        self.mock_websocket_api = MagicMock()
        self.websocket_api = MarketApi(websocket_api=self.mock_websocket_api)

    @pytest.mark.asyncio
    async def test_avg_price_success(self):
        """Test avg_price() successfully with required parameters only."""

        params = {
            "symbol": "BNBUSDT",
        }

        expected_response = {
            "id": "ddbfb65f-9ebf-42ec-8240-8f0f91de0867",
            "status": 200,
            "result": {"mins": 5, "price": "9.35751834", "closeTime": 1694061154503},
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 2,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )
        result = await self.websocket_api.avg_price(**params)

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/avgPrice".replace("/", "", 1)

        assert "params" in request_kwargs["payload"]
        params = request_kwargs["payload"]["params"]
        assert params["symbol"] == "BNBUSDT"

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/avgPrice".replace("/", "", 1), "params": params},
            response_model=AvgPriceResponse,
        )

    @pytest.mark.asyncio
    async def test_avg_price_success_with_optional_params(self):
        """Test avg_price() successfully with optional parameters."""

        params = {"symbol": "BNBUSDT", "id": "e9d6b4349871b40611412680b3445fac"}

        expected_response = {
            "id": "ddbfb65f-9ebf-42ec-8240-8f0f91de0867",
            "status": 200,
            "result": {"mins": 5, "price": "9.35751834", "closeTime": 1694061154503},
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 2,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )

        result = await self.websocket_api.avg_price(**params)

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/avgPrice".replace("/", "", 1)
        assert params["symbol"] == "BNBUSDT"
        assert params["id"] == "e9d6b4349871b40611412680b3445fac"

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/avgPrice".replace("/", "", 1), "params": params},
            response_model=AvgPriceResponse,
        )

    @pytest.mark.asyncio
    async def test_avg_price_missing_required_param_symbol(self):
        """Test that avg_price() raises RequiredError when 'symbol' is missing."""

        params = {"symbol": "BNBUSDT", "id": "e9d6b4349871b40611412680b3445fac"}
        params["symbol"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'symbol'"):
            await self.websocket_api.avg_price(**params)

    @pytest.mark.asyncio
    async def test_avg_price_server_error(self):
        """Test that avg_price() raises an error when the server returns an error."""

        params = {
            "symbol": "BNBUSDT",
        }

        mock_error = Exception("ResponseError")
        self.mock_websocket_api.send_message.side_effect = mock_error

        with pytest.raises(Exception, match="ResponseError"):
            await self.websocket_api.avg_price(**params)

    @pytest.mark.asyncio
    async def test_depth_success(self):
        """Test depth() successfully with required parameters only."""

        params = {
            "symbol": "BNBUSDT",
        }

        expected_response = {
            "id": "51e2affb-0aba-4821-ba75-f2625006eb43",
            "status": 200,
            "result": {
                "lastUpdateId": 2731179239,
                "bids": [
                    ["0.01379900", "3.43200000"],
                    ["0.01379800", "3.24300000"],
                    ["0.01379700", "10.45500000"],
                    ["0.01379600", "3.82100000"],
                    ["0.01379500", "10.26200000"],
                ],
                "asks": [
                    ["0.01380000", "5.91700000"],
                    ["0.01380100", "6.01400000"],
                    ["0.01380200", "0.26800000"],
                    ["0.01380300", "0.33800000"],
                    ["0.01380400", "0.26800000"],
                ],
            },
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 2,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )
        result = await self.websocket_api.depth(**params)

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/depth".replace("/", "", 1)

        assert params["symbol"] == "BNBUSDT"

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/depth".replace("/", "", 1), "params": params},
            response_model=DepthResponse,
        )

    @pytest.mark.asyncio
    async def test_depth_success_with_optional_params(self):
        """Test depth() successfully with optional parameters."""

        params = {
            "symbol": "BNBUSDT",
            "id": "e9d6b4349871b40611412680b3445fac",
            "limit": 100,
            "symbol_status": DepthSymbolStatusEnum["TRADING"].value,
        }

        expected_response = {
            "id": "51e2affb-0aba-4821-ba75-f2625006eb43",
            "status": 200,
            "result": {
                "lastUpdateId": 2731179239,
                "bids": [
                    ["0.01379900", "3.43200000"],
                    ["0.01379800", "3.24300000"],
                    ["0.01379700", "10.45500000"],
                    ["0.01379600", "3.82100000"],
                    ["0.01379500", "10.26200000"],
                ],
                "asks": [
                    ["0.01380000", "5.91700000"],
                    ["0.01380100", "6.01400000"],
                    ["0.01380200", "0.26800000"],
                    ["0.01380300", "0.33800000"],
                    ["0.01380400", "0.26800000"],
                ],
            },
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 2,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )

        result = await self.websocket_api.depth(**params)

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/depth".replace("/", "", 1)
        assert params["symbol"] == "BNBUSDT"
        assert params["id"] == "e9d6b4349871b40611412680b3445fac"
        assert params["limit"] == 100
        assert params["symbol_status"] == DepthSymbolStatusEnum["TRADING"].value

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/depth".replace("/", "", 1), "params": params},
            response_model=DepthResponse,
        )

    @pytest.mark.asyncio
    async def test_depth_missing_required_param_symbol(self):
        """Test that depth() raises RequiredError when 'symbol' is missing."""

        params = {
            "symbol": "BNBUSDT",
            "id": "e9d6b4349871b40611412680b3445fac",
            "limit": 100,
            "symbol_status": DepthSymbolStatusEnum["TRADING"].value,
        }
        params["symbol"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'symbol'"):
            await self.websocket_api.depth(**params)

    @pytest.mark.asyncio
    async def test_depth_server_error(self):
        """Test that depth() raises an error when the server returns an error."""

        params = {
            "symbol": "BNBUSDT",
        }

        mock_error = Exception("ResponseError")
        self.mock_websocket_api.send_message.side_effect = mock_error

        with pytest.raises(Exception, match="ResponseError"):
            await self.websocket_api.depth(**params)

    @pytest.mark.asyncio
    async def test_klines_success(self):
        """Test klines() successfully with required parameters only."""

        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
        }

        expected_response = {
            "id": "1dbbeb56-8eea-466a-8f6e-86bdcfa2fc0b",
            "status": 200,
            "result": [
                [
                    1655971200000,
                    "0.01086000",
                    "0.01086600",
                    "0.01083600",
                    "0.01083800",
                    "2290.53800000",
                    1655974799999,
                    "24.85074442",
                    2283,
                    "1171.64000000",
                    "12.71225884",
                    "0",
                ]
            ],
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 2,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )
        result = await self.websocket_api.klines(**params)

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/klines".replace("/", "", 1)

        assert params["symbol"] == "BNBUSDT"

        assert params["interval"] == KlinesIntervalEnum["INTERVAL_1s"].value

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/klines".replace("/", "", 1), "params": params},
            response_model=KlinesResponse,
        )

    @pytest.mark.asyncio
    async def test_klines_success_with_optional_params(self):
        """Test klines() successfully with optional parameters."""

        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
            "id": "e9d6b4349871b40611412680b3445fac",
            "start_time": 1735693200000,
            "end_time": 1735693200000,
            "time_zone": "time_zone_example",
            "limit": 100,
        }

        expected_response = {
            "id": "1dbbeb56-8eea-466a-8f6e-86bdcfa2fc0b",
            "status": 200,
            "result": [
                [
                    1655971200000,
                    "0.01086000",
                    "0.01086600",
                    "0.01083600",
                    "0.01083800",
                    "2290.53800000",
                    1655974799999,
                    "24.85074442",
                    2283,
                    "1171.64000000",
                    "12.71225884",
                    "0",
                ]
            ],
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 2,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )

        result = await self.websocket_api.klines(**params)

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/klines".replace("/", "", 1)
        assert params["symbol"] == "BNBUSDT"
        assert params["interval"] == KlinesIntervalEnum["INTERVAL_1s"].value
        assert params["id"] == "e9d6b4349871b40611412680b3445fac"
        assert params["start_time"] == 1735693200000
        assert params["end_time"] == 1735693200000
        assert params["time_zone"] == "time_zone_example"
        assert params["limit"] == 100

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/klines".replace("/", "", 1), "params": params},
            response_model=KlinesResponse,
        )

    @pytest.mark.asyncio
    async def test_klines_missing_required_param_symbol(self):
        """Test that klines() raises RequiredError when 'symbol' is missing."""

        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
            "id": "e9d6b4349871b40611412680b3445fac",
            "start_time": 1735693200000,
            "end_time": 1735693200000,
            "time_zone": "time_zone_example",
            "limit": 100,
        }
        params["symbol"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'symbol'"):
            await self.websocket_api.klines(**params)

    @pytest.mark.asyncio
    async def test_klines_missing_required_param_interval(self):
        """Test that klines() raises RequiredError when 'interval' is missing."""

        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
            "id": "e9d6b4349871b40611412680b3445fac",
            "start_time": 1735693200000,
            "end_time": 1735693200000,
            "time_zone": "time_zone_example",
            "limit": 100,
        }
        params["interval"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'interval'"
        ):
            await self.websocket_api.klines(**params)

    @pytest.mark.asyncio
    async def test_klines_server_error(self):
        """Test that klines() raises an error when the server returns an error."""

        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
        }

        mock_error = Exception("ResponseError")
        self.mock_websocket_api.send_message.side_effect = mock_error

        with pytest.raises(Exception, match="ResponseError"):
            await self.websocket_api.klines(**params)

    @pytest.mark.asyncio
    async def test_ticker_success(self):
        """Test ticker() successfully with required parameters only."""

        expected_response = {
            "id": "bdb7c503-542c-495c-b797-4d2ee2e91173",
            "status": 200,
            "result": {
                "symbol": "BNBBTC",
                "priceChange": "0.00061500",
                "priceChangePercent": "4.735",
                "weightedAvgPrice": "0.01368242",
                "openPrice": "0.01298900",
                "highPrice": "0.01418800",
                "lowPrice": "0.01296000",
                "lastPrice": "0.01360400",
                "volume": "587179.23900000",
                "quoteVolume": "8034.03382165",
                "openTime": 1659580020000,
                "closeTime": 1660184865291,
                "firstId": 192977765,
                "lastId": 195365758,
                "count": 2387994,
            },
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 4,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )
        result = await self.websocket_api.ticker()

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/ticker".replace("/", "", 1)

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/ticker".replace("/", "", 1), "params": {}},
            response_model=TickerResponse,
        )

    @pytest.mark.asyncio
    async def test_ticker_success_with_optional_params(self):
        """Test ticker() successfully with optional parameters."""

        params = {
            "id": "e9d6b4349871b40611412680b3445fac",
            "symbol": "BNBUSDT",
            "symbols": ["symbols_example"],
            "type": TickerTypeEnum["FULL"].value,
            "window_size": TickerWindowSizeEnum["WINDOW_SIZE_1m"].value,
            "symbol_status": TickerSymbolStatusEnum["TRADING"].value,
        }

        expected_response = {
            "id": "bdb7c503-542c-495c-b797-4d2ee2e91173",
            "status": 200,
            "result": {
                "symbol": "BNBBTC",
                "priceChange": "0.00061500",
                "priceChangePercent": "4.735",
                "weightedAvgPrice": "0.01368242",
                "openPrice": "0.01298900",
                "highPrice": "0.01418800",
                "lowPrice": "0.01296000",
                "lastPrice": "0.01360400",
                "volume": "587179.23900000",
                "quoteVolume": "8034.03382165",
                "openTime": 1659580020000,
                "closeTime": 1660184865291,
                "firstId": 192977765,
                "lastId": 195365758,
                "count": 2387994,
            },
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 4,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )

        result = await self.websocket_api.ticker(**params)

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/ticker".replace("/", "", 1)
        assert params["id"] == "e9d6b4349871b40611412680b3445fac"
        assert params["symbol"] == "BNBUSDT"
        assert params["symbols"] == ["symbols_example"]
        assert params["type"] == TickerTypeEnum["FULL"].value
        assert params["window_size"] == TickerWindowSizeEnum["WINDOW_SIZE_1m"].value
        assert params["symbol_status"] == TickerSymbolStatusEnum["TRADING"].value

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/ticker".replace("/", "", 1), "params": params},
            response_model=TickerResponse,
        )

    @pytest.mark.asyncio
    async def test_ticker_server_error(self):
        """Test that ticker() raises an error when the server returns an error."""

        mock_error = Exception("ResponseError")
        self.mock_websocket_api.send_message.side_effect = mock_error

        with pytest.raises(Exception, match="ResponseError"):
            await self.websocket_api.ticker()

    @pytest.mark.asyncio
    async def test_ticker24hr_success(self):
        """Test ticker24hr() successfully with required parameters only."""

        expected_response = {
            "id": "9fa2a91b-3fca-4ed7-a9ad-58e3b67483de",
            "status": 200,
            "result": {
                "symbol": "BNBBTC",
                "priceChange": "0.00013900",
                "priceChangePercent": "1.020",
                "weightedAvgPrice": "0.01382453",
                "prevClosePrice": "0.01362800",
                "lastPrice": "0.01376700",
                "lastQty": "1.78800000",
                "bidPrice": "0.01376700",
                "bidQty": "4.64600000",
                "askPrice": "0.01376800",
                "askQty": "14.31400000",
                "openPrice": "0.01362800",
                "highPrice": "0.01414900",
                "lowPrice": "0.01346600",
                "volume": "69412.40500000",
                "quoteVolume": "959.59411487",
                "openTime": 1660014164909,
                "closeTime": 1660100564909,
                "firstId": 194696115,
                "lastId": 194968287,
                "count": 272173,
            },
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 2,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )
        result = await self.websocket_api.ticker24hr()

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/ticker.24hr".replace("/", "", 1)

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/ticker.24hr".replace("/", "", 1), "params": {}},
            response_model=Ticker24hrResponse,
        )

    @pytest.mark.asyncio
    async def test_ticker24hr_success_with_optional_params(self):
        """Test ticker24hr() successfully with optional parameters."""

        params = {
            "id": "e9d6b4349871b40611412680b3445fac",
            "symbol": "BNBUSDT",
            "symbols": ["symbols_example"],
            "type": Ticker24hrTypeEnum["FULL"].value,
            "symbol_status": Ticker24hrSymbolStatusEnum["TRADING"].value,
        }

        expected_response = {
            "id": "9fa2a91b-3fca-4ed7-a9ad-58e3b67483de",
            "status": 200,
            "result": {
                "symbol": "BNBBTC",
                "priceChange": "0.00013900",
                "priceChangePercent": "1.020",
                "weightedAvgPrice": "0.01382453",
                "prevClosePrice": "0.01362800",
                "lastPrice": "0.01376700",
                "lastQty": "1.78800000",
                "bidPrice": "0.01376700",
                "bidQty": "4.64600000",
                "askPrice": "0.01376800",
                "askQty": "14.31400000",
                "openPrice": "0.01362800",
                "highPrice": "0.01414900",
                "lowPrice": "0.01346600",
                "volume": "69412.40500000",
                "quoteVolume": "959.59411487",
                "openTime": 1660014164909,
                "closeTime": 1660100564909,
                "firstId": 194696115,
                "lastId": 194968287,
                "count": 272173,
            },
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 6000,
                    "count": 2,
                }
            ],
        }

        self.mock_websocket_api.send_message = AsyncMock(
            return_value=WebsocketApiResponse(
                data_function=lambda: expected_response,
                rate_limits=(
                    parse_ws_rate_limit_headers(expected_response["rateLimits"])
                    if "rateLimits" in expected_response
                    else None
                ),
            )
        )

        result = await self.websocket_api.ticker24hr(**params)

        actual_call_args = self.mock_websocket_api.send_message.call_args
        request_kwargs = actual_call_args.kwargs

        assert "payload" in request_kwargs
        assert "method" in request_kwargs["payload"]
        assert request_kwargs["payload"]["method"] == "/ticker.24hr".replace("/", "", 1)
        assert params["id"] == "e9d6b4349871b40611412680b3445fac"
        assert params["symbol"] == "BNBUSDT"
        assert params["symbols"] == ["symbols_example"]
        assert params["type"] == Ticker24hrTypeEnum["FULL"].value
        assert params["symbol_status"] == Ticker24hrSymbolStatusEnum["TRADING"].value

        assert result is not None
        assert result.data() == expected_response
        self.mock_websocket_api.send_message.assert_called_once_with(
            payload={"method": "/ticker.24hr".replace("/", "", 1), "params": params},
            response_model=Ticker24hrResponse,
        )

    @pytest.mark.asyncio
    async def test_ticker24hr_server_error(self):
        """Test that ticker24hr() raises an error when the server returns an error."""

        mock_error = Exception("ResponseError")
        self.mock_websocket_api.send_message.side_effect = mock_error

        with pytest.raises(Exception, match="ResponseError"):
            await self.websocket_api.ticker24hr()

    @pytest.mark.asyncio
    async def test_ticker_book_success(self):
        """Test ticker_book() successfully with required parameters only."""

        expected_response = {
            "id": "9d32157c-a556-4d27-9866-66760a174b57",
            "status": 200,
            "result": {
