Skip to content

Commit 2abda85

Browse files
committed
listController: fix
1 parent cc3c3bc commit 2abda85

3 files changed

Lines changed: 89 additions & 18 deletions

File tree

packages/ra-core/src/controller/list/useListController.security.stories.tsx

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Resource } from '../../core/Resource';
1111
import { AuthProvider, DataProvider } from '../../types';
1212
import { ListControllerProps, useListController } from './useListController';
1313
import { TestMemoryRouter } from '../../routing/TestMemoryRouter';
14+
import { useAuthState } from '../..';
1415

1516
export default {
1617
title: 'ra-core/controller/list/useListController',
@@ -42,6 +43,16 @@ const defaultDataProvider = fakeDataProvider(
4243
process.env.NODE_ENV === 'development'
4344
);
4445

46+
const Dashboard = () => {
47+
useAuthState();
48+
return (
49+
<div style={styles.mainContainer}>
50+
<div>Dashboard view</div>
51+
<Link to="/posts">List</Link>
52+
</div>
53+
);
54+
};
55+
4556
const Posts = (props: Partial<ListControllerProps>) => {
4657
const params = useListController({
4758
resource: 'posts',
@@ -62,6 +73,7 @@ const Posts = (props: Partial<ListControllerProps>) => {
6273
</ul>
6374
</div>
6475
)}
76+
<Link to="/">Dashboard</Link>
6577
</div>
6678
);
6779
};
@@ -82,14 +94,16 @@ export const Authenticated = ({
8294
dataProvider?: DataProvider;
8395
}) => {
8496
return (
85-
<CoreAdminContext
86-
dataProvider={dataProvider}
87-
authProvider={authProvider}
88-
>
89-
<CoreAdminUI>
90-
<Resource name="posts" list={Posts} />
91-
</CoreAdminUI>
92-
</CoreAdminContext>
97+
<TestMemoryRouter initialEntries={['/posts']}>
98+
<CoreAdminContext
99+
dataProvider={dataProvider}
100+
authProvider={authProvider}
101+
>
102+
<CoreAdminUI>
103+
<Resource name="posts" list={Posts} />
104+
</CoreAdminUI>
105+
</CoreAdminContext>
106+
</TestMemoryRouter>
93107
);
94108
};
95109

@@ -101,16 +115,38 @@ export const DisableAuthentication = ({
101115
dataProvider?: DataProvider;
102116
}) => {
103117
return (
104-
<CoreAdminContext
105-
dataProvider={dataProvider}
106-
authProvider={authProvider}
107-
>
108-
<CoreAdminUI>
109-
<Resource name="posts" list={<Posts disableAuthentication />} />
110-
</CoreAdminUI>
111-
</CoreAdminContext>
118+
<TestMemoryRouter initialEntries={['/posts']}>
119+
<CoreAdminContext
120+
dataProvider={dataProvider}
121+
authProvider={authProvider}
122+
dashboard={Dashboard}
123+
>
124+
<CoreAdminUI dashboard={Dashboard} accessDenied={AccessDenied}>
125+
<Resource
126+
name="posts"
127+
list={<Posts disableAuthentication />}
128+
/>
129+
</CoreAdminUI>
130+
</CoreAdminContext>
131+
</TestMemoryRouter>
112132
);
113133
};
134+
DisableAuthentication.args = {
135+
authProvider: undefined,
136+
};
137+
DisableAuthentication.argTypes = {
138+
authProvider: {
139+
options: ['default', 'canAccess'],
140+
mapping: {
141+
default: undefined,
142+
canAccess: {
143+
...defaultAuthProvider,
144+
canAccess: () => Promise.resolve(false),
145+
},
146+
},
147+
control: { type: 'inline-radio' },
148+
},
149+
};
114150

115151
export const CanAccess = ({
116152
authProviderDelay = 300,

packages/ra-core/src/controller/list/useListController.spec.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,42 @@ describe('useListController', () => {
589589
expect(dataProvider.getList).toHaveBeenCalled();
590590
expect(authProvider.checkAuth).not.toHaveBeenCalled();
591591
});
592+
593+
it('should not call checkAuth nor canAccess when disableAuthentication is true', async () => {
594+
const authProvider: AuthProvider = {
595+
checkAuth: jest.fn().mockResolvedValue(true),
596+
login: () => Promise.resolve(),
597+
logout: () => Promise.resolve(),
598+
checkError: () => Promise.resolve(),
599+
getPermissions: () => Promise.resolve(),
600+
canAccess: jest.fn().mockResolvedValue(false),
601+
};
602+
render(<DisableAuthentication authProvider={authProvider} />);
603+
await screen.findByText('Post #1 - 90 votes');
604+
expect(authProvider.checkAuth).not.toHaveBeenCalled();
605+
expect(authProvider.canAccess).not.toHaveBeenCalled();
606+
});
607+
608+
it('should not call checkAuth nor canAccess when disableAuthentication is true even if useAuthState was called before', async () => {
609+
const authProvider: AuthProvider = {
610+
checkAuth: jest.fn().mockResolvedValue(true),
611+
login: () => Promise.resolve(),
612+
logout: () => Promise.resolve(),
613+
checkError: () => Promise.resolve(),
614+
getPermissions: () => Promise.resolve(),
615+
canAccess: jest.fn().mockResolvedValue(false),
616+
};
617+
render(<DisableAuthentication authProvider={authProvider} />);
618+
await screen.findByText('Post #1 - 90 votes');
619+
fireEvent.click(await screen.findByText('Dashboard'));
620+
await screen.findByText('Dashboard view');
621+
fireEvent.click(await screen.findByText('List'));
622+
await screen.findByText('Post #1 - 90 votes');
623+
// checkAuth is called twice: once by RA (with different params)
624+
// and once by our custom Dashboard component
625+
expect(authProvider.checkAuth).toHaveBeenCalledTimes(2);
626+
expect(authProvider.canAccess).not.toHaveBeenCalled();
627+
});
592628
});
593629

594630
describe('onSelectAll', () => {

packages/ra-core/src/controller/list/useListController.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ export const useListController = <
8585
const { isPending: isPendingCanAccess } = useRequireAccess<RecordType>({
8686
action: 'list',
8787
resource,
88-
// If disableAuthentication is true then isPendingAuthenticated will always be true so this hook is disabled
89-
enabled: !isPendingAuthenticated,
88+
enabled: !disableAuthentication && !isPendingAuthenticated,
9089
});
9190

9291
const translate = useTranslate();

0 commit comments

Comments
 (0)