Skip to content

Commit

Permalink
feat: added a complementary concat function for wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
cecilia-sanare committed Feb 15, 2024
1 parent 3bc6fda commit 719a059
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 92 deletions.
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@happy-dom/jest-environment": "^13.0.6",
"@inrupt/jest-jsdom-polyfills": "^3.0.2",
"@swc/jest": "^0.2.29",
"@tanstack/react-query": "^5.20.5",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
Expand Down
225 changes: 133 additions & 92 deletions src/tests/__tests__/wrap.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,132 +1,173 @@
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { QueryClientProvider, QueryClient, useQuery } from '@tanstack/react-query';
import { wrap } from '../wrap';
import { render, screen } from '@testing-library/react';

describe('fn(wrap)', () => {
it('should support not providing props', async () => {
const Component = wrap(MemoryRouter);
describe('utils(wrap)', () => {
describe('fn(wrap)', () => {
it('should support not providing props', async () => {
const Component = wrap(MemoryRouter);

const MyComponent = await Component(() => (
<Routes>
<Route index element={'Index'} />
</Routes>
));

render(<MyComponent />);
const MyComponent = await Component(() => (
<Routes>
<Route index element={'Index'} />
</Routes>
));

expect(screen.getByText('Index')).toBeTruthy();
});
render(<MyComponent />);

it('should support options as direct props', async () => {
const Component = wrap(MemoryRouter, {
initialEntries: ['/profile'],
expect(screen.getByText('Index')).toBeTruthy();
});

const MyComponent = await Component(() => (
<Routes>
<Route path="/profile" element={'Profile'} />
</Routes>
));

render(<MyComponent />);

expect(screen.getByText('Profile')).toBeTruthy();
});

it('should support options as a function that returns the props', async () => {
const Component = wrap(MemoryRouter, () => ({
initialEntries: ['/profile'],
}));
it('should support options as direct props', async () => {
const Component = wrap(MemoryRouter, {
initialEntries: ['/profile'],
});

const MyComponent = await Component(() => (
<Routes>
<Route path="/profile" element={'Profile'} />
</Routes>
));
const MyComponent = await Component(() => (
<Routes>
<Route path="/profile" element={'Profile'} />
</Routes>
));

render(<MyComponent />);
render(<MyComponent />);

expect(screen.getByText('Profile')).toBeTruthy();
});
expect(screen.getByText('Profile')).toBeTruthy();
});

it('should providing components via promises', async () => {
const Component = wrap(MemoryRouter);
it('should support options as a function that returns the props', async () => {
const Component = wrap(MemoryRouter, () => ({
initialEntries: ['/profile'],
}));

const MyComponent = await Component(
Promise.resolve(() => (
const MyComponent = await Component(() => (
<Routes>
<Route index element={'Index'} />
<Route path="/profile" element={'Profile'} />
</Routes>
))
);
));

render(<MyComponent />);
render(<MyComponent />);

expect(screen.getByText('Index')).toBeTruthy();
});
expect(screen.getByText('Profile')).toBeTruthy();
});

it('should providing components via react routers async Component format', async () => {
const Component = wrap(MemoryRouter);
it('should providing components via promises', async () => {
const Component = wrap(MemoryRouter);

const MyComponent = await Component(
Promise.resolve({
Component: () => (
const MyComponent = await Component(
Promise.resolve(() => (
<Routes>
<Route index element={'Index'} />
</Routes>
),
})
);
))
);

render(<MyComponent />);
render(<MyComponent />);

expect(screen.getByText('Index')).toBeTruthy();
});
expect(screen.getByText('Index')).toBeTruthy();
});

it('should providing components via default async exports', async () => {
const Component = await wrap(MemoryRouter);
it('should providing components via react routers async Component format', async () => {
const Component = wrap(MemoryRouter);

const MyComponent = await Component(
Promise.resolve({
default: () => (
<Routes>
<Route index element={'Index'} />
</Routes>
),
})
);
const MyComponent = await Component(
Promise.resolve({
Component: () => (
<Routes>
<Route index element={'Index'} />
</Routes>
),
})
);

render(<MyComponent />);
render(<MyComponent />);

expect(screen.getByText('Index')).toBeTruthy();
});
expect(screen.getByText('Index')).toBeTruthy();
});

it('should providing components via default async exports', async () => {
const mockOptions = jest.fn();
const Component = await wrap(MemoryRouter, mockOptions);
it('should providing components via default async exports', async () => {
const Component = wrap(MemoryRouter);

const MyComponent = await Component(
Promise.resolve({
default: () => (
<Routes>
<Route index element={'Index'} />
</Routes>
),
})
);
const MyComponent = await Component(
Promise.resolve({
default: () => (
<Routes>
<Route index element={'Index'} />
</Routes>
),
})
);

expect(mockOptions).toHaveBeenCalledTimes(0);
render(<MyComponent />);

render(<MyComponent />);
expect(screen.getByText('Index')).toBeTruthy();
});

expect(mockOptions).toHaveBeenCalledTimes(1);
it('should providing components via default async exports', async () => {
const mockOptions = jest.fn();
const Component = wrap(MemoryRouter, mockOptions);

const { rerender } = render(<MyComponent />);
const MyComponent = await Component(
Promise.resolve({
default: () => (
<Routes>
<Route index element={'Index'} />
</Routes>
),
})
);

expect(mockOptions).toHaveBeenCalledTimes(2);
expect(mockOptions).toHaveBeenCalledTimes(0);

rerender(<MyComponent />);
render(<MyComponent />);

expect(mockOptions).toHaveBeenCalledTimes(2);
expect(mockOptions).toHaveBeenCalledTimes(1);

const { rerender } = render(<MyComponent />);

expect(mockOptions).toHaveBeenCalledTimes(2);

rerender(<MyComponent />);

expect(mockOptions).toHaveBeenCalledTimes(2);
});
});

describe('fn(wrap.concat)', () => {
it('should support combining wrappers', async () => {
const Router = wrap(MemoryRouter);
const ReactQuery = wrap(QueryClientProvider, () => ({
client: new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
}),
}));

const KitchenSink = wrap.concat(Router, ReactQuery);

const MyComponent = await KitchenSink(({ value }: { value: string }) => {
const { data, isSuccess } = useQuery({
queryKey: [],
queryFn: async () => 'hello world!',
});

return (
<>
{isSuccess && <div data-testid="query">{data}</div>}
<Routes>
<Route index element={value} />
</Routes>
</>
);
});

render(<MyComponent value={'Index'} />);

expect(screen.findByTestId('query')).toBeTruthy();
expect(screen.getByText('Index')).toBeTruthy();
});
});
});
14 changes: 14 additions & 0 deletions src/tests/wrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,17 @@ export function wrap<WC extends ElementType>(
};
};
}
export namespace wrap {
export function concat(...wrappers: ReturnType<typeof wrap>[]): ReturnType<typeof wrap> {
return async <C extends React.ElementType>(component: SupportedComponentFormats<C>) => {
let result;

// TODO: Figure out if this can be generated per concater rather then per component
for (const wrapper of wrappers) {
result = result ? wrapper(result) : wrapper(component);
}

return result;
};
}
}

0 comments on commit 719a059

Please sign in to comment.