@@ -4,7 +4,7 @@ import xpath from 'xpath'
44import { DOMParser as xmldom } from '@xmldom/xmldom'
55
66import { removeBadNameUsageAttrs , unwrapSimpleElement , fixTitleAttributes , unwrapDateCreated , unwrapDateOther , fixDateCreatedKeyDate , fixDateCreatedQualifer , renameElement , removeElement , removeEmptyElements , removeAttribute , convertAuthorityElement , moveClassificationToSubject , wrapElement , wrapTextWithChild , moveAndRenameElement , convertNamePartDate , convertSubNameWrapper , wrapCopyInformation , removeEmptyClassifications , convertSpeakerReleaseDetail , convertArchivesWrapper , toStrictMODS } from './strict-mods.js'
7- import { hasDirectTextContent } from './xml-helpers.js'
7+ import { hasDirectTextContent , safeSelect , safeSelectFirst } from './xml-helpers.js'
88
99// Test fixtures
1010const fixtures = {
@@ -4279,5 +4279,64 @@ describe('Strict MODS Conversion', () => {
42794279 assert . strictEqual ( hasDirectTextContent ( location ) , false )
42804280 } )
42814281 } )
4282+
4283+ describe ( 'safeSelect' , ( ) => {
4284+ it ( 'should return empty array for null document' , ( ) => {
4285+ const result = safeSelect ( '//mods' , null )
4286+ assert . deepStrictEqual ( result , [ ] )
4287+ } )
4288+
4289+ it ( 'should return empty array for undefined document' , ( ) => {
4290+ const result = safeSelect ( '//mods' , undefined )
4291+ assert . deepStrictEqual ( result , [ ] )
4292+ } )
4293+
4294+ it ( 'should return empty array for XPath with no matches' , ( ) => {
4295+ const parser = new xmldom ( )
4296+ const doc = parser . parseFromString ( '<xml><mods/></xml>' , 'text/xml' )
4297+ const result = safeSelect ( '//invalid_xpath' , doc )
4298+ assert . deepStrictEqual ( result , [ ] )
4299+ } )
4300+
4301+ it ( 'should return matching elements for valid XPath' , ( ) => {
4302+ const parser = new xmldom ( )
4303+ const doc = parser . parseFromString ( '<xml><mods/><mods/></xml>' , 'text/xml' )
4304+ const result = safeSelect ( '//mods' , doc )
4305+ assert . strictEqual ( result . length , 2 )
4306+ } )
4307+
4308+ it ( 'should not return elements without parents' , ( ) => {
4309+ const parser = new xmldom ( )
4310+ const doc = parser . parseFromString ( '<mods><child/></mods>' , 'text/xml' )
4311+ const child = xpath . select1 ( "//child" , doc )
4312+ // Manually remove the parent to simulate an orphaned element
4313+ child . parentNode . parentNode . removeChild ( child . parentNode )
4314+ assert . deepStrictEqual ( safeSelect ( '//child' , doc ) , [ ] )
4315+ } )
4316+ } )
4317+
4318+ describe ( 'safeSelectFirst' , ( ) => {
4319+ it ( 'should return null for null document' , ( ) => {
4320+ const result = safeSelectFirst ( '//mods' , null )
4321+ assert . strictEqual ( result , null )
4322+ } )
4323+
4324+ it ( 'should return null for XPath with no matches' , ( ) => {
4325+ const parser = new xmldom ( )
4326+ const doc = parser . parseFromString ( '<xml><mods/></xml>' , 'text/xml' )
4327+ const result = safeSelectFirst ( '//invalid_xpath' , doc )
4328+ assert . strictEqual ( result , null )
4329+ } )
4330+
4331+ it ( 'should return the first matching element for valid XPath' , ( ) => {
4332+ const parser = new xmldom ( )
4333+ const doc = parser . parseFromString ( '<xml><mods/><mods/></xml>' , 'text/xml' )
4334+ const modsElements = xpath . select ( '//mods' , doc )
4335+ const firstMods = safeSelectFirst ( '//mods' , doc )
4336+ assert . ok ( firstMods )
4337+ assert . strictEqual ( firstMods . nodeName , 'mods' )
4338+ assert . deepEqual ( firstMods , modsElements [ 0 ] )
4339+ } )
4340+ } )
42824341 } )
42834342} )
0 commit comments