[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:
@ -1,6 +1,6 @@
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { gql } from '@apollo/client';
|
||||
import { getPersonRecord } from '~/testing/mock-data/people';
|
||||
import { getMockPersonRecord } from '~/testing/mock-data/people';
|
||||
|
||||
export const query = gql`
|
||||
mutation DeleteManyPeople($filter: PersonFilterInput!) {
|
||||
@ -17,7 +17,7 @@ export const personIds = [
|
||||
];
|
||||
|
||||
export const personRecords = personIds.map<ObjectRecord>((personId, index) =>
|
||||
getPersonRecord({ id: personId, deletedAt: null }, index),
|
||||
getMockPersonRecord({ id: personId, deletedAt: null }, index),
|
||||
);
|
||||
|
||||
export const variables = {
|
||||
|
||||
@ -8,14 +8,4 @@ export const query = gql`
|
||||
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 { 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`
|
||||
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 { act } from 'react';
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
import { getPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
||||
import { getMockPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
||||
const getDefaultMocks = (
|
||||
overrides?: Partial<MockedResponse>,
|
||||
): MockedResponse[] => [
|
||||
@ -40,7 +40,7 @@ const mockRefetchAggregateQueries = jest.fn();
|
||||
(useRefetchAggregateQueries as jest.Mock).mockReturnValue({
|
||||
refetchAggregateQueries: mockRefetchAggregateQueries,
|
||||
});
|
||||
const objectMetadataItem = getPersonObjectMetadataItem();
|
||||
const objectMetadataItem = getMockPersonObjectMetadataItem();
|
||||
const objectMetadataItems = [objectMetadataItem];
|
||||
const expectedCachedRecordsWithDeletedAt = personRecords.map(
|
||||
(personRecord) => ({
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
|
||||
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 {
|
||||
query,
|
||||
responseData,
|
||||
variables,
|
||||
} from '@/object-record/hooks/__mocks__/useDeleteOneRecord';
|
||||
import { query } from '@/object-record/hooks/__mocks__/useDeleteOneRecord';
|
||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { InMemoryCache } from '@apollo/client';
|
||||
import { MockedResponse } from '@apollo/client/testing';
|
||||
import { expect } from '@storybook/jest';
|
||||
import { InMemoryTestingCacheInstance } from '~/testing/cache/inMemoryTestingCacheInstance';
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
import { getMockCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
|
||||
import {
|
||||
getPersonObjectMetadataItem,
|
||||
getPersonRecord,
|
||||
allMockCompanyRecordsWithRelation,
|
||||
findMockCompanyWithRelationRecord,
|
||||
} from '~/testing/mock-data/companiesWithRelations';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
import {
|
||||
allMockPersonRecords,
|
||||
getMockPersonObjectMetadataItem,
|
||||
getMockPersonRecord,
|
||||
} from '~/testing/mock-data/people';
|
||||
|
||||
jest.mock('@/object-record/hooks/useRefetchAggregateQueries');
|
||||
@ -27,64 +27,63 @@ const mockRefetchAggregateQueries = jest.fn();
|
||||
refetchAggregateQueries: mockRefetchAggregateQueries,
|
||||
});
|
||||
|
||||
// TODO Should test relation deletion cache hydratation
|
||||
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 = (
|
||||
overrides?: Partial<MockedResponse>,
|
||||
): MockedResponse[] => [
|
||||
{
|
||||
): MockedResponse[] => {
|
||||
const deleteOneQueryMock: MockedResponse<
|
||||
Record<string, any>,
|
||||
Record<'idToDelete', string>
|
||||
> = {
|
||||
request: {
|
||||
variables: { idToDelete: personRecord.id },
|
||||
query,
|
||||
variables,
|
||||
},
|
||||
result: jest.fn(() => ({
|
||||
result: jest.fn((variables) => ({
|
||||
data: {
|
||||
deletePerson: responseData,
|
||||
deletePerson: {
|
||||
__typename: 'Person',
|
||||
deletedAt: '2024-02-14T09:45:00Z',
|
||||
id: variables.idToDelete,
|
||||
},
|
||||
},
|
||||
})),
|
||||
...overrides,
|
||||
},
|
||||
];
|
||||
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);
|
||||
};
|
||||
return [deleteOneQueryMock];
|
||||
};
|
||||
const assertCachedRecordIsNull = () =>
|
||||
expect(
|
||||
getRecordFromCache({
|
||||
cache,
|
||||
objectMetadataItem,
|
||||
objectMetadataItems,
|
||||
recordId: personRecord.id,
|
||||
}),
|
||||
).toBeNull();
|
||||
const defaultMocks = getDefaultMocks();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
cache = new InMemoryCache();
|
||||
});
|
||||
|
||||
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 () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useDeleteOneRecord({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||
}),
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
@ -98,13 +97,22 @@ describe('useDeleteOneRecord', () => {
|
||||
const deleteOneResult = await result.current.deleteOneRecord(
|
||||
personRecord.id,
|
||||
);
|
||||
const expectedResult: ObjectRecord = {
|
||||
expect(deleteOneResult).toStrictEqual<ObjectRecord>({
|
||||
__typename: personRecord.__typename,
|
||||
deletedAt: expect.any(String),
|
||||
id: personRecord.id,
|
||||
};
|
||||
expect(deleteOneResult).toStrictEqual(expectedResult);
|
||||
assertCachedRecordMatch(expectedResult);
|
||||
});
|
||||
assertCachedRecordMatchSnapshot({
|
||||
recordId: personRecord.id,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
matchObject: {
|
||||
deletedAt: expect.any(String),
|
||||
},
|
||||
});
|
||||
assertCachedRecordIsNull({
|
||||
objectMetadataItem: companyObjectMetadataItem,
|
||||
recordId: personRecord.company.id,
|
||||
});
|
||||
});
|
||||
|
||||
expect(defaultMocks[0].result).toHaveBeenCalled();
|
||||
@ -115,10 +123,11 @@ describe('useDeleteOneRecord', () => {
|
||||
const apolloMocks: MockedResponse[] = getDefaultMocks({
|
||||
delay: Number.POSITIVE_INFINITY,
|
||||
});
|
||||
expect(personRecord).toHaveProperty('company');
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useDeleteOneRecord({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||
}),
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
@ -131,7 +140,14 @@ describe('useDeleteOneRecord', () => {
|
||||
await act(async () => {
|
||||
result.current.deleteOneRecord(personRecord.id);
|
||||
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(
|
||||
() =>
|
||||
useDeleteOneRecord({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||
}),
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
@ -161,32 +177,47 @@ describe('useDeleteOneRecord', () => {
|
||||
await result.current.deleteOneRecord(personRecord.id);
|
||||
fail('Should have thrown an error');
|
||||
} catch (e) {
|
||||
assertCachedRecordIsNull();
|
||||
assertCachedRecordIsNull({
|
||||
recordId: personRecord.id,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
});
|
||||
assertCachedRecordIsNull({
|
||||
recordId: relatedCompanyRecord.id,
|
||||
objectMetadataItem: companyObjectMetadataItem,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('B. Starting from filled cache', () => {
|
||||
const {
|
||||
assertCachedRecordMatchSnapshot,
|
||||
cache,
|
||||
restoreCacheToInitialState,
|
||||
} = new InMemoryTestingCacheInstance({
|
||||
objectMetadataItems,
|
||||
initialRecordsInCache: [
|
||||
{
|
||||
objectMetadataItem: companyObjectMetadataItem,
|
||||
records: allMockCompanyRecordsWithRelation,
|
||||
},
|
||||
{
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
records: allMockPersonRecords,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const recordGqlFields = computeDepthOneRecordGqlFieldsFromRecord({
|
||||
objectMetadataItem,
|
||||
record: personRecord,
|
||||
});
|
||||
updateRecordFromCache({
|
||||
cache,
|
||||
objectMetadataItem,
|
||||
objectMetadataItems,
|
||||
record: personRecord,
|
||||
recordGqlFields,
|
||||
});
|
||||
restoreCacheToInitialState();
|
||||
});
|
||||
|
||||
it('1. Should handle successfull record deletion', async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useDeleteOneRecord({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||
}),
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
@ -198,15 +229,23 @@ describe('useDeleteOneRecord', () => {
|
||||
|
||||
await act(async () => {
|
||||
const res = await result.current.deleteOneRecord(personRecord.id);
|
||||
expect(res).toBeDefined();
|
||||
expect(res.deletedAt).toBeDefined();
|
||||
expect(res).toHaveProperty('id', personRecord.id);
|
||||
|
||||
const personRecordWithDeletedAt = {
|
||||
...personRecord,
|
||||
expect(res).toMatchObject<ObjectRecord>({
|
||||
__typename: 'Person',
|
||||
id: personRecord.id,
|
||||
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();
|
||||
@ -221,7 +260,7 @@ describe('useDeleteOneRecord', () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useDeleteOneRecord({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||
}),
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
@ -234,11 +273,21 @@ describe('useDeleteOneRecord', () => {
|
||||
await act(async () => {
|
||||
result.current.deleteOneRecord(personRecord.id);
|
||||
await waitFor(() => {
|
||||
const personRecordWithDeletedAt = {
|
||||
...personRecord,
|
||||
deletedAt: expect.any(String),
|
||||
};
|
||||
assertCachedRecordMatch(personRecordWithDeletedAt);
|
||||
assertCachedRecordMatchSnapshot({
|
||||
recordId: personRecord.id,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
snapshotPropertyMatchers: {
|
||||
// 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(
|
||||
() =>
|
||||
useDeleteOneRecord({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
objectNameSingular: personObjectMetadataItem.nameSingular,
|
||||
}),
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
@ -268,11 +317,17 @@ describe('useDeleteOneRecord', () => {
|
||||
await result.current.deleteOneRecord(personRecord.id);
|
||||
fail('Should have thrown an error');
|
||||
} catch (e) {
|
||||
const personRecordWithDeletedAt = {
|
||||
...personRecord,
|
||||
deletedAt: null,
|
||||
};
|
||||
assertCachedRecordMatch(personRecordWithDeletedAt);
|
||||
assertCachedRecordMatchSnapshot({
|
||||
recordId: personRecord.id,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
matchObject: {
|
||||
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 gql from 'graphql-tag';
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
||||
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||
|
||||
const recordTableId = 'people';
|
||||
const objectNameSingular = 'person';
|
||||
const onColumnsChange = jest.fn();
|
||||
@ -422,7 +423,7 @@ const mocks: MockedResponse[] = [
|
||||
},
|
||||
result: jest.fn(() => ({
|
||||
data: {
|
||||
people: getPeopleMock(),
|
||||
people: getPeopleRecordConnectionMock(),
|
||||
},
|
||||
})),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user