From 82daa89ea0b6274ee864aca71f0d87ec0fe47d4c Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Thu, 18 Dec 2025 13:30:04 +0530 Subject: [PATCH 1/3] SK-2050: set tokens in reveal elements --- __tests__/components/components.test.js | 79 +++++++++++++++++++++++++ __tests__/core/RevealContainer.test.js | 52 ++++++++++++++++ src/components/RevealElement/index.tsx | 32 ++++++---- src/core/RevealContainer/index.ts | 17 +++++- src/core/RevealSkyflowElement/index.ts | 4 ++ src/utils/logs/index.ts | 2 + src/utils/skyflow-error-code/index.ts | 4 ++ 7 files changed, 179 insertions(+), 11 deletions(-) diff --git a/__tests__/components/components.test.js b/__tests__/components/components.test.js index aa2fb49..302967c 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', 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..60780df 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,24 @@ 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} + + ); +}); 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, From cd83a8f30b2b4b17e114eb7a5c3411a78b05c273 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Thu, 18 Dec 2025 13:59:08 +0530 Subject: [PATCH 2/3] SK-2050: upload test snapshots --- .../__snapshots__/components.test.js.snap | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/__tests__/components/__snapshots__/components.test.js.snap b/__tests__/components/__snapshots__/components.test.js.snap index ad718fd..962440c 100644 --- a/__tests__/components/__snapshots__/components.test.js.snap +++ b/__tests__/components/__snapshots__/components.test.js.snap @@ -302,6 +302,25 @@ 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 From 1b541802fddbcfcaf2a344e9b493e472950eae45 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Fri, 19 Dec 2025 14:28:46 +0530 Subject: [PATCH 3/3] SK-2050: resolve comments --- __tests__/components/__snapshots__/components.test.js.snap | 2 +- __tests__/components/components.test.js | 2 +- src/components/RevealElement/index.tsx | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/__tests__/components/__snapshots__/components.test.js.snap b/__tests__/components/__snapshots__/components.test.js.snap index 962440c..11db7c9 100644 --- a/__tests__/components/__snapshots__/components.test.js.snap +++ b/__tests__/components/__snapshots__/components.test.js.snap @@ -323,6 +323,6 @@ Array [ 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 302967c..207df89 100644 --- a/__tests__/components/components.test.js +++ b/__tests__/components/components.test.js @@ -686,7 +686,7 @@ describe('test Collect And Reveal Elements Components', () => { const providerElement = render( - Provider Childern + Provider Children ); expect(providerElement).toMatchSnapshot(); diff --git a/src/components/RevealElement/index.tsx b/src/components/RevealElement/index.tsx index 60780df..41ab521 100644 --- a/src/components/RevealElement/index.tsx +++ b/src/components/RevealElement/index.tsx @@ -45,4 +45,6 @@ const RevealElement = forwardRef((props: RevealElementProps, ref) => { ); }); +RevealElement.displayName = 'RevealElement'; + export default RevealElement; \ No newline at end of file