@@ -10,10 +10,11 @@ import {
1010} from "../src/ceremonies" ;
1111import type {
1212 PublicKeyCredentialCreationOptionsJson ,
13- PublicKeyCredentialRequestOptionsJson ,
13+ PublicKeyCredentialRequestOptionsJson , StartRegistrationRequest , StartRegistrationResponse ,
1414} from "../src/types" ;
15- import { HttpHandler , HttpServer } from "./helpers/httpServer" ;
15+ import { decodeJson , encodeJson , Handler , HttpHandler , HttpServer , newHttpHandler } from "./helpers/httpServer" ;
1616import * as http from "node:http" ;
17+ import { RegistrationService } from "./helpers/registration" ;
1718
1819const CREATE_OPTIONS_JSON : PublicKeyCredentialCreationOptionsJson = {
1920 rp : { id : "example.com" , name : "Example" } ,
@@ -134,6 +135,7 @@ describe("encodeAuthenticationResponse", () => {
134135 } ) ;
135136} ) ;
136137
138+
137139describe ( "PkAuthCeremonyClient http test" , ( ) => {
138140 it ( "when startRegistration endpoint returns 500 then the client makes no attempt to create credential" , async ( ) => {
139141 using server = await startHttpServer ( {
@@ -146,11 +148,59 @@ describe("PkAuthCeremonyClient http test", () => {
146148 ) ;
147149
148150 await expect ( client . register ( { username : "alice" , label : "key" } ) ) . rejects . toThrow ( "HTTP 500: unit test error from errorHttpHandler" ) ;
149- expect ( credentialsContainer . create ) . not . toHaveBeenCalled ( ) ; // this proves the client did not attempt to create a credential upon failure to start registration
151+
152+ expect ( credentialsContainer . create ) . not . toHaveBeenCalled ( ) ; // this proves the client did not attempt to create a credential upon failure to start registration.ts
153+ } )
154+
155+ it ( "when start registration succeeds but no credential is created, then the client fails with credential cancellation" , async ( ) => {
156+ const registration = new RegistrationService ( "localhost" , "alice" , "bob" )
157+ using server = await startHttpServer ( {
158+ [ startPath ] : newStartHandler ( registration ) ,
159+ [ finishPath ] : errorHttpHandler
160+ } ) ;
161+ const credentialsContainer = noOpCredentialsContainer ( ) ;
162+ const client = new PkAuthCeremonyClient (
163+ { apiBase : server . url } ,
164+ { credentials : credentialsContainer } ,
165+ ) ;
166+
167+ await expect ( client . register ( { username : "alice" , label : "key" } ) ) . rejects . toThrow ( ) ;
168+
169+ expect ( credentialsContainer . create ) . toHaveBeenCalled ( ) ; // this proves the client did attempt to create a credential
170+ } )
171+
172+ it ( "when finish registration fails, the credential was still created" , async ( ) => {
173+ const registration = new RegistrationService ( "localhost" , "alice" , "bob" )
174+ using server = await startHttpServer ( {
175+ [ startPath ] : newStartHandler ( registration ) ,
176+ [ finishPath ] : errorHttpHandler
177+ } ) ;
178+ const credentialsContainer = mockCredentialContainer ( ) ;
179+ const client = new PkAuthCeremonyClient (
180+ { apiBase : server . url } ,
181+ { credentials : credentialsContainer } ,
182+ ) ;
183+
184+ await expect ( client . register ( { username : "alice" , label : "key" } ) ) . rejects . toThrow ( "HTTP 500: unit test error from errorHttpHandler" ) ;
185+
186+ expect ( credentialsContainer . create ) . toHaveBeenCalled ( ) ; // this proves the client did attempt to create a credential
187+ // TODO: wait for the finish handler to more strongly assert behavior of "finish" phase of client.register
150188 } )
151189
152190 const startPath = "/auth/passkeys/registration/start" ;
153- //currently not used: const finishPath = "/auth/passkeys/registration/finish"
191+ const finishPath = "/auth/passkeys/registration.ts/finish"
192+
193+ function mockCredentialContainer ( ) : CredentialsContainer {
194+ return {
195+ create : vi . fn ( async ( ) =>
196+ fakeCredential ( new Uint8Array ( [ 7 ] ) , {
197+ clientDataJSON : new Uint8Array ( [ 0 ] ) . buffer as ArrayBuffer ,
198+ attestationObject : new Uint8Array ( [ 0 ] ) . buffer as ArrayBuffer ,
199+ } as unknown as AuthenticatorResponse ) ,
200+ ) ,
201+ get : vi . fn ( ) ,
202+ } as unknown as CredentialsContainer ;
203+ }
154204
155205 function noOpCredentialsContainer ( ) : CredentialsContainer {
156206 return { create : vi . fn ( ) , get : vi . fn ( ) , preventSilentAccess : vi . fn ( ) , store : vi . fn ( ) } ;
@@ -161,6 +211,14 @@ describe("PkAuthCeremonyClient http test", () => {
161211 res . end ( "unit test error from errorHttpHandler" )
162212 }
163213
214+ function newStartHandler ( registration : RegistrationService ) : HttpHandler {
215+ const endpoint = async ( req : StartRegistrationRequest ) : Promise < StartRegistrationResponse > => {
216+ return registration . start ( req ) ;
217+ } ;
218+ const handler = new Handler ( decodeJson , endpoint , encodeJson ) ;
219+ return newHttpHandler ( handler ) ;
220+ }
221+
164222 async function startHttpServer ( routes : Record < string , HttpHandler > ) : Promise < HttpServer > {
165223 const server = new HttpServer ( routes ) ;
166224 await server . listen ( ) ;
0 commit comments