mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-28 05:54:43 -04:00
test(html-to-react): replace jest with vitest
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
b27f195e30
commit
97219ef497
8 changed files with 1078 additions and 134 deletions
|
@ -13,13 +13,8 @@ module.exports = {
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@typescript-eslint",
|
"@typescript-eslint",
|
||||||
"jest",
|
|
||||||
"prettier"
|
"prettier"
|
||||||
],
|
],
|
||||||
"env": {
|
|
||||||
"jest": true,
|
|
||||||
"jest/globals": true
|
|
||||||
},
|
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
"eslint:recommended",
|
||||||
"plugin:@typescript-eslint/eslint-recommended",
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
|
@ -31,10 +26,5 @@ module.exports = {
|
||||||
"prettier/prettier": ["error",
|
"prettier/prettier": ["error",
|
||||||
require('./.prettierrc.json')
|
require('./.prettierrc.json')
|
||||||
],
|
],
|
||||||
"jest/no-disabled-tests": "warn",
|
|
||||||
"jest/no-focused-tests": "error",
|
|
||||||
"jest/no-identical-title": "error",
|
|
||||||
"jest/prefer-to-have-length": "warn",
|
|
||||||
"jest/valid-expect": "error"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
"testRegex" : "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
|
|
||||||
"testPathIgnorePatterns" : [
|
|
||||||
"/dist/"
|
|
||||||
],
|
|
||||||
"moduleFileExtensions" : [
|
|
||||||
"ts",
|
|
||||||
"tsx",
|
|
||||||
"js"
|
|
||||||
],
|
|
||||||
"extensionsToTreatAsEsm" : [
|
|
||||||
".ts"
|
|
||||||
],
|
|
||||||
"moduleNameMapper" : {
|
|
||||||
"^(\\.{1,2}/.*)\\.js$" : "$1"
|
|
||||||
},
|
|
||||||
"transform" : {
|
|
||||||
"^.+\\.tsx?$" : [
|
|
||||||
"ts-jest",
|
|
||||||
{
|
|
||||||
"tsconfig" : "tsconfig.test.json",
|
|
||||||
"useESM" : true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
|
||||||
|
|
||||||
SPDX-License-Identifier: CC0-1.0
|
|
|
@ -18,7 +18,7 @@
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest",
|
"test": "vitest",
|
||||||
"build": "./build.sh",
|
"build": "./build.sh",
|
||||||
"prepublish": "yarn lint && yarn build && yarn test",
|
"prepublish": "yarn lint && yarn build && yarn test",
|
||||||
"lint": "eslint src --ext .ts",
|
"lint": "eslint src --ext .ts",
|
||||||
|
@ -48,22 +48,18 @@
|
||||||
"author": "The HedgeDoc Authors",
|
"author": "The HedgeDoc Authors",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest/globals": "29.7.0",
|
|
||||||
"@jest/types": "29.6.3",
|
|
||||||
"@types/react": "18.3.11",
|
"@types/react": "18.3.11",
|
||||||
"@types/react-dom": "18.3.1",
|
"@types/react-dom": "18.3.1",
|
||||||
"@typescript-eslint/eslint-plugin": "8.14.0",
|
"@typescript-eslint/eslint-plugin": "8.14.0",
|
||||||
"@typescript-eslint/parser": "8.14.0",
|
"@typescript-eslint/parser": "8.14.0",
|
||||||
"eslint": "8.57.1",
|
"eslint": "8.57.1",
|
||||||
"eslint-config-prettier": "9.1.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
"eslint-plugin-jest": "28.9.0",
|
|
||||||
"eslint-plugin-prettier": "5.2.3",
|
"eslint-plugin-prettier": "5.2.3",
|
||||||
"jest": "29.7.0",
|
|
||||||
"prettier": "3.3.3",
|
"prettier": "3.3.3",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"ts-jest": "29.2.5",
|
"typescript": "5.6.3",
|
||||||
"typescript": "5.6.3"
|
"vitest": "3.1.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"domelementtype": "2.3.0",
|
"domelementtype": "2.3.0",
|
||||||
|
|
|
@ -10,76 +10,103 @@ import { convertNodeToReactElement } from './convertNodeToReactElement.js'
|
||||||
import { Document, isTag, isText } from 'domhandler'
|
import { Document, isTag, isText } from 'domhandler'
|
||||||
import { NodeToReactElementTransformer } from './NodeToReactElementTransformer.js'
|
import { NodeToReactElementTransformer } from './NodeToReactElementTransformer.js'
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import { describe, expect, it } from '@jest/globals'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { ElementType } from 'htmlparser2'
|
||||||
|
|
||||||
const expectSameHtml = function (html: string, options: ParserOptions = {}) {
|
function parseHtmlToReactHtml(html: string, options: ParserOptions = {}) {
|
||||||
const actual = renderToStaticMarkup(<div>{convertHtmlToReact(html, options)}</div>)
|
return renderToStaticMarkup(<div>{convertHtmlToReact(html, options)}</div>)
|
||||||
const expected = `<div>${html}</div>`
|
|
||||||
expect(actual).toBe(expected)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const expectOtherHtml = function (html: string, override: string, options: ParserOptions = {}) {
|
function expectedHtml(html: string) {
|
||||||
const actual = renderToStaticMarkup(<div>{convertHtmlToReact(html, options)}</div>)
|
return `<div>${html}</div>`
|
||||||
const expected = `<div>${override}</div>`
|
|
||||||
expect(actual).toBe(expected)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Integration tests: ', () => {
|
describe('Integration tests', () => {
|
||||||
it('should render a simple element', () => {
|
it('should render a simple element', () => {
|
||||||
expectSameHtml('<div>test</div>')
|
const markup = '<div>test</div>'
|
||||||
|
expect(parseHtmlToReactHtml(markup)).toBe(expectedHtml(markup))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render multiple sibling elements', () => {
|
it('should render multiple sibling elements', () => {
|
||||||
expectSameHtml('<div>test1</div><span>test2</span><footer>test3</footer>')
|
const markup = '<div>test1</div><span>test2</span><footer>test3</footer>'
|
||||||
|
expect(parseHtmlToReactHtml(markup)).toBe(expectedHtml(markup))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render nested elements', () => {
|
it('should render nested elements', () => {
|
||||||
expectSameHtml('<div><span>test1</span><div><ul><li>test2</li><li>test3</li></ul></div></div>')
|
const markup =
|
||||||
|
'<div><span>test1</span><div><ul><li>test2</li><li>test3</li></ul></div></div>'
|
||||||
|
expect(parseHtmlToReactHtml(markup)).toBe(expectedHtml(markup))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle bad html', () => {
|
it('should handle bad html', () => {
|
||||||
expectOtherHtml(
|
expect(
|
||||||
'<div class=test>test<ul><li>test1<li>test2</ul><span>test</span></div>',
|
parseHtmlToReactHtml(
|
||||||
'<div class="test">test<ul><li>test1</li><li>test2</li></ul><span>test</span></div>'
|
'<div class=test>test<ul><li>test1<li>test2</ul><span>test</span></div>'
|
||||||
|
)
|
||||||
|
).toBe(
|
||||||
|
expectedHtml(
|
||||||
|
'<div class="test">test<ul><li>test1</li><li>test2</li></ul><span>test</span></div>'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should ignore doctypes', () => {
|
it('should ignore doctypes', () => {
|
||||||
expectOtherHtml('<!doctype html><div>test</div>', '<div>test</div>')
|
expect(parseHtmlToReactHtml('<!doctype html><div>test</div>')).toBe(
|
||||||
|
expectedHtml('<div>test</div>')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should ignore comments', () => {
|
it('should ignore comments', () => {
|
||||||
expectOtherHtml('<div>test1</div><!-- comment --><div>test2</div>', '<div>test1</div><div>test2</div>')
|
expect(
|
||||||
|
parseHtmlToReactHtml('<div>test1</div><!-- comment --><div>test2</div>')
|
||||||
|
).toBe(parseHtmlToReactHtml('<div>test1</div><div>test2</div>'))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should ignore script tags', () => {
|
it('should ignore script tags', () => {
|
||||||
expectOtherHtml('<script>alert(1)</script>', '')
|
expect(parseHtmlToReactHtml('<script>alert(1)</script>')).toBe(
|
||||||
|
expectedHtml('')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should ignore event handlers', () => {
|
it('should ignore event handlers', () => {
|
||||||
expectOtherHtml('<a href="#" onclick="alert(1)">test</a>', '<a href="#">test</a>')
|
expect(
|
||||||
|
parseHtmlToReactHtml('<a href="#" onclick="alert(1)">test</a>')
|
||||||
|
).toBe(expectedHtml('<a href="#">test</a>'))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle attributes', () => {
|
it('should handle attributes', () => {
|
||||||
expectSameHtml('<div class="test" id="test" aria-valuetext="test" data-test="test">test</div>')
|
const markup =
|
||||||
|
'<div class="test" id="test" aria-valuetext="test" data-test="test">test</div>'
|
||||||
|
expect(parseHtmlToReactHtml(markup)).toBe(expectedHtml(markup))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle inline styles', () => {
|
it('should handle inline styles', () => {
|
||||||
expectSameHtml('<div style="border-radius:1px;background:red">test</div>')
|
const markup = '<div style="border-radius:1px;background:red">test</div>'
|
||||||
|
expect(parseHtmlToReactHtml(markup)).toBe(expectedHtml(markup))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should ignore inline styles that are empty strings', () => {
|
it('should ignore inline styles that are empty strings', () => {
|
||||||
expectOtherHtml('<div style="">test</div>', '<div>test</div>')
|
expect(parseHtmlToReactHtml('<div style="">test</div>')).toBe(
|
||||||
|
expectedHtml('<div>test</div>')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not allow nesting of void elements', () => {
|
it('should not allow nesting of void elements', () => {
|
||||||
expectOtherHtml('<input><p>test</p></input>', '<input/><p>test</p>')
|
expect(parseHtmlToReactHtml('<input><p>test</p></input>')).toBe(
|
||||||
|
expectedHtml('<input/><p>test</p>')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should convert boolean attribute values', () => {
|
it('should convert boolean attribute values', () => {
|
||||||
expectOtherHtml('<input disabled>', '<input disabled=""/>')
|
expect(parseHtmlToReactHtml('<input disabled>')).toBe(
|
||||||
expectOtherHtml('<input disabled="">', '<input disabled=""/>')
|
expectedHtml('<input disabled=""/>')
|
||||||
expectOtherHtml('<input disabled="disabled">', '<input disabled=""/>')
|
)
|
||||||
|
expect(parseHtmlToReactHtml('<input disabled="">')).toBe(
|
||||||
|
expectedHtml('<input disabled=""/>')
|
||||||
|
)
|
||||||
|
expect(parseHtmlToReactHtml('<input disabled="disabled">')).toBe(
|
||||||
|
expectedHtml('<input disabled=""/>')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
;[
|
;[
|
||||||
['CONTENTEDITABLE', 'contentEditable'],
|
['CONTENTEDITABLE', 'contentEditable'],
|
||||||
|
@ -94,43 +121,60 @@ describe('Integration tests: ', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should decode html entities by default', () => {
|
it('should decode html entities by default', () => {
|
||||||
expectOtherHtml('<span>!</span>', '<span>!</span>')
|
expect(parseHtmlToReactHtml('<span>!</span>')).toBe(
|
||||||
|
expectedHtml('<span>!</span>')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not decode html entities when the option is disabled', () => {
|
it('should not decode html entities when the option is disabled', () => {
|
||||||
expectOtherHtml('<span>!</span>', '<span>&excl;</span>', {
|
expect(
|
||||||
decodeEntities: false
|
parseHtmlToReactHtml('<span>!</span>', {
|
||||||
})
|
decodeEntities: false
|
||||||
|
})
|
||||||
|
).toBe(expectedHtml('<span>&excl;</span>'))
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('transform function', () => {
|
describe('transform function', () => {
|
||||||
it('should use the response when it is not undefined', () => {
|
it('should use the response when it is not undefined', () => {
|
||||||
expectOtherHtml('<span>test</span><div>another</div>', '<p>transformed</p><p>transformed</p>', {
|
expect(
|
||||||
transform(node, index) {
|
parseHtmlToReactHtml('<span>test</span><div>another</div>', {
|
||||||
return <p key={index}>transformed</p>
|
transform(node, index) {
|
||||||
}
|
return <p key={index}>transformed</p>
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
).toBe(expectedHtml('<p>transformed</p><p>transformed</p>'))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not render elements and children when returning null', () => {
|
it('should not render elements and children when returning null', () => {
|
||||||
expectOtherHtml('<p>test<span>inner test<b>bold child</b></span></p>', '<p>test</p>', {
|
expect(
|
||||||
transform(node) {
|
parseHtmlToReactHtml(
|
||||||
if (isTag(node) && node.type === 'tag' && node.name === 'span') {
|
'<p>test<span>inner test<b>bold child</b></span></p>',
|
||||||
return null
|
{
|
||||||
|
transform(node) {
|
||||||
|
if (
|
||||||
|
isTag(node) &&
|
||||||
|
ElementType.isTag(node) &&
|
||||||
|
node.name === 'span'
|
||||||
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
})
|
).toBe(expectedHtml('<p>test</p>'))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should allow modifying nodes', () => {
|
it('should allow modifying nodes', () => {
|
||||||
expectOtherHtml('<a href="/test">test link</a>', '<a href="/changed">test link</a>', {
|
expect(
|
||||||
transform(node, index) {
|
parseHtmlToReactHtml('<a href="/test">test link</a>', {
|
||||||
if (isTag(node)) {
|
transform(node, index) {
|
||||||
node.attribs.href = '/changed'
|
if (isTag(node)) {
|
||||||
|
node.attribs.href = '/changed'
|
||||||
|
}
|
||||||
|
return convertNodeToReactElement(node, index)
|
||||||
}
|
}
|
||||||
return convertNodeToReactElement(node, index)
|
})
|
||||||
}
|
).toBe(expectedHtml('<a href="/changed">test link</a>'))
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should allow passing the transform function down to children', () => {
|
it('should allow passing the transform function down to children', () => {
|
||||||
|
@ -146,29 +190,37 @@ describe('Integration tests: ', () => {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expectOtherHtml(
|
expect(
|
||||||
'<ul><li>list 1</li><li>list 2</li></ul>',
|
parseHtmlToReactHtml('<ul><li>list 1</li><li>list 2</li></ul>', {
|
||||||
'<ul class="test"><li>changed 1</li><li>changed 2</li></ul>',
|
|
||||||
{
|
|
||||||
transform
|
transform
|
||||||
}
|
})
|
||||||
|
).toBe(
|
||||||
|
expectedHtml(
|
||||||
|
'<ul class="test"><li>changed 1</li><li>changed 2</li></ul>'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not render invalid tags', () => {
|
it('should not render invalid tags', () => {
|
||||||
expectOtherHtml('<div>test<test</div>', '<div>test</div>')
|
expect(parseHtmlToReactHtml('<div>test<test</div>')).toBe(
|
||||||
|
expectedHtml('<div>test</div>')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not render invalid attributes', () => {
|
it('should not render invalid attributes', () => {
|
||||||
expectOtherHtml('<div data-test<="test" class="test">content</div>', '<div class="test">content</div>')
|
expect(
|
||||||
|
parseHtmlToReactHtml('<div data-test<="test" class="test">content</div>')
|
||||||
|
).toBe(expectedHtml('<div class="test">content</div>'))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should preprocess nodes correctly', () => {
|
it('should preprocess nodes correctly', () => {
|
||||||
expectOtherHtml('<div>preprocess test</div>', '<div>preprocess test</div><div>preprocess test</div>', {
|
expect(
|
||||||
preprocessNodes(document) {
|
parseHtmlToReactHtml('<div>preprocess test</div>', {
|
||||||
return new Document([...document.childNodes, ...document.childNodes])
|
preprocessNodes(document) {
|
||||||
}
|
return new Document([...document.childNodes, ...document.childNodes])
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
).toBe(expectedHtml('<div>preprocess test</div><div>preprocess test</div>'))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
import { convertInlineStyleToMap } from './convertInlineStyleToMap.js'
|
import { convertInlineStyleToMap } from './convertInlineStyleToMap.js'
|
||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
|
||||||
describe('convertInlineStyleToMap', () => {
|
describe('convertInlineStyleToMap', () => {
|
||||||
it('should split on normal ;', () => {
|
it('should split on normal ;', () => {
|
||||||
|
|
|
@ -16,5 +16,5 @@
|
||||||
"jsx": "react"
|
"jsx": "react"
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src"],
|
||||||
"exclude": ["dist", "**/*.test.ts"]
|
"exclude": ["dist", "**/*.test.ts", "**/*.spec.tsx", "**/*.spec.ts"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue