DetectChanges: Serialize message payload to avoid non-clonable props (#92831)

Detect changes: Serialize message payload to avoid non-clonable properties
This commit is contained in:
Ivan Ortega Alba 2024-09-05 20:52:05 +02:00 committed by GitHub
parent 35ba8fbad1
commit ae0e970bef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 54 additions and 4 deletions

View File

@ -1,7 +1,23 @@
import { SceneObjectStateChangedEvent } from '@grafana/scenes';
import { Dashboard } from '@grafana/schema';
import { CorsWorker } from 'app/core/utils/CorsWorker';
import * as createDetectChangesWorker from 'app/features/dashboard-scene/saving/createDetectChangesWorker';
import { DashboardScene } from '../scene/DashboardScene';
import { DashboardSceneChangeTracker } from './DashboardSceneChangeTracker';
jest.mock('../serialization/transformSceneToSaveModel', () => {
return {
transformSceneToSaveModel: () => {
return {
title: 'updated dashboard',
invalidProp: () => 'function',
};
},
};
});
describe('DashboardSceneChangeTracker', () => {
it('should set _changesWorker to undefined when terminate is called', () => {
const terminate = jest.fn();
@ -20,4 +36,32 @@ describe('DashboardSceneChangeTracker', () => {
changeTracker.terminate();
expect(changeTracker['_changesWorker']).toBeUndefined();
});
it('should remove non clonable properties before sending to worker', () => {
const scene = new DashboardScene({});
const postMessage = jest.fn();
jest.spyOn(createDetectChangesWorker, 'createWorker').mockImplementation(() => {
return {
postMessage,
} as unknown as CorsWorker;
});
jest.spyOn(DashboardSceneChangeTracker, 'isUpdatingPersistedState').mockImplementation(() => {
return true;
});
jest.spyOn(scene, 'getInitialSaveModel').mockReturnValue({
title: 'initial dashboard',
invalidProp: () => 'function',
} as unknown as Dashboard);
const changeTracker = new DashboardSceneChangeTracker(scene);
changeTracker.startTrackingChanges();
scene.publishEvent({ type: SceneObjectStateChangedEvent.type, payload: { a: 1 } });
expect(postMessage).toHaveBeenCalledWith({
initial: { title: 'initial dashboard' },
changed: { title: 'updated dashboard' },
});
});
});

View File

@ -139,10 +139,16 @@ export class DashboardSceneChangeTracker {
}
private detectSaveModelChanges() {
this._changesWorker?.postMessage({
changed: transformSceneToSaveModel(this._dashboard),
initial: this._dashboard.getInitialSaveModel(),
});
const changedDashboard = transformSceneToSaveModel(this._dashboard);
const initialDashboard = this._dashboard.getInitialSaveModel();
// Objects must be stringify to ensure they are clonable, so they don't contain functions
const changed =
typeof changedDashboard === 'object' ? JSON.parse(JSON.stringify(changedDashboard)) : changedDashboard;
const initial =
typeof initialDashboard === 'object' ? JSON.parse(JSON.stringify(initialDashboard)) : initialDashboard;
this._changesWorker?.postMessage({ initial, changed });
}
private hasMetadataChanges() {