From 819cfd002e2492be1b9f415051f4d88c0279d903 Mon Sep 17 00:00:00 2001 From: Gildas <1122076+djhi@users.noreply.github.com> Date: Wed, 16 Jul 2025 10:10:45 +0200 Subject: [PATCH 1/2] Fix `useEditController` does not pass all variables to `useUpdate` --- .../edit/useEditController.spec.tsx | 66 ++++++++++++++++--- .../src/controller/edit/useEditController.ts | 2 + 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/packages/ra-core/src/controller/edit/useEditController.spec.tsx b/packages/ra-core/src/controller/edit/useEditController.spec.tsx index 221d4f9b41a..da67beec784 100644 --- a/packages/ra-core/src/controller/edit/useEditController.spec.tsx +++ b/packages/ra-core/src/controller/edit/useEditController.spec.tsx @@ -420,15 +420,31 @@ describe('useEditController', () => { mutationMode="pessimistic" mutationOptions={{ onSuccess }} > - {({ save }) => { + {({ record, save }) => { saveCallback = save; - return
; + return
{record?.id}
; }} ); + await screen.findByText('12'); await act(async () => saveCallback({ foo: 'bar' })); - await waitFor(() => expect(onSuccess).toHaveBeenCalled()); + await waitFor(() => + expect(onSuccess).toHaveBeenCalledWith( + { + id: 12, + foo: 'bar', + }, + { + id: 12, + data: { foo: 'bar' }, + previousData: { id: 12 }, + resource: 'posts', + meta: undefined, + }, + { snapshot: expect.any(Array) } + ) + ); expect(notificationsSpy).toEqual([]); }); @@ -458,15 +474,31 @@ describe('useEditController', () => { mutationMode="optimistic" mutationOptions={{ onSuccess }} > - {({ save }) => { + {({ record, save }) => { saveCallback = save; - return
; + return
{record?.id}
; }} ); + await screen.findByText('12'); await act(async () => saveCallback({ foo: 'bar' })); - await waitFor(() => expect(onSuccess).toHaveBeenCalled()); + await waitFor(() => + expect(onSuccess).toHaveBeenCalledWith( + { + id: 12, + foo: 'bar', + }, + { + id: 12, + data: { foo: 'bar' }, + previousData: { id: 12 }, + resource: 'posts', + meta: undefined, + }, + { snapshot: expect.any(Array) } + ) + ); expect(notificationsSpy).toEqual([]); }); @@ -495,15 +527,31 @@ describe('useEditController', () => { {...defaultProps} mutationOptions={{ onSuccess }} > - {({ save }) => { + {({ record, save }) => { saveCallback = save; - return
; + return
{record?.id}
; }} ); + await screen.findByText('12'); await act(async () => saveCallback({ foo: 'bar' })); - await waitFor(() => expect(onSuccess).toHaveBeenCalled()); + await waitFor(() => + expect(onSuccess).toHaveBeenCalledWith( + { + id: 12, + foo: 'bar', + }, + { + id: 12, + data: { foo: 'bar' }, + previousData: { id: 12 }, + resource: 'posts', + meta: undefined, + }, + { snapshot: expect.any(Array) } + ) + ); expect(notificationsSpy).toEqual([]); }); diff --git a/packages/ra-core/src/controller/edit/useEditController.ts b/packages/ra-core/src/controller/edit/useEditController.ts index d345d5227ab..96d8c25a7f1 100644 --- a/packages/ra-core/src/controller/edit/useEditController.ts +++ b/packages/ra-core/src/controller/edit/useEditController.ts @@ -262,6 +262,7 @@ export const useEditController = < id, data, meta: metaFromSave ?? mutationMeta, + previousData: record, }, { onError: onErrorFromSave, @@ -277,6 +278,7 @@ export const useEditController = < [ id, mutationMeta, + record, resource, transform, update, From cd4a7199e506d408481e6141e6751865d6423ce4 Mon Sep 17 00:00:00 2001 From: Gildas <1122076+djhi@users.noreply.github.com> Date: Wed, 16 Jul 2025 10:29:34 +0200 Subject: [PATCH 2/2] Fix tests --- .../src/controller/edit/EditBase.spec.tsx | 24 ++++++++++++------- .../src/button/SaveButton.spec.tsx | 4 ++++ .../ra-ui-materialui/src/detail/Edit.spec.tsx | 10 +++++++- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/ra-core/src/controller/edit/EditBase.spec.tsx b/packages/ra-core/src/controller/edit/EditBase.spec.tsx index ae241a8af1e..7635a69a072 100644 --- a/packages/ra-core/src/controller/edit/EditBase.spec.tsx +++ b/packages/ra-core/src/controller/edit/EditBase.spec.tsx @@ -13,8 +13,8 @@ import { describe('EditBase', () => { it('should give access to the save function', async () => { const dataProvider = testDataProvider({ - // @ts-ignore getOne: () => + // @ts-ignore Promise.resolve({ data: { id: 12, test: 'previous' } }), update: jest.fn((_, { id, data, previousData }) => Promise.resolve({ data: { id, ...previousData, ...data } }) @@ -44,8 +44,8 @@ describe('EditBase', () => { it('should allow to override the onSuccess function', async () => { const dataProvider = testDataProvider({ - // @ts-ignore getOne: () => + // @ts-ignore Promise.resolve({ data: { id: 12, test: 'previous' } }), update: jest.fn((_, { id, data, previousData }) => Promise.resolve({ data: { id, ...previousData, ...data } }) @@ -75,7 +75,9 @@ describe('EditBase', () => { { id: 12, data: { test: 'test' }, + previousData: { id: 12, test: 'previous' }, resource: 'posts', + meta: undefined, }, { snapshot: [] } ); @@ -84,8 +86,8 @@ describe('EditBase', () => { it('should allow to override the onSuccess function at call time', async () => { const dataProvider = testDataProvider({ - // @ts-ignore getOne: () => + // @ts-ignore Promise.resolve({ data: { id: 12, test: 'previous' } }), update: jest.fn((_, { id, data, previousData }) => Promise.resolve({ data: { id, ...previousData, ...data } }) @@ -117,7 +119,9 @@ describe('EditBase', () => { { id: 12, data: { test: 'test' }, + previousData: { id: 12, test: 'previous' }, resource: 'posts', + meta: undefined, }, { snapshot: [] } ); @@ -128,10 +132,9 @@ describe('EditBase', () => { it('should allow to override the onError function', async () => { jest.spyOn(console, 'error').mockImplementation(() => {}); const dataProvider = testDataProvider({ - // @ts-ignore getOne: () => + // @ts-ignore Promise.resolve({ data: { id: 12, test: 'previous' } }), - // @ts-ignore update: jest.fn(() => Promise.reject({ message: 'test' })), }); const onError = jest.fn(); @@ -153,7 +156,9 @@ describe('EditBase', () => { { id: 12, data: { test: 'test' }, + previousData: { id: 12, test: 'previous' }, resource: 'posts', + meta: undefined, }, { snapshot: [] } ); @@ -162,10 +167,9 @@ describe('EditBase', () => { it('should allow to override the onError function at call time', async () => { const dataProvider = testDataProvider({ - // @ts-ignore getOne: () => + // @ts-ignore Promise.resolve({ data: { id: 12, test: 'previous' } }), - // @ts-ignore update: jest.fn(() => Promise.reject({ message: 'test' })), }); const onError = jest.fn(); @@ -189,7 +193,9 @@ describe('EditBase', () => { { id: 12, data: { test: 'test' }, + previousData: { id: 12, test: 'previous' }, resource: 'posts', + meta: undefined, }, { snapshot: [] } ); @@ -199,8 +205,8 @@ describe('EditBase', () => { it('should allow to override the transform function', async () => { const dataProvider = testDataProvider({ - // @ts-ignore getOne: () => + // @ts-ignore Promise.resolve({ data: { id: 12, test: 'previous' } }), update: jest.fn((_, { id, data, previousData }) => Promise.resolve({ data: { id, ...previousData, ...data } }) @@ -239,8 +245,8 @@ describe('EditBase', () => { it('should allow to override the transform function at call time', async () => { const dataProvider = testDataProvider({ - // @ts-ignore getOne: () => + // @ts-ignore Promise.resolve({ data: { id: 12, test: 'previous' } }), update: jest.fn((_, { id, data, previousData }) => Promise.resolve({ data: { id, ...previousData, ...data } }) diff --git a/packages/ra-ui-materialui/src/button/SaveButton.spec.tsx b/packages/ra-ui-materialui/src/button/SaveButton.spec.tsx index 3e1dea27c67..410cff37d48 100644 --- a/packages/ra-ui-materialui/src/button/SaveButton.spec.tsx +++ b/packages/ra-ui-materialui/src/button/SaveButton.spec.tsx @@ -173,7 +173,9 @@ describe('', () => { { id: '123', data: { id: 123, title: 'ipsum' }, + previousData: { id: 123, title: 'lorem' }, resource: 'posts', + meta: undefined, }, { snapshot: [] } ); @@ -224,7 +226,9 @@ describe('', () => { { id: '123', data: { id: 123, title: 'ipsum' }, + previousData: { id: 123, title: 'lorem' }, resource: 'posts', + meta: undefined, }, { snapshot: [] } ); diff --git a/packages/ra-ui-materialui/src/detail/Edit.spec.tsx b/packages/ra-ui-materialui/src/detail/Edit.spec.tsx index 58c7fbd5845..0a5a8f77e31 100644 --- a/packages/ra-ui-materialui/src/detail/Edit.spec.tsx +++ b/packages/ra-ui-materialui/src/detail/Edit.spec.tsx @@ -108,7 +108,7 @@ describe('', () => { }); }); - it("shoudln't display the Edit aside while loading with the emptyWhileLoading prop", async () => { + it("shouldn't display the Edit aside while loading with the emptyWhileLoading prop", async () => { let resolveGetOne; const RenderedComponent = () => { const myDataProvider = { @@ -390,7 +390,9 @@ describe('', () => { { id: '123', data: { id: 123, title: 'ipsum' }, + previousData: { id: 123, title: 'lorem' }, resource: 'foo', + meta: undefined, }, { snapshot: [] } ); @@ -453,7 +455,9 @@ describe('', () => { { id: '123', data: { id: 123, title: 'ipsum' }, + previousData: { id: 123, title: 'lorem' }, resource: 'foo', + meta: undefined, }, { snapshot: [] } ); @@ -510,7 +514,9 @@ describe('', () => { { id: '123', data: { id: 123, title: 'ipsum' }, + previousData: { id: 123, title: 'lorem' }, resource: 'foo', + meta: undefined, }, { snapshot: [] } ); @@ -573,7 +579,9 @@ describe('', () => { { id: '123', data: { id: 123, title: 'ipsum' }, + previousData: { id: 123, title: 'lorem' }, resource: 'foo', + meta: undefined, }, { snapshot: [] } );