diff --git a/Dockerfile.it b/Dockerfile.it index 6ed30638..9ed6365d 100644 --- a/Dockerfile.it +++ b/Dockerfile.it @@ -5,6 +5,7 @@ RUN apk add --no-cache --update --virtual .build-deps \ linux-headers \ ca-certificates \ python3-dev \ + git \ && rm -rf /var/cache/* \ && mkdir /var/cache/apk \ && ln -sf /lib/ld-musl-x86_64.so.1 /usr/bin/ldd \ @@ -14,16 +15,24 @@ WORKDIR /svc COPY requirements/test.txt /svc/ RUN pip install pip setuptools wheel --upgrade \ - && pip wheel --wheel-dir=/svc/wheels -r test.txt + && pip wheel --wheel-dir=/svc/wheels -r test.txt \ + poetry-core>=1.0.0 FROM python:3.10-alpine ENV PYTHONUNBUFFERED=1 \ DEBUG=0 \ + PYTEST_CACHE_DIR=".pytest_cache" \ SITE_DOMAIN="app" \ - SITE_PORT=5000 + SITE_PORT=5000 \ + WEB_URL="http://app:5000" \ + API_URL="http://app:5000/api" \ + BROWSABLE_API_URL="http://app:5000/api/browse" RUN apk add --no-cache --update \ + git \ + chromium \ + chromium-chromedriver \ && rm -rf /var/cache/* \ && mkdir /var/cache/apk \ && ln -sf /lib/ld-musl-x86_64.so.1 /usr/bin/ldd \ @@ -52,6 +61,8 @@ RUN pip install pip setuptools wheel --upgrade \ --no-create-home \ -s /bin/false \ flask_user \ + && mkdir -p /app/test-results \ + && mkdir -p /app/.pytest_cache/screenshots \ && chown flask_user:flask_user -R /app USER flask_user diff --git a/Dockerfile.local b/Dockerfile.local index d4a798cc..ad083f4e 100644 --- a/Dockerfile.local +++ b/Dockerfile.local @@ -26,7 +26,8 @@ RUN pip install pip setuptools wheel --upgrade \ FROM python:3.10-alpine ENV PYTHONUNBUFFERED=1 \ - DEBUG=0 + DEBUG=0 \ + FLASK_SERVER_NAME="app:5000" RUN apk add --no-cache --update \ && rm -rf /var/cache/* \ diff --git a/docker-compose.it.yml b/docker-compose.it.yml index 2487e46f..01eca75e 100644 --- a/docker-compose.it.yml +++ b/docker-compose.it.yml @@ -6,13 +6,16 @@ services: context: . dockerfile: Dockerfile.it environment: - - FLASK_ENV=TESTING + - PYTEST_CACHE_DIR=.pytest_cache - SITE_DOMAIN=async_app - SITE_PORT=5000 - WEB_URL=http://async_app:5000 - API_URL=http://async_app:5000/api - BROWSABLE_API_URL=http://async_app:5000/api/browse user: ${UID:-0}:${GID:-0} + volumes: + - .pytest_cache/test-results/async_app:/app/test-results + - .pytest_cache/screnshots/async_app:/app/.pytest_cache/screnshots depends_on: - async_app @@ -23,7 +26,6 @@ services: args: - FLASK_ASYNC=1 environment: - - FLASK_ENV=TESTING - FLASK_SERVER_NAME=async_app:5000 user: ${UID:-0}:${GID:-0} command: > @@ -36,13 +38,16 @@ services: context: . dockerfile: Dockerfile.it environment: - - FLASK_ENV=TESTING + - PYTEST_CACHE_DIR=.pytest_cache - SITE_DOMAIN=app - SITE_PORT=5000 - WEB_URL=http://app:5000 - API_URL=http://app:5000/api - BROWSABLE_API_URL=http://app:5000/api/browse user: ${UID:-0}:${GID:-0} + volumes: + - .pytest_cache/test-results/app:/app/test-results + - .pytest_cache/screnshots/app:/app/.pytest_cache/screnshots depends_on: - app @@ -51,7 +56,6 @@ services: context: . dockerfile: Dockerfile.local environment: - - FLASK_ENV=TESTING - FLASK_SERVER_NAME=app:5000 user: ${UID:-0}:${GID:-0} command: > diff --git a/docker-compose.test.yml b/docker-compose.test.yml index bacdd98b..435d469e 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -6,7 +6,6 @@ services: context: . dockerfile: Dockerfile.py310.test environment: - - FLASK_ENV=TESTING - PRAGMA_VERSION=py3.10 command: > sh -c "flake8 src/ tests/ && @@ -21,7 +20,6 @@ services: context: . dockerfile: Dockerfile.py39.test environment: - - FLASK_ENV=TESTING - PRAGMA_VERSION=py3.9 command: > sh -c "flake8 src/ tests/ && @@ -33,7 +31,6 @@ services: context: . dockerfile: Dockerfile.py38.test environment: - - FLASK_ENV=TESTING - PRAGMA_VERSION=py3.8 command: > sh -c "flake8 src/ tests/ && @@ -45,7 +42,6 @@ services: context: . dockerfile: Dockerfile.py37.test environment: - - FLASK_ENV=TESTING - PRAGMA_VERSION=py3.7 command: > sh -c "flake8 src/ tests/ && diff --git a/requirements/test.txt b/requirements/test.txt index 61877e70..506a1671 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -8,6 +8,7 @@ pytest-xdist<=3.0.2;python_version<="3.6" pytest-sugar==0.9.6 # https://github.com/Frozenball/pytest-sugar pytest-env==0.8.1;python_version>"3.6" # https://github.com/MobileDynasty/pytest-env pytest-env<0.7.0;python_version<="3.6" +pytest-selenium@git+https://github.com/pytest-dev/pytest-selenium.git;python_version>"3.7" # https://github.com/pytest-dev/pytest-selenium mock==5.0.1 # https://github.com/testing-cabal/mock # Type check diff --git a/tests/test_apps/conftest.py b/tests/test_apps/conftest.py index f2874ebe..42adacad 100644 --- a/tests/test_apps/conftest.py +++ b/tests/test_apps/conftest.py @@ -25,13 +25,18 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import os +import time import unittest +from pathlib import Path import requests +from selenium import webdriver + +WEB_DRIVER_SCREENSHOT_DIR = Path(os.environ['PYTEST_CACHE_DIR']) / 'screenshots' class APITestCase(unittest.TestCase): - def setUp(self): + def setUp(self) -> None: session = requests.Session() session.headers.update( { @@ -39,4 +44,23 @@ def setUp(self): } ) self.requests = session - self.api_url = os.environ['API_URL'] + + +class WebDriverTestCase(unittest.TestCase): + def setUp(self) -> None: + chrome_prefs = {} + chrome_options = webdriver.ChromeOptions() + chrome_options.add_argument('--no-sandbox') + chrome_options.add_argument('--headless') + chrome_options.add_argument('--disable-gpu') + chrome_options.add_experimental_option('prefs', chrome_prefs) + self.driver = webdriver.Chrome(options=chrome_options) + self.driver.delete_all_cookies() + self.driver.implicitly_wait(10) + self.addCleanup(self.driver.quit) + self.addCleanup(self.take_screenshot) + if not WEB_DRIVER_SCREENSHOT_DIR.exists(): + WEB_DRIVER_SCREENSHOT_DIR.mkdir(parents=True) + + def take_screenshot(self): + self.driver.get_screenshot_as_file(str(WEB_DRIVER_SCREENSHOT_DIR / f'{self.id()}-{time.time()}.png')) diff --git a/tests/test_apps/pytest.ini b/tests/test_apps/pytest.ini index fba6a5da..bbb0972f 100644 --- a/tests/test_apps/pytest.ini +++ b/tests/test_apps/pytest.ini @@ -9,5 +9,3 @@ required_plugins = pytest-xdist pytest-sugar pytest-env -env = - FLASK_ENV=TESTING diff --git a/tests/test_apps/pytest.local.ini b/tests/test_apps/pytest.local.ini index 6f840503..e67e8520 100644 --- a/tests/test_apps/pytest.local.ini +++ b/tests/test_apps/pytest.local.ini @@ -10,7 +10,7 @@ required_plugins = pytest-sugar pytest-env env = - FLASK_ENV=TESTING + PYTEST_CACHE_DIR=.pytest_cache SITE_DOMAIN=localhost SITE_PORT=5000 WEB_URL=http://localhost:5000 diff --git a/tests/test_apps/test_app.py b/tests/test_apps/test_app.py index 3e03e788..e819f89a 100644 --- a/tests/test_apps/test_app.py +++ b/tests/test_apps/test_app.py @@ -25,32 +25,35 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # pylint: disable=duplicate-code,too-many-public-methods +import os import json from .conftest import APITestCase +API_URL = os.environ['API_URL'] + class APITest(APITestCase): def test_greeting(self): - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Hello Flask JSON-RPC'}, rv.json()) self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': ['Python']} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': ['Python']} ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Hello Python'}, rv.json()) self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': {'name': 'Flask'}} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': {'name': 'Flask'}} ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Hello Flask'}, rv.json()) self.assertEqual(200, rv.status_code) def test_app_greeting_with_different_content_types(self): rv = self.requests.post( - self.api_url, + API_URL, data=json.dumps({'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}), headers={'Content-Type': 'application/json-rpc'}, ) @@ -58,7 +61,7 @@ def test_app_greeting_with_different_content_types(self): self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, + API_URL, data=json.dumps({'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': ['Python']}), headers={'Content-Type': 'application/jsonrequest'}, ) @@ -66,7 +69,7 @@ def test_app_greeting_with_different_content_types(self): self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, + API_URL, data=json.dumps({'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': {'name': 'Flask'}}), headers={'Content-Type': 'application/json'}, ) @@ -74,7 +77,7 @@ def test_app_greeting_with_different_content_types(self): self.assertEqual(200, rv.status_code) def test_greeting_raise_parse_error(self): - rv = self.requests.post(self.api_url, data={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}) + rv = self.requests.post(API_URL, data={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}) self.assertEqual( { 'id': None, @@ -91,7 +94,7 @@ def test_greeting_raise_parse_error(self): self.assertEqual(400, rv.status_code) rv = self.requests.post( - self.api_url, + API_URL, data="{'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}", headers={'Content-Type': 'application/json'}, ) @@ -115,7 +118,7 @@ def test_greeting_raise_parse_error(self): self.assertEqual(400, rv.status_code) rv = self.requests.post( - self.api_url, + API_URL, data="""[ {'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': ['Flask'], 'id': '1'}, {'jsonrpc': '2.0', 'method' @@ -143,7 +146,7 @@ def test_greeting_raise_parse_error(self): self.assertEqual(400, rv.status_code) def test_greeting_raise_invalid_request_error(self): - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0'}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0'}) self.assertEqual( { 'id': 1, @@ -161,7 +164,7 @@ def test_greeting_raise_invalid_request_error(self): def test_greeting_raise_invalid_params_error(self): rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': 'Wrong'} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': 'Wrong'} ) self.assertEqual( { @@ -180,9 +183,7 @@ def test_greeting_raise_invalid_params_error(self): ) self.assertEqual(400, rv.status_code) - rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': [1]} - ) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': [1]}) self.assertEqual( { 'id': 1, @@ -199,7 +200,7 @@ def test_greeting_raise_invalid_params_error(self): self.assertEqual(400, rv.status_code) rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': {'name': 2}} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': {'name': 2}} ) self.assertEqual( { @@ -217,7 +218,7 @@ def test_greeting_raise_invalid_params_error(self): self.assertEqual(400, rv.status_code) def test_greeting_raise_method_not_found_error(self): - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'method-not-found'}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'method-not-found'}) self.assertEqual( { 'id': 1, @@ -235,21 +236,19 @@ def test_greeting_raise_method_not_found_error(self): def test_echo(self): rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': ['Python']} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': ['Python']} ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Python'}, rv.json()) self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': {'string': 'Flask'}} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': {'string': 'Flask'}} ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Flask'}, rv.json()) self.assertEqual(200, rv.status_code) def test_echo_raise_invalid_params_error(self): - rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': 'Wrong'} - ) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': 'Wrong'}) self.assertEqual( { 'id': 1, @@ -267,7 +266,7 @@ def test_echo_raise_invalid_params_error(self): ) self.assertEqual(400, rv.status_code) - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': [1]}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': [1]}) self.assertEqual( { 'id': 1, @@ -284,7 +283,7 @@ def test_echo_raise_invalid_params_error(self): self.assertEqual(400, rv.status_code) rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': {'name': 2}} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo', 'params': {'name': 2}} ) self.assertEqual( { @@ -301,7 +300,7 @@ def test_echo_raise_invalid_params_error(self): ) self.assertEqual(400, rv.status_code) - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo'}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.echo'}) self.assertEqual( { 'id': 1, @@ -318,30 +317,28 @@ def test_echo_raise_invalid_params_error(self): self.assertEqual(400, rv.status_code) def test_notify(self): - rv = self.requests.post(self.api_url, json={'jsonrpc': '2.0', 'method': 'jsonrpc.notify'}) + rv = self.requests.post(API_URL, json={'jsonrpc': '2.0', 'method': 'jsonrpc.notify'}) self.assertEqual('', rv.text) self.assertEqual(204, rv.status_code) - rv = self.requests.post( - self.api_url, json={'jsonrpc': '2.0', 'method': 'jsonrpc.notify', 'params': ['Some string']} - ) + rv = self.requests.post(API_URL, json={'jsonrpc': '2.0', 'method': 'jsonrpc.notify', 'params': ['Some string']}) self.assertEqual('', rv.text) self.assertEqual(204, rv.status_code) def test_not_allow_notify(self): - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.not_allow_notify'}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.not_allow_notify'}) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Not allow notify'}, rv.json()) self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.not_allow_notify', 'params': ['Some string']}, ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Not allow notify'}, rv.json()) self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, json={'jsonrpc': '2.0', 'method': 'jsonrpc.not_allow_notify', 'params': ['Some string']} + API_URL, json={'jsonrpc': '2.0', 'method': 'jsonrpc.not_allow_notify', 'params': ['Some string']} ) self.assertEqual( { @@ -362,15 +359,11 @@ def test_not_allow_notify(self): self.assertEqual(400, rv.status_code) def test_fails(self): - rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.fails', 'params': [2]} - ) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.fails', 'params': [2]}) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 2}, rv.json()) self.assertEqual(200, rv.status_code) - rv = self.requests.post( - self.api_url, json={'id': '1', 'jsonrpc': '2.0', 'method': 'jsonrpc.fails', 'params': [1]} - ) + rv = self.requests.post(API_URL, json={'id': '1', 'jsonrpc': '2.0', 'method': 'jsonrpc.fails', 'params': [1]}) self.assertEqual( { 'id': '1', @@ -393,7 +386,7 @@ def test_strange_echo(self): 'method': 'jsonrpc.strangeEcho', 'params': ['string', {'a': 1}, ['a', 'b', 'c'], 23, 'Flask'], } - rv = self.requests.post(self.api_url, json=data) + rv = self.requests.post(API_URL, json=data) self.assertEqual( {'id': 1, 'jsonrpc': '2.0', 'result': ['string', {'a': 1}, ['a', 'b', 'c'], 23, 'Flask']}, rv.json() ) @@ -405,7 +398,7 @@ def test_strange_echo(self): 'method': 'jsonrpc.strangeEcho', 'params': ['string', {'a': 1}, ['a', 'b', 'c'], 23], } - rv = self.requests.post(self.api_url, json=data) + rv = self.requests.post(API_URL, json=data) self.assertEqual( {'id': 1, 'jsonrpc': '2.0', 'result': ['string', {'a': 1}, ['a', 'b', 'c'], 23, 'Default']}, rv.json() ) @@ -413,31 +406,31 @@ def test_strange_echo(self): def test_sum(self): data = {'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.sum', 'params': [1, 3]} - rv = self.requests.post(self.api_url, json=data) + rv = self.requests.post(API_URL, json=data) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 4}, rv.json()) self.assertEqual(200, rv.status_code) data = {'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.sum', 'params': [0.5, 1.5]} - rv = self.requests.post(self.api_url, json=data) + rv = self.requests.post(API_URL, json=data) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 2.0}, rv.json()) self.assertEqual(200, rv.status_code) def test_decorators(self): data = {'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.decorators', 'params': ['Python']} - rv = self.requests.post(self.api_url, json=data) + rv = self.requests.post(API_URL, json=data) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Hello Python from decorator, ;)'}, rv.json()) self.assertEqual(200, rv.status_code) def test_return_status_code(self): rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.returnStatusCode', 'params': ['OK']} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.returnStatusCode', 'params': ['OK']} ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Status Code OK'}, rv.json()) self.assertEqual(201, rv.status_code) def test_return_headers(self): rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.returnHeaders', 'params': ['OK']} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.returnHeaders', 'params': ['OK']} ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Headers OK'}, rv.json()) self.assertEqual(200, rv.status_code) @@ -445,7 +438,7 @@ def test_return_headers(self): def test_return_status_code_and_headers(self): rv = self.requests.post( - self.api_url, + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.returnStatusCodeAndHeaders', 'params': ['OK']}, ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Status Code and Headers OK'}, rv.json()) @@ -454,19 +447,19 @@ def test_return_status_code_and_headers(self): def test_not_validate_method(self): rv = self.requests.post( - self.api_url, + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.not_validate', 'params': ['OK']}, ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Not validate: OK'}, rv.json()) self.assertEqual(200, rv.status_code) def test_with_rcp_batch(self): - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Hello Flask JSON-RPC'}, rv.json()) self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, + API_URL, json=[ {'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': ['Python']}, {'id': 2, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': ['Flask']}, @@ -484,7 +477,7 @@ def test_with_rcp_batch(self): self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, + API_URL, json=[ {'id': 1, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': ['Python']}, {'jsonrpc': '2.0', 'method': 'jsonrpc.greeting', 'params': ['Flask']}, @@ -511,37 +504,33 @@ def test_with_rcp_batch(self): ) self.assertEqual(200, rv.status_code) - rv = self.requests.post(self.api_url, json={'id': 2, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}) + rv = self.requests.post(API_URL, json={'id': 2, 'jsonrpc': '2.0', 'method': 'jsonrpc.greeting'}) self.assertEqual({'id': 2, 'jsonrpc': '2.0', 'result': 'Hello Flask JSON-RPC'}, rv.json()) self.assertEqual(200, rv.status_code) def test_class(self): - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'classapp.index'}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'classapp.index'}) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Hello Flask JSON-RPC'}, rv.json()) self.assertEqual(200, rv.status_code) - rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'greeting', 'params': ['Python']} - ) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'greeting', 'params': ['Python']}) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Hello Python'}, rv.json()) self.assertEqual(200, rv.status_code) rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'hello', 'params': {'name': 'Flask'}} + API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'hello', 'params': {'name': 'Flask'}} ) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Hello Flask'}, rv.json()) self.assertEqual(200, rv.status_code) - rv = self.requests.post( - self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'echo', 'params': ['Python', 1]} - ) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'echo', 'params': ['Python', 1]}) self.assertEqual({'id': 1, 'jsonrpc': '2.0', 'result': 'Python'}, rv.json()) self.assertEqual(200, rv.status_code) - rv = self.requests.post(self.api_url, json={'jsonrpc': '2.0', 'method': 'notify', 'params': ['Python']}) + rv = self.requests.post(API_URL, json={'jsonrpc': '2.0', 'method': 'notify', 'params': ['Python']}) self.assertEqual(204, rv.status_code) - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'fails', 'params': [13]}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'fails', 'params': [13]}) self.assertEqual( { 'id': 1, @@ -558,7 +547,7 @@ def test_class(self): self.assertEqual(500, rv.status_code) def test_system_describe(self): - rv = self.requests.post(self.api_url, json={'id': 1, 'jsonrpc': '2.0', 'method': 'system.describe'}) + rv = self.requests.post(API_URL, json={'id': 1, 'jsonrpc': '2.0', 'method': 'system.describe'}) json_data = rv.json() self.assertEqual(1, json_data['id']) self.assertEqual('2.0', json_data['jsonrpc']) diff --git a/tests/test_apps/test_browse.py b/tests/test_apps/test_browse.py new file mode 100644 index 00000000..cee9a7c1 --- /dev/null +++ b/tests/test_apps/test_browse.py @@ -0,0 +1,41 @@ +# Copyright (c) 2022-2022, Cenobit Technologies, Inc. http://cenobit.es/ +# All rights reserved. +# +# Redistribution and use in source and binary forms, 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 Cenobit Technologies 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 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, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# pylint: disable=duplicate-code,too-many-public-methods +import os + +from selenium.webdriver.common.by import By + +from .conftest import WebDriverTestCase + +BROWSABLE_API_URL = os.environ['BROWSABLE_API_URL'] + + +class WebBrowsableAPITest(WebDriverTestCase): + def test_index(self): + self.driver.get(BROWSABLE_API_URL) + logo_link = self.driver.find_element(By.XPATH, '//*[@id="logo-link"]') + self.assertEqual('Web browsable API', logo_link.text)