mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-25 01:46:14 -04:00
Moved to ts (#6593)
* Moved to ts * Fixed type check * Removed js suffixes * Migrated to ts * Fixed ts. * Fixed type check * Installed missing d ts
This commit is contained in:
parent
5ee2c4e7f8
commit
7e3ad03e2f
81 changed files with 961 additions and 830 deletions
|
@ -1,17 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
const AttributeMap = require('../../../static/js/AttributeMap.js');
|
||||
const AttributePool = require('../../../static/js/AttributePool');
|
||||
const attributes = require('../../../static/js/attributes');
|
||||
import AttributeMap from '../../../static/js/AttributeMap';
|
||||
import AttributePool from '../../../static/js/AttributePool';
|
||||
import attributes from '../../../static/js/attributes';
|
||||
import {expect, describe, it, beforeEach} from 'vitest'
|
||||
import {Attribute} from "../../../static/js/types/Attribute";
|
||||
|
||||
describe('AttributeMap', function () {
|
||||
const attribs = [
|
||||
const attribs: Attribute[] = [
|
||||
['foo', 'bar'],
|
||||
['baz', 'bif'],
|
||||
['emptyValue', ''],
|
||||
];
|
||||
let pool: { eachAttrib: (arg0: () => number) => void; putAttrib: (arg0: string[]) => any; getAttrib: (arg0: number) => any; };
|
||||
let pool: AttributePool;
|
||||
|
||||
const getPoolSize = () => {
|
||||
let n = 0;
|
||||
|
@ -70,12 +71,14 @@ describe('AttributeMap', function () {
|
|||
describe(desc as string, function () {
|
||||
it('key is coerced to string', async function () {
|
||||
const m = new AttributeMap(pool);
|
||||
// @ts-ignore
|
||||
m.set(input, 'value');
|
||||
expect(m.get(want)).to.equal('value');
|
||||
});
|
||||
|
||||
it('value is coerced to string', async function () {
|
||||
const m = new AttributeMap(pool);
|
||||
// @ts-ignore
|
||||
m.set('key', input);
|
||||
expect(m.get('key')).to.equal(want);
|
||||
});
|
||||
|
@ -122,6 +125,7 @@ describe('AttributeMap', function () {
|
|||
// @ts-ignore
|
||||
args[0] = attributes.attribsToString(attributes.sort([...args[0]]), pool);
|
||||
}
|
||||
// @ts-ignore
|
||||
return AttributeMap.prototype[funcName].call(m, ...args);
|
||||
};
|
||||
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
|
||||
import {APool} from "../../../node/types/PadType";
|
||||
|
||||
const AttributePool = require('../../../static/js/AttributePool');
|
||||
const attributes = require('../../../static/js/attributes');
|
||||
import AttributePool from '../../../static/js/AttributePool';
|
||||
import attributes from '../../../static/js/attributes';
|
||||
|
||||
import {expect, describe, it, beforeEach} from 'vitest';
|
||||
import {Attribute} from "../../../static/js/types/Attribute";
|
||||
|
||||
describe('attributes', function () {
|
||||
const attribs = [['foo', 'bar'], ['baz', 'bif']];
|
||||
let pool: APool;
|
||||
const attribs: Attribute[] = [['foo', 'bar'], ['baz', 'bif']];
|
||||
let pool: AttributePool;
|
||||
|
||||
beforeEach(async function () {
|
||||
pool = new AttributePool();
|
||||
|
@ -45,6 +46,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, want] of testCases) {
|
||||
it(`${JSON.stringify(input)} -> ${JSON.stringify(want)}`, async function () {
|
||||
// @ts-ignore
|
||||
const got = [...attributes.decodeAttribString(input)];
|
||||
expect(JSON.stringify(got)).to.equal(JSON.stringify(want));
|
||||
});
|
||||
|
@ -61,6 +63,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [desc, input] of testCases) {
|
||||
it(desc as string, async function () {
|
||||
// @ts-ignore
|
||||
expect(attributes.encodeAttribString(input)).to.equal('*0*1');
|
||||
});
|
||||
}
|
||||
|
@ -78,6 +81,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, wantErr] of testCases) {
|
||||
it(JSON.stringify(input), async function () {
|
||||
// @ts-ignore
|
||||
expect(() => attributes.encodeAttribString(input)).toThrowError(wantErr as RegExp);
|
||||
});
|
||||
}
|
||||
|
@ -97,6 +101,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, want] of testCases) {
|
||||
it(`${JSON.stringify(input)} -> ${JSON.stringify(want)}`, async function () {
|
||||
// @ts-ignore
|
||||
expect(attributes.encodeAttribString(input)).to.equal(want);
|
||||
});
|
||||
}
|
||||
|
@ -117,6 +122,7 @@ describe('attributes', function () {
|
|||
|
||||
for (const [desc, input] of testCases) {
|
||||
it(desc as string, async function () {
|
||||
// @ts-ignore
|
||||
const gotAttribs = [...attributes.attribsFromNums(input, pool)];
|
||||
expect(JSON.stringify(gotAttribs)).to.equal(JSON.stringify(attribs));
|
||||
});
|
||||
|
@ -136,6 +142,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, wantErr] of testCases) {
|
||||
it(JSON.stringify(input), async function () {
|
||||
// @ts-ignore
|
||||
expect(() => [...attributes.attribsFromNums(input, pool)]).toThrowError(wantErr as RegExp);
|
||||
});
|
||||
}
|
||||
|
@ -151,6 +158,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, want] of testCases) {
|
||||
it(`${JSON.stringify(input)} -> ${JSON.stringify(want)}`, async function () {
|
||||
// @ts-ignore
|
||||
const gotAttribs = [...attributes.attribsFromNums(input, pool)];
|
||||
expect(JSON.stringify(gotAttribs)).to.equal(JSON.stringify(want));
|
||||
});
|
||||
|
@ -172,6 +180,7 @@ describe('attributes', function () {
|
|||
|
||||
for (const [desc, input] of testCases) {
|
||||
it(desc as string, async function () {
|
||||
// @ts-ignore
|
||||
const gotNums = [...attributes.attribsToNums(input, pool)];
|
||||
expect(JSON.stringify(gotNums)).to.equal(JSON.stringify([0, 1]));
|
||||
});
|
||||
|
@ -182,6 +191,7 @@ describe('attributes', function () {
|
|||
const testCases = [null, [null]];
|
||||
for (const input of testCases) {
|
||||
it(JSON.stringify(input), async function () {
|
||||
// @ts-ignore
|
||||
expect(() => [...attributes.attribsToNums(input, pool)]).toThrowError();
|
||||
});
|
||||
}
|
||||
|
@ -197,6 +207,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, want] of testCases) {
|
||||
it(`${JSON.stringify(input)} -> ${JSON.stringify(want)}`, async function () {
|
||||
// @ts-ignore
|
||||
const got = [...attributes.attribsToNums(input, pool)];
|
||||
expect(JSON.stringify(got)).to.equal(JSON.stringify(want));
|
||||
});
|
||||
|
@ -211,6 +222,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, want] of testCases) {
|
||||
it(`${JSON.stringify(input)} -> ${JSON.stringify(want)}`, async function () {
|
||||
// @ts-ignore
|
||||
const got = [...attributes.attribsToNums(input, pool)];
|
||||
expect(JSON.stringify(got)).to.equal(JSON.stringify(want));
|
||||
expect(JSON.stringify(pool.getAttrib(attribs.length)))
|
||||
|
@ -234,6 +246,7 @@ describe('attributes', function () {
|
|||
['value is coerced to string', [['key', inputVal]], [['key', wantVal]]],
|
||||
]) {
|
||||
it(desc as string, async function () {
|
||||
// @ts-ignore
|
||||
const gotNums = [...attributes.attribsToNums(inputAttribs, pool)];
|
||||
// Each attrib in inputAttribs is expected to be new to the pool.
|
||||
const wantNums = [...Array(attribs.length + 1).keys()].slice(attribs.length);
|
||||
|
@ -265,6 +278,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, wantErr] of testCases) {
|
||||
it(JSON.stringify(input), async function () {
|
||||
// @ts-ignore
|
||||
expect(() => [...attributes.attribsFromString(input, pool)]).toThrowError(wantErr);
|
||||
});
|
||||
}
|
||||
|
@ -280,6 +294,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, want] of testCases) {
|
||||
it(`${JSON.stringify(input)} -> ${JSON.stringify(want)}`, async function () {
|
||||
// @ts-ignore
|
||||
const gotAttribs = [...attributes.attribsFromString(input, pool)];
|
||||
expect(JSON.stringify(gotAttribs)).to.equal(JSON.stringify(want));
|
||||
});
|
||||
|
@ -297,6 +312,7 @@ describe('attributes', function () {
|
|||
|
||||
for (const [desc, input] of testCases) {
|
||||
it(desc as string, async function () {
|
||||
// @ts-ignore
|
||||
const got = attributes.attribsToString(input, pool);
|
||||
expect(got).to.equal('*0*1');
|
||||
});
|
||||
|
@ -307,6 +323,7 @@ describe('attributes', function () {
|
|||
const testCases = [null, [null]];
|
||||
for (const input of testCases) {
|
||||
it(JSON.stringify(input), async function () {
|
||||
// @ts-ignore
|
||||
expect(() => attributes.attribsToString(input, pool)).toThrowError();
|
||||
});
|
||||
}
|
||||
|
@ -322,6 +339,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, want] of testCases) {
|
||||
it(`${JSON.stringify(input)} -> ${JSON.stringify(want)}`, async function () {
|
||||
// @ts-ignore
|
||||
const got = attributes.attribsToString(input, pool);
|
||||
expect(got).to.equal(want);
|
||||
});
|
||||
|
@ -336,6 +354,7 @@ describe('attributes', function () {
|
|||
];
|
||||
for (const [input, want] of testCases) {
|
||||
it(`${JSON.stringify(input)} -> ${JSON.stringify(want)}`, async function () {
|
||||
// @ts-ignore
|
||||
const got = attributes.attribsToString(input, pool);
|
||||
expect(got).to.equal(want);
|
||||
expect(JSON.stringify(pool.getAttrib(attribs.length)))
|
||||
|
|
|
@ -1,398 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
* While importexport tests target the `setHTML` API endpoint, which is nearly identical to what
|
||||
* happens when a user manually imports a document via the UI, the contentcollector tests here don't
|
||||
* use rehype to process the document. Rehype removes spaces and newĺines were applicable, so the
|
||||
* expected results here can differ from importexport.js.
|
||||
*
|
||||
* If you add tests here, please also add them to importexport.js
|
||||
*/
|
||||
|
||||
import {APool} from "../../../node/types/PadType";
|
||||
|
||||
const AttributePool = require('../../../static/js/AttributePool');
|
||||
const Changeset = require('../../../static/js/Changeset');
|
||||
const assert = require('assert').strict;
|
||||
const attributes = require('../../../static/js/attributes');
|
||||
const contentcollector = require('../../../static/js/contentcollector');
|
||||
const jsdom = require('jsdom');
|
||||
|
||||
import {describe, it, beforeAll, test} from 'vitest';
|
||||
|
||||
// All test case `wantAlines` values must only refer to attributes in this list so that the
|
||||
// attribute numbers do not change due to changes in pool insertion order.
|
||||
const knownAttribs = [
|
||||
['insertorder', 'first'],
|
||||
['italic', 'true'],
|
||||
['list', 'bullet1'],
|
||||
['list', 'bullet2'],
|
||||
['list', 'number1'],
|
||||
['list', 'number2'],
|
||||
['lmkr', '1'],
|
||||
['start', '1'],
|
||||
['start', '2'],
|
||||
];
|
||||
|
||||
const testCases = [
|
||||
{
|
||||
description: 'Simple',
|
||||
html: '<html><body><p>foo</p></body></html>',
|
||||
wantAlines: ['+3'],
|
||||
wantText: ['foo'],
|
||||
},
|
||||
{
|
||||
description: 'Line starts with asterisk',
|
||||
html: '<html><body><p>*foo</p></body></html>',
|
||||
wantAlines: ['+4'],
|
||||
wantText: ['*foo'],
|
||||
},
|
||||
{
|
||||
description: 'Complex nested Li',
|
||||
html: '<!doctype html><html><body><ol><li>one</li><li><ol><li>1.1</li></ol></li><li>two</li></ol></body></html>',
|
||||
wantAlines: [
|
||||
'*0*4*6*7+1+3',
|
||||
'*0*5*6*8+1+3',
|
||||
'*0*4*6*8+1+3',
|
||||
],
|
||||
wantText: [
|
||||
'*one', '*1.1', '*two',
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'Complex list of different types',
|
||||
html: '<!doctype html><html><body><ul class="bullet"><li>one</li><li>two</li><li>0</li><li>1</li><li>2<ul class="bullet"><li>3</li><li>4</li></ul></li></ul><ol class="number"><li>item<ol class="number"><li>item1</li><li>item2</li></ol></li></ol></body></html>',
|
||||
wantAlines: [
|
||||
'*0*2*6+1+3',
|
||||
'*0*2*6+1+3',
|
||||
'*0*2*6+1+1',
|
||||
'*0*2*6+1+1',
|
||||
'*0*2*6+1+1',
|
||||
'*0*3*6+1+1',
|
||||
'*0*3*6+1+1',
|
||||
'*0*4*6*7+1+4',
|
||||
'*0*5*6*8+1+5',
|
||||
'*0*5*6*8+1+5',
|
||||
],
|
||||
wantText: [
|
||||
'*one',
|
||||
'*two',
|
||||
'*0',
|
||||
'*1',
|
||||
'*2',
|
||||
'*3',
|
||||
'*4',
|
||||
'*item',
|
||||
'*item1',
|
||||
'*item2',
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'Tests if uls properly get attributes',
|
||||
html: '<html><body><ul><li>a</li><li>b</li></ul><div>div</div><p>foo</p></body></html>',
|
||||
wantAlines: [
|
||||
'*0*2*6+1+1',
|
||||
'*0*2*6+1+1',
|
||||
'+3',
|
||||
'+3',
|
||||
],
|
||||
wantText: ['*a', '*b', 'div', 'foo'],
|
||||
},
|
||||
{
|
||||
description: 'Tests if indented uls properly get attributes',
|
||||
html: '<html><body><ul><li>a</li><ul><li>b</li></ul><li>a</li></ul><p>foo</p></body></html>',
|
||||
wantAlines: [
|
||||
'*0*2*6+1+1',
|
||||
'*0*3*6+1+1',
|
||||
'*0*2*6+1+1',
|
||||
'+3',
|
||||
],
|
||||
wantText: ['*a', '*b', '*a', 'foo'],
|
||||
},
|
||||
{
|
||||
description: 'Tests if ols properly get line numbers when in a normal OL',
|
||||
html: '<html><body><ol><li>a</li><li>b</li><li>c</li></ol><p>test</p></body></html>',
|
||||
wantAlines: [
|
||||
'*0*4*6*7+1+1',
|
||||
'*0*4*6*7+1+1',
|
||||
'*0*4*6*7+1+1',
|
||||
'+4',
|
||||
],
|
||||
wantText: ['*a', '*b', '*c', 'test'],
|
||||
noteToSelf: 'Ensure empty P does not induce line attribute marker, wont this break the editor?',
|
||||
},
|
||||
{
|
||||
description: 'A single completely empty line break within an ol should reset count if OL is closed off..',
|
||||
html: '<html><body><ol><li>should be 1</li></ol><p>hello</p><ol><li>should be 1</li><li>should be 2</li></ol><p></p></body></html>',
|
||||
wantAlines: [
|
||||
'*0*4*6*7+1+b',
|
||||
'+5',
|
||||
'*0*4*6*8+1+b',
|
||||
'*0*4*6*8+1+b',
|
||||
'',
|
||||
],
|
||||
wantText: ['*should be 1', 'hello', '*should be 1', '*should be 2', ''],
|
||||
noteToSelf: "Shouldn't include attribute marker in the <p> line",
|
||||
},
|
||||
{
|
||||
description: 'A single <p></p> should create a new line',
|
||||
html: '<html><body><p></p><p></p></body></html>',
|
||||
wantAlines: ['', ''],
|
||||
wantText: ['', ''],
|
||||
noteToSelf: '<p></p>should create a line break but not break numbering',
|
||||
},
|
||||
{
|
||||
description: 'Tests if ols properly get line numbers when in a normal OL #2',
|
||||
html: '<html><body>a<ol><li>b<ol><li>c</li></ol></ol>notlist<p>foo</p></body></html>',
|
||||
wantAlines: [
|
||||
'+1',
|
||||
'*0*4*6*7+1+1',
|
||||
'*0*5*6*8+1+1',
|
||||
'+7',
|
||||
'+3',
|
||||
],
|
||||
wantText: ['a', '*b', '*c', 'notlist', 'foo'],
|
||||
noteToSelf: 'Ensure empty P does not induce line attribute marker, wont this break the editor?',
|
||||
},
|
||||
{
|
||||
description: 'First item being an UL then subsequent being OL will fail',
|
||||
html: '<html><body><ul><li>a<ol><li>b</li><li>c</li></ol></li></ul></body></html>',
|
||||
wantAlines: ['+1', '*0*1*2*3+1+1', '*0*4*2*5+1+1'],
|
||||
wantText: ['a', '*b', '*c'],
|
||||
noteToSelf: 'Ensure empty P does not induce line attribute marker, wont this break the editor?',
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
description: 'A single completely empty line break within an ol should NOT reset count',
|
||||
html: '<html><body><ol><li>should be 1</li><p></p><li>should be 2</li><li>should be 3</li></ol><p></p></body></html>',
|
||||
wantAlines: [],
|
||||
wantText: ['*should be 1', '*should be 2', '*should be 3'],
|
||||
noteToSelf: "<p></p>should create a line break but not break numbering -- This is what I can't get working!",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
description: 'Content outside body should be ignored',
|
||||
html: '<html><head><title>title</title><style></style></head><body>empty<br></body></html>',
|
||||
wantAlines: ['+5'],
|
||||
wantText: ['empty'],
|
||||
},
|
||||
{
|
||||
description: 'Multiple spaces should be preserved',
|
||||
html: '<html><body>Text with more than one space.<br></body></html>',
|
||||
wantAlines: ['+10'],
|
||||
wantText: ['Text with more than one space.'],
|
||||
},
|
||||
{
|
||||
description: 'non-breaking and normal space should be preserved',
|
||||
html: '<html><body>Text with more than one space.<br></body></html>',
|
||||
wantAlines: ['+10'],
|
||||
wantText: ['Text with more than one space.'],
|
||||
},
|
||||
{
|
||||
description: 'Multiple nbsp should be preserved',
|
||||
html: '<html><body> <br></body></html>',
|
||||
wantAlines: ['+2'],
|
||||
wantText: [' '],
|
||||
},
|
||||
{
|
||||
description: 'Multiple nbsp between words ',
|
||||
html: '<html><body> word1 word2 word3<br></body></html>',
|
||||
wantAlines: ['+m'],
|
||||
wantText: [' word1 word2 word3'],
|
||||
},
|
||||
{
|
||||
description: 'A non-breaking space preceded by a normal space',
|
||||
html: '<html><body> word1 word2 word3<br></body></html>',
|
||||
wantAlines: ['+l'],
|
||||
wantText: [' word1 word2 word3'],
|
||||
},
|
||||
{
|
||||
description: 'A non-breaking space followed by a normal space',
|
||||
html: '<html><body> word1 word2 word3<br></body></html>',
|
||||
wantAlines: ['+l'],
|
||||
wantText: [' word1 word2 word3'],
|
||||
},
|
||||
{
|
||||
description: 'Don\'t collapse spaces that follow a newline',
|
||||
html: '<!doctype html><html><body>something<br> something<br></body></html>',
|
||||
wantAlines: ['+9', '+m'],
|
||||
wantText: ['something', ' something'],
|
||||
},
|
||||
{
|
||||
description: 'Don\'t collapse spaces that follow a empty paragraph',
|
||||
html: '<!doctype html><html><body>something<p></p> something<br></body></html>',
|
||||
wantAlines: ['+9', '', '+m'],
|
||||
wantText: ['something', '', ' something'],
|
||||
},
|
||||
{
|
||||
description: 'Don\'t collapse spaces that preceed/follow a newline',
|
||||
html: '<html><body>something <br> something<br></body></html>',
|
||||
wantAlines: ['+l', '+m'],
|
||||
wantText: ['something ', ' something'],
|
||||
},
|
||||
{
|
||||
description: 'Don\'t collapse spaces that preceed/follow a empty paragraph',
|
||||
html: '<html><body>something <p></p> something<br></body></html>',
|
||||
wantAlines: ['+l', '', '+m'],
|
||||
wantText: ['something ', '', ' something'],
|
||||
},
|
||||
{
|
||||
description: 'Don\'t collapse non-breaking spaces that follow a newline',
|
||||
html: '<html><body>something<br> something<br></body></html>',
|
||||
wantAlines: ['+9', '+c'],
|
||||
wantText: ['something', ' something'],
|
||||
},
|
||||
{
|
||||
description: 'Don\'t collapse non-breaking spaces that follow a paragraph',
|
||||
html: '<html><body>something<p></p> something<br></body></html>',
|
||||
wantAlines: ['+9', '', '+c'],
|
||||
wantText: ['something', '', ' something'],
|
||||
},
|
||||
{
|
||||
description: 'Preserve all spaces when multiple are present',
|
||||
html: '<html><body>Need <span> more </span> space<i> s </i> !<br></body></html>',
|
||||
wantAlines: ['+h*1+4+2'],
|
||||
wantText: ['Need more space s !'],
|
||||
},
|
||||
{
|
||||
description: 'Newlines and multiple spaces across newlines should be preserved',
|
||||
html: `
|
||||
<html><body>Need
|
||||
<span> more </span>
|
||||
space
|
||||
<i> s </i>
|
||||
!<br></body></html>`,
|
||||
wantAlines: ['+19*1+4+b'],
|
||||
wantText: ['Need more space s !'],
|
||||
},
|
||||
{
|
||||
description: 'Multiple new lines at the beginning should be preserved',
|
||||
html: '<html><body><br><br><p></p><p></p>first line<br><br>second line<br></body></html>',
|
||||
wantAlines: ['', '', '', '', '+a', '', '+b'],
|
||||
wantText: ['', '', '', '', 'first line', '', 'second line'],
|
||||
},
|
||||
{
|
||||
description: 'A paragraph with multiple lines should not loose spaces when lines are combined',
|
||||
html: `<html><body><p>
|
||||
а б в г ґ д е є ж з и і ї й к л м н о
|
||||
п р с т у ф х ц ч ш щ ю я ь</p>
|
||||
</body></html>`,
|
||||
wantAlines: ['+1t'],
|
||||
wantText: ['а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ю я ь'],
|
||||
},
|
||||
{
|
||||
description: 'lines in preformatted text should be kept intact',
|
||||
html: `<html><body><p>
|
||||
а б в г ґ д е є ж з и і ї й к л м н о</p><pre>multiple
|
||||
lines
|
||||
in
|
||||
pre
|
||||
</pre><p>п р с т у ф х ц ч ш щ ю я
|
||||
ь</p>
|
||||
</body></html>`,
|
||||
wantAlines: ['+11', '+8', '+5', '+2', '+3', '+r'],
|
||||
wantText: [
|
||||
'а б в г ґ д е є ж з и і ї й к л м н о',
|
||||
'multiple',
|
||||
'lines',
|
||||
'in',
|
||||
'pre',
|
||||
'п р с т у ф х ц ч ш щ ю я ь',
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'pre should be on a new line not preceded by a space',
|
||||
html: `<html><body><p>
|
||||
1
|
||||
</p><pre>preline
|
||||
</pre></body></html>`,
|
||||
wantAlines: ['+6', '+7'],
|
||||
wantText: [' 1 ', 'preline'],
|
||||
},
|
||||
{
|
||||
description: 'Preserve spaces on the beginning and end of a element',
|
||||
html: '<html><body>Need<span> more </span>space<i> s </i>!<br></body></html>',
|
||||
wantAlines: ['+f*1+3+1'],
|
||||
wantText: ['Need more space s !'],
|
||||
},
|
||||
{
|
||||
description: 'Preserve spaces outside elements',
|
||||
html: '<html><body>Need <span>more</span> space <i>s</i> !<br></body></html>',
|
||||
wantAlines: ['+g*1+1+2'],
|
||||
wantText: ['Need more space s !'],
|
||||
},
|
||||
{
|
||||
description: 'Preserve spaces at the end of an element',
|
||||
html: '<html><body>Need <span>more </span>space <i>s </i>!<br></body></html>',
|
||||
wantAlines: ['+g*1+2+1'],
|
||||
wantText: ['Need more space s !'],
|
||||
},
|
||||
{
|
||||
description: 'Preserve spaces at the start of an element',
|
||||
html: '<html><body>Need<span> more</span> space<i> s</i> !<br></body></html>',
|
||||
wantAlines: ['+f*1+2+2'],
|
||||
wantText: ['Need more space s !'],
|
||||
},
|
||||
];
|
||||
|
||||
describe(__filename, function () {
|
||||
for (const tc of testCases) {
|
||||
describe(tc.description, function () {
|
||||
let apool: APool;
|
||||
let result: {
|
||||
lines: string[],
|
||||
lineAttribs: string[],
|
||||
};
|
||||
if (tc.disabled) {
|
||||
test.skip('If disabled we do not run the test');
|
||||
return;
|
||||
}
|
||||
|
||||
beforeAll(async function () {
|
||||
|
||||
const {window: {document}} = new jsdom.JSDOM(tc.html);
|
||||
apool = new AttributePool();
|
||||
// To reduce test fragility, the attribute pool is seeded with `knownAttribs`, and all
|
||||
// attributes in `tc.wantAlines` must be in `knownAttribs`. (This guarantees that attribute
|
||||
// numbers do not change if the attribute processing code changes.)
|
||||
for (const attrib of knownAttribs) apool.putAttrib(attrib);
|
||||
for (const aline of tc.wantAlines) {
|
||||
for (const op of Changeset.deserializeOps(aline)) {
|
||||
for (const n of attributes.decodeAttribString(op.attribs)) {
|
||||
assert(n < knownAttribs.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
const cc = contentcollector.makeContentCollector(true, null, apool);
|
||||
cc.collectContent(document.body);
|
||||
result = cc.finish();
|
||||
console.log(result);
|
||||
});
|
||||
|
||||
it('text matches', async function () {
|
||||
assert.deepEqual(result.lines, tc.wantText);
|
||||
});
|
||||
|
||||
it('alines match', async function () {
|
||||
assert.deepEqual(result.lineAttribs, tc.wantAlines);
|
||||
});
|
||||
|
||||
it('attributes are sorted in canonical order', async function () {
|
||||
const gotAttribs:string[][][] = [];
|
||||
const wantAttribs = [];
|
||||
for (const aline of result.lineAttribs) {
|
||||
const gotAlineAttribs:string[][] = [];
|
||||
gotAttribs.push(gotAlineAttribs);
|
||||
const wantAlineAttribs:string[] = [];
|
||||
wantAttribs.push(wantAlineAttribs);
|
||||
for (const op of Changeset.deserializeOps(aline)) {
|
||||
const gotOpAttribs:string[] = [...attributes.attribsFromString(op.attribs, apool)];
|
||||
gotAlineAttribs.push(gotOpAttribs);
|
||||
wantAlineAttribs.push(attributes.sort([...gotOpAttribs]));
|
||||
}
|
||||
}
|
||||
assert.deepEqual(gotAttribs, wantAttribs);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
|
@ -1,19 +1,19 @@
|
|||
import {MapArrayType} from "../../../node/types/MapType";
|
||||
const {padutils} = require('../../../static/js/pad_utils');
|
||||
import padutils from '../../../static/js/pad_utils';
|
||||
import {describe, it, expect, afterEach, beforeAll} from "vitest";
|
||||
|
||||
describe(__filename, function () {
|
||||
describe('warnDeprecated', function () {
|
||||
const {warnDeprecated} = padutils;
|
||||
const {warnDeprecatedFlags, warnDeprecated} = padutils;
|
||||
const backups:MapArrayType<any> = {};
|
||||
|
||||
beforeAll(async function () {
|
||||
backups.logger = warnDeprecated.logger;
|
||||
backups.logger = warnDeprecatedFlags.logger;
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
warnDeprecated.logger = backups.logger;
|
||||
delete warnDeprecated._rl; // Reset internal rate limiter state.
|
||||
warnDeprecatedFlags.logger = backups.logger;
|
||||
delete warnDeprecatedFlags._rl; // Reset internal rate limiter state.
|
||||
});
|
||||
|
||||
/*it('includes the stack', async function () {
|
||||
|
@ -25,13 +25,13 @@ describe(__filename, function () {
|
|||
|
||||
it('rate limited', async function () {
|
||||
let got = 0;
|
||||
warnDeprecated.logger = {warn: () => ++got};
|
||||
warnDeprecatedFlags.logger = {warn: () => ++got};
|
||||
warnDeprecated(); // Initialize internal rate limiter state.
|
||||
const {period} = warnDeprecated._rl;
|
||||
const {period} = warnDeprecatedFlags._rl!;
|
||||
got = 0;
|
||||
const testCases = [[0, 1], [0, 1], [period - 1, 1], [period, 2]];
|
||||
for (const [now, want] of testCases) { // In a loop so that the stack trace is the same.
|
||||
warnDeprecated._rl.now = () => now;
|
||||
warnDeprecatedFlags._rl!.now = () => now;
|
||||
warnDeprecated();
|
||||
expect(got).toEqual(want);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
'use strict';
|
||||
|
||||
const SkipList = require('ep_etherpad-lite/static/js/skiplist');
|
||||
import SkipList from 'ep_etherpad-lite/static/js/skiplist';
|
||||
import {expect, describe, it} from 'vitest';
|
||||
|
||||
describe('skiplist.js', function () {
|
||||
it('rejects null keys', async function () {
|
||||
const skiplist = new SkipList();
|
||||
for (const key of [undefined, null]) {
|
||||
// @ts-ignore
|
||||
expect(() => skiplist.push({key})).toThrowError();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
import {MapArrayType} from "../../node/types/MapType";
|
||||
|
||||
const AttributePool = require('../../static/js/AttributePool');
|
||||
const apiHandler = require('../../node/handler/APIHandler');
|
||||
import AttributePool from '../../static/js/AttributePool';
|
||||
const assert = require('assert').strict;
|
||||
const io = require('socket.io-client');
|
||||
const log4js = require('log4js');
|
||||
const {padutils} = require('../../static/js/pad_utils');
|
||||
import padutils from '../../static/js/pad_utils';
|
||||
const process = require('process');
|
||||
const server = require('../../node/server');
|
||||
const setCookieParser = require('set-cookie-parser');
|
||||
|
|
|
@ -8,7 +8,7 @@ const db = require('../../../node/db/DB');
|
|||
const importEtherpad = require('../../../node/utils/ImportEtherpad');
|
||||
const padManager = require('../../../node/db/PadManager');
|
||||
const plugins = require('../../../static/js/pluginfw/plugin_defs');
|
||||
const {randomString} = require('../../../static/js/pad_utils');
|
||||
import {randomString} from '../../../static/js/pad_utils';
|
||||
|
||||
describe(__filename, function () {
|
||||
let padId: string;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import {MapArrayType} from "../../../node/types/MapType";
|
||||
import {PluginDef} from "../../../node/types/PartType";
|
||||
|
||||
const ChatMessage = require('../../../static/js/ChatMessage');
|
||||
import ChatMessage from '../../../static/js/ChatMessage';
|
||||
const {Pad} = require('../../../node/db/Pad');
|
||||
const assert = require('assert').strict;
|
||||
const common = require('../common');
|
||||
|
@ -103,10 +103,14 @@ describe(__filename, function () {
|
|||
checkHook('chatNewMessage', ({message}) => {
|
||||
assert(message != null);
|
||||
assert(message instanceof ChatMessage);
|
||||
assert.equal(message.authorId, authorId);
|
||||
assert.equal(message.text, this.test!.title);
|
||||
assert(message.time >= start);
|
||||
assert(message.time <= Date.now());
|
||||
// @ts-ignore
|
||||
assert.equal(message!.authorId, authorId);
|
||||
// @ts-ignore
|
||||
assert.equal(message!.text, this.test!.title);
|
||||
// @ts-ignore
|
||||
assert(message!.time >= start);
|
||||
// @ts-ignore
|
||||
assert(message!.time <= Date.now());
|
||||
}),
|
||||
sendChat(socket, {text: this.test!.title}),
|
||||
]);
|
||||
|
@ -153,7 +157,9 @@ describe(__filename, function () {
|
|||
const customMetadata = {foo: this.test!.title};
|
||||
await Promise.all([
|
||||
checkHook('chatNewMessage', ({message}) => {
|
||||
// @ts-ignore
|
||||
message.text = modifiedText;
|
||||
// @ts-ignore
|
||||
message.customMetadata = customMetadata;
|
||||
}),
|
||||
(async () => {
|
||||
|
|
|
@ -11,16 +11,17 @@
|
|||
|
||||
import {APool} from "../../../node/types/PadType";
|
||||
|
||||
const AttributePool = require('../../../static/js/AttributePool');
|
||||
import AttributePool from '../../../static/js/AttributePool';
|
||||
const Changeset = require('../../../static/js/Changeset');
|
||||
const assert = require('assert').strict;
|
||||
const attributes = require('../../../static/js/attributes');
|
||||
import attributes from '../../../static/js/attributes';
|
||||
const contentcollector = require('../../../static/js/contentcollector');
|
||||
const jsdom = require('jsdom');
|
||||
import jsdom from 'jsdom';
|
||||
import {Attribute} from "../../../static/js/types/Attribute";
|
||||
|
||||
// All test case `wantAlines` values must only refer to attributes in this list so that the
|
||||
// attribute numbers do not change due to changes in pool insertion order.
|
||||
const knownAttribs = [
|
||||
const knownAttribs: Attribute[] = [
|
||||
['insertorder', 'first'],
|
||||
['italic', 'true'],
|
||||
['list', 'bullet1'],
|
||||
|
@ -336,7 +337,7 @@ pre
|
|||
describe(__filename, function () {
|
||||
for (const tc of testCases) {
|
||||
describe(tc.description, function () {
|
||||
let apool: APool;
|
||||
let apool: AttributePool;
|
||||
let result: {
|
||||
lines: string[],
|
||||
lineAttribs: string[],
|
||||
|
@ -376,11 +377,12 @@ describe(__filename, function () {
|
|||
for (const aline of result.lineAttribs) {
|
||||
const gotAlineAttribs:string[][] = [];
|
||||
gotAttribs.push(gotAlineAttribs);
|
||||
const wantAlineAttribs:string[] = [];
|
||||
const wantAlineAttribs:Attribute[] = [];
|
||||
wantAttribs.push(wantAlineAttribs);
|
||||
for (const op of Changeset.deserializeOps(aline)) {
|
||||
const gotOpAttribs:string[] = [...attributes.attribsFromString(op.attribs, apool)];
|
||||
const gotOpAttribs = [...attributes.attribsFromString(op.attribs, apool)] as unknown as Attribute;
|
||||
gotAlineAttribs.push(gotOpAttribs);
|
||||
// @ts-ignore
|
||||
wantAlineAttribs.push(attributes.sort([...gotOpAttribs]));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue