diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8bce85c1..2c111486 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
* [#431](https://github.com/shlinkio/shlink-web-client/pull/431) Added support to filter out visits from potential bots in visits sections, when consuming Shlink >=2.7.
* [#430](https://github.com/shlinkio/shlink-web-client/pull/430) Added support to set new and existing short URLs as crawlable, when consuming Shlink >=2.7.
* [#450](https://github.com/shlinkio/shlink-web-client/pull/450) Improved landing page design.
+* [#449](https://github.com/shlinkio/shlink-web-client/pull/449) Improved PWA update banner, allowing to restart the app directly from it without having to close the tab.
### Changed
* [#442](https://github.com/shlinkio/shlink-web-client/pull/442) Visits filtering now goes through the corresponding reducer.
diff --git a/test/common/AppUpdateBanner.test.tsx b/test/common/AppUpdateBanner.test.tsx
new file mode 100644
index 00000000..b03458b8
--- /dev/null
+++ b/test/common/AppUpdateBanner.test.tsx
@@ -0,0 +1,43 @@
+import { shallow, ShallowWrapper } from 'enzyme';
+import { Button } from 'reactstrap';
+import { AppUpdateBanner } from '../../src/common/AppUpdateBanner';
+import { SimpleCard } from '../../src/utils/SimpleCard';
+
+describe('', () => {
+ const toggle = jest.fn();
+ const forceUpdate = jest.fn();
+ let wrapper: ShallowWrapper;
+
+ beforeEach(() => {
+ wrapper = shallow();
+ });
+
+ afterEach(jest.clearAllMocks);
+ afterEach(() => wrapper?.unmount());
+
+ it('renders an alert with expected props', () => {
+ expect(wrapper.prop('className')).toEqual('app-update-banner');
+ expect(wrapper.prop('isOpen')).toEqual(true);
+ expect(wrapper.prop('toggle')).toEqual(toggle);
+ expect(wrapper.prop('tag')).toEqual(SimpleCard);
+ expect(wrapper.prop('color')).toEqual('secondary');
+ });
+
+ it('invokes toggle when alert is toggled', () => {
+ (wrapper.prop('toggle') as Function)(); // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
+
+ expect(toggle).toHaveBeenCalled();
+ });
+
+ it('triggers the update when clicking the button', () => {
+ expect(wrapper.find(Button).html()).toContain('Restart now');
+ expect(wrapper.find(Button).prop('disabled')).toEqual(false);
+ expect(forceUpdate).not.toHaveBeenCalled();
+
+ wrapper.find(Button).simulate('click');
+
+ expect(wrapper.find(Button).html()).toContain('Restarting...');
+ expect(wrapper.find(Button).prop('disabled')).toEqual(true);
+ expect(forceUpdate).toHaveBeenCalled();
+ });
+});