bug fixes and wysiwyg behaviour improvements
This commit is contained in:
@@ -534,3 +534,18 @@ describe('Backslash-escaped HTML tags', () => {
|
||||
expect(rehtml).toBe(rehtml2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Table cell round-trip', () => {
|
||||
it('inline formatting in cells survives round-trip', () => {
|
||||
const html = '<table><thead><tr><th>A</th><th>B</th></tr></thead><tbody><tr><td><strong>bold</strong></td><td><em>italic</em></td></tr></tbody></table>';
|
||||
expect(H(M(html))).toBe(html);
|
||||
});
|
||||
it('code in cells survives round-trip', () => {
|
||||
const html = '<table><thead><tr><th>A</th></tr></thead><tbody><tr><td><code>x</code></td></tr></tbody></table>';
|
||||
expect(H(M(html))).toBe(html);
|
||||
});
|
||||
it('literal * in cells survives round-trip', () => {
|
||||
const html = '<table><thead><tr><th>A</th></tr></thead><tbody><tr><td>2 * 3</td></tr></tbody></table>';
|
||||
expect(H(M(html))).toBe(html);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -318,6 +318,67 @@ async function runTests() {
|
||||
assert(html.includes('<blockquote'), `No blockquote after "> ": ${html}`);
|
||||
});
|
||||
|
||||
await test('enter inside blockquote adds new line', async () => {
|
||||
await resetEditor();
|
||||
await typeString('> first line');
|
||||
let html = await getHTML();
|
||||
assert(html.includes('<blockquote'), `No blockquote: ${html}`);
|
||||
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('second line');
|
||||
html = await getHTML();
|
||||
|
||||
// Both lines must be inside the same blockquote
|
||||
const blockquoteCount = (html.match(/<blockquote/g) || []).length;
|
||||
assert(blockquoteCount === 1, `Expected 1 blockquote, got ${blockquoteCount}: ${html}`);
|
||||
assert(html.includes('first line'), `Missing first line: ${html}`);
|
||||
assert(html.includes('second line'), `Missing second line: ${html}`);
|
||||
// The two lines must be separate — not merged into one string
|
||||
assert(!html.includes('first linesecond'), `Lines merged without break: ${html}`);
|
||||
|
||||
// Markdown should be "> foo\n> bar" — continuation, no blank lines
|
||||
const markdown = await getMarkdown();
|
||||
assert(markdown.includes('> first line'), `Missing > first line in markdown: ${markdown}`);
|
||||
assert(markdown.includes('> second line'), `Missing > second line in markdown: ${markdown}`);
|
||||
assert(!markdown.includes('>\n>'), `Unwanted blank > line in markdown: ${markdown}`);
|
||||
});
|
||||
|
||||
await test('blockquote paragraphs survive mode round-trip', async () => {
|
||||
await resetEditor();
|
||||
await typeString('> foo');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('bar');
|
||||
await driver.sleep(50);
|
||||
|
||||
// Switch to source and back to wysiwyg twice
|
||||
await driver.executeScript('window.__ribbitEditor.edit()');
|
||||
await driver.sleep(50);
|
||||
await driver.executeScript('window.__ribbitEditor.wysiwyg()');
|
||||
await driver.sleep(50);
|
||||
await driver.executeScript('window.__ribbitEditor.edit()');
|
||||
await driver.sleep(50);
|
||||
|
||||
const markdown = await driver.executeScript('return document.getElementById("ribbit").textContent');
|
||||
assert(markdown.includes('> foo'), `Missing > foo: ${markdown}`);
|
||||
assert(markdown.includes('> bar'), `Missing > bar — second line lost its prefix: ${markdown}`);
|
||||
});
|
||||
|
||||
await test('double enter exits blockquote', async () => {
|
||||
await resetEditor();
|
||||
await typeString('> quoted');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('after');
|
||||
const html = await getHTML();
|
||||
assert(html.includes('<blockquote'), `No blockquote: ${html}`);
|
||||
assert(html.includes('quoted'), `Missing quoted text: ${html}`);
|
||||
assert(html.includes('after'), `Missing text after blockquote: ${html}`);
|
||||
// "after" should NOT be inside the blockquote
|
||||
const afterBlockquote = html.indexOf('</blockquote');
|
||||
const afterText = html.indexOf('after');
|
||||
assert(afterText > afterBlockquote, `"after" is inside blockquote: ${html}`);
|
||||
});
|
||||
|
||||
// ── Horizontal rule ──
|
||||
|
||||
console.log(' Horizontal rule:');
|
||||
@@ -412,6 +473,99 @@ async function runTests() {
|
||||
assert(!html.includes('data-speculative'), `Speculative not closed: ${html}`);
|
||||
});
|
||||
|
||||
console.log(' Enter behavior:');
|
||||
|
||||
await test('block pattern after Enter splits and transforms', async () => {
|
||||
await resetEditor();
|
||||
await typeString('foo');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('> bar');
|
||||
await driver.sleep(50);
|
||||
const html = await getHTML();
|
||||
assert(html.includes('<blockquote'), `> after Enter did not create blockquote: ${html}`);
|
||||
assert(html.includes('foo'), `Lost content before split: ${html}`);
|
||||
assert(html.includes('bar'), `Lost content after split: ${html}`);
|
||||
});
|
||||
|
||||
await test('single Enter in paragraph inserts line break', async () => {
|
||||
await resetEditor();
|
||||
await typeString('line one');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('line two');
|
||||
const markdown = await getMarkdown();
|
||||
// Single Enter = one \n, not \n\n
|
||||
assert(markdown.includes('line one'), `Missing line one: ${markdown}`);
|
||||
assert(markdown.includes('line two'), `Missing line two: ${markdown}`);
|
||||
assert(!markdown.includes('line one\n\nline two'), `Got paragraph break instead of line break: ${markdown}`);
|
||||
});
|
||||
|
||||
await test('double Enter in paragraph creates new block', async () => {
|
||||
await resetEditor();
|
||||
await typeString('first paragraph');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('second paragraph');
|
||||
const html = await getHTML();
|
||||
// Double Enter = new <p>, so two separate paragraphs
|
||||
const paragraphCount = (html.match(/<p[\s>]/g) || []).length;
|
||||
assert(paragraphCount >= 2, `Expected 2+ paragraphs, got ${paragraphCount}: ${html}`);
|
||||
});
|
||||
|
||||
await test('backspace at start of line after Enter joins lines', async () => {
|
||||
await resetEditor();
|
||||
await typeString('foo');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeChar(Key.BACK_SPACE);
|
||||
await driver.sleep(50);
|
||||
const html = await getHTML();
|
||||
// The <br> should be removed, cursor at end of "foo"
|
||||
assert(!html.includes('<br'), `<br> not removed: ${html}`);
|
||||
assert(html.includes('foo'), `Content lost: ${html}`);
|
||||
});
|
||||
|
||||
await test('single Enter in list item inserts line break', async () => {
|
||||
await resetEditor();
|
||||
await typeString('- line one');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('line two');
|
||||
const markdown = await getMarkdown();
|
||||
// Both lines in the same list item
|
||||
assert(markdown.includes('- line one'), `Missing list marker: ${markdown}`);
|
||||
assert(markdown.includes('line two'), `Missing line two: ${markdown}`);
|
||||
// Should NOT create a second list item
|
||||
const markerCount = (markdown.match(/^- /gm) || []).length;
|
||||
assert(markerCount === 1, `Expected 1 list marker, got ${markerCount}: ${markdown}`);
|
||||
});
|
||||
|
||||
await test('double Enter in list item creates new item', async () => {
|
||||
await resetEditor();
|
||||
await typeString('- first');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('second');
|
||||
const markdown = await getMarkdown();
|
||||
const markerCount = (markdown.match(/^- /gm) || []).length;
|
||||
assert(markerCount === 2, `Expected 2 list markers, got ${markerCount}: ${markdown}`);
|
||||
assert(markdown.includes('- first'), `Missing first item: ${markdown}`);
|
||||
assert(markdown.includes('- second'), `Missing second item: ${markdown}`);
|
||||
});
|
||||
|
||||
await test('double Enter on empty list item exits list', async () => {
|
||||
await resetEditor();
|
||||
await typeString('- item');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeChar(Key.ENTER);
|
||||
await typeChar(Key.ENTER);
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('after list');
|
||||
const html = await getHTML();
|
||||
assert(html.includes('after list'), `Missing text after list: ${html}`);
|
||||
// "after list" should NOT be inside the <ul>
|
||||
const ulEnd = html.indexOf('</ul>');
|
||||
const afterPos = html.indexOf('after list');
|
||||
assert(afterPos > ulEnd, `"after list" is inside the list: ${html}`);
|
||||
});
|
||||
|
||||
// ── Complex document ──
|
||||
|
||||
console.log(' Complex document:');
|
||||
@@ -422,6 +576,7 @@ async function runTests() {
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('Some **bold** text.');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('## Section');
|
||||
await typeChar(Key.ENTER);
|
||||
await typeString('- item one');
|
||||
@@ -474,6 +629,32 @@ async function runTests() {
|
||||
assert(html.includes('<ul') || html.includes('<li'), `No list after "+ ": ${html}`);
|
||||
});
|
||||
|
||||
console.log(' Underscore emphasis:');
|
||||
|
||||
await test('_text_ transforms to italic (shows * delimiters)', async () => {
|
||||
await resetEditor();
|
||||
await typeString('_hello_');
|
||||
const html = await getHTML();
|
||||
assert(html.includes('<em'), `No <em> after _hello_: ${html}`);
|
||||
assert(!html.includes('data-speculative'), `Still speculative: ${html}`);
|
||||
});
|
||||
|
||||
await test('_text shows speculative italic', async () => {
|
||||
await resetEditor();
|
||||
await typeString('_hel');
|
||||
const html = await getHTML();
|
||||
assert(html.includes('<em'), `No <em> after _hel: ${html}`);
|
||||
assert(html.includes('data-speculative'), `Not speculative: ${html}`);
|
||||
});
|
||||
|
||||
await test('__text__ transforms to bold', async () => {
|
||||
await resetEditor();
|
||||
await typeString('__hello__');
|
||||
const html = await getHTML();
|
||||
assert(html.includes('<strong'), `No <strong> after __hello__: ${html}`);
|
||||
assert(!html.includes('data-speculative'), `Still speculative: ${html}`);
|
||||
});
|
||||
|
||||
console.log(' Backslash escapes:');
|
||||
|
||||
await test('backslash is just a character in WYSIWYG', async () => {
|
||||
|
||||
Reference in New Issue
Block a user