Add a test case when your open-source project’s issue is fixed.
Building a stable project is hard and time consuming. When you open source that project, reliability and stability is important because you need to establish that trust and authority. As your open source project evolves and new features are introduced, regressions (bugs that reappear) can sneak back into the code. To prevent this, it is important to add test cases whenever an issue is fixed. These test cases act as a safety net, ensuring that future changes don’t reintroduce old bugs.
In this article, we’ll explore the importance of adding test cases for bug fixes by examining two issues from Zustand’s repository — Issue #84 and Issue #86. Zustand, a popular state management library for React, experienced these bugs in its subscription management. Both issues were subtle but critical, and writing test cases for them ensures they won’t surface again in future releases.
When an issue is reported and fixed in a codebase, it’s tempting to move on after the fix. But without a dedicated test case that reproduces the problem, there is no guarantee that the issue won’t recur in future updates. Even if the code seems stable after the fix, new features or refactors can sometimes undo the correction.
Here’s why it’s crucial to add a test case after each bug fix:
Prevents Regressions: As the code evolves, automated tests ensure that past issues don’t creep back in.
Serves as Documentation: Test cases provide clear examples of what was fixed and how the software should behave under similar conditions.
Confidence in Future Development: Contributors can confidently make changes, knowing that tests will catch any breaks.
Now, let’s look at real-world examples from Zustand’s codebase and see how test cases were added after issues #84 and #86 were fixed.
The bug reported in Issue #84 revolved around Zustand’s subscription system. Under certain conditions, subscribers could be “orphaned” — meaning components subscribing to the store would stop receiving updates.
When state updates happened during the component lifecycle (e.g., unmounts or re-renders), the array of subscribers could be corrupted. This caused a component that had subscribed to the store to never get updates, as its listener was overwritten by another subscriber.
Subscribers are a Set. Here’s a proof from Zustand’s source code related to createStore
This test checks that the correct subscriber is removed when components unmount and ensures the subscription system functions as expected. Here’s what happens in the test:
A store is created with an initial count of 0.
Components subscribe to the count state.
The increment function is called when the component mounts, increasing the count.
After unmounting and mounting components, the test ensures that the right subscribers are removed and that the state update propagates correctly to the components still mounted.
This ensures the original bug, where subscribers would be corrupted during the lifecycle, does not reoccur.
In Issue #86, an issue was reported where subscribers would stop receiving updates after components remounted. This happened because subscribers in Zustand were being overwritten with the same index when switching between mounted components.
The issue boiled down to a problem in managing multiple subscribers — each subscriber was assigned an index, and when a new component subscribed, the indices could conflict. This caused one subscriber to overwrite another, leading to components not receiving state updates after a remount.
Subscribers are not overwritten when components are mounted and unmounted.
Multiple components can subscribe to the same store without conflict.
When the state changes, all subscribed components update correctly.
By testing for the correct number of count1 and count2 components receiving updates, the test guarantees that the fix for this issue works and won't regress in future versions of Zustand.
These two examples from Zustand illustrate why it is essential to add test cases after fixing bugs in an open-source project. They help ensure:
The original bug is fixed.
Future changes do not break the fix.
Contributors can refactor, add features, or improve performance without worrying about breaking functionality that was previously addressed.
By writing test cases after bug fixes, you contribute to the long-term health of the project, helping both maintainers and users trust that the project is stable and well-maintained.
Adding test cases after fixing bugs is a crucial habit for maintaining the integrity of your open-source project. As demonstrated in Zustand’s handling of Issues #84 and #86, these test cases help catch potential regressions and ensure the system behaves as expected in real-world scenarios.
So, the next time you fix a bug in your open-source project, don’t stop at the fix. Add a test case to ensure the issue is gone for good, safeguarding your project’s future stability.
Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.