为什么我的单元测试抱怨未处理的承诺拒绝?



打印收据的函数如下:

const generateOnePDF = async (ticket, orderData) =>
new Promise(async (resolve, reject) => {
let finalString = '';
if (!ticket) {
const err = new Error('missing ticket data');
reject(err);
}
if (!orderData) {
const err = new Error('missing order data');
reject(err);
}
const { payload, sequence, title } = ticket;
if (!payload) {
const err = new Error('missing payload data');
reject(err);
}
if (!sequence) {
const err = new Error('missing ticket sequence');
reject(err);
}
if (!title) {
const err = new Error('missing ticket book title');
reject(err);
}
const doc = new PDFDocument();
PDFDocument.prototype.addSVG = function (svg, x, y, options) {
return SVGtoPDF(this, svg, x, y, options);
};
const stream = doc.pipe(new Base64Encode());
// logo
const logo = await fetchImage(
`${url}/static/media/logo_157.c15ac239.svg`
);
doc.addSVG(logo.toString(), 32, 40, {});
doc.moveUp();
doc.moveUp();
doc.text(`Order: O${orderData.orderId}`, { align: 'right' });
const rectXOffset = 25;
const rectPosition = 32;
doc
.rect(rectXOffset, rectPosition, doc.page.width - rectXOffset * 2, 32)
.stroke();
doc.moveDown();
doc.moveDown();
doc.moveDown();
doc.rect(rectXOffset, 80, doc.page.width - rectXOffset * 2, 680).stroke();
doc.text(orderData.title, { align: 'left' });
doc.moveDown();
doc.text(orderData.venue, { align: 'left' });
doc.text(orderData.address, { align: 'left' });
doc.text(`${orderData.city}, ${orderData.province} ${orderData.zip}`, {
align: 'left'
});
if (orderData.custom) {
doc.moveDown();
doc.text(orderData.customCopy, { align: 'left' });
}
doc.moveDown();
doc.text(`${orderData.date} at ${orderData.show}`, { align: 'left' });
doc.moveDown();
const image = await fetchImage(orderData['image']);
doc.image(image, {
fit: [100, 100],
align: 'right',
valign: 'top'
});
doc.moveDown();
doc.text(
`Order: O${orderData.orderId}. Placed by ${orderData.firstName} ${orderData.lastName} on ${orderData.created}`
);

// right column
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.moveUp();
doc.text(`Ticket: ${sequence} ${title}`, { align: 'right' });
const qrcode = new QRCode({
content: payload,
width: 200,
height: 200,
xmlDeclaration: false,
join: true
}).svg();
const options = { align: 'right' };
doc.addSVG(qrcode, 400, 150, options);
// finalize/close the PDF file
doc.end();
stream.on('data', (chunk) => {
finalString += chunk;
});
stream.on('end', () => {
// the stream is at its end, so push the resulting base64 string to the response
resolve(finalString);
});
stream.on('error', (err) => {
reject(err);
});
});

这不是世界上最干净的一段代码,但它同时为我工作。

我在下面为这段代码添加了一个简单的单元测试:
it('should throw an error if the ticket or order data are invalid', async () => {
await expect(generateOnePDF(null, {})).rejects.toThrowError();
await expect(generateOnePDF({}, null)).rejects.toThrowError();
});

测试通过了,但是它写了"垃圾"。到控制台。代码中有未处理的拒绝

(node:53703) UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property 'payload' of '((cov_2gbfm4phuo(...).s[25]++) , ticket)' as it is null.
(Use `node --trace-warnings ...` to show where the warning was created)

是其中一个错误,另一个是:

(node:53703) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'orderId' of null

我不明白为什么if (!ticket) throw()if (!orderData) throw不能阻止错误的发生。"破碎的承诺"在哪里?

我在承诺处理程序函数内做reject,所以我不在哪里做?

问题是您的函数在reject被调用后仍然继续执行,因此发生错误。

此外,您不应该使用async回调创建new Promise。这是一个反模式。而是承诺流"end"事件,然后返回该承诺。

我也会避免在PDFDocument原型上定义函数,当然也不会在generateOnePDF的每个调用上定义函数。你不妨直接调用SVGtoPDF函数。

所以像这样:

const streamPromise = stream =>
return new Promise((resolve, reject) => {
let finalString = '';
stream.on('data',  chunk => finalString += chunk);
stream.on('end',   () => resolve(finalString));
stream.on('error', reject);
});
const generateOnePDF = async (ticket, orderData) => {
if (!ticket   ) throw new Error('missing ticket data');
if (!orderData) throw new Error('missing order data');
const { payload, sequence, title } = ticket;
if (!payload  ) throw new Error('missing payload data');
if (!sequence ) throw new Error('missing ticket sequence');
if (!title    ) throw new Error('missing ticket book title');
const doc = new PDFDocument();
const stream = doc.pipe(new Base64Encode());
// logo
const logo = await fetchImage(`${url}/static/media/logo_157.c15ac239.svg`);
SVGtoPDF(doc, logo.toString(), 32, 40, {});
// ... etc ...
// ...
doc.end();
return streamPromise(stream);
});

这是由于使用async函数作为new Promise的executor参数,而不是在reject()调用之后使用return的组合造成的。如果没有这两种方法,您既不会reject()承诺,也不会导致拒绝async函数返回的承诺失败。修复两者,你会写

async function generateOnePDF(ticket, orderData) {
if (!ticket) throw new Error('missing ticket data');
if (!orderData) throw new Error('missing order data');
const { payload, sequence, title } = ticket;
if (!payload) throw new Error('missing payload data');
if (!sequence) throw new Error('missing ticket sequence');
if (!title) throw new Error('missing ticket book title');
const doc = new PDFDocument();
const logo = await fetchImage(`${url}/static/media/logo_157.c15ac239.svg`);
doc.addSVG(logo.toString(), 32, 40, {});
…
return new Promise((resolve, reject) => {
const stream = doc.pipe(new Base64Encode());
let finalString = '';
stream.on('data', chunk => {
finalString += chunk;
});
stream.on('end', () => {
resolve(finalString);
});
stream.on('error', reject);
doc.end();
});
});

相关内容

  • 没有找到相关文章

最新更新