github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/web/src/ResourceNav.test.tsx (about)

     1  import { render, RenderOptions, screen } from "@testing-library/react"
     2  import userEvent from "@testing-library/user-event"
     3  import { createMemoryHistory, MemoryHistory } from "history"
     4  import React, { ChangeEvent, useState } from "react"
     5  import { act } from "react-dom/test-utils"
     6  import { Router } from "react-router"
     7  import { ResourceNavProvider, useResourceNav } from "./ResourceNav"
     8  import { ResourceName } from "./types"
     9  
    10  const INVALID_RESOURCE = "res3"
    11  
    12  function TestResourceNavConsumer() {
    13    const { selectedResource, invalidResource, openResource } = useResourceNav()
    14    const [resourceToSelect, setResourceToSelect] = useState("")
    15  
    16    return (
    17      <>
    18        <p aria-label="selectedResource">{selectedResource}</p>
    19        <p aria-label="invalidResource">{invalidResource}</p>
    20        <input
    21          aria-label="Resource to select"
    22          type="text"
    23          value={resourceToSelect}
    24          onChange={(e: ChangeEvent<HTMLInputElement>) =>
    25            setResourceToSelect(e.target.value)
    26          }
    27        />
    28        <button onClick={() => openResource(resourceToSelect)}>
    29          openResource
    30        </button>
    31      </>
    32    )
    33  }
    34  
    35  // history
    36  function customRender(
    37    wrapperOptions: {
    38      history: MemoryHistory
    39      validateOverride?: (name: string) => boolean
    40    },
    41    options?: RenderOptions
    42  ) {
    43    const validateResource =
    44      wrapperOptions.validateOverride ??
    45      function (name: string) {
    46        return name !== INVALID_RESOURCE
    47      }
    48    return render(<TestResourceNavConsumer />, {
    49      wrapper: ({ children }) => (
    50        <Router history={wrapperOptions.history}>
    51          <ResourceNavProvider validateResource={validateResource}>
    52            {children}
    53          </ResourceNavProvider>
    54        </Router>
    55      ),
    56      ...options,
    57    })
    58  }
    59  
    60  describe("ResourceNavContext", () => {
    61    it("navigates to resource on click", () => {
    62      const history = createMemoryHistory()
    63      customRender({ history })
    64  
    65      expect(screen.getByLabelText("selectedResource")).toHaveTextContent("")
    66  
    67      userEvent.type(screen.getByRole("textbox"), "res1")
    68      userEvent.click(screen.getByRole("button", { name: "openResource" }))
    69  
    70      expect(screen.getByLabelText("selectedResource")).toHaveTextContent("res1")
    71      expect(history.location.pathname).toEqual("/r/res1/overview")
    72    })
    73  
    74    it("filters resources that don't validate", () => {
    75      const history = createMemoryHistory()
    76      // Set location to invalid resource
    77      history.location.pathname = `/r/${INVALID_RESOURCE}/overview`
    78      customRender({ history })
    79  
    80      expect(screen.getByLabelText("selectedResource")).toHaveTextContent("")
    81      expect(screen.getByLabelText("invalidResource")).toHaveTextContent(
    82        INVALID_RESOURCE
    83      )
    84    })
    85  
    86    it("always validates the 'all' resource", () => {
    87      const history = createMemoryHistory()
    88      // Set location to 'all' resource
    89      history.location.pathname = `/r/${ResourceName.all}/overview`
    90      customRender({ history, validateOverride: (_name: string) => false })
    91  
    92      expect(screen.getByLabelText("selectedResource")).toHaveTextContent(
    93        ResourceName.all
    94      )
    95      expect(screen.getByLabelText("invalidResource")).toHaveTextContent("")
    96    })
    97  
    98    it("encodes resource names", () => {
    99      const history = createMemoryHistory()
   100      customRender({ history })
   101  
   102      userEvent.type(screen.getByRole("textbox"), "foo/bar")
   103      userEvent.click(screen.getByRole("button", { name: "openResource" }))
   104  
   105      expect(screen.getByLabelText("selectedResource")).toHaveTextContent(
   106        "foo/bar"
   107      )
   108      expect(history.location.pathname).toEqual("/r/foo%2Fbar/overview")
   109    })
   110  
   111    it("preserves filters by resource", () => {
   112      const history = createMemoryHistory()
   113      customRender({ history })
   114  
   115      let nav = (res: string) => {
   116        userEvent.clear(screen.getByRole("textbox"))
   117        userEvent.type(screen.getByRole("textbox"), res)
   118        userEvent.click(screen.getByRole("button", { name: "openResource" }))
   119      }
   120  
   121      let url = () => {
   122        return history.location.pathname + history.location.search
   123      }
   124  
   125      nav("foo")
   126      expect(url()).toEqual("/r/foo/overview")
   127      history.push("/r/foo/overview?term=hi")
   128      nav("bar")
   129      expect(url()).toEqual("/r/bar/overview")
   130      nav("foo")
   131      expect(url()).toEqual("/r/foo/overview?term=hi")
   132    })
   133  
   134    // Make sure that useResourceNav() doesn't break memoization.
   135    it("memoizes renders", () => {
   136      let renderCount = 0
   137      let FakeEl = React.memo(() => {
   138        useResourceNav()
   139        renderCount++
   140        return <div></div>
   141      })
   142  
   143      let history = createMemoryHistory()
   144      let validateResource = () => true
   145      let { rerender } = render(
   146        <Router history={history}>
   147          <ResourceNavProvider validateResource={validateResource}>
   148            <FakeEl />
   149          </ResourceNavProvider>
   150        </Router>
   151      )
   152  
   153      expect(renderCount).toEqual(1)
   154  
   155      // Make sure we don't re-render on a no-op history update.
   156      rerender(
   157        <Router history={history}>
   158          <ResourceNavProvider validateResource={validateResource}>
   159            <FakeEl />
   160          </ResourceNavProvider>
   161        </Router>
   162      )
   163      expect(renderCount).toEqual(1)
   164  
   165      // Make sure we do re-render on a real location update.
   166      act(() => history.push("/r/foo"))
   167      expect(renderCount).toEqual(2)
   168    })
   169  })