From 07727cd3d60d1a2a69ad8775058b486e3a750d99 Mon Sep 17 00:00:00 2001 From: Chris Adam Date: Tue, 15 Jul 2025 10:18:21 +0200 Subject: [PATCH 01/15] Black + isort + zpretty --- bootstrap-buildout.py | 30 ++++--------------- setup.py | 4 +-- src/collective/js/tooltipster/testing.py | 12 ++------ .../js/tooltipster/tests/test_robot.py | 8 ++--- src/collective/js/tooltipster/upgrades.py | 5 +--- 5 files changed, 12 insertions(+), 47 deletions(-) diff --git a/bootstrap-buildout.py b/bootstrap-buildout.py index dbd50b3..96b937e 100644 --- a/bootstrap-buildout.py +++ b/bootstrap-buildout.py @@ -58,19 +58,10 @@ "even if they are alphas or betas." ), ) +parser.add_option("-c", "--config-file", help=("Specify the path to the buildout configuration " "file to be used.")) +parser.add_option("-f", "--find-links", help=("Specify a URL to search for buildout releases")) parser.add_option( - "-c", - "--config-file", - help=("Specify the path to the buildout configuration " "file to be used."), -) -parser.add_option( - "-f", "--find-links", help=("Specify a URL to search for buildout releases") -) -parser.add_option( - "--allow-site-packages", - action="store_true", - default=False, - help=("Let bootstrap.py use existing site packages"), + "--allow-site-packages", action="store_true", default=False, help=("Let bootstrap.py use existing site packages") ) parser.add_option("--setuptools-version", help="use a specific setuptools version") @@ -124,22 +115,11 @@ ws = pkg_resources.working_set -cmd = [ - sys.executable, - "-c", - "from setuptools.command.easy_install import main; main()", - "-mZqNxd", - tmpeggs, -] +cmd = [sys.executable, "-c", "from setuptools.command.easy_install import main; main()", "-mZqNxd", tmpeggs] find_links = os.environ.get( "bootstrap-testing-find-links", - options.find_links - or ( - "http://downloads.buildout.org/" - if options.accept_buildout_test_releases - else None - ), + options.find_links or ("http://downloads.buildout.org/" if options.accept_buildout_test_releases else None), ) if find_links: cmd.extend(["-f", find_links]) diff --git a/setup.py b/setup.py index a187e43..4d5b361 100644 --- a/setup.py +++ b/setup.py @@ -5,9 +5,7 @@ from setuptools import setup -long_description = ( - open("README.rst").read() + "\n\n" + open("CHANGES.rst").read() + "\n" -) +long_description = open("README.rst").read() + "\n\n" + open("CHANGES.rst").read() + "\n" setup( diff --git a/src/collective/js/tooltipster/testing.py b/src/collective/js/tooltipster/testing.py index ad9e347..5dc08f1 100644 --- a/src/collective/js/tooltipster/testing.py +++ b/src/collective/js/tooltipster/testing.py @@ -18,22 +18,16 @@ COLLECTIVE_JS_TOOLTIPSTER_INTEGRATION_TESTING = IntegrationTesting( - bases=(COLLECTIVE_JS_TOOLTIPSTER_FIXTURE,), - name="CollectiveJsTooltipsterLayer:IntegrationTesting", + bases=(COLLECTIVE_JS_TOOLTIPSTER_FIXTURE,), name="CollectiveJsTooltipsterLayer:IntegrationTesting" ) COLLECTIVE_JS_TOOLTIPSTER_FUNCTIONAL_TESTING = FunctionalTesting( - bases=(COLLECTIVE_JS_TOOLTIPSTER_FIXTURE,), - name="CollectiveJsTooltipsterLayer:FunctionalTesting", + bases=(COLLECTIVE_JS_TOOLTIPSTER_FIXTURE,), name="CollectiveJsTooltipsterLayer:FunctionalTesting" ) COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING = FunctionalTesting( - bases=( - COLLECTIVE_JS_TOOLTIPSTER_FIXTURE, - REMOTE_LIBRARY_BUNDLE_FIXTURE, - z2.ZSERVER_FIXTURE, - ), + bases=(COLLECTIVE_JS_TOOLTIPSTER_FIXTURE, REMOTE_LIBRARY_BUNDLE_FIXTURE, z2.ZSERVER_FIXTURE), name="CollectiveJsTooltipsterLayer:AcceptanceTesting", ) diff --git a/src/collective/js/tooltipster/tests/test_robot.py b/src/collective/js/tooltipster/tests/test_robot.py index 7ddfcf6..387fc54 100644 --- a/src/collective/js/tooltipster/tests/test_robot.py +++ b/src/collective/js/tooltipster/tests/test_robot.py @@ -1,7 +1,5 @@ # -*- coding: UTF-8 -*- -from collective.js.tooltipster.testing import ( - COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING, -) # noqa +from collective.js.tooltipster.testing import COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING # noqa from plone.app.testing import ROBOT_TEST_LEVEL from plone.testing import layered @@ -24,9 +22,7 @@ def test_suite(): robottestsuite.level = ROBOT_TEST_LEVEL suite.addTests( [ - layered( - robottestsuite, layer=COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING - ), + layered(robottestsuite, layer=COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING), ] ) return suite diff --git a/src/collective/js/tooltipster/upgrades.py b/src/collective/js/tooltipster/upgrades.py index 92f846e..7a7bbdc 100644 --- a/src/collective/js/tooltipster/upgrades.py +++ b/src/collective/js/tooltipster/upgrades.py @@ -5,8 +5,5 @@ def upgrade_to_2000(context): """Reapply 'themes' profile if necessary.""" csstool = api.portal.get_tool("portal_css") - if ( - "++resource++collective.js.tooltipster/tooltipster-noir.css" - in csstool.concatenatedresources - ): + if "++resource++collective.js.tooltipster/tooltipster-noir.css" in csstool.concatenatedresources: context.runAllImportStepsFromProfile("collective.js.tooltipster:themes") From 3400c358a8b64358ea62e1f6b7da7196b25ecde8 Mon Sep 17 00:00:00 2001 From: Laurent Lasudry Date: Mon, 17 Jun 2024 12:00:11 +0200 Subject: [PATCH 02/15] Get rid of `includeDependencies` for Plone 6 compatibility --- src/collective/js/tooltipster/configure.zcml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/collective/js/tooltipster/configure.zcml b/src/collective/js/tooltipster/configure.zcml index ef1cf29..f5c8710 100644 --- a/src/collective/js/tooltipster/configure.zcml +++ b/src/collective/js/tooltipster/configure.zcml @@ -6,8 +6,6 @@ i18n_domain="collective.js.tooltipster" > - - Date: Thu, 10 Apr 2025 11:02:26 +0200 Subject: [PATCH 03/15] Migrated resources from Plone 4 to Plone 6 --- .../profiles/default/cssregistry.xml | 22 ------ .../profiles/default/jsregistry.xml | 19 ----- .../tooltipster/profiles/default/registry.xml | 75 +++++++++++++++++++ .../profiles/themes/cssregistry.xml | 73 ------------------ 4 files changed, 75 insertions(+), 114 deletions(-) delete mode 100644 src/collective/js/tooltipster/profiles/default/cssregistry.xml delete mode 100644 src/collective/js/tooltipster/profiles/default/jsregistry.xml create mode 100644 src/collective/js/tooltipster/profiles/default/registry.xml delete mode 100644 src/collective/js/tooltipster/profiles/themes/cssregistry.xml diff --git a/src/collective/js/tooltipster/profiles/default/cssregistry.xml b/src/collective/js/tooltipster/profiles/default/cssregistry.xml deleted file mode 100644 index b2b9edd..0000000 --- a/src/collective/js/tooltipster/profiles/default/cssregistry.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/src/collective/js/tooltipster/profiles/default/jsregistry.xml b/src/collective/js/tooltipster/profiles/default/jsregistry.xml deleted file mode 100644 index 1e957c1..0000000 --- a/src/collective/js/tooltipster/profiles/default/jsregistry.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - diff --git a/src/collective/js/tooltipster/profiles/default/registry.xml b/src/collective/js/tooltipster/profiles/default/registry.xml new file mode 100644 index 0000000..0e76c08 --- /dev/null +++ b/src/collective/js/tooltipster/profiles/default/registry.xml @@ -0,0 +1,75 @@ + + + + + True + ++resource++collective.js.tooltipster/tooltipster.bundle.min.css + ++resource++collective.js.tooltipster/tooltipster.bundle.min.js + plone + False + False + + + + True + ++resource++collective.js.tooltipster/tooltipster_helper.js + plone + False + False + + + + True + ++resource++collective.js.tooltipster/tooltipster-sideTip-borderless.min.css + plone + False + False + + + + True + ++resource++collective.js.tooltipster/tooltipster-sideTip-light.min.css + plone + False + False + + + + True + ++resource++collective.js.tooltipster/tooltipster-sideTip-noir.min.css + plone + False + False + + + + True + ++resource++collective.js.tooltipster/tooltipster-sideTip-punk.min.css + plone + False + False + + + + True + ++resource++collective.js.tooltipster/tooltipster-sideTip-shadow.min.css + plone + False + False + + + diff --git a/src/collective/js/tooltipster/profiles/themes/cssregistry.xml b/src/collective/js/tooltipster/profiles/themes/cssregistry.xml deleted file mode 100644 index ed3e97e..0000000 --- a/src/collective/js/tooltipster/profiles/themes/cssregistry.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - From 6be291bc4af3c5fd528c616203d20dbf2e02b79d Mon Sep 17 00:00:00 2001 From: Chris Adam Date: Fri, 11 Apr 2025 09:52:54 +0200 Subject: [PATCH 04/15] Added view content selector --- .../js/tooltipster/browser/static/tooltipster_helper.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/collective/js/tooltipster/browser/static/tooltipster_helper.js b/src/collective/js/tooltipster/browser/static/tooltipster_helper.js index 84c8d59..25308b8 100644 --- a/src/collective/js/tooltipster/browser/static/tooltipster_helper.js +++ b/src/collective/js/tooltipster/browser/static/tooltipster_helper.js @@ -1,5 +1,6 @@ function tooltipster_helper(selector, view_name, + view_content_selector, data_parameters=[], options={}) { @@ -59,7 +60,12 @@ function tooltipster_helper(selector, // set async: false so content is loaded when functionReady is called async: async, success: function (data) { - instance.content(data); + if (view_content_selector === undefined) { + instance.content(data); + } + else { + instance.content($(view_content_selector, data)); + } $origin.data('loaded', true); } }); From 82cdab60c5ed4a4b2a8d01226fcd8f40f5159fc1 Mon Sep 17 00:00:00 2001 From: Chris Adam Date: Fri, 11 Apr 2025 14:40:33 +0200 Subject: [PATCH 05/15] Updated tests and added gh workflow --- .github/workflows/test.yml | 23 +++++++++++ CHANGES.rst | 4 +- buildout.cfg | 17 ++++---- src/collective/js/tooltipster/configure.zcml | 19 +++++++-- .../profiles/uninstall/browserlayer.xml | 6 +++ .../profiles/uninstall/metadata.xml | 6 +++ .../profiles/uninstall/registry.xml | 39 +++++++++++++++++++ .../js/tooltipster/tests/test_setup.py | 16 ++++---- 8 files changed, 106 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 src/collective/js/tooltipster/profiles/uninstall/browserlayer.xml create mode 100644 src/collective/js/tooltipster/profiles/uninstall/metadata.xml create mode 100644 src/collective/js/tooltipster/profiles/uninstall/registry.xml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..4e980f5 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: Unit tests +on: + pull_request: + branches: + - master + types: + - opened + - synchronize + push: + branches: + - master + tags: + - '**' + workflow_dispatch: +jobs: + test: + runs-on: + group: self-hosted + steps: + - name: test + uses: IMIO/gha/plone-package-test-notify@v4 + with: + PYTHON_VERSION: ${{ vars.PYTHON_VERSION }} diff --git a/CHANGES.rst b/CHANGES.rst index 6e11a91..88bc094 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,8 +5,8 @@ Changelog 1.9 (unreleased) ---------------- -- Nothing changed yet. - +- Added Plone 6.1 version in buildout. + [chris-adam] 1.8 (2024-02-08) ---------------- diff --git a/buildout.cfg b/buildout.cfg index d2a395f..08f4590 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -1,5 +1,5 @@ [buildout] -extends = http://dist.plone.org/release/4.3-latest/versions.cfg +extends = http://dist.plone.org/release/6.1.1/versions.cfg extensions = mr.developer parts = instance @@ -44,11 +44,10 @@ eggs = [versions] -zc.buildout = 2.10.0 -zc.recipe.egg = 2.0.1 - -robotframework = 2.8.4 -robotframework-ride = 1.3 -robotframework-selenium2library = 1.6.0 -robotsuite = 1.6.1 -selenium = 2.44.0 +zc.buildout = 4.1.4 +zc.recipe.egg = 2.0.7 + +robotframework = 6.0.2 +robotframework-selenium2library = 3.0.0 +robotsuite = 2.3.2 +selenium = 4.9.1 diff --git a/src/collective/js/tooltipster/configure.zcml b/src/collective/js/tooltipster/configure.zcml index f5c8710..32b15e6 100644 --- a/src/collective/js/tooltipster/configure.zcml +++ b/src/collective/js/tooltipster/configure.zcml @@ -42,10 +42,21 @@ description="" import_steps="jsregistry" /> - + + + + + diff --git a/src/collective/js/tooltipster/profiles/uninstall/metadata.xml b/src/collective/js/tooltipster/profiles/uninstall/metadata.xml new file mode 100644 index 0000000..0ff90cf --- /dev/null +++ b/src/collective/js/tooltipster/profiles/uninstall/metadata.xml @@ -0,0 +1,6 @@ + + + 2000 + + + diff --git a/src/collective/js/tooltipster/profiles/uninstall/registry.xml b/src/collective/js/tooltipster/profiles/uninstall/registry.xml new file mode 100644 index 0000000..fa3b9bb --- /dev/null +++ b/src/collective/js/tooltipster/profiles/uninstall/registry.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/collective/js/tooltipster/tests/test_setup.py b/src/collective/js/tooltipster/tests/test_setup.py index abf906e..ec328eb 100644 --- a/src/collective/js/tooltipster/tests/test_setup.py +++ b/src/collective/js/tooltipster/tests/test_setup.py @@ -1,11 +1,9 @@ # -*- coding: utf-8 -*- """Setup tests for this package.""" -from collective.js.tooltipster.testing import ( - COLLECTIVE_JS_TOOLTIPSTER_INTEGRATION_TESTING, -) # noqa -from plone import api +from collective.js.tooltipster.testing import COLLECTIVE_JS_TOOLTIPSTER_INTEGRATION_TESTING # noqa +from Products.CMFPlone.utils import get_installer -import unittest2 as unittest +import unittest class TestSetup(unittest.TestCase): @@ -16,16 +14,16 @@ class TestSetup(unittest.TestCase): def setUp(self): """Custom shared utility setup for tests.""" self.portal = self.layer["portal"] - self.installer = api.portal.get_tool("portal_quickinstaller") + self.installer = get_installer(self.portal) def test_product_installed(self): """Test if collective.js.tooltipster is installed with portal_quickinstaller.""" - self.assertTrue(self.installer.isProductInstalled("collective.js.tooltipster")) + self.assertTrue(self.installer.is_product_installed("collective.js.tooltipster")) def test_uninstall(self): """Test if collective.js.tooltipster is cleanly uninstalled.""" - self.installer.uninstallProducts(["collective.js.tooltipster"]) - self.assertFalse(self.installer.isProductInstalled("collective.js.tooltipster")) + self.installer.uninstall_product("collective.js.tooltipster") + self.assertFalse(self.installer.is_product_installed("collective.js.tooltipster")) def test_browserlayer(self): """Test that ICollectiveJsTooltipsterLayer is registered.""" From 7f5d194c53160a10f8a5b5667334513934f7dbaa Mon Sep 17 00:00:00 2001 From: Chris Adam Date: Wed, 16 Apr 2025 16:17:43 +0200 Subject: [PATCH 06/15] Updated gha and test setup --- .github/workflows/main.yml | 108 +++++++++++++++++++++++++++++++++++++ .github/workflows/test.yml | 23 -------- .gitignore | 1 + Makefile | 97 +++++++++++++++++++++++++++++++++ buildout.cfg => base.cfg | 0 gha.cfg | 4 ++ requirements-6.0.txt | 3 ++ requirements-6.1.txt | 3 ++ setup.py | 6 ++- test-6.0.cfg | 29 ++++++++++ test-6.1.cfg | 29 ++++++++++ 11 files changed, 278 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 .github/workflows/test.yml create mode 100644 Makefile rename buildout.cfg => base.cfg (100%) create mode 100644 gha.cfg create mode 100644 requirements-6.0.txt create mode 100644 requirements-6.1.txt create mode 100644 test-6.0.cfg create mode 100644 test-6.1.cfg diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..c1cc2e1 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,108 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Push tests +# run-name: ${{ github.actor }} push tests + +on: + push: + pull_request: + +jobs: + test: + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + include: +# - python: 2.7.18 +# plone: 4.3 +# - python: 3.7.14 +# plone: 5.2 +# - python: 3.10.11 +# plone: "6.0" + - python: 3.13.1 + plone: "6.1" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up pyenv and Python + uses: "gabrielfalcao/pyenv-action@v18" + with: + default: "${{ matrix.python }}" + - name: Setup Env + run: | + pip install --upgrade pip + pip install -r requirements-${{ matrix.plone }}.txt + - name: Cache eggs + uses: actions/cache@v4 + env: + cache-name: cache-eggs + with: + path: ~/buildout-cache/eggs + key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ matrix.python }}-${{ matrix.plone }} +# - name: Cache eggs restore +# id: cache-restore +# uses: actions/cache/restore@v3 +# env: +# cache-name: cache-eggs +# with: +# path: ~/buildout-cache/eggs +# key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ matrix.python }}-${{ matrix.plone }} + - name: buildout + run: | + sed -ie "s#test.cfg#test-${{matrix.plone}}.cfg#" gha.cfg + buildout -c gha.cfg annotate + buildout -c gha.cfg +# - name: Cache eggs save +# uses: actions/cache/save@v3 +# with: +# path: ~/buildout-cache/eggs +# key: ${{ steps.cache-restore.outputs.cache-primary-key }} + - name: test + run: | + bin/test -t !robot + coverage: + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + include: + - python: 3.10.11 + plone: "6.0" + - python: 3.13.1 + plone: "6.1" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up pyenv and Python + uses: "gabrielfalcao/pyenv-action@v18" + with: + default: "${{ matrix.python }}" + - name: Setup Env + run: | + pip install --upgrade pip + pip install -r requirements-${{matrix.plone}}.txt + pip install -U coveralls coverage + - name: Cache eggs + uses: actions/cache@v4 + env: + cache-name: cache-eggs + with: + path: ~/buildout-cache/eggs + key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ matrix.python }}-${{ matrix.plone }} + - name: buildout + run: | + sed -ie "s#test.cfg#test-${{matrix.plone}}.cfg#" gha.cfg + buildout -c gha.cfg + - name: code-analysis + run: | + bin/code-analysis + - name: test coverage + run: | + coverage run bin/test -t !robot + - name: Publish to Coveralls + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + coveralls --service=github \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 4e980f5..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Unit tests -on: - pull_request: - branches: - - master - types: - - opened - - synchronize - push: - branches: - - master - tags: - - '**' - workflow_dispatch: -jobs: - test: - runs-on: - group: self-hosted - steps: - - name: test - uses: IMIO/gha/plone-package-test-notify@v4 - with: - PYTHON_VERSION: ${{ vars.PYTHON_VERSION }} diff --git a/.gitignore b/.gitignore index 241ddf5..a49853e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ .settings/ bin/ buildout-cache/ +CACHEDIR.TAG develop-eggs/ parts/ src/* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ae0494d --- /dev/null +++ b/Makefile @@ -0,0 +1,97 @@ +#!/usr/bin/make +# pyenv is a requirement, with 3.13 python versions, and virtualenv installed in each version +# plone parameter must be passed to create environment 'make setup plone=6.0' or after a make cleanall +# The original Makefile can be found on https://github.com/IMIO/scripts-buildout + +SHELL=/bin/bash +plones=6.0 6.1 +b_o= +old_plone=$(shell [ -e .plone-version ] && cat .plone-version) + +ifeq (, $(shell which pyenv)) + $(error "pyenv command not found! Aborting") +endif + +ifndef plone +ifeq (,$(filter setup,$(MAKECMDGOALS))) + plone=$(old_plone) +endif +endif + +ifneq ($(wildcard bin/instance),) + b_o=-N +endif + +ifndef python +ifeq ($(plone),6.0) + python=3.10 +endif +ifeq ($(plone),6.1) + python=3.13 +endif +endif + +all: buildout + +.PHONY: help +help: + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n\nTargets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +.python-version: ## Setups pyenv version + @pyenv local `pyenv versions |grep " $(python)" |tail -1 |xargs` + @echo "Local pyenv version is `cat .python-version`" + @ if [[ `pyenv which virtualenv` != `pyenv prefix`* ]] ; then echo "You need to install virtualenv in `cat .python-version` pyenv python (pip install virtualenv)"; exit 1; fi + +bin/buildout: .python-version ## Setups environment + virtualenv . + ./bin/pip install --upgrade pip + ./bin/pip install -r requirements-$(plone).txt + @echo "$(plone)" > .plone-version + +.PHONY: setup +setup: oneof-plone backup cleanall bin/buildout restore ## Setups environment + +.PHONY: buildout +buildout: oneof-plone bin/buildout ## Runs setup and buildout + rm -f .installed.cfg .mr.developer.cfg + bin/buildout -t 5 -c test-$(plone).cfg ${b_o} + +.PHONY: test +test: oneof-plone bin/buildout ## run bin/test without robot + # can be run by example with: make test opt='-t "settings"' + bin/test -t \!robot ${opt} + +.PHONY: cleanall +cleanall: ## Cleans all installed buildout files + rm -fr bin include lib local share develop-eggs downloads eggs parts .installed.cfg .mr.developer.cfg .python-version pyvenv.cfg + +.PHONY: backup +backup: ## Backups db files + @if [ '$(old_plone)' != '' ] && [ -f var/filestorage/Data.fs ]; then mv var/filestorage/Data.fs var/filestorage/Data.fs.$(old_plone); mv var/blobstorage var/blobstorage.$(old_plone); fi + +.PHONY: restore +restore: ## Restores db files + @if [ '$(plone)' != '' ] && [ -f var/filestorage/Data.fs.$(plone) ]; then mv var/filestorage/Data.fs.$(plone) var/filestorage/Data.fs; mv var/blobstorage.$(plone) var/blobstorage; fi + +.PHONY: which-python +which-python: oneof-plone ## Displays versions information + @echo "current plone = $(old_plone)" + @echo "current python = `cat .python-version`" + @echo "plone var = $(plone)" + @echo "python var = $(python)" + +.PHONY: vcr +vcr: ## Shows requirements in checkversion-r.html + @bin/versioncheck -rbo checkversion-r-$(plone).html test-$(plone).cfg + +.PHONY: vcn +vcn: ## Shows newer packages in checkversion-n.html + @bin/versioncheck -npbo checkversion-n-$(plone).html test-$(plone).cfg + +.PHONY: guard-% +guard-%: + @ if [ "${${*}}" = "" ]; then echo "You must give a value for variable '$*' : like $*=xxx"; exit 1; fi + +.PHONY: oneof-% +oneof-%: + @ if ! echo "${${*}s}" | tr " " '\n' |grep -Fqx "${${*}}"; then echo "Invalid '$*' parameter ('${${*}}') : must be one of '${${*}s}'"; exit 1; fi \ No newline at end of file diff --git a/buildout.cfg b/base.cfg similarity index 100% rename from buildout.cfg rename to base.cfg diff --git a/gha.cfg b/gha.cfg new file mode 100644 index 0000000..449d60f --- /dev/null +++ b/gha.cfg @@ -0,0 +1,4 @@ +[buildout] +extends = + test.cfg +eggs-directory = ~/buildout-cache/eggs diff --git a/requirements-6.0.txt b/requirements-6.0.txt new file mode 100644 index 0000000..75ae54c --- /dev/null +++ b/requirements-6.0.txt @@ -0,0 +1,3 @@ +-c https://dist.plone.org/release/6.0-latest/requirements.txt +setuptools +zc.buildout diff --git a/requirements-6.1.txt b/requirements-6.1.txt new file mode 100644 index 0000000..aaf0495 --- /dev/null +++ b/requirements-6.1.txt @@ -0,0 +1,3 @@ +-c https://dist.plone.org/release/6.1-latest/requirements.txt +setuptools +zc.buildout diff --git a/setup.py b/setup.py index 4d5b361..5bbf542 100644 --- a/setup.py +++ b/setup.py @@ -18,10 +18,12 @@ "Development Status :: 6 - Mature", "Environment :: Web Environment", "Framework :: Plone", - "Framework :: Plone :: 4.3", + "Framework :: Plone :: 6.0", + "Framework :: Plone :: 6.1", "License :: OSI Approved :: GNU General Public License (GPL)", "Programming Language :: Python", - "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.13", ], keywords="Python Plone", author="Gauthier BASTIEN", diff --git a/test-6.0.cfg b/test-6.0.cfg new file mode 100644 index 0000000..5a95f8f --- /dev/null +++ b/test-6.0.cfg @@ -0,0 +1,29 @@ +[buildout] + +extends = + https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-6.0.x.cfg + base.cfg + +update-versions-file = test-6.0.cfg + +[versions] +# to keep prompt-toolkit < 3 +ipython = 8.3.0 + +ipdb = 0.13.9 +iw.debug = 0.3 +jedi = 0.18.1 +parso = 0.8.3 + +# Required by: +# ipdb +asttokens = 2.0.8 +backcall = 0.2.0 +executing = 1.1.1 +matplotlib-inline = 0.1.6 +pexpect = 4.8.0 +pickleshare = 0.7.5 +ptyprocess = 0.7.0 +pure-eval = 0.2.2 +stack-data = 0.5.1 +traitlets = 5.4.0 diff --git a/test-6.1.cfg b/test-6.1.cfg new file mode 100644 index 0000000..8a84fcd --- /dev/null +++ b/test-6.1.cfg @@ -0,0 +1,29 @@ +[buildout] + +extends = + https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-6.1.x.cfg + base.cfg + +#update-versions-file = test-6.1.cfg + +[versions] +# to keep prompt-toolkit < 3 +ipython = 8.3.0 + +ipdb = 0.13.9 +iw.debug = 0.3 +jedi = 0.18.1 +parso = 0.8.3 + +# Required by: +# ipdb +asttokens = 2.0.8 +backcall = 0.2.0 +executing = 1.1.1 +matplotlib-inline = 0.1.6 +pexpect = 4.8.0 +pickleshare = 0.7.5 +ptyprocess = 0.7.0 +pure-eval = 0.2.2 +stack-data = 0.5.1 +traitlets = 5.4.0 From 31e82792bc98bfb5f7e17f8e5c7d6ecc3cd9d2a2 Mon Sep 17 00:00:00 2001 From: Chris Adam Date: Tue, 10 Jun 2025 15:13:30 +0200 Subject: [PATCH 07/15] Removed deprecated code-analysis --- .github/workflows/main.yml | 9 ++------- Makefile | 2 +- base.cfg | 7 ------- setup.py | 2 +- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1cc2e1..305771e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: # plone: 5.2 # - python: 3.10.11 # plone: "6.0" - - python: 3.13.1 + - python: 3.12.7 plone: "6.1" steps: - name: Checkout @@ -68,9 +68,7 @@ jobs: fail-fast: false matrix: include: - - python: 3.10.11 - plone: "6.0" - - python: 3.13.1 + - python: 3.12.7 plone: "6.1" steps: - name: Checkout @@ -95,9 +93,6 @@ jobs: run: | sed -ie "s#test.cfg#test-${{matrix.plone}}.cfg#" gha.cfg buildout -c gha.cfg - - name: code-analysis - run: | - bin/code-analysis - name: test coverage run: | coverage run bin/test -t !robot diff --git a/Makefile b/Makefile index ae0494d..f0d2b96 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ ifeq ($(plone),6.0) python=3.10 endif ifeq ($(plone),6.1) - python=3.13 + python=3.12 endif endif diff --git a/base.cfg b/base.cfg index 08f4590..c58346e 100644 --- a/base.cfg +++ b/base.cfg @@ -18,13 +18,6 @@ eggs = zcml = collective.js.tooltipster-testing -[code-analysis] -recipe = plone.recipe.codeanalysis -directory = ${buildout:directory}/src/collective -flake8-exclude = bootstrap.py,bootstrap-buildout.py,docs,*.egg.,omelette -flake8-max-complexity = 15 - - [omelette] recipe = collective.recipe.omelette eggs = ${instance:eggs} diff --git a/setup.py b/setup.py index 5bbf542..0f1a380 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ "License :: OSI Approved :: GNU General Public License (GPL)", "Programming Language :: Python", "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.12", ], keywords="Python Plone", author="Gauthier BASTIEN", From 7298db4209819ea4fa9fcdf2dfcd265360b621f8 Mon Sep 17 00:00:00 2001 From: Chris Adam Date: Wed, 11 Jun 2025 12:04:51 +0200 Subject: [PATCH 08/15] Changed python version from 3.12 to 3.13 --- .github/workflows/main.yml | 4 ++-- Makefile | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 305771e..5750b63 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: # plone: 5.2 # - python: 3.10.11 # plone: "6.0" - - python: 3.12.7 + - python: 3.13.1 plone: "6.1" steps: - name: Checkout @@ -68,7 +68,7 @@ jobs: fail-fast: false matrix: include: - - python: 3.12.7 + - python: 3.13.1 plone: "6.1" steps: - name: Checkout diff --git a/Makefile b/Makefile index f0d2b96..ae0494d 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ ifeq ($(plone),6.0) python=3.10 endif ifeq ($(plone),6.1) - python=3.12 + python=3.13 endif endif diff --git a/setup.py b/setup.py index 0f1a380..5bbf542 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ "License :: OSI Approved :: GNU General Public License (GPL)", "Programming Language :: Python", "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ], keywords="Python Plone", author="Gauthier BASTIEN", From af94673cb8f279c2309ed41ae6e75b92518843fd Mon Sep 17 00:00:00 2001 From: Chris Adam Date: Wed, 18 Jun 2025 09:45:55 +0200 Subject: [PATCH 09/15] Added code-analysis --- .github/workflows/main.yml | 11 +++++++---- base.cfg | 14 +++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5750b63..fd90d1b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,10 +19,10 @@ jobs: # plone: 4.3 # - python: 3.7.14 # plone: 5.2 -# - python: 3.10.11 -# plone: "6.0" - - python: 3.13.1 - plone: "6.1" + - python: 3.10.11 + plone: "6.0" + # - python: 3.13.1 + # plone: "6.1" steps: - name: Checkout uses: actions/checkout@v4 @@ -93,6 +93,9 @@ jobs: run: | sed -ie "s#test.cfg#test-${{matrix.plone}}.cfg#" gha.cfg buildout -c gha.cfg + - name: code-analysis + run: | + bin/code-analysis - name: test coverage run: | coverage run bin/test -t !robot diff --git a/base.cfg b/base.cfg index c58346e..9e670e1 100644 --- a/base.cfg +++ b/base.cfg @@ -1,7 +1,9 @@ [buildout] -extends = http://dist.plone.org/release/6.1.1/versions.cfg +extends = + https://dist.plone.org/release/6.1-latest/versions.cfg + https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg extensions = mr.developer -parts = +parts += instance test develop = . @@ -18,6 +20,13 @@ eggs = zcml = collective.js.tooltipster-testing +[code-analysis] +recipe = plone.recipe.codeanalysis +directory = ${buildout:directory}/src/collective +flake8-exclude = bootstrap.py,bootstrap-buildout.py,docs,*.egg.,omelette +flake8-max-complexity = 15 + + [omelette] recipe = collective.recipe.omelette eggs = ${instance:eggs} @@ -37,7 +46,6 @@ eggs = [versions] -zc.buildout = 4.1.4 zc.recipe.egg = 2.0.7 robotframework = 6.0.2 From 3d4fdfc1e64cc2dfc1e370980b08e614fe9b8832 Mon Sep 17 00:00:00 2001 From: Chris Adam Date: Thu, 26 Jun 2025 09:52:58 +0200 Subject: [PATCH 10/15] Fixed buildout versions --- base.cfg | 1 - src/collective/js/tooltipster/configure.zcml | 27 +++---- .../profiles/uninstall/metadata.xml | 4 +- .../profiles/uninstall/registry.xml | 77 ++++++++++--------- 4 files changed, 56 insertions(+), 53 deletions(-) diff --git a/base.cfg b/base.cfg index 9e670e1..8ce7174 100644 --- a/base.cfg +++ b/base.cfg @@ -1,6 +1,5 @@ [buildout] extends = - https://dist.plone.org/release/6.1-latest/versions.cfg https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg extensions = mr.developer parts += diff --git a/src/collective/js/tooltipster/configure.zcml b/src/collective/js/tooltipster/configure.zcml index 32b15e6..4151791 100644 --- a/src/collective/js/tooltipster/configure.zcml +++ b/src/collective/js/tooltipster/configure.zcml @@ -16,6 +16,14 @@ directory="profiles/default" /> + + - - - - + 2000 - + diff --git a/src/collective/js/tooltipster/profiles/uninstall/registry.xml b/src/collective/js/tooltipster/profiles/uninstall/registry.xml index fa3b9bb..1d32e12 100644 --- a/src/collective/js/tooltipster/profiles/uninstall/registry.xml +++ b/src/collective/js/tooltipster/profiles/uninstall/registry.xml @@ -1,39 +1,46 @@ - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + From d2d55d35a74b40b9e956a688cc3f6a2de85d1cc9 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 7 Oct 2026 20:40:21 +0200 Subject: [PATCH 11/15] Add unit and robot tests Unit tests for the static files, bundles, theme bundles, uninstall and browser layer. Robot scenarios for tooltipster_helper as its callers use it (Plone 4 argument order), on a test-only view; they pass on Plone 4.3 (master) and fail on 6.1 until the helper regressions are fixed. Co-Authored-By: Claude Opus 5.5 --- Makefile | 12 +++ src/collective/js/tooltipster/testing.zcml | 10 ++ .../tests/robot/test_example.robot | 66 ------------- .../tests/robot/test_tooltipster.robot | 91 +++++++++++++++++ .../tooltipster/tests/robot/tooltipster.robot | 91 +++++++++++++++++ .../tooltipster/tests/robot/ui_plone4.robot | 97 +++++++++++++++++++ .../tooltipster/tests/robot/ui_plone6.robot | 95 ++++++++++++++++++ .../js/tooltipster/tests/test_robot.py | 40 ++++---- .../js/tooltipster/tests/test_setup.py | 54 ++++++++++- .../js/tooltipster/tests/tooltip_test_view.pt | 11 +++ 10 files changed, 481 insertions(+), 86 deletions(-) delete mode 100644 src/collective/js/tooltipster/tests/robot/test_example.robot create mode 100644 src/collective/js/tooltipster/tests/robot/test_tooltipster.robot create mode 100644 src/collective/js/tooltipster/tests/robot/tooltipster.robot create mode 100644 src/collective/js/tooltipster/tests/robot/ui_plone4.robot create mode 100644 src/collective/js/tooltipster/tests/robot/ui_plone6.robot create mode 100644 src/collective/js/tooltipster/tests/tooltip_test_view.pt diff --git a/Makefile b/Makefile index ae0494d..e6aaa46 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,18 @@ test: oneof-plone bin/buildout ## run bin/test without robot # can be run by example with: make test opt='-t "settings"' bin/test -t \!robot ${opt} +.PHONY: robot +robot: oneof-plone bin/buildout ## run robot tests in headless firefox + # opt -t filters are ORed with -t robot: run one scenario with MOZ_HEADLESS=1 bin/test --all -t "loaded once" + MOZ_HEADLESS=1 bin/test --all -t robot ${opt} + +.PHONY: robot-server +robot-server: ## Starts robot server (layer=, default COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING) + # run a robot file against it with: bin/robot -v PLONE_MAJOR:$(firstword $(subst ., ,$(plone))) src/collective/js/tooltipster/tests/robot/test_tooltipster.robot + # (no isolation between tests there: every test creates the same "doc", run one test at a time with -t) + # --no-reload: the reload watchdog restarts the server when a template is read + env ZSERVER_HOST=localhost ZSERVER_PORT=$(or $(ZSERVER_PORT),55001) bin/robot-server --no-reload -v collective.js.tooltipster.testing.$(or $(layer),COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING) + .PHONY: cleanall cleanall: ## Cleans all installed buildout files rm -fr bin include lib local share develop-eggs downloads eggs parts .installed.cfg .mr.developer.cfg .python-version pyvenv.cfg diff --git a/src/collective/js/tooltipster/testing.zcml b/src/collective/js/tooltipster/testing.zcml index 80ca31e..3b61da3 100644 --- a/src/collective/js/tooltipster/testing.zcml +++ b/src/collective/js/tooltipster/testing.zcml @@ -1,5 +1,6 @@ + + + diff --git a/src/collective/js/tooltipster/tests/robot/test_example.robot b/src/collective/js/tooltipster/tests/robot/test_example.robot deleted file mode 100644 index 1288b69..0000000 --- a/src/collective/js/tooltipster/tests/robot/test_example.robot +++ /dev/null @@ -1,66 +0,0 @@ -# ============================================================================ -# EXAMPLE ROBOT TESTS -# ============================================================================ -# -# Run this robot test stand-alone: -# -# $ bin/test -s collective.js.tooltipster -t test_example.robot --all -# -# Run this robot test with robot server (which is faster): -# -# 1) Start robot server: -# -# $ bin/robot-server --reload-path src collective.js.tooltipster.testing.COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING -# -# 2) Run robot tests: -# -# $ bin/robot src/collective/js/tooltipster/tests/robot/test_example.robot -# -# See the http://docs.plone.org for further details (search for robot -# framework). -# -# ============================================================================ - -*** Settings ***************************************************************** - -Resource plone/app/robotframework/selenium.robot -Resource plone/app/robotframework/keywords.robot - -Library Remote ${PLONE_URL}/RobotRemote - -Test Setup Open test browser -Test Teardown Close all browsers - - -*** Test Cases *************************************************************** - -Scenario: As a member I want to be able to log into the website - [Documentation] Example of a BDD-style (Behavior-driven development) test. - Given a login form - When I enter valid credentials - Then I am logged in - - -*** Keywords ***************************************************************** - -# --- Given ------------------------------------------------------------------ - -a login form - Go To ${PLONE_URL}/login_form - Wait until page contains Login Name - Wait until page contains Password - - -# --- WHEN ------------------------------------------------------------------- - -I enter valid credentials - Input Text __ac_name admin - Input Text __ac_password secret - Click Button Log in - - -# --- THEN ------------------------------------------------------------------- - -I am logged in - Wait until page contains You are now logged in - Page should contain You are now logged in diff --git a/src/collective/js/tooltipster/tests/robot/test_tooltipster.robot b/src/collective/js/tooltipster/tests/robot/test_tooltipster.robot new file mode 100644 index 0000000..25f4c27 --- /dev/null +++ b/src/collective/js/tooltipster/tests/robot/test_tooltipster.robot @@ -0,0 +1,91 @@ +*** Settings *** +Documentation Tooltips of tooltipster_helper as its Plone 4 callers use them. Version-independent: +... Plone selectors are in ui_plone*.robot. +Resource tooltipster.robot +Test Setup Open a manager browser on a document +Test Teardown Close all browsers + + +*** Test Cases *** +The tooltipster library and the helper are loaded on the pages + The javascript value is typeof jQuery.fn.tooltipster function + The javascript value is typeof tooltipster_helper function + +Hovering an element shows the content of the view loaded with its data parameters + Add a tooltip target alice Alice base_url=${DOC_URL} delay=1 + Call the tooltipster helper alice data_parameters=['name', 'delay'] + Hover the target alice + The tooltip shows \... + The tooltip shows Hello Alice from ${DOC_TITLE} + The tooltip has the class tooltipster-shadow + The tooltip has the class tooltipster-bottom + The tooltip z-index is 11000 + +Without data-base_url the view is called on the context of the page + Add a tooltip target bob Bob + Call the tooltipster helper bob + Hover the target bob + The tooltip shows Hello Bob from ${DOC_TITLE} + +Without data-base_url on a page opened with its view URL + Go to ${DOC_URL}/view + Add a tooltip target bob Bob + Call the tooltipster helper bob + Hover the target bob + The tooltip on a page opened with its view URL shows ${DOC_TITLE} Hello Bob from ${DOC_TITLE} + +The content of the view is loaded once per element + Add a tooltip target alice Alice base_url=${DOC_URL} + Call the tooltipster helper alice + Hover the target alice + The tooltip shows Hello Alice from ${DOC_TITLE} + Move the mouse to the site logo + Every tooltip is closed + Change the data-name of the target alice Bob + Hover the target alice + The tooltip still shows after a while Hello Alice from ${DOC_TITLE} + +The theme option sets the theme of the tooltip + Add a tooltip target alice Alice base_url=${DOC_URL} + Call the tooltipster helper alice options={theme: 'tooltipster-light'} + Hover the target alice + The tooltip shows Hello Alice from ${DOC_TITLE} + The tooltip has the class tooltipster-light + +The functionReady_callback option is called once the content is loaded + Add a tooltip target alice Alice base_url=${DOC_URL} + Call the tooltipster helper alice + ... options={functionReady_callback: function () {window.tooltip_ready = document.querySelector('.tooltipster-content').textContent.replace(/\\s+/g, ' ').trim();}} + Hover the target alice + The tooltip shows Hello Alice from ${DOC_TITLE} + The javascript value is window.tooltip_ready Hello Alice from ${DOC_TITLE} + +Moving the mouse out of the element closes its tooltip + Add a tooltip target alice Alice base_url=${DOC_URL} + Call the tooltipster helper alice + Hover the target alice + The tooltip shows Hello Alice from ${DOC_TITLE} + Move the mouse to the site logo + Every tooltip is closed + +With close_other_tips opening a tooltip closes the other ones + Add a tooltip target alice Alice base_url=${DOC_URL} + Add a tooltip target bob Bob base_url=${DOC_URL} + Call the tooltipster helper alice options={close_other_tips: true, triggerClose: {originClick: true}} + Call the tooltipster helper bob options={close_other_tips: true, triggerClose: {originClick: true}} + Hover the target alice + The tooltip shows Hello Alice from ${DOC_TITLE} + Hover the target bob + The tooltip shows Hello Bob from ${DOC_TITLE} + The tooltip showing this text is closed Hello Alice from ${DOC_TITLE} + +Without close_other_tips the other tooltips stay open + Add a tooltip target alice Alice base_url=${DOC_URL} + Add a tooltip target bob Bob base_url=${DOC_URL} + Call the tooltipster helper alice options={triggerClose: {originClick: true}} + Call the tooltipster helper bob options={triggerClose: {originClick: true}} + Hover the target alice + The tooltip shows Hello Alice from ${DOC_TITLE} + Hover the target bob + The tooltip shows Hello Bob from ${DOC_TITLE} + The tooltip still shows after a while Hello Alice from ${DOC_TITLE} diff --git a/src/collective/js/tooltipster/tests/robot/tooltipster.robot b/src/collective/js/tooltipster/tests/robot/tooltipster.robot new file mode 100644 index 0000000..36f267d --- /dev/null +++ b/src/collective/js/tooltipster/tests/robot/tooltipster.robot @@ -0,0 +1,91 @@ +*** Settings *** +Documentation collective.js.tooltipster keywords, built on the ui_plone${PLONE_MAJOR}.robot keywords. +... Robot Framework 3.0 syntax (shared with the Plone 4.3 environment). +... The helper is called in the Plone 4 positional order of every caller: +... tooltipster_helper(selector, view_name, data_parameters, options). +Resource ui_plone${PLONE_MAJOR}.robot + + +*** Variables *** +${DOC_URL} ${PLONE_URL}/doc +${DOC_TITLE} My document +# test-only page of testing.zcml: "Hello from ", waits seconds +${VIEW_NAME} tooltipster-test-view +${TOOLTIP} css=.tooltipster-base +${TOOLTIP_XPATH} //div[contains(concat(" ", @class, " "), " tooltipster-base ")] +${TOOLTIP_VISIBLE_TEXT} document.querySelector('.tooltipster-content').innerText.replace(/\\s+/g, ' ').trim() + + +*** Keywords *** +Open a manager browser on a document + Open test browser + Enable autologin as Manager + Create content type=Document id=doc title=${DOC_TITLE} + Go to ${DOC_URL} + +Add a tooltip target + [Documentation] Span at the top of the content area with a data-name attribute, + ... and data-base_url / data-delay (seconds the page waits) when given + [Arguments] ${id} ${name} ${base_url}=${EMPTY} ${delay}=${EMPTY} + Execute javascript + ... var target = document.createElement('span'); + ... target.id = '${id}'; + ... target.textContent = 'Target ${id}'; + ... target.style.display = 'inline-block'; + ... target.style.padding = '5px'; + ... target.style.marginRight = '300px'; + ... target.setAttribute('data-name', '${name}'); + ... if ('${base_url}') {target.setAttribute('data-base_url', '${base_url}');} + ... if ('${delay}') {target.setAttribute('data-delay', '${delay}');} + ... var content = document.getElementById('${CONTENT_ID}'); + ... content.insertBefore(target, content.firstChild); + +Change the data-name of the target + [Arguments] ${id} ${name} + Execute javascript document.getElementById('${id}').setAttribute('data-name', '${name}'); + +Call the tooltipster helper + [Documentation] Plone 4 positional order. data_parameters and options are JS literals. + [Arguments] ${id} ${data_parameters}=['name'] ${options}={} + Execute javascript tooltipster_helper('[id="${id}"]', '${VIEW_NAME}', ${data_parameters}, ${options}); + +Hover the target + [Arguments] ${id} + Mouse over css=[id="${id}"] + +The tooltip shows + [Documentation] A visible tooltip shows exactly this text + [Arguments] ${text} + Wait until element is visible xpath=${TOOLTIP_XPATH}\[normalize-space(.)="${text}"] + +The visible text of the tooltip is + [Documentation] Text the user sees in the open tooltip, once loaded + [Arguments] ${text} + Wait until keyword succeeds 10s 0.2s The javascript value is ${TOOLTIP_VISIBLE_TEXT} ${text} + +The tooltip showing this text is closed + [Arguments] ${text} + Wait until page does not contain element xpath=${TOOLTIP_XPATH}\[normalize-space(.)="${text}"] + +The tooltip still shows after a while + [Documentation] Leaves time to a new loading of the content + [Arguments] ${text} + Sleep 1s + The tooltip shows ${text} + +Every tooltip is closed + Wait until page does not contain element ${TOOLTIP} + +The tooltip has the class + [Arguments] ${class} + Page should contain element ${TOOLTIP}.${class} + +The tooltip z-index is + [Arguments] ${expected} + ${z_index}= Execute javascript return window.getComputedStyle(document.querySelector('.tooltipster-base')).zIndex; + Should be equal as strings ${z_index} ${expected} + +The javascript value is + [Arguments] ${expression} ${expected} + ${value}= Execute javascript return ${expression}; + Should be equal as strings ${value} ${expected} diff --git a/src/collective/js/tooltipster/tests/robot/ui_plone4.robot b/src/collective/js/tooltipster/tests/robot/ui_plone4.robot new file mode 100644 index 0000000..d1d9efe --- /dev/null +++ b/src/collective/js/tooltipster/tests/robot/ui_plone4.robot @@ -0,0 +1,97 @@ +*** Settings *** +Documentation Plone 4.3 keywords. Same keyword names and arguments as ui_plone6.robot. +... Robot Framework 3.0 syntax (Python 2 environment). +... Checked on Plone 4.3 (collective.js.tooltipster master): CONTENT_ID, +... Move the mouse to the site logo. The others are NOT CHECKED YET (see imio.history). +Resource plone/app/robotframework/selenium.robot +Resource plone/app/robotframework/keywords.robot +Library Remote ${PLONE_URL}/RobotRemote + + +*** Variables *** +${MODAL} css=div.overlay-ajax +${ERROR_PAGE_TEXT} there seems to be an error +${NOT_FOUND_TEXT} This page does not seem to exist +# id of the content area +${CONTENT_ID} content + + +*** Keywords *** +Log in with the login form + [Documentation] Real login (creates the user folder), unlike autologin + [Arguments] ${username} ${password} + Disable autologin + Go to ${PLONE_URL}/login_form + Input text css=#__ac_name ${username} + Input password css=#__ac_password ${password} + Click button css=input[name="submit"] + Wait until page contains element css=#portal-personaltools + +Click the content action + [Documentation] Item of the Actions menu (object_buttons), by action id + [Arguments] ${action_id} + Click element css=#plone-contentmenu-actions dt.actionMenuHeader a + Wait until element is visible css=#plone-contentmenu-actions-${action_id} + Click element css=#plone-contentmenu-actions-${action_id} + +The content action is available + [Arguments] ${action_id} ${expected}=${True} + Click element css=#plone-contentmenu-actions dt.actionMenuHeader a + Wait until element is visible css=#plone-contentmenu-actions dd.actionMenuContent + Run keyword if ${expected} + ... Page should contain element css=#plone-contentmenu-actions-${action_id} + ... ELSE Page should not contain element css=#plone-contentmenu-actions-${action_id} + +Open the add menu + Click element css=#plone-contentmenu-factories dt.actionMenuHeader a + Wait until element is visible css=#plone-contentmenu-factories dd.actionMenuContent + +The personal action links to + [Documentation] Item of the user menu (user actions), by action id + [Arguments] ${action_id} ${url} + Element attribute value should be css=#personaltools-${action_id} a href ${url} + +The personal action is not available + [Arguments] ${action_id} + Page should not contain element css=#personaltools-${action_id} + +The modal is open + [Documentation] Overlay (Plone 4) or modal (Plone 6) showing a form + Wait until element is visible ${MODAL} form + +Modal element + [Documentation] Locator of the element with this id inside the modal + ... (an argument starting with # would be a robot comment) + [Arguments] ${id} + [Return] ${MODAL} [id="${id}"] + +Save the modal + Click button ${MODAL} #form-buttons-save + +Cancel the modal + Click button ${MODAL} #form-buttons-cancel + +The modal is closed + Wait until element is not visible ${MODAL} + +The status message contains + [Documentation] Skips the hidden, empty #kssPortalMessage placeholder + [Arguments] ${text} + Wait until element contains css=.portalMessage:not(#kssPortalMessage) ${text} + +The page is not an error + Page should not contain ${ERROR_PAGE_TEXT} + +The page is not found + Page should contain ${NOT_FOUND_TEXT} + +The edit link is not available + Page should not contain element css=#contentview-edit + +Move the mouse to the site logo + Mouse over css=#portal-logo + +The tooltip on a page opened with its view URL shows + [Documentation] Plone 4: the document page (the is /view, /view/ renders the document) + [Arguments] ${document_page_text} ${view_text} + The visible text of the tooltip is ${document_page_text} diff --git a/src/collective/js/tooltipster/tests/robot/ui_plone6.robot b/src/collective/js/tooltipster/tests/robot/ui_plone6.robot new file mode 100644 index 0000000..3d0b99f --- /dev/null +++ b/src/collective/js/tooltipster/tests/robot/ui_plone6.robot @@ -0,0 +1,95 @@ +*** Settings *** +Documentation Plone 6 Classic UI keywords. Same keyword names and arguments as ui_plone4.robot. +... Robot Framework 3.0 syntax: shared with the Plone 4.3 (Python 2) environment. +... Selectors checked on Plone 6.1 (collective.contact.contactlist). +Resource plone/app/robotframework/selenium.robot +Resource plone/app/robotframework/keywords.robot +Library Remote ${PLONE_URL}/RobotRemote + + +*** Variables *** +${MODAL} css=.modal-dialog +${ERROR_PAGE_TEXT} there seems to be an error +${NOT_FOUND_TEXT} This page does not seem to exist +# id of the content area +${CONTENT_ID} content + + +*** Keywords *** +Log in with the login form + [Documentation] Real login (creates the user folder), unlike autologin + [Arguments] ${username} ${password} + Disable autologin + Go to ${PLONE_URL}/login + Input text css=#__ac_name ${username} + Input password css=#__ac_password ${password} + Click button css=#buttons-login + Wait until page contains element css=#personaltools-menulink + +Click the content action + [Documentation] Item of the Actions menu (object_buttons), by action id + [Arguments] ${action_id} + Click element css=#plone-contentmenu-actions > a + Wait until element is visible css=#plone-contentmenu-actions-${action_id} + Click element css=#plone-contentmenu-actions-${action_id} + +The content action is available + [Arguments] ${action_id} ${expected}=${True} + Click element css=#plone-contentmenu-actions > a + Wait until element is visible css=#plone-contentmenu-actions ul + Run keyword if ${expected} + ... Page should contain element css=#plone-contentmenu-actions-${action_id} + ... ELSE Page should not contain element css=#plone-contentmenu-actions-${action_id} + +Open the add menu + Click element css=#plone-contentmenu-factories > a + Wait until element is visible css=#plone-contentmenu-factories ul + +The personal action links to + [Documentation] Item of the user menu (user actions), by action id + [Arguments] ${action_id} ${url} + Element attribute value should be css=#personaltools-${action_id} href ${url} + +The personal action is not available + [Arguments] ${action_id} + Page should not contain element css=#personaltools-${action_id} + +The modal is open + [Documentation] Overlay (Plone 4) or modal (Plone 6) showing a form + Wait until element is visible ${MODAL} form + +Modal element + [Documentation] Locator of the element with this id inside the modal + ... (an argument starting with # would be a robot comment) + [Arguments] ${id} + [Return] ${MODAL} [id="${id}"] + +Save the modal + Click button css=.modal-footer #form-buttons-save + +Cancel the modal + Click button css=.modal-footer #form-buttons-cancel + +The modal is closed + Wait until page does not contain element ${MODAL} + +The status message contains + [Arguments] ${text} + Wait until element contains css=.portalMessage ${text} + +The page is not an error + Page should not contain ${ERROR_PAGE_TEXT} + +The page is not found + Page should contain ${NOT_FOUND_TEXT} + +The edit link is not available + Page should not contain element css=#contentview-edit + +Move the mouse to the site logo + Mouse over css=#portal-logo + +The tooltip on a page opened with its view URL shows + [Documentation] Plone 6: the view of the context (no tag, the helper uses the body data-base-url) + [Arguments] ${document_page_text} ${view_text} + The visible text of the tooltip is ${view_text} diff --git a/src/collective/js/tooltipster/tests/test_robot.py b/src/collective/js/tooltipster/tests/test_robot.py index 387fc54..e6b3337 100644 --- a/src/collective/js/tooltipster/tests/test_robot.py +++ b/src/collective/js/tooltipster/tests/test_robot.py @@ -1,5 +1,10 @@ -# -*- coding: UTF-8 -*- -from collective.js.tooltipster.testing import COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING # noqa +# -*- coding: utf-8 -*- +"""Robot suites of tests/robot. + +ROBOT_PLONE_MAJOR (4 or 6) selects the UI keywords: robotsuite passes the +ROBOT_* environment variables to the suites as robot variables. +""" +from collective.js.tooltipster.testing import COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING from plone.app.testing import ROBOT_TEST_LEVEL from plone.testing import layered @@ -8,21 +13,22 @@ import unittest +try: + from importlib.metadata import version +except ImportError: # Python 2 + from pkg_resources import get_distribution + + def version(name): + return get_distribution(name).version + + def test_suite(): + os.environ.setdefault("ROBOT_PLONE_MAJOR", version("Products.CMFPlone").split(".")[0]) suite = unittest.TestSuite() - current_dir = os.path.abspath(os.path.dirname(__file__)) - robot_dir = os.path.join(current_dir, "robot") - robot_tests = [ - os.path.join("robot", doc) - for doc in os.listdir(robot_dir) - if doc.endswith(".robot") and doc.startswith("test_") - ] - for robot_test in robot_tests: - robottestsuite = robotsuite.RobotTestSuite(robot_test) - robottestsuite.level = ROBOT_TEST_LEVEL - suite.addTests( - [ - layered(robottestsuite, layer=COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING), - ] - ) + robot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "robot") + for name in sorted(os.listdir(robot_dir)): + if name.startswith("test_") and name.endswith(".robot"): + robottestsuite = robotsuite.RobotTestSuite(os.path.join("robot", name)) + robottestsuite.level = ROBOT_TEST_LEVEL + suite.addTests([layered(robottestsuite, layer=COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING)]) return suite diff --git a/src/collective/js/tooltipster/tests/test_setup.py b/src/collective/js/tooltipster/tests/test_setup.py index ec328eb..9473ea2 100644 --- a/src/collective/js/tooltipster/tests/test_setup.py +++ b/src/collective/js/tooltipster/tests/test_setup.py @@ -1,11 +1,20 @@ # -*- coding: utf-8 -*- """Setup tests for this package.""" +from collective.js.tooltipster.interfaces import ICollectiveJsTooltipsterLayer from collective.js.tooltipster.testing import COLLECTIVE_JS_TOOLTIPSTER_INTEGRATION_TESTING # noqa +from plone.browserlayer import utils +from plone.registry.interfaces import IRegistry +from Products.CMFPlone.interfaces import IBundleRegistry from Products.CMFPlone.utils import get_installer +from zope.component import getUtility import unittest +RESOURCE = "++resource++collective.js.tooltipster/" +THEMES = ("borderless", "light", "noir", "punk", "shadow") + + class TestSetup(unittest.TestCase): """Test that collective.js.tooltipster is properly installed.""" @@ -16,18 +25,57 @@ def setUp(self): self.portal = self.layer["portal"] self.installer = get_installer(self.portal) + def bundles(self): + """Bundles of the package, by name""" + bundles = getUtility(IRegistry).collectionOfInterface(IBundleRegistry, prefix="plone.bundles", check=False) + return {name: bundle for name, bundle in bundles.items() if name.startswith("collective.js.tooltipster.")} + def test_product_installed(self): """Test if collective.js.tooltipster is installed with portal_quickinstaller.""" self.assertTrue(self.installer.is_product_installed("collective.js.tooltipster")) + def test_static_files(self): + """Every static file is published as a resource""" + names = ["tooltipster.bundle.min.js", "tooltipster.bundle.min.css", "tooltipster_helper.js"] + names += ["tooltipster-sideTip-{}.min.css".format(theme) for theme in THEMES] + for name in names: + self.assertIsNotNone(self.portal.restrictedTraverse(RESOURCE + name), name) + + def test_bundles(self): + """The tooltipster library (js + css) and the helper are loaded on every page""" + bundles = self.bundles() + base = bundles["collective.js.tooltipster.base"] + self.assertEqual( + (base.enabled, base.jscompilation, base.csscompilation, base.depends, base.load_async, base.load_defer), + (True, RESOURCE + "tooltipster.bundle.min.js", RESOURCE + "tooltipster.bundle.min.css", "plone", False, + False), + ) + helper = bundles["collective.js.tooltipster.helper"] + self.assertEqual( + (helper.enabled, helper.jscompilation, helper.csscompilation, helper.depends, helper.load_async, + helper.load_defer), + (True, RESOURCE + "tooltipster_helper.js", None, "plone", False, False), + ) + + def test_theme_bundles(self): + """The 5 theme stylesheets are loaded on every page""" + bundles = self.bundles() + for theme in THEMES: + bundle = bundles["collective.js.tooltipster.{}theme".format(theme)] + self.assertEqual( + (bundle.enabled, bundle.jscompilation, bundle.csscompilation, bundle.depends), + (True, None, RESOURCE + "tooltipster-sideTip-{}.min.css".format(theme), "plone"), + theme, + ) + def test_uninstall(self): """Test if collective.js.tooltipster is cleanly uninstalled.""" + self.assertEqual(len(self.bundles()), 7) self.installer.uninstall_product("collective.js.tooltipster") self.assertFalse(self.installer.is_product_installed("collective.js.tooltipster")) + self.assertEqual(self.bundles(), {}) + self.assertNotIn(ICollectiveJsTooltipsterLayer, utils.registered_layers()) def test_browserlayer(self): """Test that ICollectiveJsTooltipsterLayer is registered.""" - from collective.js.tooltipster.interfaces import ICollectiveJsTooltipsterLayer - from plone.browserlayer import utils - self.assertIn(ICollectiveJsTooltipsterLayer, utils.registered_layers()) diff --git a/src/collective/js/tooltipster/tests/tooltip_test_view.pt b/src/collective/js/tooltipster/tests/tooltip_test_view.pt new file mode 100644 index 0000000..1b53362 --- /dev/null +++ b/src/collective/js/tooltipster/tests/tooltip_test_view.pt @@ -0,0 +1,11 @@ +
Hello + name + from + title
From 59523d07e4e68af5b10a20b937fff63d1aec5c05 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 7 Oct 2026 20:50:29 +0200 Subject: [PATCH 12/15] Migrate to Plone 6.2 Plone 6.0, 6.1 and 6.2 (test-6.2.cfg, Makefile, GHA matrix, coverage on 6.2). pkgutil-style namespace __init__ without namespace_packages: the pkg_resources declaration hides the native namespace eggs of 6.2. tooltipster_helper gets back the signature its callers use (view_content_selector moved into options) and calls the view on the context URL (body data-base-url, no tag on Plone 6). Plone 4 themes profile and upgrade step removed. Co-Authored-By: Claude Opus 5.5 --- .coveragerc | 3 ++ .github/workflows/main.yml | 8 +++-- .gitignore | 3 ++ .travis.yml | 13 --------- CHANGES.rst | 7 +++++ Makefile | 5 +++- README.rst | 5 ++-- base.cfg | 11 ++----- requirements-6.2.txt | 3 ++ setup.py | 3 +- src/collective/__init__.py | 9 +----- src/collective/js/__init__.py | 9 +----- .../browser/static/tooltipster_helper.js | 8 ++--- src/collective/js/tooltipster/configure.zcml | 29 ------------------- .../tooltipster/profiles/default/registry.xml | 14 ++++----- .../profiles/uninstall/registry.xml | 14 ++++----- src/collective/js/tooltipster/testing.py | 4 +-- .../tests/robot/test_content_selector.robot | 13 +++++++++ .../js/tooltipster/tests/test_setup.py | 6 ++-- src/collective/js/tooltipster/upgrades.py | 9 ------ travis.cfg => test-6.2.cfg | 8 +++-- 21 files changed, 74 insertions(+), 110 deletions(-) delete mode 100644 .travis.yml create mode 100644 requirements-6.2.txt create mode 100644 src/collective/js/tooltipster/tests/robot/test_content_selector.robot delete mode 100644 src/collective/js/tooltipster/upgrades.py rename travis.cfg => test-6.2.cfg (52%) diff --git a/.coveragerc b/.coveragerc index f66a2b6..3a97b0d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,3 +1,6 @@ +[run] +source = src/collective/js/tooltipster + [report] include = src/collective/* diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fd90d1b..a47a786 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,8 +21,10 @@ jobs: # plone: 5.2 - python: 3.10.11 plone: "6.0" - # - python: 3.13.1 - # plone: "6.1" + - python: 3.13.1 + plone: "6.1" + - python: 3.13.1 + plone: "6.2" steps: - name: Checkout uses: actions/checkout@v4 @@ -69,7 +71,7 @@ jobs: matrix: include: - python: 3.13.1 - plone: "6.1" + plone: "6.2" steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index a49853e..b7ab19c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ htmlcov/ output.xml *.swp lib/ +.plone-version +.python-version +pyvenv.cfg include/ temp_auto_push.bat temp_interactive_push.bat diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d64ee7e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: python -python: - - 2.7 -install: - - mkdir -p buildout-cache/{eggs,downloads} - - python bootstrap-buildout.py -c travis.cfg - - bin/buildout -Nc travis.cfg -script: - - bin/test - -notifications: - email: - - devs@imio.be diff --git a/CHANGES.rst b/CHANGES.rst index 88bc094..8fc2c42 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,13 @@ Changelog - Added Plone 6.1 version in buildout. [chris-adam] +- Plone 6.2 support. Removed the Plone 4 `themes` profile and upgrade step + (themes are bundles of the default profile). + [chris-adam] +- `tooltipster_helper`: `view_content_selector` moved into `options` (the 3rd + positional parameter is `data_parameters` again, as callers expect), and the + view is called on the context URL (`data-base-url`) when there is no `data-base_url`. + [chris-adam] 1.8 (2024-02-08) ---------------- diff --git a/Makefile b/Makefile index e6aaa46..1b12eb7 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # The original Makefile can be found on https://github.com/IMIO/scripts-buildout SHELL=/bin/bash -plones=6.0 6.1 +plones=6.0 6.1 6.2 b_o= old_plone=$(shell [ -e .plone-version ] && cat .plone-version) @@ -29,6 +29,9 @@ endif ifeq ($(plone),6.1) python=3.13 endif +ifeq ($(plone),6.2) + python=3.13 +endif endif all: buildout diff --git a/README.rst b/README.rst index 38e8da0..c65e5a7 100644 --- a/README.rst +++ b/README.rst @@ -9,10 +9,9 @@ Version 4.2.6 Themes ****** -If you want to use additional themes, just import profile "collective.js.tooltipster Themes" in portal_setup. - -Following themes are available : +The default profile also installs the theme stylesheets (one bundle each): +- tooltipster-borderless - tooltipster-light - tooltipster-noir - tooltipster-punk diff --git a/base.cfg b/base.cfg index 8ce7174..419a2c4 100644 --- a/base.cfg +++ b/base.cfg @@ -5,6 +5,7 @@ extensions = mr.developer parts += instance test + robot develop = . @@ -41,13 +42,5 @@ defaults = ['-s', 'collective.js.tooltipster', '--auto-color', '--auto-progress' recipe = zc.recipe.egg eggs = ${test:eggs} - plone.app.robotframework[debug,ride,reload] + plone.app.robotframework[debug,reload] - -[versions] -zc.recipe.egg = 2.0.7 - -robotframework = 6.0.2 -robotframework-selenium2library = 3.0.0 -robotsuite = 2.3.2 -selenium = 4.9.1 diff --git a/requirements-6.2.txt b/requirements-6.2.txt new file mode 100644 index 0000000..5e0f81b --- /dev/null +++ b/requirements-6.2.txt @@ -0,0 +1,3 @@ +-c https://dist.plone.org/release/6.2-latest/requirements.txt +setuptools +zc.buildout diff --git a/setup.py b/setup.py index 5bbf542..02780f1 100644 --- a/setup.py +++ b/setup.py @@ -20,6 +20,7 @@ "Framework :: Plone", "Framework :: Plone :: 6.0", "Framework :: Plone :: 6.1", + "Framework :: Plone :: 6.2", "License :: OSI Approved :: GNU General Public License (GPL)", "Programming Language :: Python", "Programming Language :: Python :: 3.10", @@ -31,10 +32,10 @@ url="http://pypi.python.org/pypi/collective.js.tooltipster", license="GPL", packages=find_packages("src", exclude=["ez_setup"]), - namespace_packages=["collective", "collective.js"], package_dir={"": "src"}, include_package_data=True, zip_safe=False, + python_requires=">=3.10", install_requires=[ "plone.api", "setuptools", diff --git a/src/collective/__init__.py b/src/collective/__init__.py index 08ad8d5..8db66d3 100644 --- a/src/collective/__init__.py +++ b/src/collective/__init__.py @@ -1,8 +1 @@ -# -*- coding: UTF-8 -*- -# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages -try: - __import__("pkg_resources").declare_namespace(__name__) -except ImportError: - from pkgutil import extend_path - - __path__ = extend_path(__path__, __name__) +__path__ = __import__("pkgutil").extend_path(__path__, __name__) diff --git a/src/collective/js/__init__.py b/src/collective/js/__init__.py index 08ad8d5..8db66d3 100644 --- a/src/collective/js/__init__.py +++ b/src/collective/js/__init__.py @@ -1,8 +1 @@ -# -*- coding: UTF-8 -*- -# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages -try: - __import__("pkg_resources").declare_namespace(__name__) -except ImportError: - from pkgutil import extend_path - - __path__ = extend_path(__path__, __name__) +__path__ = __import__("pkgutil").extend_path(__path__, __name__) diff --git a/src/collective/js/tooltipster/browser/static/tooltipster_helper.js b/src/collective/js/tooltipster/browser/static/tooltipster_helper.js index 25308b8..961d20d 100644 --- a/src/collective/js/tooltipster/browser/static/tooltipster_helper.js +++ b/src/collective/js/tooltipster/browser/static/tooltipster_helper.js @@ -1,6 +1,5 @@ function tooltipster_helper(selector, view_name, - view_content_selector, data_parameters=[], options={}) { @@ -49,7 +48,8 @@ function tooltipster_helper(selector, // base_url var base_url = $($origin).attr('data-base_url'); if (!base_url) { - base_url = document.baseURI; + // Plone 6 has no tag: data-base-url of body is the context URL + base_url = document.body.dataset.baseUrl || document.baseURI; } parameters.ajax_load = new Date().getTime(); @@ -60,11 +60,11 @@ function tooltipster_helper(selector, // set async: false so content is loaded when functionReady is called async: async, success: function (data) { - if (view_content_selector === undefined) { + if (options.view_content_selector === undefined) { instance.content(data); } else { - instance.content($(view_content_selector, data)); + instance.content($(options.view_content_selector, data)); } $origin.data('loaded', true); } diff --git a/src/collective/js/tooltipster/configure.zcml b/src/collective/js/tooltipster/configure.zcml index 4151791..ae74e46 100644 --- a/src/collective/js/tooltipster/configure.zcml +++ b/src/collective/js/tooltipster/configure.zcml @@ -24,14 +24,6 @@ directory="profiles/uninstall" /> - - - - - - - - diff --git a/src/collective/js/tooltipster/profiles/default/registry.xml b/src/collective/js/tooltipster/profiles/default/registry.xml index 0e76c08..7048d76 100644 --- a/src/collective/js/tooltipster/profiles/default/registry.xml +++ b/src/collective/js/tooltipster/profiles/default/registry.xml @@ -1,7 +1,7 @@ - True @@ -12,7 +12,7 @@ False - True @@ -22,7 +22,7 @@ False - True @@ -32,7 +32,7 @@ False - True @@ -42,7 +42,7 @@ False - True @@ -52,7 +52,7 @@ False - True @@ -62,7 +62,7 @@ False - True diff --git a/src/collective/js/tooltipster/profiles/uninstall/registry.xml b/src/collective/js/tooltipster/profiles/uninstall/registry.xml index 1d32e12..e26e2c0 100644 --- a/src/collective/js/tooltipster/profiles/uninstall/registry.xml +++ b/src/collective/js/tooltipster/profiles/uninstall/registry.xml @@ -1,43 +1,43 @@ - - - - - - - diff --git a/src/collective/js/tooltipster/testing.py b/src/collective/js/tooltipster/testing.py index 5dc08f1..5bf840a 100644 --- a/src/collective/js/tooltipster/testing.py +++ b/src/collective/js/tooltipster/testing.py @@ -3,7 +3,7 @@ from plone.app.testing import FunctionalTesting from plone.app.testing import IntegrationTesting from plone.app.testing import PloneWithPackageLayer -from plone.testing import z2 +from plone.testing.zope import WSGI_SERVER_FIXTURE import collective.js.tooltipster @@ -28,6 +28,6 @@ COLLECTIVE_JS_TOOLTIPSTER_ACCEPTANCE_TESTING = FunctionalTesting( - bases=(COLLECTIVE_JS_TOOLTIPSTER_FIXTURE, REMOTE_LIBRARY_BUNDLE_FIXTURE, z2.ZSERVER_FIXTURE), + bases=(COLLECTIVE_JS_TOOLTIPSTER_FIXTURE, REMOTE_LIBRARY_BUNDLE_FIXTURE, WSGI_SERVER_FIXTURE), name="CollectiveJsTooltipsterLayer:AcceptanceTesting", ) diff --git a/src/collective/js/tooltipster/tests/robot/test_content_selector.robot b/src/collective/js/tooltipster/tests/robot/test_content_selector.robot new file mode 100644 index 0000000..774742c --- /dev/null +++ b/src/collective/js/tooltipster/tests/robot/test_content_selector.robot @@ -0,0 +1,13 @@ +*** Settings *** +Documentation Plone 6 only: view_content_selector was added by the Plone 6 branch (not in the Plone 4 helper). +Resource tooltipster.robot +Test Setup Open a manager browser on a document +Test Teardown Close all browsers + + +*** Test Cases *** +The view_content_selector option shows only the matching part of the view + Add a tooltip target alice Alice base_url=${DOC_URL} + Call the tooltipster helper alice options={view_content_selector: '.tt-name'} + Hover the target alice + The tooltip shows Alice diff --git a/src/collective/js/tooltipster/tests/test_setup.py b/src/collective/js/tooltipster/tests/test_setup.py index 9473ea2..4e1bc21 100644 --- a/src/collective/js/tooltipster/tests/test_setup.py +++ b/src/collective/js/tooltipster/tests/test_setup.py @@ -2,10 +2,10 @@ """Setup tests for this package.""" from collective.js.tooltipster.interfaces import ICollectiveJsTooltipsterLayer from collective.js.tooltipster.testing import COLLECTIVE_JS_TOOLTIPSTER_INTEGRATION_TESTING # noqa +from plone.base.interfaces import IBundleRegistry +from plone.base.utils import get_installer from plone.browserlayer import utils from plone.registry.interfaces import IRegistry -from Products.CMFPlone.interfaces import IBundleRegistry -from Products.CMFPlone.utils import get_installer from zope.component import getUtility import unittest @@ -31,7 +31,7 @@ def bundles(self): return {name: bundle for name, bundle in bundles.items() if name.startswith("collective.js.tooltipster.")} def test_product_installed(self): - """Test if collective.js.tooltipster is installed with portal_quickinstaller.""" + """Test if collective.js.tooltipster is installed.""" self.assertTrue(self.installer.is_product_installed("collective.js.tooltipster")) def test_static_files(self): diff --git a/src/collective/js/tooltipster/upgrades.py b/src/collective/js/tooltipster/upgrades.py deleted file mode 100644 index 7a7bbdc..0000000 --- a/src/collective/js/tooltipster/upgrades.py +++ /dev/null @@ -1,9 +0,0 @@ -# -*- coding: utf-8 -*- -from plone import api - - -def upgrade_to_2000(context): - """Reapply 'themes' profile if necessary.""" - csstool = api.portal.get_tool("portal_css") - if "++resource++collective.js.tooltipster/tooltipster-noir.css" in csstool.concatenatedresources: - context.runAllImportStepsFromProfile("collective.js.tooltipster:themes") diff --git a/travis.cfg b/test-6.2.cfg similarity index 52% rename from travis.cfg rename to test-6.2.cfg index 8fa13db..c89d127 100644 --- a/travis.cfg +++ b/test-6.2.cfg @@ -1,5 +1,7 @@ [buildout] + extends = - https://raw.githubusercontent.com/collective/buildout.plonetest/master/travis-4.3.x.cfg - buildout.cfg -parts = download install test + https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-6.2.x.cfg + base.cfg + +#update-versions-file = test-6.2.cfg From 683df830981cc8e1c80f17b3b9aac6622a64f92e Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 8 Oct 2026 13:03:54 +0200 Subject: [PATCH 13/15] Next version is 2.0.0 Co-Authored-By: Claude Opus 5.5 --- CHANGES.rst | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 8fc2c42..9abd28b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,8 +2,8 @@ Changelog ========= -1.9 (unreleased) ----------------- +2.0.0 (unreleased) +------------------ - Added Plone 6.1 version in buildout. [chris-adam] diff --git a/setup.py b/setup.py index 02780f1..f43d462 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name="collective.js.tooltipster", - version="1.9.dev0", + version="2.0.0.dev0", description="Plone integration of tooltipster jquery plugin", long_description=long_description, # Get more from http://pypi.python.org/pypi?%3Aaction=list_classifiers From 3772d36effa3c1d30a1909a3203f51919babb49b Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 8 Oct 2026 14:28:44 +0200 Subject: [PATCH 14/15] Credit laulaz in CHANGES Co-Authored-By: Claude Opus 5.5 --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 9abd28b..72d3f25 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog 2.0.0 (unreleased) ------------------ +- Migrated to Plone 6.2 / Python 3, based on the work started on `plone61` + by @chris-adam and @laulaz. + [laulaz, chris-adam] - Added Plone 6.1 version in buildout. [chris-adam] - Plone 6.2 support. Removed the Plone 4 `themes` profile and upgrade step From 01d80c1ac4a051e19a7984d8069802a9a5da4293 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 9 Oct 2026 14:25:21 +0200 Subject: [PATCH 15/15] Send ajax_load=1 so Plone 6 renders only the content Co-Authored-By: Claude Opus 5.5 --- CHANGES.rst | 2 ++ .../tooltipster/browser/static/tooltipster_helper.js | 5 ++++- .../js/tooltipster/tests/robot/test_tooltipster.robot | 6 ++++++ .../js/tooltipster/tests/robot/tooltipster.robot | 10 ++++++++-- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 72d3f25..853f04e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -17,6 +17,8 @@ Changelog positional parameter is `data_parameters` again, as callers expect), and the view is called on the context URL (`data-base-url`) when there is no `data-base_url`. [chris-adam] +- `tooltipster_helper`: send `ajax_load=1` (Plone 6 rendered the whole page for a timestamp). + [chris-adam] 1.8 (2024-02-08) ---------------- diff --git a/src/collective/js/tooltipster/browser/static/tooltipster_helper.js b/src/collective/js/tooltipster/browser/static/tooltipster_helper.js index 961d20d..9181937 100644 --- a/src/collective/js/tooltipster/browser/static/tooltipster_helper.js +++ b/src/collective/js/tooltipster/browser/static/tooltipster_helper.js @@ -51,12 +51,15 @@ function tooltipster_helper(selector, // Plone 6 has no tag: data-base-url of body is the context URL base_url = document.body.dataset.baseUrl || document.baseURI; } - parameters.ajax_load = new Date().getTime(); + // Plone 6 only takes "1"/"true"/... as true (a timestamp renders the whole page) + parameters.ajax_load = 1; $.ajax({ type: 'GET', url: base_url + '/' + view_name, data: parameters, + // cache busting (the timestamp of ajax_load did it): adds _= + cache: false, // set async: false so content is loaded when functionReady is called async: async, success: function (data) { diff --git a/src/collective/js/tooltipster/tests/robot/test_tooltipster.robot b/src/collective/js/tooltipster/tests/robot/test_tooltipster.robot index 25f4c27..6ac781a 100644 --- a/src/collective/js/tooltipster/tests/robot/test_tooltipster.robot +++ b/src/collective/js/tooltipster/tests/robot/test_tooltipster.robot @@ -34,6 +34,12 @@ Without data-base_url on a page opened with its view URL Hover the target bob The tooltip on a page opened with its view URL shows ${DOC_TITLE} Hello Bob from ${DOC_TITLE} +A page of the site is loaded without the site layout + Add a tooltip target alice Alice base_url=${DOC_URL} + Call the tooltipster helper alice view_name=view + Hover the target alice + The tooltip shows the page without the site layout ${DOC_TITLE} + The content of the view is loaded once per element Add a tooltip target alice Alice base_url=${DOC_URL} Call the tooltipster helper alice diff --git a/src/collective/js/tooltipster/tests/robot/tooltipster.robot b/src/collective/js/tooltipster/tests/robot/tooltipster.robot index 36f267d..30a8656 100644 --- a/src/collective/js/tooltipster/tests/robot/tooltipster.robot +++ b/src/collective/js/tooltipster/tests/robot/tooltipster.robot @@ -46,8 +46,8 @@ Change the data-name of the target Call the tooltipster helper [Documentation] Plone 4 positional order. data_parameters and options are JS literals. - [Arguments] ${id} ${data_parameters}=['name'] ${options}={} - Execute javascript tooltipster_helper('[id="${id}"]', '${VIEW_NAME}', ${data_parameters}, ${options}); + [Arguments] ${id} ${data_parameters}=['name'] ${options}={} ${view_name}=${VIEW_NAME} + Execute javascript tooltipster_helper('[id="${id}"]', '${view_name}', ${data_parameters}, ${options}); Hover the target [Arguments] ${id} @@ -73,6 +73,12 @@ The tooltip still shows after a while Sleep 1s The tooltip shows ${text} +The tooltip shows the page without the site layout + [Documentation] Page of the site loaded with ajax_load: its title, no portal header + [Arguments] ${title} + Wait until element contains css=.tooltipster-base h1 ${title} + Page should not contain element css=.tooltipster-base #portal-header + Every tooltip is closed Wait until page does not contain element ${TOOLTIP}