python-getpaid-simulator 3.0.0a3__tar.gz → 3.0.0a4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_getpaid_simulator-3.0.0a4/.github/workflows/ci.yml +55 -0
- python_getpaid_simulator-3.0.0a4/Dockerfile.dockerignore +22 -0
- python_getpaid_simulator-3.0.0a4/Dockerfile.test +39 -0
- python_getpaid_simulator-3.0.0a4/Dockerfile.test.dockerignore +22 -0
- python_getpaid_simulator-3.0.0a4/Makefile +50 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/PKG-INFO +2 -2
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/README.md +1 -1
- python_getpaid_simulator-3.0.0a4/compose.test.yml +30 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/docker-compose.yml +1 -3
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/pyproject.toml +4 -3
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/__init__.py +1 -1
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/app.py +6 -4
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/routes.py +45 -9
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/e2e/conftest.py +26 -10
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_app.py +58 -0
- python_getpaid_simulator-3.0.0a4/tests/test_smoke.py +43 -0
- python_getpaid_simulator-3.0.0a4/tests/test_test_infrastructure.py +102 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_ui_authorize.py +51 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_ui_dashboard.py +39 -0
- python_getpaid_simulator-3.0.0a3/tests/test_smoke.py +0 -22
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/.gitignore +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/Dockerfile +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/__main__.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/core/__init__.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/core/config.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/core/discovery.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/core/state.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/core/storage.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/core/webhooks.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/plugins.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/spi.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/__init__.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/static/.gitkeep +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/static/style.css +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/templates/.gitkeep +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/templates/authorize.html +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/templates/base.html +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/templates/components/dashboard_payment_card.html +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/templates/components/payment_card.html +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/templates/components/status_badge.html +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/ui/templates/dashboard.html +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/__init__.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/conftest.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/e2e/__init__.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/e2e/test_e2e_dashboard.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/e2e/test_e2e_payu_flow.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_cli.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_config.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_discovery.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_legacy_provider_modules.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_paynow_payments.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_paynow_refunds.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_paynow_signing.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_paynow_webhooks.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_lifecycle.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_oauth.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_orders.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_refunds.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_webhooks.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_state.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_storage.py +0 -0
- {python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_webhooks.py +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
unit:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.12", "3.13"]
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
run: pip install uv
|
|
25
|
+
|
|
26
|
+
- name: Install unit dependencies
|
|
27
|
+
run: uv sync --frozen
|
|
28
|
+
|
|
29
|
+
- name: Lint with ruff
|
|
30
|
+
run: uv run ruff check .
|
|
31
|
+
|
|
32
|
+
- name: Run unit tests
|
|
33
|
+
run: make test-unit
|
|
34
|
+
|
|
35
|
+
integration:
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
needs: unit
|
|
38
|
+
timeout-minutes: 30
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
- name: Run Docker-backed integration tests
|
|
44
|
+
run: make test-integration
|
|
45
|
+
|
|
46
|
+
e2e:
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
needs: unit
|
|
49
|
+
timeout-minutes: 30
|
|
50
|
+
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v4
|
|
53
|
+
|
|
54
|
+
- name: Run Docker-backed end-to-end tests
|
|
55
|
+
run: make test-e2e
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
**
|
|
2
|
+
!getpaid-core/
|
|
3
|
+
!getpaid-core/**
|
|
4
|
+
!getpaid-payu/
|
|
5
|
+
!getpaid-payu/**
|
|
6
|
+
!getpaid-paynow/
|
|
7
|
+
!getpaid-paynow/**
|
|
8
|
+
!getpaid-simulator/
|
|
9
|
+
!getpaid-simulator/**
|
|
10
|
+
|
|
11
|
+
**/.git
|
|
12
|
+
**/__pycache__
|
|
13
|
+
**/.pytest_cache
|
|
14
|
+
**/.ruff_cache
|
|
15
|
+
**/.mypy_cache
|
|
16
|
+
**/.venv
|
|
17
|
+
**/.sisyphus
|
|
18
|
+
**/dist
|
|
19
|
+
**/build
|
|
20
|
+
**/*.pyc
|
|
21
|
+
**/*.pyo
|
|
22
|
+
**/*.egg-info
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
FROM python:3.12-slim
|
|
2
|
+
|
|
3
|
+
WORKDIR /app/getpaid-simulator
|
|
4
|
+
|
|
5
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
6
|
+
git \
|
|
7
|
+
libnss3 \
|
|
8
|
+
libnspr4 \
|
|
9
|
+
libdbus-1-3 \
|
|
10
|
+
libatk1.0-0 \
|
|
11
|
+
libatk-bridge2.0-0 \
|
|
12
|
+
libcups2 \
|
|
13
|
+
libdrm2 \
|
|
14
|
+
libxkbcommon0 \
|
|
15
|
+
libatspi2.0-0 \
|
|
16
|
+
libxcomposite1 \
|
|
17
|
+
libxdamage1 \
|
|
18
|
+
libxfixes3 \
|
|
19
|
+
libxrandr2 \
|
|
20
|
+
libgbm1 \
|
|
21
|
+
libpango-1.0-0 \
|
|
22
|
+
libcairo2 \
|
|
23
|
+
libasound2 \
|
|
24
|
+
libwayland-client0 \
|
|
25
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
26
|
+
|
|
27
|
+
RUN pip install --no-cache-dir uv
|
|
28
|
+
|
|
29
|
+
COPY getpaid-core/ /app/getpaid-core/
|
|
30
|
+
COPY getpaid-payu/ /app/getpaid-payu/
|
|
31
|
+
COPY getpaid-paynow/ /app/getpaid-paynow/
|
|
32
|
+
COPY getpaid-simulator/ /app/getpaid-simulator/
|
|
33
|
+
|
|
34
|
+
ENV PLAYWRIGHT_BROWSERS_PATH="/app/getpaid-simulator/.cache/ms-playwright"
|
|
35
|
+
|
|
36
|
+
RUN uv sync --frozen --group e2e
|
|
37
|
+
RUN uv run playwright install chromium
|
|
38
|
+
|
|
39
|
+
ENV PATH="/app/getpaid-simulator/.venv/bin:$PATH"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
**
|
|
2
|
+
!getpaid-core/
|
|
3
|
+
!getpaid-core/**
|
|
4
|
+
!getpaid-payu/
|
|
5
|
+
!getpaid-payu/**
|
|
6
|
+
!getpaid-paynow/
|
|
7
|
+
!getpaid-paynow/**
|
|
8
|
+
!getpaid-simulator/
|
|
9
|
+
!getpaid-simulator/**
|
|
10
|
+
|
|
11
|
+
**/.git
|
|
12
|
+
**/__pycache__
|
|
13
|
+
**/.pytest_cache
|
|
14
|
+
**/.ruff_cache
|
|
15
|
+
**/.mypy_cache
|
|
16
|
+
**/.venv
|
|
17
|
+
**/.sisyphus
|
|
18
|
+
**/dist
|
|
19
|
+
**/build
|
|
20
|
+
**/*.pyc
|
|
21
|
+
**/*.pyo
|
|
22
|
+
**/*.egg-info
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
.PHONY: test test-unit test-integration test-e2e test-build test-down
|
|
2
|
+
|
|
3
|
+
UNIT_TESTS = \
|
|
4
|
+
tests/test_cli.py \
|
|
5
|
+
tests/test_config.py \
|
|
6
|
+
tests/test_discovery.py \
|
|
7
|
+
tests/test_smoke.py \
|
|
8
|
+
tests/test_storage.py \
|
|
9
|
+
tests/test_state.py \
|
|
10
|
+
tests/test_app.py \
|
|
11
|
+
tests/test_legacy_provider_modules.py \
|
|
12
|
+
tests/test_test_infrastructure.py
|
|
13
|
+
|
|
14
|
+
INTEGRATION_TESTS = \
|
|
15
|
+
tests/test_ui_dashboard.py \
|
|
16
|
+
tests/test_ui_authorize.py \
|
|
17
|
+
tests/test_payu_oauth.py \
|
|
18
|
+
tests/test_payu_orders.py \
|
|
19
|
+
tests/test_payu_webhooks.py \
|
|
20
|
+
tests/test_payu_refunds.py \
|
|
21
|
+
tests/test_payu_lifecycle.py \
|
|
22
|
+
tests/test_paynow_signing.py \
|
|
23
|
+
tests/test_paynow_payments.py \
|
|
24
|
+
tests/test_paynow_webhooks.py \
|
|
25
|
+
tests/test_paynow_refunds.py \
|
|
26
|
+
tests/test_webhooks.py
|
|
27
|
+
|
|
28
|
+
E2E_TESTS = \
|
|
29
|
+
tests/e2e/test_e2e_dashboard.py \
|
|
30
|
+
tests/e2e/test_e2e_payu_flow.py
|
|
31
|
+
|
|
32
|
+
test-unit:
|
|
33
|
+
uv run pytest $(UNIT_TESTS) -x
|
|
34
|
+
|
|
35
|
+
test-integration: test-build
|
|
36
|
+
docker compose -f compose.test.yml run --rm tests uv run pytest $(INTEGRATION_TESTS) -x
|
|
37
|
+
|
|
38
|
+
test-e2e: test-build
|
|
39
|
+
docker compose -f compose.test.yml run --rm tests uv run pytest $(E2E_TESTS) -x
|
|
40
|
+
|
|
41
|
+
test:
|
|
42
|
+
$(MAKE) test-unit
|
|
43
|
+
$(MAKE) test-integration
|
|
44
|
+
$(MAKE) test-e2e
|
|
45
|
+
|
|
46
|
+
test-build:
|
|
47
|
+
docker compose -f compose.test.yml build
|
|
48
|
+
|
|
49
|
+
test-down:
|
|
50
|
+
docker compose -f compose.test.yml down -v
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-getpaid-simulator
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.0a4
|
|
4
4
|
Summary: Payment gateway simulator for testing the python-getpaid ecosystem.
|
|
5
5
|
Project-URL: Homepage, https://github.com/django-getpaid/python-getpaid-simulator
|
|
6
6
|
Project-URL: Repository, https://github.com/django-getpaid/python-getpaid-simulator
|
|
@@ -96,7 +96,7 @@ Example:
|
|
|
96
96
|
```toml
|
|
97
97
|
[project.optional-dependencies]
|
|
98
98
|
simulator = [
|
|
99
|
-
"python-getpaid-simulator>=3.0.
|
|
99
|
+
"python-getpaid-simulator>=3.0.0a4",
|
|
100
100
|
"litestar>=2.0",
|
|
101
101
|
]
|
|
102
102
|
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
services:
|
|
2
|
+
testdb:
|
|
3
|
+
image: postgres:16
|
|
4
|
+
environment:
|
|
5
|
+
POSTGRES_DB: test_db
|
|
6
|
+
POSTGRES_USER: test_user
|
|
7
|
+
POSTGRES_PASSWORD: test_password
|
|
8
|
+
healthcheck:
|
|
9
|
+
test: ["CMD-SHELL", "pg_isready -U test_user -d test_db"]
|
|
10
|
+
interval: 2s
|
|
11
|
+
timeout: 5s
|
|
12
|
+
retries: 10
|
|
13
|
+
networks:
|
|
14
|
+
- test-net
|
|
15
|
+
|
|
16
|
+
tests:
|
|
17
|
+
build:
|
|
18
|
+
context: ..
|
|
19
|
+
dockerfile: getpaid-simulator/Dockerfile.test
|
|
20
|
+
depends_on:
|
|
21
|
+
testdb:
|
|
22
|
+
condition: service_healthy
|
|
23
|
+
environment:
|
|
24
|
+
TEST_DATABASE_URL: postgresql://test_user:test_password@testdb:5432/test_db
|
|
25
|
+
networks:
|
|
26
|
+
- test-net
|
|
27
|
+
|
|
28
|
+
networks:
|
|
29
|
+
test-net:
|
|
30
|
+
driver: bridge
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
version: "3.9"
|
|
2
|
-
|
|
3
1
|
services:
|
|
4
2
|
simulator:
|
|
5
3
|
build:
|
|
@@ -12,7 +10,7 @@ services:
|
|
|
12
10
|
- SIMULATOR_PORT=9000
|
|
13
11
|
- SIMULATOR_LOG_LEVEL=info
|
|
14
12
|
healthcheck:
|
|
15
|
-
test: ["CMD", "curl", "-f", "http://localhost:9000/sim/
|
|
13
|
+
test: ["CMD", "curl", "-f", "http://localhost:9000/sim/status"]
|
|
16
14
|
interval: 10s
|
|
17
15
|
timeout: 5s
|
|
18
16
|
retries: 3
|
|
@@ -36,12 +36,13 @@ dev = [
|
|
|
36
36
|
'litestar[testing]',
|
|
37
37
|
'respx>=0.21.0',
|
|
38
38
|
"playwright>=1.40.0",
|
|
39
|
-
'python-getpaid-
|
|
40
|
-
'python-getpaid-
|
|
39
|
+
'python-getpaid-core>=3.0.0a4',
|
|
40
|
+
'python-getpaid-payu>=3.0.0a4',
|
|
41
|
+
'python-getpaid-paynow>=3.0.0a4',
|
|
41
42
|
]
|
|
42
43
|
e2e = [
|
|
43
44
|
{include-group = "dev"},
|
|
44
|
-
'python-getpaid-core>=3.0.
|
|
45
|
+
'python-getpaid-core>=3.0.0a4',
|
|
45
46
|
'python-getpaid-payu',
|
|
46
47
|
'python-getpaid-paynow',
|
|
47
48
|
]
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/app.py
RENAMED
|
@@ -9,6 +9,7 @@ from litestar import Litestar
|
|
|
9
9
|
from litestar import get
|
|
10
10
|
from litestar.contrib.jinja import JinjaTemplateEngine
|
|
11
11
|
from litestar.datastructures import State
|
|
12
|
+
from litestar.static_files import create_static_files_router
|
|
12
13
|
from litestar.template.config import TemplateConfig
|
|
13
14
|
|
|
14
15
|
from getpaid_simulator.core.config import SimulatorConfig
|
|
@@ -115,9 +116,13 @@ def create_app(
|
|
|
115
116
|
"invalid_transition_error": InvalidTransitionError,
|
|
116
117
|
}
|
|
117
118
|
)
|
|
119
|
+
static_files_router = create_static_files_router(
|
|
120
|
+
path="/static",
|
|
121
|
+
directories=[Path(__file__).parent / "ui" / "static"],
|
|
122
|
+
)
|
|
118
123
|
|
|
119
124
|
return Litestar(
|
|
120
|
-
route_handlers=route_handlers,
|
|
125
|
+
route_handlers=[*route_handlers, static_files_router],
|
|
121
126
|
state=state,
|
|
122
127
|
template_config=TemplateConfig(
|
|
123
128
|
engine=JinjaTemplateEngine(
|
|
@@ -125,6 +130,3 @@ def create_app(
|
|
|
125
130
|
)
|
|
126
131
|
),
|
|
127
132
|
)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
app = create_app()
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
from decimal import InvalidOperation
|
|
3
|
+
from typing import Any
|
|
1
4
|
from typing import Optional
|
|
2
5
|
|
|
3
6
|
from litestar import get
|
|
@@ -9,6 +12,43 @@ from getpaid_simulator.plugins import ProviderLoadFailure
|
|
|
9
12
|
from getpaid_simulator.spi import SimulatorProviderPlugin
|
|
10
13
|
|
|
11
14
|
|
|
15
|
+
def _format_amount_for_display(
|
|
16
|
+
order: dict[str, Any],
|
|
17
|
+
provider_config: dict[str, Any] | None,
|
|
18
|
+
) -> str:
|
|
19
|
+
amount_raw = order.get("amount", order.get("totalAmount", 0))
|
|
20
|
+
currency = str(order.get("currency", order.get("currencyCode", "PLN")))
|
|
21
|
+
try:
|
|
22
|
+
amount_value = Decimal(str(amount_raw))
|
|
23
|
+
except (InvalidOperation, TypeError, ValueError):
|
|
24
|
+
return str(amount_raw)
|
|
25
|
+
|
|
26
|
+
minor_unit_places = _minor_unit_places(provider_config)
|
|
27
|
+
if minor_unit_places is not None:
|
|
28
|
+
amount_value /= Decimal(10) ** minor_unit_places
|
|
29
|
+
|
|
30
|
+
return f"{amount_value:.2f} {currency}"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _minor_unit_places(provider_config: dict[str, Any] | None) -> int | None:
|
|
34
|
+
if provider_config is None:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
raw_value = provider_config.get("amount_minor_unit_places")
|
|
38
|
+
if raw_value is None:
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
places = int(raw_value)
|
|
43
|
+
except (TypeError, ValueError):
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
if places < 0:
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
return places
|
|
50
|
+
|
|
51
|
+
|
|
12
52
|
@get(["/sim/", "/sim/dashboard"])
|
|
13
53
|
async def dashboard(state: State, provider: Optional[str] = None) -> Template:
|
|
14
54
|
"""Render payments dashboard."""
|
|
@@ -30,16 +70,9 @@ async def dashboard(state: State, provider: Optional[str] = None) -> Template:
|
|
|
30
70
|
|
|
31
71
|
orders = []
|
|
32
72
|
for order in orders_data:
|
|
33
|
-
amount_raw = order.get("amount", order.get("totalAmount", 0))
|
|
34
|
-
currency = order.get("currency", order.get("currencyCode", "PLN"))
|
|
35
|
-
try:
|
|
36
|
-
val = float(amount_raw) / 100
|
|
37
|
-
formatted = f"{val:.2f} {currency}"
|
|
38
|
-
except (ValueError, TypeError):
|
|
39
|
-
formatted = str(amount_raw)
|
|
40
|
-
|
|
41
73
|
provider_slug = str(order.get("provider", "unknown"))
|
|
42
74
|
plugin = loaded_plugins.get(provider_slug)
|
|
75
|
+
provider_config = state.provider_configs.get(provider_slug)
|
|
43
76
|
orders.append(
|
|
44
77
|
{
|
|
45
78
|
"id": order["id"],
|
|
@@ -48,7 +81,10 @@ async def dashboard(state: State, provider: Optional[str] = None) -> Template:
|
|
|
48
81
|
plugin.display_name if plugin is not None else provider_slug
|
|
49
82
|
),
|
|
50
83
|
"status": order.get("status", "NEW"),
|
|
51
|
-
"formatted_amount":
|
|
84
|
+
"formatted_amount": _format_amount_for_display(
|
|
85
|
+
order,
|
|
86
|
+
provider_config,
|
|
87
|
+
),
|
|
52
88
|
"authorize_url": (
|
|
53
89
|
plugin.build_authorize_path(str(order["id"]))
|
|
54
90
|
if plugin is not None
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
"""E2E test configuration with Playwright and live server."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import os
|
|
4
5
|
import socket
|
|
5
6
|
from collections.abc import AsyncGenerator
|
|
6
7
|
from typing import Any
|
|
8
|
+
from typing import NotRequired
|
|
9
|
+
from typing import TypedDict
|
|
7
10
|
from urllib.parse import urlsplit
|
|
8
11
|
|
|
9
12
|
import httpx
|
|
@@ -16,6 +19,27 @@ from playwright.async_api import async_playwright
|
|
|
16
19
|
from getpaid_simulator.app import create_app
|
|
17
20
|
|
|
18
21
|
|
|
22
|
+
class ChromiumLaunchKwargs(TypedDict):
|
|
23
|
+
headless: bool
|
|
24
|
+
args: list[str]
|
|
25
|
+
executable_path: NotRequired[str]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_chromium_launch_kwargs() -> ChromiumLaunchKwargs:
|
|
29
|
+
kwargs: ChromiumLaunchKwargs = {
|
|
30
|
+
"headless": True,
|
|
31
|
+
"args": [
|
|
32
|
+
"--no-sandbox",
|
|
33
|
+
"--disable-dev-shm-usage",
|
|
34
|
+
"--disable-gpu",
|
|
35
|
+
],
|
|
36
|
+
}
|
|
37
|
+
executable_path = os.getenv("PLAYWRIGHT_CHROMIUM_EXECUTABLE")
|
|
38
|
+
if executable_path:
|
|
39
|
+
kwargs["executable_path"] = executable_path
|
|
40
|
+
return kwargs
|
|
41
|
+
|
|
42
|
+
|
|
19
43
|
def _find_free_port() -> int:
|
|
20
44
|
"""Find a free port for the test server."""
|
|
21
45
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
@@ -66,17 +90,9 @@ async def live_server() -> AsyncGenerator[str, None]:
|
|
|
66
90
|
|
|
67
91
|
@pytest.fixture
|
|
68
92
|
async def browser() -> AsyncGenerator[Browser, None]:
|
|
69
|
-
"""Playwright browser instance
|
|
93
|
+
"""Playwright browser instance for E2E tests."""
|
|
70
94
|
async with async_playwright() as p:
|
|
71
|
-
browser = await p.chromium.launch(
|
|
72
|
-
headless=True,
|
|
73
|
-
executable_path="/usr/bin/chromium",
|
|
74
|
-
args=[
|
|
75
|
-
"--no-sandbox",
|
|
76
|
-
"--disable-dev-shm-usage",
|
|
77
|
-
"--disable-gpu",
|
|
78
|
-
],
|
|
79
|
-
)
|
|
95
|
+
browser = await p.chromium.launch(**get_chromium_launch_kwargs())
|
|
80
96
|
yield browser
|
|
81
97
|
await browser.close()
|
|
82
98
|
|
|
@@ -158,3 +158,61 @@ async def test_dashboard_renders_dynamic_filters_and_plugin_warning(
|
|
|
158
158
|
body = response.text
|
|
159
159
|
assert "FakePay" in body
|
|
160
160
|
assert "brokenpay" in body
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@pytest.mark.asyncio
|
|
164
|
+
async def test_create_app_serves_static_stylesheet(monkeypatch):
|
|
165
|
+
monkeypatch.setattr(
|
|
166
|
+
app_module,
|
|
167
|
+
"load_provider_plugins",
|
|
168
|
+
lambda config: PluginLoadResult(
|
|
169
|
+
loaded_plugins=(),
|
|
170
|
+
failed_plugins=(),
|
|
171
|
+
provider_configs={},
|
|
172
|
+
),
|
|
173
|
+
)
|
|
174
|
+
app = app_module.create_app()
|
|
175
|
+
|
|
176
|
+
async with AsyncTestClient(app=app) as test_client:
|
|
177
|
+
response = await test_client.get("/static/style.css")
|
|
178
|
+
|
|
179
|
+
assert response.status_code == 200
|
|
180
|
+
assert "text/css" in response.headers["content-type"]
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def test_importing_app_module_does_not_load_plugins(monkeypatch):
|
|
184
|
+
import importlib
|
|
185
|
+
import sys
|
|
186
|
+
|
|
187
|
+
sys.modules.pop("getpaid_simulator.app", None)
|
|
188
|
+
load_calls: list[object] = []
|
|
189
|
+
|
|
190
|
+
def fake_load_provider_plugins(config):
|
|
191
|
+
load_calls.append(config)
|
|
192
|
+
return PluginLoadResult(
|
|
193
|
+
loaded_plugins=(),
|
|
194
|
+
failed_plugins=(),
|
|
195
|
+
provider_configs={},
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
monkeypatch.setattr(
|
|
199
|
+
"getpaid_simulator.plugins.load_provider_plugins",
|
|
200
|
+
fake_load_provider_plugins,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
app_module_reimported = importlib.import_module("getpaid_simulator.app")
|
|
204
|
+
|
|
205
|
+
assert load_calls == []
|
|
206
|
+
app_module_reimported.create_app()
|
|
207
|
+
assert len(load_calls) == 1
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_docker_compose_healthcheck_uses_health_endpoint():
|
|
211
|
+
from pathlib import Path
|
|
212
|
+
|
|
213
|
+
compose_file = Path(__file__).resolve().parents[1] / "docker-compose.yml"
|
|
214
|
+
content = compose_file.read_text()
|
|
215
|
+
|
|
216
|
+
assert 'http://localhost:9000/"' not in content
|
|
217
|
+
assert "http://localhost:9000/sim/dashboard" not in content
|
|
218
|
+
assert "http://localhost:9000/sim/status" in content
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Smoke tests for getpaid-simulator."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import tomllib
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
import getpaid_simulator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_version():
|
|
12
|
+
"""Test that version is accessible."""
|
|
13
|
+
assert getpaid_simulator.__version__ == "3.0.0a4"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_e2e_core_dependency_floor():
|
|
17
|
+
"""E2E dependency group requires the published core alpha."""
|
|
18
|
+
pyproject_data = tomllib.loads(Path("pyproject.toml").read_text())
|
|
19
|
+
assert (
|
|
20
|
+
"python-getpaid-core>=3.0.0a4"
|
|
21
|
+
in pyproject_data["dependency-groups"]["e2e"]
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_dev_provider_dependency_floors():
|
|
26
|
+
"""Simulator dev environment tracks published provider alpha floors."""
|
|
27
|
+
pyproject_data = tomllib.loads(Path("pyproject.toml").read_text())
|
|
28
|
+
dev_dependencies = pyproject_data["dependency-groups"]["dev"]
|
|
29
|
+
assert "python-getpaid-core>=3.0.0a4" in dev_dependencies
|
|
30
|
+
assert "python-getpaid-payu>=3.0.0a4" in dev_dependencies
|
|
31
|
+
assert "python-getpaid-paynow>=3.0.0a4" in dev_dependencies
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.mark.asyncio
|
|
35
|
+
async def test_health_endpoint(test_client):
|
|
36
|
+
"""Test health endpoint returns OK."""
|
|
37
|
+
response = await test_client.get("/")
|
|
38
|
+
assert response.status_code == 200
|
|
39
|
+
body = response.json()
|
|
40
|
+
assert body["service"] == "getpaid-simulator"
|
|
41
|
+
assert body["status"] in {"ok", "degraded"}
|
|
42
|
+
assert isinstance(body["loadedProviders"], list)
|
|
43
|
+
assert isinstance(body["failedProviders"], list)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from tests.e2e.conftest import get_chromium_launch_kwargs
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_compose_test_uses_isolated_services_without_host_ports() -> None:
|
|
10
|
+
content = (REPO_ROOT / "compose.test.yml").read_text()
|
|
11
|
+
|
|
12
|
+
assert "testdb:" in content
|
|
13
|
+
assert "tests:" in content
|
|
14
|
+
assert "dockerfile: getpaid-simulator/Dockerfile.test" in content
|
|
15
|
+
assert "condition: service_healthy" in content
|
|
16
|
+
assert (
|
|
17
|
+
"TEST_DATABASE_URL: postgresql://test_user:test_password@testdb:5432/test_db"
|
|
18
|
+
in content
|
|
19
|
+
)
|
|
20
|
+
assert "ports:" not in content
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_dockerfile_test_installs_e2e_dependencies() -> None:
|
|
24
|
+
content = (REPO_ROOT / "Dockerfile.test").read_text()
|
|
25
|
+
|
|
26
|
+
assert "FROM python:3.12-slim" in content
|
|
27
|
+
assert "COPY getpaid-core/ /app/getpaid-core/" in content
|
|
28
|
+
assert "COPY getpaid-payu/ /app/getpaid-payu/" in content
|
|
29
|
+
assert "COPY getpaid-paynow/ /app/getpaid-paynow/" in content
|
|
30
|
+
assert "COPY getpaid-simulator/ /app/getpaid-simulator/" in content
|
|
31
|
+
assert "uv sync --frozen --group e2e" in content
|
|
32
|
+
assert (
|
|
33
|
+
'ENV PLAYWRIGHT_BROWSERS_PATH="/app/getpaid-simulator/.cache/ms-playwright"'
|
|
34
|
+
in content
|
|
35
|
+
)
|
|
36
|
+
assert "uv run playwright install chromium" in content
|
|
37
|
+
assert content.index("PLAYWRIGHT_BROWSERS_PATH") < content.index(
|
|
38
|
+
"uv run playwright install chromium"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_makefile_exposes_unit_integration_and_e2e_targets() -> None:
|
|
43
|
+
content = (REPO_ROOT / "Makefile").read_text()
|
|
44
|
+
|
|
45
|
+
assert (
|
|
46
|
+
".PHONY: test test-unit test-integration test-e2e test-build test-down"
|
|
47
|
+
in content
|
|
48
|
+
)
|
|
49
|
+
assert "test-unit:" in content
|
|
50
|
+
assert "test-integration:" in content
|
|
51
|
+
assert "test-e2e:" in content
|
|
52
|
+
assert "docker compose -f compose.test.yml run --rm tests" in content
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_dockerfile_specific_ignore_files_keep_only_required_repos() -> None:
|
|
56
|
+
for file_name in (
|
|
57
|
+
"Dockerfile.dockerignore",
|
|
58
|
+
"Dockerfile.test.dockerignore",
|
|
59
|
+
):
|
|
60
|
+
content = (REPO_ROOT / file_name).read_text()
|
|
61
|
+
|
|
62
|
+
assert "**" in content
|
|
63
|
+
assert "!getpaid-core/" in content
|
|
64
|
+
assert "!getpaid-core/**" in content
|
|
65
|
+
assert "!getpaid-payu/" in content
|
|
66
|
+
assert "!getpaid-payu/**" in content
|
|
67
|
+
assert "!getpaid-paynow/" in content
|
|
68
|
+
assert "!getpaid-paynow/**" in content
|
|
69
|
+
assert "!getpaid-simulator/" in content
|
|
70
|
+
assert "!getpaid-simulator/**" in content
|
|
71
|
+
assert "**/.git" in content
|
|
72
|
+
assert "**/.venv" in content
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_chromium_launch_uses_playwright_bundle_by_default(
|
|
76
|
+
monkeypatch,
|
|
77
|
+
) -> None:
|
|
78
|
+
monkeypatch.delenv("PLAYWRIGHT_CHROMIUM_EXECUTABLE", raising=False)
|
|
79
|
+
|
|
80
|
+
kwargs = get_chromium_launch_kwargs()
|
|
81
|
+
|
|
82
|
+
assert kwargs == {
|
|
83
|
+
"headless": True,
|
|
84
|
+
"args": [
|
|
85
|
+
"--no-sandbox",
|
|
86
|
+
"--disable-dev-shm-usage",
|
|
87
|
+
"--disable-gpu",
|
|
88
|
+
],
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_chromium_launch_allows_explicit_executable_override(
|
|
93
|
+
monkeypatch,
|
|
94
|
+
) -> None:
|
|
95
|
+
monkeypatch.setenv(
|
|
96
|
+
"PLAYWRIGHT_CHROMIUM_EXECUTABLE",
|
|
97
|
+
"/usr/bin/chromium",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
kwargs = get_chromium_launch_kwargs()
|
|
101
|
+
|
|
102
|
+
assert kwargs.get("executable_path") == "/usr/bin/chromium"
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_ui_authorize.py
RENAMED
|
@@ -40,6 +40,32 @@ async def test_payu_authorize_get(test_client, simulator_storage):
|
|
|
40
40
|
assert "Reject" in response.text
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
@pytest.mark.asyncio
|
|
44
|
+
async def test_payu_authorize_get_uses_provider_amount_minor_unit_places(
|
|
45
|
+
test_client,
|
|
46
|
+
simulator_storage,
|
|
47
|
+
):
|
|
48
|
+
test_client.app.state.provider_configs["payu"][
|
|
49
|
+
"amount_minor_unit_places"
|
|
50
|
+
] = 0
|
|
51
|
+
order_id = simulator_storage.create_order(
|
|
52
|
+
{
|
|
53
|
+
"provider": "payu",
|
|
54
|
+
"totalAmount": "1000",
|
|
55
|
+
"currencyCode": "PLN",
|
|
56
|
+
"description": "Test order",
|
|
57
|
+
"continueUrl": "https://example.com/continue",
|
|
58
|
+
"notifyUrl": "https://example.com/notify",
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
response = await test_client.get(f"/sim/payu/authorize/{order_id}")
|
|
63
|
+
|
|
64
|
+
assert response.status_code == 200
|
|
65
|
+
assert "1000.00 PLN" in response.text
|
|
66
|
+
assert "10.00 PLN" not in response.text
|
|
67
|
+
|
|
68
|
+
|
|
43
69
|
@pytest.mark.asyncio
|
|
44
70
|
async def test_payu_authorize_get_404(test_client):
|
|
45
71
|
response = await test_client.get("/sim/payu/authorize/non-existent-order")
|
|
@@ -116,6 +142,31 @@ async def test_paynow_authorize_get(test_client, simulator_storage):
|
|
|
116
142
|
assert "PayNow" in response.text
|
|
117
143
|
|
|
118
144
|
|
|
145
|
+
@pytest.mark.asyncio
|
|
146
|
+
async def test_paynow_authorize_get_uses_provider_amount_minor_unit_places(
|
|
147
|
+
test_client,
|
|
148
|
+
simulator_storage,
|
|
149
|
+
):
|
|
150
|
+
test_client.app.state.provider_configs["paynow"][
|
|
151
|
+
"amount_minor_unit_places"
|
|
152
|
+
] = 0
|
|
153
|
+
payment_id = simulator_storage.create_order(
|
|
154
|
+
{
|
|
155
|
+
"provider": "paynow",
|
|
156
|
+
"amount": 1000,
|
|
157
|
+
"currency": "PLN",
|
|
158
|
+
"description": "Test PayNow",
|
|
159
|
+
"continueUrl": "https://example.com/paynow-continue",
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
response = await test_client.get(f"/sim/paynow/authorize/{payment_id}")
|
|
164
|
+
|
|
165
|
+
assert response.status_code == 200
|
|
166
|
+
assert "1000.00 PLN" in response.text
|
|
167
|
+
assert "10.00 PLN" not in response.text
|
|
168
|
+
|
|
169
|
+
|
|
119
170
|
@pytest.mark.asyncio
|
|
120
171
|
async def test_paynow_authorize_post_approve(test_client, simulator_storage):
|
|
121
172
|
payment_id = simulator_storage.create_order(
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_ui_dashboard.py
RENAMED
|
@@ -68,6 +68,45 @@ async def test_dashboard_filter_by_provider(test_client, simulator_storage):
|
|
|
68
68
|
assert f"/sim/payu/authorize/{order1_id}" not in html2
|
|
69
69
|
|
|
70
70
|
|
|
71
|
+
@pytest.mark.asyncio
|
|
72
|
+
async def test_dashboard_uses_provider_amount_minor_unit_places(
|
|
73
|
+
test_client,
|
|
74
|
+
simulator_storage,
|
|
75
|
+
):
|
|
76
|
+
test_client.app.state.provider_configs["payu"][
|
|
77
|
+
"amount_minor_unit_places"
|
|
78
|
+
] = 0
|
|
79
|
+
simulator_storage.create_order(
|
|
80
|
+
{"totalAmount": "1500", "currencyCode": "PLN", "description": "test"},
|
|
81
|
+
provider="payu",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
response = await test_client.get("/sim/dashboard?provider=payu")
|
|
85
|
+
|
|
86
|
+
assert response.status_code == 200
|
|
87
|
+
html = response.text
|
|
88
|
+
assert "1500.00 PLN" in html
|
|
89
|
+
assert "15.00 PLN" not in html
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@pytest.mark.asyncio
|
|
93
|
+
async def test_dashboard_falls_back_to_raw_units_for_unknown_provider(
|
|
94
|
+
test_client,
|
|
95
|
+
simulator_storage,
|
|
96
|
+
):
|
|
97
|
+
simulator_storage.create_order(
|
|
98
|
+
{"amount": "12.50", "currency": "PLN", "description": "custom"},
|
|
99
|
+
provider="custompay",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
response = await test_client.get("/sim/dashboard?provider=custompay")
|
|
103
|
+
|
|
104
|
+
assert response.status_code == 200
|
|
105
|
+
html = response.text
|
|
106
|
+
assert "12.50 PLN" in html
|
|
107
|
+
assert "0.12 PLN" not in html
|
|
108
|
+
|
|
109
|
+
|
|
71
110
|
@pytest.mark.asyncio
|
|
72
111
|
async def test_dashboard_redirects_from_root(test_client, simulator_storage):
|
|
73
112
|
response = await test_client.get("/sim/")
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"""Smoke tests for getpaid-simulator."""
|
|
2
|
-
|
|
3
|
-
import pytest
|
|
4
|
-
|
|
5
|
-
import getpaid_simulator
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def test_version():
|
|
9
|
-
"""Test that version is accessible."""
|
|
10
|
-
assert getpaid_simulator.__version__ == "3.0.0a3"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@pytest.mark.asyncio
|
|
14
|
-
async def test_health_endpoint(test_client):
|
|
15
|
-
"""Test health endpoint returns OK."""
|
|
16
|
-
response = await test_client.get("/")
|
|
17
|
-
assert response.status_code == 200
|
|
18
|
-
body = response.json()
|
|
19
|
-
assert body["service"] == "getpaid-simulator"
|
|
20
|
-
assert body["status"] in {"ok", "degraded"}
|
|
21
|
-
assert isinstance(body["loadedProviders"], list)
|
|
22
|
-
assert isinstance(body["failedProviders"], list)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/src/getpaid_simulator/spi.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_discovery.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_paynow_payments.py
RENAMED
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_paynow_refunds.py
RENAMED
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_paynow_signing.py
RENAMED
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_paynow_webhooks.py
RENAMED
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_lifecycle.py
RENAMED
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_oauth.py
RENAMED
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_orders.py
RENAMED
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_refunds.py
RENAMED
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_payu_webhooks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_getpaid_simulator-3.0.0a3 → python_getpaid_simulator-3.0.0a4}/tests/test_webhooks.py
RENAMED
|
File without changes
|