如何在NodeJS中测试服务器发送事件(SSE)路由?

问题描述 投票:7回答:1

我在NodeJS应用上有一个“服务器发送事件”路由,客户端可以订阅该路由,客户端可以从服务器获取实时更新。看起来如下:

router.get('/updates', (req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    })

    const triggered = (info) => {
        res.write(`\ndata: ${JSON.stringify(info)}\n\n`)
    }

    eventEmitter.addListener(constants.events.TRIGGERED, triggered)

    req.on('close', () => {
        eventEmitter.removeListener(constants.events.TRIGGERED, triggered)
    })
})

在节点中使用supertest测试传统路由非常简单:

test('Should get and render view', async() => {
    const res = await request(app)
        .get('/')
        .expect(200)

    expect(res.text).not.toBeUndefined()
})

但是,这在测试SSE路由时不起作用。

有人对如何使用Node测试SSE路由有任何想法吗?不一定必须使用supertest进行测试。只是想寻找有关如何测试的想法,supertest或其他。

编辑:我对如何进行集成测试有一个想法。基本上,必须在测试之前启动服务器,在测试期间订阅它,然后在测试之后关闭它。但是,当我使用beforeEach()和afterEach()启动服务器时,它无法达到Jest的预期效果。

node.js server-sent-events supertest
1个回答
3
投票

我会模拟/伪造终结点使用的所有内容,并检查终结点是否使用正确的变量以正确的顺序执行。首先,我将在端点外部声明trigger函数和close事件回调,以便可以直接对其进行测试。其次,我将消除所有函数中的所有全局引用,而推荐使用函数参数:

let triggered = (res) => (info) => {
    res.write(`\ndata: ${JSON.stringify(info)}\n\n`);
}

let onCloseHandler = (eventEmitter, constants, triggered, res) => () => {
    eventEmitter.removeListener(constants.events.TRIGGERED, triggered(res));
}

let updatesHandler = (eventEmitter, constants, triggered) => (req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    eventEmitter.addListener(constants.events.TRIGGERED, triggered(res));

    req.on('close', onCloseHandler(eventEmitter, constants, triggered, res));
};

router.get('/updates', updatesHandler(eventEmitter, constants, triggered));

使用此代码,测试用例将像:

test("triggered", () => {
    let res;

    beforeEach(() => {
        res = generateFakeRespone();
    });

    it("should execute res.write with the correct variable", () => {
        trigger(res)("whatever");

        expect(res.write).to.have.been.called.once;
        expect(res.write).to.have.been.called.with(`\ndata: ${JSON.stringify("whatever")}\n\n`);
    });
});


test("onCloseHandler", () => {
    let res;
    let eventEmitter;
    let constants;
    let triggered;

    beforeEach(() => {
        res = Math.random();
        eventEmitter = generateFakeEventEmitter();
        constants = generateFakeConstants();
        triggered = generateFakeTriggered();
    });

    it("should execute eventEmitter.removeListener", () => {
        onCloseHandler(eventEmitter, constants, triggered, res);

        expect(eventEmitter.removeListener).to.have.been.called.once;
        expect(eventEmitter.removeListener).to.have.been.called.with(/*...*/)
    });
});

test("updatesHandler", () => {
    beforeEach(() => {
        req = generateFakeRequest();
        res = generateFakeRespone();
        eventEmitter = generateFakeEventEmitter();
        constants = generateFakeConstants();
        triggered = generateFakeTriggered();
    });

    it("should execute res.writeHead", () => {
        updatesHandler(eventEmitter, constants, triggered)(req, res);

        expect(res.writeHead).to.have.been.called.once;
        expect(res.writeHead).to.have.been.called.with(/*...*/)
    });

    it("should execute req.on", () => {
        //...
    });

    // more tests ...
});

通过这种编码和测试风格,您可以进行非常详细的单元测试。缺点是要花费更多的精力来正确测试所有内容。

© www.soinside.com 2019 - 2024. All rights reserved.