@@ -1271,4 +1271,113 @@ describe("Sdcard Job", () => {
12711271 ` ) ;
12721272 expect ( directorySnapshot ( tempDir . path ) ) . toMatchSnapshot ( ) ;
12731273 } ) ;
1274+
1275+ it ( "should continue erasing even if a file/directory is not found during deletion" , async ( ) => {
1276+ const handle = await getOriginPrivateDirectory ( nodeAdapter , tempDir . path ) ;
1277+ // @ts -expect-error is readonly but this is testing
1278+ handle . name = tempDir . path ;
1279+
1280+ // Create some files and directories to erase
1281+ await Promise . all ( [
1282+ fs . mkdir ( path . join ( tempDir . path , "EEPROM" ) ) , // Should not be deleted
1283+ fs . mkdir ( path . join ( tempDir . path , "THEMES" ) ) ,
1284+ fs . mkdir ( path . join ( tempDir . path , "SCRIPTS" ) ) ,
1285+ ] ) ;
1286+
1287+ // Mock removeEntry to throw NotFoundError for one entry
1288+ const originalRemoveEntry = handle . removeEntry . bind ( handle ) ;
1289+ handle . removeEntry = vitest . fn (
1290+ async ( name : string , options ?: { recursive ?: boolean } ) => {
1291+ if ( name === "THEMES" ) {
1292+ const error = new Error ( "Entry not found" ) ;
1293+ error . name = "NotFoundError" ;
1294+ throw error ;
1295+ }
1296+ return originalRemoveEntry ( name , options ) ;
1297+ }
1298+ ) ;
1299+
1300+ requestWritableDirectory . mockResolvedValue ( handle ) ;
1301+
1302+ const directoryRequest = await backend . mutate ( {
1303+ mutation : gql `
1304+ mutation RequestDirectory {
1305+ pickSdcardDirectory {
1306+ id
1307+ name
1308+ }
1309+ }
1310+ ` ,
1311+ } ) ;
1312+
1313+ const { id : directoryId } = directoryRequest . data ?. pickSdcardDirectory as {
1314+ id : string ;
1315+ } ;
1316+
1317+ const { nockDone } = await nock . back ( "sdcard-job-jumper-t8-cn-latest.json" ) ;
1318+
1319+ const createJobRequest = await backend . mutate ( {
1320+ mutation : gql `
1321+ mutation CreateSdcardJob($directoryId: ID!) {
1322+ createSdcardWriteJob(
1323+ directoryId: $directoryId
1324+ pack: { target: "t8", version: "latest" }
1325+ sounds: { ids: ["cn"], version: "latest" }
1326+ ) {
1327+ id
1328+ }
1329+ }
1330+ ` ,
1331+ variables : {
1332+ directoryId,
1333+ } ,
1334+ } ) ;
1335+
1336+ const jobId = (
1337+ createJobRequest . data ?. createSdcardWriteJob as { id : string } | null
1338+ ) ?. id ;
1339+
1340+ expect ( createJobRequest . errors ) . toBeFalsy ( ) ;
1341+ expect ( jobId ) . toBeTruthy ( ) ;
1342+
1343+ await waitForSdcardJobCompleted ( jobId ! ) ;
1344+ nockDone ( ) ;
1345+
1346+ const { data, errors } = await backend . query ( {
1347+ query : gql `
1348+ query SdcardJobStatus($id: ID!) {
1349+ sdcardWriteJobStatus(jobId: $id) {
1350+ cancelled
1351+ stages {
1352+ erase {
1353+ started
1354+ completed
1355+ progress
1356+ error
1357+ }
1358+ write {
1359+ started
1360+ completed
1361+ progress
1362+ }
1363+ }
1364+ }
1365+ }
1366+ ` ,
1367+ variables : {
1368+ id : jobId ,
1369+ } ,
1370+ } ) ;
1371+
1372+ expect ( errors ) . toBeFalsy ( ) ;
1373+ // Erase should complete successfully despite NotFoundError
1374+ expect ( ( data as any ) ?. sdcardWriteJobStatus ?. stages . erase . completed ) . toBe (
1375+ true
1376+ ) ;
1377+ expect ( ( data as any ) ?. sdcardWriteJobStatus ?. stages . erase . error ) . toBeNull ( ) ;
1378+ // Write should also complete
1379+ expect ( ( data as any ) ?. sdcardWriteJobStatus ?. stages . write . completed ) . toBe (
1380+ true
1381+ ) ;
1382+ } ) ;
12741383} ) ;
0 commit comments