0

我正在尝试使用 TypeScript、Jest 和 jQuery 编写单元测试。我已经走了很远,但是当我运行测试时,我得到“jQuery 需要一个带有文档的窗口”

显然,问题在于import * as $ from "jquery"见这个问题)也会初始化 jQuery,但当时没有窗口。我需要的是 jQuery 模块的“懒惰”版本,除了符号本身之外,$(document).ready(...)这通常是一种。$

背景:我将 jQuery 安装为npm install @types/jquery. 我jsdom用来创建一个假窗口。我正在使用ts-jest将 TS 文件转换为 JavaScript for jest. npx jest --watch使用或运行测试npm t

我想避免global.$Jest setupFile中使用,因为许多测试不需要开销。

4

1 回答 1

0

我有一个解决方案,但您不能在被测代码中使用 $,因此它仅适用于您编写/可以更改的代码。

不要$直接使用,而是将其包装在提供程序中:

export class JQueryProvider {
    constructor(public jq: any) {
        // empty
    }

    get(selector: string): JQuery {
        return this.jq(selector)
    }
}

这样,我们可以隐藏$来自哪里的细节。get()即使输入jq是type ,该方法也会将结果转换为正确的类型any

此代码应进入共享实用程序模块。

测试应该包括一个带有这个设置代码的模块:

import { JQueryProvider } from "./utils"
import { JSDOM } from "jsdom";

export type WithJQueryFunction = (jq: JQueryProvider) => void;

export function withJQuery(fn: WithJQueryFunction): void {
    // Create window before loading jquery
    const window = new JSDOM().window 

    // Create jQuery instance
    const $ = require('jquery')(window);

    // Create provider to avoid the global variable $
    const jq = new JQueryProvider($)

    fn(jq)
}

请注意,我使用require()而不是import因为我不确定如何达到相同的效果。

测试现在看起来像这样:

withJQuery((jq) => {
    describe('jQuery tests', () => {
        it('empty div', () => {
            const parent = jq.get('<div>')
            expect(parent[0]).toMatchSnapshot()
        })      

        it('empty div with class', () => {
            const parent = jq.get('<div>').addClass('foo')
            expect(parent[0]).toMatchSnapshot()
        })      
    })
})

生产代码示例:

export class DivAppender implements Appender {
    constructor(public jq: JQueryProvider, public parent: JQuery, public dateFormat = TIME_FORMAT) {
        // empty
    }

    append(event: LogEvent): void {
        const element = this.jq.get('<div>').addClass('event')
        ...

const appender = new DivAppender(new JQueryProvider($), $('body'))
于 2019-07-12T09:39:29.090 回答