-1

I have the default setup for unit tests (Jasmine and Karma). I need to write a unit test for a function that reads a provided Element node from an XMLDocument. While I could generate the DOMs programatically, I already have example XML files in the asset folder and it would be easiest and most realistic to parse those the same way I do in the actual app. However, providing the files to the unit tests seems to be very difficult. Since the thing I'm trying to accomplish is basic and probably done a lot, I'm hoping there might be a simple solution I'm looking over.

I know I can copy-and-paste the XML source into a string literal, but the files I want to use are 20-50 kB and contain quotes, so I'm trying to avoid that. From what I've read online such as this question, the way to import files is with raw-loader. However, that takes a lot of work to setup and that method is now out of date in favor of asset modules. Angular's HttpClientTestingModule doesn't help me because it requires I already have the string in memory, which defeats the purpose of loading an asset with it.

2 Answers 2

1

In older times to import a JSON file in your TS code you could add a d.ts file with this syntax

declare module "*.json" {
  const value: any;
  export default value;
}

Maybe you could try to do the same with XML ?

Note : use it with the default export, i.e. import XML from "file.xml";

Sign up to request clarification or add additional context in comments.

1 Comment

I got further, but that alone wasn't enough. I got this error when running ng test: > You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See webpack.js.org/concepts#loaders > > [beginning of file text] This looks like the raw-loader thing. I'll have to read up on the up-to-date webpack documentation and then try it again. Thanks for the help!
0

As it turns out, the solution can be almost as simple as installing an npm package and then following MGX's answer.

Declaring and Importing

Assuming the default configuration for Angular CLI 17, to declare a module, just add a file with any name ending with a .d.ts in the /src/ directory. You then use declare module 'expression', where 'expression' seems to follow a regex-like syntax. '*.xml' is all you need for it to automatically apply to all xml files, while you can also make it more specific. I ended up with this:

declare module '*.xml' {
  const value: string;
  export default value;
}

As MGX said, you then need to import the file you want to read, not the .d.ts file.

Configuring raw-loading

If you just do that, it still won't work. You will get an error:

Error: Module parse failed: Unexpected token (1:0) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

According to the docs, the fix for this involves overriding the default settings for webpack, either with something like this:

module: {
  rules: [{ test: /\.xml$/, use: 'raw-loader' }],
},

or like this:

module: {
  rules: [{ test: /\.xml/, type: 'asset/source' }],
},

However, manually fiddling with the the webpack config will mess up Angular CLI's scripts. Many, but not all, of the ways said to edit the config are out of date. Fortunately, Angular Builders, a tool for making custom build scripts with Angular, is actively maintained.

Instead of trying that first, I tried the package raw-loader. It has been archived for more than three years, but it worked for me in Angular 17.

I just had to install it:

npm install raw-loader --save-dev

and edit my import statement slightly:

import XML from 'raw-loader!file.xml';

and then I got the contents of the file as a string in XML.

Parsing the String

To actually use the XML data, I still had to parse the string, but that is relatively trivial. Since Angular is a web framework, I used the browser's api to parse the string into an XMLDocument, similar to a web pages DOM representation.

const parser = new DOMParser();
const xmlDoc: XMLDocument = parser.parseFromString(XML, "text/xml");

For more information, check out the w3schools guide on XML.

For those who don't reliably have that API, or who think parsing to a DOM is overkill, look into xml2js or fast-xml-parser.

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.