Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WEB-3418] - Enable Safari on Mobile [DON'T MERGE] #1513

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
16 changes: 14 additions & 2 deletions app/core/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,29 @@ utils.isSupportedBrowser = () => {
const userAgent = navigator.userAgent.toLowerCase();

const isOpera = userAgent.indexOf('opr') > -1;
const isBrave = userAgent.indexOf('brave') > -1;
const isFirefox = userAgent.indexOf('firefox') > -1;
const isFirefoxIOS = userAgent.indexOf('fxios') > -1;

if (isOpera) return false;
if (isOpera || isBrave || isFirefox || isFirefoxIOS) return false;

const isEdgeIOS = userAgent.indexOf('edgios') > -1;
const isChrome = userAgent.indexOf('chrome') > -1;
const isChromeIOS = userAgent.indexOf('crios') > -1;
const isSafariIOS = userAgent.indexOf('safari') > -1 && /iphone|ipad/.test(userAgent);

return isChrome || isChromeIOS;
if (isChrome || isChromeIOS || isEdgeIOS || isSafariIOS) return true;

return false;
};

utils.isMobile = () => {
var userAgent = navigator.userAgent.toLowerCase();

const isIOSDevice = /iphone|ipad/.test(userAgent);

if (isIOSDevice) return true;

return (userAgent.indexOf('mobi') > -1);
};

Expand Down
7 changes: 4 additions & 3 deletions test/unit/bootstrap.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import appContext from '../../app/bootstrap';

describe('appContext', () => {
before(() => {
Object.defineProperty(window.navigator, 'userAgent', { value: 'Mozilla/5.0 .. truncated .. Chrome/131.0.0.0' });
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36';
Object.defineProperty(window.navigator, 'userAgent', { value: userAgent, configurable: true });
Copy link
Contributor Author

@henry-tp henry-tp Feb 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They key change here is the addition of configurable: true. I found that if configurable is not set to true, Object.defineProperty() cannot be called again with window.navigator, so setting configurable: true allows us to re-define the property.

Unfortunately, defineProperty is called in one file, the effect seems to bleed into other test files as well, as the test runner is not restarting for every new file. That's why I needed to make an adjustment here.


appContext.api = {
metrics: {
Expand Down Expand Up @@ -42,12 +43,12 @@ describe('appContext', () => {
[loggedInUserId]: { username: '[email protected]', roles: ['clinician'] },
};

appContext.store.getState.returns({
appContext.store.getState.returns({
blip: {
selectedClinicId,
loggedInUserId,
allUsersMap,
},
},
});

appContext.trackMetric('someMetric2');
Expand Down
3 changes: 2 additions & 1 deletion test/unit/redux/utils/trackingMiddleware.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ describe('trackingMiddleware', () => {
const next = sinon.stub();

beforeEach(() => {
Object.defineProperty(window.navigator, 'userAgent', { value: 'Mozilla/5.0 .. truncated .. Chrome/131.0.0.0' });
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36';
Object.defineProperty(window.navigator, 'userAgent', { value: userAgent, configurable: true });
api.metrics.track.resetHistory();
});

Expand Down
98 changes: 98 additions & 0 deletions test/unit/utils/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/* global it */
/* global context */
/* global sinon */
/* global after */
/* global afterEach */
/* global assert */

Expand All @@ -14,6 +15,11 @@ import releases from '../../fixtures/githubreleasefixture';
const expect = chai.expect;

describe('utils', () => {
after(() => {
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36';
Object.defineProperty(window.navigator, 'userAgent', { value: userAgent, configurable: true });
});

describe('capitalize', () => {
it('should return a capitalized string', () => {
expect(utils.capitalize('lower')).to.equal('Lower');
Expand Down Expand Up @@ -72,6 +78,98 @@ describe('utils', () => {
});
});

const USER_AGENTS = {
chromeWin: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
chromeMac: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
chromeIPad: 'Mozilla/5.0 (iPad; CPU OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/133.0.6943.33 Mobile/15E148 Safari/604.1',
chromeIPhone: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/133.0.6943.33 Mobile/15E148 Safari/604.1',
chromeAndroid: 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.6943.49 Mobile Safari/537.36',

firefoxWin: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0',
firefoxMac: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.7; rv:135.0) Gecko/20100101 Firefox/135.0',
firefoxIPhone: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/135.0 Mobile/15E148 Safari/605.1.15',
firefoxAndroid: 'Mozilla/5.0 (Android 15; Mobile; rv:135.0) Gecko/135.0 Firefox/135.0',

edgeWin: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/131.0.2903.86',
edgeMac: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/131.0.2903.86',
edgeAndroid: 'Mozilla/5.0 (Linux; Android 10; HD1913) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.6943.49 Mobile Safari/537.36 EdgA/131.0.2903.87',
edgeIPhone: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 EdgiOS/131.2903.92 Mobile/15E148 Safari/605.1.15',

safariMac: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_7_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15',
safariIPhone: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Mobile/15E148 Safari/604.1',
safariIPad: 'Mozilla/5.0 (iPad; CPU OS 17_7_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Mobile/15E148 Safari/604.1',
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the value / longevity of these tests given that they capture only a specific device. But I feel like we should have something.


describe('isSupportedBrowser', () => {
it('returns true for only supported devices', () => {
_.each(Object.values(USER_AGENTS), userAgent => {
Object.defineProperty(window.navigator, 'userAgent', { value: userAgent, configurable: true });

switch(userAgent) {
case USER_AGENTS.chromeWin:
case USER_AGENTS.chromeMac:
case USER_AGENTS.chromeIPad:
case USER_AGENTS.chromeIPhone:
case USER_AGENTS.chromeAndroid:
case USER_AGENTS.edgeWin:
case USER_AGENTS.edgeMac:
case USER_AGENTS.edgeAndroid:
case USER_AGENTS.edgeIPhone:
case USER_AGENTS.safariIPhone:
case USER_AGENTS.safariIPad:
expect(utils.isSupportedBrowser()).to.be.true;
break;

case USER_AGENTS.firefoxWin:
case USER_AGENTS.firefoxMac:
case USER_AGENTS.firefoxIPhone:
case USER_AGENTS.firefoxAndroid:
case USER_AGENTS.safariMac:
expect(utils.isSupportedBrowser()).to.be.false;
break;

default:
throw new Error('Each string in USER_AGENTS should have an expected result in the test');
}
});
});
});

describe('isMobile', () => {
it('returns true for only supported devices', () => {
_.each(Object.values(USER_AGENTS), userAgent => {
Object.defineProperty(window.navigator, 'userAgent', { value: userAgent, configurable: true });

switch(userAgent) {
case USER_AGENTS.chromeIPad:
case USER_AGENTS.chromeIPhone:
case USER_AGENTS.chromeAndroid:
case USER_AGENTS.edgeAndroid:
case USER_AGENTS.edgeIPhone:
case USER_AGENTS.safariIPhone:
case USER_AGENTS.safariIPad:
case USER_AGENTS.firefoxIPhone:
case USER_AGENTS.firefoxAndroid:
expect(utils.isMobile()).to.be.true;
break;

case USER_AGENTS.chromeWin:
case USER_AGENTS.chromeMac:
case USER_AGENTS.edgeWin:
case USER_AGENTS.edgeMac:
case USER_AGENTS.firefoxWin:
case USER_AGENTS.firefoxMac:
case USER_AGENTS.safariMac:
expect(utils.isMobile()).to.be.false;
break;

default:
throw new Error('Each string in USER_AGENTS should have an expected result in the test');
}
});
});
});

describe('validateEmail', () => {
it('should validate [email protected] as email', () => {
expect(utils.validateEmail('[email protected]')).to.be.true;
Expand Down