Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

How to implement automatic text-to-link conversion in TypeScript?

+1
−2

I'm trying to create an automatic text-to-link conversion feature in a TypeScript application. The desired workflow is:

  1. Copy a URL to the clipboard
  2. Select some text
  3. Paste the URL - this should convert the selected text into a link pointing to the pasted URL

For example:

Selected text: "Click here"
Pasted URL: "https://www.example.com"

Returns: [Click here](https://www.example.com)

This allows easily creating links on the fly without typing Markdown syntax manually.

I tried implementing this in a TypeScript project with the following code:

let selectedText = '';

document.addEventListener('copy', e => {
  const selection = window.getSelection();
  if (selection) {
    selectedText = selection.toString();
  }
});

document.addEventListener('paste', e => {
  if (e.clipboardData) {
    const pasted = e.clipboardData.getData('text');
    if (isValidUrl(pasted)) {
      e.preventDefault();
      insertLink(selectedText, pasted);
    }
  }
});

function insertLink(text: string, url: string): void {
  document.execCommand('insertHTML', false, `[${text}](${url})`);
}

function isValidUrl(url: string): boolean {
  try {
    new URL(url);
    return true;
  } catch (err) {
    return false;
  }
}

To test this code, I set up a TypeScript project on Manjaro Linux and configured Jest for testing:

  1. Installed Node.js and npm using sudo pacman -S nodejs npm
  2. Created a new TS project
mkdir my-ts-project
cd my-ts-project
npm init -y
  1. Installed TypeScript with npm install --save-dev typescript
  2. Added a tsconfig.json file with npx tsc --init
  3. Installed Jest, ts-jest, and @types/jest packages with npm install --save-dev jest ts-jest @types/jest
  4. Added jest.config.js for configuration
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
};
  1. Added test script to package.json
  2. Wrote the code in src/index.ts and test cases in src/index.test.ts
// src/index.test.ts

import { Clipboard } from './mocks/clipboard';

describe('copy handler', () => {

  it('copies selected text to clipboard', () => {

    const selectedText = 'hello';

    window.getSelection = () => {
      return {
        toString: () => selectedText  
      } as unknown as Selection;
    };

    document.addEventListener('copy', e => {
      if(e.clipboardData) {
        e.clipboardData.setData('text', selectedText); 
      }
    });

    document.dispatchEvent(new Event('copy'));

    expect(Clipboard.prototype.writeText).toHaveBeenCalledWith(selectedText);
  });

});

describe('paste handler', () => {

  it('inserts link on valid url paste', () => {

    const url = 'https://example.com';
    Clipboard.prototype.clipboardText = url;

    document.addEventListener('paste', e => {
      if(e.clipboardData) {
        const pasted = Clipboard.prototype.readText();
        if(isValidUrl(pasted)) {
          insertLink('text', pasted);
        }
      }
    });

    document.dispatchEvent(new Event('paste'));

    expect(insertLink).toHaveBeenCalledWith('text', url);
  });

});
// src/mocks/clipboard.ts

export class Clipboard {
  public static prototype = {
    writeText: jest.fn(),
    readText: jest.fn(),
    clipboardText: ''
  };
}
  1. Ran tests with npm test

However, when running npm test, I got some errors:

> test@1.0.0 test
> jest

 FAIL  src/index.test.ts
  ● Test suite failed to run

    src/index.test.ts:25:32 - error TS2339: Property 'writeText' does not exist on type 'Clipboard'.

    25     expect(Clipboard.prototype.writeText).toHaveBeenCalledWith(selectedText);
                                      ~~~~~~~~~
    src/index.test.ts:35:25 - error TS2339: Property 'clipboardText' does not exist on type 'Clipboard'.

    35     Clipboard.prototype.clipboardText = url;
                               ~~~~~~~~~~~~~
    src/index.test.ts:39:44 - error TS2339: Property 'readText' does not exist on type 'Clipboard'.

    39         const pasted = Clipboard.prototype.readText();
                                                  ~~~~~~~~

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        2.056 s
Ran all test suites.

I want to write tests for:

  • empty clipboard
  • valid URL
  • invalid URL

How can I fix the errors and properly mock the clipboard in the tests?

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.
Why should this post be closed?

2 comment threads

Testing vs. Q&A (1 comment)
This technique is called ‘hijacking your users' paste function to do something they probably weren't ... (1 comment)

0 answers

Sign up to answer this question »