Skip to content

Commit

Permalink
Fix race condition with rapid src changes
Browse files Browse the repository at this point in the history
  • Loading branch information
gilbarbara committed May 2, 2021
1 parent 3c280f3 commit 2659e48
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 2 deletions.
65 changes: 65 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"react-from-dom": "^0.6.0"
},
"devDependencies": {
"@gilbarbara/helpers": "^0.2.0",
"@gilbarbara/tsconfig": "^0.1.0",
"@size-limit/preset-small-lib": "^4.10.2",
"@types/enzyme": "^3.10.8",
Expand Down
7 changes: 7 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,13 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
return response.text();
})
.then((content) => {
const { src: currentSrc } = this.props;

// the current src don't match the previous one, skipping...
if (src !== currentSrc) {
return;
}

this.handleLoad(content);

/* istanbul ignore else */
Expand Down
26 changes: 26 additions & 0 deletions test/__snapshots__/index.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2206,6 +2206,32 @@ exports[`react-inlinesvg cached requests should skip the cache if \`cacheRequest
</svg>
`;
exports[`react-inlinesvg integration should handle race condition with fast src changes 1`] = `
<svg width="256px"
height="256px"
viewbox="0 0 256 256"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
preserveaspectratio="xMidYMid"
>
<g>
<path d="M0,0 L256,0 L256,256 L0,256 L0,0 Z"
fill="#F7DF1E"
>
</path>
<path d="M67.311746,213.932292 L86.902654,202.076241 C90.6821079,208.777346 94.1202286,214.447137 102.367086,214.447137 C110.272203,214.447137 115.256076,211.354819 115.256076,199.326883 L115.256076,117.528787 L139.313575,117.528787 L139.313575,199.666997 C139.313575,224.58433 124.707759,235.925943 103.3984,235.925943 C84.1532952,235.925943 72.9819429,225.958603 67.3113397,213.93026"
fill="#000000"
>
</path>
<path d="M152.380952,211.354413 L171.969422,200.0128 C177.125994,208.433981 183.827911,214.619835 195.684368,214.619835 C205.652521,214.619835 212.009041,209.635962 212.009041,202.762159 C212.009041,194.513676 205.479416,191.592025 194.481168,186.78207 L188.468419,184.202565 C171.111213,176.81473 159.597308,167.53534 159.597308,147.944838 C159.597308,129.901308 173.344508,116.153295 194.825752,116.153295 C210.119924,116.153295 221.117765,121.48094 229.021663,135.400432 L210.29059,147.428775 C206.166146,140.040127 201.699556,137.119289 194.826159,137.119289 C187.78047,137.119289 183.312254,141.587098 183.312254,147.428775 C183.312254,154.646349 187.78047,157.568406 198.089956,162.036622 L204.103924,164.614095 C224.553448,173.378641 236.067352,182.313448 236.067352,202.418387 C236.067352,224.071924 219.055137,235.927975 196.200432,235.927975 C173.860978,235.927975 159.425829,225.274311 152.381359,211.354413"
fill="#000000"
>
</path>
</g>
</svg>
`;
exports[`react-inlinesvg with errors should trigger an error and render the fallback children if src is not found 1`] = `
<div class="missing">
<span>
Expand Down
65 changes: 63 additions & 2 deletions test/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import { poll } from '@gilbarbara/helpers';
import { mount, ReactWrapper } from 'enzyme';
import fetchMock from 'jest-fetch-mock';

Expand Down Expand Up @@ -50,8 +51,6 @@ function setup({ onLoad, ...rest }: Props): Promise<ReactWrapper<Props>> {
{...rest}
/>,
);

return wrapper;
});
}

Expand Down Expand Up @@ -387,6 +386,68 @@ describe('react-inlinesvg', () => {
});
});

describe('integration', () => {
it('should handle race condition with fast src changes', async () => {
const mockOnLoad = jest.fn();

const wrapper = mount(
<ReactInlineSVG cacheRequests={false} src={fixtures.react} onLoad={mockOnLoad} />,
);

wrapper.setProps({ src: fixtures.url2 });

await poll(() => !!mockOnLoad.mock.calls.length);
wrapper.update();

expect(mockOnLoad).toHaveBeenCalledWith(fixtures.url2, false);
expect(wrapper.html()).toMatchSnapshot();
});

it('should render multiple SVGs', async () => {
const mockOnLoad = jest.fn();

const multiSetup: () => Promise<ReactWrapper<any>> = () => {
return new Promise((resolve) => {
const onLoad = (wrapper: any, ...rest: any[]) => {
mockOnLoad(...rest);

if (mockOnLoad.mock.calls.length === 4) {
resolve(wrapper);
}
};

const wrapper = mount(
<div>
<ReactInlineSVG
cacheRequests={false}
src={fixtures.react}
onLoad={(...args) => onLoad(wrapper, ...args)}
/>
<ReactInlineSVG
cacheRequests={false}
src={fixtures.circles}
onLoad={(...args) => onLoad(wrapper, ...args)}
/>
<ReactInlineSVG
cacheRequests={false}
src={fixtures.dots}
onLoad={(...args) => onLoad(wrapper, ...args)}
/>
<ReactInlineSVG
cacheRequests={false}
src={fixtures.datahref}
onLoad={(...args) => onLoad(wrapper, ...args)}
/>
</div>,
);
});
};

await multiSetup();
expect(mockOnLoad).toHaveBeenCalledTimes(4);
});
});

describe('with errors', () => {
beforeEach(() => {
mockOnError.mockClear();
Expand Down

0 comments on commit 2659e48

Please sign in to comment.