Jasmine spionere på importert modul (typescript)
Jeg prøver å teste en enkel hjelpeklasse med statiske metoder med Jasmine og TypeScript. Problemet er at hjelpeklassen importerer et tredjepartsbibliotek for å oppnå et mål. Jeg trenger å teste at dette tredjepartsbiblioteket blir kalt i alle situasjoner.
import Helpers from '../../src/utils/Helpers';
import {parseString} from 'xml2js';
describe('Helper class', function() {
let mockParseString: any;
describe('xmlToJson', function() {
beforeEach(function(done) {
mockParseString = jasmine.createSpy('parseString', parseString);
// spyOn(xml2js, 'parseString').and.callFake(function(xml: string, callback: (error: any, data: object) => void) {
//
// });
setTimeout(() => {
done();
}, 1);
})
it('calls library to parse string', async function(done) {
await Helpers.xmlToJson('<div></div>');
expect(mockParseString).toHaveBeenCalled();
done();
})
})
});
Så i hjelpeklassen pakker jeg bare en tilbakeringingsfunksjon inn i et løfte:
import {convertableToString, OptionsV2, parseString} from 'xml2js';
export default class Helpers {
public static xmlToJson(xml: convertableToString, options?: OptionsV2): Promise<any> {
return new Promise((resolve, reject) => {
if(options) {
parseString(xml, (err, results) => {
if(err) {
reject(err);
}
resolve(results);
});
} else {
parseString(xml, options, (err, results) => {
if(err) {
reject(err);
}
resolve(results);
});
}
})
}
}
Feilen jeg får er at spionen ikke blir kalt. Jeg har gravd rundt en stund, men jeg har ikke funnet en måte å få spionen til å fungere på. Kanskje det enkelt og greit ikke er mulig.
REDIGER
Hvordan jeg kaller testen:
./node_modules/.bin/ts-node ./node_modules/.bin/jasmine spec/utils/Helpers-spec.ts
Svar #1
Her er en fungerende test for koden din:
import Helpers from '../../src/utils/Helpers';
import * as xml2js from 'xml2js';
describe('Helper class', function() {
let mockParseString;
describe('xmlToJson', function() {
beforeAll(() => {
mockParseString = spyOn(xml2js, 'parseString').and.callThrough();
});
it('calls library to parse string', (done) => {
(async () => {
await Helpers.xmlToJson('<div></div>');
expect(mockParseString).toHaveBeenCalled();
})().then(() => done());
});
});
});
Svar #2
Til slutt klarte jeg ikke å få dette til å fungere ved å referere til biblioteket implisitt. Jeg valgte å bruke en løsning med avhengighetsinnsprøytning i stedet og la klassen min være en tjeneste. Dette er sannsynligvis renere i det lange løp uansett. (Jeg må fortsatt rydde opp typer da dette er ganske ufint)
import {convertableToString, OptionsV2, parseString} from 'xml2js';
export default class Helpers {
parseString: any;
constructor(parseString: any) {
this.parseString = parseString;
}
public xmlToJson(xml: convertableToString, options?: OptionsV2): Promise<any> {
return new Promise((resolve, reject) => {
if(options) {
this.parseString(xml, (err: any, results: string) => {
if(err) {
reject(err);
}
resolve(results);
});
} else {
this.parseString(xml, options, (err: any, results: string) => {
if(err) {
reject(err);
}
resolve(results);
});
}
})
}
}
Og deretter barebones-test med:
import Helpers from '../../src/utils/helpers';
import * as xml2js from 'xml2js';
describe('Helper class', function() {
let mockParseString:any;
describe('xmlToJson', function() {
beforeAll(() => {
mockParseString = spyOn(xml2js, 'parseString').and.callThrough();
});
it('calls library to parse string', async (done) => {
let helper = new Helpers(mockParseString);
await helper.xmlToJson('<div></div>');
expect(mockParseString).toHaveBeenCalled();
done();
});
});
});
Takk til @brian-lives-outdoors for hjelpen likevel!
