Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
29 changes: 29 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 @@ -86,6 +88,33 @@ describe('typedUnion', () => {
);
});

it('validates when nested in a union including primitives', () => {
const stringUnion = nullUnion([
string(),
typedUnion([TextStruct, BoldStruct]),
]);

// @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 nonTypedObjectUnion = nullUnion([
typedUnion([TextStruct, BoldStruct]),
object({ type: literal('bar') }),
]);

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
58 changes: 37 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 ItalicStruct as unknown as Struct<
SnapElement<JsonObject, 'Italic'>
>;
}),
]),
});

Expand All @@ -628,10 +632,13 @@ 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 BoldStruct as unknown as Struct<SnapElement<JsonObject, 'Bold'>>;
}),
]),
});

Expand Down Expand Up @@ -774,11 +781,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 +910,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