Skip to content

Commit b675072

Browse files
Phase 13: Add comprehensive tests for CLI and API, fix conftest.py
1 parent 71b7c24 commit b675072

6 files changed

Lines changed: 132 additions & 12 deletions

File tree

pythoncms/__main__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .cli import cli
2+
3+
if __name__ == "__main__":
4+
cli()

pythoncms/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131

3232
@click.group()
33-
@click.version_option(__version__)
33+
@click.version_option(__version__, prog_name="pythoncms")
3434
def cli():
3535
"""pythoncms CLI - The fastest way to build CMS in Python"""
3636
pass

pythoncms/conftest.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
from flask import url_for
1313
from flask_login import current_user as _current_user
1414
from init import db as _db
15-
from modules.box__default.auth.models import User
16-
from modules.box__default.keyvalue.models import Settings
15+
from shopyo_auth.models import User
16+
from shopyo_settings.models import Settings
1717
from sqlalchemy import event
1818

1919
# run in shopyo/shopyo
@@ -111,8 +111,12 @@ def db(test_client, non_admin_user, admin_user, unconfirmed_user):
111111
with open("config.json") as config:
112112
config = json.load(config)
113113
for name, value in config["settings"].items():
114-
s = Settings(setting=name, value=value)
115-
_db.session.add(s)
114+
existing = Settings.query.filter_by(setting=name).first()
115+
if not existing:
116+
s = Settings(setting=name, value=value)
117+
_db.session.add(s)
118+
else:
119+
existing.value = value
116120

117121
# Commit the changes for the users
118122
_db.session.commit()
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import pytest
2+
from init import db
3+
from modules.contenttype.models import ContentType, ContentItem
4+
import os
5+
6+
# We use fixtures from conftest.py: test_client, db, db_session
7+
8+
def test_get_types_empty(test_client):
9+
response = test_client.get("/api/v1/types")
10+
assert response.status_code == 200
11+
# Might not be empty if other tests or initialization added types
12+
# but in a clean testing.db it should be [] if we didn't add any in db fixture
13+
assert isinstance(response.json, list)
14+
15+
def test_get_content_not_found(test_client):
16+
response = test_client.get("/api/v1/nonexistent")
17+
assert response.status_code == 404
18+
assert "error" in response.json
19+
20+
def test_api_auth(test_client, monkeypatch):
21+
# Set API_TOKEN for testing auth
22+
monkeypatch.setenv("API_TOKEN", "test-token")
23+
24+
# Unauthorized request (get_content checks auth)
25+
response = test_client.get("/api/v1/blog")
26+
assert response.status_code == 401
27+
28+
# Authorized request
29+
headers = {"Authorization": "Bearer test-token"}
30+
response = test_client.get("/api/v1/blog", headers=headers)
31+
assert response.status_code == 404 # Content type not found, but not 401
32+
33+
def test_get_content_with_data(test_client):
34+
# Create content type and items
35+
ct = ContentType(name="blog", schema=[{"name": "title", "type": "text"}])
36+
db.session.add(ct)
37+
db.session.commit()
38+
39+
item1 = ContentItem(content_type_id=ct.id, data={"title": "First"})
40+
item2 = ContentItem(content_type_id=ct.id, data={"title": "Second"})
41+
db.session.add_all([item1, item2])
42+
db.session.commit()
43+
44+
response = test_client.get("/api/v1/blog")
45+
assert response.status_code == 200
46+
assert response.json["meta"]["total"] == 2
47+
assert len(response.json["data"]) == 2
48+
# Default order is desc by created_at, item2 was added last
49+
assert response.json["data"][0]["content"]["title"] == "Second"
50+
51+
def test_api_pagination(test_client):
52+
ct = ContentType(name="posts", schema=[{"name": "title", "type": "text"}])
53+
db.session.add(ct)
54+
db.session.commit()
55+
56+
for i in range(5):
57+
db.session.add(ContentItem(content_type_id=ct.id, data={"title": str(i)}))
58+
db.session.commit()
59+
60+
response = test_client.get("/api/v1/posts?limit=2&offset=0")
61+
assert response.status_code == 200
62+
assert response.json["meta"]["limit"] == 2
63+
assert len(response.json["data"]) == 2
64+
65+
response = test_client.get("/api/v1/posts?limit=2&offset=4")
66+
assert len(response.json["data"]) == 1
67+
68+
def test_api_sorting(test_client):
69+
ct = ContentType(name="news", schema=[{"name": "title", "type": "text"}])
70+
db.session.add(ct)
71+
db.session.commit()
72+
73+
item1 = ContentItem(content_type_id=ct.id, data={"title": "A"})
74+
item2 = ContentItem(content_type_id=ct.id, data={"title": "B"})
75+
db.session.add_all([item1, item2])
76+
db.session.commit()
77+
78+
response = test_client.get("/api/v1/news?sort_by=id&order=asc")
79+
assert response.json["data"][0]["content"]["title"] == "A"
80+
81+
response = test_client.get("/api/v1/news?sort_by=id&order=desc")
82+
assert response.json["data"][0]["content"]["title"] == "B"

pythoncms/tests/test_cli.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
import shutil
3+
from click.testing import CliRunner
4+
from pythoncms.cli import cli
5+
6+
def test_cli_start(tmp_path):
7+
runner = CliRunner()
8+
with runner.isolated_filesystem(temp_dir=tmp_path):
9+
result = runner.invoke(cli, ["start", "mysite"])
10+
assert result.exit_code == 0
11+
assert "mysite is ready" in result.output
12+
assert os.path.exists("mysite")
13+
assert os.path.exists("mysite/.env")
14+
assert os.path.exists("mysite/requirements.txt")
15+
16+
def test_cli_deploy(tmp_path):
17+
runner = CliRunner()
18+
with runner.isolated_filesystem(temp_dir=tmp_path):
19+
result = runner.invoke(cli, ["deploy"])
20+
assert result.exit_code == 0
21+
assert "Deployment files generated" in result.output
22+
assert os.path.exists("Dockerfile")
23+
assert os.path.exists("docker-compose.yml")
24+
assert os.path.exists(".dockerignore")
25+
26+
def test_cli_version():
27+
runner = CliRunner()
28+
result = runner.invoke(cli, ["--version"])
29+
assert result.exit_code == 0
30+
assert "pythoncms, version" in result.output

pythoncms/tests/test_dunder_main.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
# __main__.main()
1212
# captured = capfd.readouterr()
1313
# assert "Please use Shopyo in a virtual environment for this command" in captured.out
14-
import subprocess
15-
import sys
14+
from click.testing import CliRunner
15+
from pythoncms.cli import cli
1616

17-
18-
def test_no_args(capfd):
19-
subprocess.run([sys.executable, "__main__.py"], text=True)
20-
captured = capfd.readouterr()
21-
assert "No arguments supplied" in captured.out
17+
def test_no_args():
18+
runner = CliRunner()
19+
result = runner.invoke(cli)
20+
assert result.exit_code == 0
21+
assert "The fastest way to build CMS in Python" in result.output

0 commit comments

Comments
 (0)