Friday, April 12, 2024
HomeJavaScriptConstruct a Chrome Extension that can Make Your Fb Posts Higher?

Construct a Chrome Extension that can Make Your Fb Posts Higher?

construct a chrome extension, manipulate and work together with a web page and publish it to the Chrome Internet Retailer? Right here’s how I created a Chrome extension that allows me to fashion the textual content in my posts and feedback – and the way you are able to do it too

I publish on Fb often. I assume many different folks do this too. Typically, I need to emphasize a specific phrase or phrase in my posts. I received used to instruments reminiscent of Slack or Google docs, the place I press ctrl/cmd + b, and my textual content turns daring.

On Fb, it doesn’t work. The options I discovered have been to go to an internet site, paste your phrase, click on on a button to alter your textual content to daring, copy it, and paste it again on Fb.

That’s tiresome. I’m a developer – there have to be a greater approach, proper?

Per week in the past, I printed an article impressed by Keren Kenzi’s speak on how one can construct a chrome extension. I promised I might construct one thing helpful with it and couldn’t discover the time, however a few of you readers contacted me to ask what’s with my mission – so right here it’s now. A chrome extension that can assist you write daring textual content on Fb posts and feedback (even messenger, Twitter, and LinkedIn work…).

If you’re not into the technical stuff – you possibly can seize the extension right here.

How did I Construct the Social Textual content Type Chrome Extension?

Setup Testing Infrastructure for a Chrome Extension?

After making a folder, initiating it with git init and npm init, I put in some wanted dependencies:

npm i -D jest babel-jest @babel/core @babel/plugin-transform-module-commonjs jest-environment-jsdom sinon-chrome

These are all devDependencies wanted for testing our code.

Then we have to configure babel and jest to work properly collectively:

Babel and Jest configuration. See the commit right here

Take a look at a Click on Occasion in a Chrome Extension

Our extension goes to be easy for now. We can have a boldenizer button. On click on, we’ll get the chosen textual content and exchange it with a daring model of it.

Our first check goes to appear like this:

describe(`popup`, perform () {
    it(`ought to set a listener on the bolderize button`, async perform () {
        doc.physique.innerHTML = '<button class="bolderize">Bolderize</button>';
        const bolderizeButton = doc.querySelector('.bolderize');
        const originalAddEventListener = bolderizeButton.addEventListener;
        const spy = jest.fn();
        jest.spyOn(bolderizeButton, 'addEventListener').mockImplementation((eventName, _) => {
            originalAddEventListener(eventName, spy);
        await import('./popup.js'); on();
        count on(spy).toHaveBeenCalled();

Within the code above, we’re testing our extension’s popup script. The primary check is straightforward – it ought to set a listener on a bolderize button.

We create the wanted HTML (a button with a category bolderize). We then mock the addEventListener and set a mock implementation in its stead. What it does is about our spy as an alternative of any callback set within the addEventListener. This fashion, we are able to count on our spy to be known as when the button is clicked.

The await import ('./popup.js') acts as calling our script by way of a script tag (as we’d do in our HTML file).

Operating the check with a easy jest command fails as a result of jest can’t do dynamic imports by itself (with node 16, not less than). Including NODE_OPTIONS=--experimental-vm-modules solves this problem.

See the commit right here.

Now that the check fails for an actual cause, we are able to work on the code that makes it move. In our popup.js file, we add the next code:

const button = doc.querySelector('.bolderize');
button.addEventListener('click on', () => {


So simple as that, the check passes, and everyone’s completely satisfied. A small refactor to our assessments would make it rather more simple for future builders:

describe(`popup`, perform () {
    it(`ought to set a listener on the bolderize button`, async perform () {
        const bolderizeButton = doc.querySelector('.bolderize');
        const spy = spyOnClickCallback(bolderizeButton);
        await import('./popup.js'); on();
        count on(spy).toHaveBeenCalled();

The check I wrote at first was a bit clumsy. With the ability of refactoring, I made it extra welcoming to others. See the commit right here.

Set off a Script on the Present Tab?

Slightly Chrome API voodoo comes into play now. chrome.tabs.question is the API that permits us to question for open tabs and get their IDs. You might, for example, discover all of the tabs with a sure URL (which may be tremendous helpful). For us, all we want is the present tab, so we have to name it like this:

chrome.tabs.question({lively: true, currentWindow: true})

Right here’s what we need to occur:

    it(`ought to work on present tab`, async perform () {
        jest.spyOn(chrome.tabs, 'question');

        const bolderizeButton = doc.querySelector('.bolderize');
        await import('./popup.js'); on();

        count on(chrome.tabs.question).toHaveBeenCalledWith({lively: true, currentWindow: true}, count on.any(Perform));

We wish our code to work on our present tab. It has the worth of giving us the tab’s ID for future use. We’re going to mock Chrome’s API right here utilizing jest.spy. We make the identical transfer of including a button, importing our script, and clicking the button. We ultimately want the question to be known as with the article that ensures we’re on the present tab.

Right here’s the commit for this check.

The implementation is straightforward:

The strains that have been added to make the “present tab” check move

Whereas engaged on the implementation, I couldn’t make it work. I discovered I made a mistake and needed to repair the addEventListener mock to additionally name the unique callback – in any other case, our fantastic script doesn’t run in any respect. Whoopsy…

Including the decision to the unique callback of the press listener

You will discover the total commit right here.

Now that the whole lot’s passing, a small refactor is to ensure that the assessments. The next strains repeat themselves:

const bolderizeButton = doc.querySelector('.bolderize');

This commit simply extracted them to a beforeEach assertion.

Make a Textual content Daring?

We is not going to go over the implementation intimately, however it’s fairly simple and may be seen within the implementation commit. The file utils/bolderizeWord.js holds the entire bolding logic. It’s an implementation element, so no assessments are written for this file – its results are examined within the public API.

What we want to focus is the utilization of the executeScipt API.

We have to ship it a configuration object and an elective callback.

The article should include a goalproperty which is a tab ID. We get this from the tabs.question we have already got in place.

It additionally optionally accepts a func property – a perform we write to run on the web page (identical to you’d run it within the console). There are just a few extra choices you can examine within the docs.

The elective callback returns the outcome from the perform we despatched it to execute by way of the func attribute. This callback runs within the context of our popup, so we can’t use DOM manipulation of the web page the person interacts with.

The getSelectionText perform seems to be like this:

perform getSelectionText() {
return window.getSelection().toString();

Keep in mind it runs within the context of the web page the person is visiting proper now (for example – fb).

The callback for this script execution seems to be like this:

perform(outcomes) {
const boldValues = bolderizeWord(outcomes[0].outcome);
chrome.scripting.executeScript( {
goal: {tabId},
func: modifySelection,
args: [boldValues]

outcomes[0].outcome is the chosen textual content despatched to us from getSelectionText. We use this to get the daring model of the textual content and ship it to a different executionScript name. This time – it’s going to run the modifySelection perform that can exchange our chosen textual content with the daring one.

Discover the args property – an array of arguments to ship to the func perform. Therefore, modifySelection seems to be like this:

perform modifySelection(newValue) {
    const choice = window.getSelection();
    const vary = choice.getRangeAt(0);
    const clone = vary.cloneRange();

    vary.endContainer.textContent =, newValue);


It accepts the newValue – which is the daring textual content – and replaces the chosen worth within the web page with the daring worth.

See the total file right here.

Use Our Extension Domestically?

Our extension will not be but an extension. We’d like just a few extra issues to make it so.

A manifest.json file

I’ll dive into the important elements right here. You’ll be able to learn the previous article concerning the fundamentals. We’ll populate the file with the next:

"identify": "Social Styled Textual content",
"model": "0.1",
"manifest_version": 3,
"motion": {
"default_icon": "belongings/photos/bold-option.png",
"default_popup": "ui/popup.html"
"icons": {
"128": "belongings/photos/bold-option.png"
"description": "This extension permits you to add daring textual content to fb posts",
"permissions": [

We inform the extension the place to search for the popup.html file, and the icons. We additionally describe the permissions – scripting and activeTab on this case – in any other case, chrome wouldn’t let our question and executeScript run. Every API requires a unique permission, as said within the documentation.

A popup.html file

We said the situation of the popup file — so we’ll create it there and set its content material:

        physique {
            width: 100px;
            padding: 25px;
            text-align: heart;
    <button class="bolderize">Bolderize</button>
    <script kind="module" src=""></script>

It merely provides a button with the category bolderize and imports the popup.js – very similar to what we did in our… check 🙂

I additionally added the picture file (bold-option.png) to the repository, however that doesn’t require an excessive amount of explaining.

Take a look at the Extension Domestically

This was defined intimately right here. In essence, you need to open the extension supervisor within the browser and switch Developer mode on. Then you’ll have a button to load an extension from an area folder. Once I do this, my extension will likely be put in, and I’ll be capable to use it:

The Boldenizer button in motion on Fb

The enjoyable factor is — this trick works in each social community. I attempted it on Twitter and LinkedIn too. Test it out 🙂

See the total code within the repository.

publish the chrome extension?

That is truly the simple half. Simply head over to and observe the directions. Be aware it prices 5$ to open a Chrome Internet Retailer account, however as soon as your extension is on the market — it’s the perfect 5$ you’ll ever make investments. Okay — aside from that scrumptious Waffle with ice cream and melted chocolate…

Only a small word to avoid wasting you frustration – common approval time for brand new extensions is three days. Should you require extra complicated permissions (like file system) – you’d may need to attend longer.


This was a considerably hacky TDD demonstration. There are another assessments I might have performed to make me really feel higher about my code. Testing my HTML to make sure the button exists (integration-test) might turn out to be useful.

Extra options can clearly be added to the extension, like extra languages (it presently helps solely English and numbers), extra kinds (italic, underline, strikethrough, and so on.), design, documentation, and extra.

If you wish to assist, be at liberty to contribute to the repository. As at all times, be at liberty to achieve out with questions within the feedback or on social media.

Thanks quite a bit to Michal Porag from Pull Request and Miki Ezra Stanger for the sort and thorough assessment of this text



Please enter your comment!
Please enter your name here

Most Popular

Recent Comments