def test_url_for(): numbers = Recipe("numbers") @numbers.route("/real") async def real(req, res): pass assert numbers.url_for("numbers:real") == "/numbers/real"
def numbers(): integers = Recipe("integers") @integers.route("/{x}") async def convert(req, res, x): res.json = {"value": int(float(x))} floats = Recipe("floats") @floats.route("/{x}") async def convert(req, res, x): res.json = {"value": float(x)} return Recipe.book(integers, floats, prefix="/numbers")
def test_if_prefix_not_given_then_routes_mounted_at_slash_name(app, client): numbers = Recipe("numbers") @numbers.route("/real") async def real(req, res): pass app.recipe(numbers) assert client.get("/numbers/real").status_code == 200
def test_if_prefix_then_routes_mounted_at_prefix(app, client): numbers = Recipe("numbers", prefix="/numbers-yo") @numbers.route("/real") async def real(req, res): pass app.recipe(numbers) assert client.get("/numbers-yo/real").status_code == 200
def test_if_prefix_then_routes_mounted_at_prefix(api: API): numbers = Recipe("numbers", prefix="/numbers-yo") @numbers.route("/real") async def real(req, res): pass api.recipe(numbers) assert api.url_for("numbers:real") == "/numbers-yo/real"
def test_if_prefix_not_given_then_routes_mounted_at_slash_name(api: API): numbers = Recipe("numbers") @numbers.route("/real") async def real(req, res): pass api.recipe(numbers) assert api.url_for("numbers:real") == "/numbers/real"
def test_on_async_function_view(api: API): numbers = Recipe("numbers") with async_function_hooks() as (before, after): @numbers.before(before) @numbers.after(after) @numbers.route("/real") async def real_numbers(req, res): pass api.recipe(numbers) api.client.get("/numbers/real")
def test_on_class_based_view(api: API): numbers = Recipe("numbers") with async_function_hooks() as (before, after): @numbers.before(before) @numbers.route("/real") class RealNumbers: @numbers.after(after) async def get(self, req, res): pass api.recipe(numbers) api.client.get("/numbers/real")
def test_render_sync_template_in_recipe_route(template_file: TemplateWrapper, api: API): numbers = Recipe("numbers") @numbers.route("/sync") def get_numbers_sync(req, res): res.html = numbers.template_sync(template_file.name, **template_file.context) api.recipe(numbers) response = api.client.get("/numbers/sync") assert response.status_code == 200 assert response.text == template_file.rendered
def test_websocket_recipe_route(app: App, client): chat = Recipe("chat") @chat.websocket_route("/room/{name}", receive_type="json", send_type="text") async def chat_room(ws: WebSocket, name: str): message = await ws.receive() await ws.send(f"[{name}]: {message['text']}") app.recipe(chat) with client.websocket_connect("/chat/room/test") as ws: ws.send_json({"text": "Hello"}) assert ws.receive_text() == "[test]: Hello"
def test_redirect(app: App, client): numbers = Recipe("numbers") @numbers.route("/R") async def R(req, res): numbers.redirect(name="numbers:real") @numbers.route("/real") async def real(req, res): res.text = "inf" app.recipe(numbers) response = client.get("/numbers/R") assert response.status_code == 200 assert response.text == "inf"
def test_use_url_for(api: API): foo = Recipe("foo") @foo.route("/bar") async def bar(req, res): pass @foo.route("/fez") async def fez(req, res): res.html = foo.template_string( "<a href=\"{{ url_for('foo:bar') }}\">To bar</a>") api.recipe(foo) response = api.client.get("/foo/fez") assert response.status_code == 200 assert response.text == '<a href="/foo/bar">To bar</a>'
def test_if_templates_dir_is_that_of_api_by_default(api: API): numbers = Recipe("numbers") api.recipe(numbers) assert numbers.templates_dir == api.templates_dir
courses = storage.list() # Notes: # - Templates are loaded from the `./templates` # directory by default. # - Static files (powered by WhiteNoise) are # served by default at `/static` from the # `./static` directory. # - This means the HTML template can use a reference # to `/static/styles.css`. res.html = await api.template("index.html", courses=courses) # Recipes! # (API-like group of stuff, good for cutting # an app into manageable, bite-sized components.) courses = Recipe("courses") # Class-based views! @courses.route("/") class CoursesList: """API endpoints on the list of courses.""" async def get(self, req, res): # Media responses! (JSON by default) res.media = storage.list() @hooks.before(validate_course) # Hooks again! async def post(self, req, res): payload = await req.json() course = storage.create(**payload) res.media = course._asdict()
from typing import NamedTuple import pytest from bocadillo import App, Templates, Recipe from bocadillo.testing import create_client APP_CLASSES = [App, lambda: Recipe("tacos")] @pytest.fixture(params=APP_CLASSES, name="app") def fixture_app(request): cls = request.param return cls() @pytest.fixture def client(app): return create_client(app) @pytest.fixture(name="templates") def fixture_templates(app: App): return Templates(app) class TemplateWrapper(NamedTuple): name: str context: dict rendered: str
def test_use_template_string(): numbers = Recipe("numbers") html = numbers.template_string("<h1>{{ title }}</h1>", title="Numbers") assert html == "<h1>Numbers</h1>"
def test_if_templates_dir_given_then_it_is_used(api: API): other_dir = "my_recipe/templates" numbers = Recipe("numbers", templates_dir=other_dir) api.recipe(numbers) assert numbers.templates_dir == other_dir != api.templates_dir
def test_if_prefix_does_not_start_with_slash_then_error_raised(): with pytest.raises(AssertionError): Recipe("numbers", prefix="numbers-yo")