In the past few Media Library posts we haven't spent a lot of time thinking about testing. In this post we will catch up on any missing tests and fix at least one broken test.
Walk Through
I have started by running all tests. The first thing I am noticing is that the RegisterContainer test - 'renders and submits registration successfully' - is failing due to insufficient permissions. However, when I take a peak at the Firebase console I can see that the user in the test (newregister@example.com) is being created. This points to the issue being in the Firestore layer (where we are storing additional information about the user). If we look at Firestrore we can see the user is created in the users table. This leads me to believe the problem is with the cleanup part of the test. Sure enough, if we look at the authorization rules we wrote in the last post we did not allow a user permissions to delete themselves.
In this case I am going to edit the rule. I believe it is actually part of the new GDPR rules in the EU that a user be allowed to delete their account, so it makes sense to change the rule. However, this might not always be the case and in the future we might have to find creative ways to cleanup a test like this. Remember that these rules are not part of our project's source code (although I am maintaining a text file copy of the Firestore rules we have discussed in our project). We need to make this update in the Firestore rules in the Firebase console.
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow create;
allow get, update, delete: if request.auth.uid == userId;
allow list: if false;
}
match /{document=**} {
allow read, write: if request.auth.token.admin == true;
}
}
}
I want to look at the test coverage for our app but before I do this is a good time to update the libraries we are using. I am also going to manually update the versions of react and react-dom we are using. This is a good time to catch any problems with updated libraries. During this process npm also flagged a high vulnerability with react-scripts so I will force it to update at well.
npm update
npm install --save react@next react-dom@next
npm install --save react-scripts@latest
With that out of the way let's regenerate test coverage for our project (using coverage flag from Jest).
npm test -- --coverage
With the updates to Firebase there is some feedback in the tests that the previous setting to set timestampsInSnapshots is no longer required so I will comment that line out. Note that his setting is part of the Firebase config file that I cannot check into Github.
...
const db = firebase.firestore();
// db.settings({ timestampsInSnapshots: true });
...
There are a couple ways to view the coverage reports generated by Jest. I like to open lcov-report/index.html (from the coverage folder).
These are some of the things I am noticing:
- We do not have negative test cases for our db/users.js functions - we should add this.
- We do not have full coverage (primarily negative test cases) on redux/actions/auth.js. We can improve this.
- We need some level of testing for ResetPasswordForm.jsx. We will add testing to Account.jsx as the container for the form I would rather test that the form is rendering correctly and that it does what it is supposed to (instead of testing the form in isolation).
- We have Admin.jsx and Properties.jsx components with no coverage. We can create some very simple tests that we will enhance when we work on these pages in the future.
- We need some level of testing for all of the menu components. We should include testing of header components with this. This is a little bit tricky and at the heart of the application. To keep things simple I'm going to create a test for the App component that should render the header and menu and not much more. We will want to revisit this.
- We could go further with the registration test coverage but I can live with where it is for now.
- With App.jsx we are not testing the loading of lazily loaded components. I am going to live with that until an issue arises.
Overall our coverage numbers are:
- Statements - 68.67%
- Branches - 49.07%
- Functions - 61.32%
- Lines - 67.32%
Let's make some updates and see if we can improve the numbers. I am not going to bore you with the details of the updates here, you can review them in the code. This is what you can look for:
- db/users.test.js now has a number of tests that verify negative cases
- As always with testing, I found something that was broken that I was not aware of. The correct way to validate whether of not data was return by Firestore is not to look for a null document but to check if document.exists (see update to db/users.js below).
- actions/auth.test.js now has authCheck tests and a negative resetPassword test.
- Account.test.jsx now renders ResetPasswordForm.jsx and executes a password reset.
- Created very simple tests for Properties.jsx and Admin.jsx.
- Create a very simple test for App.jsx.
...
export const fetchUser = async (id) => {
try {
const getDoc = await db
.collection('users')
.doc(id)
.get();
if (getDoc.exists) {
return getDoc.data();
} else {
return null;
}
} catch (err) {
throw err;
}
};
...
With those updates our coverage has improved to:
- Statements - 77.58%
- Branches - 55.28%
- Functions - 70.75%
- Lines - 75.99%
Better but we can and will do more as we move forward.
Next
Now that we have caught up on test coverage we can start working more seriously on our application. We will begin with the Admin side of our app.
Code
https://github.com/peterdyer7/media-library/tree/23.MoreTesting