[TEST] Covering useDeleteOne relations optimistic cache behavior (#10238)
## Introduction Added coverage on the `useDeleteOneRecord` hooks, especially its optimistic behavior feature. Introduced a new testing tool `InMemoryTestingCacheInstance` that has builtin very basic expectors in order to avoid future duplication when covering others record hooks `update, create, destroy` etc etc ## Notes Added few comments in this PR regarding some builtin functions I've created around companies and people mocked object model and that I think could be cool to spread and centralize within a dedicated "class template" Also put in light that unless I'm mistaken some tests are running on `RecordNode` and not `RecordObject` Took few directions on my own that as I always I would suggestion nor remarks on them ! Let me know ## Misc - Should we refactor `useDeleteOneRecord` tests to follow `eachTesting` pattern ? => I feel like this is inappropriate as this hooks is already high level, the only plus value would be less tests code despite readability IMO
This commit is contained in:
@ -4,14 +4,14 @@ import { renderHook, waitFor } from '@testing-library/react';
|
|||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
import { useDeleteMultipleRecordsAction } from '../useDeleteMultipleRecordsAction';
|
import { useDeleteMultipleRecordsAction } from '../useDeleteMultipleRecordsAction';
|
||||||
|
|
||||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const peopleMock = getPeopleRecordConnectionMock();
|
||||||
|
|
||||||
const deleteManyRecordsMock = jest.fn();
|
const deleteManyRecordsMock = jest.fn();
|
||||||
const resetTableRowSelectionMock = jest.fn();
|
const resetTableRowSelectionMock = jest.fn();
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
getJestMetadataAndApolloMocksAndActionMenuWrapper,
|
getJestMetadataAndApolloMocksAndActionMenuWrapper,
|
||||||
} from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
} from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
import { useDestroyMultipleRecordsAction } from '../useDestroyMultipleRecordsAction';
|
import { useDestroyMultipleRecordsAction } from '../useDestroyMultipleRecordsAction';
|
||||||
|
|
||||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
@ -20,10 +20,12 @@ const personMockObjectMetadataItemDeletedAtField =
|
|||||||
if (personMockObjectMetadataItemDeletedAtField === undefined)
|
if (personMockObjectMetadataItemDeletedAtField === undefined)
|
||||||
throw new Error('Should never occur');
|
throw new Error('Should never occur');
|
||||||
|
|
||||||
const [firstPeopleMock, secondPeopleMock] = getPeopleMock().map((record) => ({
|
const [firstPeopleMock, secondPeopleMock] = getPeopleRecordConnectionMock().map(
|
||||||
...record,
|
(record) => ({
|
||||||
deletedAt: new Date().toISOString(),
|
...record,
|
||||||
}));
|
deletedAt: new Date().toISOString(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const destroyManyRecordsMock = jest.fn();
|
const destroyManyRecordsMock = jest.fn();
|
||||||
const resetTableRowSelectionMock = jest.fn();
|
const resetTableRowSelectionMock = jest.fn();
|
||||||
|
|||||||
@ -3,14 +3,14 @@ import { renderHook, waitFor } from '@testing-library/react';
|
|||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
import { useExportMultipleRecordsAction } from '../useExportMultipleRecordsAction';
|
import { useExportMultipleRecordsAction } from '../useExportMultipleRecordsAction';
|
||||||
|
|
||||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const peopleMock = getPeopleRecordConnectionMock();
|
||||||
|
|
||||||
const downloadMock = jest.fn();
|
const downloadMock = jest.fn();
|
||||||
|
|
||||||
|
|||||||
@ -6,14 +6,14 @@ import {
|
|||||||
getJestMetadataAndApolloMocksAndActionMenuWrapper,
|
getJestMetadataAndApolloMocksAndActionMenuWrapper,
|
||||||
} from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
} from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
import { useAddToFavoritesSingleRecordAction } from '../useAddToFavoritesSingleRecordAction';
|
import { useAddToFavoritesSingleRecordAction } from '../useAddToFavoritesSingleRecordAction';
|
||||||
|
|
||||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const peopleMock = getPeopleRecordConnectionMock();
|
||||||
|
|
||||||
const favoritesMock = [
|
const favoritesMock = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,14 +3,14 @@ import { renderHook } from '@testing-library/react';
|
|||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
import { useDeleteSingleRecordAction } from '../useDeleteSingleRecordAction';
|
import { useDeleteSingleRecordAction } from '../useDeleteSingleRecordAction';
|
||||||
|
|
||||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const peopleMock = getPeopleRecordConnectionMock();
|
||||||
|
|
||||||
const deleteOneRecordMock = jest.fn();
|
const deleteOneRecordMock = jest.fn();
|
||||||
|
|
||||||
|
|||||||
@ -6,14 +6,14 @@ import {
|
|||||||
getJestMetadataAndApolloMocksAndActionMenuWrapper,
|
getJestMetadataAndApolloMocksAndActionMenuWrapper,
|
||||||
} from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
} from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
import { useRemoveFromFavoritesSingleRecordAction } from '../useRemoveFromFavoritesSingleRecordAction';
|
import { useRemoveFromFavoritesSingleRecordAction } from '../useRemoveFromFavoritesSingleRecordAction';
|
||||||
|
|
||||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const peopleMock = getPeopleRecordConnectionMock();
|
||||||
|
|
||||||
const favoritesMock = [
|
const favoritesMock = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
|||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { getCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
|
import { getMockCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { mockedUserData } from '~/testing/mock-data/users';
|
import { mockedUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ const renderHooks = ({
|
|||||||
{
|
{
|
||||||
id: 'viewId',
|
id: 'viewId',
|
||||||
name: 'Test View',
|
name: 'Test View',
|
||||||
objectMetadataId: getCompanyObjectMetadataItem().id,
|
objectMetadataId: getMockCompanyObjectMetadataItem().id,
|
||||||
type: ViewType.Table,
|
type: ViewType.Table,
|
||||||
key: null,
|
key: null,
|
||||||
isCompact: false,
|
isCompact: false,
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
|
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getRecordNodeFromRecord } from '../getRecordNodeFromRecord';
|
import { getRecordNodeFromRecord } from '../getRecordNodeFromRecord';
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const peopleMock = getPeopleRecordConnectionMock();
|
||||||
|
|
||||||
describe('getRecordNodeFromRecord', () => {
|
describe('getRecordNodeFromRecord', () => {
|
||||||
it('computes relation records cache references by default', () => {
|
it('computes relation records cache references by default', () => {
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
|
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
|
||||||
import {
|
import {
|
||||||
getPersonObjectMetadataItem,
|
allMockPersonRecords,
|
||||||
getPersonRecord,
|
getMockPersonObjectMetadataItem,
|
||||||
} from '~/testing/mock-data/people';
|
} from '~/testing/mock-data/people';
|
||||||
|
|
||||||
describe('computeDepthOneRecordGqlFieldsFromRecord', () => {
|
describe('computeDepthOneRecordGqlFieldsFromRecord', () => {
|
||||||
const objectMetadataItem = getPersonObjectMetadataItem();
|
const objectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
it('Should handle basic call', () => {
|
it('Should handle basic call', () => {
|
||||||
const personRecord = getPersonRecord();
|
const personRecord = allMockPersonRecords[0];
|
||||||
const result = computeDepthOneRecordGqlFieldsFromRecord({
|
const result = computeDepthOneRecordGqlFieldsFromRecord({
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
record: personRecord,
|
record: personRecord,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||||
import { getPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
import { getMockPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
||||||
|
|
||||||
describe('generateDepthOneRecordGqlFields', () => {
|
describe('generateDepthOneRecordGqlFields', () => {
|
||||||
const objectMetadataItem = getPersonObjectMetadataItem();
|
const objectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
it('Should handle basic call with standalone objectMetadataItem', () => {
|
it('Should handle basic call with standalone objectMetadataItem', () => {
|
||||||
const result = generateDepthOneRecordGqlFields({
|
const result = generateDepthOneRecordGqlFields({
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import { getPersonRecord } from '~/testing/mock-data/people';
|
import { getMockPersonRecord } from '~/testing/mock-data/people';
|
||||||
|
|
||||||
export const query = gql`
|
export const query = gql`
|
||||||
mutation DeleteManyPeople($filter: PersonFilterInput!) {
|
mutation DeleteManyPeople($filter: PersonFilterInput!) {
|
||||||
@ -17,7 +17,7 @@ export const personIds = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const personRecords = personIds.map<ObjectRecord>((personId, index) =>
|
export const personRecords = personIds.map<ObjectRecord>((personId, index) =>
|
||||||
getPersonRecord({ id: personId, deletedAt: null }, index),
|
getMockPersonRecord({ id: personId, deletedAt: null }, index),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const variables = {
|
export const variables = {
|
||||||
|
|||||||
@ -8,14 +8,4 @@ export const query = gql`
|
|||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const variables = {
|
|
||||||
idToDelete: 'a7286b9a-c039-4a89-9567-2dfa7953cda9',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const responseData = {
|
|
||||||
__typename: 'Person',
|
|
||||||
deletedAt: '2024-02-14T09:45:00Z',
|
|
||||||
id: 'a7286b9a-c039-4a89-9567-2dfa7953cda9',
|
|
||||||
};
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
|
import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
|
||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const peopleMock = getPeopleRecordConnectionMock();
|
||||||
|
|
||||||
export const query = gql`
|
export const query = gql`
|
||||||
query FindDuplicatePerson($ids: [ID!]!) {
|
query FindDuplicatePerson($ids: [ID!]!) {
|
||||||
|
|||||||
@ -0,0 +1,624 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`useDeleteOneRecord A. Starting from empty cache 1. Should successfully delete record and update record cache entry 1`] = `
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"deletedAt": "2024-02-14T09:45:00Z",
|
||||||
|
"id": "da3c2c4b-da01-4b81-9734-226069eb4cd0",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`useDeleteOneRecord B. Starting from filled cache 1. Should handle successfull record deletion 1`] = `
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"city": "ASd",
|
||||||
|
"company": {
|
||||||
|
"__typename": "Company",
|
||||||
|
"address": {
|
||||||
|
"__typename": "Address",
|
||||||
|
"addressCity": "Dublin",
|
||||||
|
"addressCountry": "Ireland",
|
||||||
|
"addressLat": null,
|
||||||
|
"addressLng": null,
|
||||||
|
"addressPostcode": null,
|
||||||
|
"addressState": null,
|
||||||
|
"addressStreet1": "Eutaw Street",
|
||||||
|
"addressStreet2": null,
|
||||||
|
},
|
||||||
|
"createdAt": "2025-02-16T08:21:51.715Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"context": {},
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"domainName": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "https://linkedin.com",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"employees": null,
|
||||||
|
"id": "20202020-3ec3-4fe3-8997-b76aa0bfa408",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": "Linkedin",
|
||||||
|
"position": 1,
|
||||||
|
},
|
||||||
|
"createdAt": "2024-08-02T09:52:46.814Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": "2024-02-14T09:45:00Z",
|
||||||
|
"id": "da3c2c4b-da01-4b81-9734-226069eb4cd0",
|
||||||
|
"jobTitle": "",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"__typename": "FullName",
|
||||||
|
"firstName": "Test",
|
||||||
|
"lastName": "Test",
|
||||||
|
},
|
||||||
|
"noteTargets": [],
|
||||||
|
"phones": {
|
||||||
|
"primaryPhoneCallingCode": "+33",
|
||||||
|
"primaryPhoneCountryCode": "FR",
|
||||||
|
"primaryPhoneNumber": "781234562",
|
||||||
|
},
|
||||||
|
"position": 0,
|
||||||
|
"taskTargets": [],
|
||||||
|
"xLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`useDeleteOneRecord B. Starting from filled cache 1. Should handle successfull record deletion 2`] = `
|
||||||
|
{
|
||||||
|
"__typename": "Company",
|
||||||
|
"accountOwner": null,
|
||||||
|
"address": {
|
||||||
|
"__typename": "Address",
|
||||||
|
"addressCity": "Dublin",
|
||||||
|
"addressCountry": "Ireland",
|
||||||
|
"addressLat": null,
|
||||||
|
"addressLng": null,
|
||||||
|
"addressPostcode": null,
|
||||||
|
"addressState": null,
|
||||||
|
"addressStreet1": "Eutaw Street",
|
||||||
|
"addressStreet2": null,
|
||||||
|
},
|
||||||
|
"createdAt": "2025-02-16T08:21:51.715Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"context": {},
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"domainName": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "https://linkedin.com",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"employees": null,
|
||||||
|
"id": "20202020-3ec3-4fe3-8997-b76aa0bfa408",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": "Linkedin",
|
||||||
|
"noteTargets": [],
|
||||||
|
"opportunities": [
|
||||||
|
{},
|
||||||
|
],
|
||||||
|
"people": [
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"city": "Seattle",
|
||||||
|
"createdAt": "2024-08-01T09:50:00.000Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"id": "20202020-1c0e-494c-a1b6-85b1c6fefaa5",
|
||||||
|
"jobTitle": "",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"__typename": "FullName",
|
||||||
|
"firstName": "Christoph",
|
||||||
|
"lastName": "Callisto",
|
||||||
|
},
|
||||||
|
"phones": {
|
||||||
|
"primaryPhoneCallingCode": "+33",
|
||||||
|
"primaryPhoneCountryCode": "FR",
|
||||||
|
"primaryPhoneNumber": "781234562",
|
||||||
|
},
|
||||||
|
"position": 1,
|
||||||
|
"xLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"city": "Los Angeles",
|
||||||
|
"createdAt": "2024-08-02T09:48:36.193Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"id": "20202020-ac73-4797-824e-87a1f5aea9e0",
|
||||||
|
"jobTitle": "",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"__typename": "FullName",
|
||||||
|
"firstName": "Sylvie",
|
||||||
|
"lastName": "Palmer",
|
||||||
|
},
|
||||||
|
"phones": {
|
||||||
|
"primaryPhoneCallingCode": "+33",
|
||||||
|
"primaryPhoneCountryCode": "FR",
|
||||||
|
"primaryPhoneNumber": "781234576",
|
||||||
|
},
|
||||||
|
"position": 2,
|
||||||
|
"xLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"position": 1,
|
||||||
|
"taskTargets": [],
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`useDeleteOneRecord B. Starting from filled cache 2. Should handle optimistic cache on record deletion 1`] = `
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"city": "ASd",
|
||||||
|
"company": {
|
||||||
|
"__typename": "Company",
|
||||||
|
"address": {
|
||||||
|
"__typename": "Address",
|
||||||
|
"addressCity": "Dublin",
|
||||||
|
"addressCountry": "Ireland",
|
||||||
|
"addressLat": null,
|
||||||
|
"addressLng": null,
|
||||||
|
"addressPostcode": null,
|
||||||
|
"addressState": null,
|
||||||
|
"addressStreet1": "Eutaw Street",
|
||||||
|
"addressStreet2": null,
|
||||||
|
},
|
||||||
|
"createdAt": "2025-02-16T08:21:51.715Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"context": {},
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"domainName": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "https://linkedin.com",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"employees": null,
|
||||||
|
"id": "20202020-3ec3-4fe3-8997-b76aa0bfa408",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": "Linkedin",
|
||||||
|
"position": 1,
|
||||||
|
},
|
||||||
|
"createdAt": "2024-08-02T09:52:46.814Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": Any<String>,
|
||||||
|
"id": "da3c2c4b-da01-4b81-9734-226069eb4cd0",
|
||||||
|
"jobTitle": "",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"__typename": "FullName",
|
||||||
|
"firstName": "Test",
|
||||||
|
"lastName": "Test",
|
||||||
|
},
|
||||||
|
"noteTargets": [],
|
||||||
|
"phones": {
|
||||||
|
"primaryPhoneCallingCode": "+33",
|
||||||
|
"primaryPhoneCountryCode": "FR",
|
||||||
|
"primaryPhoneNumber": "781234562",
|
||||||
|
},
|
||||||
|
"position": 0,
|
||||||
|
"taskTargets": [],
|
||||||
|
"xLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`useDeleteOneRecord B. Starting from filled cache 2. Should handle optimistic cache on record deletion 2`] = `
|
||||||
|
{
|
||||||
|
"__typename": "Company",
|
||||||
|
"accountOwner": null,
|
||||||
|
"address": {
|
||||||
|
"__typename": "Address",
|
||||||
|
"addressCity": "Dublin",
|
||||||
|
"addressCountry": "Ireland",
|
||||||
|
"addressLat": null,
|
||||||
|
"addressLng": null,
|
||||||
|
"addressPostcode": null,
|
||||||
|
"addressState": null,
|
||||||
|
"addressStreet1": "Eutaw Street",
|
||||||
|
"addressStreet2": null,
|
||||||
|
},
|
||||||
|
"createdAt": "2025-02-16T08:21:51.715Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"context": {},
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"domainName": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "https://linkedin.com",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"employees": null,
|
||||||
|
"id": "20202020-3ec3-4fe3-8997-b76aa0bfa408",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": "Linkedin",
|
||||||
|
"noteTargets": [],
|
||||||
|
"opportunities": [
|
||||||
|
{},
|
||||||
|
],
|
||||||
|
"people": [
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"city": "Seattle",
|
||||||
|
"createdAt": "2024-08-01T09:50:00.000Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"id": "20202020-1c0e-494c-a1b6-85b1c6fefaa5",
|
||||||
|
"jobTitle": "",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"__typename": "FullName",
|
||||||
|
"firstName": "Christoph",
|
||||||
|
"lastName": "Callisto",
|
||||||
|
},
|
||||||
|
"phones": {
|
||||||
|
"primaryPhoneCallingCode": "+33",
|
||||||
|
"primaryPhoneCountryCode": "FR",
|
||||||
|
"primaryPhoneNumber": "781234562",
|
||||||
|
},
|
||||||
|
"position": 1,
|
||||||
|
"xLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"city": "Los Angeles",
|
||||||
|
"createdAt": "2024-08-02T09:48:36.193Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"id": "20202020-ac73-4797-824e-87a1f5aea9e0",
|
||||||
|
"jobTitle": "",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"__typename": "FullName",
|
||||||
|
"firstName": "Sylvie",
|
||||||
|
"lastName": "Palmer",
|
||||||
|
},
|
||||||
|
"phones": {
|
||||||
|
"primaryPhoneCallingCode": "+33",
|
||||||
|
"primaryPhoneCountryCode": "FR",
|
||||||
|
"primaryPhoneNumber": "781234576",
|
||||||
|
},
|
||||||
|
"position": 2,
|
||||||
|
"xLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"position": 1,
|
||||||
|
"taskTargets": [],
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`useDeleteOneRecord B. Starting from filled cache 3. Should handle optimistic cache rollback on record deletion failure 1`] = `
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"city": "ASd",
|
||||||
|
"company": {
|
||||||
|
"__typename": "Company",
|
||||||
|
"address": {
|
||||||
|
"__typename": "Address",
|
||||||
|
"addressCity": "Dublin",
|
||||||
|
"addressCountry": "Ireland",
|
||||||
|
"addressLat": null,
|
||||||
|
"addressLng": null,
|
||||||
|
"addressPostcode": null,
|
||||||
|
"addressState": null,
|
||||||
|
"addressStreet1": "Eutaw Street",
|
||||||
|
"addressStreet2": null,
|
||||||
|
},
|
||||||
|
"createdAt": "2025-02-16T08:21:51.715Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"context": {},
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"domainName": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "https://linkedin.com",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"employees": null,
|
||||||
|
"id": "20202020-3ec3-4fe3-8997-b76aa0bfa408",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": "Linkedin",
|
||||||
|
"position": 1,
|
||||||
|
},
|
||||||
|
"createdAt": "2024-08-02T09:52:46.814Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"id": "da3c2c4b-da01-4b81-9734-226069eb4cd0",
|
||||||
|
"jobTitle": "",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"__typename": "FullName",
|
||||||
|
"firstName": "Test",
|
||||||
|
"lastName": "Test",
|
||||||
|
},
|
||||||
|
"noteTargets": [],
|
||||||
|
"phones": {
|
||||||
|
"primaryPhoneCallingCode": "+33",
|
||||||
|
"primaryPhoneCountryCode": "FR",
|
||||||
|
"primaryPhoneNumber": "781234562",
|
||||||
|
},
|
||||||
|
"position": 0,
|
||||||
|
"taskTargets": [],
|
||||||
|
"xLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`useDeleteOneRecord B. Starting from filled cache 3. Should handle optimistic cache rollback on record deletion failure 2`] = `
|
||||||
|
{
|
||||||
|
"__typename": "Company",
|
||||||
|
"accountOwner": null,
|
||||||
|
"address": {
|
||||||
|
"__typename": "Address",
|
||||||
|
"addressCity": "Dublin",
|
||||||
|
"addressCountry": "Ireland",
|
||||||
|
"addressLat": null,
|
||||||
|
"addressLng": null,
|
||||||
|
"addressPostcode": null,
|
||||||
|
"addressState": null,
|
||||||
|
"addressStreet1": "Eutaw Street",
|
||||||
|
"addressStreet2": null,
|
||||||
|
},
|
||||||
|
"createdAt": "2025-02-16T08:21:51.715Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"context": {},
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"domainName": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "https://linkedin.com",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"employees": null,
|
||||||
|
"id": "20202020-3ec3-4fe3-8997-b76aa0bfa408",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": "Linkedin",
|
||||||
|
"noteTargets": [],
|
||||||
|
"opportunities": [
|
||||||
|
{},
|
||||||
|
],
|
||||||
|
"people": [
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"city": "Seattle",
|
||||||
|
"createdAt": "2024-08-01T09:50:00.000Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"id": "20202020-1c0e-494c-a1b6-85b1c6fefaa5",
|
||||||
|
"jobTitle": "",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"__typename": "FullName",
|
||||||
|
"firstName": "Christoph",
|
||||||
|
"lastName": "Callisto",
|
||||||
|
},
|
||||||
|
"phones": {
|
||||||
|
"primaryPhoneCallingCode": "+33",
|
||||||
|
"primaryPhoneCountryCode": "FR",
|
||||||
|
"primaryPhoneNumber": "781234562",
|
||||||
|
},
|
||||||
|
"position": 1,
|
||||||
|
"xLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__typename": "Person",
|
||||||
|
"city": "Los Angeles",
|
||||||
|
"createdAt": "2024-08-02T09:48:36.193Z",
|
||||||
|
"createdBy": {
|
||||||
|
"__typename": "Actor",
|
||||||
|
"name": "Tim Apple",
|
||||||
|
"source": "MANUAL",
|
||||||
|
"workspaceMemberId": "20202020-0687-4c41-b707-ed1bfca972a7",
|
||||||
|
},
|
||||||
|
"deletedAt": null,
|
||||||
|
"id": "20202020-ac73-4797-824e-87a1f5aea9e0",
|
||||||
|
"jobTitle": "",
|
||||||
|
"linkedinLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"__typename": "FullName",
|
||||||
|
"firstName": "Sylvie",
|
||||||
|
"lastName": "Palmer",
|
||||||
|
},
|
||||||
|
"phones": {
|
||||||
|
"primaryPhoneCallingCode": "+33",
|
||||||
|
"primaryPhoneCountryCode": "FR",
|
||||||
|
"primaryPhoneNumber": "781234576",
|
||||||
|
},
|
||||||
|
"position": 2,
|
||||||
|
"xLink": {
|
||||||
|
"__typename": "Links",
|
||||||
|
"primaryLinkLabel": "",
|
||||||
|
"primaryLinkUrl": "",
|
||||||
|
"secondaryLinks": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"position": 1,
|
||||||
|
"taskTargets": [],
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -17,7 +17,7 @@ import { InMemoryCache } from '@apollo/client';
|
|||||||
import { MockedResponse } from '@apollo/client/testing';
|
import { MockedResponse } from '@apollo/client/testing';
|
||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||||
import { getPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
import { getMockPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
||||||
const getDefaultMocks = (
|
const getDefaultMocks = (
|
||||||
overrides?: Partial<MockedResponse>,
|
overrides?: Partial<MockedResponse>,
|
||||||
): MockedResponse[] => [
|
): MockedResponse[] => [
|
||||||
@ -40,7 +40,7 @@ const mockRefetchAggregateQueries = jest.fn();
|
|||||||
(useRefetchAggregateQueries as jest.Mock).mockReturnValue({
|
(useRefetchAggregateQueries as jest.Mock).mockReturnValue({
|
||||||
refetchAggregateQueries: mockRefetchAggregateQueries,
|
refetchAggregateQueries: mockRefetchAggregateQueries,
|
||||||
});
|
});
|
||||||
const objectMetadataItem = getPersonObjectMetadataItem();
|
const objectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
const objectMetadataItems = [objectMetadataItem];
|
const objectMetadataItems = [objectMetadataItem];
|
||||||
const expectedCachedRecordsWithDeletedAt = personRecords.map(
|
const expectedCachedRecordsWithDeletedAt = personRecords.map(
|
||||||
(personRecord) => ({
|
(personRecord) => ({
|
||||||
|
|||||||
@ -1,24 +1,24 @@
|
|||||||
import { renderHook, waitFor } from '@testing-library/react';
|
import { renderHook, waitFor } from '@testing-library/react';
|
||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
|
|
||||||
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
|
import { query } from '@/object-record/hooks/__mocks__/useDeleteOneRecord';
|
||||||
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
|
|
||||||
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
|
|
||||||
import {
|
|
||||||
query,
|
|
||||||
responseData,
|
|
||||||
variables,
|
|
||||||
} from '@/object-record/hooks/__mocks__/useDeleteOneRecord';
|
|
||||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||||
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
|
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { InMemoryCache } from '@apollo/client';
|
|
||||||
import { MockedResponse } from '@apollo/client/testing';
|
import { MockedResponse } from '@apollo/client/testing';
|
||||||
import { expect } from '@storybook/jest';
|
import { expect } from '@storybook/jest';
|
||||||
|
import { InMemoryTestingCacheInstance } from '~/testing/cache/inMemoryTestingCacheInstance';
|
||||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||||
|
import { getMockCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
|
||||||
import {
|
import {
|
||||||
getPersonObjectMetadataItem,
|
allMockCompanyRecordsWithRelation,
|
||||||
getPersonRecord,
|
findMockCompanyWithRelationRecord,
|
||||||
|
} from '~/testing/mock-data/companiesWithRelations';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
import {
|
||||||
|
allMockPersonRecords,
|
||||||
|
getMockPersonObjectMetadataItem,
|
||||||
|
getMockPersonRecord,
|
||||||
} from '~/testing/mock-data/people';
|
} from '~/testing/mock-data/people';
|
||||||
|
|
||||||
jest.mock('@/object-record/hooks/useRefetchAggregateQueries');
|
jest.mock('@/object-record/hooks/useRefetchAggregateQueries');
|
||||||
@ -27,64 +27,63 @@ const mockRefetchAggregateQueries = jest.fn();
|
|||||||
refetchAggregateQueries: mockRefetchAggregateQueries,
|
refetchAggregateQueries: mockRefetchAggregateQueries,
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO Should test relation deletion cache hydratation
|
|
||||||
describe('useDeleteOneRecord', () => {
|
describe('useDeleteOneRecord', () => {
|
||||||
let cache: InMemoryCache;
|
const personRecord = getMockPersonRecord({
|
||||||
|
deletedAt: null,
|
||||||
|
});
|
||||||
|
const relatedCompanyRecord = findMockCompanyWithRelationRecord({
|
||||||
|
id: personRecord.company.id,
|
||||||
|
});
|
||||||
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
|
const companyObjectMetadataItem = getMockCompanyObjectMetadataItem();
|
||||||
|
const objectMetadataItems = generatedMockObjectMetadataItems;
|
||||||
|
|
||||||
const getDefaultMocks = (
|
const getDefaultMocks = (
|
||||||
overrides?: Partial<MockedResponse>,
|
overrides?: Partial<MockedResponse>,
|
||||||
): MockedResponse[] => [
|
): MockedResponse[] => {
|
||||||
{
|
const deleteOneQueryMock: MockedResponse<
|
||||||
|
Record<string, any>,
|
||||||
|
Record<'idToDelete', string>
|
||||||
|
> = {
|
||||||
request: {
|
request: {
|
||||||
|
variables: { idToDelete: personRecord.id },
|
||||||
query,
|
query,
|
||||||
variables,
|
|
||||||
},
|
},
|
||||||
result: jest.fn(() => ({
|
result: jest.fn((variables) => ({
|
||||||
data: {
|
data: {
|
||||||
deletePerson: responseData,
|
deletePerson: {
|
||||||
|
__typename: 'Person',
|
||||||
|
deletedAt: '2024-02-14T09:45:00Z',
|
||||||
|
id: variables.idToDelete,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
...overrides,
|
...overrides,
|
||||||
},
|
};
|
||||||
];
|
return [deleteOneQueryMock];
|
||||||
const defaultMocks = getDefaultMocks();
|
|
||||||
const personRecord = getPersonRecord({
|
|
||||||
id: 'a7286b9a-c039-4a89-9567-2dfa7953cda9',
|
|
||||||
deletedAt: null,
|
|
||||||
});
|
|
||||||
const objectMetadataItem = getPersonObjectMetadataItem();
|
|
||||||
const objectMetadataItems = [objectMetadataItem];
|
|
||||||
const assertCachedRecordMatch = (expectedRecord: ObjectRecord) => {
|
|
||||||
const cachedRecord = getRecordFromCache({
|
|
||||||
cache,
|
|
||||||
objectMetadataItem,
|
|
||||||
objectMetadataItems,
|
|
||||||
recordId: personRecord.id,
|
|
||||||
});
|
|
||||||
expect(cachedRecord).not.toBeNull();
|
|
||||||
if (cachedRecord === null) throw new Error('Should never occur');
|
|
||||||
// Find a way to reverse assertion
|
|
||||||
expect(expectedRecord).toMatchObject(cachedRecord);
|
|
||||||
};
|
};
|
||||||
const assertCachedRecordIsNull = () =>
|
const defaultMocks = getDefaultMocks();
|
||||||
expect(
|
|
||||||
getRecordFromCache({
|
|
||||||
cache,
|
|
||||||
objectMetadataItem,
|
|
||||||
objectMetadataItems,
|
|
||||||
recordId: personRecord.id,
|
|
||||||
}),
|
|
||||||
).toBeNull();
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
cache = new InMemoryCache();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('A. Starting from empty cache', () => {
|
describe('A. Starting from empty cache', () => {
|
||||||
|
const {
|
||||||
|
cache,
|
||||||
|
assertCachedRecordIsNull,
|
||||||
|
assertCachedRecordMatchSnapshot,
|
||||||
|
restoreCacheToInitialState,
|
||||||
|
} = new InMemoryTestingCacheInstance({
|
||||||
|
objectMetadataItems,
|
||||||
|
});
|
||||||
|
beforeEach(async () => restoreCacheToInitialState());
|
||||||
|
|
||||||
it('1. Should successfully delete record and update record cache entry', async () => {
|
it('1. Should successfully delete record and update record cache entry', async () => {
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() =>
|
() =>
|
||||||
useDeleteOneRecord({
|
useDeleteOneRecord({
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||||
@ -98,13 +97,22 @@ describe('useDeleteOneRecord', () => {
|
|||||||
const deleteOneResult = await result.current.deleteOneRecord(
|
const deleteOneResult = await result.current.deleteOneRecord(
|
||||||
personRecord.id,
|
personRecord.id,
|
||||||
);
|
);
|
||||||
const expectedResult: ObjectRecord = {
|
expect(deleteOneResult).toStrictEqual<ObjectRecord>({
|
||||||
__typename: personRecord.__typename,
|
__typename: personRecord.__typename,
|
||||||
deletedAt: expect.any(String),
|
deletedAt: expect.any(String),
|
||||||
id: personRecord.id,
|
id: personRecord.id,
|
||||||
};
|
});
|
||||||
expect(deleteOneResult).toStrictEqual(expectedResult);
|
assertCachedRecordMatchSnapshot({
|
||||||
assertCachedRecordMatch(expectedResult);
|
recordId: personRecord.id,
|
||||||
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
|
matchObject: {
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assertCachedRecordIsNull({
|
||||||
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
|
recordId: personRecord.company.id,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(defaultMocks[0].result).toHaveBeenCalled();
|
expect(defaultMocks[0].result).toHaveBeenCalled();
|
||||||
@ -115,10 +123,11 @@ describe('useDeleteOneRecord', () => {
|
|||||||
const apolloMocks: MockedResponse[] = getDefaultMocks({
|
const apolloMocks: MockedResponse[] = getDefaultMocks({
|
||||||
delay: Number.POSITIVE_INFINITY,
|
delay: Number.POSITIVE_INFINITY,
|
||||||
});
|
});
|
||||||
|
expect(personRecord).toHaveProperty('company');
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() =>
|
() =>
|
||||||
useDeleteOneRecord({
|
useDeleteOneRecord({
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||||
@ -131,7 +140,14 @@ describe('useDeleteOneRecord', () => {
|
|||||||
await act(async () => {
|
await act(async () => {
|
||||||
result.current.deleteOneRecord(personRecord.id);
|
result.current.deleteOneRecord(personRecord.id);
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
assertCachedRecordIsNull();
|
assertCachedRecordIsNull({
|
||||||
|
recordId: personRecord.id,
|
||||||
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
|
});
|
||||||
|
assertCachedRecordIsNull({
|
||||||
|
recordId: personRecord.company.id,
|
||||||
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -146,7 +162,7 @@ describe('useDeleteOneRecord', () => {
|
|||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() =>
|
() =>
|
||||||
useDeleteOneRecord({
|
useDeleteOneRecord({
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||||
@ -161,32 +177,47 @@ describe('useDeleteOneRecord', () => {
|
|||||||
await result.current.deleteOneRecord(personRecord.id);
|
await result.current.deleteOneRecord(personRecord.id);
|
||||||
fail('Should have thrown an error');
|
fail('Should have thrown an error');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assertCachedRecordIsNull();
|
assertCachedRecordIsNull({
|
||||||
|
recordId: personRecord.id,
|
||||||
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
|
});
|
||||||
|
assertCachedRecordIsNull({
|
||||||
|
recordId: relatedCompanyRecord.id,
|
||||||
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('B. Starting from filled cache', () => {
|
describe('B. Starting from filled cache', () => {
|
||||||
|
const {
|
||||||
|
assertCachedRecordMatchSnapshot,
|
||||||
|
cache,
|
||||||
|
restoreCacheToInitialState,
|
||||||
|
} = new InMemoryTestingCacheInstance({
|
||||||
|
objectMetadataItems,
|
||||||
|
initialRecordsInCache: [
|
||||||
|
{
|
||||||
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
|
records: allMockCompanyRecordsWithRelation,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
|
records: allMockPersonRecords,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const recordGqlFields = computeDepthOneRecordGqlFieldsFromRecord({
|
restoreCacheToInitialState();
|
||||||
objectMetadataItem,
|
|
||||||
record: personRecord,
|
|
||||||
});
|
|
||||||
updateRecordFromCache({
|
|
||||||
cache,
|
|
||||||
objectMetadataItem,
|
|
||||||
objectMetadataItems,
|
|
||||||
record: personRecord,
|
|
||||||
recordGqlFields,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('1. Should handle successfull record deletion', async () => {
|
it('1. Should handle successfull record deletion', async () => {
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() =>
|
() =>
|
||||||
useDeleteOneRecord({
|
useDeleteOneRecord({
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||||
@ -198,15 +229,23 @@ describe('useDeleteOneRecord', () => {
|
|||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
const res = await result.current.deleteOneRecord(personRecord.id);
|
const res = await result.current.deleteOneRecord(personRecord.id);
|
||||||
expect(res).toBeDefined();
|
expect(res).toMatchObject<ObjectRecord>({
|
||||||
expect(res.deletedAt).toBeDefined();
|
__typename: 'Person',
|
||||||
expect(res).toHaveProperty('id', personRecord.id);
|
id: personRecord.id,
|
||||||
|
|
||||||
const personRecordWithDeletedAt = {
|
|
||||||
...personRecord,
|
|
||||||
deletedAt: expect.any(String),
|
deletedAt: expect.any(String),
|
||||||
};
|
});
|
||||||
assertCachedRecordMatch(personRecordWithDeletedAt);
|
|
||||||
|
assertCachedRecordMatchSnapshot({
|
||||||
|
recordId: personRecord.id,
|
||||||
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
|
matchObject: {
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assertCachedRecordMatchSnapshot({
|
||||||
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
|
recordId: personRecord.company.id,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(defaultMocks[0].result).toHaveBeenCalled();
|
expect(defaultMocks[0].result).toHaveBeenCalled();
|
||||||
@ -221,7 +260,7 @@ describe('useDeleteOneRecord', () => {
|
|||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() =>
|
() =>
|
||||||
useDeleteOneRecord({
|
useDeleteOneRecord({
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||||
@ -234,11 +273,21 @@ describe('useDeleteOneRecord', () => {
|
|||||||
await act(async () => {
|
await act(async () => {
|
||||||
result.current.deleteOneRecord(personRecord.id);
|
result.current.deleteOneRecord(personRecord.id);
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
const personRecordWithDeletedAt = {
|
assertCachedRecordMatchSnapshot({
|
||||||
...personRecord,
|
recordId: personRecord.id,
|
||||||
deletedAt: expect.any(String),
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
};
|
snapshotPropertyMatchers: {
|
||||||
assertCachedRecordMatch(personRecordWithDeletedAt);
|
// Request is paused then the cached get filled with optmistic deletedAt
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
},
|
||||||
|
matchObject: {
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assertCachedRecordMatchSnapshot({
|
||||||
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
|
recordId: personRecord.company.id,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -253,7 +302,7 @@ describe('useDeleteOneRecord', () => {
|
|||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() =>
|
() =>
|
||||||
useDeleteOneRecord({
|
useDeleteOneRecord({
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||||
@ -268,11 +317,17 @@ describe('useDeleteOneRecord', () => {
|
|||||||
await result.current.deleteOneRecord(personRecord.id);
|
await result.current.deleteOneRecord(personRecord.id);
|
||||||
fail('Should have thrown an error');
|
fail('Should have thrown an error');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const personRecordWithDeletedAt = {
|
assertCachedRecordMatchSnapshot({
|
||||||
...personRecord,
|
recordId: personRecord.id,
|
||||||
deletedAt: null,
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
};
|
matchObject: {
|
||||||
assertCachedRecordMatch(personRecordWithDeletedAt);
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assertCachedRecordMatchSnapshot({
|
||||||
|
objectMetadataItem: companyObjectMetadataItem,
|
||||||
|
recordId: personRecord.company.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,8 @@ import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewCompon
|
|||||||
import { MockedResponse } from '@apollo/client/testing';
|
import { MockedResponse } from '@apollo/client/testing';
|
||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
|
|
||||||
const recordTableId = 'people';
|
const recordTableId = 'people';
|
||||||
const objectNameSingular = 'person';
|
const objectNameSingular = 'person';
|
||||||
const onColumnsChange = jest.fn();
|
const onColumnsChange = jest.fn();
|
||||||
@ -422,7 +423,7 @@ const mocks: MockedResponse[] = [
|
|||||||
},
|
},
|
||||||
result: jest.fn(() => ({
|
result: jest.fn(() => ({
|
||||||
data: {
|
data: {
|
||||||
people: getPeopleMock(),
|
people: getPeopleRecordConnectionMock(),
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -7,21 +7,21 @@ import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/Componen
|
|||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { allMockPersonRecords } from '~/testing/mock-data/people';
|
||||||
import { sleep } from '~/utils/sleep';
|
import { sleep } from '~/utils/sleep';
|
||||||
|
|
||||||
import { SingleRecordPicker } from '@/object-record/record-picker/components/SingleRecordPicker';
|
import { SingleRecordPicker } from '@/object-record/record-picker/components/SingleRecordPicker';
|
||||||
import { SingleRecordPickerRecord } from '../../types/SingleRecordPickerRecord';
|
import { SingleRecordPickerRecord } from '../../types/SingleRecordPickerRecord';
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const records = allMockPersonRecords.map<SingleRecordPickerRecord>(
|
||||||
|
(person) => ({
|
||||||
const records = peopleMock.map<SingleRecordPickerRecord>((person) => ({
|
id: person.id,
|
||||||
id: person.id,
|
name: person.name.firstName + ' ' + person.name.lastName,
|
||||||
name: person.name.firstName + ' ' + person.name.lastName,
|
avatarUrl: 'https://picsum.photos/200',
|
||||||
avatarUrl: 'https://picsum.photos/200',
|
avatarType: 'rounded',
|
||||||
avatarType: 'rounded',
|
record: { ...person, __typename: 'Person' },
|
||||||
record: { ...person, __typename: 'Person' },
|
}),
|
||||||
}));
|
);
|
||||||
|
|
||||||
const meta: Meta<typeof SingleRecordPicker> = {
|
const meta: Meta<typeof SingleRecordPicker> = {
|
||||||
title: 'UI/RecordPicker/SingleRecordPicker',
|
title: 'UI/RecordPicker/SingleRecordPicker',
|
||||||
|
|||||||
@ -9,16 +9,14 @@ import { RecordStoreDecorator } from '~/testing/decorators/RecordStoreDecorator'
|
|||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
|
||||||
|
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
import { allMockPersonRecords } from '~/testing/mock-data/people';
|
||||||
import { RecordDetailRelationSection } from '../RecordDetailRelationSection';
|
import { RecordDetailRelationSection } from '../RecordDetailRelationSection';
|
||||||
|
|
||||||
const companiesMock = getCompaniesMock();
|
const companiesMock = getCompaniesMock();
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
|
||||||
|
|
||||||
const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'company',
|
(item) => item.nameSingular === 'company',
|
||||||
);
|
);
|
||||||
@ -72,9 +70,9 @@ export const WithRecords: Story = {
|
|||||||
records: [
|
records: [
|
||||||
{
|
{
|
||||||
...companiesMock[0],
|
...companiesMock[0],
|
||||||
people: peopleMock,
|
people: allMockPersonRecords,
|
||||||
},
|
},
|
||||||
...peopleMock,
|
...allMockPersonRecords,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,9 +4,9 @@ import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphq
|
|||||||
import { FieldActorForInputValue } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldActorForInputValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
|
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
|
||||||
import { InMemoryCache } from '@apollo/client';
|
import { InMemoryCache } from '@apollo/client';
|
||||||
import { getCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
|
import { getMockCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
import { getMockPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
||||||
import { mockCurrentWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
import { mockCurrentWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
||||||
|
|
||||||
describe('computeOptimisticRecordFromInput', () => {
|
describe('computeOptimisticRecordFromInput', () => {
|
||||||
@ -14,7 +14,7 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
const currentWorkspaceMemberFullname = `${currentWorkspaceMember.name.firstName} ${currentWorkspaceMember.name.lastName}`;
|
const currentWorkspaceMemberFullname = `${currentWorkspaceMember.name.firstName} ${currentWorkspaceMember.name.lastName}`;
|
||||||
it('should generate correct optimistic record if no relation field is present', () => {
|
it('should generate correct optimistic record if no relation field is present', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
|
|
||||||
const result = computeOptimisticRecordFromInput({
|
const result = computeOptimisticRecordFromInput({
|
||||||
currentWorkspaceMember,
|
currentWorkspaceMember,
|
||||||
@ -33,7 +33,7 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
|
|
||||||
it('should generate correct optimistic record with actor field', () => {
|
it('should generate correct optimistic record with actor field', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
const actorFieldValueForInput: FieldActorForInputValue = {
|
const actorFieldValueForInput: FieldActorForInputValue = {
|
||||||
context: {},
|
context: {},
|
||||||
source: 'API',
|
source: 'API',
|
||||||
@ -62,7 +62,7 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
|
|
||||||
it('should generate correct optimistic record createdBy when recordInput contains id', () => {
|
it('should generate correct optimistic record createdBy when recordInput contains id', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
const result = computeOptimisticRecordFromInput({
|
const result = computeOptimisticRecordFromInput({
|
||||||
currentWorkspaceMember,
|
currentWorkspaceMember,
|
||||||
objectMetadataItems: generatedMockObjectMetadataItems,
|
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||||
@ -90,7 +90,7 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
|
|
||||||
it('should generate correct optimistic record if relation field is present but cache is empty', () => {
|
it('should generate correct optimistic record if relation field is present but cache is empty', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
|
|
||||||
const result = computeOptimisticRecordFromInput({
|
const result = computeOptimisticRecordFromInput({
|
||||||
currentWorkspaceMember,
|
currentWorkspaceMember,
|
||||||
@ -109,8 +109,8 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
|
|
||||||
it('should generate correct optimistic record even if recordInput contains field __typename', () => {
|
it('should generate correct optimistic record even if recordInput contains field __typename', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
const companyObjectMetadataItem = getCompanyObjectMetadataItem();
|
const companyObjectMetadataItem = getMockCompanyObjectMetadataItem();
|
||||||
|
|
||||||
const companyRecord = {
|
const companyRecord = {
|
||||||
id: '123',
|
id: '123',
|
||||||
@ -154,8 +154,8 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
|
|
||||||
it('should generate correct optimistic record if relation field is present and cache is not empty', () => {
|
it('should generate correct optimistic record if relation field is present and cache is not empty', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
const companyObjectMetadataItem = getCompanyObjectMetadataItem();
|
const companyObjectMetadataItem = getMockCompanyObjectMetadataItem();
|
||||||
|
|
||||||
const companyRecord = {
|
const companyRecord = {
|
||||||
id: '123',
|
id: '123',
|
||||||
@ -198,7 +198,7 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
|
|
||||||
it('should generate correct optimistic record if relation field is null and cache is empty', () => {
|
it('should generate correct optimistic record if relation field is null and cache is empty', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
|
|
||||||
const result = computeOptimisticRecordFromInput({
|
const result = computeOptimisticRecordFromInput({
|
||||||
currentWorkspaceMember,
|
currentWorkspaceMember,
|
||||||
@ -218,7 +218,7 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
|
|
||||||
it('should throw an error if recordInput contains fields unrelated to the current objectMetadata', () => {
|
it('should throw an error if recordInput contains fields unrelated to the current objectMetadata', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
computeOptimisticRecordFromInput({
|
computeOptimisticRecordFromInput({
|
||||||
@ -240,7 +240,7 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
|
|
||||||
it('should throw an error if recordInput contains both the relationFieldId and relationField', () => {
|
it('should throw an error if recordInput contains both the relationFieldId and relationField', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
computeOptimisticRecordFromInput({
|
computeOptimisticRecordFromInput({
|
||||||
@ -260,7 +260,7 @@ describe('computeOptimisticRecordFromInput', () => {
|
|||||||
|
|
||||||
it('should throw an error if recordInput contains both the relationFieldId and relationField even if null', () => {
|
it('should throw an error if recordInput contains both the relationFieldId and relationField even if null', () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
const personObjectMetadataItem = getPersonObjectMetadataItem();
|
const personObjectMetadataItem = getMockPersonObjectMetadataItem();
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
computeOptimisticRecordFromInput({
|
computeOptimisticRecordFromInput({
|
||||||
|
|||||||
@ -6,11 +6,11 @@ import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadat
|
|||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
|
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
|
||||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||||
|
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { allMockPersonRecords } from '~/testing/mock-data/people';
|
||||||
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
|
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
|
||||||
import { WorkflowEditActionFormDeleteRecord } from '../WorkflowEditActionFormDeleteRecord';
|
import { WorkflowEditActionFormDeleteRecord } from '../WorkflowEditActionFormDeleteRecord';
|
||||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
|
||||||
|
|
||||||
const DEFAULT_ACTION = {
|
const DEFAULT_ACTION = {
|
||||||
id: getWorkflowNodeIdMock(),
|
id: getWorkflowNodeIdMock(),
|
||||||
@ -100,7 +100,7 @@ export const DisabledWithEmptyValues: Story = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const peopleMock = getPeopleMock()[0];
|
const peopleMock = allMockPersonRecords[0];
|
||||||
|
|
||||||
export const DisabledWithDefaultStaticValues: Story = {
|
export const DisabledWithDefaultStaticValues: Story = {
|
||||||
args: {
|
args: {
|
||||||
|
|||||||
@ -6,11 +6,11 @@ import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadat
|
|||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
|
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
|
||||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||||
|
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { allMockPersonRecords } from '~/testing/mock-data/people';
|
||||||
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
|
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
|
||||||
import { WorkflowEditActionFormUpdateRecord } from '../WorkflowEditActionFormUpdateRecord';
|
import { WorkflowEditActionFormUpdateRecord } from '../WorkflowEditActionFormUpdateRecord';
|
||||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
|
||||||
|
|
||||||
const DEFAULT_ACTION = {
|
const DEFAULT_ACTION = {
|
||||||
id: getWorkflowNodeIdMock(),
|
id: getWorkflowNodeIdMock(),
|
||||||
@ -128,7 +128,7 @@ export const DisabledWithEmptyValues: Story = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const peopleMock = getPeopleMock()[0];
|
const peopleMock = allMockPersonRecords[0];
|
||||||
|
|
||||||
export const DisabledWithDefaultStaticValues: Story = {
|
export const DisabledWithDefaultStaticValues: Story = {
|
||||||
args: {
|
args: {
|
||||||
|
|||||||
@ -8,13 +8,15 @@ import {
|
|||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { getPeopleMock, peopleQueryResult } from '~/testing/mock-data/people';
|
import {
|
||||||
|
allMockPersonRecords,
|
||||||
|
peopleQueryResult,
|
||||||
|
} from '~/testing/mock-data/people';
|
||||||
import { mockedWorkspaceMemberData } from '~/testing/mock-data/users';
|
import { mockedWorkspaceMemberData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
import { RecordShowPage } from '../RecordShowPage';
|
import { RecordShowPage } from '../RecordShowPage';
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const personRecord = allMockPersonRecords[0];
|
||||||
|
|
||||||
const meta: Meta<PageDecoratorArgs> = {
|
const meta: Meta<PageDecoratorArgs> = {
|
||||||
title: 'Pages/ObjectRecord/RecordShowPage',
|
title: 'Pages/ObjectRecord/RecordShowPage',
|
||||||
component: RecordShowPage,
|
component: RecordShowPage,
|
||||||
@ -22,7 +24,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
routePath: '/object/:objectNameSingular/:objectRecordId',
|
routePath: '/object/:objectNameSingular/:objectRecordId',
|
||||||
routeParams: {
|
routeParams: {
|
||||||
':objectNameSingular': 'person',
|
':objectNameSingular': 'person',
|
||||||
':objectRecordId': peopleMock[0].id,
|
':objectRecordId': personRecord.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
parameters: {
|
parameters: {
|
||||||
@ -36,7 +38,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
graphql.query('FindOnePerson', () => {
|
graphql.query('FindOnePerson', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
person: peopleMock[0],
|
person: personRecord,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
113
packages/twenty-front/src/testing/cache/inMemoryTestingCacheInstance.ts
vendored
Normal file
113
packages/twenty-front/src/testing/cache/inMemoryTestingCacheInstance.ts
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
|
||||||
|
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
|
||||||
|
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
|
||||||
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
|
import { InMemoryCache, NormalizedCacheObject } from '@apollo/client';
|
||||||
|
import { expect } from '@storybook/jest';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
type ObjectMetadataItemAndRecordId = {
|
||||||
|
recordId: string;
|
||||||
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
|
};
|
||||||
|
type RecordsWithObjectMetadataItem = {
|
||||||
|
records: ObjectRecord[];
|
||||||
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
type GetMockCachedRecord = {
|
||||||
|
recordId: string;
|
||||||
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
|
matchObject?: Record<string, unknown>;
|
||||||
|
snapshotPropertyMatchers?: {
|
||||||
|
deletedAt?: any;
|
||||||
|
updatedAt?: any;
|
||||||
|
createdAt?: any;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
type InMemoryTestingCacheInstanceArgs = {
|
||||||
|
objectMetadataItems: ObjectMetadataItem[];
|
||||||
|
initialRecordsInCache?: RecordsWithObjectMetadataItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class InMemoryTestingCacheInstance {
|
||||||
|
private _cache: InMemoryCache;
|
||||||
|
private objectMetadataItems: ObjectMetadataItem[];
|
||||||
|
private initialStateExtract: NormalizedCacheObject;
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
objectMetadataItems,
|
||||||
|
initialRecordsInCache = [],
|
||||||
|
}: InMemoryTestingCacheInstanceArgs) {
|
||||||
|
this.objectMetadataItems = objectMetadataItems;
|
||||||
|
this._cache = new InMemoryCache();
|
||||||
|
|
||||||
|
this.populateRecordsInCache(initialRecordsInCache);
|
||||||
|
this.initialStateExtract = this._cache.extract();
|
||||||
|
}
|
||||||
|
|
||||||
|
public populateRecordsInCache = (
|
||||||
|
recordsWithObjectMetadataItem: RecordsWithObjectMetadataItem,
|
||||||
|
) => {
|
||||||
|
recordsWithObjectMetadataItem.forEach(({ objectMetadataItem, records }) =>
|
||||||
|
records.forEach((record) =>
|
||||||
|
updateRecordFromCache({
|
||||||
|
cache: this._cache,
|
||||||
|
objectMetadataItem,
|
||||||
|
objectMetadataItems: this.objectMetadataItems,
|
||||||
|
record,
|
||||||
|
recordGqlFields: computeDepthOneRecordGqlFieldsFromRecord({
|
||||||
|
objectMetadataItem,
|
||||||
|
record,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
public assertCachedRecordIsNull = ({
|
||||||
|
objectMetadataItem,
|
||||||
|
recordId,
|
||||||
|
}: ObjectMetadataItemAndRecordId) => {
|
||||||
|
const cachedRecord = getRecordFromCache({
|
||||||
|
cache: this._cache,
|
||||||
|
objectMetadataItem,
|
||||||
|
objectMetadataItems: this.objectMetadataItems,
|
||||||
|
recordId,
|
||||||
|
});
|
||||||
|
expect(cachedRecord).toBeNull();
|
||||||
|
};
|
||||||
|
|
||||||
|
public assertCachedRecordMatchSnapshot = ({
|
||||||
|
objectMetadataItem,
|
||||||
|
recordId,
|
||||||
|
matchObject,
|
||||||
|
snapshotPropertyMatchers,
|
||||||
|
}: GetMockCachedRecord) => {
|
||||||
|
const cachedRecord = getRecordFromCache({
|
||||||
|
cache: this._cache,
|
||||||
|
objectMetadataItem,
|
||||||
|
objectMetadataItems: this.objectMetadataItems,
|
||||||
|
recordId,
|
||||||
|
});
|
||||||
|
expect(cachedRecord).not.toBeNull();
|
||||||
|
|
||||||
|
if (cachedRecord === null) {
|
||||||
|
throw new Error('Should never occurs, cachedRecord is null');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefined(matchObject)) {
|
||||||
|
expect(cachedRecord).toMatchObject(matchObject);
|
||||||
|
}
|
||||||
|
expect(cachedRecord).toMatchSnapshot(snapshotPropertyMatchers ?? {});
|
||||||
|
};
|
||||||
|
|
||||||
|
public restoreCacheToInitialState = async () => {
|
||||||
|
return this._cache.restore(this.initialStateExtract);
|
||||||
|
};
|
||||||
|
|
||||||
|
public get cache() {
|
||||||
|
return this._cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,7 +6,7 @@ import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-s
|
|||||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { isUndefined } from '@sniptt/guards';
|
import { isUndefined } from '@sniptt/guards';
|
||||||
import { getCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
|
import { getMockCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
|
||||||
|
|
||||||
export const ContextStoreDecorator: Decorator = (Story, context) => {
|
export const ContextStoreDecorator: Decorator = (Story, context) => {
|
||||||
const { contextStore } = context.parameters;
|
const { contextStore } = context.parameters;
|
||||||
@ -24,7 +24,7 @@ export const ContextStoreDecorator: Decorator = (Story, context) => {
|
|||||||
|
|
||||||
const [isLoaded, setIsLoaded] = useState(false);
|
const [isLoaded, setIsLoaded] = useState(false);
|
||||||
|
|
||||||
const objectMetadataItem = getCompanyObjectMetadataItem();
|
const objectMetadataItem = getMockCompanyObjectMetadataItem();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrentObjectMetadataItem(objectMetadataItem);
|
setCurrentObjectMetadataItem(objectMetadataItem);
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
|||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
import { mockedTasks } from '~/testing/mock-data/tasks';
|
import { mockedTasks } from '~/testing/mock-data/tasks';
|
||||||
|
|
||||||
const RecordMockSetterEffect = ({
|
const RecordMockSetterEffect = ({
|
||||||
@ -71,7 +71,7 @@ export const getFieldDecorator =
|
|||||||
]
|
]
|
||||||
: companiesMock;
|
: companiesMock;
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const peopleMock = getPeopleRecordConnectionMock();
|
||||||
|
|
||||||
const people =
|
const people =
|
||||||
objectNameSingular === 'person' && isDefined(fieldValue)
|
objectNameSingular === 'person' && isDefined(fieldValue)
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { mockedClientConfig } from '~/testing/mock-data/config';
|
|||||||
import { mockedFavoritesData } from '~/testing/mock-data/favorite';
|
import { mockedFavoritesData } from '~/testing/mock-data/favorite';
|
||||||
import { mockedFavoriteFoldersData } from '~/testing/mock-data/favorite-folders';
|
import { mockedFavoriteFoldersData } from '~/testing/mock-data/favorite-folders';
|
||||||
import { mockedNotes } from '~/testing/mock-data/notes';
|
import { mockedNotes } from '~/testing/mock-data/notes';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||||
import { mockedRemoteTables } from '~/testing/mock-data/remote-tables';
|
import { mockedRemoteTables } from '~/testing/mock-data/remote-tables';
|
||||||
import { mockedUserData } from '~/testing/mock-data/users';
|
import { mockedUserData } from '~/testing/mock-data/users';
|
||||||
import { mockedViewsData } from '~/testing/mock-data/views';
|
import { mockedViewsData } from '~/testing/mock-data/views';
|
||||||
@ -33,7 +33,7 @@ import {
|
|||||||
import { mockedRemoteServers } from './mock-data/remote-servers';
|
import { mockedRemoteServers } from './mock-data/remote-servers';
|
||||||
import { mockedViewFieldsData } from './mock-data/view-fields';
|
import { mockedViewFieldsData } from './mock-data/view-fields';
|
||||||
|
|
||||||
const peopleMock = getPeopleMock();
|
const peopleMock = getPeopleRecordConnectionMock();
|
||||||
const companiesMock = getCompaniesMock();
|
const companiesMock = getCompaniesMock();
|
||||||
const duplicateCompanyMock = getCompanyDuplicateMock();
|
const duplicateCompanyMock = getCompanyDuplicateMock();
|
||||||
|
|
||||||
|
|||||||
@ -1,50 +1,7 @@
|
|||||||
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
export const getCompaniesMock = () => {
|
|
||||||
return companiesQueryResult.companies.edges.map((edge) => edge.node);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getCompanyObjectMetadataItem = () => {
|
|
||||||
const companyObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
|
||||||
(item) => item.nameSingular === 'company',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!companyObjectMetadataItem) {
|
|
||||||
throw new Error('Company object metadata item not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return companyObjectMetadataItem;
|
|
||||||
};
|
|
||||||
export const getCompanyDuplicateMock = () => {
|
|
||||||
return {
|
|
||||||
...companiesQueryResult.companies.edges[0].node,
|
|
||||||
id: '8b40856a-2ec9-4c03-8bc0-c032c89e1824',
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getEmptyCompanyMock = () => {
|
|
||||||
return {
|
|
||||||
id: '9231e6ee-4cc2-4c7b-8c55-dff16f4d968a',
|
|
||||||
name: '',
|
|
||||||
domainName: {
|
|
||||||
__typename: 'Links',
|
|
||||||
primaryLinkUrl: '',
|
|
||||||
primaryLinkLabel: '',
|
|
||||||
secondaryLinks: [],
|
|
||||||
},
|
|
||||||
address: {},
|
|
||||||
accountOwner: null,
|
|
||||||
createdAt: null,
|
|
||||||
updatedAt: null,
|
|
||||||
employees: null,
|
|
||||||
idealCustomerProfile: null,
|
|
||||||
linkedinLink: null,
|
|
||||||
xLink: null,
|
|
||||||
_activityCount: null,
|
|
||||||
__typename: 'Company',
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const companiesQueryResult = {
|
export const companiesQueryResult = {
|
||||||
companies: {
|
companies: {
|
||||||
__typename: 'CompanyConnection',
|
__typename: 'CompanyConnection',
|
||||||
@ -774,3 +731,75 @@ export const companiesQueryResult = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const allMockedCompanyRecords = companiesQueryResult.companies.edges.map(
|
||||||
|
(edge) => edge.node,
|
||||||
|
);
|
||||||
|
export const getCompaniesMock = () => {
|
||||||
|
return [...allMockedCompanyRecords];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMockCompanyObjectMetadataItem = () => {
|
||||||
|
const companyObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === 'company',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!companyObjectMetadataItem) {
|
||||||
|
throw new Error('Company object metadata item not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return companyObjectMetadataItem;
|
||||||
|
};
|
||||||
|
export const getCompanyDuplicateMock = () => {
|
||||||
|
return {
|
||||||
|
...companiesQueryResult.companies.edges[0].node,
|
||||||
|
id: '8b40856a-2ec9-4c03-8bc0-c032c89e1824',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMockCompanyRecord = (
|
||||||
|
overrides?: Partial<ObjectRecord>,
|
||||||
|
index = 0,
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
...allMockedCompanyRecords[index],
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const findMockCompanyRecord = ({
|
||||||
|
id: queriedCompanyId,
|
||||||
|
}: Pick<ObjectRecord, 'id'>) => {
|
||||||
|
const company = allMockedCompanyRecords.find(
|
||||||
|
({ id: currentCompanyId }) => currentCompanyId === queriedCompanyId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDefined(company)) {
|
||||||
|
throw new Error(`Could not find company with id, ${queriedCompanyId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return company;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getEmptyCompanyMock = () => {
|
||||||
|
return {
|
||||||
|
id: '9231e6ee-4cc2-4c7b-8c55-dff16f4d968a',
|
||||||
|
name: '',
|
||||||
|
domainName: {
|
||||||
|
__typename: 'Links',
|
||||||
|
primaryLinkUrl: '',
|
||||||
|
primaryLinkLabel: '',
|
||||||
|
secondaryLinks: [],
|
||||||
|
},
|
||||||
|
address: {},
|
||||||
|
accountOwner: null,
|
||||||
|
createdAt: null,
|
||||||
|
updatedAt: null,
|
||||||
|
employees: null,
|
||||||
|
idealCustomerProfile: null,
|
||||||
|
linkedinLink: null,
|
||||||
|
xLink: null,
|
||||||
|
_activityCount: null,
|
||||||
|
__typename: 'Company',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,73 +1,9 @@
|
|||||||
|
import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode';
|
||||||
import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection';
|
import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { FieldMetadataType } from 'twenty-shared';
|
import { FieldMetadataType } from 'twenty-shared';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
export const getPeopleMock = (): ObjectRecord[] => {
|
|
||||||
const peopleMock = peopleQueryResult.people.edges.map((edge) => edge.node);
|
|
||||||
|
|
||||||
return peopleMock;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPersonObjectMetadataItem = () => {
|
|
||||||
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
|
||||||
(item) => item.nameSingular === 'person',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!personObjectMetadataItem) {
|
|
||||||
throw new Error('Person object metadata item not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return personObjectMetadataItem;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPersonFieldMetadataItem = (
|
|
||||||
fieldMetadataType: FieldMetadataType,
|
|
||||||
objectMetadataItem = getPersonObjectMetadataItem(),
|
|
||||||
) => {
|
|
||||||
const result = objectMetadataItem.fields.find(
|
|
||||||
(field) => field.type === fieldMetadataType,
|
|
||||||
);
|
|
||||||
if (!result) {
|
|
||||||
throw new Error(
|
|
||||||
`Person fieldmetadata item type ${fieldMetadataType} not found`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPersonRecord = (
|
|
||||||
overrides?: Partial<ObjectRecord>,
|
|
||||||
index = 0,
|
|
||||||
) => {
|
|
||||||
const personRecords = getPeopleMock();
|
|
||||||
return {
|
|
||||||
...personRecords[index],
|
|
||||||
...overrides,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mockedEmptyPersonData = {
|
|
||||||
id: 'ce7f0a37-88d7-4cd8-8b41-6721c57195b5',
|
|
||||||
firstName: '',
|
|
||||||
lastName: '',
|
|
||||||
phone: null,
|
|
||||||
email: null,
|
|
||||||
city: null,
|
|
||||||
createdBy: null,
|
|
||||||
displayName: null,
|
|
||||||
avatarUrl: null,
|
|
||||||
createdAt: null,
|
|
||||||
jobTitle: null,
|
|
||||||
linkedinUrl: null,
|
|
||||||
xUrl: null,
|
|
||||||
_activityCount: null,
|
|
||||||
company: null,
|
|
||||||
deletedAt: null,
|
|
||||||
__typename: 'Person',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const peopleQueryResult = {
|
export const peopleQueryResult = {
|
||||||
people: {
|
people: {
|
||||||
__typename: 'PersonConnection',
|
__typename: 'PersonConnection',
|
||||||
@ -1762,3 +1698,71 @@ export const peopleQueryResult = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
} satisfies { people: RecordGqlConnection };
|
} satisfies { people: RecordGqlConnection };
|
||||||
|
|
||||||
|
export const allMockPersonRecords = peopleQueryResult.people.edges.map((edge) =>
|
||||||
|
getRecordFromRecordNode({ recordNode: edge.node }),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getPeopleRecordConnectionMock = () => {
|
||||||
|
const peopleMock = peopleQueryResult.people.edges.map((edge) => edge.node);
|
||||||
|
|
||||||
|
return peopleMock;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMockPersonObjectMetadataItem = () => {
|
||||||
|
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === 'person',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!personObjectMetadataItem) {
|
||||||
|
throw new Error('Person object metadata item not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return personObjectMetadataItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMockPersonFieldMetadataItem = (
|
||||||
|
fieldMetadataType: FieldMetadataType,
|
||||||
|
objectMetadataItem = getMockPersonObjectMetadataItem(),
|
||||||
|
) => {
|
||||||
|
const result = objectMetadataItem.fields.find(
|
||||||
|
(field) => field.type === fieldMetadataType,
|
||||||
|
);
|
||||||
|
if (!result) {
|
||||||
|
throw new Error(
|
||||||
|
`Person fieldmetadata item type ${fieldMetadataType} not found`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMockPersonRecord = (
|
||||||
|
overrides?: Partial<ObjectRecord>,
|
||||||
|
index = 0,
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
...allMockPersonRecords[index],
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mockedEmptyPersonData = {
|
||||||
|
id: 'ce7f0a37-88d7-4cd8-8b41-6721c57195b5',
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
phone: null,
|
||||||
|
email: null,
|
||||||
|
city: null,
|
||||||
|
createdBy: null,
|
||||||
|
displayName: null,
|
||||||
|
avatarUrl: null,
|
||||||
|
createdAt: null,
|
||||||
|
jobTitle: null,
|
||||||
|
linkedinUrl: null,
|
||||||
|
xUrl: null,
|
||||||
|
_activityCount: null,
|
||||||
|
company: null,
|
||||||
|
deletedAt: null,
|
||||||
|
__typename: 'Person',
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user