diff --git a/src/routes/policy-playground/PolicyPlayground.tsx b/src/routes/policy-playground/PolicyPlayground.tsx index fb85403..7932fca 100644 --- a/src/routes/policy-playground/PolicyPlayground.tsx +++ b/src/routes/policy-playground/PolicyPlayground.tsx @@ -100,15 +100,26 @@ export default function PolicyPlayground() { const evaluateInput = () => { const { policy, entities, context, principal, action, resource, schema } = uiState; const start = performance.now(); - let parsedEntities: EntityJson[] = []; - let parsedContext: Context = {}; + const setParseError = (e: unknown) => + setOutput({ + status: 'error', + message: t('issueAuthRequest.parseError'), + errors: [(e as Error).message], + warnings: [], + }); + let parsedEntities: EntityJson[]; + let parsedContext: Context; try { parsedEntities = JSON.parse(entities) as EntityJson[]; + } catch (e) { + setParseError(e); + return; + } + try { parsedContext = JSON.parse(context) as Context; - } catch (_e) { - // Fall through: let wasm produce the error if JSON is invalid. - parsedEntities = []; - parsedContext = {}; + } catch (e) { + setParseError(e); + return; } const result = isAuthorized({ principal, diff --git a/tests/sandbox.test.tsx b/tests/sandbox.test.tsx index a322912..4bf0b71 100644 --- a/tests/sandbox.test.tsx +++ b/tests/sandbox.test.tsx @@ -7,6 +7,11 @@ import { IntlProvider } from 'react-intl'; import nestedMessages from '../src/translations/en.json'; import { flattenMessages } from '../src/util/flattenMessages'; import { getCedarVersion } from '@cedar-policy/cedar-wasm'; +import { + exportCedarPlaygroundDataToBase64, + PLAYGROUND_URL_FRAG_PREFIX, + CedarPlaygroundDataTransferObject, +} from '../src/playground-helpers'; const messages = flattenMessages(nestedMessages); @@ -84,4 +89,60 @@ describe('playground tests', () => { expect(cedarVersion).toBeDefined(); expect(cedarVersion).toEqual(expect.any(String)); }); + + it('should show error when entities JSON is invalid', async () => { + const dto: CedarPlaygroundDataTransferObject = { + interfaceVersion: 1, + cedarVersion: getCedarVersion(), + playgroundData: { + policy: 'permit(principal, action, resource);', + schema: '', + principal: { type: 'User', id: 'alice' }, + action: { type: 'Action', id: 'view' }, + resource: { type: 'Photo', id: 'photo1' }, + entities: 'not valid json [[[', + context: '{}', + isAVPFormat: false, + }, + }; + const exported = exportCedarPlaygroundDataToBase64(dto); + if ('error' in exported) throw new Error(exported.error); + window.location.hash = `#${PLAYGROUND_URL_FRAG_PREFIX}${exported.result}`; + const { unmount } = mountPlayground(); + try { + fireEvent.click(screen.getByTestId('evaluate-button')); + await screen.findByText(/Invalid context or entities input/); + } finally { + unmount(); + window.location.hash = ''; + } + }); + + it('should show error when context JSON is invalid', async () => { + const dto: CedarPlaygroundDataTransferObject = { + interfaceVersion: 1, + cedarVersion: getCedarVersion(), + playgroundData: { + policy: 'permit(principal, action, resource);', + schema: '', + principal: { type: 'User', id: 'alice' }, + action: { type: 'Action', id: 'view' }, + resource: { type: 'Photo', id: 'photo1' }, + entities: '[]', + context: '{invalid context}', + isAVPFormat: false, + }, + }; + const exported = exportCedarPlaygroundDataToBase64(dto); + if ('error' in exported) throw new Error(exported.error); + window.location.hash = `#${PLAYGROUND_URL_FRAG_PREFIX}${exported.result}`; + const { unmount } = mountPlayground(); + try { + fireEvent.click(screen.getByTestId('evaluate-button')); + await screen.findByText(/Invalid context or entities input/); + } finally { + unmount(); + window.location.hash = ''; + } + }); });