开玩笑:测试window.location.reload

时间:2019-04-16 16:21:33

标签: javascript jestjs

如何编写测试以确保方法reloadFn实际上确实重新加载了窗口?我找到了this resource,但不清楚在给定函数中发生窗口重载时编写测试时如何期望窗口重载。感谢您的帮助!

const reloadFn = () => {
  window.location.reload(true);
}

7 个答案:

答案 0 :(得分:7)

  1. 创建副本,然后删除窗口的location属性。
  2. 使用reload函数模拟设置属性。
  3. 现在在测试完成时将原始值重新设置。

代码:

const location: Location = window.location;
delete window.location;
window.location = {
    ...location,
    reload: jest.fn()
};

// <code to test>
// <code to test>
// <code to test>

expect(window.location.reload).toHaveBeenCalledTimes(1);
jest.restoreAllMocks();
window.location = location;

答案 1 :(得分:6)

这是解决方案,但为了更好的组织而进行了重构:

describe('test window location\'s reload function', () => {
  const { reload } = window.location;

  beforeAll(() => {
    Object.defineProperty(window.location, 'reload', {
      configurable: true,
    });
    window.location.reload = jest.fn();
  });

  afterAll(() => {
    window.location.reload = reload;
  });

  it('mocks reload function', () => {
    expect(jest.isMockFunction(window.location.reload)).toBe(true);
  });

  it('calls reload function', () => {
    reloadFn(); // as defined above..
    expect(window.location.reload).toHaveBeenCalled();
  });
});

谢谢:)

答案 2 :(得分:6)

您可以使用sessionStorage为每次重新加载保存一个值。 只要浏览器没有关闭,该值将保留在sessionStorage中。 页面重新加载时,该值将增加。验证新的重载与此值。 通过将reloadFn()粘贴到控制台中进行测试。 控制台将显示Reload count:1,并随每次重新加载而增加。

const reloadFn = () => {
  window.location.reload(true);
}

window.onload = function() {
    // get reloadCount from sessionStorage
    reloadCount = sessionStorage.getItem('reloadCount');

    // reloadCount will be null the first page load or a new value for each reload
    if (reloadCount) {
        // increment reloadCount
        reloadCount = parseInt(reloadCount) + 1;
        // save the new value to sessionStorage
        sessionStorage.setItem('reloadCount', reloadCount);
        console.log("Reload count: " + reloadCount);
    } else {
        // if reloadCount was null then set it to 1 and save to sessionStorage
        sessionStorage.setItem('reloadCount', 1);
        console.log("Page was loaded for the first time");
    }
}

答案 3 :(得分:4)

在功能测试reloadFn中,您应该使用链接到的模拟代码:

Object.defineProperty(window.location, 'reload', {
    configurable: true,
}); // makes window.location.reload writable
window.location.reload = jest.fn(); // set up the mock
reloadFn(); // this should call your mock defined above
expect(window.location.reload).toHaveBeenCalled(); // assert the call
window.location.reload.mockRestore(); // restore window.location.reload to its original function

要进行更好的测试,可以使用

expect(window.location.reload).toHaveBeenCalledWith(true);

值得注意的是,这实际上不是在验证是否重新加载了窗口,而该窗口不在单元测试的范围之内。诸如浏览器测试或集成测试之类的东西都可以验证这一点。

答案 4 :(得分:2)

您还可以将Murtaza Hussain的解决方案简化为

  describe('refreshPage', () => {
    const { reload } = window.location;

    beforeAll(() => {
      Object.defineProperty(window, 'location', {
        writable: true,
        value: { reload: jest.fn() },
      });
    });

    afterAll(() => {
      window.location.reload = reload;
    });

    it('reloads the window', () => {
      refreshPage();
      expect(window.location.reload).toHaveBeenCalled();
    });
  });

答案 5 :(得分:1)

如果有人要在2020年进行查找,那么我也要发布相同的消息。

为什么问题在某些人而不是其他人中发生?

这完全取决于您所运行的chrome版本,我为最终称为window.location.reload的组件编写了一个测试。以下是组件代码部分:

onConfirmChange() {
    const {data, id} = this.state;

    this.setState({showConfirmationModal: false}, () => {
        this.update(data, id)
          .then(() => window.location.reload());
    });
}

该测试最初在chrome版本为71的构建服务器上失败,该测试通过了chrome版本为79的本地计算机。 我今天将chrome更新为版本84,该问题在我的本地系统中弹出 似乎不支持删除window.local。尝试了所有我可以在Google中找到的解决方案,但没有用。

那是什么解决方案?

实际上非常简单,为了进行反应测试,我的系统正在使用酶,因此我所做的工作是将window.location.reload包裹在实例方法中并存入测试中

JSX代码:

reloadWindow() {
    window.location.reload();
}

onConfirmChange() {
    const {data, id} = this.state;
  
    this.setState({showConfirmationModal: false}, () => {
      this.update(data, id)
        .then(() => reloadWindow());
    });   
}

测试

it('check what happened', () => {
    render();
    const component = wrapper.instance();
    sandbox.stub(component, 'reloadWindow').callsFake();
});

答案 6 :(得分:0)

更新答案(2021 年 5 月)

我在线程中的很多答案中遇到了一些问题。我认为随着时间的推移,底层库的版本变化导致了损坏。

我的配置:

  • "typescript": "~4.1.5"
  • "jest": "^26.6.3"
  • "jest-environment-jsdom": "^26.6.2"

另外,我应该注意,我的解决方案非常冗长。但我的用例需要测试 window.location.replace() 和结果。所以我不能 简单地模拟window.location.replace。如果您只需要模拟其中一个函数,而不关心实际 href 的变化,那么线程中的一些解决方案会以更少的代码工作得很好。

工作版本

我发现完全填充 window.location 对象解决了我所有的问题。

window.location 填充

使用此代码并将其放在测试文件或设置文件中的任何位置:

export class MockWindowLocation {
  private _url: URL = new URL();

  get href (): string {
    return this._url.toString();
  }

  set href (url: string) {
    this._url = new URL(url);
  }

  get protocol (): string {
    return this._url.protocol;
  }

  get host (): string {
    return this._url.host;
  }

  get hostname (): string {
    return this._url.hostname;
  }

  get origin (): string {
    return this._url.origin;
  }

  get port (): string {
    return this._url.port;
  }

  get pathname (): string {
    return this._url.pathname;
  }

  get hash (): string {
    return this._url.hash;
  }

  get search (): string {
    return this._url.search;
  }

  replace = jest.fn().mockImplementation((url: string) => {
    this.href = url;
  });

  assign = jest.fn().mockImplementation((url: string) => {
    this.href = url;
  });

  reload = jest.fn();

  toString(): string {
    return this._url.toString();
  }
}

测试一下

然后你必须删除 window.location 并将其设置为新的 polyfill:

  it('should be able to test window.location', () => {
    delete window.location;
    Object.defineProperty(window, 'location', {
      value: new MockWindowLocation()
    });

    window.location.href = 'https://example.com/app/#/route/1';
    window.location.reload();

    expect(window.location.reload).toHaveBeenCalled();
    expect(window.location.href).toBe('https://example.com/app/#/route/1');
    expect(window.location.pathname).toBe('/app/');
    expect(window.location.hash).toBe('#/route/1');
  });

这对我来说很神奇。希望能帮到别人。

其他答案更简单

再次重申,此线程中还有其他答案可以正常工作。我发现:

Object.defineProperty(window, 'location', {
  writable: true,
  value: { reload: jest.fn() },
});

还有:

const location: Location = window.location;
delete window.location;
window.location = {
  ...location,
  reload: jest.fn()
};

两者都有帮助。但就像我说的,我需要监视 replace() 并且仍然拥有 window.location 的标准功能。

希望这对某人有所帮助。干杯!