-
Notifications
You must be signed in to change notification settings - Fork 181
Chore fix ios nfc scanning and compiling #979
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ import React | |
| import NFCPassportReader | ||
| #endif | ||
| import Security | ||
| import Mixpanel | ||
|
|
||
| #if !E2E_TESTING | ||
| @available(iOS 13, macOS 10.15, *) | ||
|
|
@@ -46,12 +47,29 @@ class PassportReader: NSObject { | |
| super.init() | ||
| } | ||
|
|
||
| private var analytics: SelfAnalytics? | ||
|
|
||
| @objc(configure:enableDebugLogs:) | ||
| func configure(token: String, enableDebugLogs: Bool) { | ||
| let analytics = SelfAnalytics(token: token, enableDebugLogs: enableDebugLogs) | ||
| self.analytics = analytics | ||
| self.passportReader = NFCPassportReader.PassportReader(analytics: analytics) | ||
| } | ||
|
|
||
| @objc(trackEvent:properties:) | ||
| func trackEvent(_ name: String, properties: [String: Any]?) { | ||
| if let mpProps = properties as? Properties { | ||
| analytics?.trackEvent(name, properties: mpProps) | ||
| } else { | ||
| analytics?.trackEvent(name, properties: nil) | ||
| } | ||
| } | ||
|
|
||
| @objc(flush) | ||
| func flush() { | ||
| analytics?.flush() | ||
| } | ||
|
|
||
|
Comment on lines
+59
to
+72
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add E2E stubs for trackEvent/flush to keep the RN API consistent The bridge declares these methods unconditionally in Objective-C. In E2E builds, missing selectors can cause runtime errors if JS calls them. Apply near the E2E stub class: class PassportReader: NSObject {
override init() {
super.init()
}
+ @objc(trackEvent:properties:)
+ func trackEvent(_ name: String, properties: [String: Any]?) {
+ // No-op in E2E testing
+ }
+
+ @objc(flush)
+ func flush() {
+ // No-op in E2E testing
+ }
+
@objc(configure:enableDebugLogs:)
func configure(token: String, enableDebugLogs: Bool) {
// No-op for E2E testing
}
🤖 Prompt for AI Agents |
||
| func getMRZKey(passportNumber: String, dateOfBirth: String, dateOfExpiry: String ) -> String { | ||
|
|
||
| // Pad fields if necessary | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,17 +6,17 @@ import Mixpanel | |
|
|
||
| public class SelfAnalytics: Analytics { | ||
| private let enableDebugLogs: Bool | ||
|
|
||
| public override init(token: String, enableDebugLogs: Bool = false, trackAutomaticEvents: Bool = false) { | ||
| self.enableDebugLogs = enableDebugLogs | ||
| super.init(token: token, enableDebugLogs: enableDebugLogs, trackAutomaticEvents: trackAutomaticEvents) | ||
| } | ||
|
|
||
| public override func trackEvent(_ name: String, properties: Properties? = nil) { | ||
| super.trackEvent(name, properties: properties) | ||
|
|
||
| print("[NFC Analytics] Event: \(name), Properties: \(properties ?? [:])") | ||
|
|
||
| if let logger = NativeLoggerBridge.shared { | ||
| logger.sendEvent(withName: "logEvent", body: [ | ||
| "level": "info", | ||
|
|
@@ -29,10 +29,10 @@ public class SelfAnalytics: Analytics { | |
|
|
||
| public override func trackDebugEvent(_ name: String, properties: Properties? = nil) { | ||
| super.trackDebugEvent(name, properties: properties) | ||
| if enableDebugLogs { | ||
|
|
||
| if enableDebugLogs { | ||
| print("[NFC Analytics Debug] Event: \(name), Properties: \(properties ?? [:])") | ||
|
|
||
| if let logger = NativeLoggerBridge.shared { | ||
| logger.sendEvent(withName: "logEvent", body: [ | ||
| "level": "debug", | ||
|
|
@@ -43,12 +43,12 @@ public class SelfAnalytics: Analytics { | |
| } | ||
| } | ||
| } | ||
|
|
||
| public override func trackError(_ error: Error, context: String) { | ||
| super.trackError(error, context: context) | ||
|
|
||
| print("[NFC Analytics Error] Context: \(context), Error: \(error.localizedDescription)") | ||
|
|
||
| if let logger = NativeLoggerBridge.shared { | ||
| logger.sendEvent(withName: "logEvent", body: [ | ||
| "level": "error", | ||
|
|
@@ -62,4 +62,8 @@ public class SelfAnalytics: Analytics { | |
| ]) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public func flush() { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fyi @seshanthS added a flush method to the analytics package |
||
| Mixpanel.mainInstance().flush() | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -237,8 +237,31 @@ NativeModules.PassportReader = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scanPassport: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackEvent: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| flush: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reset: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Mock @/utils/passportReader to properly expose the interface expected by tests | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jest.mock('./src/utils/passportReader', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mockScanPassport = jest.fn(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Mock the parameter count for scanPassport (iOS native method takes 9 parameters) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Object.defineProperty(mockScanPassport, 'length', { value: 9 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mockPassportReader = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configure: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scanPassport: mockScanPassport, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackEvent: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| flush: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reset: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PassportReader: mockPassportReader, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reset: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scan: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: mockPassportReader, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+243
to
+264
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Mock the aliased module name and expose ESM default to avoid resolution edge cases. Apply: -// Mock @/utils/passportReader to properly expose the interface expected by tests
-jest.mock('./src/utils/passportReader', () => {
+// Mock @/utils/passportReader to properly expose the interface expected by tests
+jest.mock('@/utils/passportReader', () => {
const mockScanPassport = jest.fn();
// Mock the parameter count for scanPassport (iOS native method takes 9 parameters)
Object.defineProperty(mockScanPassport, 'length', { value: 9 });
const mockPassportReader = {
configure: jest.fn(),
scanPassport: mockScanPassport,
trackEvent: jest.fn(),
flush: jest.fn(),
reset: jest.fn(),
};
return {
+ __esModule: true,
PassportReader: mockPassportReader,
reset: jest.fn(),
scan: jest.fn(),
default: mockPassportReader,
};
});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Mock @stablelib packages | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jest.mock('@stablelib/cbor', () => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| encode: jest.fn(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,15 +4,15 @@ | |
|
|
||
| import { Buffer } from 'buffer'; | ||
| import { Platform } from 'react-native'; | ||
| import { | ||
| PassportReader, | ||
| reset, | ||
| scan as scanDocument, | ||
| } from 'react-native-passport-reader'; | ||
|
|
||
| import type { PassportData } from '@selfxyz/common/types'; | ||
|
|
||
| import { configureNfcAnalytics } from '@/utils/analytics'; | ||
| import { | ||
| PassportReader, | ||
| reset, | ||
| scan as scanDocument, | ||
| } from '@/utils/passportReader'; | ||
|
|
||
| interface AndroidScanResponse { | ||
| mrz: string; | ||
|
|
@@ -57,6 +57,14 @@ export const scan = async (inputs: Inputs) => { | |
|
|
||
| const scanAndroid = async (inputs: Inputs) => { | ||
| reset(); | ||
|
|
||
| if (!scanDocument) { | ||
| console.warn( | ||
| 'Android passport scanner is not available - native module failed to load', | ||
| ); | ||
| return Promise.reject(new Error('NFC scanning is currently unavailable.')); | ||
| } | ||
|
Comment on lines
59
to
+66
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard and await reset to avoid TypeError and race. Apply: - reset();
+ if (typeof reset === 'function') {
+ await Promise.resolve(reset());
+ }🤖 Prompt for AI Agents |
||
|
|
||
| return await scanDocument({ | ||
| documentNumber: inputs.passportNumber, | ||
| dateOfBirth: inputs.dateOfBirth, | ||
|
|
@@ -67,6 +75,17 @@ const scanAndroid = async (inputs: Inputs) => { | |
| }; | ||
|
|
||
| const scanIOS = async (inputs: Inputs) => { | ||
| if (!PassportReader?.scanPassport) { | ||
| console.warn( | ||
| 'iOS passport scanner is not available - native module failed to load', | ||
| ); | ||
| return Promise.reject( | ||
| new Error( | ||
| 'NFC scanning is currently unavailable. Please ensure the app is properly installed.', | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| return await Promise.resolve( | ||
| PassportReader.scanPassport( | ||
| inputs.passportNumber, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard Mixpanel import to avoid E2E/CI compile breaks
Unconditional
import Mixpanelcan fail in E2E or CI where Mixpanel isn’t linked. Wrap it.Apply:
📝 Committable suggestion
🤖 Prompt for AI Agents