mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-21 03:05:38 -05:00
Better test support for Python Plugins (#1108)
* add plugins testing utils module * add plugins manager fixture and init plugins tests helper in conftest * add _custom_elements attribute to pyscript.Plugin to allow plugins to track the CE they register * add test for py_tutor * remove unrelated code from prims js script * ensure a Plugin always has the app attribute and improve tests * add tests for py_tutor create_code_section * implement PluginsManager reset and add teardown on plugins_manager fixture to clean it up after a test * add test to check if plugin has been registered * add docstrings to new tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add docstrings to plugins tester * add changes from main * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * lint * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add todo to add remaining PluginsManager lifecycle events Co-authored-by: Fabio Pliger <fpliger@anaconda.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
119
pyscriptjs/tests/py-unit/pyscript_plugins_tester.py
Normal file
119
pyscriptjs/tests/py-unit/pyscript_plugins_tester.py
Normal file
@@ -0,0 +1,119 @@
|
||||
import xml.dom
|
||||
from xml.dom.minidom import Node # nosec
|
||||
|
||||
import pyscript
|
||||
|
||||
|
||||
class classList:
|
||||
"""Class that (lightly) emulates the behaviour of HTML Nodes ClassList"""
|
||||
|
||||
def __init__(self):
|
||||
self._classes = []
|
||||
|
||||
def add(self, classname: str):
|
||||
"""Add classname to the classList"""
|
||||
self._classes.append(classname)
|
||||
|
||||
def remove(self, classname: str):
|
||||
"""Remove classname from the classList"""
|
||||
self._classes.remove(classname)
|
||||
|
||||
|
||||
class PluginsManager:
|
||||
"""
|
||||
Emulator of PyScript PluginsManager that can be used to simulate plugins lifecycle events
|
||||
|
||||
TODO: Currently missing most of the lifecycle events in PluginsManager implementation. Need
|
||||
to add more than just addPythonPlugin
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.plugins = []
|
||||
|
||||
# mapping containing all the custom elements createed by plugins
|
||||
self._custom_elements = {}
|
||||
|
||||
def addPythonPlugin(self, pluginInstance: pyscript.Plugin):
|
||||
"""
|
||||
Add a pluginInstance to the plugins managed by the PluginManager and calls
|
||||
pluginInstance.init(self) to initialized the plugin with the manager
|
||||
"""
|
||||
pluginInstance.init(self)
|
||||
self.plugins.append(pluginInstance)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Unregister all plugins and related custom elements.
|
||||
"""
|
||||
for plugin in self.plugins:
|
||||
plugin.app = None
|
||||
|
||||
self.plugins = []
|
||||
self._custom_elements = {}
|
||||
|
||||
|
||||
class CustomElement:
|
||||
def __init__(self, plugin_class: pyscript.Plugin):
|
||||
self.pyPluginInstance = plugin_class(self)
|
||||
self.attributes = {}
|
||||
self.innerHTML = ""
|
||||
|
||||
def connectedCallback(self):
|
||||
return self.pyPluginInstance.connect()
|
||||
|
||||
def getAttribute(self, attr: str):
|
||||
return self.attributes.get(attr)
|
||||
|
||||
|
||||
def define_custom_element(tag, plugin_class: pyscript.Plugin):
|
||||
"""
|
||||
Mock method to emulate the behaviour of the PyScript `define_custom_element`
|
||||
that basically creates a new CustomElement passing plugin_class as Python
|
||||
proxy object. For more info check out the logic of the original implementation at:
|
||||
|
||||
src/plugin.ts:define_custom_element
|
||||
"""
|
||||
ce = CustomElement(plugin_class)
|
||||
plugins_manager._custom_elements[tag] = ce
|
||||
|
||||
|
||||
plugins_manager = PluginsManager()
|
||||
|
||||
# Init pyscript testing mocks
|
||||
impl = xml.dom.getDOMImplementation()
|
||||
|
||||
|
||||
class Node:
|
||||
"""
|
||||
Represent an HTML Node.
|
||||
|
||||
This classes us an abstraction on top of xml.dom.minidom.Node
|
||||
"""
|
||||
|
||||
def __init__(self, el: Node):
|
||||
self._el = el
|
||||
self.classList = classList()
|
||||
|
||||
# Automatic delegation is a simple and short boilerplate:
|
||||
def __getattr__(self, attr: str):
|
||||
return getattr(self._el, attr)
|
||||
|
||||
def createElement(self, *args, **kws):
|
||||
newEl = self._el.createElement(*args, **kws)
|
||||
return Node(newEl)
|
||||
|
||||
|
||||
class Document(Node):
|
||||
"""
|
||||
Represent an HTML Document.
|
||||
|
||||
This classes us an abstraction on top of xml.dom.minidom.Document
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._el = impl.createDocument(None, "document", None)
|
||||
|
||||
|
||||
pyscript.js.document = doc = Document()
|
||||
pyscript.js.document.head = doc.createElement("head")
|
||||
pyscript.js.document.body = doc.createElement("body")
|
||||
Reference in New Issue
Block a user