Path: blob/main/extensions/markdown-language-features/src/test/pasteUrl.test.ts
3292 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import * as assert from 'assert';5import 'mocha';6import * as vscode from 'vscode';7import { InMemoryDocument } from '../client/inMemoryDocument';8import { createInsertUriListEdit, imageEditKind, linkEditKind } from '../languageFeatures/copyFiles/shared';9import { InsertMarkdownLink, findValidUriInText, shouldInsertMarkdownLinkByDefault } from '../languageFeatures/copyFiles/smartDropOrPaste';10import { noopToken } from '../util/cancellation';11import { UriList } from '../util/uriList';12import { createNewMarkdownEngine } from './engine';13import { joinLines } from './util';1415function makeTestDoc(contents: string) {16return new InMemoryDocument(vscode.Uri.file('test.md'), contents);17}1819suite('createEditAddingLinksForUriList', () => {2021test('Markdown Link Pasting should occur for a valid link (end to end)', async () => {22const result = createInsertUriListEdit(23new InMemoryDocument(vscode.Uri.file('test.md'), 'hello world!'), [new vscode.Range(0, 0, 0, 12)], UriList.from('https://www.microsoft.com/'));24// need to check the actual result -> snippet value25assert.strictEqual(result?.label, 'Insert Markdown Link');26});2728suite('validateLink', () => {2930test('Markdown pasting should occur for a valid link', () => {31assert.strictEqual(32findValidUriInText('https://www.microsoft.com/'),33'https://www.microsoft.com/');34});3536test('Markdown pasting should occur for a valid link preceded by a new line', () => {37assert.strictEqual(38findValidUriInText('\r\nhttps://www.microsoft.com/'),39'https://www.microsoft.com/');40});4142test('Markdown pasting should occur for a valid link followed by a new line', () => {43assert.strictEqual(44findValidUriInText('https://www.microsoft.com/\r\n'),45'https://www.microsoft.com/');46});4748test('Markdown pasting should not occur for a valid hostname and invalid protool', () => {49assert.strictEqual(50findValidUriInText('invalid:www.microsoft.com'),51undefined);52});5354test('Markdown pasting should not occur for plain text', () => {55assert.strictEqual(56findValidUriInText('hello world!'),57undefined);58});5960test('Markdown pasting should not occur for plain text including a colon', () => {61assert.strictEqual(62findValidUriInText('hello: world!'),63undefined);64});6566test('Markdown pasting should not occur for plain text including a slashes', () => {67assert.strictEqual(68findValidUriInText('helloworld!'),69undefined);70});7172test('Markdown pasting should not occur for a link followed by text', () => {73assert.strictEqual(74findValidUriInText('https://www.microsoft.com/ hello world!'),75undefined);76});7778test('Markdown pasting should occur for a link preceded or followed by spaces', () => {79assert.strictEqual(80findValidUriInText(' https://www.microsoft.com/ '),81'https://www.microsoft.com/');82});8384test('Markdown pasting should not occur for a link with an invalid scheme', () => {85assert.strictEqual(86findValidUriInText('hello:www.microsoft.com'),87undefined);88});8990test('Markdown pasting should not occur for multiple links being pasted', () => {91assert.strictEqual(92findValidUriInText('https://www.microsoft.com/\r\nhttps://www.microsoft.com/\r\nhttps://www.microsoft.com/\r\nhttps://www.microsoft.com/'),93undefined);94});9596test('Markdown pasting should not occur for multiple links with spaces being pasted', () => {97assert.strictEqual(98findValidUriInText('https://www.microsoft.com/ \r\nhttps://www.microsoft.com/\r\nhttps://www.microsoft.com/\r\n hello \r\nhttps://www.microsoft.com/'),99undefined);100});101102test('Markdown pasting should not occur for just a valid uri scheme', () => {103assert.strictEqual(104findValidUriInText('https://'),105undefined);106});107});108109suite('createInsertUriListEdit', () => {110test('Should create snippet with < > when pasted link has an mismatched parentheses', () => {111const edit = createInsertUriListEdit(makeTestDoc(''), [new vscode.Range(0, 0, 0, 0)], UriList.from('https://www.mic(rosoft.com'));112assert.strictEqual(edit?.edits?.[0].snippet.value, '[${1:text}](<https://www.mic(rosoft.com>)');113});114115test('Should create Markdown link snippet when pasteAsMarkdownLink is true', () => {116const edit = createInsertUriListEdit(makeTestDoc(''), [new vscode.Range(0, 0, 0, 0)], UriList.from('https://www.microsoft.com'));117assert.strictEqual(edit?.edits?.[0].snippet.value, '[${1:text}](https://www.microsoft.com)');118});119120test('Should use an unencoded URI string in Markdown link when passing in an external browser link', () => {121const edit = createInsertUriListEdit(makeTestDoc(''), [new vscode.Range(0, 0, 0, 0)], UriList.from('https://www.microsoft.com'));122assert.strictEqual(edit?.edits?.[0].snippet.value, '[${1:text}](https://www.microsoft.com)');123});124125test('Should not decode an encoded URI string when passing in an external browser link', () => {126const edit = createInsertUriListEdit(makeTestDoc(''), [new vscode.Range(0, 0, 0, 0)], UriList.from('https://www.microsoft.com/%20'));127assert.strictEqual(edit?.edits?.[0].snippet.value, '[${1:text}](https://www.microsoft.com/%20)');128});129130test('Should not encode an unencoded URI string when passing in an external browser link', () => {131const edit = createInsertUriListEdit(makeTestDoc(''), [new vscode.Range(0, 0, 0, 0)], UriList.from('https://www.example.com/path?query=value&another=value#fragment'));132assert.strictEqual(edit?.edits?.[0].snippet.value, '[${1:text}](https://www.example.com/path?query=value&another=value#fragment)');133});134135test('Should add image for image file by default', () => {136const edit = createInsertUriListEdit(makeTestDoc(''), [new vscode.Range(0, 0, 0, 0)], UriList.from('https://www.example.com/cat.png'));137assert.strictEqual(edit?.edits?.[0].snippet.value, '');138});139140test('Should be able to override insert style to use link', () => {141const edit = createInsertUriListEdit(makeTestDoc(''), [new vscode.Range(0, 0, 0, 0)], UriList.from('https://www.example.com/cat.png'), {142linkKindHint: linkEditKind,143});144assert.strictEqual(edit?.edits?.[0].snippet.value, '[${1:text}](https://www.example.com/cat.png)');145});146147test('Should be able to override insert style to use images', () => {148const edit = createInsertUriListEdit(makeTestDoc(''), [new vscode.Range(0, 0, 0, 0)], UriList.from('https://www.example.com/'), {149linkKindHint: imageEditKind,150});151assert.strictEqual(edit?.edits?.[0].snippet.value, '');152});153});154155156suite('shouldInsertMarkdownLinkByDefault', () => {157158test('Smart should be enabled for selected plain text', async () => {159assert.strictEqual(160await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('hello world'), InsertMarkdownLink.SmartWithSelection, [new vscode.Range(0, 0, 0, 12)], noopToken),161true);162});163164test('Smart should be enabled in headers', async () => {165assert.strictEqual(166await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('# title'), InsertMarkdownLink.Smart, [new vscode.Range(0, 2, 0, 2)], noopToken),167true);168});169170test('Smart should be enabled in lists', async () => {171assert.strictEqual(172await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('1. text'), InsertMarkdownLink.Smart, [new vscode.Range(0, 3, 0, 3)], noopToken),173true);174});175176test('Smart should be enabled in blockquotes', async () => {177assert.strictEqual(178await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('> text'), InsertMarkdownLink.Smart, [new vscode.Range(0, 3, 0, 3)], noopToken),179true);180});181182test('Smart should be disabled in indented code blocks', async () => {183assert.strictEqual(184await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc(' code'), InsertMarkdownLink.Smart, [new vscode.Range(0, 4, 0, 4)], noopToken),185false);186});187188test('Smart should be disabled in fenced code blocks', async () => {189assert.strictEqual(190await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('```\r\n\r\n```'), InsertMarkdownLink.Smart, [new vscode.Range(0, 5, 0, 5)], noopToken),191false);192193assert.strictEqual(194await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('~~~\r\n\r\n~~~'), InsertMarkdownLink.Smart, [new vscode.Range(0, 5, 0, 5)], noopToken),195false);196});197198test('Smart should be disabled in math blocks', async () => {199200let katex: any = (await import('@vscode/markdown-it-katex')).default;201if (typeof katex === 'object') {202katex = katex.default;203}204205const engine = createNewMarkdownEngine();206(await engine.getEngine(undefined)).use(katex);207assert.strictEqual(208await shouldInsertMarkdownLinkByDefault(engine, makeTestDoc('$$\r\n\r\n$$'), InsertMarkdownLink.Smart, [new vscode.Range(0, 5, 0, 5)], noopToken),209false);210});211212test('Smart should be disabled in link definitions', async () => {213assert.strictEqual(214await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('[ref]: http://example.com'), InsertMarkdownLink.Smart, [new vscode.Range(0, 4, 0, 6)], noopToken),215false);216217assert.strictEqual(218await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('[ref]: '), InsertMarkdownLink.Smart, [new vscode.Range(0, 7, 0, 7)], noopToken),219false);220221assert.strictEqual(222await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('[ref]: '), InsertMarkdownLink.Smart, [new vscode.Range(0, 0, 0, 0)], noopToken),223false);224});225226test('Smart should be disabled in html blocks', async () => {227assert.strictEqual(228await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('<p>\na\n</p>'), InsertMarkdownLink.Smart, [new vscode.Range(1, 0, 1, 0)], noopToken),229false);230});231232test('Smart should be disabled in html blocks where paste creates the block', async () => {233assert.strictEqual(234await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('<p>\n\n</p>'), InsertMarkdownLink.Smart, [new vscode.Range(1, 0, 1, 0)], noopToken),235false,236'Between two html tags should be treated as html block');237238assert.strictEqual(239await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('<p>\n\ntext'), InsertMarkdownLink.Smart, [new vscode.Range(1, 0, 1, 0)], noopToken),240false,241'Between opening html tag and text should be treated as html block');242243assert.strictEqual(244await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('<p>\n\n\n</p>'), InsertMarkdownLink.Smart, [new vscode.Range(1, 0, 1, 0)], noopToken),245true,246'Extra new line after paste should not be treated as html block');247});248249test('Smart should be disabled in Markdown links', async () => {250assert.strictEqual(251await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('[a](bcdef)'), InsertMarkdownLink.Smart, [new vscode.Range(0, 4, 0, 6)], noopToken),252false);253});254255test('Smart should be disabled in Markdown images', async () => {256assert.strictEqual(257await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc(''), InsertMarkdownLink.Smart, [new vscode.Range(0, 5, 0, 10)], noopToken),258false);259});260261test('Smart should be disabled in inline code', async () => {262assert.strictEqual(263await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('``'), InsertMarkdownLink.Smart, [new vscode.Range(0, 1, 0, 1)], noopToken),264false,265'Should be disabled inside of inline code');266267assert.strictEqual(268await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('``'), InsertMarkdownLink.Smart, [new vscode.Range(0, 0, 0, 0)], noopToken),269true,270'Should be enabled when cursor is outside but next to inline code');271272assert.strictEqual(273await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('`a`'), InsertMarkdownLink.Smart, [new vscode.Range(0, 3, 0, 3)], noopToken),274true,275'Should be enabled when cursor is outside but next to inline code');276});277278test('Smart should be enabled when pasting over inline code ', async () => {279assert.strictEqual(280await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('`xyz`'), InsertMarkdownLink.Smart, [new vscode.Range(0, 0, 0, 5)], noopToken),281true);282});283284test('Smart should be disabled in inline math', async () => {285assert.strictEqual(286await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('$$'), InsertMarkdownLink.SmartWithSelection, [new vscode.Range(0, 1, 0, 1)], noopToken),287false);288});289290test('Smart should be enabled for empty selection', async () => {291assert.strictEqual(292await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('xyz'), InsertMarkdownLink.Smart, [new vscode.Range(0, 0, 0, 0)], noopToken),293true);294});295296test('SmartWithSelection should disable for empty selection', async () => {297assert.strictEqual(298await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('xyz'), InsertMarkdownLink.SmartWithSelection, [new vscode.Range(0, 0, 0, 0)], noopToken),299false);300});301302test('Smart should disable for selected link', async () => {303assert.strictEqual(304await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('https://www.microsoft.com'), InsertMarkdownLink.SmartWithSelection, [new vscode.Range(0, 0, 0, 25)], noopToken),305false);306});307308test('Smart should disable for selected link with trailing whitespace', async () => {309assert.strictEqual(310await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc(' https://www.microsoft.com '), InsertMarkdownLink.SmartWithSelection, [new vscode.Range(0, 0, 0, 30)], noopToken),311false);312});313314test('Should evaluate pasteAsMarkdownLink as true for a link pasted in square brackets', async () => {315assert.strictEqual(316await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('[abc]'), InsertMarkdownLink.SmartWithSelection, [new vscode.Range(0, 1, 0, 4)], noopToken),317true);318});319320test('Should evaluate pasteAsMarkdownLink as false for selected whitespace and new lines', async () => {321assert.strictEqual(322await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc(' \r\n\r\n'), InsertMarkdownLink.SmartWithSelection, [new vscode.Range(0, 0, 0, 7)], noopToken),323false);324});325326test('Smart should be disabled inside of autolinks', async () => {327assert.strictEqual(328await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc('<>'), InsertMarkdownLink.Smart, [new vscode.Range(0, 1, 0, 1)], noopToken),329false);330});331332test('Smart should be disabled in frontmatter', async () => {333const textDoc = makeTestDoc(joinLines(334`---`,335`layout: post`,336`title: Blogging Like a Hacker`,337`---`,338``,339`Link Text`340));341assert.strictEqual(342await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), textDoc, InsertMarkdownLink.Smart, [new vscode.Range(0, 0, 0, 0)], noopToken),343false);344345assert.strictEqual(346await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), textDoc, InsertMarkdownLink.Smart, [new vscode.Range(1, 0, 1, 0)], noopToken),347false);348});349350test('Smart should enabled after frontmatter', async () => {351assert.strictEqual(352await shouldInsertMarkdownLinkByDefault(createNewMarkdownEngine(), makeTestDoc(joinLines(353`---`,354`layout: post`,355`title: Blogging Like a Hacker`,356`---`,357``,358`Link Text`359)), InsertMarkdownLink.Smart, [new vscode.Range(5, 0, 5, 0)], noopToken),360true);361});362});363});364365366