Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: Add CKEditor integration tests and update dependencies #32

Merged
merged 7 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ jobs:
python -m pip install --upgrade pip
pip install -r tests/requirements/${{ matrix.requirements-file }}
python setup.py install
npm install
npx webpack
playwright install --with-deps

- name: Run coverage
run: coverage run -m pytest
Expand Down
6 changes: 3 additions & 3 deletions private/js/cms.editor.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-env es6 */
/* jshint esversion: 6 */
/* eslint-env es11 */
/* jshint esversion: 11 */
/* global window, document, fetch, IntersectionObserver, URLSearchParams, console */

import CmsTextEditor from './cms.texteditor.js';
Expand Down Expand Up @@ -90,7 +90,7 @@ class CMSEditor {
// Add event listener to delete data on modal cancel
if (settings.revert_on_cancel) {
const CMS = this.CMS;
const csrf = CMS.config.csrf;
const csrf = CMS.config?.csrf || document.querySelector('input[name="csrfmiddlewaretoken"]').value;
CMS.API.Helpers.addEventListener(
'modal-close.text-plugin.text-plugin-' + settings.plugin_id,
function(e, opts) {
Expand Down
61 changes: 61 additions & 0 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os
import pytest
from pytest_django.live_server_helper import LiveServer
from playwright.sync_api import sync_playwright

from tests.fixtures import DJANGO_CMS4


@pytest.fixture(scope="session")
def live_server():
server = LiveServer("127.0.0.1:9090")
yield server
server.stop()


@pytest.fixture(scope="session")
def browser_context():
with sync_playwright() as p:
browser = p.chromium.launch()
context = browser.new_context()
yield context
context.close()
browser.close()


@pytest.fixture(scope="session")
def page(browser_context):
page = browser_context.new_page()
yield page
page.close()


@pytest.fixture
def user(db):
from django.contrib.auth import get_user_model

User = get_user_model()
return User.objects.create_user(username="admin", password="admin", is_staff=True, is_superuser=True)


@pytest.fixture
def cms_page(db, user):
from cms.api import create_page

return create_page("Test Page", "page.html", "en", created_by=user)


@pytest.fixture
def text_plugin(db, cms_page):
if not DJANGO_CMS4:
return None

from cms.api import add_plugin

page_content = cms_page.pagecontent_set(manager="admin_manager").current_content(language="en").first()
placeholder = page_content.get_placeholders().first()
return add_plugin(placeholder, "TextPlugin", "en", body="<p>Test content</p>")


def pytest_configure():
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
67 changes: 67 additions & 0 deletions tests/integration/test_text_editor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from unittest import skipIf

import pytest
from cms.utils.urlutils import admin_reverse
from playwright.sync_api import expect

from tests.fixtures import DJANGO_CMS4


def login(page, live_server):
page.goto(f"{live_server.url}/en/admin/")
page.fill("input[name='username']", "admin")
page.fill("input[name='password']", "admin")
page.click("input[type='submit']")
# Ensure success
expect(page.locator("h1", has_text="Site administration")).to_be_visible()


def get_pagecontent(cms_page):
return cms_page.pagecontent_set(manager="admin_manager").current_content(language="en").first()


@pytest.mark.django_db
@skipIf(not DJANGO_CMS4, reason="Integration tests only work on Django CMS 4")
def test_editor_loads(live_server, page, text_plugin):
"""Test that tiptap editor loads and initializes properly"""
# Navigate to the text plugin add view
login(page, live_server)

page.goto(f"{live_server.url}{admin_reverse('cms_placeholder_edit_plugin', args=(text_plugin.pk,))}")

editor = page.locator(".cms-editor-inline-wrapper.fixed")
expect(editor).to_be_visible() # Editor

tiptap = page.locator(".ProseMirror.tiptap")
expect(tiptap).to_be_visible() # Editor

expect(page.locator('div[role="menubar"]')).to_be_visible() # its menu bar
expect(page.locator('button[title="Bold"]')).to_be_visible() # a button in the menu bar

assert tiptap.inner_text() == "Test content"


@pytest.mark.django_db
@skipIf(not DJANGO_CMS4, reason="Integration tests only work on Django CMS 4")
def _test_text_plugin_saves(live_server, page):
"""Test that text plugin content saves correctly"""
# Navigate and login (reusing steps from above)
page.goto(f"{live_server.url}/admin/cms/page/add/")
page.fill("input[name='username']", "admin")
page.fill("input[name='password']", "admin")
page.click("input[type='submit']")

# Add and fill text plugin
page.click("text=Add plugin")
page.click("text=Text")

iframe_locator = page.frame_locator(".cke_wysiwyg_frame")
iframe_locator.locator("body").fill("Content to save")

# Save the plugin
page.click("text=Save")

# Verify saved content
page.reload()
saved_content = iframe_locator.locator("body").inner_text()
assert saved_content == "Content to save"
2 changes: 2 additions & 0 deletions tests/requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ flake8
flake8-pyproject
pytest
pytest-django
playwright>=1.42.0
pytest-playwright>=0.4.0

# other requirements
coverage
Expand Down
1 change: 1 addition & 0 deletions tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def __getitem__(self, item):
"django.contrib.sessions",
"django.contrib.admin",
"django.contrib.messages",
"django.contrib.staticfiles",
"easy_thumbnails",
"filer",
"cms",
Expand Down
10 changes: 5 additions & 5 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ def get_post_request(self, data):
def get_plugin_id_from_response(self, response):
url = unquote(response.url)
# Ideal case, this looks like:
# /en/admin/cms/page/edit-plugin/1/
return re.findall(r"\d+", url)[0]
# /en/admin/cms/placeholder/add-plugin/...?...&plugin=123
return re.findall(r"plugin=\d+", url)[0][7:]

def test_add_and_edit_plugin(self):
"""
Expand Down Expand Up @@ -632,9 +632,9 @@ def test_render_child_plugin_endpoint(self):
# <cms-plugin></cms-plugin>
rendered_child_plugin = (
"<cms-plugin render-plugin=false "
'alt="Preview Disabled Plugin - 3" '
'title="Preview Disabled Plugin - 3" '
'id="3" type="PreviewDisabledPlugin">'
f'alt="Preview Disabled Plugin - {child_plugin.pk}" '
f'title="Preview Disabled Plugin - {child_plugin.pk}" '
f'id="{child_plugin.pk}" type="PreviewDisabledPlugin">'
"<span>Preview is disabled for this plugin</span>"
"</cms-plugin>"
)
Expand Down