"""What the loaders present to the graph, and to the person wiring it. These are seam tests, not unit tests: a loader that "loads" is worth nothing if what it offers cannot be filled in, or if what it produces is not what the next stage reads. No model weights are needed for any of this. """ import pytest @pytest.fixture(scope="module") def schemas(comfyui): from modules.loaders.clip.nodes import FunUICLIPLoader from modules.loaders.diffusion_model.nodes import FunUIDiffusionModelLoader from modules.loaders.lora.nodes import FunUILoraLoader from modules.loaders.vae.nodes import FunUIVAELoader return [FunUICLIPLoader, FunUIDiffusionModelLoader, FunUILoraLoader, FunUIVAELoader] def test_a_file_picker_is_a_widget_not_a_socket(schemas): """The failure this exists for: ComfyUI's autogrow input sets force_input=True on any WidgetInput, so a list of Combos renders as a row of sockets and the file picker stops being a picker. A dropdown nobody can drop down is not a loader.""" for node in schemas: spec = node.INPUT_TYPES() for section in ("required", "optional"): for name, (kind, options) in (spec.get(section) or {}).items(): if kind != "COMBO": continue assert not options.get("forceInput"), ( f"{node.__name__}.{name} is a COMBO forced to be a socket; " f"nobody can pick a file from it" ) def test_every_combo_offers_something_to_pick(schemas): for node in schemas: spec = node.INPUT_TYPES() for section in ("required", "optional"): for name, (kind, options) in (spec.get(section) or {}).items(): if kind != "COMBO": continue assert "options" in options, f"{node.__name__}.{name} has no options at all" def test_a_default_is_actually_one_of_the_options(schemas): """A default outside its own list makes ComfyUI refuse to queue the whole prompt with 'Value not in list' -- and the node looks configured.""" for node in schemas: spec = node.INPUT_TYPES() for section in ("required", "optional"): for name, (kind, options) in (spec.get(section) or {}).items(): if kind != "COMBO" or "default" not in options: continue assert options["default"] in options["options"], ( f"{node.__name__}.{name} defaults to {options['default']!r}, " f"which is not one of its options" ) def test_the_lora_loader_asks_for_one_slot_at_a_time(comfyui): """No LoRA picked: only the first picker. A picked LoRA brings its own settings and the next slot's picker.""" from modules.loaders.lora.nodes import FunUILoraLoader as L rules = {i.id: (i.extra_dict or {}).get("funui_shows", []) for i in L.define_schema().inputs} assert rules["lora_name"] == [] assert rules["strength_model"] == [{"input": "lora_name", "not": ["None"]}] assert rules["strength_clip_3"] == [{"input": "lora_name_3", "not": ["None"]}] assert rules["apply_to_stage_2"] == [{"input": "lora_name_2", "not": ["None"]}] ask = rules["lora_name_2"][0]["either"] assert [c["input"] for c in ask] == ["lora_name", "lora_name_2"] # after slot 1, or already filled assert [c["input"] for c in rules["lora_name_4"][0]["either"]] == ["lora_name_3", "lora_name_4"]