Skip to content

Commit

Permalink
local copy of jotai tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dmaskasky committed Sep 24, 2024
1 parent 66164b3 commit a027650
Show file tree
Hide file tree
Showing 37 changed files with 9,896 additions and 0 deletions.
12 changes: 12 additions & 0 deletions __tests__/derive/00_derive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { atom } from '../../jotai';
import { createStore } from './derivedStore';

it('calls subscribe callback when state changes', () => {
const countAtom = atom(1);
const store = createStore();
const updateSpy = jest.fn((num) => num);
store.sub(countAtom, () => updateSpy(store.get(countAtom)));
store.set(countAtom, 2);
expect(updateSpy).toHaveBeenCalledTimes(1);
expect(updateSpy).toHaveBeenLastCalledWith(2);
});
223 changes: 223 additions & 0 deletions __tests__/derive/baseTests/react/abortable.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import { StrictMode, Suspense, useState } from 'react';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useAtomValue, useSetAtom } from '../../../../jotai/react';
import { atom } from '../../../../jotai/vanilla';

describe('abortable atom test', () => {
it('can abort with signal.aborted', async () => {
const countAtom = atom(0);
let abortedCount = 0;
const resolve: (() => void)[] = [];
const derivedAtom = atom(async (get, { signal }) => {
const count = get(countAtom);
await new Promise<void>((r) => resolve.push(r));
if (signal.aborted) {
++abortedCount;
}
return count;
});

const Component = () => {
const count = useAtomValue(derivedAtom);
return <div>count: {count}</div>;
};

const Controls = () => {
const setCount = useSetAtom(countAtom);
return (
<>
<button onClick={() => setCount((c) => c + 1)}>button</button>
</>
);
};

const { findByText, getByText } = render(
<StrictMode>
<Suspense fallback="loading">
<Component />
<Controls />
</Suspense>
</StrictMode>,
);

await findByText('loading');

resolve.splice(0).forEach((fn) => fn());
await findByText('count: 0');
expect(abortedCount).toBe(0);

await userEvent.click(getByText('button'));
await userEvent.click(getByText('button'));
resolve.splice(0).forEach((fn) => fn());
await findByText('count: 2');

expect(abortedCount).toBe(1);

await userEvent.click(getByText('button'));
resolve.splice(0).forEach((fn) => fn());
await findByText('count: 3');
expect(abortedCount).toBe(1);
});

it('can abort with event listener', async () => {
const countAtom = atom(0);
let abortedCount = 0;
const resolve: (() => void)[] = [];
const derivedAtom = atom(async (get, { signal }) => {
const count = get(countAtom);
const callback = () => {
++abortedCount;
};
signal.addEventListener('abort', callback);
await new Promise<void>((r) => resolve.push(r));
signal.removeEventListener('abort', callback);
return count;
});

const Component = () => {
const count = useAtomValue(derivedAtom);
return <div>count: {count}</div>;
};

const Controls = () => {
const setCount = useSetAtom(countAtom);
return (
<>
<button onClick={() => setCount((c) => c + 1)}>button</button>
</>
);
};

const { findByText, getByText } = render(
<StrictMode>
<Suspense fallback="loading">
<Component />
<Controls />
</Suspense>
</StrictMode>,
);

await findByText('loading');
resolve.splice(0).forEach((fn) => fn());
await findByText('count: 0');

expect(abortedCount).toBe(0);

await userEvent.click(getByText('button'));
await userEvent.click(getByText('button'));
resolve.splice(0).forEach((fn) => fn());
await findByText('count: 2');

expect(abortedCount).toBe(1);

await userEvent.click(getByText('button'));
resolve.splice(0).forEach((fn) => fn());
await findByText('count: 3');

expect(abortedCount).toBe(1);
});

it('does not abort on unmount', async () => {
const countAtom = atom(0);
let abortedCount = 0;
const resolve: (() => void)[] = [];
const derivedAtom = atom(async (get, { signal }) => {
const count = get(countAtom);
await new Promise<void>((r) => resolve.push(r));
if (signal.aborted) {
++abortedCount;
}
return count;
});

const Component = () => {
const count = useAtomValue(derivedAtom);
return <div>count: {count}</div>;
};

const Parent = () => {
const setCount = useSetAtom(countAtom);
const [show, setShow] = useState(true);
return (
<>
{show ? <Component /> : 'hidden'}
<button onClick={() => setCount((c) => c + 1)}>button</button>
<button onClick={() => setShow((x) => !x)}>toggle</button>
</>
);
};

const { findByText, getByText } = render(
<StrictMode>
<Suspense fallback="loading">
<Parent />
</Suspense>
</StrictMode>,
);

await findByText('loading');

resolve.splice(0).forEach((fn) => fn());
await findByText('count: 0');
expect(abortedCount).toBe(0);

await userEvent.click(getByText('button'));
await userEvent.click(getByText('toggle'));

await findByText('hidden');

resolve.splice(0).forEach((fn) => fn());
await waitFor(() => expect(abortedCount).toBe(0));
});

it('throws aborted error (like fetch)', async () => {
const countAtom = atom(0);
const resolve: (() => void)[] = [];
const derivedAtom = atom(async (get, { signal }) => {
const count = get(countAtom);
await new Promise<void>((r) => resolve.push(r));
if (signal.aborted) {
throw new Error('aborted');
}
return count;
});

const Component = () => {
const count = useAtomValue(derivedAtom);
return <div>count: {count}</div>;
};

const Controls = () => {
const setCount = useSetAtom(countAtom);
return (
<>
<button onClick={() => setCount((c) => c + 1)}>button</button>
</>
);
};

const { findByText, getByText } = render(
<StrictMode>
<Suspense fallback="loading">
<Component />
<Controls />
</Suspense>
</StrictMode>,
);

await findByText('loading');

resolve.splice(0).forEach((fn) => fn());
await findByText('count: 0');

await userEvent.click(getByText('button'));
await userEvent.click(getByText('button'));
resolve.splice(0).forEach((fn) => fn());
await findByText('count: 2');

await userEvent.click(getByText('button'));
resolve.splice(0).forEach((fn) => fn());
await findByText('count: 3');
});
});
Loading

0 comments on commit a027650

Please sign in to comment.