Skip to content

Commit

Permalink
[ASL-4413] Snippets will continue falling back if non-string template…
Browse files Browse the repository at this point in the history
… is found (#332)
  • Loading branch information
jeff-horton-ho-sas committed May 20, 2024
1 parent 6f50246 commit 51a14e9
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 11 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ukhomeoffice/asl-components",
"version": "13.5.0",
"version": "13.5.1",
"description": "React components for ASL layouts and elements",
"main": "src/index.jsx",
"styles": "styles/index.scss",
Expand Down
25 changes: 18 additions & 7 deletions src/snippet/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ import { connect } from 'react-redux';
import Markdown from '../markdown';
import { render } from 'mustache';

function getKeysToTry(primary, fallback) {
if (Array.isArray(fallback)) {
return [primary, ...fallback];
}

if(['string', 'number'].includes(typeof fallback)) {
return [primary, fallback];
}

return [primary];
}

function getTemplate(content, primary, fallback) {
const keysToTry = [primary, ...(Array.isArray(fallback) ? fallback : [fallback])];
const keysToTry = getKeysToTry(primary, fallback);

for (let key of keysToTry) {
const template = get(content, key);
if (template != undefined) {
if (typeof template === 'string') {
return template;
}
}
Expand All @@ -19,16 +31,15 @@ function getTemplate(content, primary, fallback) {

export const Snippet = ({ content, children, optional, fallback, ...props }) => {
const str = getTemplate(content, children, fallback);

if (str === undefined && optional) {
return null;

}

if (str === undefined) {
throw new Error(`Failed to lookup content snippet: ${children}`);
}
if (typeof str !== 'string') {
throw new Error(`Invalid content snippet for key ${children}: ${JSON.stringify(str)}`);
throw new Error(`Failed to lookup content snippet. Tried keys: ${JSON.stringify(getKeysToTry(children, fallback))}`);
}

const source = render(str, props);

return (
Expand Down
31 changes: 30 additions & 1 deletion src/snippet/index.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ describe('<Snippet />', () => {
* three`,
paragraphs: `one
two`
two`,
nested: {
string: 'nested string',
template: 'Hello {{ name }}'
}
};

test('does not include a wrapping element on single line input', () => {
Expand All @@ -42,6 +46,11 @@ two`
expect(wrapper.html()).toEqual(paragraphs);
});

test('will inject props as template variables', () => {
const wrapper = render(<div><Snippet content={content} name={"world"}>nested.template</Snippet></div>);
expect(wrapper.html()).toEqual('<span>Hello world</span>');
})

test('can accept single fallback', () => {
const wrapper = render(<div><Snippet content={content} fallback={'paragraphs'}>non.existent</Snippet></div>);
expect(wrapper.find('p').length).toEqual(2);
Expand All @@ -54,4 +63,24 @@ two`
expect(wrapper.html()).toEqual(paragraphs);
});

test('will error if no fallback matches content', () => {
expect(() => render(<div><Snippet content={content} fallback={['non.existent.2', 'missing']}>non.existent</Snippet></div>))
.toThrow('Failed to lookup content snippet. Tried keys: ["non.existent","non.existent.2","missing"]');
});

test('will return null if no content matches and the snippet is optional', () => {
const wrapper = render(<div><Snippet content={content} fallback={['non.existent.2', 'missing']} optional>non.existent</Snippet></div>);
expect(wrapper.html()).toEqual('');
});

test('errors if content at the specified key is not a string', () => {
expect(() => render(<div><Snippet content={content}>nested</Snippet></div>))
.toThrow('Failed to lookup content snippet. Tried keys: ["nested"]');
});

test('renders a fallback if content at the specified key is not a string', () => {
const wrapper = render(<div><Snippet content={content} fallback={'nested.string'}>nested</Snippet></div>);
expect(wrapper.html()).toEqual('<span>nested string</span>');
});

});

0 comments on commit 51a14e9

Please sign in to comment.