starling-devex 0.1.2

Starling: a local dev orchestrator with a central daemon, shared named-URL proxy, and a k9s-style TUI (a Rust port of Tilt + portless)
import { act, render } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import React from "react"
import {
  DEFAULT_GROUP_STATE,
  ResourceGroupsContextProvider,
  useResourceGroups,
} from "./ResourceGroupsContext"

const GROUP_STATE_ID = "test-group-state"
const LABEL_STATE_ID = "test-label-state"

// This is a very basic test component that prints out the state
// from the ResourceGroups context and provides buttons to trigger
// methods returned by the context, so they can be tested
const TestConsumer = (props: { labelName?: string }) => {
  const { groups, getGroup, toggleGroupExpanded } = useResourceGroups()

  return (
    <>
      <p id={GROUP_STATE_ID}>{JSON.stringify(groups)}</p>
      {/* Display the label state if a specific label is present */}
      {props.labelName && (
        <p id={LABEL_STATE_ID}>{JSON.stringify(getGroup(props.labelName))}</p>
      )}
      {/* Display a button to toggle the label state if a specific label is present */}
      {props.labelName && (
        <button onClick={() => toggleGroupExpanded(props.labelName || "")} />
      )}
    </>
  )
}

describe("ResourceGroupsContext", () => {
  let wrapper: HTMLElement

  // Helpers
  const groupState = () =>
    wrapper.querySelector(`#${GROUP_STATE_ID}`)!.innerHTML
  const labelState = () =>
    wrapper.querySelector(`#${LABEL_STATE_ID}`)!.innerHTML
  const clickButton = () => {
    userEvent.click(wrapper.querySelector("button")!)
  }

  beforeEach(() => {
    localStorage.clear()
  })

  afterEach(() => {
    localStorage.clear()
  })

  it("defaults to an empty state with no groups", () => {
    wrapper = renderContainer(
      <ResourceGroupsContextProvider>
        <TestConsumer />
      </ResourceGroupsContextProvider>
    )

    expect(groupState()).toBe(JSON.stringify({}))
  })

  describe("toggleGroupExpanded", () => {
    it("sets expanded to `true` when group is collapsed", () => {
      const testValues = { test: { expanded: false } }
      wrapper = renderContainer(
        <ResourceGroupsContextProvider initialValuesForTesting={testValues}>
          <TestConsumer labelName="test" />
        </ResourceGroupsContextProvider>
      )
      clickButton()

      expect(labelState()).toBe(JSON.stringify({ expanded: true }))
    })

    it("sets expanded to `false` when group is expanded", () => {
      const testValues = { test: { expanded: true } }
      wrapper = renderContainer(
        <ResourceGroupsContextProvider initialValuesForTesting={testValues}>
          <TestConsumer labelName="test" />
        </ResourceGroupsContextProvider>
      )
      clickButton()

      expect(labelState()).toBe(JSON.stringify({ expanded: false }))
    })

    it("sets expanded to `false` if a group isn't saved yet and is toggled", () => {
      wrapper = renderContainer(
        <ResourceGroupsContextProvider>
          <TestConsumer labelName="a-non-existent-group" />
        </ResourceGroupsContextProvider>
      )
      clickButton()

      expect(labelState()).toBe(JSON.stringify({ expanded: false }))
    })
  })

  describe("getGroup", () => {
    it("returns the correct state of a resource group", () => {
      const testValues = { frontend: { expanded: false } }
      wrapper = renderContainer(
        <ResourceGroupsContextProvider initialValuesForTesting={testValues}>
          <TestConsumer labelName="frontend" />
        </ResourceGroupsContextProvider>
      )

      expect(labelState()).toBe(JSON.stringify({ expanded: false }))
    })

    it("returns a default state of a resource group if a group isn't saved yet", () => {
      const testValues = { frontend: { expanded: false } }
      wrapper = renderContainer(
        <ResourceGroupsContextProvider initialValuesForTesting={testValues}>
          <TestConsumer labelName="backend" />
        </ResourceGroupsContextProvider>
      )

      expect(labelState()).toBe(JSON.stringify(DEFAULT_GROUP_STATE))
    })
  })

  it("memoizes renders", () => {
    let renderCount = 0
    let toggleGroupExpanded: any
    let FakeEl = React.memo(() => {
      let context = useResourceGroups()
      toggleGroupExpanded = context.toggleGroupExpanded
      renderCount++
      return <div></div>
    })

    let tree = () => {
      const init = { frontend: { expanded: false } }
      return (
        <ResourceGroupsContextProvider initialValuesForTesting={init}>
          <FakeEl />
        </ResourceGroupsContextProvider>
      )
    }

    let { rerender } = render(tree())
    expect(renderCount).toEqual(1)

    // Make sure we don't re-render
    rerender(tree())
    expect(renderCount).toEqual(1)

    act(() => toggleGroupExpanded("frontend"))
    expect(renderCount).toEqual(2)
  })
})

function renderContainer(x: any) {
  let { container } = render(x)
  return container
}