Test Utils

Common Test Utilities and Fixtures for AgriTheory Projects

Install Test Utils

bench get-app https://github.com/agritheory/test_utils

Add the Frappe Gems badge to your README

Maintain Test Utils? Paste this into your README:

[![Listed on Frappe Gems](https://frappegems.com/api/method/frappe_gems.seo.badge?app=agritheory%2Ftest_utils)](https://frappegems.com/gems/apps/agritheory/test_utils)

About Test Utils

AgriTheory Test Utils

Development tools for Frappe apps: test fixtures, pre-commit hooks, GitHub Action templates, and static analysis.

See docs/index.md for a full overview of every tool.


Installation

Python

pip install "git+https://github.com/agritheory/test_utils.git@v0.17.0"

Or with Poetry:

poetry add "git+https://github.com/agritheory/test_utils.git@v0.17.0"

Pre-commit

Add to your app's .pre-commit-config.yaml:

- repo: https://github.com/agritheory/test_utils
  rev: v0.17.0
  hooks:
    - id: static_analysis
    # - id: validate_customizations
    #   args: ['--app', 'your_app_name']
    # ... see docs/index.md for all available hooks

Programmatic use

Static analysis

from test_utils.utils.static_analysis import analyze_app, StaticAnalysisConfig

result = analyze_app("/path/to/my_app")

if result.has_errors:
    for msg in result.all_errors:
        print(msg)

for msg in result.all_warnings:
    print(msg)

Selective passes:

result = analyze_app(
    "/path/to/my_app",
    config=StaticAnalysisConfig(
        detect_orphans=False,
        validate_reports=False,
    ),
)

JSON output:

print(result.to_json())

Path resolution only:

from test_utils.utils.static_analysis.path_resolver import PathResolver

resolver = PathResolver.from_app("/path/to/my_app")
resolved = resolver.resolve("my_app.api.create_order")
print(resolved.exists, resolved.kind, resolved.is_whitelisted)

Code graph (DuckDB)

Build a structural graph for one Frappe app (functions, hooks.py registrations, JS frappe.call / xcall sites with loop context via tree-sitter). Requires optional dependencies:

poetry install --with graph
from pathlib import Path
from test_utils.utils.graph import build_graph, complexity_leaderboard

build_graph(Path("/bench/apps/myapp"), Path("myapp_graph.duckdb"))
rows = complexity_leaderboard("myapp_graph.duckdb", limit=50)

CLI (from a clone of test_utils, with the project env active):

poetry run code_graph --help
poetry run code_graph build /path/to/app -o /tmp/app.duckdb
# Skip extra paths (globs are relative to the app root; tests/ excluded by default):
poetry run code_graph build /path/to/app -o /tmp/app.duckdb --exclude '**/node_modules/**'
# Include default test directories/files in the scan:
poetry run code_graph build /path/to/app -o /tmp/app.duckdb --include-tests
poetry run code_graph leaderboard /tmp/app.duckdb --limit 20
poetry run code_graph js-loops /tmp/app.duckdb
# PNG charts (needs `poetry install --with dev --with graph` for matplotlib + duckdb)
poetry run code_graph plot /tmp/app.duckdb -o /tmp/graph_plots
# Interactive “Obsidian-style” force graph (open HTML in a browser; needs network for CDN)
poetry run code_graph export-view /tmp/app.duckdb -o /tmp/code_graph.html
poetry run code_graph export-view /tmp/app.duckdb -o /tmp/out_dir/ --json   # + out_dir/code_graph.graph.json

The interactive graph includes module import dependencies (file → imported module), Python classes (for override_doctype_class and other hooks whose target is a class path), Python call edges resolved across files via import / from … import plus name.attr chains when the callee is a scanned function in the same app, and edges from classes → file like functions. Calls only through dynamic indirection (e.g. getattr, dict dispatch) are not linked.

Weekly reports and authenticated MCP-style HTTP endpoints are intended to live in ATERP; this package supplies the builder and query helpers only.

CLI

static_analysis /path/to/my_app
static_analysis /path/to/my_app --no-orphans --json

Full CLI reference in docs/static_analysis.md.

Related Developer Tools apps for Frappe & ERPNext

  • Frappe — Low code web framework for real world applications, in Python and Javascript
  • Frappe Docker — Docker environment for developing, deploying, and running Frappe applications (ERPNext and custom apps) in production and development
  • Builder — Craft beautiful websites effortlessly with an intuitive visual builder and publish them instantly
  • Bench — CLI to manage Multi-tenant deployments for Frappe apps
  • Frappe Ui — A set of components and utilities for rapid UI development
  • Press — Full service cloud hosting for the Frappe stack - powers Frappe Cloud
  • Gameplan — Open Source Discussions Platform for Remote Teams
  • Doppio — A Frappe app (CLI) to magically setup single page applications and Vue/React powered desk pages on your custom Frappe apps.