Files
HelixNotes/tests/code-block-input-scroll.test.mjs
T

96 lines
3.4 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { Schema } from '@tiptap/pm/model';
import { EditorState, Plugin, TextSelection } from '@tiptap/pm/state';
import { createCodeBlockInputScrollPlugin } from '../src/lib/editor/extensions/codeBlockInputScroll.ts';
const schema = new Schema({
nodes: {
doc: { content: 'block+' },
paragraph: { content: 'text*', group: 'block' },
codeBlock: {
attrs: { language: { default: null } },
content: 'text*',
group: 'block',
code: true,
},
text: { group: 'inline' },
},
});
const inputRulesPlugin = new Plugin({ isInputRules: true });
function textBlock(type, text, attrs = null) {
return schema.node(type, attrs, text ? [schema.text(text)] : undefined);
}
function stateWithSelection(type, text, options = {}) {
const { attrs = null, from = text.length + 1, to = from } = options;
const doc = schema.node('doc', null, [textBlock(type, text, attrs)]);
return EditorState.create({
doc,
selection: TextSelection.create(doc, from, to),
plugins: [inputRulesPlugin, createCodeBlockInputScrollPlugin()],
});
}
function convertToCodeBlock(state, language = null, { inputRule = true } = {}) {
const codeBlock = textBlock('codeBlock', '', { language });
const tr = state.tr.replaceWith(0, state.doc.content.size, codeBlock);
tr.setSelection(TextSelection.create(tr.doc, 1));
if (inputRule) {
tr.setMeta(inputRulesPlugin, {
transform: tr,
from: state.selection.from,
to: state.selection.to,
text: '\n',
});
}
return state.applyTransaction(tr);
}
function assertAppendedScroll(result) {
assert.equal(result.transactions.length, 2);
assert.equal(result.transactions[0].scrolledIntoView, false);
assert.equal(result.transactions[1].scrolledIntoView, true);
assert.equal(result.state.selection.$from.parent.type.name, 'codeBlock');
}
function assertNoAppendedScroll(result) {
assert.equal(result.transactions.length, 1);
assert.equal(result.transactions[0].scrolledIntoView, false);
}
test('appends a scroll request for backtick and tilde input-rule transitions', () => {
assertAppendedScroll(convertToCodeBlock(stateWithSelection('paragraph', '```')));
assertAppendedScroll(convertToCodeBlock(stateWithSelection('paragraph', '~~~rust'), 'rust'));
});
test('does not append a scroll request for non-fence paragraph conversions', () => {
assertNoAppendedScroll(convertToCodeBlock(stateWithSelection('paragraph', 'ordinary text')));
assertNoAppendedScroll(convertToCodeBlock(stateWithSelection('paragraph', '```TypeScript')));
assertNoAppendedScroll(convertToCodeBlock(stateWithSelection('paragraph', '````')));
});
test('does not append a scroll request for toolbar conversions or note loads', () => {
assertNoAppendedScroll(
convertToCodeBlock(stateWithSelection('paragraph', '```'), null, { inputRule: false })
);
assertNoAppendedScroll(
convertToCodeBlock(stateWithSelection('paragraph', '~~~rust'), 'rust', { inputRule: false })
);
});
test('does not append a scroll request for a non-empty fence selection', () => {
const state = stateWithSelection('paragraph', '```', { from: 1, to: 4 });
assertNoAppendedScroll(convertToCodeBlock(state));
});
test('does not append a scroll request for a transaction already in a code block', () => {
const state = stateWithSelection('codeBlock', '```');
const tr = state.tr.insertText('x');
assertNoAppendedScroll(state.applyTransaction(tr));
});