test: cover collab field preservation
This commit is contained in:
@@ -286,13 +286,10 @@ const initializeScene = async (opts: {
|
|||||||
scene = {
|
scene = {
|
||||||
elements: bumpElementVersions(
|
elements: bumpElementVersions(
|
||||||
restoreElements(
|
restoreElements(
|
||||||
migrateSceneElements(
|
migrateSceneElements(imported.elements, {
|
||||||
imported.elements,
|
payloadSchemaVersion: imported.schemaVersion,
|
||||||
{
|
fallbackVersion: SCHEMA_VERSIONS.initial,
|
||||||
payloadSchemaVersion: imported.schemaVersion,
|
}),
|
||||||
fallbackVersion: SCHEMA_VERSIONS.initial,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
repairBindings: true,
|
repairBindings: true,
|
||||||
|
|||||||
@@ -87,10 +87,12 @@ const saveDataStateToLocalStorage = (
|
|||||||
_appState.openSidebar = null;
|
_appState.openSidebar = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const persistedElements = getNonDeletedElements(elements).map((element) => ({
|
const persistedElements = getNonDeletedElements(elements).map(
|
||||||
...element,
|
(element) => ({
|
||||||
schemaVersion: SCHEMA_VERSIONS.latest,
|
...element,
|
||||||
}));
|
schemaVersion: SCHEMA_VERSIONS.latest,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
STORAGE_KEYS.LOCAL_STORAGE_ELEMENTS,
|
STORAGE_KEYS.LOCAL_STORAGE_ELEMENTS,
|
||||||
|
|||||||
@@ -69,6 +69,98 @@ vi.mock("socket.io-client", () => {
|
|||||||
* i.e. multiplayer history tests could be a good first candidate, as we could test both history stacks simultaneously.
|
* i.e. multiplayer history tests could be a good first candidate, as we could test both history stacks simultaneously.
|
||||||
*/
|
*/
|
||||||
describe("collaboration", () => {
|
describe("collaboration", () => {
|
||||||
|
it("should preserve future element fields across collab reconciliation", async () => {
|
||||||
|
await render(<ExcalidrawApp />);
|
||||||
|
|
||||||
|
const frame = API.createElement({
|
||||||
|
type: "frame",
|
||||||
|
id: "A",
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
backgroundColor: "#ff0000",
|
||||||
|
});
|
||||||
|
|
||||||
|
const frameWithFutureFields = {
|
||||||
|
...frame,
|
||||||
|
schemaVersion: 2,
|
||||||
|
futureField: "keep-me",
|
||||||
|
} as typeof frame & {
|
||||||
|
schemaVersion: number;
|
||||||
|
futureField: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
API.updateScene({
|
||||||
|
elements: [frameWithFutureFields],
|
||||||
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect((h.elements[0] as any).futureField).toBe("keep-me");
|
||||||
|
expect((h.elements[0] as any).schemaVersion).toBe(2);
|
||||||
|
expect(h.elements[0].backgroundColor).toBe("#ff0000");
|
||||||
|
});
|
||||||
|
|
||||||
|
const remoteMovedFrame = newElementWith(h.elements[0] as any, {
|
||||||
|
x: 120,
|
||||||
|
y: 80,
|
||||||
|
});
|
||||||
|
|
||||||
|
const reconciled = (window.collab as any)._reconcileElements([
|
||||||
|
remoteMovedFrame,
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(reconciled[0]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
x: 120,
|
||||||
|
y: 80,
|
||||||
|
backgroundColor: "#ff0000",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect((reconciled[0] as any).futureField).toBe("keep-me");
|
||||||
|
expect((reconciled[0] as any).schemaVersion).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should preserve future element fields on local edits before broadcast", async () => {
|
||||||
|
await render(<ExcalidrawApp />);
|
||||||
|
|
||||||
|
const rect = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
id: "A",
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rectWithFutureFields = {
|
||||||
|
...rect,
|
||||||
|
schemaVersion: 2,
|
||||||
|
futureField: { value: "keep-me" },
|
||||||
|
} as typeof rect & {
|
||||||
|
schemaVersion: number;
|
||||||
|
futureField: { value: string };
|
||||||
|
};
|
||||||
|
|
||||||
|
API.updateScene({
|
||||||
|
elements: [rectWithFutureFields],
|
||||||
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
|
});
|
||||||
|
|
||||||
|
const locallyEdited = newElementWith(h.elements[0] as any, { x: 200 });
|
||||||
|
API.updateScene({
|
||||||
|
elements: [locallyEdited],
|
||||||
|
captureUpdate: CaptureUpdateAction.NEVER,
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect((h.elements[0] as any).futureField).toEqual({ value: "keep-me" });
|
||||||
|
expect((h.elements[0] as any).schemaVersion).toBe(2);
|
||||||
|
expect(h.elements[0]).toEqual(expect.objectContaining({ x: 200 }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("should emit two ephemeral increments even though updates get batched", async () => {
|
it("should emit two ephemeral increments even though updates get batched", async () => {
|
||||||
const durableIncrements: DurableIncrement[] = [];
|
const durableIncrements: DurableIncrement[] = [];
|
||||||
const ephemeralIncrements: EphemeralIncrement[] = [];
|
const ephemeralIncrements: EphemeralIncrement[] = [];
|
||||||
|
|||||||
@@ -35,12 +35,13 @@ import {
|
|||||||
|
|
||||||
import { tryParseSpreadsheet, VALID_SPREADSHEET } from "./charts";
|
import { tryParseSpreadsheet, VALID_SPREADSHEET } from "./charts";
|
||||||
|
|
||||||
|
import { SCHEMA_VERSIONS } from "./data/schema";
|
||||||
|
|
||||||
import type { FileSystemHandle } from "./data/filesystem";
|
import type { FileSystemHandle } from "./data/filesystem";
|
||||||
|
|
||||||
import type { Spreadsheet } from "./charts";
|
import type { Spreadsheet } from "./charts";
|
||||||
|
|
||||||
import type { BinaryFiles } from "./types";
|
import type { BinaryFiles } from "./types";
|
||||||
import { SCHEMA_VERSIONS } from "./data/schema";
|
|
||||||
|
|
||||||
type ElementsClipboard = {
|
type ElementsClipboard = {
|
||||||
type: typeof EXPORT_DATA_TYPES.excalidrawClipboard;
|
type: typeof EXPORT_DATA_TYPES.excalidrawClipboard;
|
||||||
|
|||||||
@@ -2822,13 +2822,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
? SCHEMA_VERSIONS.initial
|
? SCHEMA_VERSIONS.initial
|
||||||
: SCHEMA_VERSIONS.latest;
|
: SCHEMA_VERSIONS.latest;
|
||||||
const restoredElements = restoreElements(
|
const restoredElements = restoreElements(
|
||||||
migrateSceneElements(
|
migrateSceneElements(initialData?.elements, {
|
||||||
initialData?.elements,
|
payloadSchemaVersion: initialData?.schemaVersion,
|
||||||
{
|
fallbackVersion: initialDataSchemaFallback,
|
||||||
payloadSchemaVersion: initialData?.schemaVersion,
|
}),
|
||||||
fallbackVersion: initialDataSchemaFallback,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
repairBindings: true,
|
repairBindings: true,
|
||||||
@@ -3764,13 +3761,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
? migrateLibraryElements(opts.elements, opts.schemaVersionSource)
|
? migrateLibraryElements(opts.elements, opts.schemaVersionSource)
|
||||||
: migrateAPIElements(opts.elements, opts.schemaVersionSource);
|
: migrateAPIElements(opts.elements, opts.schemaVersionSource);
|
||||||
|
|
||||||
const elements = restoreElements(
|
const elements = restoreElements(migratedElements, null, {
|
||||||
migratedElements,
|
deleteInvisibleElements: true,
|
||||||
null,
|
});
|
||||||
{
|
|
||||||
deleteInvisibleElements: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
|
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
|
||||||
|
|
||||||
const elementsCenterX = distance(minX, maxX) / 2;
|
const elementsCenterX = distance(minX, maxX) / 2;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
chunk,
|
chunk,
|
||||||
getExportSource,
|
getExportSource,
|
||||||
} from "@excalidraw/common";
|
} from "@excalidraw/common";
|
||||||
|
|
||||||
import { SCHEMA_VERSIONS } from "../data/schema";
|
import { SCHEMA_VERSIONS } from "../data/schema";
|
||||||
|
|
||||||
import { EditorLocalStorage } from "../data/EditorLocalStorage";
|
import { EditorLocalStorage } from "../data/EditorLocalStorage";
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ import {
|
|||||||
restoreElements,
|
restoreElements,
|
||||||
restoreLibraryItems,
|
restoreLibraryItems,
|
||||||
} from "./restore";
|
} from "./restore";
|
||||||
import {
|
import { migrateSceneElements, SCHEMA_VERSIONS } from "./schema";
|
||||||
migrateSceneElements,
|
|
||||||
SCHEMA_VERSIONS,
|
|
||||||
} from "./schema";
|
|
||||||
|
|
||||||
import type { AppState, DataURL, LibraryItem } from "../types";
|
import type { AppState, DataURL, LibraryItem } from "../types";
|
||||||
|
|
||||||
@@ -161,13 +158,10 @@ export const loadSceneOrLibraryFromBlob = async (
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
if (isValidExcalidrawData(data)) {
|
if (isValidExcalidrawData(data)) {
|
||||||
const migratedElements = migrateSceneElements(
|
const migratedElements = migrateSceneElements(data.elements, {
|
||||||
data.elements,
|
payloadSchemaVersion: data.schemaVersion,
|
||||||
{
|
fallbackVersion: SCHEMA_VERSIONS.initial,
|
||||||
payloadSchemaVersion: data.schemaVersion,
|
});
|
||||||
fallbackVersion: SCHEMA_VERSIONS.initial,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
type: MIME_TYPES.excalidraw,
|
type: MIME_TYPES.excalidraw,
|
||||||
data: {
|
data: {
|
||||||
@@ -233,14 +227,10 @@ export const parseLibraryJSON = (
|
|||||||
throw new Error("Invalid library");
|
throw new Error("Invalid library");
|
||||||
}
|
}
|
||||||
const libraryItems = data.libraryItems || data.library;
|
const libraryItems = data.libraryItems || data.library;
|
||||||
return restoreLibraryItems(
|
return restoreLibraryItems(libraryItems, defaultStatus, {
|
||||||
libraryItems,
|
payloadSchemaVersion: data.schemaVersion,
|
||||||
defaultStatus,
|
fallbackVersion: SCHEMA_VERSIONS.initial,
|
||||||
{
|
});
|
||||||
payloadSchemaVersion: data.schemaVersion,
|
|
||||||
fallbackVersion: SCHEMA_VERSIONS.initial,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadLibraryFromBlob = async (
|
export const loadLibraryFromBlob = async (
|
||||||
|
|||||||
@@ -91,9 +91,10 @@ export interface LibraryPersistenceAdapter {
|
|||||||
* purposes, in which case host app can implement more aggressive caching.
|
* purposes, in which case host app can implement more aggressive caching.
|
||||||
*/
|
*/
|
||||||
source: LibraryAdatapterSource;
|
source: LibraryAdatapterSource;
|
||||||
}): MaybePromise<
|
}): MaybePromise<{
|
||||||
{ libraryItems: LibraryItems_anyVersion; schemaVersion?: number } | null
|
libraryItems: LibraryItems_anyVersion;
|
||||||
>;
|
schemaVersion?: number;
|
||||||
|
} | null>;
|
||||||
/** Should persist to the database as is (do no change the data structure). */
|
/** Should persist to the database as is (do no change the data structure). */
|
||||||
save(libraryData: LibraryPersistedData): MaybePromise<void>;
|
save(libraryData: LibraryPersistedData): MaybePromise<void>;
|
||||||
}
|
}
|
||||||
@@ -103,9 +104,10 @@ export interface LibraryMigrationAdapter {
|
|||||||
* loads data from legacy data source. Returns `null` if no data is
|
* loads data from legacy data source. Returns `null` if no data is
|
||||||
* to be migrated.
|
* to be migrated.
|
||||||
*/
|
*/
|
||||||
load(): MaybePromise<
|
load(): MaybePromise<{
|
||||||
{ libraryItems: LibraryItems_anyVersion; schemaVersion?: number } | null
|
libraryItems: LibraryItems_anyVersion;
|
||||||
>;
|
schemaVersion?: number;
|
||||||
|
} | null>;
|
||||||
|
|
||||||
/** clears entire storage afterwards */
|
/** clears entire storage afterwards */
|
||||||
clear(): MaybePromise<void>;
|
clear(): MaybePromise<void>;
|
||||||
@@ -561,14 +563,10 @@ class AdapterTransaction {
|
|||||||
try {
|
try {
|
||||||
const data = await adapter.load({ source });
|
const data = await adapter.load({ source });
|
||||||
resolve(
|
resolve(
|
||||||
restoreLibraryItems(
|
restoreLibraryItems(data?.libraryItems || [], "published", {
|
||||||
data?.libraryItems || [],
|
payloadSchemaVersion: data?.schemaVersion,
|
||||||
"published",
|
fallbackVersion: SCHEMA_VERSIONS.initial,
|
||||||
{
|
}),
|
||||||
payloadSchemaVersion: data?.schemaVersion,
|
|
||||||
fallbackVersion: SCHEMA_VERSIONS.initial,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
reject(error);
|
reject(error);
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ import {
|
|||||||
getNormalizedGridStep,
|
getNormalizedGridStep,
|
||||||
getNormalizedZoom,
|
getNormalizedZoom,
|
||||||
} from "../scene";
|
} from "../scene";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
migrateLibraryElements,
|
migrateLibraryElements,
|
||||||
type SchemaVersionSource,
|
type SchemaVersionSource,
|
||||||
@@ -984,12 +985,15 @@ export const restoreLibraryItems = (
|
|||||||
for (const item of libraryItems) {
|
for (const item of libraryItems) {
|
||||||
// migrate older libraries
|
// migrate older libraries
|
||||||
if (Array.isArray(item)) {
|
if (Array.isArray(item)) {
|
||||||
const restoredItem = restoreLibraryItem({
|
const restoredItem = restoreLibraryItem(
|
||||||
status: defaultStatus,
|
{
|
||||||
elements: item,
|
status: defaultStatus,
|
||||||
id: randomId(),
|
elements: item,
|
||||||
created: Date.now(),
|
id: randomId(),
|
||||||
}, schemaVersionSource);
|
created: Date.now(),
|
||||||
|
},
|
||||||
|
schemaVersionSource,
|
||||||
|
);
|
||||||
if (restoredItem) {
|
if (restoredItem) {
|
||||||
restoredItems.push(restoredItem);
|
restoredItems.push(restoredItem);
|
||||||
}
|
}
|
||||||
@@ -998,12 +1002,15 @@ export const restoreLibraryItems = (
|
|||||||
LibraryItem,
|
LibraryItem,
|
||||||
"id" | "status" | "created"
|
"id" | "status" | "created"
|
||||||
>;
|
>;
|
||||||
const restoredItem = restoreLibraryItem({
|
const restoredItem = restoreLibraryItem(
|
||||||
..._item,
|
{
|
||||||
id: _item.id || randomId(),
|
..._item,
|
||||||
status: _item.status || defaultStatus,
|
id: _item.id || randomId(),
|
||||||
created: _item.created || Date.now(),
|
status: _item.status || defaultStatus,
|
||||||
}, schemaVersionSource);
|
created: _item.created || Date.now(),
|
||||||
|
},
|
||||||
|
schemaVersionSource,
|
||||||
|
);
|
||||||
if (restoredItem) {
|
if (restoredItem) {
|
||||||
restoredItems.push(restoredItem);
|
restoredItems.push(restoredItem);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { DEFAULT_ELEMENT_PROPS } from "@excalidraw/common";
|
import { DEFAULT_ELEMENT_PROPS } from "@excalidraw/common";
|
||||||
|
|
||||||
import { API } from "../tests/helpers/api";
|
import { API } from "../tests/helpers/api";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ALL_SCOPES,
|
ALL_SCOPES,
|
||||||
hasElementSchemaVersion,
|
hasElementSchemaVersion,
|
||||||
@@ -194,13 +195,10 @@ describe("schema migration", () => {
|
|||||||
schemaVersion: SCHEMA_VERSIONS.latest,
|
schemaVersion: SCHEMA_VERSIONS.latest,
|
||||||
} as typeof modernFrame & { schemaVersion: number };
|
} as typeof modernFrame & { schemaVersion: number };
|
||||||
|
|
||||||
const migrated = migrateSceneElements(
|
const migrated = migrateSceneElements([legacyFrame, modernFrameWithHint], {
|
||||||
[legacyFrame, modernFrameWithHint],
|
payloadSchemaVersion: undefined,
|
||||||
{
|
fallbackVersion: SCHEMA_VERSIONS.initial,
|
||||||
payloadSchemaVersion: undefined,
|
})!;
|
||||||
fallbackVersion: SCHEMA_VERSIONS.initial,
|
|
||||||
},
|
|
||||||
)!;
|
|
||||||
|
|
||||||
expect(migrated[0].backgroundColor).toBe(
|
expect(migrated[0].backgroundColor).toBe(
|
||||||
DEFAULT_ELEMENT_PROPS.backgroundColor,
|
DEFAULT_ELEMENT_PROPS.backgroundColor,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const SCHEMA_MIGRATION_SCOPES = [
|
|||||||
"api",
|
"api",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type SchemaMigrationScope = (typeof SCHEMA_MIGRATION_SCOPES)[number];
|
export type SchemaMigrationScope = typeof SCHEMA_MIGRATION_SCOPES[number];
|
||||||
|
|
||||||
export const ALL_SCOPES: readonly SchemaMigrationScope[] =
|
export const ALL_SCOPES: readonly SchemaMigrationScope[] =
|
||||||
SCHEMA_MIGRATION_SCOPES;
|
SCHEMA_MIGRATION_SCOPES;
|
||||||
@@ -135,7 +135,9 @@ export const validateSchemaMigrations = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!migration.scope.length) {
|
if (!migration.scope.length) {
|
||||||
errors.push(`Migration "${migration.title}" must declare at least one scope.`);
|
errors.push(
|
||||||
|
`Migration "${migration.title}" must declare at least one scope.`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for (const scope of migration.scope) {
|
for (const scope of migration.scope) {
|
||||||
if (!SCHEMA_MIGRATION_SCOPES.includes(scope)) {
|
if (!SCHEMA_MIGRATION_SCOPES.includes(scope)) {
|
||||||
@@ -155,12 +157,13 @@ export const validateSchemaMigrations = (
|
|||||||
return errors;
|
return errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
const schemaMigrationValidationErrors = validateSchemaMigrations(
|
const schemaMigrationValidationErrors =
|
||||||
SCHEMA_MIGRATIONS,
|
validateSchemaMigrations(SCHEMA_MIGRATIONS);
|
||||||
);
|
|
||||||
if (schemaMigrationValidationErrors.length) {
|
if (schemaMigrationValidationErrors.length) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid schema migration configuration:\n${schemaMigrationValidationErrors.join("\n")}`,
|
`Invalid schema migration configuration:\n${schemaMigrationValidationErrors.join(
|
||||||
|
"\n",
|
||||||
|
)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,23 +238,19 @@ const migrateElementsByScope = (
|
|||||||
export const migrateSceneElements = (
|
export const migrateSceneElements = (
|
||||||
elements: readonly ExcalidrawElement[] | null | undefined,
|
elements: readonly ExcalidrawElement[] | null | undefined,
|
||||||
source: SchemaVersionSource,
|
source: SchemaVersionSource,
|
||||||
) =>
|
) => migrateElementsByScope(elements, "scene", source);
|
||||||
migrateElementsByScope(elements, "scene", source);
|
|
||||||
|
|
||||||
export const migrateLibraryElements = (
|
export const migrateLibraryElements = (
|
||||||
elements: readonly ExcalidrawElement[] | null | undefined,
|
elements: readonly ExcalidrawElement[] | null | undefined,
|
||||||
source: SchemaVersionSource,
|
source: SchemaVersionSource,
|
||||||
) =>
|
) => migrateElementsByScope(elements, "library", source);
|
||||||
migrateElementsByScope(elements, "library", source);
|
|
||||||
|
|
||||||
export const migrateClipboardElements = (
|
export const migrateClipboardElements = (
|
||||||
elements: readonly ExcalidrawElement[] | null | undefined,
|
elements: readonly ExcalidrawElement[] | null | undefined,
|
||||||
source: SchemaVersionSource,
|
source: SchemaVersionSource,
|
||||||
) =>
|
) => migrateElementsByScope(elements, "clipboard", source);
|
||||||
migrateElementsByScope(elements, "clipboard", source);
|
|
||||||
|
|
||||||
export const migrateAPIElements = (
|
export const migrateAPIElements = (
|
||||||
elements: readonly ExcalidrawElement[] | null | undefined,
|
elements: readonly ExcalidrawElement[] | null | undefined,
|
||||||
source: SchemaVersionSource,
|
source: SchemaVersionSource,
|
||||||
) =>
|
) => migrateElementsByScope(elements, "api", source);
|
||||||
migrateElementsByScope(elements, "api", source);
|
|
||||||
|
|||||||
@@ -121,7 +121,8 @@ describe("restoreElements", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
(restoredLibraryItems[0].elements[0] as ExcalidrawElement).backgroundColor,
|
(restoredLibraryItems[0].elements[0] as ExcalidrawElement)
|
||||||
|
.backgroundColor,
|
||||||
).toBe("#a5d8ff");
|
).toBe("#a5d8ff");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -145,7 +146,8 @@ describe("restoreElements", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
(restoredLibraryItems[0].elements[0] as ExcalidrawElement).backgroundColor,
|
(restoredLibraryItems[0].elements[0] as ExcalidrawElement)
|
||||||
|
.backgroundColor,
|
||||||
).toBe(DEFAULT_ELEMENT_PROPS.backgroundColor);
|
).toBe(DEFAULT_ELEMENT_PROPS.backgroundColor);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user