Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ios/SdkReactNative.mm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
if (config.languageCode()) {
dict[@"languageCode"] = config.languageCode();
}
if (config.showLanguageSelector().has_value()) {
dict[@"showLanguageSelector"] = @(config.showLanguageSelector().value());
}
if (config.fontFamily()) {
dict[@"fontFamily"] = config.fontFamily();
}
Expand Down Expand Up @@ -99,7 +102,7 @@
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject
{
NSDictionary *configDict = (&config != nullptr) ? [self configDictFrom:config] : nil;

Check warning on line 105 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]

Check warning on line 105 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]

Check warning on line 105 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]

[_bridge startVerificationWithToken:token
config:configDict
Expand All @@ -117,9 +120,9 @@
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject
{
NSDictionary *configDict = (&config != nullptr) ? [self configDictFrom:config] : nil;

Check warning on line 123 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]

Check warning on line 123 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]

Check warning on line 123 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]
NSDictionary *contactDict = (&contactDetails != nullptr) ? [self contactDictFrom:contactDetails] : nil;

Check warning on line 124 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]

Check warning on line 124 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]
NSDictionary *expectedDict = (&expectedDetails != nullptr) ? [self expectedDictFrom:expectedDetails] : nil;

Check warning on line 125 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]

Check warning on line 125 in ios/SdkReactNative.mm

View workflow job for this annotation

GitHub Actions / Released iOS compatibility and bridge tests

reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare]

[_bridge startVerificationWithWorkflowWithWorkflowId:workflowId
vendorData:vendorData
Expand Down
90 changes: 90 additions & 0 deletions src/__tests__/native-config-forwarding.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { readFileSync } from 'fs';
import { join } from 'path';

/**
* A configuration option the JavaScript layer accepts is only useful when both
* native bridges hand it to the native SDK. The bridges parse the config
* independently (an Objective-C dictionary on iOS, a ReadableMap on Android),
* so a key added to the JS type and one bridge can silently be dropped by the
* other. The language selector shipped this way once: JS and Android forwarded
* it, while the iOS dictionary never included it and the selector could not be
* enabled on iOS at all.
*
* These tests read the public config type and both parsers and fail when a key
* has no counterpart on a platform.
*/

const repoRoot = join(__dirname, '..', '..');

const read = (relativePath: string) =>
readFileSync(join(repoRoot, relativePath), 'utf8');

/** The body of the first braced declaration after `signature`. */
function bracedBody(source: string, signature: RegExp): string {
const start = source.search(signature);
expect(start).toBeGreaterThanOrEqual(0);

const open = source.indexOf('{', start);
let depth = 0;

for (let index = open; index < source.length; index += 1) {
if (source[index] === '{') depth += 1;
if (source[index] === '}') depth -= 1;
if (depth === 0) return source.slice(open, index + 1);
}

throw new Error('Unclosed declaration');
}

/** Every optional property declared on the public VerificationConfig type. */
function configKeys(): string[] {
const source = read('src/NativeSdkReactNative.ts');
const start = source.indexOf('export type VerificationConfig = {');
expect(start).toBeGreaterThanOrEqual(0);

const end = source.indexOf('\n};', start);
expect(end).toBeGreaterThan(start);

return Array.from(
source.slice(start, end).matchAll(/^\s{2}(\w+)\?:/gm),
(match) => String(match[1])
);
}

const keys = configKeys();
const iosConfig = bracedBody(
read('ios/SdkReactNative.mm'),
/- \(NSDictionary \*\)configDictFrom:/
);
const androidConfig = bracedBody(
read('android/src/main/java/com/sdkreactnative/SdkReactNativeModule.kt'),
/private fun parseConfiguration\(/
);

describe('verification configuration forwarding', () => {
it('reads every key both bridges must forward', () => {
expect(keys).toEqual(
expect.arrayContaining([
'languageCode',
'showLanguageSelector',
'fontFamily',
'loggingEnabled',
'showCloseButton',
'showExitConfirmation',
'closeOnComplete',
'defaultDocumentCamera',
'defaultLivenessCamera',
'showDocumentCameraSwitchButton',
'showLivenessCameraSwitchButton',
])
);
});

it.each(keys)('forwards %s to the native SDK on iOS', (key) => {
expect(iosConfig).toContain(`config.${key}()`);
});

it.each(keys)('forwards %s to the native SDK on Android', (key) => {
expect(androidConfig).toContain(`"${key}"`);
});
});
Loading