# -*- coding: utf-8 -*- """ 扫描 cfc-frontend,提取所有 request() 调用的 method+path,用于检测 「新增 / 变更需求」——与基线对比即可知道前端新增了哪些接口,从而自动补全用例。 输出(默认 endpoints 模式):每行 `METHOD /api/path`(排序去重),便于 comm 对比。 python scan_frontend_endpoints.py --out endpoints.txt python scan_frontend_endpoints.py --mode cases --out extra.tsv # 直接产出冒烟用例 TSV """ import os, re, sys, argparse HERE = os.path.dirname(os.path.abspath(__file__)) FRONTEND = os.path.join(HERE, 'cfc-frontend') # 两种 request 调用风格: # 1) request('/api/x', 'POST', data) # 2) request({ url: BASE_URL + '/api/x', method: 'POST' }) path_re_pos = re.compile(r"request\(\s*['\"](/api/[^'\"]+)['\"]\s*,\s*['\"](GET|POST|PUT|DELETE|PATCH)['\"]", re.I) path_re_obj = re.compile(r"url\s*:\s*(?:BASE_URL\s*\+\s*)?['\"](/api/[^'\"]+)['\"]") method_re_obj = re.compile(r"method\s*:\s*['\"](GET|POST|PUT|DELETE|PATCH)['\"]", re.I) SKIP_DIRS = ('node_modules', 'unpackage', '.git', 'dist', 'assets') def scan_file(path): out = set() try: with open(path, 'r', encoding='utf-8', errors='ignore') as f: text = f.read() except Exception: return out for m in path_re_pos.finditer(text): out.add((m.group(2).upper(), m.group(1))) for um in path_re_obj.finditer(text): p = um.group(1) window = text[um.end(): um.end() + 200] mm = method_re_obj.search(window) method = mm.group(1).upper() if mm else 'POST' out.add((method, p)) return out def main(): ap = argparse.ArgumentParser() ap.add_argument('--frontend', default=FRONTEND) ap.add_argument('--out') ap.add_argument('--mode', choices=['endpoints', 'cases'], default='endpoints') args = ap.parse_args() results = set() for root, dirs, files in os.walk(args.frontend): dirs[:] = [d for d in dirs if d not in SKIP_DIRS] for fn in files: if fn.endswith(('.js', '.vue')): results |= scan_file(os.path.join(root, fn)) if args.mode == 'cases': # page fn method path auth param —— 自动补全的用例默认匿名、无路径参数 lines = sorted(f"auto\tauto\t{m}\t{p}\tfalse\tfalse" for m, p in results) else: lines = sorted(f"{m} {p}" for m, p in results) text = "\n".join(lines) + ("\n" if lines else "") if args.out: with open(args.out, 'w', encoding='utf-8') as f: f.write(text) else: sys.stdout.write(text) if __name__ == '__main__': main()