cstesting 0.1.0__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.
@@ -0,0 +1,231 @@
1
+ Metadata-Version: 2.4
2
+ Name: cstesting
3
+ Version: 0.1.0
4
+ Summary: Python testing framework — test runner, assertions, API testing, browser automation (EasyTesting/CSTesting port)
5
+ Author: Gorantla Lokesh
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/lokesh771988/EasyTesting
8
+ Project-URL: Repository, https://github.com/lokesh771988/EasyTesting
9
+ Keywords: testing,test-runner,assertions,playwright,automation
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Requires-Python: >=3.8
21
+ Description-Content-Type: text/markdown
22
+ Provides-Extra: browser
23
+ Requires-Dist: playwright>=1.40.0; extra == "browser"
24
+
25
+ # CSTesting (Python)
26
+
27
+ Python port of **CSTesting** — a simple testing framework with a test runner, assertions, API testing, and browser automation (Playwright).
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ # Core only (describe, it, expect, request — no browser)
33
+ pip install -e .
34
+
35
+ # With browser support (Playwright)
36
+ pip install -e ".[browser]"
37
+ playwright install chromium
38
+ ```
39
+
40
+ ## Quick start
41
+
42
+ **1. Create a test file** (e.g. `math_test.py`):
43
+
44
+ ```python
45
+ from cstesting import describe, it, expect
46
+
47
+ def _suite():
48
+ it("adds numbers", lambda: expect(1 + 1).to_be(2))
49
+ it("compares objects", lambda: expect({"a": 1}).to_equal({"a": 1}))
50
+
51
+ describe("Math", _suite)
52
+ ```
53
+
54
+ **2. Run tests:**
55
+
56
+ ```bash
57
+ python -m cstesting
58
+ python -m cstesting "**/*.test.py"
59
+ python -m cstesting tests/
60
+ python -m cstesting example/math_test.py
61
+ ```
62
+
63
+ ## API
64
+
65
+ ### Test structure
66
+
67
+ - **`describe(name, fn)`** — define a suite
68
+ - **`it(name, fn)`** — define a test (sync or async)
69
+ - **`describe.only(name, fn)`** / **`it.only(name, fn)`** — run only this suite/test
70
+ - **`describe.skip(name, fn)`** / **`it.skip(name, fn)`** — skip
71
+
72
+ ### Hooks
73
+
74
+ - **`before_all(fn)`** — run once before all tests in the suite
75
+ - **`after_all(fn)`** — run once after all tests
76
+ - **`beforeEach(fn)`** / **`afterEach(fn)`** — run before/after each test
77
+
78
+ ### Assertions (`expect(value)`)
79
+
80
+ | Matcher | Example |
81
+ |--------|--------|
82
+ | `to_be(expected)` | strict equality |
83
+ | `to_equal(expected)` | deep equality |
84
+ | `to_be_truthy()` / `to_be_falsy()` | boolean |
85
+ | `to_be_null()` / `to_be_defined()` / `to_be_undefined()` | null/defined |
86
+ | `to_throw(message?)` | expect(fn).to_throw() |
87
+ | `to_be_greater_than(n)` / `to_be_less_than(n)` | numbers |
88
+ | `to_contain(item)` | list or string |
89
+ | `to_have_length(n)` | length |
90
+ | `expect(x).not_.to_be(y)` | negate (use `not_` in Python) |
91
+
92
+ ### API testing (Rest-Assured style)
93
+
94
+ ```python
95
+ from cstesting import describe, it, request
96
+
97
+ def _suite():
98
+ it("GET", lambda: (
99
+ request.get("https://api.example.com/users/1")
100
+ .expect_status(200)
101
+ .expect_json("name", "John")
102
+ ))
103
+ it("verifyStatus", lambda: request.verify_status("GET", "https://api.example.com/health", 200))
104
+
105
+ describe("API", _suite)
106
+ ```
107
+
108
+ - **`request.get(url)`**, **`request.post(url, body)`**, **`request.put`**, **`request.patch`**, **`request.delete`**
109
+ - Chain: **`.expect_status(200)`**, **`.expect_header('content-type', pattern)`**, **`.expect_body({})`**, **`.expect_json('path', value)`**
110
+ - **`request.verify_status(method, url, expected_status, body=None)`**
111
+ - **`res.get_response()`** for raw `ApiResponse` (status, headers, body, raw_body)
112
+
113
+ ### Browser automation (optional)
114
+
115
+ Requires: `pip install playwright && playwright install chromium`
116
+
117
+ ```python
118
+ import asyncio
119
+ from cstesting import describe, it, expect, before_all, after_all, create_browser
120
+
121
+ browser = None
122
+
123
+ def _suite():
124
+ def _before():
125
+ global browser
126
+ browser = asyncio.get_event_loop().run_until_complete(create_browser(headless=True))
127
+ def _after():
128
+ global browser
129
+ if browser:
130
+ asyncio.get_event_loop().run_until_complete(browser.close())
131
+
132
+ before_all(_before)
133
+ after_all(_after)
134
+
135
+ async def _test():
136
+ await browser.goto("https://example.com")
137
+ html = await browser.content()
138
+ expect(html).to_contain("Example Domain")
139
+
140
+ it("loads the page", _test)
141
+
142
+ describe("Browser", _suite)
143
+ ```
144
+
145
+ - **`create_browser(headless=True, browser='chromium')`** — async, returns browser API
146
+ - **`browser.goto(url)`**, **`browser.click(selector)`**, **`browser.type(selector, text)`**
147
+ - **`browser.locator(selector)`** → **`.click()`**, **`.type(text)`**, **`.first`**, **`.nth(n)`**
148
+ - **`browser.wait_for_selector(selector)`**, **`browser.content()`**, **`browser.evaluate(expr)`**
149
+ - **`browser.check(selector)`**, **`browser.uncheck(selector)`**, **`browser.select(selector, option)`**
150
+
151
+ ### Config-driven tests
152
+
153
+ Run flows from a `.conf` file without writing code:
154
+
155
+ ```conf
156
+ # Login (one test case)
157
+ headed=true
158
+ goto:https://example.com/login
159
+ username:#email=value:user@test.com
160
+ password:#password=value:secret
161
+ click=button[type="submit"]
162
+ ```
163
+
164
+ ```bash
165
+ python -m cstesting run login.conf
166
+ python -m cstesting login.conf --headed
167
+ ```
168
+
169
+ Programmatic: **`from cstesting import run_config_file; result = run_config_file('login.conf')`**
170
+
171
+ ### Init (Page Object Model)
172
+
173
+ ```bash
174
+ python -m cstesting init
175
+ ```
176
+
177
+ Creates `pages/` and `tests/` with sample HomePage and test.
178
+
179
+ ### Report
180
+
181
+ After a run, an HTML report is written to **`report/report.html`** (searchable, expandable steps, errors).
182
+
183
+ ## Programmatic run
184
+
185
+ ```python
186
+ from cstesting import describe, it, expect, run
187
+
188
+ def _suite():
189
+ it("works", lambda: expect(1).to_be(1))
190
+
191
+ describe("My tests", _suite)
192
+
193
+ result = run()
194
+ print(result) # passed, failed, skipped, total, duration, errors
195
+ ```
196
+
197
+ ## Publish to PyPI
198
+
199
+ 1. **Create accounts** (if needed):
200
+ - [PyPI](https://pypi.org/account/register/)
201
+ - Optional: [Test PyPI](https://test.pypi.org/account/register/) for testing first
202
+
203
+ 2. **Install build tools:**
204
+ ```bash
205
+ python -m pip install build twine
206
+ ```
207
+ (If `pip` or `python` isn’t recognized, use the full path to your Python executable, or on Windows try `py -m pip install build twine`.)
208
+
209
+ 3. **Build the package:**
210
+ ```bash
211
+ python -m build
212
+ ```
213
+ On Windows, if `python` isn’t recognized, use **`py -m build`** instead.
214
+ This creates `dist/cstesting-0.1.0.tar.gz` and a wheel.
215
+
216
+ 4. **Upload to PyPI:**
217
+ ```bash
218
+ twine upload dist/*
219
+ ```
220
+ Use your PyPI username and password (or [API token](https://pypi.org/manage/account/token/)).
221
+
222
+ To try Test PyPI first:
223
+ ```bash
224
+ twine upload --repository testpypi dist/*
225
+ ```
226
+
227
+ 5. **Bump version** in `pyproject.toml` for each new release, then repeat steps 3–4.
228
+
229
+ ## License
230
+
231
+ MIT. Port of [EasyTesting](https://github.com/lokesh771988/EasyTesting) (Node.js) to Python.
@@ -0,0 +1,207 @@
1
+ # CSTesting (Python)
2
+
3
+ Python port of **CSTesting** — a simple testing framework with a test runner, assertions, API testing, and browser automation (Playwright).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ # Core only (describe, it, expect, request — no browser)
9
+ pip install -e .
10
+
11
+ # With browser support (Playwright)
12
+ pip install -e ".[browser]"
13
+ playwright install chromium
14
+ ```
15
+
16
+ ## Quick start
17
+
18
+ **1. Create a test file** (e.g. `math_test.py`):
19
+
20
+ ```python
21
+ from cstesting import describe, it, expect
22
+
23
+ def _suite():
24
+ it("adds numbers", lambda: expect(1 + 1).to_be(2))
25
+ it("compares objects", lambda: expect({"a": 1}).to_equal({"a": 1}))
26
+
27
+ describe("Math", _suite)
28
+ ```
29
+
30
+ **2. Run tests:**
31
+
32
+ ```bash
33
+ python -m cstesting
34
+ python -m cstesting "**/*.test.py"
35
+ python -m cstesting tests/
36
+ python -m cstesting example/math_test.py
37
+ ```
38
+
39
+ ## API
40
+
41
+ ### Test structure
42
+
43
+ - **`describe(name, fn)`** — define a suite
44
+ - **`it(name, fn)`** — define a test (sync or async)
45
+ - **`describe.only(name, fn)`** / **`it.only(name, fn)`** — run only this suite/test
46
+ - **`describe.skip(name, fn)`** / **`it.skip(name, fn)`** — skip
47
+
48
+ ### Hooks
49
+
50
+ - **`before_all(fn)`** — run once before all tests in the suite
51
+ - **`after_all(fn)`** — run once after all tests
52
+ - **`beforeEach(fn)`** / **`afterEach(fn)`** — run before/after each test
53
+
54
+ ### Assertions (`expect(value)`)
55
+
56
+ | Matcher | Example |
57
+ |--------|--------|
58
+ | `to_be(expected)` | strict equality |
59
+ | `to_equal(expected)` | deep equality |
60
+ | `to_be_truthy()` / `to_be_falsy()` | boolean |
61
+ | `to_be_null()` / `to_be_defined()` / `to_be_undefined()` | null/defined |
62
+ | `to_throw(message?)` | expect(fn).to_throw() |
63
+ | `to_be_greater_than(n)` / `to_be_less_than(n)` | numbers |
64
+ | `to_contain(item)` | list or string |
65
+ | `to_have_length(n)` | length |
66
+ | `expect(x).not_.to_be(y)` | negate (use `not_` in Python) |
67
+
68
+ ### API testing (Rest-Assured style)
69
+
70
+ ```python
71
+ from cstesting import describe, it, request
72
+
73
+ def _suite():
74
+ it("GET", lambda: (
75
+ request.get("https://api.example.com/users/1")
76
+ .expect_status(200)
77
+ .expect_json("name", "John")
78
+ ))
79
+ it("verifyStatus", lambda: request.verify_status("GET", "https://api.example.com/health", 200))
80
+
81
+ describe("API", _suite)
82
+ ```
83
+
84
+ - **`request.get(url)`**, **`request.post(url, body)`**, **`request.put`**, **`request.patch`**, **`request.delete`**
85
+ - Chain: **`.expect_status(200)`**, **`.expect_header('content-type', pattern)`**, **`.expect_body({})`**, **`.expect_json('path', value)`**
86
+ - **`request.verify_status(method, url, expected_status, body=None)`**
87
+ - **`res.get_response()`** for raw `ApiResponse` (status, headers, body, raw_body)
88
+
89
+ ### Browser automation (optional)
90
+
91
+ Requires: `pip install playwright && playwright install chromium`
92
+
93
+ ```python
94
+ import asyncio
95
+ from cstesting import describe, it, expect, before_all, after_all, create_browser
96
+
97
+ browser = None
98
+
99
+ def _suite():
100
+ def _before():
101
+ global browser
102
+ browser = asyncio.get_event_loop().run_until_complete(create_browser(headless=True))
103
+ def _after():
104
+ global browser
105
+ if browser:
106
+ asyncio.get_event_loop().run_until_complete(browser.close())
107
+
108
+ before_all(_before)
109
+ after_all(_after)
110
+
111
+ async def _test():
112
+ await browser.goto("https://example.com")
113
+ html = await browser.content()
114
+ expect(html).to_contain("Example Domain")
115
+
116
+ it("loads the page", _test)
117
+
118
+ describe("Browser", _suite)
119
+ ```
120
+
121
+ - **`create_browser(headless=True, browser='chromium')`** — async, returns browser API
122
+ - **`browser.goto(url)`**, **`browser.click(selector)`**, **`browser.type(selector, text)`**
123
+ - **`browser.locator(selector)`** → **`.click()`**, **`.type(text)`**, **`.first`**, **`.nth(n)`**
124
+ - **`browser.wait_for_selector(selector)`**, **`browser.content()`**, **`browser.evaluate(expr)`**
125
+ - **`browser.check(selector)`**, **`browser.uncheck(selector)`**, **`browser.select(selector, option)`**
126
+
127
+ ### Config-driven tests
128
+
129
+ Run flows from a `.conf` file without writing code:
130
+
131
+ ```conf
132
+ # Login (one test case)
133
+ headed=true
134
+ goto:https://example.com/login
135
+ username:#email=value:user@test.com
136
+ password:#password=value:secret
137
+ click=button[type="submit"]
138
+ ```
139
+
140
+ ```bash
141
+ python -m cstesting run login.conf
142
+ python -m cstesting login.conf --headed
143
+ ```
144
+
145
+ Programmatic: **`from cstesting import run_config_file; result = run_config_file('login.conf')`**
146
+
147
+ ### Init (Page Object Model)
148
+
149
+ ```bash
150
+ python -m cstesting init
151
+ ```
152
+
153
+ Creates `pages/` and `tests/` with sample HomePage and test.
154
+
155
+ ### Report
156
+
157
+ After a run, an HTML report is written to **`report/report.html`** (searchable, expandable steps, errors).
158
+
159
+ ## Programmatic run
160
+
161
+ ```python
162
+ from cstesting import describe, it, expect, run
163
+
164
+ def _suite():
165
+ it("works", lambda: expect(1).to_be(1))
166
+
167
+ describe("My tests", _suite)
168
+
169
+ result = run()
170
+ print(result) # passed, failed, skipped, total, duration, errors
171
+ ```
172
+
173
+ ## Publish to PyPI
174
+
175
+ 1. **Create accounts** (if needed):
176
+ - [PyPI](https://pypi.org/account/register/)
177
+ - Optional: [Test PyPI](https://test.pypi.org/account/register/) for testing first
178
+
179
+ 2. **Install build tools:**
180
+ ```bash
181
+ python -m pip install build twine
182
+ ```
183
+ (If `pip` or `python` isn’t recognized, use the full path to your Python executable, or on Windows try `py -m pip install build twine`.)
184
+
185
+ 3. **Build the package:**
186
+ ```bash
187
+ python -m build
188
+ ```
189
+ On Windows, if `python` isn’t recognized, use **`py -m build`** instead.
190
+ This creates `dist/cstesting-0.1.0.tar.gz` and a wheel.
191
+
192
+ 4. **Upload to PyPI:**
193
+ ```bash
194
+ twine upload dist/*
195
+ ```
196
+ Use your PyPI username and password (or [API token](https://pypi.org/manage/account/token/)).
197
+
198
+ To try Test PyPI first:
199
+ ```bash
200
+ twine upload --repository testpypi dist/*
201
+ ```
202
+
203
+ 5. **Bump version** in `pyproject.toml` for each new release, then repeat steps 3–4.
204
+
205
+ ## License
206
+
207
+ MIT. Port of [EasyTesting](https://github.com/lokesh771988/EasyTesting) (Node.js) to Python.
@@ -0,0 +1,57 @@
1
+ """
2
+ CSTesting — Python testing framework (port of EasyTesting/CSTesting Node).
3
+ Usage: from cstesting import describe, it, expect, before_all, after_all, create_browser, request
4
+ """
5
+
6
+ from .runner import (
7
+ describe,
8
+ it,
9
+ before_all,
10
+ after_all,
11
+ beforeEach,
12
+ afterEach,
13
+ before_each,
14
+ after_each,
15
+ run,
16
+ reset_runner,
17
+ step,
18
+ )
19
+ from .assertions import expect, AssertionError
20
+ from .api_request import request, ResponseAssertions, ApiResponse
21
+ from .config_runner import run_config_file
22
+ from .config_parser import parse_config_file, ParsedConfig, ConfigStep, ConfigTestCase
23
+ from .report import write_report, generate_html_report
24
+ from .types import RunResult
25
+
26
+ __all__ = [
27
+ "describe",
28
+ "it",
29
+ "before_all",
30
+ "after_all",
31
+ "beforeEach",
32
+ "afterEach",
33
+ "before_each",
34
+ "after_each",
35
+ "run",
36
+ "reset_runner",
37
+ "step",
38
+ "expect",
39
+ "AssertionError",
40
+ "request",
41
+ "ResponseAssertions",
42
+ "ApiResponse",
43
+ "run_config_file",
44
+ "parse_config_file",
45
+ "ParsedConfig",
46
+ "ConfigStep",
47
+ "ConfigTestCase",
48
+ "write_report",
49
+ "generate_html_report",
50
+ "RunResult",
51
+ ]
52
+
53
+ # Lazy import for browser (optional Playwright)
54
+ def create_browser(*args, **kwargs):
55
+ """Launch browser. Requires: pip install playwright && playwright install"""
56
+ from .browser import create_browser as _create_browser
57
+ return _create_browser(*args, **kwargs)
@@ -0,0 +1,5 @@
1
+ """Allow running as python -m cstesting."""
2
+ from .cli import main
3
+
4
+ if __name__ == "__main__":
5
+ main()