From 75e4d24db8c6bd96cea32da830ed5c964ac1f136 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Wed, 3 May 2023 19:22:59 +0300 Subject: [PATCH 1/3] Explicitly map user action SO attributes --- .../server/services/user_actions/transform.ts | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/cases/server/services/user_actions/transform.ts b/x-pack/plugins/cases/server/services/user_actions/transform.ts index fb0a17fc6a57b..318906fbf588e 100644 --- a/x-pack/plugins/cases/server/services/user_actions/transform.ts +++ b/x-pack/plugins/cases/server/services/user_actions/transform.ts @@ -61,7 +61,10 @@ export function transformToExternalModel( return { ...userAction, attributes: { - ...userAction.attributes, + type: userAction.attributes.type, + action: userAction.attributes.action, + created_at: userAction.attributes.created_at, + created_by: userAction.attributes.created_by, comment_id: commentId, payload, } as UserActionTransformedAttributes, @@ -104,7 +107,10 @@ function legacyTransformToExternalModel( return { ...userAction, attributes: { - ...userAction.attributes, + type: userAction.attributes.type, + action: userAction.attributes.action, + created_at: userAction.attributes.created_at, + created_by: userAction.attributes.created_by, action_id: userAction.id, case_id: caseId, comment_id: commentId, @@ -122,17 +128,22 @@ const addReferenceIdToPayload = ( if (isConnectorUserAction(userActionAttributes) || isCreateCaseUserAction(userActionAttributes)) { return { - ...userActionAttributes.payload, connector: { - ...userActionAttributes.payload.connector, + name: userActionAttributes.payload.connector.name, + type: userActionAttributes.payload.connector.type, + fields: userActionAttributes.payload.connector.fields, id: connectorId ?? NONE_CONNECTOR_ID, }, }; } else if (isPushedUserAction(userActionAttributes)) { return { - ...userAction.attributes.payload, externalService: { - ...userActionAttributes.payload.externalService, + connector_name: userActionAttributes.payload.externalService.connector_name, + external_id: userActionAttributes.payload.externalService.external_id, + external_title: userActionAttributes.payload.externalService.external_title, + external_url: userActionAttributes.payload.externalService.external_url, + pushed_at: userActionAttributes.payload.externalService.pushed_at, + pushed_by: userActionAttributes.payload.externalService.pushed_by, connector_id: connectorId ?? NONE_CONNECTOR_ID, }, }; @@ -145,9 +156,13 @@ const addReferenceIdToPayload = ( ); return { - ...userAction.attributes.payload, comment: { - ...userActionAttributes.payload.comment, + externalReferenceAttachmentTypeId: + userActionAttributes.payload.comment.externalReferenceAttachmentTypeId, + externalReferenceMetadata: userActionAttributes.payload.comment.externalReferenceMetadata, + externalReferenceStorage: userActionAttributes.payload.comment.externalReferenceStorage, + owner: userActionAttributes.payload.comment.owner, + type: userActionAttributes.payload.comment.type, externalReferenceId: externalReferenceId ?? '', }, }; @@ -163,10 +178,11 @@ const addReferenceIdToPayload = ( ); return { - ...userAction.attributes.payload, comment: { - ...userActionAttributes.payload.comment, - ...injectedAttributes, + persistableStateAttachmentState: injectedAttributes.persistableStateAttachmentState, + persistableStateAttachmentTypeId: injectedAttributes.persistableStateAttachmentTypeId, + owner: injectedAttributes.owner, + type: injectedAttributes.type, }, }; } From 107c58b6789cb4090b5edc1a33050788287dabbb Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Wed, 3 May 2023 19:37:19 +0300 Subject: [PATCH 2/3] Fix bug --- .../server/services/user_actions/transform.ts | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/server/services/user_actions/transform.ts b/x-pack/plugins/cases/server/services/user_actions/transform.ts index 318906fbf588e..e227b5424bb14 100644 --- a/x-pack/plugins/cases/server/services/user_actions/transform.ts +++ b/x-pack/plugins/cases/server/services/user_actions/transform.ts @@ -65,6 +65,7 @@ export function transformToExternalModel( action: userAction.attributes.action, created_at: userAction.attributes.created_at, created_by: userAction.attributes.created_by, + owner: userAction.attributes.owner, comment_id: commentId, payload, } as UserActionTransformedAttributes, @@ -111,6 +112,7 @@ function legacyTransformToExternalModel( action: userAction.attributes.action, created_at: userAction.attributes.created_at, created_by: userAction.attributes.created_by, + owner: userAction.attributes.owner, action_id: userAction.id, case_id: caseId, comment_id: commentId, @@ -126,7 +128,24 @@ const addReferenceIdToPayload = ( const connectorId = getConnectorIdFromReferences(userAction); const userActionAttributes = userAction.attributes; - if (isConnectorUserAction(userActionAttributes) || isCreateCaseUserAction(userActionAttributes)) { + if (isCreateCaseUserAction(userActionAttributes)) { + return { + assignees: userActionAttributes.payload.assignees, + description: userActionAttributes.payload.description, + owner: userActionAttributes.payload.owner, + settings: userActionAttributes.payload.settings, + severity: userActionAttributes.payload.severity, + status: userActionAttributes.payload.status, + tags: userActionAttributes.payload.tags, + title: userActionAttributes.payload.title, + connector: { + name: userActionAttributes.payload.connector.name, + type: userActionAttributes.payload.connector.type, + fields: userActionAttributes.payload.connector.fields, + id: connectorId ?? NONE_CONNECTOR_ID, + }, + }; + } else if (isConnectorUserAction(userActionAttributes)) { return { connector: { name: userActionAttributes.payload.connector.name, From 5e4e02503341b9fdde0115242047f7d6c8e89a27 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Thu, 4 May 2023 15:41:25 +0300 Subject: [PATCH 3/3] Add more tests --- .../__snapshots__/transform.test.ts.snap | 310 ++++++++++++++++++ .../services/user_actions/test_utils.ts | 141 +++++--- .../services/user_actions/transform.test.ts | 174 +++++++++- 3 files changed, 565 insertions(+), 60 deletions(-) diff --git a/x-pack/plugins/cases/server/services/user_actions/__snapshots__/transform.test.ts.snap b/x-pack/plugins/cases/server/services/user_actions/__snapshots__/transform.test.ts.snap index fe35cda0f2475..20fd62a96a611 100644 --- a/x-pack/plugins/cases/server/services/user_actions/__snapshots__/transform.test.ts.snap +++ b/x-pack/plugins/cases/server/services/user_actions/__snapshots__/transform.test.ts.snap @@ -331,3 +331,313 @@ Object { "total": 1, } `; + +exports[`transform transformToExternalModel formats the payload correctly for: create case 1`] = ` +Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "assignees": undefined, + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "id": "1", + "name": ".jira", + "type": ".jira", + }, + "description": "a desc", + "owner": "securitySolution", + "settings": Object { + "syncAlerts": false, + }, + "severity": "low", + "status": "open", + "tags": Array [], + "title": "a title", + }, + "type": "create_case", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ], + "type": "cases-user-actions", +} +`; + +exports[`transform transformToExternalModel formats the payload correctly for: create connector 1`] = ` +Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "id": "1", + "name": ".jira", + "type": ".jira", + }, + }, + "type": "connector", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ], + "type": "cases-user-actions", +} +`; + +exports[`transform transformToExternalModel formats the payload correctly for: description 1`] = ` +Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "description": "test", + }, + "type": "description", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + ], + "type": "cases-user-actions", +} +`; + +exports[`transform transformToExternalModel formats the payload correctly for: external reference 1`] = ` +Object { + "attributes": Object { + "action": "create", + "comment_id": "external-reference-test-id", + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "comment": Object { + "externalReferenceAttachmentTypeId": ".test", + "externalReferenceId": "my-id", + "externalReferenceMetadata": null, + "externalReferenceStorage": Object { + "soType": "test-so", + "type": "savedObject", + }, + "owner": "securitySolution", + "type": "externalReference", + }, + }, + "type": "comment", + }, + "id": "100", + "references": Array [ + Object { + "id": "my-id", + "name": "externalReferenceId", + "type": "test-so", + }, + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "external-reference-test-id", + "name": "associated-cases-comments", + "type": "cases-comments", + }, + ], + "type": "cases-user-actions", +} +`; + +exports[`transform transformToExternalModel formats the payload correctly for: persistable state 1`] = ` +Object { + "attributes": Object { + "action": "create", + "comment_id": "persistable-state-test-id", + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "comment": Object { + "owner": "securitySolutionFixture", + "persistableStateAttachmentState": Object { + "foo": "foo", + "injectedId": "testRef", + }, + "persistableStateAttachmentTypeId": ".test", + "type": "persistableState", + }, + }, + "type": "comment", + }, + "id": "100", + "references": Array [ + Object { + "id": "testRef", + "name": "myTestReference", + "type": "test-so", + }, + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "persistable-state-test-id", + "name": "associated-cases-comments", + "type": "cases-comments", + }, + ], + "type": "cases-user-actions", +} +`; + +exports[`transform transformToExternalModel formats the payload correctly for: push connector 1`] = ` +Object { + "attributes": Object { + "action": "push_to_service", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "externalService": Object { + "connector_id": "100", + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + }, + "type": "pushed", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ], + "type": "cases-user-actions", +} +`; + +exports[`transform transformToExternalModel formats the payload correctly for: update connector 1`] = ` +Object { + "attributes": Object { + "action": "update", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "id": "1", + "name": ".jira", + "type": ".jira", + }, + }, + "type": "connector", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ], + "type": "cases-user-actions", +} +`; diff --git a/x-pack/plugins/cases/server/services/user_actions/test_utils.ts b/x-pack/plugins/cases/server/services/user_actions/test_utils.ts index b4dbb114fc2fe..947de303360f5 100644 --- a/x-pack/plugins/cases/server/services/user_actions/test_utils.ts +++ b/x-pack/plugins/cases/server/services/user_actions/test_utils.ts @@ -10,7 +10,7 @@ import type { SavedObjectsFindResponse, SavedObjectsFindResult, } from '@kbn/core-saved-objects-api-server'; -import type { SavedObject, SavedObjectReference } from '@kbn/core-saved-objects-common'; +import type { SavedObject, SavedObjectReference } from '@kbn/core/server'; import { omit, get } from 'lodash'; import { CASE_COMMENT_SAVED_OBJECT, @@ -42,7 +42,7 @@ import { persistableStateAttachment, } from '../../attachment_framework/mocks'; import type { PersistableStateAttachmentTypeRegistry } from '../../attachment_framework/persistable_state_registry'; -import { transformFindResponseToExternalModel } from './transform'; +import { transformFindResponseToExternalModel, transformToExternalModel } from './transform'; export const createUserActionFindSO = ( userAction: SavedObject @@ -235,56 +235,107 @@ export const testConnectorId = ( path: string, expectedConnectorId = '1' ) => { - it('does set payload.connector.id to none when it cannot find the reference', () => { - const userActionWithEmptyRef = { ...userAction, references: [] }; - const transformed = transformFindResponseToExternalModel( - createSOFindResponse([createUserActionFindSO(userActionWithEmptyRef)]), - persistableStateAttachmentTypeRegistry - ); + describe('transformFindResponseToExternalModel', () => { + it('does set payload.connector.id to none when it cannot find the reference', () => { + const userActionWithEmptyRef = { ...userAction, references: [] }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userActionWithEmptyRef)]), + persistableStateAttachmentTypeRegistry + ); - expect(get(transformed.saved_objects[0].attributes.payload, path)).toBe('none'); - }); + expect(get(transformed.saved_objects[0].attributes.payload, path)).toBe('none'); + }); - it('does not populate the payload.connector.id when the reference exists but the action is not of type connector', () => { - const invalidUserAction = { - ...userAction, - attributes: { ...userAction.attributes, type: 'not-connector' }, - }; - const transformed = transformFindResponseToExternalModel( - createSOFindResponse([ - createUserActionFindSO( - invalidUserAction as SavedObject - ), - ]), - persistableStateAttachmentTypeRegistry - ); + it('does not populate the payload.connector.id when the reference exists but the action is not of type connector', () => { + const invalidUserAction = { + ...userAction, + attributes: { ...userAction.attributes, type: 'not-connector' }, + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO( + invalidUserAction as SavedObject + ), + ]), + persistableStateAttachmentTypeRegistry + ); - expect(get(transformed.saved_objects[0].attributes.payload, path)).toBeUndefined(); - }); + expect(get(transformed.saved_objects[0].attributes.payload, path)).toBeUndefined(); + }); + + it('does not populate the payload.connector.id when the reference exists but the payload does not contain a connector', () => { + const invalidUserAction = { + ...userAction, + attributes: { ...userAction.attributes, payload: {} }, + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO( + invalidUserAction as SavedObject + ), + ]), + persistableStateAttachmentTypeRegistry + ) as SavedObjectsFindResponse; - it('does not populate the payload.connector.id when the reference exists but the payload does not contain a connector', () => { - const invalidUserAction = { - ...userAction, - attributes: { ...userAction.attributes, payload: {} }, - }; - const transformed = transformFindResponseToExternalModel( - createSOFindResponse([ - createUserActionFindSO( - invalidUserAction as SavedObject - ), - ]), - persistableStateAttachmentTypeRegistry - ) as SavedObjectsFindResponse; + expect(get(transformed.saved_objects[0].attributes.payload, path)).toBeUndefined(); + }); - expect(get(transformed.saved_objects[0].attributes.payload, path)).toBeUndefined(); + it('populates the payload.connector.id', () => { + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]), + persistableStateAttachmentTypeRegistry + ) as SavedObjectsFindResponse; + + expect(get(transformed.saved_objects[0].attributes.payload, path)).toEqual( + expectedConnectorId + ); + }); }); - it('populates the payload.connector.id', () => { - const transformed = transformFindResponseToExternalModel( - createSOFindResponse([createUserActionFindSO(userAction)]), - persistableStateAttachmentTypeRegistry - ) as SavedObjectsFindResponse; + describe('transformToExternalModel', () => { + it('does set payload.connector.id to none when it cannot find the reference', () => { + const userActionWithEmptyRef = { ...userAction, references: [] }; + const transformed = transformToExternalModel( + userActionWithEmptyRef, + persistableStateAttachmentTypeRegistry + ); + + expect(get(transformed.attributes.payload, path)).toBe('none'); + }); + + it('does not populate the payload.connector.id when the reference exists but the action is not of type connector', () => { + const invalidUserAction = { + ...userAction, + attributes: { ...userAction.attributes, type: 'not-connector' }, + }; + const transformed = transformToExternalModel( + invalidUserAction, + persistableStateAttachmentTypeRegistry + ); + + expect(get(transformed.attributes.payload, path)).toBeUndefined(); + }); + + it('does not populate the payload.connector.id when the reference exists but the payload does not contain a connector', () => { + const invalidUserAction = { + ...userAction, + attributes: { ...userAction.attributes, payload: {} }, + }; + const transformed = transformToExternalModel( + invalidUserAction, + persistableStateAttachmentTypeRegistry + ); + + expect(get(transformed.attributes.payload, path)).toBeUndefined(); + }); + + it('populates the payload.connector.id', () => { + const transformed = transformToExternalModel( + userAction, + persistableStateAttachmentTypeRegistry + ); - expect(get(transformed.saved_objects[0].attributes.payload, path)).toEqual(expectedConnectorId); + expect(get(transformed.attributes.payload, path)).toEqual(expectedConnectorId); + }); }); }; diff --git a/x-pack/plugins/cases/server/services/user_actions/transform.test.ts b/x-pack/plugins/cases/server/services/user_actions/transform.test.ts index effe650182bef..8df74d0527515 100644 --- a/x-pack/plugins/cases/server/services/user_actions/transform.test.ts +++ b/x-pack/plugins/cases/server/services/user_actions/transform.test.ts @@ -8,6 +8,7 @@ import { legacyTransformFindResponseToExternalModel, transformFindResponseToExternalModel, + transformToExternalModel, } from './transform'; import { createSOFindResponse } from '../test_utils'; import { @@ -25,6 +26,8 @@ import { createPersistableStateAttachmentTypeRegistryMock } from '../../attachme import type { SavedObjectsFindResponse } from '@kbn/core-saved-objects-api-server'; import type { ConnectorUserAction } from '../../../common/api'; import { Actions } from '../../../common/api'; +import type { UserActionPersistedAttributes } from '../../common/types/user_actions'; +import type { SavedObject } from '@kbn/core/server'; describe('transform', () => { const persistableStateAttachmentTypeRegistry = createPersistableStateAttachmentTypeRegistryMock(); @@ -179,6 +182,30 @@ describe('transform', () => { }); }); + describe('persistable state attachments', () => { + it('populates the persistable state', () => { + const transformed = transformer( + createSOFindResponse([createUserActionFindSO(createPersistableStateUserAction())]), + persistableStateAttachmentTypeRegistry + ) as SavedObjectsFindResponse; + + expect(transformed).toMatchSnapshot(); + }); + }); + + describe('external references', () => { + it('populates the external references attributes', () => { + const transformed = transformer( + createSOFindResponse([createUserActionFindSO(createExternalReferenceUserAction())]), + persistableStateAttachmentTypeRegistry + ) as SavedObjectsFindResponse; + + expect(transformed).toMatchSnapshot(); + }); + }); + }); + + describe('connectors', () => { describe('create connector', () => { const userAction = createConnectorUserAction(); testConnectorId(persistableStateAttachmentTypeRegistry, userAction, 'connector.id'); @@ -203,27 +230,144 @@ describe('transform', () => { const userAction = createCaseUserAction(); testConnectorId(persistableStateAttachmentTypeRegistry, userAction, 'connector.id'); }); + }); - describe('persistable state attachments', () => { - it('populates the persistable state', () => { - const transformed = transformer( - createSOFindResponse([createUserActionFindSO(createPersistableStateUserAction())]), - persistableStateAttachmentTypeRegistry - ) as SavedObjectsFindResponse; + describe('transformToExternalModel', () => { + it('returns the correct fields', () => { + const transformed = transformToExternalModel( + createConnectorUserAction(), + persistableStateAttachmentTypeRegistry + ); - expect(transformed).toMatchSnapshot(); - }); + expect(transformed.attributes).toMatchInlineSnapshot(` + Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "id": "1", + "name": ".jira", + "type": ".jira", + }, + }, + "type": "connector", + } + `); }); - describe('external references', () => { - it('populates the external references attributes', () => { - const transformed = transformer( - createSOFindResponse([createUserActionFindSO(createExternalReferenceUserAction())]), - persistableStateAttachmentTypeRegistry - ) as SavedObjectsFindResponse; + it('preserves the saved object fields and attributes when inject the ids', () => { + const transformed = transformToExternalModel( + createConnectorUserAction(), + persistableStateAttachmentTypeRegistry + ); - expect(transformed).toMatchSnapshot(); + expect(transformed).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "id": "1", + "name": ".jira", + "type": ".jira", + }, + }, + "type": "connector", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ], + "type": "cases-user-actions", + } + `); + }); + + it('sets comment_id to null when it cannot find the reference', () => { + const userAction = { + ...createUserActionSO({ action: Actions.create, commentId: '5' }), + references: [], + }; + const transformed = transformToExternalModel( + userAction, + persistableStateAttachmentTypeRegistry + ); + + expect(transformed.attributes.comment_id).toBeNull(); + }); + + it('sets comment_id correctly when it finds the reference', () => { + const userAction = createUserActionSO({ + action: Actions.create, + commentId: '5', }); + + const transformed = transformToExternalModel( + userAction, + persistableStateAttachmentTypeRegistry + ); + + expect(transformed.attributes.comment_id).toEqual('5'); + }); + + const userActions = [ + ['create connector', createConnectorUserAction()], + ['update connector', updateConnectorUserAction()], + ['push connector', pushConnectorUserAction()], + ['create case', createCaseUserAction()], + ['persistable state', createPersistableStateUserAction()], + ['external reference', createExternalReferenceUserAction()], + [ + 'description', + createUserActionSO({ + action: Actions.create, + payload: { description: 'test' }, + type: 'description', + }), + ], + ] as Array<[string, SavedObject]>; + + it.each(userActions)('formats the payload correctly for: %s', (_, userAction) => { + const transformed = transformToExternalModel( + userAction, + persistableStateAttachmentTypeRegistry + ); + + expect(transformed).toMatchSnapshot(); }); }); });