react-native-sensitive-info icon indicating copy to clipboard operation
react-native-sensitive-info copied to clipboard

Jest cannot read property setItem

Open zagoa opened this issue 6 years ago • 15 comments

I have a little problem with Jest. When I try to test a function using SInfo jest crash and says :

  TypeError: Cannot read property 'setItem' of undefined

Do you have any hint ?

zagoa avatar Oct 10 '18 14:10 zagoa

I had the same issue, i made a PR, which is already merged. Should be fixed in version 5.2.6. Could you check your version?

SebiVPS avatar Oct 10 '18 14:10 SebiVPS

Ok I was on 5.2.4, I upgrade this dependency but that change nothing. Did I miss something ?

zagoa avatar Oct 10 '18 16:10 zagoa

I'm still having this problem with the version "5.3.0"

NachoJusticia avatar Apr 18 '19 18:04 NachoJusticia

Same issue version 5.4.0, trying to make a mock.

TypeError: _reactNativeSensitiveInfo.default.deleteItem is not a function

lcorniglione avatar May 13 '19 13:05 lcorniglione

Similar issue with 5.4.1

TypeError: _reactNativeSensitiveInfo.default.getItem is not a function

zakdances avatar May 15 '19 18:05 zakdances

I am also having this issue when attempting:

const key = "buzzes"
    var value = JSON.stringify(this.state.buzzes)
    await SInfo.setItem(key, value, {});

TypeError: _reactNativeSensitiveInfo.default.getItem is not a function

konjoinfinity avatar Jul 17 '19 20:07 konjoinfinity

Well in my case

$ cd ios $ pod install $ cd ..

this works for me...

guitorioadar avatar Oct 20 '19 06:10 guitorioadar

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jun 10 '20 20:06 stale[bot]

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jul 10 '20 20:07 stale[bot]

I have a little problem with Jest. When I try to test a function using SInfo jest crash and says :

  TypeError: Cannot read property 'setItem' of undefined

Do you have any hint ?

I'm still having this issue with 6.0.0-alpha.6

atabariscanalp avatar Oct 05 '20 21:10 atabariscanalp

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Nov 04 '20 22:11 stale[bot]

You can create a mock for it. I created a simple one that satisfies my needs without needing to mock every function. Got some inspiration in @react-native-async-storage/async-storage mock.

__mocks__/react-native-sensitive-info.js:

const asMock = {
  __INTERNAL_MOCK_STORAGE__: {},

  getItem: jest.fn(async (key, options) => {
    const storeName = _getStoreName(options);

    const result = asMock.__INTERNAL_MOCK_STORAGE__[storeName]
      ? asMock.__INTERNAL_MOCK_STORAGE__[storeName][key]
      : undefined;

    return result;
  }),

  setItem: jest.fn(async (key, value, options) => {
    const storeName = _getStoreName(options);

    if (asMock.__INTERNAL_MOCK_STORAGE__[storeName] === undefined) {
      asMock.__INTERNAL_MOCK_STORAGE__[storeName] = {};
    }

    asMock.__INTERNAL_MOCK_STORAGE__[storeName][key] = value;
    return null;
  }),
};

const _getStoreName = options =>
  options.sharedPreferencesName || options.keychainService || 'default';

module.exports = asMock;

And when I need to mock a specific result in a test:

it('should mock', () => {
  const sensitiveInfoMock = jest.spyOn(RNSInfo, 'getItem');
  sensitiveInfoMock.mockImplementation(async () => 'specific value');

  // ... test

  sensitiveInfoMock.mockRestore();
});

If someone can mock all functions using the "options" object, I bet a PR would be welcome.

PS: The code above won't distinguish iOS and Android for sharedPreferencesName and keychainService due to _getStoreName implementation being unware of the current platform.

Rafatcb avatar Nov 12 '20 12:11 Rafatcb

Blind code so take it for what it is...

// __mocks__/react-native-sensitive-info.js

class RNSInfo {
	static stores = new Map()

	static getServiceName(o) {
		return o.sharedPreferencesName
			|| o.keychainService
			|| 'default'
	}

	static validateString(s){
		if (typeof s !== 'string') throw new Error('Invalid string:', s)
	}

	static getItem = jest.fn(async (k, o) => {
		RNSInfo.validateString(k)

		const serviceName = RNSInfo.getServiceName(o)
		const service = RNSInfo.stores.get(serviceName)

		if(service) return service.get(k) || null
	})

	static getAllItems = jest.fn(async (o) => {
		const serviceName = RNSInfo.getServiceName(o)
		const service = RNSInfo.stores.get(serviceName)
		const mappedValues = []

		if(service?.size){
			for(const [k, v] of service.entries()){
				mappedValues.push({key: k, value: v, service: serviceName})
			}
		}

		return mappedValues
	})

	static setItem = jest.fn(async (k, v, o) => {
		RNSInfo.validateString(k)
		RNSInfo.validateString(v)

		const serviceName = getServiceName(o)
		let service = RNSInfo.stores.get(serviceName)

		if (!service){
			RNSInfo.stores.set(serviceName, new Map())
			service = RNSInfo.stores.get(serviceName)
		}

		service.set(k, v)

		return null
	})

	static deleteItem = jest.fn(async (k, o) => {
		RNSInfo.validateString(k)

		const serviceName = RNSInfo.getServiceName(o)
		const service = RNSInfo.stores.get(serviceName)

		if (service) service.delete(k)

		return null
	})

	static hasEnrolledFingerprints = jest.fn(async () => true)

	static setInvalidatedByBiometricEnrollment = jest.fn()

	// "Touch ID" | "Face ID" | false
	static isSensorAvailable = jest.fn(async () => 'Face ID')
}

module.exports = RNSInfo

ingvardm avatar Aug 20 '21 09:08 ingvardm

For some reason writing the mocks as __mocks__/react-native-sensitive-info.js didn't work for me.

So I added it inside jest.setup.js file

jest.mock('react-native-sensitive-info', () => {
// your mock here
});

gabimoncha avatar Oct 11 '21 17:10 gabimoncha

Had to change the contents of __mocks__/@react-native-async-storage/async-storage.js to:

const asyncMock = require('@react-native-async-storage/async-storage/jest/async-storage-mock')
export default asyncMock

The import from the corresponding d.ts file is just the type, so AsyncStorage object is empty. Haven't looked into root causing this though.

daku avatar Sep 06 '23 01:09 daku