In the Angular version of the app, the component consists of a nav, a p with a hard-coded string "Menu", a ul, and three links to our routes.
Create a branch feat/NavBar. Create 2 files under src/components/ folder; NavBar.cy.tsx, NavBar.tsx. As usual, start minimal with a component rendering; copy the below to the files and execute the test after opening the runner with yarn cy:open-ct.
We start with a failing test that verifies the skeleton of the component. We want the top tag to have a data-cy attribute with the component name, making the component easier to reference when it is used. We can also add data-cy attributes for the tags that may be of importance later (Red 1).
In the previous components that had to do with application routes (HeaderBarBrand, ListHeader), we used NavLink from react-router-dom. We can refactor the component the same way. The refactor results in a familiar Router error we saw in the previous routing related components. In the component test, we wrap the mount with BrowserRouter to address the issue (Refactor 1).
We have a new failure in the test *(uncaught exception)**TypeError: Cannot read properties of undefined (reading 'pathname')*. There is also a TS error that gives us a hint Property 'to' is missing in type '{}' but required in type 'NavLinkProps (Red 2). We need to enhance the links with to attributes (Green 2). It is of significance here that TS also aids us, alongside a failing test, figuring out the source of the failure.
Any time we have a green test, we can either refactor or add additional tests until we get another red. Let's add some tests which verify that clicking on these routes takes us to the respective urls. The test is similar to what was done in HeaderBarBrand and ListHeader components. We can use Cypress' selector playground for this enhancement. cy.get targeting an href is a good selector in this case, which will not change unless the route changes (Green 3).
The test is still green as a part of the refactor. The only additional test we can think of at this time is checking the string in the link. We can indicate that the route is of type string, and we can match either casing with {matchCase: false} (Refactor 3).
We went through RedGreenRefactor cycles, we enhanced the test as much as possible, and we did not get any failures. At this time we can use the test tool as the design tool and enhance the visuals. Let's add the css from the Angular version of the component. Remember to add import '../styles.scss' to the component test.
Adding the styles, we realize an issue in the visuals; every link is active all the time (Red 4).
Of significance here is component test aiding us as the design tool to create a new failing test. What we need is the active node to have the class active-link and the other nodes not to have it. Let's write a failing test (Red 4).
In the component test, we also realize that the subject cy.get([href="/${route}"]) is common to each assertion. We can take advantage of Cypress' chain syntax to lean out the assertions. We can also have a little less hard-coding with the menu length assertion (Refactor 4).
We identified the skeleton of the component and wrote a failing test for it (Red 1).
We created a minimal component to pass the test (Green 1).
We refactored the component to use NavLinks instead of anchor tags (Refactor 1)
We had a test failure, aided by TS errors, about a missing an attribute from the NavLinks (Red 2).
The to attributes and their routes got added to the NavLinks (Green 2).
Similar to the previous chapters, of significance here was TS also aiding us, alongside a failing test.
Any time we have a green test, *we can either refactor or add additional tests until we get another red*.
Our preference is adding tests before styles.
We added tests for route checks (Green 3), and refactored the test further (Refactor 3).
Once we exhausted the tests we can think of, we added styles to the component and realized something off with visuals. Every link was active (Red 4).
We wrote a failing test to double check the styles, using have.class vs not.have.class assertions (Red 4).
We added logic to the component css to determine the style of active vs inactive links (Green 4).
We refactored the logic to be more DRY (Refactor 4).
Finally, we refactored the component test to take advantage of Cypress' chaining syntax and use less magic numbers (Refactor 4).
Takeaway
Of significance here was component testing aiding us as the design tool to create a new failing test. We wrote as many tests as we could think of, but only when we saw that all links are always active, we thought about an additional feature.