From b4413c3581995662b48d6c467a9ad6ef63d775d4 Mon Sep 17 00:00:00 2001 From: gebov Date: Tue, 19 Dec 2023 16:04:33 +0200 Subject: [PATCH] image tests start --- .../editor/widget-framework/attributes.ts | 8 +- .../widget-editor-metadata.ts | 1 + .../widgets/image/image-tag.tsx | 78 +++++++++---------- src/nextjs-framework/widgets/image/image.tsx | 26 +++---- .../widgets/widget-registry.ts | 6 +- tests/__snapshots__/image.test.tsx.snap | 40 ++-------- tests/framework/widget-tester.ts | 6 +- tests/image.test.tsx | 36 +++++++-- 8 files changed, 103 insertions(+), 98 deletions(-) diff --git a/src/nextjs-framework/editor/widget-framework/attributes.ts b/src/nextjs-framework/editor/widget-framework/attributes.ts index 8b92f44..eb99b44 100644 --- a/src/nextjs-framework/editor/widget-framework/attributes.ts +++ b/src/nextjs-framework/editor/widget-framework/attributes.ts @@ -1,4 +1,5 @@ +import { Dictionary } from '../../typings/dictionary'; import { LinkModel } from './link-model'; import { WidgetContext } from './widget-context'; @@ -7,7 +8,7 @@ export type CustomAttribute = { Value: string; }; -export function htmlAttributes(widgetContext: WidgetContext, error: string | undefined = undefined) { +export function htmlAttributes(widgetContext: WidgetContext, error: string | undefined = undefined): { [key: string]: any } { if (!widgetContext.requestContext.isEdit) { return {}; } @@ -41,7 +42,10 @@ export function htmlAttributes(widgetContext: WidgetContext, error: string attributes['data-sfisemptyvisualhidden'] = false; attributes['data-sfisempty'] = false; attributes['draggable'] = true; - attributes['data-sfhasquickeditoperation'] = true; + + if (widgetContext.metadata.editorMetadata?.HasQuickEditOperation) { + attributes['data-sfhasquickeditoperation'] = true; + } if (error) { attributes['data-sferror'] = error; diff --git a/src/nextjs-framework/editor/widget-framework/widget-editor-metadata.ts b/src/nextjs-framework/editor/widget-framework/widget-editor-metadata.ts index f818144..d696f46 100644 --- a/src/nextjs-framework/editor/widget-framework/widget-editor-metadata.ts +++ b/src/nextjs-framework/editor/widget-framework/widget-editor-metadata.ts @@ -10,5 +10,6 @@ export interface EditorMetadata { Toolbox?: string; Warning?: string; HideEmptyVisual?: boolean; + HasQuickEditOperation?: boolean; Order?: number; } diff --git a/src/nextjs-framework/widgets/image/image-tag.tsx b/src/nextjs-framework/widgets/image/image-tag.tsx index 79b5492..750c785 100644 --- a/src/nextjs-framework/widgets/image/image-tag.tsx +++ b/src/nextjs-framework/widgets/image/image-tag.tsx @@ -6,7 +6,7 @@ import { getCustomAttributes, classNames } from '../../editor'; const imageWrapperClass = 'd-inline-block'; -export function ImageTag(props: {imageModel: ImageViewModel, className?: string }) { +export function ImageTag(props: { imageModel: ImageViewModel, className?: string }) { const { imageModel, className = '', ...others } = props; const selectedImageUrl = imageModel.SelectedImageUrl; const imageCustomAttributes = getCustomAttributes(imageModel.Attributes, 'Image'); @@ -14,45 +14,45 @@ export function ImageTag(props: {imageModel: ImageViewModel, className?: string const sortedList = (imageModel.Thumbnails || []).sort(t => t.Width); const wrapperClass = classNames(imageWrapperClass, className); const imageClass = classNames(className, { - [className]: className && imageModel.ImageSize === ImageDisplayMode.Responsive, - 'img-fluid': imageModel.FitToContainer || true - }); + [className]: className && imageModel.ImageSize === ImageDisplayMode.Responsive, + 'img-fluid': !!imageModel.FitToContainer + }); return ( imageModel.ImageSize === ImageDisplayMode.Responsive - ? - { - sortedList.map((thumbnail: any, idx: number) => { - const sourceWidth = imageModel.Width && thumbnail.Width !== imageModel.Width ? thumbnail.Width : undefined; - const sourceHeight = imageModel.Height && thumbnail.Height !== imageModel.Height ? thumbnail.Height : undefined; - if (sourceWidth && sourceHeight) { - return (); + ? + { + sortedList.map((thumbnail: any, idx: number) => { + const sourceWidth = imageModel.Width && thumbnail.Width !== imageModel.Width ? thumbnail.Width : undefined; + const sourceHeight = imageModel.Height && thumbnail.Height !== imageModel.Height ? thumbnail.Height : undefined; + if (sourceWidth && sourceHeight) { + return (); + } + }) } - }) - } - { - /* eslint-disable-next-line @next/next/no-img-element */ - {altAttr}} - - : { + { /* eslint-disable-next-line @next/next/no-img-element */ - {altAttr}/ - } - ); - } + {altAttr}} + + : { + /* eslint-disable-next-line @next/next/no-img-element */ + {altAttr + } + ); +} diff --git a/src/nextjs-framework/widgets/image/image.tsx b/src/nextjs-framework/widgets/image/image.tsx index 5f84c15..26668a3 100644 --- a/src/nextjs-framework/widgets/image/image.tsx +++ b/src/nextjs-framework/widgets/image/image.tsx @@ -5,25 +5,18 @@ import { ImageTag } from './image-tag'; import { ImageClickAction } from './interfaces/ImageClickAction'; import { ImageDisplayMode } from './interfaces/ImageDisplayMode'; import { WidgetContext, htmlAttributes, classNames, generateAnchorAttrsFromLink, LinkModel } from '../../editor'; -import { RestService, RestSdkTypes, ThumbnailItem, SdkItem, ImageItem } from '../../rest-sdk'; +import { RestService, RestSdkTypes, ThumbnailItem, ImageItem, SdkItem } from '../../rest-sdk'; const imageWrapperClass = 'd-inline-block'; export async function Image(props: WidgetContext) { - const entity = { + const entity: ImageEntity = { ImageSize: ImageDisplayMode.Responsive, ...props.model.Properties }; const dataAttributes = htmlAttributes(props); - const defaultClass = classNames(imageWrapperClass, entity.CssClass); - const marginClass = entity.Margins && StyleGenerator.getMarginClasses(entity.Margins); const anchorAttributes = generateAnchorAttrsFromLink(entity.ActionLink); - dataAttributes['className'] = classNames( - defaultClass, - marginClass - ); - dataAttributes['data-sfhasquickeditoperation'] = true; let imageItem = null; if (entity.Item && entity.Item.Id) { imageItem = await RestService.getItemWithFallback(RestSdkTypes.Image, entity.Item.Id.toString(), entity.Item.Provider); @@ -33,6 +26,13 @@ export async function Image(props: WidgetContext) { return (
); } + const defaultClass = classNames(imageWrapperClass, entity.CssClass); + const marginClass = entity.Margins && StyleGenerator.getMarginClasses(entity.Margins); + dataAttributes['className'] = classNames( + defaultClass, + marginClass + ); + const isSvg = imageItem.MimeType === 'image/svg+xml'; const hasZeroDimensions = imageItem.Width === 0 && imageItem.Height === 0; let width = isSvg && hasZeroDimensions ? null : imageItem.Width; @@ -91,12 +91,10 @@ export async function Image(props: WidgetContext) { } export interface ImageEntity { - Item?: ImageItem; - Attributes?: { [key: string]: Array<{ Key: string, Value: string}> }; - Margins?: OffsetStyle; + Item?: SdkItem; + CssClass?: string; Title?: string; AlternativeText?: string; - CssClass?: string; ClickAction?: ImageClickAction; ActionLink?: LinkModel; ImageSize?: ImageDisplayMode; @@ -104,4 +102,6 @@ export interface ImageEntity { CustomSize?: { Width: number, Height: number}; Thumnail?: ThumbnailItem; ViewName?: string; + Margins?: OffsetStyle; + Attributes?: { [key: string]: Array<{ Key: string, Value: string}> }; } diff --git a/src/nextjs-framework/widgets/widget-registry.ts b/src/nextjs-framework/widgets/widget-registry.ts index a09ff57..f79125d 100644 --- a/src/nextjs-framework/widgets/widget-registry.ts +++ b/src/nextjs-framework/widgets/widget-registry.ts @@ -86,7 +86,8 @@ export const widgetRegistry: WidgetRegistry = { Section: 'Basic', EmptyIcon: 'picture-o', EmptyIconAction: 'Edit', - EmptyIconText: 'Select image' + EmptyIconText: 'Select image', + HasQuickEditOperation: true }, ssr: true }, @@ -164,7 +165,8 @@ export const widgetRegistry: WidgetRegistry = { componentType: ContentBlock, editorMetadata: { Title: 'Content block', - Section: 'Basic' + Section: 'Basic', + HasQuickEditOperation: true }, ssr: true }, diff --git a/tests/__snapshots__/image.test.tsx.snap b/tests/__snapshots__/image.test.tsx.snap index a5ae82e..a91675d 100644 --- a/tests/__snapshots__/image.test.tsx.snap +++ b/tests/__snapshots__/image.test.tsx.snap @@ -1,43 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Image with selected image item 1`] = ` +exports[`Image rendered with original size 1`] = `
- - + - -
-`; - -exports[`should render image default state 1`] = ` -
-
+
`; diff --git a/tests/framework/widget-tester.ts b/tests/framework/widget-tester.ts index cccc62c..b54a48d 100644 --- a/tests/framework/widget-tester.ts +++ b/tests/framework/widget-tester.ts @@ -25,8 +25,12 @@ export class WidgetTester { if (args.properties) { Object.keys(args.properties).forEach((key) => { let value: any = (args.properties as any)[key]; - if (value && !(typeof value === 'undefined')) { + if (typeof value === 'object') { value = JSON.stringify(value); + } else if (typeof value !== 'undefined') { + value = value.toString(); + } else { + return; } properties[key] = value; diff --git a/tests/image.test.tsx b/tests/image.test.tsx index b353b45..e00aa6e 100644 --- a/tests/image.test.tsx +++ b/tests/image.test.tsx @@ -1,14 +1,16 @@ import { waitFor } from '@testing-library/react'; import { WidgetTester } from './framework/widget-tester'; -import { RestSdkTypes, RestService } from '../src/nextjs-framework/rest-sdk'; +import { RestSdkTypes, RestService, SdkItem } from '../src/nextjs-framework/rest-sdk'; import fs from 'fs'; +import { ImageEntity } from '../src/nextjs-framework/widgets/image/image'; +import { ImageDisplayMode } from '../src/nextjs-framework/widgets/image/interfaces/ImageDisplayMode'; - -test('Image with selected image item', async () => { +let sdkItem: SdkItem; +beforeAll(async () => { const base64Image = fs.readFileSync('./tests/data/1.jpg', { encoding: 'base64' }); let libraryId = '4BA7AD46-F29B-4e65-BE17-9BF7CE5BA1FB'; - const imageItem = await RestService.uploadItem({ + sdkItem = await RestService.uploadItem({ Title: 'Image', Type: RestSdkTypes.Image, ContentType: 'image/jpeg', @@ -16,13 +18,35 @@ test('Image with selected image item', async () => { ParentId: libraryId, BinaryData: base64Image }); +}); + +test('Image rendered with original size', async () => { + await WidgetTester.testWidgetRender({ + name: 'SitefinityImage', + properties: { + Item: { + Id: sdkItem.Id, + Provider: sdkItem.Provider + }, + FitToContainer: false, + ImageSize: ImageDisplayMode.OriginalSize, + Title: 'custom title' + }, + assert: async (element) => { + await waitFor(() => { + expect(element).toMatchSnapshot(); + }); + } + }); +}); +test('Image with selected image item', async () => { await WidgetTester.testWidgetRender({ name: 'SitefinityImage', properties: { Item: { - Id: imageItem.Id, - Provider: imageItem.Provider + Id: sdkItem.Id, + Provider: sdkItem.Provider } }, assert: async (element) => {