Skip to content

Commit 0023f6c

Browse files
Merge pull request #273 from contentstack/VE-3709
Ve 3709
2 parents ae3705d + d2c2210 commit 0023f6c

57 files changed

Lines changed: 2390 additions & 1643 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package-lock.json

Lines changed: 445 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"author": "Contentstack",
4444
"license": "MIT",
4545
"devDependencies": {
46-
"@contentstack/advanced-post-message": "github:contentstack/adv-post-message#main",
46+
"@contentstack/advanced-post-message": "^0.0.2",
4747
"@eslint/js": "^9.10.0",
4848
"@testing-library/jest-dom": "^6.5.0",
4949
"@testing-library/preact": "^3.2.4",
@@ -54,6 +54,7 @@
5454
"@types/react": "^18.2.57",
5555
"@types/react-dom": "^18.2.19",
5656
"@types/uuid": "^8.3.1",
57+
"@vitest/coverage-v8": "^2.1.2",
5758
"@vitest/ui": "^2.1.2",
5859
"esbuild-plugin-file-path-extensions": "^2.1.0",
5960
"eslint": "^7.32.0",
@@ -85,6 +86,9 @@
8586
"preact": "^10.19.5",
8687
"uuid": "^8.3.2"
8788
},
89+
"optionalDependencies": {
90+
"@rollup/rollup-linux-x64-gnu": "4.9.5"
91+
},
8892
"lint-staged": {
8993
"src/**/*.{ts,css,md}": [
9094
"npm run prettier:fix",

src/__test__/utils.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import { EventManager } from "@contentstack/advanced-post-message";
2+
import { act, fireEvent, render, waitFor } from "@testing-library/preact";
3+
import { VisualBuilderPostMessageEvents } from "../visualBuilder/utils/types/postMessage.types";
4+
import { ComponentChild } from "preact";
5+
16
export function convertObjectToMinifiedString(
27
obj: { [key: string]: any } | string
38
): any {
@@ -30,3 +35,63 @@ export class DOMRect {
3035
export async function sleep(waitTimeInMs = 100): Promise<void> {
3136
return new Promise((resolve) => setTimeout(resolve, waitTimeInMs));
3237
}
38+
39+
export const waitForHoverOutline = async () => {
40+
await waitFor(() => {
41+
const hoverOutline = document.querySelector(
42+
"[data-testid='visual-builder__hover-outline']"
43+
);
44+
expect(hoverOutline).not.toBeNull();
45+
});
46+
}
47+
export const waitForBuilderSDKToBeInitialized = async (visualBuilderPostMessage: EventManager | undefined) => {
48+
await waitFor(() => {
49+
expect(visualBuilderPostMessage?.send).toBeCalledWith(
50+
VisualBuilderPostMessageEvents.INIT,
51+
expect.any(Object)
52+
);
53+
});
54+
}
55+
interface WaitForClickActionOptions {
56+
skipWaitForFieldType?: boolean;
57+
}
58+
export const triggerAndWaitForClickAction = async (visualBuilderPostMessage: EventManager | undefined, element: HTMLElement, {skipWaitForFieldType}: WaitForClickActionOptions = {}) => {
59+
await waitForBuilderSDKToBeInitialized(visualBuilderPostMessage);
60+
await act(async () => {
61+
await fireEvent.click(element);
62+
})
63+
if(!skipWaitForFieldType) {
64+
await waitFor(() => {
65+
expect(element).toHaveAttribute("data-cslp-field-type")
66+
})
67+
}
68+
}
69+
export const waitForToolbaxToBeVisible = async () => {
70+
await waitFor(() => {
71+
const toolbar = document.querySelector(
72+
".visual-builder__focused-toolbar__field-label-container"
73+
);
74+
expect(toolbar).not.toBeNull();
75+
});
76+
}
77+
const defaultRect = {
78+
left: 10,
79+
right: 20,
80+
top: 10,
81+
bottom: 20,
82+
width: 10,
83+
height: 5,
84+
}
85+
export const mockGetBoundingClientRect = (element: HTMLElement, rect = defaultRect) => {
86+
vi.spyOn(element, "getBoundingClientRect").mockImplementation(() => rect as DOMRect);
87+
}
88+
export const getElementBytestId = (testId: string) => {
89+
return document.querySelector(`[data-testid="${testId}"]`);
90+
}
91+
export const asyncRender: (componentChild: ComponentChild) => ReturnType<typeof render> = async (...args) => {
92+
let returnValue: ReturnType<typeof render>;
93+
await act(async () => {
94+
returnValue = render(...args);
95+
});
96+
return returnValue;
97+
}

src/preview/__test__/contentstack-live-preview-HOC.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ describe("Live Preview HOC init", () => {
109109

110110
await sleep();
111111
expect(livePreviewPostMessageSpy).toHaveBeenCalledTimes(1);
112-
expect(visualBuilderPostMessageSpy).toHaveBeenCalledTimes(1);
112+
expect(visualBuilderPostMessageSpy).toHaveBeenCalledWith('init', { isSSR: true, href: 'http://localhost:3000/' });
113+
expect(visualBuilderPostMessageSpy).toHaveBeenCalledWith('send-variant-and-locale');
114+
expect(visualBuilderPostMessageSpy).toHaveBeenCalledTimes(2);
113115
});
114116

115117
test("should return the existing live preview instance if it is already initialized", async () => {

src/visualBuilder/__test__/__snapshots__/index.test.ts.snap

Lines changed: 25 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,37 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`Visual builder > inline editing > should add overlay to DOM when clicked 1`] = `
4-
<body>
5-
<h1
6-
data-cslp="all_fields.blt58a50b4cebae75c5.en-us.modular_blocks.0.block.single_line"
7-
data-cslp-field-type="singleline"
8-
style="visibility: hidden;"
9-
>
10-
Hello World
11-
</h1>
12-
<div
13-
class="go263407482 visual-builder__container"
14-
data-testid="visual-builder__container"
15-
>
16-
<style>
17-
18-
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap");
19-
20-
[data-cslp] [contenteditable="true"] {
21-
outline: none;
22-
}
23-
24-
@keyframes visual-builder__spinner {
25-
0% {
26-
transform: rotate(0deg);
27-
}
28-
100% {
29-
transform: rotate(360deg);
30-
}
31-
}
32-
33-
34-
</style>
35-
<div
36-
class="go1688149084 visual-builder__cursor"
37-
data-testid="visual-builder__cursor"
38-
/>
39-
<div
40-
class="go842373233 visual-builder__overlay__wrapper"
41-
data-testid="visual-builder__overlay__wrapper"
42-
>
43-
<div
44-
class="visual-builder__overlay visual-builder__overlay--top go2262268276"
45-
data-testid="visual-builder__overlay--top"
46-
/>
47-
<div
48-
class="visual-builder__overlay visual-builder__overlay--left go2262268276"
49-
data-testid="visual-builder__overlay--left"
50-
/>
51-
<div
52-
class="visual-builder__overlay visual-builder__overlay--right go2262268276"
53-
data-testid="visual-builder__overlay--right"
54-
/>
55-
<div
56-
class="visual-builder__overlay visual-builder__overlay--bottom go2262268276"
57-
data-testid="visual-builder__overlay--bottom"
58-
/>
59-
<div
60-
class="visual-builder__overlay--outline go3391008271"
61-
data-testid="visual-builder__overlay--outline"
62-
/>
63-
</div>
64-
<div
65-
class="visual-builder__hover-outline visual-builder__hover-outline--unclickable go3177626044 go1719569523"
66-
data-testid="visual-builder__hover-outline"
67-
/>
68-
<div
69-
class="visual-builder__focused-toolbar go635291819"
70-
data-testid="visual-builder__focused-toolbar"
71-
/>
72-
</div>
73-
</body>
74-
`;
75-
763
exports[`Visual builder > on click, the sdk > inline elements must be contenteditable > file should render a replacer and remove when it is not 1`] = `
774
<h1
785
data-cslp="all_fields.blt58a50b4cebae75c5.en-us.file"
796
data-cslp-field-type="file"
807
/>
818
`;
829

83-
exports[`Visual builder > on click, the sdk > inline elements must be contenteditable > file should render a replacer and remove when it is not 2`] = `undefined`;
10+
exports[`Visual builder > on click, the sdk > inline elements must be contenteditable > file should render a replacer and remove when it is not 2`] = `
11+
<button
12+
class="visual-builder__replace-button visual-builder__button visual-builder__button--secondary go2828613387 go2545267607 go3805905658"
13+
data-testid="visual-builder-replace-file"
14+
data-tooltip="Replace"
15+
>
16+
<svg
17+
data-testid="visual-builder__replace-asset-icon"
18+
fill="none"
19+
height="16"
20+
viewBox="0 0 16 16"
21+
width="16"
22+
xmlns="http://www.w3.org/2000/svg"
23+
>
24+
<path
25+
d="M13.8903 3.99632L11.5039 1.60984C11.3574 1.46339 11.12 1.46339 10.9735 1.60984C10.8271 1.75628 10.8271 1.99372 10.9735 2.14017L12.7198 3.88649H2.87506C2.39181 3.88649 2.00006 4.27824 2.00006 4.76149V6.13114C2.00006 6.33825 2.16795 6.50614 2.37506 6.50614C2.58217 6.50614 2.75006 6.33825 2.75006 6.13114V4.76149C2.75006 4.69245 2.80603 4.63649 2.87506 4.63649H12.7198L10.9735 6.38281C10.8271 6.52925 10.8271 6.76669 10.9735 6.91314C11.12 7.05958 11.3574 7.05958 11.5039 6.91314L13.8903 4.52665C14.0368 4.3802 14.0368 4.14277 13.8903 3.99632Z"
26+
fill="#475161"
27+
/>
28+
<path
29+
d="M2.10983 12.0054L4.49632 14.3919C4.64277 14.5383 4.8802 14.5383 5.02665 14.3919C5.1731 14.2455 5.1731 14.008 5.02665 13.8616L3.28033 12.1152H13.1251C13.6084 12.1152 14.0001 11.7235 14.0001 11.2402V9.87059C14.0001 9.66348 13.8322 9.49559 13.6251 9.49559C13.418 9.49559 13.2501 9.66348 13.2501 9.87059V11.2402C13.2501 11.3093 13.1942 11.3652 13.1251 11.3652H3.28033L5.02665 9.61893C5.1731 9.47248 5.1731 9.23504 5.02665 9.0886C4.8802 8.94215 4.64277 8.94215 4.49632 9.0886L2.10983 11.4751C1.96339 11.6215 1.96339 11.859 2.10983 12.0054Z"
30+
fill="#475161"
31+
/>
32+
</svg>
33+
</button>
34+
`;
8435

8536
exports[`Visual builder > on click, the sdk > inline elements must be contenteditable > multi line should be contenteditable 1`] = `
8637
<h1

src/visualBuilder/__test__/click/fields/boolean.test.tsx

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { waitFor } from "@testing-library/preact";
1+
import { act, waitFor, fireEvent } from "@testing-library/preact";
22
import "@testing-library/jest-dom";
33
import { getFieldSchemaMap } from "../../../../__test__/data/fieldSchemaMap";
44
import Config from "../../../../configManager/configManager";
@@ -9,6 +9,7 @@ import visualBuilderPostMessage from "../../../utils/visualBuilderPostMessage";
99
import { vi } from "vitest";
1010
import { VisualBuilderPostMessageEvents } from "../../../utils/types/postMessage.types";
1111
import { VisualBuilder } from "../../../index";
12+
import { triggerAndWaitForClickAction } from "../../../../__test__/utils";
1213

1314
global.ResizeObserver = vi.fn().mockImplementation(() => ({
1415
observe: vi.fn(),
@@ -78,9 +79,7 @@ describe("When an element is clicked in visual builder mode", () => {
7879
"get"
7980
).mockReturnValue(100);
8081
vi.spyOn(document.body, "scrollHeight", "get").mockReturnValue(100);
81-
});
8282

83-
beforeEach(() => {
8483
Config.reset();
8584
Config.set("mode", 2);
8685
mouseClickEvent = new Event("click", {
@@ -89,20 +88,17 @@ describe("When an element is clicked in visual builder mode", () => {
8988
});
9089
});
9190

92-
afterEach(() => {
93-
vi.clearAllMocks();
94-
document.body.innerHTML = "";
95-
});
96-
9791
afterAll(() => {
9892
Config.reset();
93+
vi.clearAllMocks();
94+
document.body.innerHTML = "";
9995
});
10096

10197
describe("boolean field", () => {
10298
let booleanField: HTMLParagraphElement;
10399
let visualBuilder: VisualBuilder;
104100

105-
beforeEach(() => {
101+
beforeAll(async () => {
106102
booleanField = document.createElement("p");
107103
booleanField.setAttribute(
108104
"data-cslp",
@@ -111,33 +107,30 @@ describe("When an element is clicked in visual builder mode", () => {
111107
document.body.appendChild(booleanField);
112108

113109
visualBuilder = new VisualBuilder();
110+
await triggerAndWaitForClickAction(visualBuilderPostMessage, booleanField);
114111
});
115112

116-
afterEach(() => {
113+
afterAll(() => {
117114
visualBuilder.destroy();
118115
});
119116

120117
test("should have outline", () => {
121-
booleanField.dispatchEvent(mouseClickEvent);
122118
expect(booleanField.classList.contains("cslp-edit-mode"));
123119
});
124120

125121
test("should have an overlay", () => {
126-
booleanField.dispatchEvent(mouseClickEvent);
127122
const overlay = document.querySelector(".visual-builder__overlay");
128123
expect(overlay!.classList.contains("visible"));
129124
});
130125

131126
test.skip("should have a field path dropdown", () => {
132-
booleanField.dispatchEvent(mouseClickEvent);
133127
const toolbar = document.querySelector(
134128
".visual-builder__focused-toolbar__field-label-wrapper__current-field"
135129
);
136130
expect(toolbar).toBeInTheDocument();
137131
});
138132

139133
test("should contain a data-cslp-field-type attribute", async () => {
140-
booleanField.dispatchEvent(mouseClickEvent);
141134
await waitFor(() => {
142135
expect(booleanField).toHaveAttribute(
143136
VISUAL_BUILDER_FIELD_TYPE_ATTRIBUTE_KEY
@@ -146,14 +139,13 @@ describe("When an element is clicked in visual builder mode", () => {
146139
});
147140

148141
test("should not contain a contenteditable attribute", async () => {
149-
booleanField.dispatchEvent(mouseClickEvent);
150142
await waitFor(() => {
151143
expect(booleanField).not.toHaveAttribute("contenteditable");
152144
});
153145
});
154146

155147
test("should send a focus field message to parent", async () => {
156-
booleanField.dispatchEvent(mouseClickEvent);
148+
157149
await waitFor(() => {
158150
expect(visualBuilderPostMessage?.send).toBeCalledWith(
159151
VisualBuilderPostMessageEvents.FOCUS_FIELD,

0 commit comments

Comments
 (0)