From fce1885f7614c60c7cd8e4a4eadc5b99fe036264 Mon Sep 17 00:00:00 2001 From: David Lord Date: Thu, 12 Apr 2018 11:06:02 -0700 Subject: [PATCH] add javascript ajax example --- docs/patterns/jquery.rst | 5 +- docs/testing.rst | 6 --- examples/javascript/.gitignore | 14 ++++++ examples/javascript/LICENSE | 31 ++++++++++++ examples/javascript/MANIFEST.in | 4 ++ examples/javascript/README.rst | 49 +++++++++++++++++++ examples/javascript/js_example/__init__.py | 5 ++ .../javascript/js_example/templates/base.html | 33 +++++++++++++ .../js_example/templates/fetch.html | 35 +++++++++++++ .../js_example/templates/jquery.html | 27 ++++++++++ .../js_example/templates/plain.html | 27 ++++++++++ examples/javascript/js_example/views.py | 16 ++++++ examples/javascript/setup.cfg | 13 +++++ examples/javascript/setup.py | 30 ++++++++++++ examples/javascript/tests/conftest.py | 15 ++++++ examples/javascript/tests/test_js_example.py | 28 +++++++++++ examples/tutorial/README.rst | 3 +- examples/tutorial/flaskr/auth.py | 2 +- examples/tutorial/setup.cfg | 2 +- examples/tutorial/setup.py | 6 +++ tox.ini | 3 +- 21 files changed, 341 insertions(+), 13 deletions(-) create mode 100644 examples/javascript/.gitignore create mode 100644 examples/javascript/LICENSE create mode 100644 examples/javascript/MANIFEST.in create mode 100644 examples/javascript/README.rst create mode 100644 examples/javascript/js_example/__init__.py create mode 100644 examples/javascript/js_example/templates/base.html create mode 100644 examples/javascript/js_example/templates/fetch.html create mode 100644 examples/javascript/js_example/templates/jquery.html create mode 100644 examples/javascript/js_example/templates/plain.html create mode 100644 examples/javascript/js_example/views.py create mode 100644 examples/javascript/setup.cfg create mode 100644 examples/javascript/setup.py create mode 100644 examples/javascript/tests/conftest.py create mode 100644 examples/javascript/tests/test_js_example.py diff --git a/docs/patterns/jquery.rst b/docs/patterns/jquery.rst index 24569a53..8297bd44 100644 --- a/docs/patterns/jquery.rst +++ b/docs/patterns/jquery.rst @@ -162,5 +162,6 @@ explanation of the little bit of code above: argument. Note that we can use the `$SCRIPT_ROOT` variable here that we set earlier. -If you don't get the whole picture, download the :gh:`sourcecode -for this example `. +Check out the :gh:`example source ` for a full +application demonstrating the jQuery on this page, as well as the same +thing using ``XMLHttpRequest`` and ``fetch``. diff --git a/docs/testing.rst b/docs/testing.rst index bfbc1d91..82e10328 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -209,12 +209,6 @@ Running that should now give us three passing tests:: ============= 3 passed in 0.23 seconds ============== -For more complex tests with headers and status codes, check out the -`MiniTwit Example`_ from the sources which contains a larger test -suite. - -.. _MiniTwit Example: - https://github.com/pallets/flask/tree/master/examples/minitwit/ Other Testing Tricks -------------------- diff --git a/examples/javascript/.gitignore b/examples/javascript/.gitignore new file mode 100644 index 00000000..85a35845 --- /dev/null +++ b/examples/javascript/.gitignore @@ -0,0 +1,14 @@ +venv/ +*.pyc +__pycache__/ +instance/ +.cache/ +.pytest_cache/ +.coverage +htmlcov/ +dist/ +build/ +*.egg-info/ +.idea/ +*.swp +*~ diff --git a/examples/javascript/LICENSE b/examples/javascript/LICENSE new file mode 100644 index 00000000..8f9252f4 --- /dev/null +++ b/examples/javascript/LICENSE @@ -0,0 +1,31 @@ +Copyright © 2010 by the Pallets team. + +Some rights reserved. + +Redistribution and use in source and binary forms of the software as +well as documentation, with or without modification, are permitted +provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/examples/javascript/MANIFEST.in b/examples/javascript/MANIFEST.in new file mode 100644 index 00000000..0ba3d5b8 --- /dev/null +++ b/examples/javascript/MANIFEST.in @@ -0,0 +1,4 @@ +include LICENSE +graft js_example/templates +graft tests +global-exclude *.pyc diff --git a/examples/javascript/README.rst b/examples/javascript/README.rst new file mode 100644 index 00000000..fc074284 --- /dev/null +++ b/examples/javascript/README.rst @@ -0,0 +1,49 @@ +JavaScript Ajax Example +======================= + +Demonstrates how to post form data and process a JSON response using +JavaScript. This allows making requests without navigating away from the +page. Demonstrates using |XMLHttpRequest|_, |fetch|_, and +|jQuery.ajax|_. See the `Flask docs`_ about jQuery and Ajax. + +.. |XMLHttpRequest| replace:: ``XMLHttpRequest`` +.. _XMLHttpRequest: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest + +.. |fetch| replace:: ``fetch`` +.. _fetch: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch + +.. |jQuery.ajax| replace:: ``jQuery.ajax`` +.. _jQuery.ajax: https://api.jquery.com/jQuery.ajax/ + +.. _Flask docs: http://flask.pocoo.org/docs/patterns/jquery/ + + +Install +------- + +:: + + python3 -m venv venv + . venv/bin/activate + pip install -e . + + +Run +--- + +:: + + export FLASK_APP=js_example + flask run + +Open http://127.0.0.1:5000 in a browser. + + +Test +---- + +:: + + pip install -e '.[test]' + coverage run -m pytest + coverage report diff --git a/examples/javascript/js_example/__init__.py b/examples/javascript/js_example/__init__.py new file mode 100644 index 00000000..d90fc4d4 --- /dev/null +++ b/examples/javascript/js_example/__init__.py @@ -0,0 +1,5 @@ +from flask import Flask + +app = Flask(__name__) + +from js_example import views diff --git a/examples/javascript/js_example/templates/base.html b/examples/javascript/js_example/templates/base.html new file mode 100644 index 00000000..a4b4480e --- /dev/null +++ b/examples/javascript/js_example/templates/base.html @@ -0,0 +1,33 @@ + +JavaScript Example + + + + +
+

{% block intro %}{% endblock %}

+
+
+ + + + + +
+= +{% block script %}{% endblock %} diff --git a/examples/javascript/js_example/templates/fetch.html b/examples/javascript/js_example/templates/fetch.html new file mode 100644 index 00000000..4d5fcc56 --- /dev/null +++ b/examples/javascript/js_example/templates/fetch.html @@ -0,0 +1,35 @@ +{% extends 'base.html' %} + +{% block intro %} + fetch + is the new plain JavaScript way to make requests. It's + supported in all modern browsers except IE, which requires a + polyfill. +{% endblock %} + +{% block script %} + + + +{% endblock %} diff --git a/examples/javascript/js_example/templates/jquery.html b/examples/javascript/js_example/templates/jquery.html new file mode 100644 index 00000000..17bafd4d --- /dev/null +++ b/examples/javascript/js_example/templates/jquery.html @@ -0,0 +1,27 @@ +{% extends 'base.html' %} + +{% block intro %} + jQuery is a popular library that + adds cross browser APIs for common tasks. However, it requires loading + an extra library. +{% endblock %} + +{% block script %} + + +{% endblock %} diff --git a/examples/javascript/js_example/templates/plain.html b/examples/javascript/js_example/templates/plain.html new file mode 100644 index 00000000..98e81e53 --- /dev/null +++ b/examples/javascript/js_example/templates/plain.html @@ -0,0 +1,27 @@ +{% extends 'base.html' %} + +{% block intro %} + XMLHttpRequest + is the plain JavaScript way to make requests. It's natively supported + by all browsers. +{% endblock %} + +{% block script %} + +{% endblock %} diff --git a/examples/javascript/js_example/views.py b/examples/javascript/js_example/views.py new file mode 100644 index 00000000..c898e6de --- /dev/null +++ b/examples/javascript/js_example/views.py @@ -0,0 +1,16 @@ +from flask import jsonify, render_template, request + +from js_example import app + + +@app.route('/', defaults={'js': 'plain'}) +@app.route('/') +def index(js): + return render_template('{0}.html'.format(js), js=js) + + +@app.route('/add', methods=['POST']) +def add(): + a = request.form.get('a', 0, type=float) + b = request.form.get('b', 0, type=float) + return jsonify(result=a + b) diff --git a/examples/javascript/setup.cfg b/examples/javascript/setup.cfg new file mode 100644 index 00000000..a14fa80e --- /dev/null +++ b/examples/javascript/setup.cfg @@ -0,0 +1,13 @@ +[metadata] +license_file = LICENSE + +[bdist_wheel] +universal = True + +[tool:pytest] +testpaths = tests + +[coverage:run] +branch = True +source = + js_example diff --git a/examples/javascript/setup.py b/examples/javascript/setup.py new file mode 100644 index 00000000..c699e8f1 --- /dev/null +++ b/examples/javascript/setup.py @@ -0,0 +1,30 @@ +import io + +from setuptools import find_packages, setup + +with io.open('README.rst', 'rt', encoding='utf8') as f: + readme = f.read() + +setup( + name='js_example', + version='1.0.0', + url='http://flask.pocoo.org/docs/patterns/jquery/', + license='BSD', + maintainer='Pallets team', + maintainer_email='contact@palletsprojects.com', + description='Demonstrates making Ajax requests to Flask.', + long_description=readme, + packages=find_packages(), + include_package_data=True, + zip_safe=False, + install_requires=[ + 'flask', + ], + extras_require={ + 'test': [ + 'pytest', + 'coverage', + 'blinker', + ], + }, +) diff --git a/examples/javascript/tests/conftest.py b/examples/javascript/tests/conftest.py new file mode 100644 index 00000000..ea81ba59 --- /dev/null +++ b/examples/javascript/tests/conftest.py @@ -0,0 +1,15 @@ +import pytest + +from js_example import app + + +@pytest.fixture(name='app') +def fixture_app(): + app.testing = True + yield app + app.testing = False + + +@pytest.fixture +def client(app): + return app.test_client() diff --git a/examples/javascript/tests/test_js_example.py b/examples/javascript/tests/test_js_example.py new file mode 100644 index 00000000..f1bcf96d --- /dev/null +++ b/examples/javascript/tests/test_js_example.py @@ -0,0 +1,28 @@ +import pytest + +from flask import template_rendered + + +@pytest.mark.parametrize(('path', 'template_name'), ( + ('/', 'plain.html'), + ('/plain', 'plain.html'), + ('/fetch', 'fetch.html'), + ('/jquery', 'jquery.html'), +)) +def test_index(app, client, path, template_name): + def check(sender, template, context): + assert template.name == template_name + + with template_rendered.connected_to(check, app): + client.get(path) + + +@pytest.mark.parametrize(('a', 'b', 'result'), ( + (2, 3, 5), + (2.5, 3, 5.5), + (2, None, 2), + (2, 'b', 2), +)) +def test_add(client, a, b, result): + response = client.post('/add', data={'a': a, 'b': b}) + assert response.get_json()['result'] == result diff --git a/examples/tutorial/README.rst b/examples/tutorial/README.rst index e0c44b61..1afb1ebd 100644 --- a/examples/tutorial/README.rst +++ b/examples/tutorial/README.rst @@ -65,12 +65,11 @@ Test :: - pip install pytest + pip install '.[test]' pytest Run with coverage report:: - pip install pytest coverage coverage run -m pytest coverage report coverage html # open htmlcov/index.html in a browser diff --git a/examples/tutorial/flaskr/auth.py b/examples/tutorial/flaskr/auth.py index d86095bf..e8cd2940 100644 --- a/examples/tutorial/flaskr/auth.py +++ b/examples/tutorial/flaskr/auth.py @@ -56,7 +56,7 @@ def register(): elif db.execute( 'SELECT id FROM user WHERE username = ?', (username,) ).fetchone() is not None: - error = 'User {} is already registered.'.format(username) + error = 'User {0} is already registered.'.format(username) if error is None: # the name is available, store it in the database and go to diff --git a/examples/tutorial/setup.cfg b/examples/tutorial/setup.cfg index b0cc972d..3e47794e 100644 --- a/examples/tutorial/setup.cfg +++ b/examples/tutorial/setup.cfg @@ -2,7 +2,7 @@ license_file = LICENSE [bdist_wheel] -universal = False +universal = True [tool:pytest] testpaths = tests diff --git a/examples/tutorial/setup.py b/examples/tutorial/setup.py index 52a282a2..460d789b 100644 --- a/examples/tutorial/setup.py +++ b/examples/tutorial/setup.py @@ -20,4 +20,10 @@ setup( install_requires=[ 'flask', ], + extras_require={ + 'test': [ + 'pytest', + 'coverage', + ], + }, ) diff --git a/tox.ini b/tox.ini index cbc72ade..5818fa89 100644 --- a/tox.ini +++ b/tox.ini @@ -31,7 +31,8 @@ deps = commands = # the examples need to be installed to test successfully - pip install -e examples/tutorial -q + pip install -q -e examples/tutorial[test] + pip install -q -e examples/javascript[test] # pytest-cov doesn't seem to play nice with -p coverage run -p -m pytest tests examples