Mocha 发现全局变量在扩展 class 时未定义
Mocha finds global variable is undefined when extended by class
我有来自 Chromecast 接收器的以下 ES6 模块,我想使用 Mocha 对其进行测试...
// SUT - app.js
import { Queue } from 'queue.js'
export const app = async () => {
const context = cast.framework.CastReceiverContext.getInstance();
const options = {};
options.queue = new Queue();
context.start(options);
}
此代码 运行 在 Chromecast 用户代理中,它提供对全局演员表对象的访问。这个 cast 对象公开了一个 api ,它反过来使 JS 线程能够直接与 Chromecast CAF SDK 交互。此转换变量在 运行 时间始终可用。
队列 class 有点不寻常,因为为了使其根据 CAF 框架文档工作,必须从框架 cast.framework.QueueBase
扩展抽象 class...
// queue.js
class Queue extends cast.framework.QueueBase {
initialize(){
// build queue here
}
}
现在我想写一些单元测试来检查我的 app
函数是否正确。例如:
// app.test.js
import { app } from 'app.js';
it('should do some stuff', async function () {
// inject a mock cast object
global.cast = {
framework: {
QueueBase: class {},
CastReceiverContext: {
getInstance: () => {},
},
},
};
await app();
// Make some assertions
});
但是,即使我正在使用 global.cast
注入模拟,这对于所有对 cast 对象的常规引用都足够了,在 class 是 扩展的情况下 注入的 cast 对象,显然它还不可用,我收到以下错误:
ReferenceError: cast is not defined
我发现了一个丑陋的 hack 来使这个错误消失。如果我将以下代码片段放在 class 声明之上,那么我可以在 运行 时间注入模拟,它不仅适用于 Mocha,也适用于在 Chromecast 设备上执行....
try {
// The following line throws in Mocha's node environment
// but executes fine on the Chromecast device
if (cast) {
}
} catch {
global.cast = {
framework: {
QueueBase: class {},
},
};
}
export class Queue extends cast.framework.QueueBase {
...
但是,我想找到一个更好的解决方案,这样我就不必用这个 hack 污染我的生产代码,它只允许我进行 运行 测试。
我的 .mocharc.yml
文件如下所示:
require:
- '@babel/register'
- 'ignore-styles'
- 'jsdom-global/register'
- 'babel-polyfill'
... 我对 运行 测试的命令是:
mocha --recursive --use_strict
最后,我的 .babelrc
文件如下所示:
{
"presets": [
[
"@babel/preset-env"
]
],
"plugins": [
"inline-svg",
"import-graphql"
]
}
静态导入总是先求值,所以操作顺序大致是:
import { Queue } from 'queue.js'
class Queue extends cast.framework.QueueBase { // ReferenceError outside Chromecast!
initialize(){
// build queue here
}
}
global.cast = {
framework: {
QueueBase: class {},
CastReceiverContext: {
getInstance: () => {},
},
},
};
您可以看到在 app.js 中 对 cast
的引用之后 创建了 mock。
在导入应用模块之前 运行 模拟创建的唯一可靠方法是使用动态导入:
// app.test.js
it('should do some stuff', async function () {
// inject a mock cast object
global.cast = {
framework: {
QueueBase: class {},
CastReceiverContext: {
getInstance: () => {},
},
},
};
const { app } = await import('app.js');
await app();
// Make some assertions
delete global.cast;
});
如果您不想在每个测试中重复创建模拟和 import
,您可以将两者移出测试定义:
// app.test.js
// inject a mock cast object
global.cast = {
framework: {
QueueBase: class {},
CastReceiverContext: {
getInstance: () => {},
},
},
};
const { app } = await import('app.js');
it('should do some stuff', async function () {
await app();
// Make some assertions
});
// Optionally clean up the mock after all tests
after(() => delete global.cast);
我有来自 Chromecast 接收器的以下 ES6 模块,我想使用 Mocha 对其进行测试...
// SUT - app.js
import { Queue } from 'queue.js'
export const app = async () => {
const context = cast.framework.CastReceiverContext.getInstance();
const options = {};
options.queue = new Queue();
context.start(options);
}
此代码 运行 在 Chromecast 用户代理中,它提供对全局演员表对象的访问。这个 cast 对象公开了一个 api ,它反过来使 JS 线程能够直接与 Chromecast CAF SDK 交互。此转换变量在 运行 时间始终可用。
队列 class 有点不寻常,因为为了使其根据 CAF 框架文档工作,必须从框架 cast.framework.QueueBase
扩展抽象 class...
// queue.js
class Queue extends cast.framework.QueueBase {
initialize(){
// build queue here
}
}
现在我想写一些单元测试来检查我的 app
函数是否正确。例如:
// app.test.js
import { app } from 'app.js';
it('should do some stuff', async function () {
// inject a mock cast object
global.cast = {
framework: {
QueueBase: class {},
CastReceiverContext: {
getInstance: () => {},
},
},
};
await app();
// Make some assertions
});
但是,即使我正在使用 global.cast
注入模拟,这对于所有对 cast 对象的常规引用都足够了,在 class 是 扩展的情况下 注入的 cast 对象,显然它还不可用,我收到以下错误:
ReferenceError: cast is not defined
我发现了一个丑陋的 hack 来使这个错误消失。如果我将以下代码片段放在 class 声明之上,那么我可以在 运行 时间注入模拟,它不仅适用于 Mocha,也适用于在 Chromecast 设备上执行....
try {
// The following line throws in Mocha's node environment
// but executes fine on the Chromecast device
if (cast) {
}
} catch {
global.cast = {
framework: {
QueueBase: class {},
},
};
}
export class Queue extends cast.framework.QueueBase {
...
但是,我想找到一个更好的解决方案,这样我就不必用这个 hack 污染我的生产代码,它只允许我进行 运行 测试。
我的 .mocharc.yml
文件如下所示:
require:
- '@babel/register'
- 'ignore-styles'
- 'jsdom-global/register'
- 'babel-polyfill'
... 我对 运行 测试的命令是:
mocha --recursive --use_strict
最后,我的 .babelrc
文件如下所示:
{
"presets": [
[
"@babel/preset-env"
]
],
"plugins": [
"inline-svg",
"import-graphql"
]
}
静态导入总是先求值,所以操作顺序大致是:
import { Queue } from 'queue.js'
class Queue extends cast.framework.QueueBase { // ReferenceError outside Chromecast!
initialize(){
// build queue here
}
}
global.cast = {
framework: {
QueueBase: class {},
CastReceiverContext: {
getInstance: () => {},
},
},
};
您可以看到在 app.js 中 对 cast
的引用之后 创建了 mock。
在导入应用模块之前 运行 模拟创建的唯一可靠方法是使用动态导入:
// app.test.js
it('should do some stuff', async function () {
// inject a mock cast object
global.cast = {
framework: {
QueueBase: class {},
CastReceiverContext: {
getInstance: () => {},
},
},
};
const { app } = await import('app.js');
await app();
// Make some assertions
delete global.cast;
});
如果您不想在每个测试中重复创建模拟和 import
,您可以将两者移出测试定义:
// app.test.js
// inject a mock cast object
global.cast = {
framework: {
QueueBase: class {},
CastReceiverContext: {
getInstance: () => {},
},
},
};
const { app } = await import('app.js');
it('should do some stuff', async function () {
await app();
// Make some assertions
});
// Optionally clean up the mock after all tests
after(() => delete global.cast);