|
| 1 | +# DOM snapshots |
| 2 | + |
| 3 | +I've got two failing tests on my hands, and a good place to start is to isolate the one I'm going to address first: |
| 4 | + |
| 5 | +```tsx filename=debug.browser.test.tsx |
| 6 | +test.only('places cross marks in a horizontal line', async () => { |
| 7 | +``` |
| 8 | +
|
| 9 | +Now that the test results represent only this failing test, I can move on with taking a look at what's going on here. |
| 10 | +
|
| 11 | +The goal of this test is to validate one of the scenarios of interacting with the `<TicTacToe />` component. If I place three marks in a horizontal line, they should form a winning line. This is precisely what the test actions do: |
| 12 | +
|
| 13 | +```tsx filename=debug.browser.test.tsx |
| 14 | +await page.getByRole('button', { name: 'left middle' }).click() |
| 15 | +await page.getByRole('button', { name: 'middle', exact: true }).click() |
| 16 | +await page.getByRole('button', { name: 'right middle' }).click() |
| 17 | +``` |
| 18 | +
|
| 19 | +> 🦉 Notice the usage of `exact: true` in the second action. It is there so that `name: 'middle'` matches the element with the accessible name `'middle'` exactly, ignoring the `'left middle'` and `'right middle'` elements that would otherwise match, too. |
| 20 | +
|
| 21 | +The usage seems to be in order, but the test still fails: |
| 22 | +
|
| 23 | +``` |
| 24 | +AssertionError: expected [ '✗', '✗', '' ] to deeply equal [ '✗', '✗', '✗' ] |
| 25 | +``` |
| 26 | +
|
| 27 | +The rightmost mark is missing! But how? The test is clearly marking the left middle, middle, and the right middle squares of the game. Something is certainly off here... |
| 28 | +
|
| 29 | +## Printing the entire DOM |
| 30 | +
|
| 31 | +Luckily, I can observe the full state of the rendered DOM at any point in time using the `debug()` utility returned from `render()`: |
| 32 | +
|
| 33 | +```tsx filename=debug.browser.test.tsx add=1,7 |
| 34 | +const { debug } = render(<TicTacToe />) |
| 35 | + |
| 36 | +await page.getByRole('button', { name: 'left middle' }).click() |
| 37 | +await page.getByRole('button', { name: 'middle', exact: true }).click() |
| 38 | +await page.getByRole('button', { name: 'right middle' }).click() |
| 39 | + |
| 40 | +debug() |
| 41 | +``` |
| 42 | +
|
| 43 | +Calling the `debug()` function here will print out the entire DOM tree into the console after the test is done interacting with the `<TicTacToe />` component. This should, hopefully, give me some clue as to why that last check mark is missing. |
| 44 | +
|
| 45 | +```html highlight=18-29,34-39 |
| 46 | +<body> |
| 47 | + <div> |
| 48 | + <div |
| 49 | + class="grid grid-cols-3 grid-rows-3" |
| 50 | + > |
| 51 | + <button |
| 52 | + aria-label="top left" |
| 53 | + class="size-16 border border-slate-400 text-4xl text-blue-500 hover:bg-slate-200 border-l-0 border-t-0" |
| 54 | + /> |
| 55 | + <button |
| 56 | + aria-label="top middle" |
| 57 | + class="size-16 border border-slate-400 text-4xl text-blue-500 hover:bg-slate-200 border-t-0" |
| 58 | + /> |
| 59 | + <button |
| 60 | + aria-label="top right" |
| 61 | + class="size-16 border border-slate-400 text-4xl text-blue-500 hover:bg-slate-200 border-r-0 border-t-0" |
| 62 | + /> |
| 63 | + <button |
| 64 | + aria-label="left middle" |
| 65 | + class="size-16 border border-slate-400 text-4xl text-blue-500 hover:bg-slate-200 border-l-0" |
| 66 | + > |
| 67 | + ✗ |
| 68 | + </button> |
| 69 | + <button |
| 70 | + aria-label="middle" |
| 71 | + class="size-16 border border-slate-400 text-4xl text-blue-500 hover:bg-slate-200 " |
| 72 | + > |
| 73 | + ✗ |
| 74 | + </button> |
| 75 | + <button |
| 76 | + aria-label="bottom left" |
| 77 | + class="size-16 border border-slate-400 text-4xl text-blue-500 hover:bg-slate-200 border-r-0" |
| 78 | + /> |
| 79 | + <button |
| 80 | + aria-label="right middle" |
| 81 | + class="size-16 border border-slate-400 text-4xl text-blue-500 hover:bg-slate-200 border-b-0 border-l-0" |
| 82 | + > |
| 83 | + ✗ |
| 84 | + </button> |
| 85 | + <button |
| 86 | + aria-label="bottom middle" |
| 87 | + class="size-16 border border-slate-400 text-4xl text-blue-500 hover:bg-slate-200 border-b-0" |
| 88 | + /> |
| 89 | + <button |
| 90 | + aria-label="bottom right" |
| 91 | + class="size-16 border border-slate-400 text-4xl text-blue-500 hover:bg-slate-200 border-b-0 border-r-0" |
| 92 | + /> |
| 93 | + </div> |
| 94 | + </div> |
| 95 | +</body |
| 96 | +``` |
| 97 | + |
| 98 | +Having a bird's eye view on the DOM lets me see whether everything is rendered correctly and . . . What do you know! The last check mark indeed gets placed, and even in the correct square, but the square itself is at the wrong place! Looks like the `'bottom left'` and `'right middle'` sections of the game got swapped by accident the other day 😅. |
| 99 | + |
| 100 | +Hopefully, it's much easier to fix the bug than it was to find it: |
| 101 | + |
| 102 | +```tsx filename=tic-tac-toe.tsx remove=3 add=5 |
| 103 | + <Button aria-label="left middle" className="border-l-0" /> |
| 104 | + <Button aria-label="middle" /> |
| 105 | + <Button aria-label="bottom left" className="border-r-0" /> |
| 106 | + <Button aria-label="right middle" className="border-b-0 border-l-0" /> |
| 107 | + <Button aria-label="bottom left" className="border-r-0" /> |
| 108 | +``` |
| 109 | + |
| 110 | +Alright! The first test is back to green. But what about the second one? |
| 111 | + |
| 112 | +## Printing selected elements |
| 113 | + |
| 114 | +Sometimes the rendered element tree is too large to digest all at once. This is where isolating it to a particular element or a set of elements is a huge time-saver to get to the bottom of the issue. |
| 115 | + |
| 116 | +As it turns out, this is exactly the case for the second failing test. |
| 117 | + |
| 118 | +> TODO: Complete the solution once the second failing test is there. |
| 119 | + |
| 120 | +--- |
| 121 | + |
| 122 | +This is where taking _spapshots_ comes in handy. At any point of your test, you can take a look at the current state of the DOM to see if it's what you expect it to be. You can do that by calling the `debug()` utility function returned from `render()`: |
| 123 | + |
| 124 | +```tsx |
| 125 | +const { debug } = render(<p>Hello world</p>) |
| 126 | +debug() |
| 127 | +``` |
| 128 | + |
| 129 | +```html |
| 130 | +<body> |
| 131 | + <p>Hello world</p> |
| 132 | +</body> |
| 133 | +``` |
| 134 | + |
| 135 | +--- |
| 136 | + |
| 137 | +- How to use `debug()` from `render()`. |
| 138 | +- You can debug the entire rendered tree by calling `debug()`. |
| 139 | +- You can debug a subportion of the tree but calling `debug(locator)` or even an array of locators. |
0 commit comments