如何从Jasmine更改包含的Javascript文件中定义的全局变量? 背景

如何从Jasmine更改包含的Javascript文件中定义的全局变量? 背景,javascript,node.js,jasmine,Javascript,Node.js,Jasmine,我花了几个小时试图找到这个问题的答案,但这可能是因为我对require.js缺乏理解 下面是我的工作内容:我有一个紧密耦合的传统企业web应用程序,它是在2001年编写的,当时使用的是IE5特定的Javascript。Javascript文件名为Menu.js,其功能使HTML表格能够像菜单一样工作,其中表格单元格是菜单项,其中一些菜单项可以展开子菜单,子菜单是更多的表格单元格 简而言之,代码是错误的。但是,我必须提供一个创可贴,使之与Chrome和Firefox兼容。解决方案是重写每个Java

我花了几个小时试图找到这个问题的答案,但这可能是因为我对
require.js
缺乏理解

下面是我的工作内容:我有一个紧密耦合的传统企业web应用程序,它是在2001年编写的,当时使用的是IE5特定的Javascript。Javascript文件名为
Menu.js
,其功能使HTML表格能够像菜单一样工作,其中表格单元格是菜单项,其中一些菜单项可以展开子菜单,子菜单是更多的表格单元格

简而言之,代码是错误的。但是,我必须提供一个创可贴,使之与Chrome和Firefox兼容。解决方案是重写每个Javascript函数的内部,以使用jQuery,这样它就可以跨浏览器兼容

每个网页都包含
Menu.js
,并且每个网页都是自动生成的,因此我被迫通过从
Menu.js
注入jQuery来包含它,它有以下代码:

spyOn(sut, 'injectJquery').and.callFake(() => null);
Menu.js

function injectQuery() {
  const script = document.createElement('script');
  script.src = 'https://code.jquery.com/jquery-3.2.1.min.js';
  document.getElementByTagName('head')[0].appendChild(script);
}

injectJQuery();

function getSubMenu(el) {
  return $(el).find('table')[0] || null;
}

// Other functions are defined here as well

if ( typeof module !=== 'undefined' && module.hasOwnProperty('exports') ) {
  module.exports.getSubMenu = getSubMenu;
}
const sut = require('../src/js/Menu.js');
const testMenu = require('./resources/test.menu').data();

const { JSDOM } = require('jsdom');
const { window } = new JSDOM();
const { document } = window.window;
const jQuery = require('jquery')(window);

global.$ = jQuery;

describe('getSubMenu()', () => {
  beforeEach(() => {
    document.querySelector('body').innerHTML = testMenu;
  });

  it('should return the nested sub-menu-3 table given the sub-menu-2 element', () => {
    const subMenu2 = $('#sub-menu-2');
    const result = sut.getSubMenu(subMenu2);

    expect(result.id).toBe('sub-menu-3');
  });
});
var isUnderTest = false;

...

if (!isUnderTest) {
  injectJquery();
}

...

if ( typeof module !=== 'undefined' && module.hasOwnProperty('exports') ) {
  ...
  module.exports.isUnderTest = isUnderTest;
}
在Jasmine中,当测试
Menu.js
时,我无法使用
$()
函数而不会得到未定义的错误。为了解决这个问题,我有以下代码:

spyOn(sut, 'injectJquery').and.callFake(() => null);
menu.spec.js

function injectQuery() {
  const script = document.createElement('script');
  script.src = 'https://code.jquery.com/jquery-3.2.1.min.js';
  document.getElementByTagName('head')[0].appendChild(script);
}

injectJQuery();

function getSubMenu(el) {
  return $(el).find('table')[0] || null;
}

// Other functions are defined here as well

if ( typeof module !=== 'undefined' && module.hasOwnProperty('exports') ) {
  module.exports.getSubMenu = getSubMenu;
}
const sut = require('../src/js/Menu.js');
const testMenu = require('./resources/test.menu').data();

const { JSDOM } = require('jsdom');
const { window } = new JSDOM();
const { document } = window.window;
const jQuery = require('jquery')(window);

global.$ = jQuery;

describe('getSubMenu()', () => {
  beforeEach(() => {
    document.querySelector('body').innerHTML = testMenu;
  });

  it('should return the nested sub-menu-3 table given the sub-menu-2 element', () => {
    const subMenu2 = $('#sub-menu-2');
    const result = sut.getSubMenu(subMenu2);

    expect(result.id).toBe('sub-menu-3');
  });
});
var isUnderTest = false;

...

if (!isUnderTest) {
  injectJquery();
}

...

if ( typeof module !=== 'undefined' && module.hasOwnProperty('exports') ) {
  ...
  module.exports.isUnderTest = isUnderTest;
}
问题 无论何时运行规范,都会出现以下错误:

const script = document.createElement('script');
                        ^
ReferenceError: document is not defined
    at injectJquery
因此,我不希望在Jasmine规范运行时运行
Menu.js
中定义的
injectJquery()
方法。我尝试了以下方法:

尝试1-将全局值从Jasmine更改为

Menu.js

function injectQuery() {
  const script = document.createElement('script');
  script.src = 'https://code.jquery.com/jquery-3.2.1.min.js';
  document.getElementByTagName('head')[0].appendChild(script);
}

injectJQuery();

function getSubMenu(el) {
  return $(el).find('table')[0] || null;
}

// Other functions are defined here as well

if ( typeof module !=== 'undefined' && module.hasOwnProperty('exports') ) {
  module.exports.getSubMenu = getSubMenu;
}
const sut = require('../src/js/Menu.js');
const testMenu = require('./resources/test.menu').data();

const { JSDOM } = require('jsdom');
const { window } = new JSDOM();
const { document } = window.window;
const jQuery = require('jquery')(window);

global.$ = jQuery;

describe('getSubMenu()', () => {
  beforeEach(() => {
    document.querySelector('body').innerHTML = testMenu;
  });

  it('should return the nested sub-menu-3 table given the sub-menu-2 element', () => {
    const subMenu2 = $('#sub-menu-2');
    const result = sut.getSubMenu(subMenu2);

    expect(result.id).toBe('sub-menu-3');
  });
});
var isUnderTest = false;

...

if (!isUnderTest) {
  injectJquery();
}

...

if ( typeof module !=== 'undefined' && module.hasOwnProperty('exports') ) {
  ...
  module.exports.isUnderTest = isUnderTest;
}
menu.spec.js
中,我尝试设置以下内容:

sut.isUnderTest = true;
try {
  injectJquery();
} catch (e) {
  if (e instanceof ReferenceError) {
    // The system is under test: do nothing
  }
}
但是,规范仍然试图执行
injectJquery()
,我收到了相同的错误。我尝试为
isUnderTest
变量定义一个setter函数并调用它,然后导出该函数,但仍然收到相同的错误

尝试2-使用Jasmine spy强制函数不执行任何操作

我尝试使用Jasmine spy使函数不执行规范中的任何操作,代码如下:

spyOn(sut, 'injectJquery').and.callFake(() => null);
我确实从
Menu.js
中导出了
injectJquery()
函数;然而,这也不起作用

尝试3-定义节点全局变量

我试图在
menu.spec.js
中定义一个节点全局变量,如下所示:

global.isUnderTest = true;
但是,它仍然不起作用

最后的想法 我来自Java世界,使用JUnit,我希望我在Jasmine中定义的系统测试对象的行为与Java类似,尽管我知道Javascript文件
Menu.js
,不是一个对象


我希望
injectJquery()
在浏览器中运行,但不在规范中运行。是否有任何方法可以抑制我没有看到的方法调用?

经过长时间的尝试和错误,我决定使用一种黑客方法来解决此问题,方法是执行以下操作:

sut.isUnderTest = true;
try {
  injectJquery();
} catch (e) {
  if (e instanceof ReferenceError) {
    // The system is under test: do nothing
  }
}

希望这能帮助使用Jasmine测试遗留Javascript的其他人。

您不能将普通的
文档
Javascript包含到主文件中,它需要链接到html文件。