[DASHBOARDS] Allow dashboards to be restored (#17042)
This PR introduces a few changes: - Add three actions: see deleted dashboards, destroy dashboard and restore dashboard - Remove the soft delete and restore on all the page layout entities - Cascade the destruction of a dashboard to a page layout Video QA: https://github.com/user-attachments/assets/ab993b11-dd9c-4e88-880c-92691a521cc2
This commit is contained in:
+2
-44
@@ -6,19 +6,16 @@ import {
|
||||
} from 'test/integration/metadata/suites/dashboard/utils/dashboard-graphql.util';
|
||||
import { duplicateOneDashboard } from 'test/integration/metadata/suites/dashboard/utils/duplicate-one-dashboard.util';
|
||||
import { createOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/create-one-page-layout-tab.util';
|
||||
import { destroyOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/destroy-one-page-layout-tab.util';
|
||||
import { createOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/create-one-page-layout-widget.util';
|
||||
import { destroyOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/destroy-one-page-layout-widget.util';
|
||||
import { createOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/create-one-page-layout.util';
|
||||
import { destroyOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/destroy-one-page-layout.util';
|
||||
import { extractRecordIdsAndDatesAsExpectAny } from 'test/utils/extract-record-ids-and-dates-as-expect-any';
|
||||
import {
|
||||
type EachTestingContext,
|
||||
eachTestingContextFilter,
|
||||
} from 'twenty-shared/testing';
|
||||
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
|
||||
type TestContext = {
|
||||
id: string;
|
||||
@@ -57,10 +54,8 @@ const SUCCESSFUL_TEST_CASES: EachTestingContext<TestContext>[] = [
|
||||
describe('Dashboard duplication should succeed', () => {
|
||||
let testPageLayoutId: string;
|
||||
let testPageLayoutTabId: string;
|
||||
let testPageLayoutWidgetId: string;
|
||||
let testDashboardId: string;
|
||||
let duplicatedDashboardId: string;
|
||||
let duplicatedPageLayoutId: string;
|
||||
let currentTestContextId: string;
|
||||
|
||||
const cleanup = async () => {
|
||||
@@ -69,30 +64,6 @@ describe('Dashboard duplication should succeed', () => {
|
||||
duplicatedDashboardId = '';
|
||||
}
|
||||
|
||||
if (isNonEmptyString(duplicatedPageLayoutId)) {
|
||||
await destroyOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: duplicatedPageLayoutId },
|
||||
});
|
||||
duplicatedPageLayoutId = '';
|
||||
}
|
||||
|
||||
if (isNonEmptyString(testPageLayoutWidgetId)) {
|
||||
await destroyOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: testPageLayoutWidgetId },
|
||||
});
|
||||
testPageLayoutWidgetId = '';
|
||||
}
|
||||
|
||||
if (isNonEmptyString(testPageLayoutTabId)) {
|
||||
await destroyOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: testPageLayoutTabId },
|
||||
});
|
||||
testPageLayoutTabId = '';
|
||||
}
|
||||
|
||||
if (isNonEmptyString(testDashboardId)) {
|
||||
await destroyDashboardWithGraphQL(testDashboardId);
|
||||
testDashboardId = '';
|
||||
@@ -102,23 +73,13 @@ describe('Dashboard duplication should succeed', () => {
|
||||
await destroyDashboardWithGraphQL(currentTestContextId);
|
||||
currentTestContextId = '';
|
||||
}
|
||||
|
||||
if (isNonEmptyString(testPageLayoutId)) {
|
||||
await destroyOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: testPageLayoutId },
|
||||
});
|
||||
testPageLayoutId = '';
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
testPageLayoutId = '';
|
||||
testPageLayoutTabId = '';
|
||||
testPageLayoutWidgetId = '';
|
||||
testDashboardId = '';
|
||||
duplicatedDashboardId = '';
|
||||
duplicatedPageLayoutId = '';
|
||||
currentTestContextId = '';
|
||||
});
|
||||
|
||||
@@ -153,7 +114,7 @@ describe('Dashboard duplication should succeed', () => {
|
||||
testPageLayoutTabId = tabData.createPageLayoutTab.id;
|
||||
|
||||
if (withWidgets) {
|
||||
const { data: widgetData } = await createOnePageLayoutWidget({
|
||||
await createOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: {
|
||||
title: 'Test Widget',
|
||||
@@ -168,8 +129,6 @@ describe('Dashboard duplication should succeed', () => {
|
||||
configuration: TEST_IFRAME_CONFIG,
|
||||
},
|
||||
});
|
||||
|
||||
testPageLayoutWidgetId = widgetData.createPageLayoutWidget.id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +146,6 @@ describe('Dashboard duplication should succeed', () => {
|
||||
});
|
||||
|
||||
duplicatedDashboardId = data.duplicateDashboard.id;
|
||||
duplicatedPageLayoutId = data.duplicateDashboard.pageLayoutId ?? '';
|
||||
|
||||
expect(data.duplicateDashboard).toMatchSnapshot(
|
||||
extractRecordIdsAndDatesAsExpectAny({ ...data.duplicateDashboard }),
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import {
|
||||
createManyDashboardsWithGraphQL,
|
||||
createTestDashboardWithGraphQL,
|
||||
destroyDashboardWithGraphQL,
|
||||
destroyManyDashboardsWithGraphQL,
|
||||
} from 'test/integration/metadata/suites/dashboard/utils/dashboard-graphql.util';
|
||||
import { findPageLayoutTabs } from 'test/integration/metadata/suites/page-layout-tab/utils/find-page-layout-tabs.util';
|
||||
import { createOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/create-one-page-layout.util';
|
||||
import { destroyOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/destroy-one-page-layout.util';
|
||||
import { findOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/find-one-page-layout.util';
|
||||
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
|
||||
describe('Dashboard page layout auto-creation should succeed', () => {
|
||||
describe('createOne dashboard without pageLayoutId', () => {
|
||||
let createdDashboardId: string;
|
||||
|
||||
beforeEach(() => {
|
||||
createdDashboardId = '';
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (isNonEmptyString(createdDashboardId)) {
|
||||
await destroyDashboardWithGraphQL(createdDashboardId);
|
||||
}
|
||||
});
|
||||
|
||||
it('should auto-create page layout and tab for dashboard without pageLayoutId', async () => {
|
||||
const title = 'Test Dashboard';
|
||||
const dashboard = await createTestDashboardWithGraphQL({ title });
|
||||
|
||||
createdDashboardId = dashboard.id;
|
||||
|
||||
expect(dashboard.id).toBeDefined();
|
||||
expect(dashboard.title).toBe(title);
|
||||
expect(dashboard.pageLayoutId).toBeDefined();
|
||||
expect(isNonEmptyString(dashboard.pageLayoutId)).toBe(true);
|
||||
|
||||
const { data: pageLayoutData } = await findOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: dashboard.pageLayoutId! },
|
||||
});
|
||||
|
||||
expect(pageLayoutData.getPageLayout).toBeDefined();
|
||||
expect(pageLayoutData.getPageLayout?.type).toBe(PageLayoutType.DASHBOARD);
|
||||
|
||||
const { data: tabsData } = await findPageLayoutTabs({
|
||||
expectToFail: false,
|
||||
input: { pageLayoutId: dashboard.pageLayoutId! },
|
||||
});
|
||||
|
||||
expect(tabsData.getPageLayoutTabs).toBeDefined();
|
||||
expect(tabsData.getPageLayoutTabs.length).toBeGreaterThanOrEqual(1);
|
||||
expect(tabsData.getPageLayoutTabs[0].title).toBe('Tab 1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createMany dashboards without pageLayoutId', () => {
|
||||
let createdDashboardIds: string[] = [];
|
||||
|
||||
beforeEach(() => {
|
||||
createdDashboardIds = [];
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (createdDashboardIds.length > 0) {
|
||||
await destroyManyDashboardsWithGraphQL({
|
||||
id: { in: createdDashboardIds },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('should auto-create separate page layouts for each dashboard in createMany', async () => {
|
||||
const dashboardsData = [
|
||||
{ title: 'Dashboard 1' },
|
||||
{ title: 'Dashboard 2' },
|
||||
{ title: 'Dashboard 3' },
|
||||
];
|
||||
|
||||
const dashboards = await createManyDashboardsWithGraphQL(dashboardsData);
|
||||
|
||||
createdDashboardIds = dashboards.map((d) => d.id);
|
||||
|
||||
expect(dashboards.length).toBe(dashboardsData.length);
|
||||
|
||||
const pageLayoutIds = new Set(
|
||||
dashboards.map((d) => d.pageLayoutId).filter(isNonEmptyString),
|
||||
);
|
||||
|
||||
expect(pageLayoutIds.size).toBe(dashboardsData.length);
|
||||
|
||||
for (const dashboard of dashboards) {
|
||||
expect(dashboard.pageLayoutId).toBeDefined();
|
||||
expect(isNonEmptyString(dashboard.pageLayoutId)).toBe(true);
|
||||
|
||||
const { data: pageLayoutData } = await findOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: dashboard.pageLayoutId! },
|
||||
});
|
||||
|
||||
expect(pageLayoutData.getPageLayout).toBeDefined();
|
||||
expect(pageLayoutData.getPageLayout?.type).toBe(
|
||||
PageLayoutType.DASHBOARD,
|
||||
);
|
||||
|
||||
const { data: tabsData } = await findPageLayoutTabs({
|
||||
expectToFail: false,
|
||||
input: { pageLayoutId: dashboard.pageLayoutId! },
|
||||
});
|
||||
|
||||
expect(tabsData.getPageLayoutTabs).toBeDefined();
|
||||
expect(tabsData.getPageLayoutTabs.length).toBeGreaterThanOrEqual(1);
|
||||
}
|
||||
});
|
||||
|
||||
it('should use provided pageLayoutId for some dashboards and auto-create for others', async () => {
|
||||
const { data: pageLayoutData } = await createOnePageLayout({
|
||||
input: {
|
||||
name: 'Pre-existing page layout',
|
||||
type: PageLayoutType.DASHBOARD,
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const existingPageLayoutId = pageLayoutData.createPageLayout.id;
|
||||
|
||||
expect(existingPageLayoutId).toBeDefined();
|
||||
|
||||
const dashboardsData = [
|
||||
{
|
||||
title: 'Dashboard with provided layout',
|
||||
pageLayoutId: existingPageLayoutId,
|
||||
},
|
||||
{ title: 'Dashboard without layout 1' },
|
||||
{ title: 'Dashboard without layout 2' },
|
||||
];
|
||||
|
||||
const dashboards = await createManyDashboardsWithGraphQL(dashboardsData);
|
||||
|
||||
createdDashboardIds = dashboards.map((d) => d.id);
|
||||
|
||||
expect(dashboards.length).toBe(3);
|
||||
|
||||
const dashboardWithProvidedLayout = dashboards.find(
|
||||
(d) => d.title === 'Dashboard with provided layout',
|
||||
);
|
||||
const dashboardsWithAutoCreatedLayout = dashboards.filter(
|
||||
(d) => d.title !== 'Dashboard with provided layout',
|
||||
);
|
||||
|
||||
expect(dashboardWithProvidedLayout?.pageLayoutId).toBe(
|
||||
existingPageLayoutId,
|
||||
);
|
||||
|
||||
for (const dashboard of dashboardsWithAutoCreatedLayout) {
|
||||
expect(dashboard.pageLayoutId).toBeDefined();
|
||||
expect(isNonEmptyString(dashboard.pageLayoutId)).toBe(true);
|
||||
expect(dashboard.pageLayoutId).not.toBe(existingPageLayoutId);
|
||||
}
|
||||
|
||||
await destroyOnePageLayout({
|
||||
input: { id: existingPageLayoutId },
|
||||
expectToFail: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import {
|
||||
createManyDashboardsWithGraphQL,
|
||||
createTestDashboardWithGraphQL,
|
||||
destroyDashboardWithGraphQL,
|
||||
destroyManyDashboardsWithGraphQL,
|
||||
} from 'test/integration/metadata/suites/dashboard/utils/dashboard-graphql.util';
|
||||
import { destroyOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/destroy-one-page-layout.util';
|
||||
import { findOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/find-one-page-layout.util';
|
||||
|
||||
describe('Dashboard to Page Layout sync should succeed', () => {
|
||||
describe('destroyOne dashboard', () => {
|
||||
let pageLayoutId: string;
|
||||
|
||||
beforeEach(() => {
|
||||
pageLayoutId = '';
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (isNonEmptyString(pageLayoutId)) {
|
||||
await destroyOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
pageLayoutId = '';
|
||||
}
|
||||
});
|
||||
|
||||
it('should hard delete linked page layout when dashboard is destroyed', async () => {
|
||||
const dashboard = await createTestDashboardWithGraphQL({
|
||||
title: 'Dashboard for Destroy Test',
|
||||
});
|
||||
|
||||
pageLayoutId = dashboard.pageLayoutId ?? '';
|
||||
|
||||
expect(isNonEmptyString(pageLayoutId)).toBe(true);
|
||||
|
||||
const { data: beforeData } = await findOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
|
||||
expect(beforeData.getPageLayout).toBeDefined();
|
||||
|
||||
await destroyDashboardWithGraphQL(dashboard.id);
|
||||
|
||||
const { errors } = await findOnePageLayout({
|
||||
expectToFail: true,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
|
||||
expect(errors).toBeDefined();
|
||||
|
||||
pageLayoutId = '';
|
||||
});
|
||||
});
|
||||
|
||||
describe('destroyMany dashboards', () => {
|
||||
let pageLayoutIds: string[] = [];
|
||||
|
||||
beforeEach(() => {
|
||||
pageLayoutIds = [];
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
for (const pageLayoutId of pageLayoutIds) {
|
||||
if (isNonEmptyString(pageLayoutId)) {
|
||||
await destroyOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
}
|
||||
}
|
||||
pageLayoutIds = [];
|
||||
});
|
||||
|
||||
it('should hard delete all linked page layouts when multiple dashboards are destroyed', async () => {
|
||||
const dashboardsData = [
|
||||
{ title: 'Dashboard 1 for Destroy Many Test' },
|
||||
{ title: 'Dashboard 2 for Destroy Many Test' },
|
||||
];
|
||||
|
||||
const dashboards = await createManyDashboardsWithGraphQL(dashboardsData);
|
||||
|
||||
const dashboardIds = dashboards.map((d) => d.id);
|
||||
|
||||
pageLayoutIds = dashboards
|
||||
.map((d) => d.pageLayoutId)
|
||||
.filter(isNonEmptyString);
|
||||
|
||||
expect(pageLayoutIds.length).toBe(dashboardsData.length);
|
||||
|
||||
for (const pageLayoutId of pageLayoutIds) {
|
||||
const { data } = await findOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
|
||||
expect(data.getPageLayout).toBeDefined();
|
||||
}
|
||||
|
||||
await destroyManyDashboardsWithGraphQL({
|
||||
id: { in: dashboardIds },
|
||||
});
|
||||
|
||||
for (const pageLayoutId of pageLayoutIds) {
|
||||
const { errors } = await findOnePageLayout({
|
||||
expectToFail: true,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
|
||||
expect(errors).toBeDefined();
|
||||
}
|
||||
|
||||
pageLayoutIds = [];
|
||||
});
|
||||
});
|
||||
});
|
||||
-147
@@ -5,19 +5,13 @@ import {
|
||||
findDashboardWithGraphQL,
|
||||
} from 'test/integration/metadata/suites/dashboard/utils/dashboard-graphql.util';
|
||||
import { createOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/create-one-page-layout-tab.util';
|
||||
import { deleteOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/delete-one-page-layout-tab.util';
|
||||
import { destroyOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/destroy-one-page-layout-tab.util';
|
||||
import { restoreOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/restore-one-page-layout-tab.util';
|
||||
import { updateOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/update-one-page-layout-tab.util';
|
||||
import { createOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/create-one-page-layout-widget.util';
|
||||
import { deleteOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/delete-one-page-layout-widget.util';
|
||||
import { destroyOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/destroy-one-page-layout-widget.util';
|
||||
import { restoreOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/restore-one-page-layout-widget.util';
|
||||
import { updateOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/update-one-page-layout-widget.util';
|
||||
import { createOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/create-one-page-layout.util';
|
||||
import { deleteOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/delete-one-page-layout.util';
|
||||
import { destroyOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/destroy-one-page-layout.util';
|
||||
import { restoreOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/restore-one-page-layout.util';
|
||||
import { updateOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/update-one-page-layout.util';
|
||||
|
||||
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
@@ -83,22 +77,7 @@ const createTestContext = async (): Promise<TestContext> => {
|
||||
};
|
||||
|
||||
const cleanupTestContext = async (context: TestContext): Promise<void> => {
|
||||
await destroyOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: context.widgetId },
|
||||
});
|
||||
|
||||
await destroyOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: context.tabId },
|
||||
});
|
||||
|
||||
await destroyDashboardWithGraphQL(context.dashboardId);
|
||||
|
||||
await destroyOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: context.pageLayoutId },
|
||||
});
|
||||
};
|
||||
|
||||
const assertDashboardUpdatedAtIncreased = async (
|
||||
@@ -124,43 +103,6 @@ const assertDashboardUpdatedAtIncreased = async (
|
||||
expect(isIncreased).toBe(true);
|
||||
};
|
||||
|
||||
const assertDashboardSoftDeleted = async (
|
||||
dashboardId: string,
|
||||
operation: () => Promise<void>,
|
||||
): Promise<void> => {
|
||||
const dashboardBefore = await findDashboardWithGraphQL(dashboardId);
|
||||
|
||||
expect(dashboardBefore).not.toBeNull();
|
||||
|
||||
await operation();
|
||||
|
||||
const dashboardAfter = await findDashboardWithGraphQL(dashboardId);
|
||||
|
||||
expect(dashboardAfter).toBeNull();
|
||||
};
|
||||
|
||||
const assertDashboardRestored = async (
|
||||
dashboardId: string,
|
||||
operation: () => Promise<void>,
|
||||
): Promise<void> => {
|
||||
const dashboardBefore = await findDashboardWithGraphQL(dashboardId);
|
||||
|
||||
expect(dashboardBefore).toBeNull();
|
||||
|
||||
await operation();
|
||||
|
||||
const dashboardAfter = await findDashboardWithGraphQL(dashboardId);
|
||||
|
||||
expect(dashboardAfter).not.toBeNull();
|
||||
|
||||
const updatedAtAfter = new Date(dashboardAfter!.updatedAt);
|
||||
|
||||
const now = new Date();
|
||||
const timeDiff = now.getTime() - updatedAtAfter.getTime();
|
||||
|
||||
expect(timeDiff).toBeLessThan(5000);
|
||||
};
|
||||
|
||||
describe('Dashboard updatedAt should sync when linked page layout entities change', () => {
|
||||
describe('Widget operations', () => {
|
||||
let context: TestContext;
|
||||
@@ -212,29 +154,6 @@ describe('Dashboard updatedAt should sync when linked page layout entities chang
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should update dashboard updatedAt when widget is soft deleted', async () => {
|
||||
await assertDashboardUpdatedAtIncreased(context.dashboardId, async () => {
|
||||
await deleteOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: context.widgetId },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should update dashboard updatedAt when widget is restored', async () => {
|
||||
await deleteOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: context.widgetId },
|
||||
});
|
||||
|
||||
await assertDashboardUpdatedAtIncreased(context.dashboardId, async () => {
|
||||
await restoreOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: context.widgetId },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tab operations', () => {
|
||||
@@ -278,49 +197,6 @@ describe('Dashboard updatedAt should sync when linked page layout entities chang
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should update dashboard updatedAt when tab is soft deleted', async () => {
|
||||
const { data: tabData } = await createOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: {
|
||||
title: 'Tab to Delete',
|
||||
pageLayoutId: context.pageLayoutId,
|
||||
},
|
||||
});
|
||||
|
||||
additionalTabId = tabData.createPageLayoutTab.id;
|
||||
|
||||
await assertDashboardUpdatedAtIncreased(context.dashboardId, async () => {
|
||||
await deleteOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: additionalTabId! },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should update dashboard updatedAt when tab is restored', async () => {
|
||||
const { data: tabData } = await createOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: {
|
||||
title: 'Tab to Restore',
|
||||
pageLayoutId: context.pageLayoutId,
|
||||
},
|
||||
});
|
||||
|
||||
additionalTabId = tabData.createPageLayoutTab.id;
|
||||
|
||||
await deleteOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: additionalTabId },
|
||||
});
|
||||
|
||||
await assertDashboardUpdatedAtIncreased(context.dashboardId, async () => {
|
||||
await restoreOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: additionalTabId! },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Page layout operations', () => {
|
||||
@@ -345,29 +221,6 @@ describe('Dashboard updatedAt should sync when linked page layout entities chang
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should update dashboard updatedAt when page layout is soft deleted', async () => {
|
||||
await assertDashboardSoftDeleted(context.dashboardId, async () => {
|
||||
await deleteOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: context.pageLayoutId },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should update dashboard updatedAt when page layout is restored', async () => {
|
||||
await deleteOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: context.pageLayoutId },
|
||||
});
|
||||
|
||||
await assertDashboardRestored(context.dashboardId, async () => {
|
||||
await restoreOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: context.pageLayoutId },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Non-dashboard page layout operations should not trigger sync', () => {
|
||||
+266
-3
@@ -10,10 +10,34 @@ interface CreateDashboardResponse extends Record<string, unknown> {
|
||||
createDashboard: DashboardWorkspaceEntity;
|
||||
}
|
||||
|
||||
interface CreateManyDashboardsResponse extends Record<string, unknown> {
|
||||
createDashboards: DashboardWorkspaceEntity[];
|
||||
}
|
||||
|
||||
interface FindDashboardResponse extends Record<string, unknown> {
|
||||
dashboard: DashboardWorkspaceEntity | null;
|
||||
}
|
||||
|
||||
interface DeleteDashboardResponse extends Record<string, unknown> {
|
||||
deleteDashboard: DashboardWorkspaceEntity;
|
||||
}
|
||||
|
||||
interface DeleteManyDashboardsResponse extends Record<string, unknown> {
|
||||
deleteDashboards: DashboardWorkspaceEntity[];
|
||||
}
|
||||
|
||||
interface RestoreDashboardResponse extends Record<string, unknown> {
|
||||
restoreDashboard: DashboardWorkspaceEntity;
|
||||
}
|
||||
|
||||
interface RestoreManyDashboardsResponse extends Record<string, unknown> {
|
||||
restoreDashboards: DashboardWorkspaceEntity[];
|
||||
}
|
||||
|
||||
interface DestroyManyDashboardsResponse extends Record<string, unknown> {
|
||||
destroyDashboards: DashboardWorkspaceEntity[];
|
||||
}
|
||||
|
||||
export const createTestDashboardWithGraphQL = async (data: {
|
||||
id?: string;
|
||||
title: string;
|
||||
@@ -87,20 +111,259 @@ export const destroyDashboardWithGraphQL = async (
|
||||
): Promise<void> => {
|
||||
const operation = {
|
||||
query: gql`
|
||||
mutation DestroyDashboard($filter: DashboardFilterInput!) {
|
||||
destroyDashboard(filter: $filter) {
|
||||
mutation DestroyDashboard($dashboardId: UUID!) {
|
||||
destroyDashboard(id: $dashboardId) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
filter: { id: { eq: dashboardId } },
|
||||
dashboardId,
|
||||
},
|
||||
};
|
||||
|
||||
await makeGraphqlAPIRequest(operation);
|
||||
};
|
||||
|
||||
export const createManyDashboardsWithGraphQL = async (
|
||||
data: Array<{
|
||||
id?: string;
|
||||
title: string;
|
||||
position?: number;
|
||||
pageLayoutId?: string;
|
||||
}>,
|
||||
): Promise<DashboardWorkspaceEntity[]> => {
|
||||
const operation = {
|
||||
query: gql`
|
||||
mutation CreateDashboards($data: [DashboardCreateInput!]!) {
|
||||
createDashboards(data: $data) {
|
||||
${DASHBOARD_GQL_FIELDS}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
data: data.map((item, index) => ({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
position: item.position ?? index,
|
||||
pageLayoutId: item.pageLayoutId,
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
const response = (await makeGraphqlAPIRequest(
|
||||
operation,
|
||||
)) as GraphQLResponse<CreateManyDashboardsResponse>;
|
||||
|
||||
if (response.body.errors) {
|
||||
throw new Error(
|
||||
`Failed to create dashboards: ${JSON.stringify(response.body.errors)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.body.data) {
|
||||
throw new Error('No data returned from createManyDashboardsWithGraphQL');
|
||||
}
|
||||
|
||||
return response.body.data.createDashboards;
|
||||
};
|
||||
|
||||
export const deleteDashboardWithGraphQL = async (
|
||||
dashboardId: string,
|
||||
): Promise<DashboardWorkspaceEntity> => {
|
||||
const operation = {
|
||||
query: gql`
|
||||
mutation DeleteDashboard($dashboardId: UUID!) {
|
||||
deleteDashboard(id: $dashboardId) {
|
||||
${DASHBOARD_GQL_FIELDS}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
dashboardId,
|
||||
},
|
||||
};
|
||||
|
||||
const response = (await makeGraphqlAPIRequest(
|
||||
operation,
|
||||
)) as GraphQLResponse<DeleteDashboardResponse>;
|
||||
|
||||
if (response.body.errors) {
|
||||
throw new Error(
|
||||
`Failed to delete dashboard: ${JSON.stringify(response.body.errors)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.body.data) {
|
||||
throw new Error('No data returned from deleteDashboardWithGraphQL');
|
||||
}
|
||||
|
||||
return response.body.data.deleteDashboard;
|
||||
};
|
||||
|
||||
export const deleteManyDashboardsWithGraphQL = async (filter: {
|
||||
id: { in: string[] };
|
||||
}): Promise<DashboardWorkspaceEntity[]> => {
|
||||
const operation = {
|
||||
query: gql`
|
||||
mutation DeleteDashboards($filter: DashboardFilterInput!) {
|
||||
deleteDashboards(filter: $filter) {
|
||||
${DASHBOARD_GQL_FIELDS}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
filter,
|
||||
},
|
||||
};
|
||||
|
||||
const response = (await makeGraphqlAPIRequest(
|
||||
operation,
|
||||
)) as GraphQLResponse<DeleteManyDashboardsResponse>;
|
||||
|
||||
if (response.body.errors) {
|
||||
throw new Error(
|
||||
`Failed to delete dashboards: ${JSON.stringify(response.body.errors)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.body.data) {
|
||||
throw new Error('No data returned from deleteManyDashboardsWithGraphQL');
|
||||
}
|
||||
|
||||
return response.body.data.deleteDashboards;
|
||||
};
|
||||
|
||||
export const restoreDashboardWithGraphQL = async (
|
||||
dashboardId: string,
|
||||
): Promise<DashboardWorkspaceEntity> => {
|
||||
const operation = {
|
||||
query: gql`
|
||||
mutation RestoreDashboard($dashboardId: UUID!) {
|
||||
restoreDashboard(id: $dashboardId) {
|
||||
${DASHBOARD_GQL_FIELDS}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
dashboardId,
|
||||
},
|
||||
};
|
||||
|
||||
const response = (await makeGraphqlAPIRequest(
|
||||
operation,
|
||||
)) as GraphQLResponse<RestoreDashboardResponse>;
|
||||
|
||||
if (response.body.errors) {
|
||||
throw new Error(
|
||||
`Failed to restore dashboard: ${JSON.stringify(response.body.errors)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.body.data) {
|
||||
throw new Error('No data returned from restoreDashboardWithGraphQL');
|
||||
}
|
||||
|
||||
return response.body.data.restoreDashboard;
|
||||
};
|
||||
|
||||
export const restoreManyDashboardsWithGraphQL = async (filter: {
|
||||
id: { in: string[] };
|
||||
}): Promise<DashboardWorkspaceEntity[]> => {
|
||||
const operation = {
|
||||
query: gql`
|
||||
mutation RestoreDashboards($filter: DashboardFilterInput!) {
|
||||
restoreDashboards(filter: $filter) {
|
||||
${DASHBOARD_GQL_FIELDS}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
filter,
|
||||
},
|
||||
};
|
||||
|
||||
const response = (await makeGraphqlAPIRequest(
|
||||
operation,
|
||||
)) as GraphQLResponse<RestoreManyDashboardsResponse>;
|
||||
|
||||
if (response.body.errors) {
|
||||
throw new Error(
|
||||
`Failed to restore dashboards: ${JSON.stringify(response.body.errors)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.body.data) {
|
||||
throw new Error('No data returned from restoreManyDashboardsWithGraphQL');
|
||||
}
|
||||
|
||||
return response.body.data.restoreDashboards;
|
||||
};
|
||||
|
||||
export const destroyManyDashboardsWithGraphQL = async (filter: {
|
||||
id: { in: string[] };
|
||||
}): Promise<DashboardWorkspaceEntity[]> => {
|
||||
const operation = {
|
||||
query: gql`
|
||||
mutation DestroyDashboards($filter: DashboardFilterInput!) {
|
||||
destroyDashboards(filter: $filter) {
|
||||
${DASHBOARD_GQL_FIELDS}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
filter,
|
||||
},
|
||||
};
|
||||
|
||||
const response = (await makeGraphqlAPIRequest(
|
||||
operation,
|
||||
)) as GraphQLResponse<DestroyManyDashboardsResponse>;
|
||||
|
||||
if (response.body.errors) {
|
||||
throw new Error(
|
||||
`Failed to destroy dashboards: ${JSON.stringify(response.body.errors)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.body.data) {
|
||||
throw new Error('No data returned from destroyManyDashboardsWithGraphQL');
|
||||
}
|
||||
|
||||
return response.body.data.destroyDashboards;
|
||||
};
|
||||
|
||||
export const findDeletedDashboardWithGraphQL = async (
|
||||
dashboardId: string,
|
||||
): Promise<DashboardWorkspaceEntity | null> => {
|
||||
const operation = {
|
||||
query: gql`
|
||||
query FindDeletedDashboard($filter: DashboardFilterInput!) {
|
||||
dashboard(filter: $filter) {
|
||||
${DASHBOARD_GQL_FIELDS}
|
||||
deletedAt
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
filter: {
|
||||
id: { eq: dashboardId },
|
||||
deletedAt: { is: 'NOT_NULL' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const response = (await makeGraphqlAPIRequest(
|
||||
operation,
|
||||
)) as GraphQLResponse<FindDashboardResponse>;
|
||||
|
||||
if (response.body.errors) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.body.data?.dashboard ?? null;
|
||||
};
|
||||
|
||||
const TEST_SCHEMA_NAME = 'workspace_1wgvd1injqtife6y4rvfbu3h5';
|
||||
|
||||
export const cleanupDashboardRecords = async (): Promise<void> => {
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Page layout tab deletion should fail when deleting a non-existent page layout tab 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "NOT_FOUND",
|
||||
"userFriendlyMessage": "An error occurred.",
|
||||
},
|
||||
"message": "Page layout tab to delete not found",
|
||||
"name": "NotFoundError",
|
||||
}
|
||||
`;
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Page layout tab deletion should succeed should soft delete and restore a page layout tab 1`] = `
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"id": Any<String>,
|
||||
"pageLayoutId": Any<String>,
|
||||
"position": 0,
|
||||
"title": "Tab To Delete",
|
||||
"updatedAt": Any<String>,
|
||||
}
|
||||
`;
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { expectOneNotInternalServerErrorSnapshot } from 'test/integration/graphql/utils/expect-one-not-internal-server-error-snapshot.util';
|
||||
import { deleteOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/delete-one-page-layout-tab.util';
|
||||
|
||||
describe('Page layout tab deletion should fail', () => {
|
||||
it('when deleting a non-existent page layout tab', async () => {
|
||||
const { errors } = await deleteOnePageLayoutTab({
|
||||
expectToFail: true,
|
||||
input: { id: faker.string.uuid() },
|
||||
});
|
||||
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
});
|
||||
});
|
||||
+15
-72
@@ -1,36 +1,7 @@
|
||||
import { createOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/create-one-page-layout-tab.util';
|
||||
import { deleteOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/delete-one-page-layout-tab.util';
|
||||
import { destroyOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/destroy-one-page-layout-tab.util';
|
||||
import { restoreOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/restore-one-page-layout-tab.util';
|
||||
import { createOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/create-one-page-layout.util';
|
||||
import { destroyOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/destroy-one-page-layout.util';
|
||||
import { extractRecordIdsAndDatesAsExpectAny } from 'test/utils/extract-record-ids-and-dates-as-expect-any';
|
||||
import {
|
||||
type EachTestingContext,
|
||||
eachTestingContextFilter,
|
||||
} from 'twenty-shared/testing';
|
||||
|
||||
type TestContext = {
|
||||
title: string;
|
||||
operation: 'soft-delete-restore' | 'hard-delete';
|
||||
};
|
||||
|
||||
const SUCCESSFUL_TEST_CASES: EachTestingContext<TestContext>[] = [
|
||||
{
|
||||
title: 'soft delete and restore a page layout tab',
|
||||
context: {
|
||||
title: 'Tab To Delete',
|
||||
operation: 'soft-delete-restore',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'hard delete a page layout tab',
|
||||
context: {
|
||||
title: 'Tab To Destroy',
|
||||
operation: 'hard-delete',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe('Page layout tab deletion should succeed', () => {
|
||||
let testPageLayoutId: string;
|
||||
@@ -51,50 +22,22 @@ describe('Page layout tab deletion should succeed', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each(eachTestingContextFilter(SUCCESSFUL_TEST_CASES))(
|
||||
'should $title',
|
||||
async ({ context: { title, operation } }) => {
|
||||
const { data: createData } = await createOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: {
|
||||
title,
|
||||
pageLayoutId: testPageLayoutId,
|
||||
},
|
||||
});
|
||||
it('should hard delete a page layout tab', async () => {
|
||||
const { data: createData } = await createOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: {
|
||||
title: 'Tab To Destroy',
|
||||
pageLayoutId: testPageLayoutId,
|
||||
},
|
||||
});
|
||||
|
||||
const tabId = createData.createPageLayoutTab.id;
|
||||
const tabId = createData.createPageLayoutTab.id;
|
||||
|
||||
if (operation === 'soft-delete-restore') {
|
||||
const { data: deleteData } = await deleteOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: tabId },
|
||||
});
|
||||
const { data: destroyData } = await destroyOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: tabId },
|
||||
});
|
||||
|
||||
expect(deleteData.deletePageLayoutTab).toBe(true);
|
||||
|
||||
const { data: restoreData } = await restoreOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: tabId },
|
||||
});
|
||||
|
||||
expect(restoreData.restorePageLayoutTab).toMatchSnapshot(
|
||||
extractRecordIdsAndDatesAsExpectAny({
|
||||
...restoreData.restorePageLayoutTab,
|
||||
}),
|
||||
);
|
||||
|
||||
await destroyOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: tabId },
|
||||
});
|
||||
} else {
|
||||
const { data: destroyData } = await destroyOnePageLayoutTab({
|
||||
expectToFail: false,
|
||||
input: { id: tabId },
|
||||
});
|
||||
|
||||
expect(destroyData.destroyPageLayoutTab).toBe(true);
|
||||
}
|
||||
},
|
||||
);
|
||||
expect(destroyData.destroyPageLayoutTab).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
|
||||
export type DeleteOnePageLayoutTabFactoryInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const deleteOnePageLayoutTabQueryFactory = ({
|
||||
input,
|
||||
}: PerformMetadataQueryParams<DeleteOnePageLayoutTabFactoryInput>) => ({
|
||||
query: gql`
|
||||
mutation DeletePageLayoutTab($id: String!) {
|
||||
deletePageLayoutTab(id: $id)
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: input.id,
|
||||
},
|
||||
});
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
import {
|
||||
type DeleteOnePageLayoutTabFactoryInput,
|
||||
deleteOnePageLayoutTabQueryFactory,
|
||||
} from 'test/integration/metadata/suites/page-layout-tab/utils/delete-one-page-layout-tab-query-factory.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util';
|
||||
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
|
||||
|
||||
export const deleteOnePageLayoutTab = async ({
|
||||
input,
|
||||
expectToFail = false,
|
||||
token,
|
||||
}: PerformMetadataQueryParams<DeleteOnePageLayoutTabFactoryInput>): CommonResponseBody<{
|
||||
deletePageLayoutTab: boolean;
|
||||
}> => {
|
||||
const graphqlOperation = deleteOnePageLayoutTabQueryFactory({
|
||||
input,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation, token);
|
||||
|
||||
if (expectToFail === true) {
|
||||
warnIfNoErrorButExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout tab deletion should have failed but did not',
|
||||
});
|
||||
}
|
||||
|
||||
if (expectToFail === false) {
|
||||
warnIfErrorButNotExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout tab deletion has failed but should not',
|
||||
});
|
||||
}
|
||||
|
||||
return { data: response.body.data, errors: response.body.errors };
|
||||
};
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
|
||||
export type RestoreOnePageLayoutTabFactoryInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const DEFAULT_PAGE_LAYOUT_TAB_GQL_FIELDS = `
|
||||
id
|
||||
title
|
||||
position
|
||||
pageLayoutId
|
||||
createdAt
|
||||
updatedAt
|
||||
deletedAt
|
||||
`;
|
||||
|
||||
export const restoreOnePageLayoutTabQueryFactory = ({
|
||||
input,
|
||||
gqlFields = DEFAULT_PAGE_LAYOUT_TAB_GQL_FIELDS,
|
||||
}: PerformMetadataQueryParams<RestoreOnePageLayoutTabFactoryInput>) => ({
|
||||
query: gql`
|
||||
mutation RestorePageLayoutTab($id: String!) {
|
||||
restorePageLayoutTab(id: $id) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: input.id,
|
||||
},
|
||||
});
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
import {
|
||||
type RestoreOnePageLayoutTabFactoryInput,
|
||||
restoreOnePageLayoutTabQueryFactory,
|
||||
} from 'test/integration/metadata/suites/page-layout-tab/utils/restore-one-page-layout-tab-query-factory.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util';
|
||||
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
|
||||
|
||||
import { type PageLayoutTabDTO } from 'src/engine/metadata-modules/page-layout-tab/dtos/page-layout-tab.dto';
|
||||
|
||||
export const restoreOnePageLayoutTab = async ({
|
||||
input,
|
||||
gqlFields,
|
||||
expectToFail = false,
|
||||
token,
|
||||
}: PerformMetadataQueryParams<RestoreOnePageLayoutTabFactoryInput>): CommonResponseBody<{
|
||||
restorePageLayoutTab: PageLayoutTabDTO;
|
||||
}> => {
|
||||
const graphqlOperation = restoreOnePageLayoutTabQueryFactory({
|
||||
input,
|
||||
gqlFields,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation, token);
|
||||
|
||||
if (expectToFail === true) {
|
||||
warnIfNoErrorButExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout tab restore should have failed but did not',
|
||||
});
|
||||
}
|
||||
|
||||
if (expectToFail === false) {
|
||||
warnIfErrorButNotExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout tab restore has failed but should not',
|
||||
});
|
||||
}
|
||||
|
||||
return { data: response.body.data, errors: response.body.errors };
|
||||
};
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Page layout widget deletion should fail when deleting a non-existent page layout widget 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "NOT_FOUND",
|
||||
"userFriendlyMessage": "An error occurred.",
|
||||
},
|
||||
"message": "Page layout widget to delete not found",
|
||||
"name": "NotFoundError",
|
||||
}
|
||||
`;
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Page layout widget deletion should succeed should soft delete and restore a page layout widget 1`] = `
|
||||
{
|
||||
"configuration": {
|
||||
"configurationType": "IFRAME",
|
||||
"url": null,
|
||||
},
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": Any<String>,
|
||||
"gridPosition": {
|
||||
"column": 0,
|
||||
"columnSpan": 1,
|
||||
"row": 0,
|
||||
"rowSpan": 1,
|
||||
},
|
||||
"id": Any<String>,
|
||||
"objectMetadataId": null,
|
||||
"pageLayoutTabId": Any<String>,
|
||||
"title": "Widget To Delete",
|
||||
"type": "IFRAME",
|
||||
"updatedAt": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Page layout widget deletion should succeed should soft delete and restore a page layout widget 2`] = `
|
||||
{
|
||||
"configuration": {
|
||||
"configurationType": "IFRAME",
|
||||
"url": null,
|
||||
},
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"gridPosition": {
|
||||
"column": 0,
|
||||
"columnSpan": 1,
|
||||
"row": 0,
|
||||
"rowSpan": 1,
|
||||
},
|
||||
"id": Any<String>,
|
||||
"objectMetadataId": null,
|
||||
"pageLayoutTabId": Any<String>,
|
||||
"title": "Widget To Delete",
|
||||
"type": "IFRAME",
|
||||
"updatedAt": Any<String>,
|
||||
}
|
||||
`;
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { expectOneNotInternalServerErrorSnapshot } from 'test/integration/graphql/utils/expect-one-not-internal-server-error-snapshot.util';
|
||||
import { deleteOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/delete-one-page-layout-widget.util';
|
||||
|
||||
describe('Page layout widget deletion should fail', () => {
|
||||
it('when deleting a non-existent page layout widget', async () => {
|
||||
const { errors } = await deleteOnePageLayoutWidget({
|
||||
expectToFail: true,
|
||||
input: { id: faker.string.uuid() },
|
||||
});
|
||||
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
});
|
||||
});
|
||||
+24
-85
@@ -1,42 +1,13 @@
|
||||
import { createOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/create-one-page-layout-tab.util';
|
||||
import { destroyOnePageLayoutTab } from 'test/integration/metadata/suites/page-layout-tab/utils/destroy-one-page-layout-tab.util';
|
||||
import { createOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/create-one-page-layout-widget.util';
|
||||
import { deleteOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/delete-one-page-layout-widget.util';
|
||||
import { destroyOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/destroy-one-page-layout-widget.util';
|
||||
import { restoreOnePageLayoutWidget } from 'test/integration/metadata/suites/page-layout-widget/utils/restore-one-page-layout-widget.util';
|
||||
import { createOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/create-one-page-layout.util';
|
||||
import { destroyOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/destroy-one-page-layout.util';
|
||||
import { extractRecordIdsAndDatesAsExpectAny } from 'test/utils/extract-record-ids-and-dates-as-expect-any';
|
||||
import {
|
||||
type EachTestingContext,
|
||||
eachTestingContextFilter,
|
||||
} from 'twenty-shared/testing';
|
||||
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
|
||||
type TestContext = {
|
||||
title: string;
|
||||
operation: 'soft-delete-restore' | 'hard-delete';
|
||||
};
|
||||
|
||||
const SUCCESSFUL_TEST_CASES: EachTestingContext<TestContext>[] = [
|
||||
{
|
||||
title: 'soft delete and restore a page layout widget',
|
||||
context: {
|
||||
title: 'Widget To Delete',
|
||||
operation: 'soft-delete-restore',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'hard delete a page layout widget',
|
||||
context: {
|
||||
title: 'Widget To Destroy',
|
||||
operation: 'hard-delete',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe('Page layout widget deletion should succeed', () => {
|
||||
let testPageLayoutId: string;
|
||||
let testPageLayoutTabId: string;
|
||||
@@ -71,64 +42,32 @@ describe('Page layout widget deletion should succeed', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each(eachTestingContextFilter(SUCCESSFUL_TEST_CASES))(
|
||||
'should $title',
|
||||
async ({ context: { title, operation } }) => {
|
||||
const { data: createData } = await createOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: {
|
||||
title,
|
||||
pageLayoutTabId: testPageLayoutTabId,
|
||||
type: WidgetType.IFRAME,
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.IFRAME,
|
||||
},
|
||||
gridPosition: {
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 1,
|
||||
columnSpan: 1,
|
||||
},
|
||||
it('should hard delete a page layout widget', async () => {
|
||||
const { data: createData } = await createOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: {
|
||||
title: 'Widget To Destroy',
|
||||
pageLayoutTabId: testPageLayoutTabId,
|
||||
type: WidgetType.IFRAME,
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.IFRAME,
|
||||
},
|
||||
});
|
||||
gridPosition: {
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 1,
|
||||
columnSpan: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const widgetId = createData.createPageLayoutWidget.id;
|
||||
const widgetId = createData.createPageLayoutWidget.id;
|
||||
|
||||
if (operation === 'soft-delete-restore') {
|
||||
const { data: deleteData } = await deleteOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: widgetId },
|
||||
});
|
||||
const { data: destroyData } = await destroyOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: widgetId },
|
||||
});
|
||||
|
||||
expect(deleteData.deletePageLayoutWidget).toMatchSnapshot(
|
||||
extractRecordIdsAndDatesAsExpectAny({
|
||||
...deleteData.deletePageLayoutWidget,
|
||||
}),
|
||||
);
|
||||
|
||||
const { data: restoreData } = await restoreOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: widgetId },
|
||||
});
|
||||
|
||||
expect(restoreData.restorePageLayoutWidget).toMatchSnapshot(
|
||||
extractRecordIdsAndDatesAsExpectAny({
|
||||
...restoreData.restorePageLayoutWidget,
|
||||
}),
|
||||
);
|
||||
|
||||
await destroyOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: widgetId },
|
||||
});
|
||||
} else {
|
||||
const { data: destroyData } = await destroyOnePageLayoutWidget({
|
||||
expectToFail: false,
|
||||
input: { id: widgetId },
|
||||
});
|
||||
|
||||
expect(destroyData.destroyPageLayoutWidget).toBe(true);
|
||||
}
|
||||
},
|
||||
);
|
||||
expect(destroyData.destroyPageLayoutWidget).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { WIDGET_CONFIGURATION_GQL_FIELDS } from 'test/integration/metadata/suites/page-layout-widget/constants/widget-configuration-gql-fields.constant';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
|
||||
export type DeleteOnePageLayoutWidgetFactoryInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const DEFAULT_PAGE_LAYOUT_WIDGET_GQL_FIELDS = `
|
||||
id
|
||||
title
|
||||
type
|
||||
pageLayoutTabId
|
||||
objectMetadataId
|
||||
gridPosition {
|
||||
row
|
||||
column
|
||||
rowSpan
|
||||
columnSpan
|
||||
}
|
||||
configuration {
|
||||
${WIDGET_CONFIGURATION_GQL_FIELDS}
|
||||
}
|
||||
createdAt
|
||||
updatedAt
|
||||
deletedAt
|
||||
`;
|
||||
|
||||
export const deleteOnePageLayoutWidgetQueryFactory = ({
|
||||
input,
|
||||
gqlFields = DEFAULT_PAGE_LAYOUT_WIDGET_GQL_FIELDS,
|
||||
}: PerformMetadataQueryParams<DeleteOnePageLayoutWidgetFactoryInput>) => ({
|
||||
query: gql`
|
||||
mutation DeletePageLayoutWidget($id: String!) {
|
||||
deletePageLayoutWidget(id: $id) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: input.id,
|
||||
},
|
||||
});
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
import {
|
||||
type DeleteOnePageLayoutWidgetFactoryInput,
|
||||
deleteOnePageLayoutWidgetQueryFactory,
|
||||
} from 'test/integration/metadata/suites/page-layout-widget/utils/delete-one-page-layout-widget-query-factory.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util';
|
||||
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
|
||||
|
||||
import { type PageLayoutWidgetDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/page-layout-widget.dto';
|
||||
|
||||
export const deleteOnePageLayoutWidget = async ({
|
||||
input,
|
||||
gqlFields,
|
||||
expectToFail = false,
|
||||
token,
|
||||
}: PerformMetadataQueryParams<DeleteOnePageLayoutWidgetFactoryInput>): CommonResponseBody<{
|
||||
deletePageLayoutWidget: PageLayoutWidgetDTO;
|
||||
}> => {
|
||||
const graphqlOperation = deleteOnePageLayoutWidgetQueryFactory({
|
||||
input,
|
||||
gqlFields,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation, token);
|
||||
|
||||
if (expectToFail === true) {
|
||||
warnIfNoErrorButExpectedToFail({
|
||||
response,
|
||||
errorMessage:
|
||||
'Page layout widget deletion should have failed but did not',
|
||||
});
|
||||
}
|
||||
|
||||
if (expectToFail === false) {
|
||||
warnIfErrorButNotExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout widget deletion has failed but should not',
|
||||
});
|
||||
}
|
||||
|
||||
return { data: response.body.data, errors: response.body.errors };
|
||||
};
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { WIDGET_CONFIGURATION_GQL_FIELDS } from 'test/integration/metadata/suites/page-layout-widget/constants/widget-configuration-gql-fields.constant';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
|
||||
export type RestoreOnePageLayoutWidgetFactoryInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const DEFAULT_PAGE_LAYOUT_WIDGET_GQL_FIELDS = `
|
||||
id
|
||||
title
|
||||
type
|
||||
pageLayoutTabId
|
||||
objectMetadataId
|
||||
gridPosition {
|
||||
row
|
||||
column
|
||||
rowSpan
|
||||
columnSpan
|
||||
}
|
||||
configuration {
|
||||
${WIDGET_CONFIGURATION_GQL_FIELDS}
|
||||
}
|
||||
createdAt
|
||||
updatedAt
|
||||
deletedAt
|
||||
`;
|
||||
|
||||
export const restoreOnePageLayoutWidgetQueryFactory = ({
|
||||
input,
|
||||
gqlFields = DEFAULT_PAGE_LAYOUT_WIDGET_GQL_FIELDS,
|
||||
}: PerformMetadataQueryParams<RestoreOnePageLayoutWidgetFactoryInput>) => ({
|
||||
query: gql`
|
||||
mutation RestorePageLayoutWidget($id: String!) {
|
||||
restorePageLayoutWidget(id: $id) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: input.id,
|
||||
},
|
||||
});
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
import {
|
||||
type RestoreOnePageLayoutWidgetFactoryInput,
|
||||
restoreOnePageLayoutWidgetQueryFactory,
|
||||
} from 'test/integration/metadata/suites/page-layout-widget/utils/restore-one-page-layout-widget-query-factory.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util';
|
||||
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
|
||||
|
||||
import { type PageLayoutWidgetDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/page-layout-widget.dto';
|
||||
|
||||
export const restoreOnePageLayoutWidget = async ({
|
||||
input,
|
||||
gqlFields,
|
||||
expectToFail = false,
|
||||
token,
|
||||
}: PerformMetadataQueryParams<RestoreOnePageLayoutWidgetFactoryInput>): CommonResponseBody<{
|
||||
restorePageLayoutWidget: PageLayoutWidgetDTO;
|
||||
}> => {
|
||||
const graphqlOperation = restoreOnePageLayoutWidgetQueryFactory({
|
||||
input,
|
||||
gqlFields,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation, token);
|
||||
|
||||
if (expectToFail === true) {
|
||||
warnIfNoErrorButExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout widget restore should have failed but did not',
|
||||
});
|
||||
}
|
||||
|
||||
if (expectToFail === false) {
|
||||
warnIfErrorButNotExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout widget restore has failed but should not',
|
||||
});
|
||||
}
|
||||
|
||||
return { data: response.body.data, errors: response.body.errors };
|
||||
};
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Page layout deletion should fail when deleting a non-existent page layout 1`] = `
|
||||
exports[`Page layout deletion should fail when destroying a non-existent page layout 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "NOT_FOUND",
|
||||
"userFriendlyMessage": "An error occurred.",
|
||||
},
|
||||
"message": "Page layout to delete not found",
|
||||
"message": "Page layout to destroy not found",
|
||||
"name": "NotFoundError",
|
||||
}
|
||||
`;
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Page layout deletion should succeed should soft delete and restore a page layout 1`] = `
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": Any<String>,
|
||||
"id": Any<String>,
|
||||
"name": "Page Layout To Delete",
|
||||
"objectMetadataId": null,
|
||||
"type": "RECORD_PAGE",
|
||||
"updatedAt": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Page layout deletion should succeed should soft delete and restore a page layout 2`] = `
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"id": Any<String>,
|
||||
"name": "Page Layout To Delete",
|
||||
"objectMetadataId": null,
|
||||
"type": "RECORD_PAGE",
|
||||
"updatedAt": Any<String>,
|
||||
}
|
||||
`;
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { expectOneNotInternalServerErrorSnapshot } from 'test/integration/graphql/utils/expect-one-not-internal-server-error-snapshot.util';
|
||||
import { deleteOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/delete-one-page-layout.util';
|
||||
import { destroyOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/destroy-one-page-layout.util';
|
||||
|
||||
describe('Page layout deletion should fail', () => {
|
||||
it('when deleting a non-existent page layout', async () => {
|
||||
const { errors } = await deleteOnePageLayout({
|
||||
it('when destroying a non-existent page layout', async () => {
|
||||
const { errors } = await destroyOnePageLayout({
|
||||
expectToFail: true,
|
||||
input: { id: faker.string.uuid() },
|
||||
});
|
||||
|
||||
+12
-73
@@ -1,81 +1,20 @@
|
||||
import { createOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/create-one-page-layout.util';
|
||||
import { deleteOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/delete-one-page-layout.util';
|
||||
import { destroyOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/destroy-one-page-layout.util';
|
||||
import { restoreOnePageLayout } from 'test/integration/metadata/suites/page-layout/utils/restore-one-page-layout.util';
|
||||
import { extractRecordIdsAndDatesAsExpectAny } from 'test/utils/extract-record-ids-and-dates-as-expect-any';
|
||||
import {
|
||||
type EachTestingContext,
|
||||
eachTestingContextFilter,
|
||||
} from 'twenty-shared/testing';
|
||||
|
||||
type TestContext = {
|
||||
name: string;
|
||||
operation: 'soft-delete-restore' | 'hard-delete';
|
||||
};
|
||||
|
||||
const SUCCESSFUL_TEST_CASES: EachTestingContext<TestContext>[] = [
|
||||
{
|
||||
title: 'soft delete and restore a page layout',
|
||||
context: {
|
||||
name: 'Page Layout To Delete',
|
||||
operation: 'soft-delete-restore',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'hard delete a page layout',
|
||||
context: {
|
||||
name: 'Page Layout To Destroy',
|
||||
operation: 'hard-delete',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe('Page layout deletion should succeed', () => {
|
||||
it.each(eachTestingContextFilter(SUCCESSFUL_TEST_CASES))(
|
||||
'should $title',
|
||||
async ({ context: { name, operation } }) => {
|
||||
const { data: createData } = await createOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { name },
|
||||
});
|
||||
it('should hard delete a page layout', async () => {
|
||||
const { data: createData } = await createOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { name: 'Page Layout To Destroy' },
|
||||
});
|
||||
|
||||
const pageLayoutId = createData.createPageLayout.id;
|
||||
const pageLayoutId = createData.createPageLayout.id;
|
||||
|
||||
if (operation === 'soft-delete-restore') {
|
||||
const { data: deleteData } = await deleteOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
const { data: destroyData } = await destroyOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
|
||||
expect(deleteData.deletePageLayout).toMatchSnapshot(
|
||||
extractRecordIdsAndDatesAsExpectAny({
|
||||
...deleteData.deletePageLayout,
|
||||
}),
|
||||
);
|
||||
|
||||
const { data: restoreData } = await restoreOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
|
||||
expect(restoreData.restorePageLayout).toMatchSnapshot(
|
||||
extractRecordIdsAndDatesAsExpectAny({
|
||||
...restoreData.restorePageLayout,
|
||||
}),
|
||||
);
|
||||
|
||||
await destroyOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
} else {
|
||||
const { data: destroyData } = await destroyOnePageLayout({
|
||||
expectToFail: false,
|
||||
input: { id: pageLayoutId },
|
||||
});
|
||||
|
||||
expect(destroyData.destroyPageLayout).toBe(true);
|
||||
}
|
||||
},
|
||||
);
|
||||
expect(destroyData.destroyPageLayout).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
|
||||
export type DeleteOnePageLayoutFactoryInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const DEFAULT_PAGE_LAYOUT_GQL_FIELDS = `
|
||||
id
|
||||
name
|
||||
type
|
||||
objectMetadataId
|
||||
createdAt
|
||||
updatedAt
|
||||
deletedAt
|
||||
`;
|
||||
|
||||
export const deleteOnePageLayoutQueryFactory = ({
|
||||
input,
|
||||
gqlFields = DEFAULT_PAGE_LAYOUT_GQL_FIELDS,
|
||||
}: PerformMetadataQueryParams<DeleteOnePageLayoutFactoryInput>) => ({
|
||||
query: gql`
|
||||
mutation DeletePageLayout($id: String!) {
|
||||
deletePageLayout(id: $id) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: input.id,
|
||||
},
|
||||
});
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
import {
|
||||
type DeleteOnePageLayoutFactoryInput,
|
||||
deleteOnePageLayoutQueryFactory,
|
||||
} from 'test/integration/metadata/suites/page-layout/utils/delete-one-page-layout-query-factory.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util';
|
||||
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
|
||||
|
||||
import { type PageLayoutDTO } from 'src/engine/metadata-modules/page-layout/dtos/page-layout.dto';
|
||||
|
||||
export const deleteOnePageLayout = async ({
|
||||
input,
|
||||
gqlFields,
|
||||
expectToFail = false,
|
||||
token,
|
||||
}: PerformMetadataQueryParams<DeleteOnePageLayoutFactoryInput>): CommonResponseBody<{
|
||||
deletePageLayout: PageLayoutDTO;
|
||||
}> => {
|
||||
const graphqlOperation = deleteOnePageLayoutQueryFactory({
|
||||
input,
|
||||
gqlFields,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation, token);
|
||||
|
||||
if (expectToFail === true) {
|
||||
warnIfNoErrorButExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout deletion should have failed but did not',
|
||||
});
|
||||
}
|
||||
|
||||
if (expectToFail === false) {
|
||||
warnIfErrorButNotExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout deletion has failed but should not',
|
||||
});
|
||||
}
|
||||
|
||||
return { data: response.body.data, errors: response.body.errors };
|
||||
};
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
|
||||
export type RestoreOnePageLayoutFactoryInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const DEFAULT_PAGE_LAYOUT_GQL_FIELDS = `
|
||||
id
|
||||
name
|
||||
type
|
||||
objectMetadataId
|
||||
createdAt
|
||||
updatedAt
|
||||
deletedAt
|
||||
`;
|
||||
|
||||
export const restoreOnePageLayoutQueryFactory = ({
|
||||
input,
|
||||
gqlFields = DEFAULT_PAGE_LAYOUT_GQL_FIELDS,
|
||||
}: PerformMetadataQueryParams<RestoreOnePageLayoutFactoryInput>) => ({
|
||||
query: gql`
|
||||
mutation RestorePageLayout($id: String!) {
|
||||
restorePageLayout(id: $id) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: input.id,
|
||||
},
|
||||
});
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
import {
|
||||
type RestoreOnePageLayoutFactoryInput,
|
||||
restoreOnePageLayoutQueryFactory,
|
||||
} from 'test/integration/metadata/suites/page-layout/utils/restore-one-page-layout-query-factory.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type';
|
||||
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
|
||||
import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util';
|
||||
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
|
||||
|
||||
import { type PageLayoutDTO } from 'src/engine/metadata-modules/page-layout/dtos/page-layout.dto';
|
||||
|
||||
export const restoreOnePageLayout = async ({
|
||||
input,
|
||||
gqlFields,
|
||||
expectToFail = false,
|
||||
token,
|
||||
}: PerformMetadataQueryParams<RestoreOnePageLayoutFactoryInput>): CommonResponseBody<{
|
||||
restorePageLayout: PageLayoutDTO;
|
||||
}> => {
|
||||
const graphqlOperation = restoreOnePageLayoutQueryFactory({
|
||||
input,
|
||||
gqlFields,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation, token);
|
||||
|
||||
if (expectToFail === true) {
|
||||
warnIfNoErrorButExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout restore should have failed but did not',
|
||||
});
|
||||
}
|
||||
|
||||
if (expectToFail === false) {
|
||||
warnIfErrorButNotExpectedToFail({
|
||||
response,
|
||||
errorMessage: 'Page layout restore has failed but should not',
|
||||
});
|
||||
}
|
||||
|
||||
return { data: response.body.data, errors: response.body.errors };
|
||||
};
|
||||
Reference in New Issue
Block a user