Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/bright-walls-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@lg-tools/validate': patch
---

- Adds `'@leafygreen-ui/testing-lib'` to list of external dependencies.
- Updates handling of external dependencies with glob patterns
5 changes: 5 additions & 0 deletions .changeset/fast-bananas-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@leafygreen-ui/toast': patch
---

Updates `updateToast` function to consistently return the new toast object
8 changes: 8 additions & 0 deletions .changeset/healthy-needles-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@leafygreen-ui/leafygreen-provider': patch
'@leafygreen-ui/hooks': patch
'@leafygreen-ui/toast': patch
'@leafygreen-ui/a11y': patch
---

Updates test to import `renderHook` from `@leafygreen-ui/testing-lib`
5 changes: 5 additions & 0 deletions .changeset/khaki-lies-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@leafygreen-ui/testing-lib': minor
---

Exports `waitForState`, a wrapper around `act` that returns the result of the state update callback
5 changes: 5 additions & 0 deletions .changeset/real-tomatoes-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@leafygreen-ui/table': minor
---

Table now exposes an optional second generic type for useLeafyGreenTable that controls the type of the value
5 changes: 5 additions & 0 deletions .changeset/strange-scissors-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@leafygreen-ui/testing-lib': minor
---

Exports overrides for `renderHook` and `act` that will work in both a React 17 and React 18 test environment
3 changes: 2 additions & 1 deletion packages/a11y/src/A11y.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import { axe } from 'jest-axe';

import { renderHook } from '@leafygreen-ui/testing-lib';

import { AriaLabelProps, AriaLabelPropsWithLabel } from './AriaLabelProps';
import {
prefersReducedMotion,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { PropsWithChildren } from 'react';
import React from 'react';
import { act, waitFor } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';

import { Month, newUTC } from '@leafygreen-ui/date-utils';
import { consoleOnce } from '@leafygreen-ui/lib';
import { renderHook } from '@leafygreen-ui/testing-lib';

import { MAX_DATE, MIN_DATE } from '../constants';

Expand All @@ -17,16 +17,16 @@ import {
const renderSharedDatePickerProvider = (
props?: Partial<SharedDatePickerProviderProps>,
) => {
const { result, rerender } = renderHook<
PropsWithChildren<{}>,
SharedDatePickerContextProps
>(useSharedDatePickerContext, {
wrapper: ({ children }) => (
<SharedDatePickerProvider label="" {...props}>
{children}
</SharedDatePickerProvider>
),
});
const { result, rerender } = renderHook<SharedDatePickerContextProps, {}>(
useSharedDatePickerContext,
{
wrapper: ({ children }) => (
<SharedDatePickerProvider label="" {...props}>
{children}
</SharedDatePickerProvider>
),
},
);

return { result, rerender };
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import React from 'react';
import { ChangeEventHandler } from 'react';
import { render } from '@testing-library/react';
import { renderHook, RenderHookResult } from '@testing-library/react-hooks';
import { RenderHookResult } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { act, renderHook } from '@leafygreen-ui/testing-lib';

import { useControlledValue } from './useControlledValue';

const errorSpy = jest.spyOn(console, 'error');

const renderUseControlledValueHook = <T extends any>(
...[valueProp, callback, initial]: Parameters<typeof useControlledValue<T>>
): RenderHookResult<T, ReturnType<typeof useControlledValue<T>>> => {
): RenderHookResult<
ReturnType<typeof useControlledValue<T>>,
typeof valueProp
> => {
const result = renderHook(v => useControlledValue(v, callback, initial), {
initialProps: valueProp,
});

return { ...result };
};

describe('packages/hooks/useControlledValue', () => {
describe('packages/date-picker/hooks/useControlledValue', () => {
beforeEach(() => {
errorSpy.mockImplementation(() => {});
});
Expand Down Expand Up @@ -109,7 +114,7 @@ describe('packages/hooks/useControlledValue', () => {
test('setting value to undefined should keep the component controlled', () => {
const { rerender, result } = renderUseControlledValueHook('apple');
expect(result.current.isControlled).toBe(true);
rerender(undefined);
act(() => rerender(undefined));
expect(result.current.isControlled).toBe(true);
});

Expand Down Expand Up @@ -144,8 +149,10 @@ describe('packages/hooks/useControlledValue', () => {
});

test('setValue updates the value', () => {
const { result } = renderUseControlledValueHook<string>(undefined);
const { result, rerender } =
renderUseControlledValueHook<string>(undefined);
result.current.setValue('banana');
rerender();
expect(result.current.value).toBe('banana');
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ export const useControlledValue = <T extends any>(
// If the value prop changes from undefined to something defined,
// then isControlled is set to true,
// and will remain true for the life of the component
const isControlled: boolean = useMemo(() => {
return isControlled || !isUndefined(valueProp);
}, [valueProp]);
const [isControlled, setControlled] = useState(!isUndefined(valueProp));
useEffect(() => {
setControlled(isControlled || !isUndefined(valueProp));
}, [isControlled, valueProp]);

const wasControlled = usePrevious(isControlled);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { renderHook } from '@testing-library/react';

import { DateType, Month, newUTC } from '@leafygreen-ui/date-utils';
import { renderHook } from '@leafygreen-ui/testing-lib';

import { useDateSegments } from './useDateSegments';
import { OnUpdateCallback } from './useDateSegments.types';
Expand Down
36 changes: 21 additions & 15 deletions packages/hooks/src/hooks.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { act, renderHook } from '@testing-library/react-hooks';
import { waitFor } from '@testing-library/react';

import { act, renderHook } from '@leafygreen-ui/testing-lib';

import {
useEventListener,
Expand Down Expand Up @@ -94,7 +96,7 @@ describe('packages/hooks', () => {
describe.skip('useMutationObserver', () => {}); //eslint-disable-line jest/no-disabled-tests

test('useViewportSize responds to updates in window size', async () => {
const { result, waitForNextUpdate } = renderHook(() => useViewportSize());
const { result, rerender } = renderHook(() => useViewportSize());

const mutableWindow: { -readonly [K in keyof Window]: Window[K] } = window;
const initialHeight = 360;
Expand All @@ -104,10 +106,11 @@ describe('packages/hooks', () => {
mutableWindow.innerWidth = initialWidth;

window.dispatchEvent(new Event('resize'));
await act(waitForNextUpdate);

expect(result?.current?.height).toBe(initialHeight);
expect(result?.current?.width).toBe(initialWidth);
rerender();
await waitFor(() => {
expect(result?.current?.height).toBe(initialHeight);
expect(result?.current?.width).toBe(initialWidth);
});

const updateHeight = 768;
const updateWidth = 1024;
Expand All @@ -116,10 +119,10 @@ describe('packages/hooks', () => {
mutableWindow.innerWidth = updateWidth;

window.dispatchEvent(new Event('resize'));
await act(waitForNextUpdate);

expect(result?.current?.height).toBe(updateHeight);
expect(result?.current?.width).toBe(updateWidth);
await waitFor(() => {
expect(result?.current?.height).toBe(updateHeight);
expect(result?.current?.width).toBe(updateWidth);
});
});

describe('usePoller', () => {
Expand Down Expand Up @@ -249,26 +252,29 @@ describe('packages/hooks', () => {
expect(pollHandler).toHaveBeenCalledTimes(0);
});

test('when document is not visible', () => {
test('when document is not visible', async () => {
const pollHandler = jest.fn();

renderHook(() => usePoller(pollHandler));
const { rerender } = renderHook(() => usePoller(pollHandler));

expect(pollHandler).toHaveBeenCalledTimes(1);

mutableDocument.visibilityState = 'hidden';
act(() => {
document.dispatchEvent(new Event('visibilitychange'));
});

jest.advanceTimersByTime(30e3);

expect(pollHandler).toHaveBeenCalledTimes(1);

mutableDocument.visibilityState = 'visible';

act(() => {
document.dispatchEvent(new Event('visibilitychange'));
});
jest.advanceTimersByTime(30e3);

rerender(pollHandler);

// immediate triggers the pollHandler
expect(pollHandler).toHaveBeenCalledTimes(2);
Expand Down Expand Up @@ -308,11 +314,11 @@ describe('packages/hooks', () => {
rerender(2020);
expect(result.current).toEqual(42);

rerender();
rerender(123);
expect(result.current).toEqual(2020);

rerender();
expect(result.current).toEqual(2020);
expect(result.current).toEqual(123);
});
});

Expand Down
29 changes: 18 additions & 11 deletions packages/hooks/src/useDynamicRefs/useDynamicRefs.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { renderHook } from '@testing-library/react-hooks';

// import { renderHook } from '@testing-library/react-hooks';
import { consoleOnce } from '@leafygreen-ui/lib';
import { renderHook } from '@leafygreen-ui/testing-lib';

import { DynamicRefGetter, useDynamicRefs } from '.';

Expand All @@ -11,11 +11,13 @@ describe('packages/hooks/useDynamicRefs', () => {
});

test('returns identical getter when rerendered ', () => {
const props = { prefix: 'A' };
const { result, rerender } = renderHook(v => useDynamicRefs(v), {
initialProps: { prefix: 'A' },
initialProps: props,
});
rerender();
expect(result.all[0]).toBe(result.all[1]);
const initialValue = result.current;
rerender(props);
expect(result.current).toStrictEqual(initialValue);
});

test('returns unique getters when called with the same prefix', () => {
Expand All @@ -33,11 +35,14 @@ describe('packages/hooks/useDynamicRefs', () => {

test('returns unique getters when re-rendered with a different prefix', () => {
// This is an edge-case, but this is the behavior we want if it happens
const props = { prefix: 'A' };
const { result, rerender } = renderHook(v => useDynamicRefs(v), {
initialProps: { prefix: 'A' },
initialProps: props,
});
rerender({ prefix: 'B' });
expect(result.all[0]).not.toBe(result.all[1]);
const initialValue = result.current;
const newProps = { prefix: 'B' };
rerender(newProps);
expect(result.current).not.toBe(initialValue);
});

describe('ref getter function', () => {
Expand Down Expand Up @@ -66,18 +71,20 @@ describe('packages/hooks/useDynamicRefs', () => {
});

test('returns identical refs when called with the same key', () => {
const { result } = renderHook(() => useDynamicRefs({ prefix: 'A' }));
const props = { prefix: 'A' };
const { result } = renderHook(() => useDynamicRefs(props));
const ref1 = result.current('key');
const ref2 = result.current('key');
expect(ref1).toBe(ref2);
});

test('returns identical refs when rerendered', () => {
const props = { prefix: 'A' };
const { result, rerender } = renderHook(v => useDynamicRefs(v), {
initialProps: { prefix: 'A' },
initialProps: props,
});
const ref1 = result.current('key');
rerender();
rerender(props);
const ref2 = result.current('key');
expect(ref1).toBe(ref2);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { PropsWithChildren } from 'react';
import { act, fireEvent, render, waitFor } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';

import { renderHook } from '@leafygreen-ui/testing-lib';

import { PopoverProvider, type PopoverState, usePopoverContext } from '.';

Expand Down
4 changes: 2 additions & 2 deletions packages/table/src/useLeafyGreenTable/TableHeaderCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import { useRowContext } from '../Row/RowContext';
import { disabledTableRowCheckStyles } from './useLeafyGreenTable.styles';
import { LGRowData, LGTableDataType } from '.';

export const TableHeaderCheckbox = ({
export const TableHeaderCheckbox = <T extends LGRowData>({
table,
}: {
table: Table<LGTableDataType<LGRowData>>;
table: Table<LGTableDataType<T>>;
}) => {
const { theme } = useDarkMode();
const { disabled: rowIsDisabled } = useRowContext();
Expand Down
6 changes: 3 additions & 3 deletions packages/table/src/useLeafyGreenTable/TableRowCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import { useRowContext } from '../Row/RowContext';
import { disabledTableRowCheckStyles } from './useLeafyGreenTable.styles';
import { LGRowData, LGTableDataType } from '.';

export const TableRowCheckbox = ({
export const TableRowCheckbox = <T extends LGRowData>({
row,
table,
}: {
table: Table<LGTableDataType<LGRowData>>;
row: Row<LGTableDataType<LGRowData>>;
table: Table<LGTableDataType<T>>;
row: Row<LGTableDataType<T>>;
}) => {
const { theme } = useDarkMode();
const { disabled: rowIsDisabled } = useRowContext();
Expand Down
Loading