Skip to content

Commit 1188cc0

Browse files
authored
Merge pull request #27 from wajeshubham/config-import-export
Config import export
2 parents a24c758 + 9846bda commit 1188cc0

20 files changed

+1188
-330
lines changed

__tests__/auth.test.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ import Home from "@/pages";
33
import { render, screen, waitFor } from "@testing-library/react";
44
import { act } from "react-dom/test-utils";
55

6+
beforeEach(() => {
7+
// IntersectionObserver isn't available in test environment
8+
const mockIntersectionObserver = jest.fn();
9+
mockIntersectionObserver.mockReturnValue({
10+
observe: () => null,
11+
unobserve: () => null,
12+
disconnect: () => null,
13+
});
14+
window.IntersectionObserver = mockIntersectionObserver;
15+
});
16+
617
beforeAll(() => {
718
document.createRange = () => {
819
const range = new Range();

__tests__/components/snippng_code_area.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ import { defaultEditorConfig } from "@/lib/constants";
44
import { render, screen, waitFor } from "@testing-library/react";
55
import { act } from "react-dom/test-utils";
66

7+
beforeEach(() => {
8+
// IntersectionObserver isn't available in test environment
9+
const mockIntersectionObserver = jest.fn();
10+
mockIntersectionObserver.mockReturnValue({
11+
observe: () => null,
12+
unobserve: () => null,
13+
disconnect: () => null,
14+
});
15+
window.IntersectionObserver = mockIntersectionObserver;
16+
});
17+
718
beforeAll(() => {
819
document.createRange = () => {
920
const range = new Range();
@@ -192,6 +203,8 @@ describe("SnippngCodeArea", () => {
192203
<SnippngCodeArea />
193204
</SnippngEditorContext.Provider>
194205
);
206+
207+
// @ts-ignore
195208
render(<SnippngControlHeader />);
196209
});
197210
const colorPicker = document.getElementById(

__tests__/components/snippng_control_header.test.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,21 @@ beforeAll(() => {
2222
};
2323
});
2424

25+
beforeEach(() => {
26+
// IntersectionObserver isn't available in test environment
27+
const mockIntersectionObserver = jest.fn();
28+
mockIntersectionObserver.mockReturnValue({
29+
observe: () => null,
30+
unobserve: () => null,
31+
disconnect: () => null,
32+
});
33+
window.IntersectionObserver = mockIntersectionObserver;
34+
});
35+
2536
describe("SnippngControlHeader", () => {
2637
it("renders all CTA and inputs", async () => {
2738
await act(async () => {
39+
//@ts-ignore
2840
render(<SnippngControlHeader />);
2941
});
3042
await waitFor(() => {
@@ -51,6 +63,7 @@ describe("SnippngControlHeader", () => {
5163
},
5264
}}
5365
>
66+
{/* @ts-ignore */}
5467
<SnippngControlHeader />
5568
</SnippngEditorContext.Provider>
5669
);
@@ -62,6 +75,7 @@ describe("SnippngControlHeader", () => {
6275

6376
it("renders with TypeScript as a default language", async () => {
6477
await act(async () => {
78+
//@ts-ignore
6579
render(<SnippngControlHeader />);
6680
});
6781
await waitFor(() => {

__tests__/utils.test.tsx

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { DEFAULT_RANGES, DEFAULT_WIDTHS } from "@/lib/constants";
2+
import { deepClone, validateSnippngConfig } from "@/utils";
3+
4+
const mockJSON = {
5+
code: "",
6+
snippetsName: "",
7+
editorFontSize: 16,
8+
editorWindowControlsType: "mac-left" as const,
9+
fileName: "@utils/debounce.ts",
10+
hasDropShadow: true,
11+
lineHeight: 19,
12+
paddingHorizontal: 70,
13+
paddingVertical: 70,
14+
rounded: true,
15+
selectedLang: { label: "TypeScript", id: "typescript" },
16+
selectedTheme: { id: "tokyoNightStorm", label: "Tokyo Night Storm" },
17+
showFileName: true,
18+
showLineNumbers: true,
19+
wrapperBg: "#eee811",
20+
gradients: ["#ba68c8", "#ffa7c4", "#e57373"],
21+
gradientAngle: 140,
22+
editorWidth: 450,
23+
bgImageVisiblePatch: null,
24+
bgBlur: 0,
25+
};
26+
27+
const inValidJSON = {
28+
invalidKey: "invalid value",
29+
};
30+
31+
beforeAll(() => {
32+
document.createRange = () => {
33+
const range = new Range();
34+
35+
range.getBoundingClientRect = jest.fn();
36+
37+
range.getClientRects = () => {
38+
return {
39+
item: () => null,
40+
length: 0,
41+
[Symbol.iterator]: jest.fn(),
42+
};
43+
};
44+
45+
return range;
46+
};
47+
});
48+
49+
describe("Utils", () => {
50+
it("deep clones the javascript object", async () => {
51+
let date = new Date().toISOString();
52+
let updatedDate = new Date().setFullYear(2002);
53+
54+
const objectToBeCloned = {
55+
name: "John",
56+
age: 20,
57+
marks: {
58+
science: 70,
59+
math: 75,
60+
},
61+
birthDate: date,
62+
};
63+
const clonedObject = deepClone(objectToBeCloned);
64+
clonedObject.name = "Updated";
65+
clonedObject.marks.science = 10;
66+
clonedObject.birthDate = updatedDate;
67+
68+
expect(objectToBeCloned.name).toBe("John");
69+
expect(objectToBeCloned.marks.science).toBe(70);
70+
expect(objectToBeCloned.birthDate).toBe(date);
71+
72+
expect(clonedObject.name).toBe("Updated");
73+
expect(clonedObject.marks.science).toBe(10);
74+
expect(clonedObject.birthDate).toBe(updatedDate);
75+
});
76+
77+
it("validates editor config coming from uploaded JSON file", async () => {
78+
let minValues = DEFAULT_RANGES.min;
79+
let maxValues = DEFAULT_RANGES.max;
80+
const mockOneResult = validateSnippngConfig({ ...mockJSON });
81+
82+
const mockMissingKeyResult = validateSnippngConfig({
83+
...mockJSON,
84+
selectedLang: undefined as any,
85+
});
86+
87+
const mockInvalidKeyResult = validateSnippngConfig({
88+
...mockJSON,
89+
selectedLang: [] as any,
90+
});
91+
92+
const mockBlueCheckResult = validateSnippngConfig({
93+
...mockJSON,
94+
bgBlur: 100,
95+
});
96+
const mockLineHeightResult = validateSnippngConfig({
97+
...mockJSON,
98+
lineHeight: 100,
99+
});
100+
const mockPadHorResult = validateSnippngConfig({
101+
...mockJSON,
102+
paddingHorizontal: 200,
103+
});
104+
const mockPadVerResult = validateSnippngConfig({
105+
...mockJSON,
106+
paddingVertical: 200,
107+
});
108+
const mockFontSizeResult = validateSnippngConfig({
109+
...mockJSON,
110+
editorFontSize: 54,
111+
});
112+
const mockGradAngResult = validateSnippngConfig({
113+
...mockJSON,
114+
gradientAngle: 361,
115+
});
116+
const mockEdWidthMinResult = validateSnippngConfig({
117+
...mockJSON,
118+
editorWidth: -10,
119+
});
120+
const mockEdWidthMaxResult = validateSnippngConfig({
121+
...mockJSON,
122+
editorWidth: 3000,
123+
});
124+
const invalidResult = validateSnippngConfig({ ...(inValidJSON as any) });
125+
expect(mockOneResult).toBe("");
126+
expect(mockMissingKeyResult).toBe("value.selectedLang is missing");
127+
expect(mockInvalidKeyResult).toContain("missing");
128+
expect(mockBlueCheckResult).toBe(
129+
`bgBlur value must be in the range ${minValues.BLUR} to ${maxValues.BLUR}`
130+
);
131+
expect(mockLineHeightResult).toBe(
132+
`lineHeight value must be in the range ${minValues.LINE_HEIGHT} to ${maxValues.LINE_HEIGHT}`
133+
);
134+
expect(mockPadHorResult).toBe(
135+
`paddingHorizontal value must be in the range ${minValues.PADDING_HORIZONTAL} to ${maxValues.PADDING_HORIZONTAL}`
136+
);
137+
expect(mockPadVerResult).toBe(
138+
`paddingVertical value must be in the range ${minValues.PADDING_VERTICAL} to ${maxValues.PADDING_VERTICAL}`
139+
);
140+
expect(mockFontSizeResult).toBe(
141+
`editorFontSize value must be in the range ${minValues.FONT_SIZE} to ${maxValues.FONT_SIZE}`
142+
);
143+
expect(mockGradAngResult).toBe(
144+
`gradientAngle value must be in the range ${minValues.GRADIENT_ANGLE} to ${maxValues.GRADIENT_ANGLE}`
145+
);
146+
expect(mockEdWidthMinResult).toBe(
147+
`editorWidth value must be in the range ${DEFAULT_WIDTHS.minWidth} to ${DEFAULT_WIDTHS.maxWidth}`
148+
);
149+
expect(mockEdWidthMaxResult).toBe(
150+
`editorWidth value must be in the range ${DEFAULT_WIDTHS.minWidth} to ${DEFAULT_WIDTHS.maxWidth}`
151+
);
152+
expect(invalidResult).toBeTruthy();
153+
});
154+
});

components/ThemeToggle.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { MoonIcon, SunIcon } from "@heroicons/react/24/outline";
22

3-
export const ThemeToggle = () => {
3+
const ThemeToggle = () => {
44
const disableTransitionsTemporarily = () => {
55
document.documentElement.classList.add("[&_*]:!transition-none");
66
window.setTimeout(() => {

components/Toast.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import React, { useEffect } from "react";
2-
import { Fragment, useState } from "react";
1+
import { ToastInterface } from "@/types";
32
import { Transition } from "@headlessui/react";
3+
import { XMarkIcon } from "@heroicons/react/20/solid";
44
import {
55
CheckCircleIcon,
66
InformationCircleIcon,
77
XCircleIcon,
88
} from "@heroicons/react/24/outline";
9-
import { XMarkIcon } from "@heroicons/react/20/solid";
10-
import { ToastInterface, ToastVariantType } from "@/types";
9+
import React, { Fragment, useEffect, useState } from "react";
1110

1211
interface Props extends ToastInterface {
1312
onClose: () => void;

components/editor/SnippngCodeArea.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import { useRef, useState } from "react";
22

33
import { DEFAULT_BASE_SETUP } from "@/lib/constants";
4-
import { clsx, getEditorWrapperBg, getLanguage, getTheme } from "@/utils";
4+
import {
5+
clsx,
6+
deepClone,
7+
getEditorWrapperBg,
8+
getLanguage,
9+
getTheme,
10+
} from "@/utils";
511

612
import { langs, loadLanguage } from "@uiw/codemirror-extensions-langs";
713
import * as themes from "@uiw/codemirror-themes-all";
@@ -63,7 +69,7 @@ const SnippngCodeArea = () => {
6369
if (!user) return;
6470
setSaving(true);
6571
try {
66-
const dataToBeAdded = { ...structuredClone(editorConfig) }; // deep clone the editor config to avoid mutation
72+
const dataToBeAdded = { ...deepClone(editorConfig) }; // deep clone the editor config to avoid mutation
6773
delete dataToBeAdded.uid; // delete existing uid if exists
6874
const savedDoc = await addDoc(collection(db, "snippets"), {
6975
...dataToBeAdded,

0 commit comments

Comments
 (0)