文件
mynode/packages/editor/CodeMirror/extensions/rendering/renderBlockMedia.test.ts
chen 301194963b
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
feat: Initial clean release of CHM
2026-11-04 11:29:39 +08:00

70 行
2.7 KiB
TypeScript

import { EditorSelection } from '@codemirror/state';
import createTestEditor from '../../testing/createTestEditor';
import renderBlockMedia from './renderBlockMedia';
import { EditorView } from '@codemirror/view';
const allowMediaInfoToResolve = async () => {
// Yield to the event loop. Since resource info is fetched asynchronously, this is
// needed to allow the asynchronous promise code to run
await Promise.resolve();
};
const resolveResourceInfo = jest.fn((src: string) => {
const match = src.match(/:\/([a-zA-Z0-9]{32})/);
const id = match ? match[1] : '';
const mimeById: Record<string, string> = {
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa': 'audio/mpeg',
'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb': 'video/mp4',
'cccccccccccccccccccccccccccccccc': 'application/pdf',
};
const mime = mimeById[id];
if (!mime) return Promise.resolve(null);
return Promise.resolve({ url: `https://example.com/${id}`, mime });
});
const createEditor = async (initialMarkdown: string) => {
const editor = await createTestEditor(
initialMarkdown,
EditorSelection.cursor(0),
['Link'],
[renderBlockMedia({ resolveImageSrc: async () => '', openLink: () => {}, resolveResourceInfo })],
);
await allowMediaInfoToResolve();
return editor;
};
const findMedia = (editor: EditorView) => {
return editor.dom.querySelectorAll('div.cm-md-media > audio, div.cm-md-media > video');
};
describe('renderBlockMedia', () => {
test.each([
{ markup: '[recording.m4a](:/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)', tag: 'AUDIO' },
{ markup: '[video.mp4](:/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb)', tag: 'VIDEO' },
{ markup: '[3月24日(1).mp4](:/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb)', tag: 'BODY' },
])('should render a player below a standalone media link (case %#)', async ({ markup, tag }) => {
const editor = await createEditor(markup);
const media = findMedia(editor);
expect(media).toHaveLength(1);
expect(media[0].getAttribute('aria-label')).toContain(tag === 'BODY' ? '3月24日(1).mp4' : tag === 'AUDIO' ? 'recording.m4a' : 'video.mp4');
// The raw Markdown must stay editable above the player
expect(editor.state.doc.toString()).toContain(markup);
});
test('should not render a player for non-media attachments', async () => {
const editor = await createEditor('[doc.pdf](:/cccccccccccccccccccccccccccccccc)');
expect(findMedia(editor)).toHaveLength(0);
// The leftover placeholder wrapper must be removed
expect(editor.dom.querySelectorAll('div.cm-md-media')).toHaveLength(0);
});
test('should not render a player for web links', async () => {
const editor = await createEditor('[video](https://example.com/video.mp4)');
expect(findMedia(editor)).toHaveLength(0);
expect(editor.dom.querySelectorAll('div.cm-md-media')).toHaveLength(0);
});
});