⎇ 6588d0ed6c355a57194a34a488c1ff2b3d8eb6b3
crates/modules/nahual/libs/meta-schema/tests/example_modules.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
feat(nakui): Fase 3 del ERP — ficha de detalle
1//! Validación de los 6 módulos demo en `examples/nakui-modules/`.
2//!
3//! Si esto verde, garantizamos que un usuario que clone el repo y
4//! corra `NAKUI_MODULES_DIR=examples/nakui-modules cargo run -p nakui-ui`
5//! va a obtener los 6 módulos cargados sin tocar nada.
6
7use nahual_meta_schema::{load_modules_from_dir, FieldKind, View};
8
9fn examples_dir() -> std::path::PathBuf {
10 // Tests corren desde el dir del crate; el repo root está dos
11 // niveles arriba: crates/modules/nakui/ui-schema → repo.
12 // Tras el lift a nahual, el crate vive en
13 // `crates/modules/ui_engine/libs/meta-schema`, así que el repo
14 // root queda 5 niveles arriba.
15 let here = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
16 here.join("../../../../..").join("examples/nakui-modules")
17}
18
19#[test]
20fn loads_all_demo_modules() {
21 let dir = examples_dir();
22 let mods = load_modules_from_dir(&dir).unwrap_or_else(|e| {
23 panic!("load failed for {}: {e}", dir.display());
24 });
25 let ids: Vec<&str> = mods.iter().map(|m| m.id.as_str()).collect();
26 assert_eq!(
27 ids,
28 vec![
29 "crm",
30 "customers",
31 "inventory_movements",
32 "invoices",
33 "products",
34 "sales_engine",
35 "sales_orders",
36 "suppliers",
37 ],
38 "expected 8 modules in alphabetical order \
39 (crm se sumó como ERP con morfismos)"
40 );
41}
42
43#[test]
44fn sales_engine_declares_nakui_module_dir_and_morphism() {
45 // Sanity del módulo demo de morphism: nakui_module_dir set,
46 // y al menos una vista con Action::Morphism en su on_submit.
47 let mods = load_modules_from_dir(examples_dir()).unwrap();
48 let sales = mods
49 .iter()
50 .find(|m| m.id == "sales_engine")
51 .expect("sales_engine debe estar");
52 assert!(
53 sales.nakui_module_dir.is_some(),
54 "sales_engine debería declarar nakui_module_dir"
55 );
56 let has_morphism_view = sales.views.values().any(|v| match v {
57 nahual_meta_schema::View::Form(form) => {
58 matches!(form.on_submit, nahual_meta_schema::Action::Morphism { .. })
59 }
60 _ => false,
61 });
62 assert!(
63 has_morphism_view,
64 "sales_engine debería tener al menos una Form con Action::Morphism"
65 );
66}
67
68#[test]
69fn every_demo_module_has_list_and_form_views() {
70 let mods = load_modules_from_dir(examples_dir()).unwrap();
71 for m in &mods {
72 let mut has_list = false;
73 let mut has_form = false;
74 for v in m.views.values() {
75 match v {
76 View::List(_) => has_list = true,
77 View::Form(_) => has_form = true,
78 View::Detail(_) => {}
79 }
80 }
81 assert!(
82 has_list && has_form,
83 "module {} should expose at least one list + one form view",
84 m.id
85 );
86 }
87}
88
89#[test]
90fn every_demo_form_field_kind_is_recognized() {
91 // Sanity: ningún módulo demo usa un kind que no esté en el enum
92 // (sería rechazado al parsear, pero check explícito no daña).
93 let mods = load_modules_from_dir(examples_dir()).unwrap();
94 for m in &mods {
95 for v in m.views.values() {
96 if let View::Form(form) = v {
97 for f in &form.fields {
98 let _ok = matches!(
99 f.kind,
100 FieldKind::Text
101 | FieldKind::Multiline
102 | FieldKind::Number
103 | FieldKind::Boolean
104 | FieldKind::Date
105 );
106 }
107 }
108 }
109 }
110}
111
112#[test]
113fn every_module_validates_clean() {
114 // validate() chequea que cada MenuItem.view exista en views.
115 // Un typo en cualquiera de los 6 módulos haría fallar este test.
116 let mods = load_modules_from_dir(examples_dir()).unwrap();
117 for m in &mods {
118 m.validate()
119 .unwrap_or_else(|e| panic!("module {} failed validate: {e}", m.id));
120 }
121}