Files
pyscript/pyscriptjs/tests/py-unit/pyscript_plugins_tester.py
Fabio Pliger d55340a817 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>
2023-01-24 13:32:16 -08:00

120 lines
3.2 KiB
Python

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")