集成测试节点模块中的获取调用

Integration testing a fetch calls in a node module

目标: 调用一个调用 fetch 调用的函数以验证它是否适用于我的后端 rest-api(基本上是端到端测试)。

项目: 构建节点模块以导入到多个 React Web 应用程序中。该模块仅包含提取调用和最少的逻辑。它基本上是 URL 和设置的美化包装器。创建是为了减少实现应用程序中使用的通用端点所需的工作。

设置: 我有一个 docker 构建一个 docker 测试容器并拉入我的 rest-api docker 图像(建立在不同的系统中)。测试容器拉入打包模块并使用依赖项安装它。然后它会在后端和后端所需的其他图像(数据库、登录系统等)旁边显示测试。

问题:如何实施测试来处理调用。

目前我试过直接调用获取方法。这适用于我的登录提取,但任何其他调用都无法发送 cookie。据我了解,我拥有的代码取决于 cookie 的浏览器。我已经尝试了几种解决方案来获取所述 cookie,但我一直无法获取 node-fetch 以正确发送它。我最好的猜测是每个测试都在创建一个新的 cookie,但我缺乏完全调试此解决方案路径的知识。

我的发送解决方案路径是尝试使用 puppeteer 加载虚假页面,然后评估页面中的函数,例如: https://github.com/puppeteer/puppeteer/issues/2579

问题是测试一直无法加载所需的库或其他一些问题。

代码:

这是我要测试的大部分调用。我拥有的每个函数都围绕着这个提供 {url: "api/endpoint/path", method: "GET"}。对于较大的数据帖子,有些人会传入 body。

 export function request(options) {

    //Build options
    options = {
        headers: {
            'Content-Type': 'application/json'
        },
        ...options
    };

    return fetch(options.url, options)
        .then(response => {
            //...

            //Handle errors
            if (!response.ok) {
                return Promise.reject(`${response.status} - ${response.statusText}`);
            }

            try {
                return response.json();
            } catch (e) {
                if (e.name === 'SyntaxError') {
                    return Promise.reject(response.text());
                }
            }
        });
}

我试过的测试例子:

import puppeteer from "puppeteer";
import {myCall} from "my-rest-bridge";

it('Check response', async () => {

    //Load browser
    const browser = await puppeteer.launch({
        headless: true,
        args: ['--no-sandbox']
    });
    const page = await browser.newPage();

    //Load page
    await page.goto('http://docker:8888/index.html');

    //Do login
    expect(await page.evaluate(() => login('user', 'password')).toBe(expectedUserResponseJson);

    //Make call
    expect(await page.evaluate(() => myCall(input1, input2)).toBe(expectedCallResponseJson);

    //Close page
    await page.close();
})

花了我一段时间,但我为自己的问题构建了一个解决方案。它并不完美,所以如果有人有更好的想法请回答。

所以我的解决方案如下。我构建了一个附加 git 项目来在 docker 图像中创建一个 shell reactjs 应用程序。这个应用程序拉入我的节点模块,遍历所有导出,然后为每个函数生成一个组件。

import React from 'react';
import * as magicNodeModule from "magic-node-module"; //obviously not the real name
import CallRest from "./CallRest";

/** Core component for the application */
export default class App extends React.Component {

    /** Renders the core application */
    render() {
        const restCalls = Object.keys(magicNodeModule);
        return (
            <div id={"App"}>
                <div>
                    Functions found:
                    <ul id={"function-list"}>
                        {restCalls.map(restCall => <li>{restCall}</li>)}
                    </ul>
                    <hr/>
                </div>
                {
                    restCalls.map(restCall => {
                        return (
                            <CallRest restName={restCall} restCall={magicNodeModule[restCall]}/>
                        );
                    })
                }
            </div>
        )
    }
}


此组件 (CallRest) 包含输入框、提交按钮和输出 div。用户,或者在我的用例中是人偶操纵者,可以将数据输入到输入中。然后通过单击提交,它将 运行 提取调用并将结果输出插入 div。对于那些熟悉该系统的人来说,它的工作方式非常像 swagger 2。

该解决方案仍然构建为一系列 docker 图像在 compose 中。尽管它确实需要设置反向代理以允许 React 应用程序与后端通信 API。它还将节点模块的新副本作为压缩包拉入,并将其安装到 docker 中。这样我只需要构建 shell react docker 千载难逢。