Intent:
- want to cycle through different combinations of the userAgent
- mock navigator
- run test
What is happening:
- I mock navigator.userAgent, mock happens as intended, first test runs as expected
- 2nd mock is run, but the test sees the userAgent value from the first mock
function to test:
export const isBrowseriOS = () => {
console.log(navigator.userAgent, ' & ', navigator.vendor);
return (
navigator.vendor === 'Apple Computer, Inc.' ||
(/iPad|iPhone|iPod/.test(navigator.userAgent) &&
!window.MSStream &&
'ontouchend' in document)
);
};
test file:
import { isBrowseriOS } from './isIOS';
const browserDevices = [
{
name: 'iPhone 12 Pro',
userAgent:
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
vendor: 'Apple Computer, Inc.',
iOSDevice: true,
},
{
name: 'Samsung SM-G955U',
userAgent:
'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Mobile Safari/537.36',
vendor: 'Google Inc.',
iOSDevice: false,
},
];
describe.each(browserDevices)('iOS test for $name', (device) => {
beforeEach(() => {
Object.defineProperty(window, 'navigator', {
value: {
userAgent: device.userAgent,
vendor: device.vendor,
},
});
});
afterEach(() => jest.resetAllMocks());
it(`returns ${device.iOSDevice}`, () => {
expect(isBrowseriOS()).toBe(device.iOSDevice);
});
});
CodePudding user response:
the key was using configurable: true,
inside beforeEach
and then resetting it to default inside afterEach
;
working solution below:
function:
declare global {
interface Window {
MSStream?: any;
}
}
export const isiOSDevice = () =>
navigator.vendor === 'Apple Computer, Inc.' ||
(/iPad|iPhone|iPod/.test(navigator.userAgent) &&
!window.MSStream &&
'ontouchend' in document);
test file:
import { isiOSDevice } from './isIOS';
const browserDevices = [
{
name: 'iPad Air',
userAgent:
'Mozilla/5.0 (iPad; CPU OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/87.0.4280.77 Mobile/15E148 Safari/604.1',
vendor: 'Apple Computer, Inc.',
iOSDevice: true,
},
{
name: 'Samsung SM-G955U',
userAgent:
'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Mobile Safari/537.36',
vendor: 'Google Inc.',
iOSDevice: false,
},
{
name: 'iPhone 12 Pro',
userAgent:
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
vendor: 'Apple Computer, Inc.',
iOSDevice: true,
},
{
name: 'Samsung SM-G981B',
userAgent:
'Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36',
vendor: 'Google Inc.',
iOSDevice: false,
},
{
name: 'Nest Hub Max',
userAgent:
'Mozilla/5.0 (X11; Linux aarch64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.188 Safari/537.36 CrKey/1.54.250320',
vendor: 'Google Inc.',
iOSDevice: false,
},
{
name: 'Windows Chrome',
userAgent:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
vendor: '',
iOSDevice: false,
},
{
name: 'Windows Firefox',
userAgent:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0',
vendor: '',
iOSDevice: false,
},
{
name: 'Windows edge',
userAgent:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62',
vendor: 'Google Inc.',
iOSDevice: false,
},
];
describe.each(browserDevices)('iOS test for $name', (device) => {
const { userAgent: originalUserAgent } = window.navigator;
beforeEach(() => {
Object.defineProperty(window, 'navigator', {
configurable: true,
writable: true,
value: { userAgent: device.userAgent, vendor: device.vendor },
});
});
afterEach(() => {
Object.defineProperty(window, 'navigator', {
configurable: true,
value: originalUserAgent,
});
});
it(`returns ${device.iOSDevice}`, () => {
expect(isiOSDevice()).toBe(device.iOSDevice);
});
});