diff --git a/__tests__/components/__snapshots__/components.test.js.snap b/__tests__/components/__snapshots__/components.test.js.snap index ad718fd..11db7c9 100644 --- a/__tests__/components/__snapshots__/components.test.js.snap +++ b/__tests__/components/__snapshots__/components.test.js.snap @@ -302,8 +302,27 @@ Array [ ] `; +exports[`test Collect And Reveal Elements Components test RevealElement component rendering 1`] = ` +Array [ + + Card Number + , + + XXXX XXXX XXXX XXXX + , + , +] +`; + exports[`test Collect And Reveal Elements Components test skyflow provider 1`] = ` - Provider Childern + Provider Children `; diff --git a/__tests__/components/components.test.js b/__tests__/components/components.test.js index aa2fb49..207df89 100644 --- a/__tests__/components/components.test.js +++ b/__tests__/components/components.test.js @@ -21,6 +21,7 @@ import { Text } from 'react-native'; import SkyflowError from '../../src/utils/skyflow-error'; import SKYFLOW_ERROR_CODE from '../../src/utils/skyflow-error-code'; import { ContainerType, ElementType } from '../../src/utils/constants'; +import { act } from 'react-test-renderer'; const testSkyflowClient = new Skyflow({ vaultID: '1234', @@ -598,6 +599,84 @@ describe('test Collect And Reveal Elements Components', () => { } }); + it('test RevealElement component rendering', () => { + const revealSetMethodMock = jest.fn(); + const revealSetTokenMock = jest.fn(); + const revealContainer = new RevealContainer(testSkyflowClient); + + jest.spyOn(revealContainer, 'create').mockImplementation(() => ({ + setMethods: revealSetMethodMock, + setToken: revealSetTokenMock, + })); + + const revealElement = render( + + ); + + expect(revealElement).toMatchSnapshot(); + expect(revealSetMethodMock).toBeCalledTimes(1); + + render( + + ); + expect(screen.getByText('test_token_no_alt')).toBeTruthy(); + + try { + render(); + } catch (err) { + expect(err).toEqual( + new SkyflowError( + SKYFLOW_ERROR_CODE.CONTAINER_OBJECT_IS_REQUIRED, + ['Reveal', 'useRevealContainer()'], + true + ) + ); + } + }); + + it('test RevealElement setToken via ref updates UI and internal element', () => { + const revealSetMethodMock = jest.fn(); + const revealSetTokenMock = jest.fn(); + const revealContainer = new RevealContainer(testSkyflowClient); + + jest.spyOn(revealContainer, 'create').mockImplementation(() => ({ + setMethods: revealSetMethodMock, + setToken: revealSetTokenMock, + })); + + const ref = React.createRef(); + const initialToken = 'initial_token_123'; + const newToken = 'updated_token_456'; + + const { getByText } = render( + + ); + + expect(getByText(initialToken)).toBeTruthy(); + + act(() => { + ref.current.setToken(newToken); + }); + + expect(revealSetTokenMock).toHaveBeenCalledWith(newToken); + + expect(getByText(newToken)).toBeTruthy(); + }); + it('test skyflow provider', () => { const testSkyflowConfig = { vaultID: '1234', @@ -607,7 +686,7 @@ describe('test Collect And Reveal Elements Components', () => { const providerElement = render( - Provider Childern + Provider Children ); expect(providerElement).toMatchSnapshot(); diff --git a/__tests__/core/RevealContainer.test.js b/__tests__/core/RevealContainer.test.js index a126ee6..9fb5530 100644 --- a/__tests__/core/RevealContainer.test.js +++ b/__tests__/core/RevealContainer.test.js @@ -146,4 +146,56 @@ describe('test RevealConatiner Class', () => { } }); }); + + it('test reveal method uses updated token when setToken is called', (done) => { + const initialToken = 'initial_token'; + const updatedToken = 'updated_token'; + + const revealElement = revealContainer.create({ + token: initialToken, + }); + + const revealSuccessValue = { + records: [ + { + token: updatedToken, + value: 'revealed_value', + }, + ], + }; + + const fetchSpy = jest + .spyOn(revealUtils, 'fetchRecordsByTokenId') + .mockResolvedValue(revealSuccessValue); + + const setValueMock = jest.fn(); + const setErrorMock = jest.fn(); + revealElement.setMethods(setValueMock, setErrorMock); + + revealElement.setToken(updatedToken); + + revealContainer + .reveal() + .then((res) => { + try { + expect(fetchSpy).toHaveBeenCalledWith( + expect.anything(), + expect.arrayContaining([ + expect.objectContaining({ + token: updatedToken, + elementId: revealElement.elementId, + }), + ]) + ); + + expect(res).toEqual({ success: [{ token: updatedToken }] }); + done(); + } catch (assertionError) { + done(assertionError); + } + }) + .catch((err) => { + done(err); + }); + }); }); diff --git a/src/components/RevealElement/index.tsx b/src/components/RevealElement/index.tsx index d08872a..41ab521 100644 --- a/src/components/RevealElement/index.tsx +++ b/src/components/RevealElement/index.tsx @@ -1,16 +1,16 @@ /* Copyright (c) 2022 Skyflow, Inc. */ -import React, { useEffect } from "react"; +import React, { useEffect, useImperativeHandle, forwardRef } from "react"; import { Text } from "react-native"; import RevealSkyflowElement from "../../core/RevealSkyflowElement"; import { RevealElementProps } from "../../utils/constants" import SkyflowError from "../../utils/skyflow-error"; import SKYFLOW_ERROR_CODE from "../../utils/skyflow-error-code"; - -const RevealElement: React.FC = ({ container, label, ...rest }) => { - const [element, setElement] = React.useState(undefined); +const RevealElement = forwardRef((props: RevealElementProps, ref) => { + const { container, label, ...rest } = props; + const [element, setElement] = React.useState(undefined); const [errorText, setErrorText] = React.useState(''); const [value, setValue] = React.useState(rest?.altText || rest.token); @@ -25,12 +25,26 @@ const RevealElement: React.FC = ({ container, label, ...rest }, []); - return <> - {label} - {value} - {errorText} - + useImperativeHandle(ref, () => ({ + setToken: (newToken: string) => { + if (element) { + element.setToken(newToken); + setValue(newToken); + } else { + throw new SkyflowError(SKYFLOW_ERROR_CODE.ELEMENT_NOT_FOUND, ['RevealElement'], true); + } + } + }), [element]); + + return ( + <> + {label} + {value} + {errorText} + + ); +}); -} +RevealElement.displayName = 'RevealElement'; export default RevealElement; \ No newline at end of file diff --git a/src/core/RevealContainer/index.ts b/src/core/RevealContainer/index.ts index 35552ae..bd20cc4 100644 --- a/src/core/RevealContainer/index.ts +++ b/src/core/RevealContainer/index.ts @@ -70,7 +70,22 @@ class RevealContainer extends Container { try { validateInitConfig(this.#skyflowClient.getSkyflowConfig()); validateRevealElementRecords(this.#revealRecords); - fetchRecordsByTokenId(this.#skyflowClient, this.#tokensList).then( + + const freshTokensList = this.#tokensList.map((record) => { + const elementInstance = this.#elementList.find( + (e) => e.elementId === record.elementId + ); + + if (elementInstance) { + return { + ...record, + token: elementInstance.getToken(), + }; + } + return record; + }); + + fetchRecordsByTokenId(this.#skyflowClient, freshTokensList).then( (resolvedResult) => { const formattedResult = formatRecordsForIframe(resolvedResult); this.setRevealValuesInElements(formattedResult); diff --git a/src/core/RevealSkyflowElement/index.ts b/src/core/RevealSkyflowElement/index.ts index bd4986c..c56e984 100644 --- a/src/core/RevealSkyflowElement/index.ts +++ b/src/core/RevealSkyflowElement/index.ts @@ -27,6 +27,10 @@ class RevealSkyflowElement extends SkyflowElement { this.#setErrorText(REVEAL_ELEMENT_ERROR_TEXT); } + setToken(newToken: string) { + this.#token = newToken; + } + getToken() { return this.#token; } diff --git a/src/utils/logs/index.ts b/src/utils/logs/index.ts index fb6a125..622246f 100644 --- a/src/utils/logs/index.ts +++ b/src/utils/logs/index.ts @@ -133,6 +133,8 @@ const logs = { `Skyflow ${SDK_NAME_VERSION} initialization failed - SkyflowProvider config is missing. `, CONTAINER_OBJECT_IS_REQUIRED: `${SDK_NAME_VERSION} cannot create %s1 element without container object, create a container using %s2 hook.`, + ELEMENT_NOT_FOUND: + `${SDK_NAME_VERSION} %s1 not found. The specified element does not exist in the container.`, INVALID_UPSERT_OPTION_TYPE: `${SDK_NAME_VERSION} Validation error. Invalid \'upsert\' key in insert options. Specify a value of type array instead`, EMPTY_UPSERT_OPTIONS_ARRAY: diff --git a/src/utils/skyflow-error-code/index.ts b/src/utils/skyflow-error-code/index.ts index 14e93eb..333351f 100644 --- a/src/utils/skyflow-error-code/index.ts +++ b/src/utils/skyflow-error-code/index.ts @@ -190,6 +190,10 @@ const SKYFLOW_ERROR_CODE = { code: 400, description: logs.errorLogs.CONTAINER_OBJECT_IS_REQUIRED, }, + ELEMENT_NOT_FOUND: { + code: 400, + description: logs.errorLogs.ELEMENT_NOT_FOUND, + }, INVALID_UPSERT_OPTION_TYPE: { code: 400, description: logs.errorLogs.INVALID_UPSERT_OPTION_TYPE,