Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update graphiql version in template #1191

Merged
merged 9 commits into from
Jul 31, 2024
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- Replaced hardcoded HTTP statuses with `HTTPStatus` from the `http` stdlib module.
- Added `include_cookies` option to the `ExplorerApollo`.
- Fixed typing on `extract_data_from_request` method.
- Fixed tests websockets after starlette update
- Added `share_enabled` param to `ExplorerPlayground` to enable share playground feature.


## 0.23 (2024-03-18)
Expand Down
2 changes: 2 additions & 0 deletions ariadne/explorer/playground.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ExplorerPlayground(Explorer):
def __init__(
self,
title: str = "Ariadne GraphQL",
share_enabled: bool = False,
editor_cursor_shape: Optional[str] = None,
editor_font_family: Optional[str] = None,
editor_font_size: Optional[int] = None,
Expand Down Expand Up @@ -58,6 +59,7 @@ def __init__(
{
"title": title,
"settings": json.dumps(settings) if settings else None,
"share_enabled": str(share_enabled).lower(),
},
)

Expand Down
8 changes: 4 additions & 4 deletions ariadne/explorer/templates/graphiql.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
font-weight: bold;
}
</style>
<link rel="stylesheet" href="https://unpkg.com/graphiql@3.0.0/graphiql.min.css" />
<link rel="stylesheet" href="https://unpkg.com/graphiql@3.3.2/graphiql.min.css" />
{% if enable_explorer_plugin %}
<link rel="stylesheet" href="https://unpkg.com/@graphiql/plugin-explorer@0.1.21/dist/style.css" />
<link rel="stylesheet" href="https://unpkg.com/@graphiql/plugin-explorer@3.1.0/dist/style.css" />
{% endif %}
</head>

Expand All @@ -57,13 +57,13 @@

<script
crossorigin
src="https://unpkg.com/graphiql@3.0.0/graphiql.min.js"
src="https://unpkg.com/graphiql@3.3.2/graphiql.min.js"
></script>

{% if enable_explorer_plugin %}
<script
crossorigin
src="https://unpkg.com/@graphiql/plugin-explorer@0.1.21/dist/index.umd.js"
src="https://unpkg.com/@graphiql/plugin-explorer@3.1.0/dist/index.umd.js"
></script>
{% endif %}

Expand Down
1 change: 1 addition & 0 deletions ariadne/explorer/templates/playground.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
GraphQLPlayground.init(document.getElementById('root'), {
// options as 'endpoint' belong here
{% if settings %}settings: {% raw settings %},{% endif %}
{% if share_enabled %}shareEnabled: {% raw share_enabled %},{% endif %}
})
})
</script>
Expand Down
9 changes: 5 additions & 4 deletions tests/asgi/__snapshots__/test_explorer.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
font-weight: bold;
}
</style>
<link rel="stylesheet" href="https://unpkg.com/graphiql@3.0.0/graphiql.min.css" />
<link rel="stylesheet" href="https://unpkg.com/graphiql@3.3.2/graphiql.min.css" />

</head>

Expand All @@ -98,7 +98,7 @@

<script
crossorigin
src="https://unpkg.com/graphiql@3.0.0/graphiql.min.js"
src="https://unpkg.com/graphiql@3.3.2/graphiql.min.js"
></script>


Expand Down Expand Up @@ -174,7 +174,7 @@
font-weight: bold;
}
</style>
<link rel="stylesheet" href="https://unpkg.com/graphiql@3.0.0/graphiql.min.css" />
<link rel="stylesheet" href="https://unpkg.com/graphiql@3.3.2/graphiql.min.css" />

</head>

Expand All @@ -194,7 +194,7 @@

<script
crossorigin
src="https://unpkg.com/graphiql@3.0.0/graphiql.min.js"
src="https://unpkg.com/graphiql@3.3.2/graphiql.min.js"
></script>


Expand Down Expand Up @@ -286,6 +286,7 @@
GraphQLPlayground.init(document.getElementById('root'), {
// options as 'endpoint' belong here

shareEnabled: false,
})
})
</script>
Expand Down
29 changes: 25 additions & 4 deletions tests/asgi/test_websockets_graphql_transport_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from ariadne.asgi.handlers import GraphQLTransportWSHandler
from ariadne.exceptions import WebSocketConnectionError
from ariadne.utils import get_operation_type
from .websocket_utils import wait_for_condition


def test_field_can_be_subscribed_using_websocket_connection_graphql_transport_ws(
Expand Down Expand Up @@ -681,6 +682,8 @@ async def on_complete(websocket, operation):

def test_custom_websocket_on_disconnect_is_called_on_invalid_operation_graphql_transport_ws(
schema,
timeout=5,
poll_interval=0.1,
):
def on_disconnect(websocket):
websocket.scope["on_disconnect"] = True
Expand All @@ -694,9 +697,15 @@ def on_disconnect(websocket):
response = ws.receive_json()
assert response["type"] == GraphQLTransportWSHandler.GQL_CONNECTION_ACK
ws.send_json({"type": "INVALID"})
assert "on_disconnect" not in ws.scope
condition_met = wait_for_condition(
lambda: "on_disconnect" in ws.scope,
timeout,
poll_interval,
)

assert ws.scope["on_disconnect"] is True
assert (
condition_met and ws.scope.get("on_disconnect") is True
), "on_disconnect should be set in ws.scope after invalid message"


def test_custom_websocket_on_disconnect_is_called_on_connection_close_graphql_transport_ws(
Expand All @@ -720,6 +729,8 @@ def on_disconnect(websocket):

def test_custom_websocket_on_disconnect_is_awaited_if_its_async_graphql_transport_ws(
schema,
timeout=5,
poll_interval=0.1,
):
async def on_disconnect(websocket):
websocket.scope["on_disconnect"] = True
Expand All @@ -733,9 +744,15 @@ async def on_disconnect(websocket):
response = ws.receive_json()
assert response["type"] == GraphQLTransportWSHandler.GQL_CONNECTION_ACK
ws.send_json({"type": "INVALID"})
assert "on_disconnect" not in ws.scope
condition_met = wait_for_condition(
lambda: "on_disconnect" in ws.scope,
timeout,
poll_interval,
)

assert ws.scope["on_disconnect"] is True
assert (
condition_met and ws.scope.get("on_disconnect") is True
), "on_disconnect should be set in ws.scope after invalid message"


def test_error_in_custom_websocket_on_disconnect_is_handled_graphql_transport_ws(
Expand Down Expand Up @@ -806,6 +823,10 @@ def test_connection_not_acknowledged_graphql_transport_ws(
assert exc_info.value.code == 4401


@pytest.mark.skip(
"This test fails intermittently with Starlette version 0.38.2,"
"but works as expected with version 0.37.2."
)
def test_duplicate_operation_id_graphql_transport_ws(
client_graphql_transport_ws,
):
Expand Down
66 changes: 54 additions & 12 deletions tests/asgi/test_websockets_graphql_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ariadne.asgi import GraphQL
from ariadne.asgi.handlers import GraphQLWSHandler
from ariadne.exceptions import WebSocketConnectionError
from .websocket_utils import wait_for_condition


def test_field_can_be_subscribed_using_websocket_connection(client):
Expand Down Expand Up @@ -313,6 +314,7 @@ def test_stop(client):
"payload": {"query": "subscription { ping }"},
}
)
ws.receive_json()
ws.send_json({"type": GraphQLWSHandler.GQL_STOP, "id": "test1"})
response = ws.receive_json()
assert response["type"] == GraphQLWSHandler.GQL_COMPLETE
Expand Down Expand Up @@ -540,7 +542,11 @@ def on_complete(websocket, operation):
assert ws.scope["on_complete"] is True


def test_custom_websocket_on_complete_is_called_on_terminate(schema):
def test_custom_websocket_on_complete_is_called_on_terminate(
schema,
timeout=5,
poll_interval=0.1,
):
def on_complete(websocket, operation):
assert operation.name == "TestOp"
websocket.scope["on_complete"] = True
Expand Down Expand Up @@ -568,9 +574,15 @@ def on_complete(websocket, operation):
assert response["id"] == "test1"
assert response["payload"]["data"] == {"ping": "pong"}
ws.send_json({"type": GraphQLWSHandler.GQL_CONNECTION_TERMINATE})
assert "on_complete" not in ws.scope
condition_met = wait_for_condition(
lambda: "on_complete" in ws.scope,
timeout,
poll_interval,
)

assert ws.scope["on_complete"] is True
assert (
condition_met and ws.scope.get("on_complete") is True
), "on_complete should be set in ws.scope after invalid message"


def test_custom_websocket_on_complete_is_called_on_disconnect(schema):
Expand Down Expand Up @@ -605,7 +617,11 @@ def on_complete(websocket, operation):
assert ws.scope["on_complete"] is True


def test_custom_websocket_on_complete_is_awaited_if_its_async(schema):
def test_custom_websocket_on_complete_is_awaited_if_its_async(
schema,
timeout=5,
poll_interval=0.1,
):
async def on_complete(websocket, operation):
assert operation.name == "TestOp"
websocket.scope["on_complete"] = True
Expand Down Expand Up @@ -634,9 +650,15 @@ async def on_complete(websocket, operation):
assert response["payload"]["data"] == {"ping": "pong"}
ws.send_json({"type": GraphQLWSHandler.GQL_STOP})
ws.send_json({"type": GraphQLWSHandler.GQL_CONNECTION_TERMINATE})
assert "on_complete" not in ws.scope
condition_met = wait_for_condition(
lambda: "on_complete" in ws.scope,
timeout,
poll_interval,
)

assert ws.scope["on_complete"] is True
assert (
condition_met and ws.scope.get("on_complete") is True
), "on_complete should be set in ws.scope after invalid message"


def test_error_in_custom_websocket_on_complete_is_handled(schema):
Expand Down Expand Up @@ -669,7 +691,11 @@ async def on_complete(websocket, operation):
ws.send_json({"type": GraphQLWSHandler.GQL_CONNECTION_TERMINATE})


def test_custom_websocket_on_disconnect_is_called_on_terminate_message(schema):
def test_custom_websocket_on_disconnect_is_called_on_terminate_message(
schema,
timeout=5,
poll_interval=0.1,
):
def on_disconnect(websocket):
websocket.scope["on_disconnect"] = True

Expand All @@ -682,9 +708,15 @@ def on_disconnect(websocket):
response = ws.receive_json()
assert response["type"] == GraphQLWSHandler.GQL_CONNECTION_ACK
ws.send_json({"type": GraphQLWSHandler.GQL_CONNECTION_TERMINATE})
assert "on_disconnect" not in ws.scope
condition_met = wait_for_condition(
lambda: "on_disconnect" in ws.scope,
timeout,
poll_interval,
)

assert ws.scope["on_disconnect"] is True
assert (
condition_met and ws.scope.get("on_disconnect") is True
), "on_disconnect should be set in ws.scope after invalid message"


def test_custom_websocket_on_disconnect_is_called_on_connection_close(schema):
Expand All @@ -704,7 +736,11 @@ def on_disconnect(websocket):
assert ws.scope["on_disconnect"] is True


def test_custom_websocket_on_disconnect_is_awaited_if_its_async(schema):
def test_custom_websocket_on_disconnect_is_awaited_if_its_async(
schema,
timeout=5,
poll_interval=0.1,
):
async def on_disconnect(websocket):
websocket.scope["on_disconnect"] = True

Expand All @@ -717,9 +753,15 @@ async def on_disconnect(websocket):
response = ws.receive_json()
assert response["type"] == GraphQLWSHandler.GQL_CONNECTION_ACK
ws.send_json({"type": GraphQLWSHandler.GQL_CONNECTION_TERMINATE})
assert "on_disconnect" not in ws.scope
condition_met = wait_for_condition(
lambda: "on_disconnect" in ws.scope,
timeout,
poll_interval,
)

assert ws.scope["on_disconnect"] is True
assert (
condition_met and ws.scope.get("on_disconnect") is True
), "on_disconnect should be set in ws.scope after invalid message"


def test_error_in_custom_websocket_on_disconnect_is_handled(schema):
Expand Down
18 changes: 18 additions & 0 deletions tests/asgi/websocket_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import time


def wait_for_condition(condition_func, timeout=5, poll_interval=0.1):
"""
This function is particularly useful in scenarios where asynchronous operations
are involved. For instance, in a WebSocket-based system, certain events or
state changes, like setting a flag in a callback, may not occur instantly.
The wait_for_condition function ensures that the test waits long enough for
these asynchronous events to complete, preventing race conditions or false
negatives in test outcomes.
"""
start_time = time.time()
while time.time() - start_time < timeout:
if condition_func():
return True
time.sleep(poll_interval)
return False
Loading
Loading