180 lines
8.7 KiB
Python
180 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Browser integration test for the mentioned-users bar and cyclic jumps."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import base64
|
|
from pathlib import Path
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
HTML = '''<!doctype html><html lang="pl"><head><meta charset="utf-8">
|
|
<style>__STYLES__</style>
|
|
<style>
|
|
body { padding: 20px; }
|
|
.workspace { width: min(970px, calc(100vw - 40px)); height: 400px; grid-template-columns: 1fr 1fr; }
|
|
.editor-column { display: flex; flex-direction: column; height: 100%; border: 1px solid #aaa; }
|
|
.preview-column { display: grid; min-width: 0; min-height: 0; }
|
|
.editor-shell { flex: 1 1 auto; min-height: 0; }
|
|
#editor { box-sizing: border-box; width: 100%; height: 100%; padding: 18px; line-height: 22px; }
|
|
#preview { box-sizing: border-box; width: 100%; height: 100%; overflow: auto; border: 1px solid #aaa; padding: 18px; }
|
|
</style>
|
|
</head><body class="pad-page">
|
|
<div id="editor-workspace" class="workspace view-split">
|
|
<div class="editor-column">
|
|
<div class="column-label">Editor</div>
|
|
<div class="participant-badges"><span class="participant-badge">Autor</span></div>
|
|
<div id="mentioned-users" class="mentioned-users" role="group" hidden>
|
|
<span class="mentioned-users__label">Wspomniani</span>
|
|
<div id="mentioned-users-list" class="mentioned-users__list"></div>
|
|
</div>
|
|
<div class="editor-shell"><textarea id="editor" wrap="off"></textarea></div>
|
|
</div>
|
|
<div class="preview-column">
|
|
<div id="preview-label" class="column-label">Markdown preview</div>
|
|
<div id="mentioned-users-preview" class="mentioned-users mentioned-users--preview" role="group" hidden>
|
|
<span class="mentioned-users__label">Wspomniani</span>
|
|
<div id="mentioned-users-preview-list" class="mentioned-users__list"></div>
|
|
</div>
|
|
<article class="markdown-body preview" id="preview"></article>
|
|
</div>
|
|
</div>
|
|
<script type="module">
|
|
import {createMentionNavigator} from '__NAVIGATION_URL__';
|
|
import {setMarkdownMentions,renderMarkdown} from '__MARKDOWN_URL__';
|
|
const editor = document.querySelector('#editor');
|
|
const preview = document.querySelector('#preview');
|
|
let view = 'split', members = [];
|
|
const navigator = createMentionNavigator({
|
|
container: document.querySelector('#mentioned-users'),
|
|
list: document.querySelector('#mentioned-users-list'),
|
|
previewContainer: document.querySelector('#mentioned-users-preview'),
|
|
previewList: document.querySelector('#mentioned-users-preview-list'),
|
|
editor, preview, getView: () => view, onEditorScroll: () => {},
|
|
});
|
|
window.runCase = (source, users) => {
|
|
editor.value = source; members = users;
|
|
navigator.setUsers(members);
|
|
setMarkdownMentions(members);
|
|
preview.innerHTML = renderMarkdown(source);
|
|
navigator.render({markdown:true});
|
|
};
|
|
window.setView = value => {
|
|
view=value;
|
|
document.querySelector('#editor-workspace').className = `workspace view-${value}`;
|
|
};
|
|
window.setUsers = value => {
|
|
navigator.setUsers(value);
|
|
setMarkdownMentions(value);
|
|
preview.innerHTML = renderMarkdown(editor.value);
|
|
navigator.render({markdown:true});
|
|
};
|
|
window.ready = true;
|
|
</script></body></html>'''
|
|
|
|
|
|
def as_data_url(source):
|
|
return 'data:text/javascript;base64,' + base64.b64encode(source.encode('utf-8')).decode('ascii')
|
|
|
|
|
|
def create_fixture():
|
|
autocomplete = (ROOT / 'static/js/mention-autocomplete.js').read_text()
|
|
autocomplete = autocomplete.replace('import { t } from "@rustpad/i18n";',
|
|
'const t = (key, values, fallback) => fallback;')
|
|
navigation = (ROOT / 'static/js/mention-navigation.js').read_text()
|
|
navigation = navigation.replace('import { t } from "@rustpad/i18n";',
|
|
'const t = (key, values, fallback) => fallback;')
|
|
navigation = navigation.replace('"@rustpad/mention-autocomplete"',
|
|
f'"{as_data_url(autocomplete)}"')
|
|
markdown = (ROOT / 'static/js/markdown.js').read_text()
|
|
markdown = '\n'.join(line for line in markdown.split('\n') if not line.startswith('import '))
|
|
markdown = ('const EMOJI_SHORTCODES = {}; '
|
|
'const t = (key, values, fallback) => fallback; '
|
|
'const parseImageAlias = () => null;\n') + markdown
|
|
styles = (ROOT / 'static/css/styles.css').read_text()
|
|
return (HTML.replace('__STYLES__', styles)
|
|
.replace('__NAVIGATION_URL__', as_data_url(navigation))
|
|
.replace('__MARKDOWN_URL__', as_data_url(markdown)))
|
|
|
|
|
|
def main():
|
|
fixture = create_fixture()
|
|
with sync_playwright() as playwright:
|
|
browser = playwright.chromium.launch(executable_path='/usr/bin/chromium', args=['--no-sandbox'])
|
|
try:
|
|
page = browser.new_page(viewport={'width': 1020, 'height': 680})
|
|
errors = []
|
|
page.on('pageerror', lambda error: errors.append(str(error)))
|
|
page.set_content(fixture)
|
|
page.wait_for_function('window.ready === true')
|
|
lines = [
|
|
'Na początku @Dominik i @Dominik, do tego @Dora.',
|
|
'`@Dominik` [@Dominik](https://example.com/@Dora)',
|
|
'```sh',
|
|
'@Dominik',
|
|
'```',
|
|
*[f'Wypełnienie linii {i}' for i in range(1, 18)],
|
|
'<details>',
|
|
'<summary>Szczegóły</summary>',
|
|
'Wewnątrz @Dominik',
|
|
'</details>',
|
|
*[f'Treść linii {i}' for i in range(18, 38)],
|
|
'Na końcu @Dominik.',
|
|
]
|
|
content = '\n'.join(lines)
|
|
users = [{'nickname': 'Dominik', 'color': '#123456'}, {'nickname':'Dora', 'color':'#654321', 'email':'private@example.org'}]
|
|
page.evaluate('([text,users]) => window.runCase(text,users)', [content, users])
|
|
bar = page.locator('#mentioned-users')
|
|
assert bar.is_visible()
|
|
badges = page.locator('#mentioned-users-list .mentioned-users__badge')
|
|
preview_badges = page.locator('#mentioned-users-preview-list .mentioned-users__badge')
|
|
assert page.locator('#mentioned-users-preview').is_hidden()
|
|
assert badges.count() == 2
|
|
assert preview_badges.count() == 2
|
|
assert badges.all_text_contents() == ['@Dominik4', '@Dora1']
|
|
assert 'private' not in bar.inner_text()
|
|
button = badges.first
|
|
# The two code/link occurrences are intentionally skipped.
|
|
source_starts = [content.index('@Dominik'),content.index('@Dominik',content.index('@Dominik')+1),content.index('@Dominik',content.index('Wewnątrz')), content.rindex('@Dominik')]
|
|
for step, start in enumerate(source_starts, 1):
|
|
button.click()
|
|
assert page.evaluate('document.querySelector("#editor").selectionStart') == start, step
|
|
assert page.evaluate('document.querySelector("#editor").selectionEnd') == start + len('@Dominik')
|
|
assert page.locator('.markdown-mention.is-mention-target').count() == 1
|
|
assert button.locator('.mentioned-users__count').inner_text() == f'{step}/4'
|
|
assert page.locator('details.markdown-details').evaluate('element => element.open') is True
|
|
button.click()
|
|
assert page.evaluate('document.querySelector("#editor").selectionStart') == source_starts[0]
|
|
assert button.locator('.mentioned-users__count').inner_text() == '1/4'
|
|
dora = badges.nth(1)
|
|
dora.click()
|
|
assert page.evaluate('document.querySelector("#editor").selectionStart') == content.index('@Dora')
|
|
assert dora.locator('.mentioned-users__count').inner_text() == '1/1'
|
|
page.evaluate('window.setView("preview")')
|
|
assert bar.is_hidden()
|
|
assert page.locator('#mentioned-users-preview').is_visible()
|
|
assert page.locator('#preview').is_visible()
|
|
original_selection = page.evaluate('document.querySelector("#editor").selectionStart')
|
|
preview_badges.first.click()
|
|
assert page.evaluate('document.querySelector("#editor").selectionStart') == original_selection
|
|
assert page.locator('.markdown-mention.is-mention-target').count() == 1
|
|
page.evaluate('window.setView("edit")')
|
|
assert bar.is_visible()
|
|
assert page.locator('#mentioned-users-preview').is_hidden()
|
|
button.click()
|
|
assert page.evaluate('document.querySelector("#editor").selectionStart') == source_starts[2]
|
|
page.evaluate('window.setUsers([])')
|
|
assert bar.is_hidden()
|
|
assert page.locator('#mentioned-users-preview').is_hidden()
|
|
assert badges.count() == 0
|
|
assert preview_badges.count() == 0
|
|
assert not errors, errors
|
|
print('PASS: Chromium mentions list, access, cyclic navigation, source selection, details, view switching')
|
|
finally:
|
|
browser.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|