Article summary
Recently, I was trying to set up Cypress tests for my new drag-and-drop interface. I tried to use a Cypress plugin to trigger a drag on my component, but it just wouldn’t budge in the test. Everything worked in real life, so what was the deal? It turned out I was running into a pretty common issue. Often, the way testing frameworks simulate this kind of fiddly interaction doesn’t quite jibe with the signals your app is looking for.
For example, when you click and drag on a browser, dozens of events fire at once; pointerdown
, mousedown
, click
, mousemove
, and so on. But, testing tools like Cypress will usually only simulate a small subset of those events. And plugins for a complex action like drag and drop can be even more opaque and difficult to control.
In my case, I needed the plugin’s drag action to behave subtly differently than it did, in order to overcome my app’s use of dnd-kit’s activation constraint property. And I didn’t want to abandon my testing plugin completely because it provided a lot of other value.
This kind of problem with browser testing happens a lot, and, in this case, I ended up using patch-package.
How can I get this solved quickly?
There are a lot of cases in which it’s best to invest in doing something The Right Way. It’s usually good to pay down that technical debt early, make that PR on an open-source project, and commit to that valuable refactor.
But sometimes, what you need is some good old-fashioned duct tape. The problem you need to solve is niche, trivial, or otherwise unworthy of sinking much effort into. Maybe it’s just a step of a test and not production code. Or it’s a bug in a library that will never be patched. All you need is to get the dang thing working.
If only you could just make one tiny tweak to the source of that library… but you haven’t the time to wait for PR review, or maybe it’s unmaintained. And maybe making a fork of the package is more trouble than it’s worth. You might be able to edit the installed package to do what you want manually, but you can kiss those edits goodbye the next time you npm install
.
Unless…
Enter patch-package
, the absolute lowest-effort way to slap a bandage on your favorite package! 🩹 patch-package gives you a super easy way to create and apply your own small patch to an npm library, without the rigamarole of creating and publishing a fork. It’s fragile in the face of updates but super powerful in the right circumstances.
In my case, all I needed was to simulate a mouse wiggle to overcome my movement threshold, but you can follow the steps I’ll detail next to patch your own package.
How to create a patch.
Step 1
First, stick your hands right into node_modules
and make the edits you need to the installed package’s source. I know this feels backwards, but you have to trust the process.
In my case, I used Go to references
on the helper function I wanted to tweak, which led me to node_modules/@4tw/cypress-drag-drop/index.js
.
Here, I found the spot I wanted to trigger my mouse wiggle and added just two little lines, right in the middle of a chained command:
Bear with me, here. If you take a look at your git diff
, you’ll see your hard work (should have) gone unrecorded; typically most people .gitignore
their node_modules
folder, and rightly so. But we’re getting to it!
Step 2
Now, install patch-package: npm i patch-package
Step 3
Then, use the patch-package
command to produce a patch: npx patch-package package-name
In my case, this was npx patch-package @4tw/cypress-drag-drop
.
At this point, you’ll see a new .patch
file in your git diff
. https://www.gitkraken.com/learn/git/git-patch
Step 4
Now, you have everything you need to share your brilliant fix with your lucky teammates, but it’s a bit tedious to apply. Fortunately for you, you can inflict your new change upon them, and all CI machines henceforth, by taking advantage of the package.json
postinstall
step!
In your package.json
, under scripts
, add the following: `"postinstall": "patch-package"
. This will cause your patch to be applied after any npm install
automatically.
And there we have it! A super-light way to lazily tweak your favorite packages. Just use your newfound power responsibly — with fast patching comes great maintenance responsibility 😉