Projects
-
From Idea to Acceptance: Crafting a Standout Conference Proposal
Honored to have been a part of this panel on how to get started speaking at tech conferences and meetups – with an emphasis on writing a good proposal – with some very talented and prolific folks. And a big thank you to Joy Hopkins for organizing the panel and having me on.
-
Six Things I Bet You Didn't Know You Could Do With Chrome's Devtools, Part 2
This is the second of two posts about devtools tricks; these are sourced from a conference talk I attended in early November as well as from other things I’ve picked up across the years.
In the first post we covered:
- Time functions with
console.time()andconsole.timeEnd() - Watch any DOM element for changes
- Monitor any function in the browser’s context
In this post, we’ll cover:
- Edit any website WYSIWYG style
- Record and replay any user actions
- Throttle only specific network requests
So without further ado, let’s dive in.
-
Edit any website WYSIWYG style
I love messing around with the DOM on the Elements tab. What would it look like if I removed this class from this element? What happens if the text overflows its container on this page? These are all things you can do by manually editing the node you care about on the Elements tab, but it can be a little fussy. I recently learned that you can make the entire page editable. By running
document.body.contentEditable = truein the console…well, look at this nonsense:I imagine this would be slightly useful for testing UI edge cases, and very useful for entertaining middle schoolers.
Source: Mindi Weik, who showed me a preview of a talk that included this tip – her talk is not online anywhere as far as I’m aware.
Support: All browsers
-
Record and replay any series of actions.
I’ve truly always just ignored this tab, but if you jump into the Recorder tab, hit record, take any series of actions on a site (clicking buttons, navigating, entering text in forms), and then stop recording, you can then replay those actions, share them with another person, and even generate code for many popular testing frameworks.
During Mike’s session, some attendees were really excited about the possibility of catching an “unreproducible” bug by recording the steps to generate the bug and simply replaying the actions repeatedly until the bug appeared; I was excited about getting React Testing Library code that would finally convince my colleagues that writing FE tests are worth the effort :) To my disappointment (and complete lack of surprise), however, the code output by the recorder isn’t up to my standards; it tends toward hyper-specific selectors (ex:
#story > section > div:nth-child(3) > div > div:nth-child(3)) rather than how I prefer to write tests, using more semantic selectors.I still think the generated code could be useful as a starting point, but even if I never use that, I can definitely imagine a scenario where I send a colleague a bug report that says “Run this recording and see if you see the same bug I do…”
Source: Mike Rapa
Support: Chrome for sure; Firefox doesn’t seem to have a record-and-replay function (it does allow you to record for performance analysis, which is different).
-
Throttle specific URLs.
Instead of throttling the browser’s connection speed overall, to simulate your end user being on a slow network, you can now tell Chrome to throttle or block only certain resources, to simulate what happens if a third-party API goes down or is overwhelmed.
This is only available in the Chrome Canary release, but will hopefully make its way into a general release in the next few months. DebugBear has some useful examples on how to get started now, if you can’t wait. There is an example of how to throttle an individual request as well as how to do wildcard throttling.
Source: DebugBear and Javascript Weekly
Support: Chrome only
- Time functions with
-
My 4 Testing Commandments
Bug huntingThis week I was a guest instructor at the Black Venture Capital Consortium’s Software Engineering Career Track. This is was my second year volunteering with BVCC on the SWE track, and it’s super rewarding, although I’m still learning how to deal with the “Gen Z stare” on Zoom. (Teachers who do a lot of online instruction, my hearts go out to you.)
This year, my topic was testing – both manual and automated. The students are pretty new to software engineering, so manual tests were more their speed, for the most part, and we had fun trying to break a demo application.
But automated tests are the thing software developers will spend more of their time on than manual, so I tried to give them a little taste of automated testing principles.
This is, more or less, what I said:
Tests are your contract. When you write tests, you’re forced to decide how a method should behave. This is where you can decide that a method will throw an error when given bad data vs printing a message in the console. This is where you decide that no, you’re not going to allow this edge case. Tests help you think through what you want to code, and six months later, they help you remember what you meant to code.
Always test your tests. You can use a mutation testing framework or just manually, temporarily, modify your code or test assertions. (Sometimes I just change all
assertTrues toassertFalses.) But without knowing that your tests are doing what you think they’re doing, you can’t have confidence in them.Don’t put too much stock in unit test examples when you’re learning. Many, many “how to write unit tests” blog posts use math as their example. This makes sense, because if you know that 2+2=4, it’s easier to focus on the syntax of the test code, and you don’t need to waste brainpower on understanding what the method-under-test is doing. But if you’re new to unit testing, you might be asking yourself, “why on earth would I need to test that 2+2=4”? You don’t. You’ll never write a unit test testing an “add” method in production, because you will never write an “add” method. Don’t focus on the method-under-test, just pay attention to the syntax and trust that it gets more interesting.
Tests and accessibility go hand in hand. Okay, this is more about integration tests for a web app than unit tests, but most good testing libraries, such as React Testing Library, use the same affordances to run tests on rendered elements as a screen reader user would use to interact with a page. If it’s hard to test, it’s probably hard for a screen-reader user to use. (I don’t feel confident saying that if it’s easy to test, the site is accessible–but it can’t hurt.)
What would you add to these four?
-
Six Things I Bet You Didn't Know You Could Do With Chrome's Devtools, Part 1

I just got back from TechBash conference in Pennsylvania. It was a great couple of days of meeting new people, reconnecting with old friends, and of course learning a ton.
Many of the sessions I went to were fantastic, but my favorite session by far was by Mike Rapa about the power of the browser’s devtools. His presentation was (mostly) browser-agnostic, with the exception of a few things, because (and I can attest to this) Firefox’s devtools have markedly improved over the last few years. This post, however, is specific to Chrome, for reasons you will see soon.
So, with thanks to Mike, and a few other sources, here are six things I bet you didn’t know you could do with Chrome’s devtools.
This is part 1 of this topic, covering items 1-3. I wrote way too much for a single post!
In this post we’ll cover:
- Time functions with
console.time()andconsole.timeEnd() - Watch any DOM element for changes
- Monitor any function in the browser’s context
In the second post, coming soon, we’ll cover:
- Edit any website WYSIWYG style
- Record and replay any user actions
- Throttle only specific network requests
So let’s get going!
-
Time functions with
console.timeandconsole.timeEndI have been vaguely aware of the idea that
console.log()is just one method available in a vast cornucopia of logging methods, and I have dabbled withconsole.warn()andconsole.error(). I cannot say that I have ever usedconsole.table(), although I knew it existed.Had I ever, however, even heard of
console.time()andconsole.timeEnd()? No, and I bet most people haven’t. I recently needed to track down a bug where awindow.setTimeoutfunction seemed to be clearing itself earlier than expected, and so I wanted to log when a timer was set, for how long it was supposed to be set for, and when that timer cleared. Searching around yielded a lot of people suggesting complex options, including overloadingconsole, writing wrapper functions, and so on, implying that these built-in functions are not part of most folks’ knowledge.On the other hand,
console.time()andconsole.timeEnd()seem like just what the doctor ordered.Example from MDN:
console.time("answer time"); alert("Click to continue"); console.timeLog("answer time"); alert("Do a bunch of other stuff…"); console.timeEnd("answer time");More interesting example:
const [paused,setPaused] = useState(false); const [timeoutId,setTimeoutId] = useState(); const handleClick = ()=>{ if (paused){ console.log("unpausing") clearTimeout(timeoutId); console.timeEnd(timeoutId.toString()); setPaused(false); } else { console.log("pausing for 5 s, or when the user clicks the button next, whichever comes first") setPaused(true); const timeout = setTimeout(()=>setPaused(false),5000); console.time(timeout.toString()); setTimeoutId(timeout) } } return (<> <button onClick={handleClick}>{paused?"Unpause":"Pause"}</button> </>);Source: Mike Rapa’s talk, which I couldn’t find a recording of, but the github repo is here and is fantastic.
Support: This is part of JS, so any browser.
-
Watch a DOM element for changes and pause app execution when it does.
The DOM Breakpoints option lets you select an element from the DOM and, when something on the page would cause it to change, pause execution of the JS that is causing the change, entering Chrome’s debugger mode. I have known about placing
debugger;on a line in my JS/React to trigger debug mode, and of course there’s also the pause button on the Debugger tab, but a DOM breakpoint was also new to me.Visit this SO page and run the code snippet in the answer. If you inspect the element as it’s running, you can see the DOM highlight as it updates:
If you were to right click on it, choose “Break On”, and one of the options, you will now hit a breakpoint when that DOM element is modified, allowing you to see what Javascript is affecting this element.

Source: Mike Rapa’s talk
Support: Most major browsers, although Firefox behaves slightly differently than Chrome
-
Attach a listener to any function on the page
Say you’re debugging some interaction in some third-party script that you don’t control. (Something that used to come up a lot on my old team.) You’d like to know when the third-party script is doing something, but you can’t exactly go into that script’s code and add
console.log()(or one of the fancy console methods that we just learned about).Chrome lets you attach a listener to any function in the browser’s context, with
monitor.Contrived example:
function sum(x, y) { return x + y; } monitor(sum); sum(1,2) //results in console.log message: "Function sum called with arguments: 1,2"Source: Google documentation
Support: Chrome only
That’s it for the first half of this post! Come back later to see the next three tips.
- Time functions with
-
The Surprising Power of Jekyll's site.data

I’ve been speaking a lot this past year. This is new and exciting to me, and I want to track all my accomplishments, because each one of them feels new, exciting, and honestly a little scary. So keeping track of everything is a great way for me to mark these accomplishments (I may also have had a donut after my last talk at Momentum).
But do I want to manually update this page every time something changes? Heck naw. This is structured data, and Jekyll should treat it as such.
Enter site.data
Enter
site.data. Any structured file (JSON, YAML, CSV or TSV) you place in your Jekyll_datafolder will become accessible assite.data.filename1. You can then access it like any other variable. Jekyll is smart enough to interpret your file as a list which you can sort, filter, etc.What this means is I can create a CSV like this:
event_date,venue,talk,link 2025-10-16,Momentum Dev Con,Get Unblocked Faster,, ....and then access it via:
{% assign all_appearances = site.data.speaking_appearances | sort:'event_date' %} <h2>Upcoming</h2> {% for row in all_appearances %} {% assign date_to_check = row.event_date | date: '%s' %} {% if date_to_check > current_date %} <p> {{row.event_date | date: '%B %d, %Y'}}: {%if row.link%} <a href="{{row.link}}"> {%endif%} {{row.talk}} - {%if row.link%} </a> {%endif%} {{row.venue}} </p> {%endif%} {% endfor %}This looks like a lot if you’re not used to Liquid syntax, but it’s basically a fancy templating language. On the first line, we assign a variable to hold the “list of stuff in site.data.appearances, sorted by event_date” (which is one of the headers in the CSV). Then we loop through each item in the list and compare its date, which has been converted to a UNIX timestamp, to the current date (which I assigned earlier in the template). If the item has a date in the future, we render it to the page, optionally with a link to the source material.
This is already a huge time-saver, and means that all my dates, links, etc., will be rendered consistently, and I can change their styling/look without having to manually copy and paste.
But let’s not stop there. I don’t want to manually update a CSV that lives on my home computer (or in a github repo), that sounds boring. So inspired by my husband Chris Combs who has set up something similar, let’s automate this!
Enter a database that is not a database
Google Sheets is not a database, although I wouldn’t be the first person to use it as such. And for a simple way to store (a small amount of) structured data2, it’s pretty darn good.
So I copy my CSV from above into a google sheet and publish it to the web as a CSV. This does make the CSV publicly accessible for anyone who knows the URL, but I’m not storing any PII in here, so it’s fine. Then, as an extra line in my custom deploy pipeline as well as my custom preview script, I add:
wget https://docs.google.com/spreadsheets/link/to/spreadsheet?output=csv --output-document=${SITE_ROOT_DIR}/_data/speaking_appearances.csv || echo "Something went wrong"This means that every time I deploy, or launch a local version of the site with
bundle exec jekyll serve, I get the most up-to-date version of the Google sheet, which I can update from anywhere.Jekyll is still a static site generator, so I still have to deploy to see the most recent changes, but that works for me, for this thing that is only semi-regularly updated anyway. If this is not for you, you probably already know that and will not use Jekyll.
I hope this was useful! I definitely think there’s a lot more that can be done with Jekyll’s datafiles and I can’t wait to come up with more insane ideas.
Further reading
- Jekyll’s official site has some very cool examples of things you can do with a datafile.
Footnotes

