Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/snaps-sdk/src/internals/structs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
any,
} from '@metamask/superstruct';

import { nullUnion } from './jsx';
import {
enumValue,
literal,
Expand All @@ -18,6 +19,7 @@ import {
import type { BoxElement } from '../jsx';
import { Footer, Icon, Text, Button, Box } from '../jsx';
import {
BoldStruct,
BoxStruct,
FieldStruct,
FooterStruct,
Expand Down Expand Up @@ -67,6 +69,14 @@ describe('typedUnion', () => {
BoxStruct,
typedUnion([TextStruct, FieldStruct]),
]);
const stringUnion = nullUnion([
string(),
typedUnion([TextStruct, BoldStruct]),
]);
const nonTypedObjectUnion = nullUnion([
typedUnion([TextStruct, BoldStruct]),
object({ type: literal('bar') }),
]);

it('validates strictly the part of the union that matches the type', () => {
// @ts-expect-error Invalid props.
Expand All @@ -86,6 +96,23 @@ describe('typedUnion', () => {
);
});

it('validates when nested in a union including primitives', () => {
// @ts-expect-error Invalid props.
const result = validate(Text({}), stringUnion);

expect(result[0]?.message).toBe(
'Expected the value to satisfy a union of `string | union`, but received: [object Object]',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was this message before? This doesn't seem ideal either 😅

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mostly for coverage purposes, not to actually test the error messages. We want to ensure that typedUnion doesn't do something unexpected when *entries is called with a string for example

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E.g.

if (
!isObject(value) ||
!hasProperty(value, 'type') ||
typeof value.type !== 'string'
) {
return;
}

);
});

it('validates when nested in a union including non-typed objects', () => {
const result = validate({ type: 'abc' }, nonTypedObjectUnion);

expect(result[0]?.message).toBe(
'Expected the value to satisfy a union of `union | object`, but received: [object Object]',
);
});

it('validates refined elements', () => {
const refinedUnionStruct = typedUnion([BoxStruct, FooterStruct]);
const result = validate(
Expand Down
60 changes: 39 additions & 21 deletions packages/snaps-sdk/src/jsx/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,11 +615,15 @@ export const FieldStruct: Describe<FieldElement> = element('Field', {
*/
export const BoldStruct: Describe<BoldElement> = element('Bold', {
children: children([
string(),
// eslint-disable-next-line @typescript-eslint/no-use-before-define
lazy(() => ItalicStruct) as unknown as Struct<
SnapElement<JsonObject, 'Italic'>
>,
selectiveUnion((value) => {
if (typeof value === 'string') {
return string();
}
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return lazy(() => ItalicStruct) as unknown as Struct<
SnapElement<JsonObject, 'Italic'>
>;
}),
]),
});

Expand All @@ -628,10 +632,15 @@ export const BoldStruct: Describe<BoldElement> = element('Bold', {
*/
export const ItalicStruct: Describe<ItalicElement> = element('Italic', {
children: children([
string(),
lazy(() => BoldStruct) as unknown as Struct<
SnapElement<JsonObject, 'Bold'>
>,
selectiveUnion((value) => {
if (typeof value === 'string') {
return string();
}

return lazy(() => BoldStruct) as unknown as Struct<
SnapElement<JsonObject, 'Bold'>
>;
}),
]),
});

Expand Down Expand Up @@ -774,11 +783,18 @@ export const HeadingStruct: Describe<HeadingElement> = element('Heading', {
export const LinkStruct: Describe<LinkElement> = element('Link', {
href: string(),
children: children([
FormattingStruct,
string(),
IconStruct,
ImageStruct,
AddressStruct,
selectiveUnion((value) => {
if (typeof value === 'string') {
return string();
}

return typedUnion([
FormattingStruct,
IconStruct,
ImageStruct,
AddressStruct,
]);
}),
]),
});

Expand Down Expand Up @@ -896,13 +912,15 @@ export const TooltipStruct: Describe<TooltipElement> = element('Tooltip', {
*/
export const BannerStruct: Describe<BannerElement> = element('Banner', {
children: children([
TextStruct,
LinkStruct,
IconStruct,
ButtonStruct,
BoldStruct,
ItalicStruct,
SkeletonStruct,
typedUnion([
TextStruct,
LinkStruct,
IconStruct,
ButtonStruct,
BoldStruct,
ItalicStruct,
SkeletonStruct,
]),
]),
title: string(),
severity: union([
Expand Down
Loading