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

     1  import { act, render } from "@testing-library/react"
     2  import userEvent from "@testing-library/user-event"
     3  import React from "react"
     4  import { AnalyticsAction, AnalyticsType } from "./analytics"
     5  import {
     6    cleanupMockAnalyticsCalls,
     7    expectIncrs,
     8    mockAnalyticsCalls,
     9  } from "./analytics_test_helpers"
    10  import {
    11    DEFAULT_GROUP_STATE,
    12    ResourceGroupsContextProvider,
    13    useResourceGroups,
    14  } from "./ResourceGroupsContext"
    15  
    16  const GROUP_STATE_ID = "test-group-state"
    17  const LABEL_STATE_ID = "test-label-state"
    18  
    19  // This is a very basic test component that prints out the state
    20  // from the ResourceGroups context and provides buttons to trigger
    21  // methods returned by the context, so they can be tested
    22  const TestConsumer = (props: { labelName?: string }) => {
    23    const { groups, getGroup, toggleGroupExpanded } = useResourceGroups()
    24  
    25    return (
    26      <>
    27        <p id={GROUP_STATE_ID}>{JSON.stringify(groups)}</p>
    28        {/* Display the label state if a specific label is present */}
    29        {props.labelName && (
    30          <p id={LABEL_STATE_ID}>{JSON.stringify(getGroup(props.labelName))}</p>
    31        )}
    32        {/* Display a button to toggle the label state if a specific label is present */}
    33        {props.labelName && (
    34          <button
    35            onClick={() =>
    36              toggleGroupExpanded(props.labelName || "", AnalyticsType.Grid)
    37            }
    38          />
    39        )}
    40      </>
    41    )
    42  }
    43  
    44  describe("ResourceGroupsContext", () => {
    45    let wrapper: HTMLElement
    46  
    47    // Helpers
    48    const groupState = () =>
    49      wrapper.querySelector(`#${GROUP_STATE_ID}`)!.innerHTML
    50    const labelState = () =>
    51      wrapper.querySelector(`#${LABEL_STATE_ID}`)!.innerHTML
    52    const clickButton = () => {
    53      userEvent.click(wrapper.querySelector("button")!)
    54    }
    55  
    56    beforeEach(() => {
    57      localStorage.clear()
    58      mockAnalyticsCalls()
    59    })
    60  
    61    afterEach(() => {
    62      localStorage.clear()
    63      cleanupMockAnalyticsCalls()
    64    })
    65  
    66    it("defaults to an empty state with no groups", () => {
    67      wrapper = renderContainer(
    68        <ResourceGroupsContextProvider>
    69          <TestConsumer />
    70        </ResourceGroupsContextProvider>
    71      )
    72  
    73      expect(groupState()).toBe(JSON.stringify({}))
    74    })
    75  
    76    describe("toggleGroupExpanded", () => {
    77      it("sets expanded to `true` when group is collapsed", () => {
    78        const testValues = { test: { expanded: false } }
    79        wrapper = renderContainer(
    80          <ResourceGroupsContextProvider initialValuesForTesting={testValues}>
    81            <TestConsumer labelName="test" />
    82          </ResourceGroupsContextProvider>
    83        )
    84        clickButton()
    85  
    86        expect(labelState()).toBe(JSON.stringify({ expanded: true }))
    87      })
    88  
    89      it("sets expanded to `false` when group is expanded", () => {
    90        const testValues = { test: { expanded: true } }
    91        wrapper = renderContainer(
    92          <ResourceGroupsContextProvider initialValuesForTesting={testValues}>
    93            <TestConsumer labelName="test" />
    94          </ResourceGroupsContextProvider>
    95        )
    96        clickButton()
    97  
    98        expect(labelState()).toBe(JSON.stringify({ expanded: false }))
    99      })
   100  
   101      it("sets expanded to `false` if a group isn't saved yet and is toggled", () => {
   102        wrapper = renderContainer(
   103          <ResourceGroupsContextProvider>
   104            <TestConsumer labelName="a-non-existent-group" />
   105          </ResourceGroupsContextProvider>
   106        )
   107        clickButton()
   108  
   109        expect(labelState()).toBe(JSON.stringify({ expanded: false }))
   110      })
   111  
   112      it("makes an analytics call with the right payload", () => {
   113        const testValues = { test: { expanded: true } }
   114        wrapper = renderContainer(
   115          <ResourceGroupsContextProvider initialValuesForTesting={testValues}>
   116            <TestConsumer labelName="test" />
   117          </ResourceGroupsContextProvider>
   118        )
   119        clickButton()
   120        // Expect the "collapse" action value because the test label group is expanded
   121        // when it's clicked on and the "grid" type value because it's hardcoded in the
   122        // test component
   123        expectIncrs({
   124          name: "ui.web.resourceGroup",
   125          tags: { action: AnalyticsAction.Collapse, type: AnalyticsType.Grid },
   126        })
   127      })
   128    })
   129  
   130    describe("getGroup", () => {
   131      it("returns the correct state of a resource group", () => {
   132        const testValues = { frontend: { expanded: false } }
   133        wrapper = renderContainer(
   134          <ResourceGroupsContextProvider initialValuesForTesting={testValues}>
   135            <TestConsumer labelName="frontend" />
   136          </ResourceGroupsContextProvider>
   137        )
   138  
   139        expect(labelState()).toBe(JSON.stringify({ expanded: false }))
   140      })
   141  
   142      it("returns a default state of a resource group if a group isn't saved yet", () => {
   143        const testValues = { frontend: { expanded: false } }
   144        wrapper = renderContainer(
   145          <ResourceGroupsContextProvider initialValuesForTesting={testValues}>
   146            <TestConsumer labelName="backend" />
   147          </ResourceGroupsContextProvider>
   148        )
   149  
   150        expect(labelState()).toBe(JSON.stringify(DEFAULT_GROUP_STATE))
   151      })
   152    })
   153  
   154    it("memoizes renders", () => {
   155      let renderCount = 0
   156      let toggleGroupExpanded: any
   157      let FakeEl = React.memo(() => {
   158        let context = useResourceGroups()
   159        toggleGroupExpanded = context.toggleGroupExpanded
   160        renderCount++
   161        return <div></div>
   162      })
   163  
   164      let tree = () => {
   165        const init = { frontend: { expanded: false } }
   166        return (
   167          <ResourceGroupsContextProvider initialValuesForTesting={init}>
   168            <FakeEl />
   169          </ResourceGroupsContextProvider>
   170        )
   171      }
   172  
   173      let { rerender } = render(tree())
   174      expect(renderCount).toEqual(1)
   175  
   176      // Make sure we don't re-render
   177      rerender(tree())
   178      expect(renderCount).toEqual(1)
   179  
   180      act(() => toggleGroupExpanded("frontend", ""))
   181      expect(renderCount).toEqual(2)
   182    })
   183  })
   184  
   185  function renderContainer(x: any) {
   186    let { container } = render(x)
   187    return container
   188  }