wgc-runner 4.0.1__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.
- wgc_runner-4.0.1/PKG-INFO +118 -0
- wgc_runner-4.0.1/README.md +96 -0
- wgc_runner-4.0.1/pyproject.toml +39 -0
- wgc_runner-4.0.1/setup.cfg +4 -0
- wgc_runner-4.0.1/src/wgc_runner/__init__.py +1 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/__init__.py +5 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/allure.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/arsenal_fixtures.py +392 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/autouse_fixtures.py +47 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/browser.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/cmd_helper.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/config.py +15 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/dgbdiag.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/encrypt.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/event_listener.py +23 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/fake_games.py +17 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/firewall.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/log.py +15 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/os.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/registry.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/screen.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/soft_assert.py +22 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/ui_map_parser.py +16 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/wgc_client.py +15 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/wgc_installer.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/wgc_settings.py +15 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/wgc_uninstaller.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/wgni_users_db.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/fixtures/wnc.py +12 -0
- wgc_runner-4.0.1/src/wgc_runner/plugin.py +1128 -0
- wgc_runner-4.0.1/src/wgc_runner/scripts.py +105 -0
- wgc_runner-4.0.1/src/wgc_runner.egg-info/PKG-INFO +118 -0
- wgc_runner-4.0.1/src/wgc_runner.egg-info/SOURCES.txt +35 -0
- wgc_runner-4.0.1/src/wgc_runner.egg-info/dependency_links.txt +1 -0
- wgc_runner-4.0.1/src/wgc_runner.egg-info/entry_points.txt +2 -0
- wgc_runner-4.0.1/src/wgc_runner.egg-info/requires.txt +10 -0
- wgc_runner-4.0.1/src/wgc_runner.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wgc-runner
|
|
3
|
+
Version: 4.0.1
|
|
4
|
+
Summary: Pytest plugin and fixtures for WGC QA framework
|
|
5
|
+
Author-email: Mykola Kovhanko <thuesdays@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/thuesdays/wgc-runner
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
9
|
+
Classifier: Framework :: Pytest
|
|
10
|
+
Requires-Python: >=3.7
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: wgc-pages>=4.0.0
|
|
13
|
+
Requires-Dist: wgc-client>=4.0.0
|
|
14
|
+
Requires-Dist: wgc-mocks>=4.0.0
|
|
15
|
+
Requires-Dist: wgc-helpers>=4.0.0
|
|
16
|
+
Requires-Dist: wgc-core>=4.0.0
|
|
17
|
+
Requires-Dist: wgc-clippy>=1.0.0
|
|
18
|
+
Requires-Dist: wgc-third-party>=1.0.0
|
|
19
|
+
Requires-Dist: pytest>=7.0
|
|
20
|
+
Requires-Dist: pytest-timeout==2.3.1
|
|
21
|
+
Requires-Dist: pyhamcrest==2.0.2
|
|
22
|
+
|
|
23
|
+
# wgc-runner
|
|
24
|
+
|
|
25
|
+
Pytest plugin and fixtures for running WGC QA tests. Manages the full test lifecycle: build download, mock server startup, WGC installation, test execution, artifact collection.
|
|
26
|
+
|
|
27
|
+
## Pytest Plugin
|
|
28
|
+
|
|
29
|
+
Registered as `wgc_plugin` via `pytest11` entry point. Activated automatically when installed.
|
|
30
|
+
|
|
31
|
+
### CLI Options
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
py.test tests/ \
|
|
35
|
+
--wgc "\\share\builds\wgc\latest" \
|
|
36
|
+
--wgc-build "12345" \
|
|
37
|
+
--wgc-branch "release/1.0" \
|
|
38
|
+
--wgc-arch "x64" \
|
|
39
|
+
--wgc-publisher "wargaming" \
|
|
40
|
+
--video-capture \
|
|
41
|
+
--no-sanity-check
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Option | Description |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `--wgc` | Path to WGC build on shared drive |
|
|
47
|
+
| `--wgc-build` | Build number |
|
|
48
|
+
| `--wgc-branch` | Git branch |
|
|
49
|
+
| `--wgc-arch` | Architecture: `win32` or `x64` |
|
|
50
|
+
| `--wgc-publisher` | Publisher: `wargaming`, `steam`, `qihoo` |
|
|
51
|
+
| `--video-capture` | Enable screen recording for each test |
|
|
52
|
+
| `--no-sanity-check` | Skip WGC sanity check before test session |
|
|
53
|
+
| `--testrail` | Enable TestRail reporting |
|
|
54
|
+
|
|
55
|
+
### Lifecycle Hooks
|
|
56
|
+
|
|
57
|
+
| Hook | What it does |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `pytest_cmdline_main` | Download WGC build, start mock server, install WGC |
|
|
60
|
+
| `pytest_configure` | Initialize TestRail API, setup config |
|
|
61
|
+
| `pytest_runtest_setup` | Prepare environment before each test |
|
|
62
|
+
| `pytest_runtest_teardown` | Crash detection, collect logs/video/screenshots, terminate WGC |
|
|
63
|
+
| `pytest_collection_modifyitems` | Auto-assign `folder_*` markers by test directory |
|
|
64
|
+
|
|
65
|
+
### Key Features
|
|
66
|
+
|
|
67
|
+
- **Auto build download** from shared drive
|
|
68
|
+
- **Mock server** startup/shutdown around test session
|
|
69
|
+
- **Video recording** — each test recorded via OpenCV
|
|
70
|
+
- **Crash detection** — automatic WGC crash check after every test
|
|
71
|
+
- **Sanity check** — WGC startup verification before test session
|
|
72
|
+
- **Artifact upload** — logs, video, screenshots uploaded to share
|
|
73
|
+
- **Auto markers** — `folder_arsenal_login1`, `folder_game_install2`, etc.
|
|
74
|
+
|
|
75
|
+
## Fixtures
|
|
76
|
+
|
|
77
|
+
All fixtures are session or function-scoped and available automatically:
|
|
78
|
+
|
|
79
|
+
| Fixture | Scope | Provides |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `wgc_client` | session | `WGCClient` instance |
|
|
82
|
+
| `config` | session | `WGCConfig` instance |
|
|
83
|
+
| `wgc_settings` | session | `WGCSettingsHelper` |
|
|
84
|
+
| `fake_games` | session | `FakeGamesHelper` |
|
|
85
|
+
| `os_helper` | session | `OSHelper` |
|
|
86
|
+
| `registry` | session | `RegistryHelper` |
|
|
87
|
+
| `browser` | session | `BrowserHelper` |
|
|
88
|
+
| `screen` | session | `ScreenHelper` |
|
|
89
|
+
| `firewall` | session | `FireWallHelper` |
|
|
90
|
+
| `encrypt` | session | `EncryptHelper` |
|
|
91
|
+
| `cmd_helper` | session | `CmdHelper` |
|
|
92
|
+
| `event_listener` | session | `EventHelper` |
|
|
93
|
+
| `wgc_installer` | session | `WGCInstaller` |
|
|
94
|
+
| `wgc_uninstaller` | session | `WGCUninstaller` |
|
|
95
|
+
| `soft_assert` | function | `SoftAssert` |
|
|
96
|
+
| `wgni_users_db` | session | `WGNIUsersDB` |
|
|
97
|
+
|
|
98
|
+
### Arsenal Fixtures
|
|
99
|
+
|
|
100
|
+
Additional fixtures for Arsenal UI tests (shop, products, billing):
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
def test_buy_item(arsenal_shop_page, arsenal_product_list):
|
|
104
|
+
# arsenal_shop_page and arsenal_product_list are auto-configured
|
|
105
|
+
arsenal_shop_page.open_product(arsenal_product_list[0])
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Install
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pip install wgc-runner
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This will pull all WGC packages transitively.
|
|
115
|
+
|
|
116
|
+
## Dependencies
|
|
117
|
+
|
|
118
|
+
All WGC packages + `pytest>=7.0`, `pytest-timeout`, `pyhamcrest`
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# wgc-runner
|
|
2
|
+
|
|
3
|
+
Pytest plugin and fixtures for running WGC QA tests. Manages the full test lifecycle: build download, mock server startup, WGC installation, test execution, artifact collection.
|
|
4
|
+
|
|
5
|
+
## Pytest Plugin
|
|
6
|
+
|
|
7
|
+
Registered as `wgc_plugin` via `pytest11` entry point. Activated automatically when installed.
|
|
8
|
+
|
|
9
|
+
### CLI Options
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
py.test tests/ \
|
|
13
|
+
--wgc "\\share\builds\wgc\latest" \
|
|
14
|
+
--wgc-build "12345" \
|
|
15
|
+
--wgc-branch "release/1.0" \
|
|
16
|
+
--wgc-arch "x64" \
|
|
17
|
+
--wgc-publisher "wargaming" \
|
|
18
|
+
--video-capture \
|
|
19
|
+
--no-sanity-check
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Option | Description |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `--wgc` | Path to WGC build on shared drive |
|
|
25
|
+
| `--wgc-build` | Build number |
|
|
26
|
+
| `--wgc-branch` | Git branch |
|
|
27
|
+
| `--wgc-arch` | Architecture: `win32` or `x64` |
|
|
28
|
+
| `--wgc-publisher` | Publisher: `wargaming`, `steam`, `qihoo` |
|
|
29
|
+
| `--video-capture` | Enable screen recording for each test |
|
|
30
|
+
| `--no-sanity-check` | Skip WGC sanity check before test session |
|
|
31
|
+
| `--testrail` | Enable TestRail reporting |
|
|
32
|
+
|
|
33
|
+
### Lifecycle Hooks
|
|
34
|
+
|
|
35
|
+
| Hook | What it does |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `pytest_cmdline_main` | Download WGC build, start mock server, install WGC |
|
|
38
|
+
| `pytest_configure` | Initialize TestRail API, setup config |
|
|
39
|
+
| `pytest_runtest_setup` | Prepare environment before each test |
|
|
40
|
+
| `pytest_runtest_teardown` | Crash detection, collect logs/video/screenshots, terminate WGC |
|
|
41
|
+
| `pytest_collection_modifyitems` | Auto-assign `folder_*` markers by test directory |
|
|
42
|
+
|
|
43
|
+
### Key Features
|
|
44
|
+
|
|
45
|
+
- **Auto build download** from shared drive
|
|
46
|
+
- **Mock server** startup/shutdown around test session
|
|
47
|
+
- **Video recording** — each test recorded via OpenCV
|
|
48
|
+
- **Crash detection** — automatic WGC crash check after every test
|
|
49
|
+
- **Sanity check** — WGC startup verification before test session
|
|
50
|
+
- **Artifact upload** — logs, video, screenshots uploaded to share
|
|
51
|
+
- **Auto markers** — `folder_arsenal_login1`, `folder_game_install2`, etc.
|
|
52
|
+
|
|
53
|
+
## Fixtures
|
|
54
|
+
|
|
55
|
+
All fixtures are session or function-scoped and available automatically:
|
|
56
|
+
|
|
57
|
+
| Fixture | Scope | Provides |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `wgc_client` | session | `WGCClient` instance |
|
|
60
|
+
| `config` | session | `WGCConfig` instance |
|
|
61
|
+
| `wgc_settings` | session | `WGCSettingsHelper` |
|
|
62
|
+
| `fake_games` | session | `FakeGamesHelper` |
|
|
63
|
+
| `os_helper` | session | `OSHelper` |
|
|
64
|
+
| `registry` | session | `RegistryHelper` |
|
|
65
|
+
| `browser` | session | `BrowserHelper` |
|
|
66
|
+
| `screen` | session | `ScreenHelper` |
|
|
67
|
+
| `firewall` | session | `FireWallHelper` |
|
|
68
|
+
| `encrypt` | session | `EncryptHelper` |
|
|
69
|
+
| `cmd_helper` | session | `CmdHelper` |
|
|
70
|
+
| `event_listener` | session | `EventHelper` |
|
|
71
|
+
| `wgc_installer` | session | `WGCInstaller` |
|
|
72
|
+
| `wgc_uninstaller` | session | `WGCUninstaller` |
|
|
73
|
+
| `soft_assert` | function | `SoftAssert` |
|
|
74
|
+
| `wgni_users_db` | session | `WGNIUsersDB` |
|
|
75
|
+
|
|
76
|
+
### Arsenal Fixtures
|
|
77
|
+
|
|
78
|
+
Additional fixtures for Arsenal UI tests (shop, products, billing):
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
def test_buy_item(arsenal_shop_page, arsenal_product_list):
|
|
82
|
+
# arsenal_shop_page and arsenal_product_list are auto-configured
|
|
83
|
+
arsenal_shop_page.open_product(arsenal_product_list[0])
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Install
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install wgc-runner
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This will pull all WGC packages transitively.
|
|
93
|
+
|
|
94
|
+
## Dependencies
|
|
95
|
+
|
|
96
|
+
All WGC packages + `pytest>=7.0`, `pytest-timeout`, `pyhamcrest`
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "wgc-runner"
|
|
7
|
+
version = "4.0.1"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Mykola Kovhanko", email="thuesdays@gmail.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "Pytest plugin and fixtures for WGC QA framework"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.7"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Operating System :: Microsoft :: Windows",
|
|
17
|
+
"Framework :: Pytest",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"wgc-pages>=4.0.0",
|
|
21
|
+
"wgc-client>=4.0.0",
|
|
22
|
+
"wgc-mocks>=4.0.0",
|
|
23
|
+
"wgc-helpers>=4.0.0",
|
|
24
|
+
"wgc-core>=4.0.0",
|
|
25
|
+
"wgc-clippy>=1.0.0",
|
|
26
|
+
"wgc-third-party>=1.0.0",
|
|
27
|
+
"pytest>=7.0",
|
|
28
|
+
"pytest-timeout==2.3.1",
|
|
29
|
+
"pyhamcrest==2.0.2",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.entry-points.pytest11]
|
|
33
|
+
wgc_plugin = "wgc_runner.plugin:WGCRunnerPlugin"
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
"Homepage" = "https://github.com/thuesdays/wgc-runner"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
where = ["src"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Shared fixtures for Arsenal test suites (buy_items1, buy_items2, etc.).
|
|
5
|
+
|
|
6
|
+
Usage in conftest.py of each test suite:
|
|
7
|
+
from wgc_runner.fixtures.arsenal_fixtures import *
|
|
8
|
+
|
|
9
|
+
This eliminates fixture duplication across multiple arsenal test directories.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__author__ = 'n_kovganko@wargaming.net'
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import pytest
|
|
16
|
+
from os import path
|
|
17
|
+
|
|
18
|
+
from aiohttp import web
|
|
19
|
+
from hamcrest import assert_that, equal_to, has_length, is_not, empty
|
|
20
|
+
|
|
21
|
+
from wgc_helpers.waiter import Waiter
|
|
22
|
+
from wgc_mocks import GameMocks
|
|
23
|
+
from wgc_mocks.wgcps.commerce_fetch_product_list_personal import CommerceFetchProductListPersonal
|
|
24
|
+
from wgc_mocks.wgcps.fetch_client_payment_methods import FetchClientPaymentMethods
|
|
25
|
+
from wgc_mocks.wgcps.fetch_storefront_categories_v2 import CommerceFetchStorefrontCategoriesV2
|
|
26
|
+
from wgc_mocks.wgcps.fetch_storefront_categories_v7 import CommerceFetchStorefrontCategoriesV7
|
|
27
|
+
from wgc_mocks.wgcps.get_account_tsv_method import GetAccountTsvMethod
|
|
28
|
+
from wgc_mocks.wgcps.get_game_page_category import GetGamePageCategory
|
|
29
|
+
from wgc_mocks.wgcps.get_geo_data import GetGeoData
|
|
30
|
+
from wgc_mocks.wgcps.purchase_product_commit import PurchaseProductCommit
|
|
31
|
+
from wgc_mocks.wgcps.purchase_product_prepare import PurchaseProductPrepare
|
|
32
|
+
from wgc_mocks.wgcps.purchase_zero_product_prepare import PurchaseZeroProductPrepare
|
|
33
|
+
from wgc_mocks.wgcps.set_billing_address import SetBillingAddress
|
|
34
|
+
from wgc_mocks.wgni.methods.account import AccountInfoV3
|
|
35
|
+
from wgc_pages import PageArsenalCommon, PageArsenalInstalledGame, PageArsenalProfile
|
|
36
|
+
from wgc_pages.page_arsenal_shop import PageArsenalShop
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# ============================================================================
|
|
40
|
+
# Error Fixture Factory
|
|
41
|
+
# ============================================================================
|
|
42
|
+
|
|
43
|
+
def _make_error_fixture(target_cls, status, response_body):
|
|
44
|
+
"""
|
|
45
|
+
Factory for creating mock error fixtures.
|
|
46
|
+
|
|
47
|
+
Creates a pytest fixture that patches target_cls._on_post to return
|
|
48
|
+
a fixed error response, and restores the original after the test.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
target_cls: The mock class whose _on_post will be patched.
|
|
52
|
+
status: HTTP status code to return.
|
|
53
|
+
response_body: dict to return as JSON response.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
A pytest fixture function.
|
|
57
|
+
"""
|
|
58
|
+
@pytest.fixture
|
|
59
|
+
def _fixture():
|
|
60
|
+
original = target_cls._on_post
|
|
61
|
+
|
|
62
|
+
async def error_handler(ins):
|
|
63
|
+
return web.json_response(response_body, status=status)
|
|
64
|
+
|
|
65
|
+
target_cls._on_post = error_handler
|
|
66
|
+
yield original
|
|
67
|
+
target_cls._on_post = original
|
|
68
|
+
|
|
69
|
+
return _fixture
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _make_platform_error_fixture(target_cls, result_code, status=500):
|
|
73
|
+
"""
|
|
74
|
+
Factory for platform_error-type fixtures.
|
|
75
|
+
|
|
76
|
+
Creates a fixture that returns a standardized WGCPS platform error
|
|
77
|
+
with the specified result_code.
|
|
78
|
+
"""
|
|
79
|
+
return _make_error_fixture(target_cls, status, {
|
|
80
|
+
"status": "error",
|
|
81
|
+
"data": {
|
|
82
|
+
"header": {
|
|
83
|
+
"message-id": "c6976f5b-61d9-4407-9637-b926d00cb1e6",
|
|
84
|
+
"tracking-id": "cf9ffc0b-a6a6-46f9-ab20-67eeb43d9a36"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"errors": [{
|
|
88
|
+
"code": "platform_error",
|
|
89
|
+
"context": {"result_code": result_code}
|
|
90
|
+
}]
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ============================================================================
|
|
95
|
+
# Standard error body constants
|
|
96
|
+
# ============================================================================
|
|
97
|
+
|
|
98
|
+
UNAUTHORIZED_BODY = {'status': 'error', 'errors': [{'code': 'unauthorized'}]}
|
|
99
|
+
|
|
100
|
+
INTERNAL_ERROR_BODY = {"status": "error", "errors": [{
|
|
101
|
+
"code": "platform_error", "context": {"result_code": "INTERNAL_ERROR"}}]}
|
|
102
|
+
|
|
103
|
+
PAYMENT_NOT_EXIST_BODY = {"status": "error", "errors": [{
|
|
104
|
+
"code": "platform_error", "context": {"result_code": "PAYMENT_METHOD_DOESNOT_EXIST"}}]}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# ============================================================================
|
|
108
|
+
# 401 Unauthorized fixtures (generated via factory)
|
|
109
|
+
# ============================================================================
|
|
110
|
+
|
|
111
|
+
error_401_commerce_info = _make_error_fixture(
|
|
112
|
+
GetAccountTsvMethod, 401, UNAUTHORIZED_BODY)
|
|
113
|
+
|
|
114
|
+
error_401_prepare_purchase = _make_error_fixture(
|
|
115
|
+
PurchaseProductPrepare, 401, UNAUTHORIZED_BODY)
|
|
116
|
+
|
|
117
|
+
error_401_commit_purchase = _make_error_fixture(
|
|
118
|
+
PurchaseProductCommit, 401, UNAUTHORIZED_BODY)
|
|
119
|
+
|
|
120
|
+
error_401_geo_data = _make_error_fixture(
|
|
121
|
+
GetGeoData, 401, UNAUTHORIZED_BODY)
|
|
122
|
+
|
|
123
|
+
error_401_set_billing = _make_error_fixture(
|
|
124
|
+
SetBillingAddress, 401, UNAUTHORIZED_BODY)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# ============================================================================
|
|
128
|
+
# 500 Platform Error fixtures (generated via factory)
|
|
129
|
+
# ============================================================================
|
|
130
|
+
|
|
131
|
+
invalid_otp = _make_platform_error_fixture(
|
|
132
|
+
PurchaseProductCommit, 'TSV_INVALID_OTP_CODE')
|
|
133
|
+
|
|
134
|
+
# Alias for backward compatibility (identical to invalid_otp)
|
|
135
|
+
banner_error_otp = _make_platform_error_fixture(
|
|
136
|
+
PurchaseProductCommit, 'TSV_INVALID_OTP_CODE')
|
|
137
|
+
|
|
138
|
+
user_profile_not_completed = _make_platform_error_fixture(
|
|
139
|
+
PurchaseProductPrepare, 'USER_PROFILE_NOT_COMPLETED')
|
|
140
|
+
|
|
141
|
+
order_error = _make_platform_error_fixture(
|
|
142
|
+
PurchaseProductCommit, 'ORDER_PROCESSING_ERROR')
|
|
143
|
+
|
|
144
|
+
payment_method_not_exist = _make_error_fixture(
|
|
145
|
+
FetchClientPaymentMethods, 500, PAYMENT_NOT_EXIST_BODY)
|
|
146
|
+
|
|
147
|
+
prepare_zero_500 = _make_error_fixture(
|
|
148
|
+
PurchaseZeroProductPrepare, 500, INTERNAL_ERROR_BODY)
|
|
149
|
+
|
|
150
|
+
prepare_zero_401 = _make_error_fixture(
|
|
151
|
+
PurchaseZeroProductPrepare, 401, UNAUTHORIZED_BODY)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# ============================================================================
|
|
155
|
+
# get_game_page_category_500 — specific to buy_items2 but kept here for sharing
|
|
156
|
+
# ============================================================================
|
|
157
|
+
|
|
158
|
+
@pytest.fixture
|
|
159
|
+
def get_game_page_category_500():
|
|
160
|
+
on_post = GetGamePageCategory._on_post
|
|
161
|
+
|
|
162
|
+
async def new_on_post(ins):
|
|
163
|
+
await asyncio.sleep(4)
|
|
164
|
+
return web.json_response(
|
|
165
|
+
{"status": "error", "errors": [{"code": "retry", "context": {"interval": 5}}]},
|
|
166
|
+
status=500)
|
|
167
|
+
|
|
168
|
+
GetGamePageCategory._on_post = new_on_post
|
|
169
|
+
yield on_post
|
|
170
|
+
GetGamePageCategory._on_post = on_post
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
# ============================================================================
|
|
174
|
+
# Restore fixtures
|
|
175
|
+
# ============================================================================
|
|
176
|
+
|
|
177
|
+
@pytest.fixture
|
|
178
|
+
def restore_prepare():
|
|
179
|
+
"""Saves and restores PurchaseProductPrepare._on_post."""
|
|
180
|
+
on_post = PurchaseProductPrepare._on_post
|
|
181
|
+
yield on_post
|
|
182
|
+
PurchaseProductPrepare._on_post = on_post
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@pytest.fixture
|
|
186
|
+
def restore():
|
|
187
|
+
"""
|
|
188
|
+
Comprehensive restore fixture covering all commonly patched handlers.
|
|
189
|
+
|
|
190
|
+
Saves original handlers and restores them after the test.
|
|
191
|
+
Yields tuple: (getAccountTsvMethod, preparePurchase, commitPurchase)
|
|
192
|
+
for backward compatibility with existing tests.
|
|
193
|
+
"""
|
|
194
|
+
getAccountTsvMethod = GetAccountTsvMethod._on_post
|
|
195
|
+
preparePurchase = PurchaseProductPrepare._on_post
|
|
196
|
+
commitPurchase = PurchaseProductCommit._on_post
|
|
197
|
+
page_category = GetGamePageCategory._on_post
|
|
198
|
+
default_info = AccountInfoV3._on_post
|
|
199
|
+
def_billing = SetBillingAddress._on_post
|
|
200
|
+
fetch_categories_v2 = CommerceFetchStorefrontCategoriesV2._on_post
|
|
201
|
+
fetch_categories_v7 = CommerceFetchStorefrontCategoriesV7._on_post
|
|
202
|
+
fetch_products = CommerceFetchProductListPersonal._on_post
|
|
203
|
+
|
|
204
|
+
yield getAccountTsvMethod, preparePurchase, commitPurchase
|
|
205
|
+
|
|
206
|
+
GetAccountTsvMethod._on_post = getAccountTsvMethod
|
|
207
|
+
PurchaseProductPrepare._on_post = preparePurchase
|
|
208
|
+
PurchaseProductCommit._on_post = commitPurchase
|
|
209
|
+
GetGamePageCategory._on_post = page_category
|
|
210
|
+
AccountInfoV3._on_post = default_info
|
|
211
|
+
SetBillingAddress._on_post = def_billing
|
|
212
|
+
CommerceFetchStorefrontCategoriesV2._on_post = fetch_categories_v2
|
|
213
|
+
CommerceFetchStorefrontCategoriesV7._on_post = fetch_categories_v7
|
|
214
|
+
CommerceFetchProductListPersonal._on_post = fetch_products
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# ============================================================================
|
|
218
|
+
# Helper class for shared test setup and assertion patterns
|
|
219
|
+
# ============================================================================
|
|
220
|
+
|
|
221
|
+
class ArsenalTestHelpers:
|
|
222
|
+
"""
|
|
223
|
+
Shared setup and assertion helpers for Arsenal tests.
|
|
224
|
+
|
|
225
|
+
Eliminates duplicated setup blocks and assertion patterns
|
|
226
|
+
across test files.
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
@staticmethod
|
|
230
|
+
def setup_standard_product(wgni_users_db, account, count=1, **kwargs):
|
|
231
|
+
"""
|
|
232
|
+
Creates standard buy products + entitlements.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
wgni_users_db: Users DB fixture.
|
|
236
|
+
account: Account object.
|
|
237
|
+
count: Number of products to create.
|
|
238
|
+
**kwargs: Additional product params (price_type, limited_quantity, etc.)
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
list: Created product objects.
|
|
242
|
+
"""
|
|
243
|
+
products = []
|
|
244
|
+
defaults = dict(
|
|
245
|
+
buy_item=True,
|
|
246
|
+
title_code=GameMocks.title_id,
|
|
247
|
+
product_code='BUY_WOT_ITEM'
|
|
248
|
+
)
|
|
249
|
+
defaults.update(kwargs)
|
|
250
|
+
|
|
251
|
+
for i in range(count):
|
|
252
|
+
name = kwargs.get('name', f'World of {i} tanks')
|
|
253
|
+
lang = kwargs.get('lang', 'en')
|
|
254
|
+
app_id = kwargs.get('app_id', 'WOT.RU.PRODUCTION')
|
|
255
|
+
|
|
256
|
+
product = wgni_users_db.add_product(
|
|
257
|
+
name, lang, app_id,
|
|
258
|
+
GameMocks.game_update_url,
|
|
259
|
+
**{k: v for k, v in defaults.items()
|
|
260
|
+
if k not in ('name', 'lang', 'app_id')})
|
|
261
|
+
products.append(product)
|
|
262
|
+
|
|
263
|
+
storefront = kwargs.get('storefront_name', None)
|
|
264
|
+
wgni_users_db.add_entitlements(
|
|
265
|
+
account.id, 'shop', product.link_id,
|
|
266
|
+
GameMocks.title_id, storefront)
|
|
267
|
+
|
|
268
|
+
return products
|
|
269
|
+
|
|
270
|
+
@staticmethod
|
|
271
|
+
def setup_billing(wgni_users_db, applicable=True, mandatory=False,
|
|
272
|
+
available=True):
|
|
273
|
+
"""
|
|
274
|
+
Configures billing settings.
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
wgni_users_db: Users DB fixture.
|
|
278
|
+
applicable: Whether billing is applicable.
|
|
279
|
+
mandatory: Whether billing is mandatory.
|
|
280
|
+
available: Whether billing info is available.
|
|
281
|
+
"""
|
|
282
|
+
wgni_users_db.billing_info_available = available
|
|
283
|
+
wgni_users_db.billing_applicable = applicable
|
|
284
|
+
wgni_users_db.billing_mandatory = mandatory
|
|
285
|
+
|
|
286
|
+
@staticmethod
|
|
287
|
+
def launch_and_open_premium_shop(wgc_client, fake_games, os_helper,
|
|
288
|
+
account, game_path):
|
|
289
|
+
"""
|
|
290
|
+
Standard flow: launch WGC → select game → verify login →
|
|
291
|
+
play → wait for game → open storefront.
|
|
292
|
+
|
|
293
|
+
This is the repetitive ~30-line setup block that appears
|
|
294
|
+
in 20+ tests in test_arsenal_premium_shop.py.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
wgc_client: WGC client fixture.
|
|
298
|
+
fake_games: Fake games fixture.
|
|
299
|
+
os_helper: OS helper fixture.
|
|
300
|
+
account: Account object.
|
|
301
|
+
game_path: Path to the fake game directory.
|
|
302
|
+
"""
|
|
303
|
+
wgc_client.create_user_info(account)
|
|
304
|
+
wgc_client.run_game_center()
|
|
305
|
+
PageArsenalCommon.select_game_page('WOT')
|
|
306
|
+
PageArsenalCommon.open_user_profile_page()
|
|
307
|
+
Waiter.poll(20, PageArsenalProfile.is_account_balance_loaded,
|
|
308
|
+
'Expected that shown account balance.')
|
|
309
|
+
Waiter.poll(3, PageArsenalProfile.is_username_in_profile_displayed,
|
|
310
|
+
'Expected that User is logged in.')
|
|
311
|
+
PageArsenalCommon.close_dialog()
|
|
312
|
+
PageArsenalInstalledGame.click_play()
|
|
313
|
+
Waiter.poll(20, fake_games.is_fake_game_running,
|
|
314
|
+
'Expected that dummy game will be running.')
|
|
315
|
+
Waiter.poll(15, lambda: 'StoreRememberMeToken return WG_S_OK' in
|
|
316
|
+
os_helper.get_file_content(
|
|
317
|
+
path.join(game_path, 'dummy_game.log')),
|
|
318
|
+
'Expected that game has been launched.')
|
|
319
|
+
assert_that(fake_games.start_dummy(
|
|
320
|
+
game_path, copy_exe=False,
|
|
321
|
+
params=' --open-storefront',
|
|
322
|
+
wait_return_code=True), equal_to('WG_S_OK'))
|
|
323
|
+
Waiter.poll(10, PageArsenalShop.is_storefront_displayed,
|
|
324
|
+
'Expected that storefront is displayed.')
|
|
325
|
+
|
|
326
|
+
@staticmethod
|
|
327
|
+
def standard_purchase_flow(product_code, select_method=0):
|
|
328
|
+
"""
|
|
329
|
+
Performs the standard purchase flow:
|
|
330
|
+
click item → payment page → select method → continue → continue(confirm).
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
product_code: Product code to purchase.
|
|
334
|
+
select_method: Index of payment method to select (default 0).
|
|
335
|
+
"""
|
|
336
|
+
PageArsenalShop.click_purchase_item_in_storefront(product_code)
|
|
337
|
+
Waiter.poll(7, PageArsenalShop.is_payment_page_displayed,
|
|
338
|
+
'Expected that opened payment page.')
|
|
339
|
+
PageArsenalShop.select_payment_method(select_method)
|
|
340
|
+
PageArsenalShop.click_continue_or_purchase()
|
|
341
|
+
Waiter.poll(7, PageArsenalShop.is_payment_page_displayed)
|
|
342
|
+
PageArsenalShop.click_continue_or_purchase()
|
|
343
|
+
|
|
344
|
+
@staticmethod
|
|
345
|
+
def assert_choose_product_stats(soft_assert=None, expected_count=1,
|
|
346
|
+
redirected=False, result='success',
|
|
347
|
+
game_app_id='WOT.RU.PRODUCTION'):
|
|
348
|
+
"""
|
|
349
|
+
Asserts wgc_choose_game_product_v1 statistics request.
|
|
350
|
+
|
|
351
|
+
With soft_assert: records non-fatal failures.
|
|
352
|
+
Without soft_assert: uses hard assert_that.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
soft_assert: Optional SoftAssert instance for soft checks.
|
|
356
|
+
expected_count: Expected number of requests.
|
|
357
|
+
redirected: Expected redirected_to_web value.
|
|
358
|
+
result: Expected result value.
|
|
359
|
+
game_app_id: Expected game_app_id value.
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
list: Found requests.
|
|
363
|
+
"""
|
|
364
|
+
requests = Waiter.poll(3, lambda: GameMocks.find_requests(
|
|
365
|
+
'/statistic/v2/wgc_choose_game_product_v1'))
|
|
366
|
+
|
|
367
|
+
if soft_assert:
|
|
368
|
+
soft_assert.check(requests, has_length(expected_count),
|
|
369
|
+
'wgc_choose_game_product_v1 request count')
|
|
370
|
+
if requests:
|
|
371
|
+
body = requests[0].params.get('body')
|
|
372
|
+
soft_assert.check(body.get('product_id'), is_not(empty()),
|
|
373
|
+
'product_id should not be empty')
|
|
374
|
+
soft_assert.check(body.get('redirected_to_web'), equal_to(redirected),
|
|
375
|
+
'redirected_to_web check')
|
|
376
|
+
soft_assert.check(body.get('result'), equal_to(result),
|
|
377
|
+
'result check')
|
|
378
|
+
soft_assert.check(body.get('game_app_id'), equal_to(game_app_id),
|
|
379
|
+
'game_app_id check')
|
|
380
|
+
soft_assert.check(body.get('buy_transaction_id'), is_not(empty()),
|
|
381
|
+
'buy_transaction_id should not be empty')
|
|
382
|
+
else:
|
|
383
|
+
assert_that(requests, has_length(expected_count))
|
|
384
|
+
if requests:
|
|
385
|
+
body = requests[0].params.get('body')
|
|
386
|
+
assert_that(body.get('product_id'), is_not(empty()))
|
|
387
|
+
assert_that(body.get('redirected_to_web'), equal_to(redirected))
|
|
388
|
+
assert_that(body.get('result'), equal_to(result))
|
|
389
|
+
assert_that(body.get('game_app_id'), equal_to(game_app_id))
|
|
390
|
+
assert_that(body.get('buy_transaction_id'), is_not(empty()))
|
|
391
|
+
|
|
392
|
+
return requests
|