test: add more test for rich content

zio/stable
Anthony Fu 2022-11-25 16:56:14 +08:00
parent 727bef6066
commit ff81389404
5 changed files with 165 additions and 9 deletions

View File

@ -25,6 +25,7 @@
"@pinia/nuxt": "^0.4.5", "@pinia/nuxt": "^0.4.5",
"@types/fs-extra": "^9.0.13", "@types/fs-extra": "^9.0.13",
"@types/js-yaml": "^4.0.5", "@types/js-yaml": "^4.0.5",
"@types/prettier": "^2.7.1",
"@types/sanitize-html": "^2.6.2", "@types/sanitize-html": "^2.6.2",
"@types/wicg-file-system-access": "^2020.9.5", "@types/wicg-file-system-access": "^2020.9.5",
"@unocss/nuxt": "^0.46.5", "@unocss/nuxt": "^0.46.5",
@ -45,12 +46,14 @@
"parse5": "^7.1.2", "parse5": "^7.1.2",
"pinia": "^2.0.26", "pinia": "^2.0.26",
"postcss-nested": "^6.0.0", "postcss-nested": "^6.0.0",
"prettier": "^2.8.0",
"rollup-plugin-node-polyfills": "^0.2.1", "rollup-plugin-node-polyfills": "^0.2.1",
"sanitize-html": "^2.7.3", "sanitize-html": "^2.7.3",
"shiki": "^0.11.1", "shiki": "^0.11.1",
"theme-vitesse": "^0.6.0", "theme-vitesse": "^0.6.0",
"typescript": "^4.9.3", "typescript": "^4.9.3",
"ufo": "^1.0.0", "ufo": "^1.0.0",
"unplugin-auto-import": "^0.11.5",
"vitest": "^0.25.3" "vitest": "^0.25.3"
} }
} }

View File

@ -10,6 +10,7 @@ specifiers:
'@pinia/nuxt': ^0.4.5 '@pinia/nuxt': ^0.4.5
'@types/fs-extra': ^9.0.13 '@types/fs-extra': ^9.0.13
'@types/js-yaml': ^4.0.5 '@types/js-yaml': ^4.0.5
'@types/prettier': ^2.7.1
'@types/sanitize-html': ^2.6.2 '@types/sanitize-html': ^2.6.2
'@types/wicg-file-system-access': ^2020.9.5 '@types/wicg-file-system-access': ^2020.9.5
'@unocss/nuxt': ^0.46.5 '@unocss/nuxt': ^0.46.5
@ -30,12 +31,14 @@ specifiers:
parse5: ^7.1.2 parse5: ^7.1.2
pinia: ^2.0.26 pinia: ^2.0.26
postcss-nested: ^6.0.0 postcss-nested: ^6.0.0
prettier: ^2.8.0
rollup-plugin-node-polyfills: ^0.2.1 rollup-plugin-node-polyfills: ^0.2.1
sanitize-html: ^2.7.3 sanitize-html: ^2.7.3
shiki: ^0.11.1 shiki: ^0.11.1
theme-vitesse: ^0.6.0 theme-vitesse: ^0.6.0
typescript: ^4.9.3 typescript: ^4.9.3
ufo: ^1.0.0 ufo: ^1.0.0
unplugin-auto-import: ^0.11.5
vitest: ^0.25.3 vitest: ^0.25.3
devDependencies: devDependencies:
@ -48,6 +51,7 @@ devDependencies:
'@pinia/nuxt': 0.4.5_typescript@4.9.3 '@pinia/nuxt': 0.4.5_typescript@4.9.3
'@types/fs-extra': 9.0.13 '@types/fs-extra': 9.0.13
'@types/js-yaml': 4.0.5 '@types/js-yaml': 4.0.5
'@types/prettier': 2.7.1
'@types/sanitize-html': 2.6.2 '@types/sanitize-html': 2.6.2
'@types/wicg-file-system-access': 2020.9.5 '@types/wicg-file-system-access': 2020.9.5
'@unocss/nuxt': 0.46.5 '@unocss/nuxt': 0.46.5
@ -68,12 +72,14 @@ devDependencies:
parse5: 7.1.2 parse5: 7.1.2
pinia: 2.0.26_typescript@4.9.3 pinia: 2.0.26_typescript@4.9.3
postcss-nested: 6.0.0 postcss-nested: 6.0.0
prettier: 2.8.0
rollup-plugin-node-polyfills: 0.2.1 rollup-plugin-node-polyfills: 0.2.1
sanitize-html: 2.7.3 sanitize-html: 2.7.3
shiki: 0.11.1 shiki: 0.11.1
theme-vitesse: 0.6.0 theme-vitesse: 0.6.0
typescript: 4.9.3 typescript: 4.9.3
ufo: 1.0.0 ufo: 1.0.0
unplugin-auto-import: 0.11.5
vitest: 0.25.3 vitest: 0.25.3
packages: packages:
@ -195,6 +201,10 @@ packages:
resolution: {integrity: sha512-sEYpyyKUPOew9QsXZ8feRVMzW6DWLviwOl+/ap06UQW02A8Srbc95CPHVm4eUbiBzBgD46eyIT+przv//KSSlQ==} resolution: {integrity: sha512-sEYpyyKUPOew9QsXZ8feRVMzW6DWLviwOl+/ap06UQW02A8Srbc95CPHVm4eUbiBzBgD46eyIT+przv//KSSlQ==}
dev: true dev: true
/@antfu/utils/0.7.0:
resolution: {integrity: sha512-tH38JQEFLOdvZJC32ZbPTvWOQzxEtOQh5jOqBPDLw8sxBr0PFF+f2Csgwb7mRpD0QB1xu+PDoAifIPiCNneeNA==}
dev: true
/@babel/code-frame/7.18.6: /@babel/code-frame/7.18.6:
resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@ -1107,6 +1117,10 @@ packages:
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
dev: true dev: true
/@types/prettier/2.7.1:
resolution: {integrity: sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==}
dev: true
/@types/resolve/1.20.2: /@types/resolve/1.20.2:
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
dev: true dev: true
@ -5968,6 +5982,12 @@ packages:
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
dev: true dev: true
/prettier/2.8.0:
resolution: {integrity: sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==}
engines: {node: '>=10.13.0'}
hasBin: true
dev: true
/pretty-bytes/6.0.0: /pretty-bytes/6.0.0:
resolution: {integrity: sha512-6UqkYefdogmzqAZWzJ7laYeJnaXDy2/J+ZqiiMtS7t7OfpXWTlaeGMwX8U6EFvPV/YWWEKRkS8hKS4k60WHTOg==} resolution: {integrity: sha512-6UqkYefdogmzqAZWzJ7laYeJnaXDy2/J+ZqiiMtS7t7OfpXWTlaeGMwX8U6EFvPV/YWWEKRkS8hKS4k60WHTOg==}
engines: {node: ^14.13.1 || >=16.0.0} engines: {node: ^14.13.1 || >=16.0.0}
@ -6973,6 +6993,25 @@ packages:
- vite - vite
dev: true dev: true
/unplugin-auto-import/0.11.5:
resolution: {integrity: sha512-nvbL2AQwLRR8wbHpJ6L1EBVNmjN045RSedTa4NtsGRkSQFXkI1iKHs4dTqJwcKZsnFrZOAKtLPiN1/oQTObLZw==}
engines: {node: '>=14'}
peerDependencies:
'@vueuse/core': '*'
peerDependenciesMeta:
'@vueuse/core':
optional: true
dependencies:
'@antfu/utils': 0.7.0
'@rollup/pluginutils': 5.0.2
local-pkg: 0.4.2
magic-string: 0.26.7
unimport: 1.0.1
unplugin: 1.0.0
transitivePeerDependencies:
- rollup
dev: true
/unplugin-combine/0.2.8: /unplugin-combine/0.2.8:
resolution: {integrity: sha512-Z38AC/TEjXbVyZ5HjVqo+lADj0/dcfwWC0Z4y0LNhybJzJQwmcMxm+ZsqHY3faauj4YigmlRMdptR5JEW9RuLg==} resolution: {integrity: sha512-Z38AC/TEjXbVyZ5HjVqo+lADj0/dcfwWC0Z4y0LNhybJzJQwmcMxm+ZsqHY3faauj4YigmlRMdptR5JEW9RuLg==}
engines: {node: '>=14.19.0'} engines: {node: '>=14.19.0'}

View File

@ -1,6 +1,49 @@
// Vitest Snapshot v1 // Vitest Snapshot v1
exports[`rich-content > plain 1`] = ` exports[`rich-content > code frame 1`] = `
"Hello "<p>Testing code block</p>
World" <pre lang=\\"ts\\">
import { useMouse, usePreferredDark } from &#39;@vueuse/core&#39;
// tracks mouse position
const { x, y } = useMouse()
// is the user prefers dark theme
const isDark = usePreferredDark()</pre
>
<p></p>
"
`;
exports[`rich-content > custom emoji 1`] = `
"Daniel Roe
<img
src=\\"https://media.mas.to/masto-public/cache/custom_emojis/images/000/288/667/original/c96ba3cb0e0e1eac.png\\"
alt=\\"nuxt\\"
class=\\"custom-emoji\\"
/>
"
`;
exports[`rich-content > empty 1`] = `""`;
exports[`rich-content > link + mention 1`] = `
"<p>
Happy 🤗 were now using
<span class=\\"h-card\\"
><a
class=\\"u-url mention\\"
rel=\\"nofollow noopener noreferrer\\"
to=\\"/@vitest@mas.to\\"
></a
></span>
(migrated from chai+mocha)
<a
href=\\"https://github.com/ayoayco/astro-reactive-library/pull/203\\"
rel=\\"nofollow noopener noreferrer\\"
target=\\"_blank\\"
><span class=\\"invisible\\">https://</span
><span class=\\"ellipsis\\">github.com/ayoayco/astro-react</span
><span class=\\"invisible\\">ive-library/pull/203</span></a
>
</p>
"
`; `;

View File

@ -1,21 +1,81 @@
import type { Emoji } from 'masto' import type { Emoji } from 'masto'
import { describe, expect, it } from 'vitest' import { describe, expect, it, vi } from 'vitest'
import { renderToString } from 'vue/server-renderer' import { renderToString } from 'vue/server-renderer'
import { format } from 'prettier'
import { contentToVNode } from '~/composables/content' import { contentToVNode } from '~/composables/content'
describe('rich-content', () => {
it('empty', async () => {
const { formatted } = await render('')
expect(formatted).toMatchSnapshot()
})
it('link + mention', async () => {
// https://fosstodon.org/@ayo/109383002937620723
const { formatted } = await render('<p>Happy 🤗 were now using <span class="h-card"><a href="https://mas.to/@vitest" class="u-url mention" rel="nofollow noopener noreferrer" target="_blank">@<span>vitest</span></a></span> (migrated from chai+mocha) <a href="https://github.com/ayoayco/astro-reactive-library/pull/203" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="ellipsis">github.com/ayoayco/astro-react</span><span class="invisible">ive-library/pull/203</span></a></p>')
expect(formatted).toMatchSnapshot()
})
it('custom emoji', async () => {
const { formatted } = await render('Daniel Roe :nuxt:', {
nuxt: {
shortcode: 'nuxt',
url: 'https://media.mas.to/masto-public/cache/custom_emojis/images/000/288/667/original/c96ba3cb0e0e1eac.png',
staticUrl: 'https://media.mas.to/masto-public/cache/custom_emojis/images/000/288/667/static/c96ba3cb0e0e1eac.png',
visibleInPicker: true,
},
})
expect(formatted).toMatchSnapshot()
})
it('code frame', async () => {
// https://mas.to/@antfu/109396489827394721
const { formatted } = await render('<p>Testing code block</p><p>```ts<br />import { useMouse, usePreferredDark } from &#39;@vueuse/core&#39;</p><p>// tracks mouse position<br />const { x, y } = useMouse()</p><p>// is the user prefers dark theme<br />const isDark = usePreferredDark()<br />```</p>')
expect(formatted).toMatchSnapshot()
})
})
async function render(content: string, emojis?: Record<string, Emoji>) { async function render(content: string, emojis?: Record<string, Emoji>) {
const vnode = contentToVNode(content, emojis) const vnode = contentToVNode(content, emojis)
const html = (await renderToString(vnode)) const html = (await renderToString(vnode))
.replace(/<!--[\[\]]-->/g, '') .replace(/<!--[\[\]]-->/g, '')
const formatted = format(html, {
parser: 'html',
})
return { return {
vnode, vnode,
html, html,
formatted,
} }
} }
describe('rich-content', () => { // mocks
it('plain', async () => { vi.mock('vue-router', () => {
const { html } = await render('Hello\nWorld') return {
expect(html).toMatchSnapshot() RouterLink: defineComponent((attrs) => {
}) return () => h('a', attrs)
}),
}
})
vi.mock('../components/content/ContentCode.vue', () => {
return {
default: defineComponent({
props: {
code: {
type: String,
required: true,
},
lang: {
type: String,
required: true,
},
},
setup(props) {
const raw = computed(() => decodeURIComponent(props.code).replace(/&#39;/g, '\''))
return () => h('pre', { lang: props.lang }, raw.value)
},
}),
}
}) })

View File

@ -1,6 +1,7 @@
import { resolve } from 'path' import { resolve } from 'path'
import { defineConfig } from 'vitest/config' import { defineConfig } from 'vitest/config'
import Vue from '@vitejs/plugin-vue' import Vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({ export default defineConfig({
resolve: { resolve: {
@ -10,5 +11,15 @@ export default defineConfig({
}, },
plugins: [ plugins: [
Vue(), Vue(),
AutoImport({
dts: false,
imports: [
'vue',
'@vueuse/core',
],
dirs: [
'composables',
],
}),
], ],
}) })