Integrating install prompt on index page

This commit is contained in:
Jeff Avallone 2019-01-15 21:08:07 -05:00
parent e77763d0b0
commit 8c312a450c
3 changed files with 195 additions and 0 deletions

View File

@ -42,6 +42,94 @@ exports[`Index Page rendering 1`] = `
</Fragment> </Fragment>
`; `;
exports[`Index Page rendering after an install prompt has been requested 1`] = `
<Fragment>
<Metadata />
<noscript>
<Message
heading="JavaScript Required"
type="error"
>
<p>
You need JavaScript to use Regexper.
</p>
<p>
If you have concerns regarding the use of tracking code on Regexper, please see the
<mockConstructor
to="/privacy"
>
Privacy Policy
</mockConstructor>
.
</p>
</Message>
</noscript>
<App
expr=""
permalinkUrl={null}
syntax="testJs"
syntaxList={
Array [
Object {
"id": "testJS",
"name": "Testing JS",
},
Object {
"id": "other",
"name": "Other",
},
]
}
/>
</Fragment>
`;
exports[`Index Page rendering after an install prompt has been requested 2`] = `
<Fragment>
<Metadata />
<noscript>
<Message
heading="JavaScript Required"
type="error"
>
<p>
You need JavaScript to use Regexper.
</p>
<p>
If you have concerns regarding the use of tracking code on Regexper, please see the
<mockConstructor
to="/privacy"
>
Privacy Policy
</mockConstructor>
.
</p>
</Message>
</noscript>
<App
expr=""
permalinkUrl={null}
syntax="testJs"
syntaxList={
Array [
Object {
"id": "testJS",
"name": "Testing JS",
},
Object {
"id": "other",
"name": "Other",
},
]
}
/>
<InstallPrompt
onAccept={[Function]}
onReject={[Function]}
/>
</Fragment>
`;
exports[`Index Page rendering with an expression on the URL 1`] = ` exports[`Index Page rendering with an expression on the URL 1`] = `
<Fragment> <Fragment>
<Metadata /> <Metadata />

View File

@ -6,6 +6,7 @@ import URLSearchParams from '@ungap/url-search-params';
import Metadata from 'components/Metadata'; import Metadata from 'components/Metadata';
import Message from 'components/Message'; import Message from 'components/Message';
import App from 'components/App'; import App from 'components/App';
import InstallPrompt from 'components/InstallPrompt';
export const query = graphql` export const query = graphql`
query IndexPageQuery { query IndexPageQuery {
@ -40,6 +41,10 @@ const readURLHash = (location, defaultSyntax) => {
}; };
class IndexPage extends React.PureComponent { class IndexPage extends React.PureComponent {
state={
installPrompt: null
}
static propTypes = { static propTypes = {
location: PropTypes.object, location: PropTypes.object,
data: PropTypes.shape({ data: PropTypes.shape({
@ -55,7 +60,37 @@ class IndexPage extends React.PureComponent {
}) })
} }
componentDidMount() {
window.addEventListener('beforeinstallprompt', this.handleInstallPrompt);
}
componentWillUnmount() {
window.removeEventListener('beforeinstallprompt', this.handleInstallPrompt);
}
handleInstallPrompt = event => {
event.preventDefault();
this.setState({
installPrompt: event
});
}
handleInstallReject = () => {
this.setState({ installPrompt: null });
}
handleInstallAccept = () => {
const { installPrompt } = this.state;
this.setState({ installPrompt: null });
installPrompt.prompt();
}
render() { render() {
const {
installPrompt
} = this.state;
const { const {
location, location,
data: { site: { siteMetadata } } data: { site: { siteMetadata } }
@ -75,6 +110,9 @@ class IndexPage extends React.PureComponent {
<App <App
syntaxList={ siteMetadata.syntaxList } syntaxList={ siteMetadata.syntaxList }
{ ...readURLHash(location, siteMetadata.defaultSyntax) } /> { ...readURLHash(location, siteMetadata.defaultSyntax) } />
{ installPrompt && <InstallPrompt
onAccept={ this.handleInstallAccept }
onReject={ this.handleInstallReject } /> }
</>; </>;
} }
} }

View File

@ -32,4 +32,73 @@ describe('Index Page', () => {
); );
expect(component).toMatchSnapshot(); expect(component).toMatchSnapshot();
}); });
test('rendering after an install prompt has been requested', () => {
const component = shallow(
<IndexPage location={{ hash: '' }} data={ queryResult } />
);
expect(component).toMatchSnapshot();
component.instance().handleInstallPrompt({
preventDefault: jest.fn(),
prompt: jest.fn()
});
expect(component).toMatchSnapshot();
});
test('removing event listener on umount', () => {
jest.spyOn(window, 'addEventListener');
jest.spyOn(window, 'removeEventListener');
const component = shallow(
<IndexPage location={{ hash: '' }} data={ queryResult } />
);
expect(window.addEventListener).toHaveBeenCalledWith(
'beforeinstallprompt',
expect.any(Function));
component.unmount();
expect(window.removeEventListener).toHaveBeenCalledWith(
'beforeinstallprompt',
expect.any(Function));
});
test('rejecting install prompt', () => {
const component = shallow(
<IndexPage location={{ hash: '' }} data={ queryResult } />
);
const instance = component.instance();
const installEvent = {
preventDefault: jest.fn(),
prompt: jest.fn()
};
instance.handleInstallPrompt(installEvent);
instance.handleInstallReject();
expect(installEvent.prompt).not.toHaveBeenCalled();
expect(component.state('installPrompt')).toEqual(null);
});
test('accepting install prompt', () => {
const component = shallow(
<IndexPage location={{ hash: '' }} data={ queryResult } />
);
const instance = component.instance();
const installEvent = {
preventDefault: jest.fn(),
prompt: jest.fn()
};
instance.handleInstallPrompt(installEvent);
instance.handleInstallAccept();
expect(installEvent.prompt).toHaveBeenCalled();
expect(component.state('installPrompt')).toEqual(null);
});
}); });