@@ -7,13 +7,15 @@ import WalletSDK
77///
88/// Tests the Swift package facade that iOS apps consume directly.
99/// Uses real iOS Keychain crypto, SQLDelight persistence, and OID4VCI/VP protocol
10- /// against the public EUDI test backend .
10+ /// against public walt.id demo and EUDI test backends .
1111///
1212/// These are integration tests (not E2E UI tests) - they test the library directly
1313/// without UI automation.
1414final class MobileWalletIntegrationTests : XCTestCase {
1515
1616 private let testWalletId = " ios-unit-test-wallet "
17+ private static let eudiPidSdJwtCredentialID = " eu.europa.ec.eudi.pid_vc_sd_jwt "
18+ private static let eudiEhicSdJwtCredentialID = " eu.europa.ec.eudi.ehic_sd_jwt_vc "
1719 private static let demoTransactionDataProfiles : [ WalletTransactionDataProfile ] = [
1820 WalletTransactionDataProfile (
1921 type: " org.waltid.transaction-data.payment-authorization " ,
@@ -174,11 +176,11 @@ final class MobileWalletIntegrationTests: XCTestCase {
174176 XCTAssertEqual ( deletedKeys, [ " \( testWalletId) :wallet_ \( testWalletId) " ] )
175177 }
176178
177- func testReceiveCredentialFromEudi ( ) async throws {
179+ func testReceiveEudiPidSdJwtFromEudi ( ) async throws {
178180 let wallet = try await makeWallet ( )
179181 _ = try await wallet. bootstrap ( )
180182
181- let offer = try await EudiTestBackend . shared. generateOffer ( )
183+ let offer = try await EudiTestBackend . shared. generateOffer ( credentialId : Self . eudiPidSdJwtCredentialID )
182184 let offerURL = try XCTUnwrap ( URL ( string: offer. offerUrl) )
183185 let resolution = try await wallet. resolveOffer ( offer: offerURL)
184186 XCTAssertTrue ( resolution. transactionCodeRequired, " EUDI offer should require a transaction code " )
@@ -199,75 +201,28 @@ final class MobileWalletIntegrationTests: XCTestCase {
199201 try await receiveCredentialFromDemoIssuer2 ( scenarioID: " iso-mdl " )
200202 }
201203
202- func testReceiveAndPresentFullFlow( ) async throws {
203- let wallet = try await makeWallet ( )
204-
205- let bootstrapResult = try await wallet. bootstrap ( )
206- let did = bootstrapResult. did
207-
208- let offer = try await EudiTestBackend . shared. generateOffer ( )
209- let offerURL = try XCTUnwrap ( URL ( string: offer. offerUrl) )
210- let credentialIDs = try await wallet. receive ( offer: offerURL, txCode: offer. txCode)
211- XCTAssertFalse ( credentialIDs. isEmpty, " Should receive at least one credential " )
212-
213- let credentials = try await wallet. credentials ( )
214- XCTAssertFalse ( credentials. isEmpty, " Should have stored credentials " )
215-
216- let credentialId = await EudiTestBackend . shared. extractCredentialIdFromOfferUrl ( offerUrl: offer. offerUrl)
217- let transaction = try await EudiTestBackend . shared. createVerifierTransaction ( credentialId: credentialId)
218- let presentationURL = try XCTUnwrap ( URL ( string: transaction. authorizationRequestUri) )
219-
220- let presentResult = try await wallet. present (
221- request: presentationURL,
222- did: did
223- )
224-
225- XCTAssertTrue (
226- presentResult. success,
227- " Presentation should succeed. Credentials: \( credentials) , Result: \( presentResult) "
228- )
229-
230- // Wait for verifier to confirm receipt
231- try await TestHelpers . waitForVerifierSuccess ( transactionID: transaction. transactionId, timeoutSeconds: verifierPollingTimeout)
204+ func testReceiveAndPresentEudiEhicSdJwtAgainstEudi( ) async throws {
205+ try await receiveAndPresentEudiCredential ( credentialID: Self . eudiEhicSdJwtCredentialID)
232206 }
233207
234- func testPreviewAndSubmitFullFlowAgainstEudi( ) async throws {
235- let walletId = " ios-eudi-preview-submit- \( UUID ( ) . uuidString) "
236- await clearTestData ( walletId: walletId)
237-
238- let wallet = try await makeWallet ( walletId: walletId)
239- let bootstrapResult = try await wallet. bootstrap ( )
240- let did = bootstrapResult. did
241-
242- let offer = try await EudiTestBackend . shared. generateOffer ( )
243- let offerURL = try XCTUnwrap ( URL ( string: offer. offerUrl) )
244- let credentialIDs = try await wallet. receive ( offer: offerURL, txCode: offer. txCode)
245- XCTAssertFalse ( credentialIDs. isEmpty, " Should receive at least one EUDI credential " )
208+ func testPreviewAndSubmitEudiEhicSdJwtAgainstEudi( ) async throws {
209+ try await previewAndSubmitEudiCredential ( credentialID: Self . eudiEhicSdJwtCredentialID)
210+ }
246211
247- let credentialId = await EudiTestBackend . shared. extractCredentialIdFromOfferUrl ( offerUrl: offer. offerUrl)
248- let transaction = try await EudiTestBackend . shared. createVerifierTransaction ( credentialId: credentialId)
249- let presentationURL = try XCTUnwrap ( URL ( string: transaction. authorizationRequestUri) )
250- let preview = try await wallet. previewPresentation ( request: presentationURL)
251- XCTAssertFalse (
252- preview. credentialOptions. isEmpty,
253- " Should preview at least one matching EUDI credential: \( preview) "
254- )
255- XCTAssertTrue (
256- preview. credentialOptions. allSatisfy { credentialIDs. contains ( $0. credentialID) } ,
257- " Preview should only offer credentials received in this test. Received: \( credentialIDs) , Preview: \( preview) "
212+ func testReceiveAndPresentEudiPidSdJwtAgainstEudi( ) async throws {
213+ try XCTSkipIf (
214+ true ,
215+ " Upstream issue: https://github.com/eu-digital-identity-wallet/eudi-srv-web-issuing-eudiw-py/issues/172 "
258216 )
217+ try await receiveAndPresentEudiCredential ( credentialID: Self . eudiPidSdJwtCredentialID)
218+ }
259219
260- let result = try await wallet . submitPresentation (
261- request : presentationURL ,
262- selectedCredentialOptions : preview . credentialOptions . map ( \ . selection ) ,
263- did : did
220+ func testPreviewAndSubmitEudiPidSdJwtAgainstEudi ( ) async throws {
221+ try XCTSkipIf (
222+ true ,
223+ " Upstream issue: https://github.com/eu-digital-identity-wallet/eudi-srv-web-issuing-eudiw-py/issues/172 "
264224 )
265- XCTAssertTrue (
266- result. success,
267- " EUDI stepwise presentation should succeed. Preview: \( preview) , Result: \( result) "
268- )
269-
270- try await TestHelpers . waitForVerifierSuccess ( transactionID: transaction. transactionId, timeoutSeconds: verifierPollingTimeout)
225+ try await previewAndSubmitEudiCredential ( credentialID: Self . eudiPidSdJwtCredentialID)
271226 }
272227
273228 func testReceiveAndPresentEudiPidSdJwtAgainstDemoIssuer2AndVerifier2( ) async throws {
@@ -290,39 +245,23 @@ final class MobileWalletIntegrationTests: XCTestCase {
290245 try await receiveAndPresentDemoCredential ( scenarioID: " iso-mdl " )
291246 }
292247
293- func testCredentialPersistsAcrossControllerRecreation ( ) async throws {
294- let wallet1 = try await makeWallet ( )
295-
296- let bootstrapResult = try await wallet1 . bootstrap ( )
297- let did = bootstrapResult . did
248+ func testEudiPidSdJwtPersistsAcrossControllerRecreation ( ) async throws {
249+ let walletId = " ios-eudi-pid-sd-jwt-persistence- \( UUID ( ) . uuidString ) "
250+ await clearTestData ( walletId : walletId )
251+ let wallet1 = try await makeWallet ( walletId : walletId )
252+ _ = try await wallet1 . bootstrap ( )
298253
299- let offer = try await EudiTestBackend . shared. generateOffer ( )
254+ let offer = try await EudiTestBackend . shared. generateOffer ( credentialId : Self . eudiPidSdJwtCredentialID )
300255 let offerURL = try XCTUnwrap ( URL ( string: offer. offerUrl) )
301256 let credentialIDs = try await wallet1. receive ( offer: offerURL, txCode: offer. txCode)
302257 XCTAssertFalse ( credentialIDs. isEmpty, " Should receive at least one credential " )
303258
304259 // Recreate wallet facade (simulates app restart)
305- let wallet2 = try await makeWallet ( )
260+ let wallet2 = try await makeWallet ( walletId : walletId )
306261
307262 _ = try await wallet2. bootstrap ( )
308263 let credentials = try await wallet2. credentials ( )
309264 XCTAssertFalse ( credentials. isEmpty, " Credentials should persist across controller recreation " )
310-
311- let credentialId = await EudiTestBackend . shared. extractCredentialIdFromOfferUrl ( offerUrl: offer. offerUrl)
312- let transaction = try await EudiTestBackend . shared. createVerifierTransaction ( credentialId: credentialId)
313- let presentationURL = try XCTUnwrap ( URL ( string: transaction. authorizationRequestUri) )
314-
315- let presentResult = try await wallet2. present (
316- request: presentationURL,
317- did: did
318- )
319-
320- XCTAssertTrue (
321- presentResult. success,
322- " Should present from persisted credentials. Credentials: \( credentials) , Result: \( presentResult) "
323- )
324-
325- try await TestHelpers . waitForVerifierSuccess ( transactionID: transaction. transactionId, timeoutSeconds: verifierPollingTimeout)
326265 }
327266
328267 func testDemoCredentialPersistsAcrossControllerRecreation( ) async throws {
@@ -366,6 +305,75 @@ final class MobileWalletIntegrationTests: XCTestCase {
366305 )
367306 }
368307
308+ private func receiveAndPresentEudiCredential( credentialID: String ) async throws {
309+ let walletId = " ios-eudi-present- \( UUID ( ) . uuidString) "
310+ await clearTestData ( walletId: walletId)
311+ let wallet = try await makeWallet ( walletId: walletId)
312+ let bootstrapResult = try await wallet. bootstrap ( )
313+
314+ let offer = try await EudiTestBackend . shared. generateOffer ( credentialId: credentialID)
315+ let offerURL = try XCTUnwrap ( URL ( string: offer. offerUrl) )
316+ let credentialIDs = try await wallet. receive ( offer: offerURL, txCode: offer. txCode)
317+ XCTAssertFalse ( credentialIDs. isEmpty, " Should receive EUDI credential \( credentialID) " )
318+
319+ let credentials = try await wallet. credentials ( )
320+ XCTAssertFalse ( credentials. isEmpty, " Should store EUDI credential \( credentialID) " )
321+
322+ let offeredCredentialID = await EudiTestBackend . shared. extractCredentialIdFromOfferUrl ( offerUrl: offer. offerUrl)
323+ let transaction = try await EudiTestBackend . shared. createVerifierTransaction ( credentialId: offeredCredentialID)
324+ let presentationURL = try XCTUnwrap ( URL ( string: transaction. authorizationRequestUri) )
325+ let result = try await wallet. present ( request: presentationURL, did: bootstrapResult. did)
326+ XCTAssertTrue (
327+ result. success,
328+ " EUDI presentation should succeed for \( credentialID) . Credentials: \( credentials) , Result: \( result) "
329+ )
330+
331+ try await TestHelpers . waitForVerifierSuccess (
332+ transactionID: transaction. transactionId,
333+ timeoutSeconds: verifierPollingTimeout
334+ )
335+ }
336+
337+ private func previewAndSubmitEudiCredential( credentialID: String ) async throws {
338+ let walletId = " ios-eudi-preview-submit- \( UUID ( ) . uuidString) "
339+ await clearTestData ( walletId: walletId)
340+ let wallet = try await makeWallet ( walletId: walletId)
341+ let bootstrapResult = try await wallet. bootstrap ( )
342+
343+ let offer = try await EudiTestBackend . shared. generateOffer ( credentialId: credentialID)
344+ let offerURL = try XCTUnwrap ( URL ( string: offer. offerUrl) )
345+ let credentialIDs = try await wallet. receive ( offer: offerURL, txCode: offer. txCode)
346+ XCTAssertFalse ( credentialIDs. isEmpty, " Should receive EUDI credential \( credentialID) " )
347+
348+ let offeredCredentialID = await EudiTestBackend . shared. extractCredentialIdFromOfferUrl ( offerUrl: offer. offerUrl)
349+ let transaction = try await EudiTestBackend . shared. createVerifierTransaction ( credentialId: offeredCredentialID)
350+ let presentationURL = try XCTUnwrap ( URL ( string: transaction. authorizationRequestUri) )
351+ let preview = try await wallet. previewPresentation ( request: presentationURL)
352+ XCTAssertFalse (
353+ preview. credentialOptions. isEmpty,
354+ " Should preview a matching EUDI credential for \( credentialID) : \( preview) "
355+ )
356+ XCTAssertTrue (
357+ preview. credentialOptions. allSatisfy { credentialIDs. contains ( $0. credentialID) } ,
358+ " Preview should only offer credentials received in this test. Received: \( credentialIDs) , Preview: \( preview) "
359+ )
360+
361+ let result = try await wallet. submitPresentation (
362+ request: presentationURL,
363+ selectedCredentialOptions: preview. credentialOptions. map ( \. selection) ,
364+ did: bootstrapResult. did
365+ )
366+ XCTAssertTrue (
367+ result. success,
368+ " EUDI stepwise presentation should succeed for \( credentialID) . Preview: \( preview) , Result: \( result) "
369+ )
370+
371+ try await TestHelpers . waitForVerifierSuccess (
372+ transactionID: transaction. transactionId,
373+ timeoutSeconds: verifierPollingTimeout
374+ )
375+ }
376+
369377 private func previewAndSubmitDemoCredential( scenarioID: String ) async throws {
370378 let scenario = try demoPresentationScenario ( scenarioID)
371379 let walletId = " ios-demo-preview-submit- \( scenario. id) - \( UUID ( ) . uuidString) "
0 commit comments