We've already explored how we can write tests to discover and specify current functionality, and, in previous chapters, we discussed the obvious benefits of following a Test-Driven-Development (TDD) approach. It follows that we should, when operating in an unfamiliar code base, always confirm our changes via cleanly written tests.
In our previous example of introducing the capability of rendering videos to GalleryImage, it would be wise to add a simple test to confirm that <VIDEO> is correctly rendered when the URL contains the "/VIDEO/" substring. This prevents the possibility of future regressions and gives us a strong level of confidence that it works as expected:
import { mount } from 'enzyme';
import GalleryImage from './GalleryImage';
describe('GalleryImage', () => {
it('Renders a <VIDEO> when URL contains "/VIDEO/"', () => {
const rendered = mount(
<GalleryImage url="https://cdn.example.org/VIDEO/1234" />
);
expect(rendered.find('video')).to.have.lengthOf(1);
});
it('Renders a <IMG> when URL contains "/IMAGE/"', () => {
const rendered = mount(
<GalleryImage url="https://cdn.example.org/IMAGE/1234" />
);
expect(rendered.find('img')).to.have.lengthOf(1);
});
});
This is a rather simple test; however, it completely encodes the expectations we have after making our changes. When making small and self-contained changes or larger systemic changes, it's so incredibly valuable to verify and communicate our intent via tests like these. As well as preventing regressions, they aid our colleagues in terms of immediate code review, and the entire team in terms of documentation and general reliability. As such, it's quite normal and preferable to have a team mandate or policy that says you cannot commit a change if it does not come with a test. Enforcing this will, over time, create a code base that produces more reliable functionality for users and is more pleasant to work with for fellow programmers.
We've now completed the section on Inheriting code, and so you should have a good foundational knowledge of how to deal with such a situation. Another challenge in dealing with other people's code is the selection and integration of third-party code, meaning libraries and frameworks. We'll explore this now.