Skip to content
Snippets Groups Projects
Unverified Commit 49cd4202 authored by Agha Awais's avatar Agha Awais Committed by GitHub
Browse files

Merge pull request #19594 from edx/awais/lett_2_bc_html_editor_II

Remaining bokchoy tests for HTML editor(II)
parents 003f2450 840ff175
No related branches found
Tags release-2020-11-02-12.26
No related merge requests found
......@@ -206,6 +206,18 @@ class ContainerPage(PageObject, HelpMixin):
"""
return self.q(css='.wrapper-xblock .level-element .header-details').text
@property
def content_html(self):
"""
Gets the html of HTML module
Returns:
list: A list containing inner HTMl
"""
self.wait_for_element_visibility('.xmodule_HtmlModule', 'Xblock content is visible')
html = self.q(css='.xmodule_HtmlModule').html
html = html[0].strip()
return html
@property
def is_staff_locked(self):
""" Returns True if staff lock is currently enabled, False otherwise """
......
from common.test.acceptance.pages.studio.utils import type_in_codemirror
from xblock_editor import XBlockEditorView
"""
HTML component editor in studio
"""
from common.test.acceptance.pages.studio.utils import type_in_codemirror, get_codemirror_value
from common.test.acceptance.pages.studio.xblock_editor import XBlockEditorView
from common.test.acceptance.pages.common.utils import click_css
......@@ -12,6 +15,62 @@ class HtmlXBlockEditorView(XBlockEditorView):
settings_tab = '.editor-modes .settings-button'
save_settings_button = '.action-save'
@property
def toolbar_dropdown_titles(self):
"""
Returns the titles of dropdowns present on the toolbar
"""
return self.q(css='.mce-listbox').text
@property
def toolbar_button_titles(self):
"""
Returns the titles of the buttons present on the toolbar
Returns:
"""
return self.q(css='.mce-ico').attrs('class')
@property
def fonts(self):
"""
Available fonts in the font dropdown
Returns:
(list): A list of font names
"""
return self.q(css='.mce-text').text
@property
def font_families(self):
"""
Available font families against each font
Returns:
(list): A list of font families
"""
return self.q(css='.mce-text').attrs('style')
def open_font_dropdown(self):
"""
Clicks and waits for font dropdown to open
"""
self.q(css='#mce_2-open').first.click()
self.wait_for_element_visibility('.mce-floatpanel', 'Dropdown is Visible')
def font_dict(self):
"""
Creates a dictionary with font labels and font families
Returns:
font_dict(dict): A dictionary of font labels as keys and font families as values
"""
font_labels = self.fonts
font_families = self.font_families
for index, font in enumerate(font_families):
font = font.replace('font-family: ', '').replace(';', '')
font_families[index] = font.split(',')
font_families[index] = [x.lstrip() for x in font_families[index]]
font_dict = dict(zip(font_labels, font_families))
return font_dict
def set_content_and_save(self, content, raw=False):
"""Types content into the html component and presses Save.
......@@ -74,6 +133,13 @@ class HtmlXBlockEditorView(XBlockEditorView):
"""
click_css(self, self.save_settings_button)
def open_raw_editor(self):
"""
Clicks and waits for raw editor to open
"""
self.q(css='[aria-label="Edit HTML"]').click()
self.wait_for_element_visibility('.mce-title', 'Wait for CodeMirror editor')
def open_link_plugin(self):
"""
Opens up the link plugin on editor
......@@ -95,6 +161,13 @@ class HtmlXBlockEditorView(XBlockEditorView):
"""
return self.q(css="#tinymce>p>a").attrs('href')[0]
@property
def editor_value(self):
"""
Returns codemirror value from raw HTMl editor
"""
return get_codemirror_value(self, 0)
def switch_to_iframe(self):
"""
Switches to the editor iframe
......@@ -109,6 +182,23 @@ class HtmlXBlockEditorView(XBlockEditorView):
self.open_link_plugin()
return self.browser.execute_script('return $(".mce-textbox").val();')
def set_text_and_select(self, text):
"""
Sets and selects text from html editor
"""
script = """
var editor = tinyMCE.activeEditor;
editor.setContent(arguments[0]);
editor.selection.select(editor.dom.select('p')[0]);"""
self.browser.execute_script(script, str(text))
self.wait_for_ajax()
def click_code_toolbar_button(self):
"""
Clicks on the code plugin on the toolbar
"""
self.q(css='.mce-i-none').first.click()
def get_default_settings(self):
"""
Returns default display name and editor
......@@ -138,6 +228,12 @@ class HtmlXBlockEditorView(XBlockEditorView):
"""
click_css(self, '.save-button')
def save_content(self):
"""
Click save button
"""
click_css(self, '.action-save')
class HTMLEditorIframe(XBlockEditorView):
"""
......
"""
Acceptance tests for HTML component in studio
"""
from common.test.acceptance.pages.studio.utils import type_in_codemirror
from common.test.acceptance.tests.studio.base_studio_test import ContainerBase
from common.test.acceptance.fixtures.course import XBlockFixtureDesc
from common.test.acceptance.pages.studio.container import ContainerPage, XBlockWrapper
......@@ -8,7 +9,7 @@ from common.test.acceptance.pages.studio.utils import add_component
from common.test.acceptance.pages.studio.html_component_editor import HtmlXBlockEditorView, HTMLEditorIframe
class HTMLComponentEditor(ContainerBase):
class HTMLComponentEditorTests(ContainerBase):
"""
Feature: CMS.Component Adding
As a course author, I want to be able to add and edit HTML component
......@@ -17,17 +18,13 @@ class HTMLComponentEditor(ContainerBase):
"""
Create a course with a section, subsection, and unit to which to add the component.
"""
super(HTMLComponentEditor, self).setUp(is_staff=is_staff)
self.component = 'Text'
super(HTMLComponentEditorTests, self).setUp(is_staff=is_staff)
self.unit = self.go_to_unit_page()
self.container_page = ContainerPage(self.browser, None)
self.xblock_wrapper = XBlockWrapper(self.browser, None)
# Add HTML component
add_component(self.container_page, 'html', self.component)
self.component = self.unit.xblocks[1]
self.container_page.edit()
self.html_editor = HtmlXBlockEditorView(self.browser, self.component.locator)
self.iframe = HTMLEditorIframe(self.browser, self.component.locator)
self.component = None
self.html_editor = None
self.iframe = None
def populate_course_fixture(self, course_fixture):
"""
......@@ -41,6 +38,29 @@ class HTMLComponentEditor(ContainerBase):
)
)
def _add_content(self, content):
"""
Set and save content in editor and assert its presence in container page's html
Args:
content(str): Verifiable content
"""
self.html_editor.set_raw_content(content)
self.html_editor.save_content()
self.container_page.wait_for_page()
def _add_component(self, sub_type):
"""
Add sub-type of HTML component in studio
Args:
sub_type(str): Sub-type of HTML component
"""
add_component(self.container_page, 'html', sub_type)
self.component = self.unit.xblocks[1]
self.html_editor = HtmlXBlockEditorView(self.browser, self.component.locator)
self.iframe = HTMLEditorIframe(self.browser, self.component.locator)
def test_user_can_view_metadata(self):
"""
Scenario: User can view metadata
......@@ -48,6 +68,10 @@ class HTMLComponentEditor(ContainerBase):
And I edit and select Settings
Then I see the HTML component settings
"""
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
self.html_editor.open_settings_tab()
display_name_value = self.html_editor.get_default_settings()[0]
display_name_key = self.html_editor.keys[0]
......@@ -72,6 +96,9 @@ class HTMLComponentEditor(ContainerBase):
Then I can modify the display name
And my display name change is persisted on save
"""
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
self.html_editor.open_settings_tab()
self.html_editor.set_field_val('Display Name', 'New Name')
self.html_editor.save_settings()
......@@ -88,6 +115,10 @@ class HTMLComponentEditor(ContainerBase):
And the link is shown as "/static/image.jpg" in the Link Plugin
"""
static_link = '/static/image.jpg'
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
self.html_editor.open_link_plugin()
self.html_editor.save_static_link(static_link)
self.html_editor.switch_to_iframe()
......@@ -100,3 +131,234 @@ class HTMLComponentEditor(ContainerBase):
static_link,
"URL in the link plugin is different"
)
def test_tinymce_and_codemirror_preserve_style_tags(self):
"""
Scenario: TinyMCE and CodeMirror preserve style tags
Given I have created a Blank HTML Page
When I edit the page
And type "<p class='title'>pages</p><style><!-- .title { color: red; } --></style>" in the code editor and
press OK
And I save the page
Then the page text contains:
""
<p class="title">pages</p>
<style><!--
.title { color: red; }
--></style>
""
"""
content = '<p class="title">pages</p><style><!-- .title { color: red; } --></style>'
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
self._add_content(content)
html = self.container_page.content_html
self.assertIn(content, html)
def test_tinymce_and_codemirror_preserve_span_tags(self):
"""
Scenario: TinyMCE and CodeMirror preserve span tags
Given I have created a Blank HTML Page
When I edit the page
And type "<span>Test</span>" in the code editor and press OK
And I save the page
Then the page text contains:
""
<span>Test</span>
""
"""
content = "<span>Test</span>"
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
self._add_content(content)
html = self.container_page.content_html
self.assertIn(content, html)
def test_tinymce_and_codemirror_preserve_math_tags(self):
"""
Scenario: TinyMCE and CodeMirror preserve math tags
Given I have created a Blank HTML Page
When I edit the page
And type "<math><msup><mi>x</mi><mn>2</mn></msup></math>" in the code editor and press OK
And I save the page
Then the page text contains:
""
<math><msup><mi>x</mi><mn>2</mn></msup></math>
""
"""
content = "<math><msup><mi>x</mi><mn>2</mn></msup></math>"
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
self._add_content(content)
html = self.container_page.content_html
self.assertIn(content, html)
def test_code_format_toolbar_wraps_text_with_code_tags(self):
"""
Scenario: Code format toolbar button wraps text with code tags
Given I have created a Blank HTML Page
When I edit the page
And I set the text to "display as code" and I select the text
And I save the page
Then the page text contains:
""
<p><code>display as code</code></p>
""
"""
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
self.html_editor.set_text_and_select("display as code")
self.html_editor.click_code_toolbar_button()
self.html_editor.save_content()
html = self.container_page.content_html
self.assertIn(html, '<p><code>display as code</code></p>')
def test_raw_html_component_does_not_change_text(self):
"""
Scenario: Raw HTML component does not change text
Given I have created a raw HTML component
When I edit the page
And type "<li>zzzz<ol> " into the Raw Editor
And I save the page
Then the page text contains:
""
<li>zzzz<ol>
""
And I edit the page
Then the Raw Editor contains exactly:
""
<li>zzzz<ol>
""
"""
content = "<li>zzzz</li>"
# Add Raw HTML type component
self._add_component('Raw HTML')
self.container_page.edit()
# Set content in tinymce editor
type_in_codemirror(self.html_editor, 0, content)
self.html_editor.save_content()
# The HTML of the content added through tinymce editor
html = self.container_page.content_html
# The text content should be present with its tag preserved
self.assertIn(content, html)
self.container_page.edit()
editor_value = self.html_editor.editor_value
# The tinymce editor value should not be different from the content added in the start
self.assertEqual(content, editor_value)
def test_tinymce_toolbar_buttons_are_as_expected(self):
"""
Scenario: TinyMCE toolbar buttons are as expected
Given I have created a Blank HTML Page
When I edit the page
Then the expected toolbar buttons are displayed
"""
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
expected_buttons = [
u'bold',
u'italic',
u'underline',
u'forecolor',
# This is our custom "code style" button, which uses an image instead of a class.
u'none',
u'alignleft',
u'aligncenter',
u'alignright',
u'alignjustify',
u'bullist',
u'numlist',
u'outdent',
u'indent',
u'blockquote',
u'link',
u'unlink',
u'image'
]
toolbar_dropdowns = self.html_editor.toolbar_dropdown_titles
# The toolbar is divided in two sections: drop-downs and all other formatting buttons
# The assertions under asserts for the drop-downs
self.assertEqual(len(toolbar_dropdowns), 2)
self.assertEqual(['Paragraph', 'Font Family'], toolbar_dropdowns)
toolbar_buttons = self.html_editor.toolbar_button_titles
# The assertions under asserts for all the remaining formatting buttons
self.assertEqual(len(toolbar_buttons), len(expected_buttons))
for index, button in enumerate(expected_buttons):
class_name = toolbar_buttons[index]
self.assertEqual("mce-ico mce-i-" + button, class_name)
def test_static_links_converted(self):
"""
Scenario: Static links are converted when switching between code editor and WYSIWYG views
Given I have created a Blank HTML Page
When I edit the page
And type "<img src="/static/image.jpg">" in the code editor and press OK
Then the src link is rewritten to the asset link /asset-v1:(course_id)+type@asset+block/image.jpg
And the code editor displays "<p><img src="/static/image.jpg" /></p>"
"""
value = '<img src="/static/image.jpg">'
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
self.html_editor.set_raw_content(value)
self.html_editor.save_content()
html = self.container_page.content_html
src = "/asset-v1:{}+type@asset+block/image.jpg".format(self.course_id.strip('course-v1:'))
self.assertIn(src, html)
self.container_page.edit()
self.html_editor.open_raw_editor()
editor_value = self.html_editor.editor_value
self.assertEqual(value, editor_value)
def test_font_selection_dropdown(self):
"""
Scenario: Font selection dropdown contains Default font and tinyMCE builtin fonts
Given I have created a Blank HTML Page
When I edit the page
And I click font selection dropdown
Then I should see a list of available fonts
And "Default" fonts should be available
And all standard tinyMCE fonts should be available
"""
# Add HTML Text type component
self._add_component('Text')
self.container_page.edit()
EXPECTED_FONTS = {
u"Default": [u'"Open Sans"', u'Verdana', u'Arial', u'Helvetica', u'sans-serif'],
u"Andale Mono": [u'andale mono', u'times'],
u"Arial": [u'arial', u'helvetica', u'sans-serif'],
u"Arial Black": [u'arial black', u'avant garde'],
u"Book Antiqua": [u'book antiqua', u'palatino'],
u"Comic Sans MS": [u'comic sans ms', u'sans-serif'],
u"Courier New": [u'courier new', u'courier'],
u"Georgia": [u'georgia', u'palatino'],
u"Helvetica": [u'helvetica'],
u"Impact": [u'impact', u'chicago'],
u"Symbol": [u'symbol'],
u"Tahoma": [u'tahoma', u'arial', u'helvetica', u'sans-serif'],
u"Terminal": [u'terminal', u'monaco'],
u"Times New Roman": [u'times new roman', u'times'],
u"Trebuchet MS": [u'trebuchet ms', u'geneva'],
u"Verdana": [u'verdana', u'geneva'],
# tinyMCE does not set font-family on dropdown span for these two fonts
u"Webdings": [u""], # webdings
u"Wingdings": [u""] # wingdings
}
self.html_editor.open_font_dropdown()
self.assertDictContainsSubset(EXPECTED_FONTS, self.html_editor.font_dict())
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment