基于Ui的集成测试无法从ElementID获取预期值

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

首先也是最重要的。我是一个完全的初学者。我没有先验知识或共识,所以我不知道我在做什么,但我知道这是一项作业。此时我已经在这一部分上停留了几个小时了。一些背景信息。我正在使用 JSDOM UI 集成测试来完成我的任务。在本例中,我们使用罗马数字转换器。更具体地说,是旧罗马数字到现代罗马数字。

这是我的 romanNumerals.html 文件

<!DOCTYPE html>
<html lang="en">
    <head>
        <link rel="stylesheet" href="romanNumerals.css">
        <script src="romanNumerals.js" defer></script>
    </head>
    <body>
        <div class="results">
            <div class="result">
                <div id="old-roman-result"></div>
                "Old" Roman Numeral
            </div>
            <div class="result">
                <div id="modern-roman-result"></div>
                "Modern" Roman Numeral
            </div>
        </div>
        <form id="arabic-number-form">
            <label>
                Arabic number (1-3999)
                <input type="number" min="1" max="3999" id="arabic-number" name="arabic-number" />
            </label>
            <button>Convert to "modern" Roman</button>
        </form>
    </body>
</html>

这是我的 romanNumerals.js 文件

/**
 * This function initializes the JavaScript functionality after the HTML content is loaded.
 */
window.addEventListener('DOMContentLoaded', () => {
    const arabicNumberInput = document.getElementById("arabic-number");
    const form = document.getElementById("arabic-number-form");
    const oldRomanResult = document.getElementById("old-roman-result");
    const modernRomanResult = document.getElementById("modern-roman-result");

    /*
     * Clear Arabic number input field when the page first loads.
     */
    arabicNumberInput.value = "";

    /*
     * Add a listener to the Arabic number input field to listen for typing and
     * update the "old" Roman numeral result "live" as the user types.  If the
     * value input by the user can't be converted to an "old" Roman numeral,
     * don't display any value.
     */
    arabicNumberInput.addEventListener("input", function () {
        modernRomanResult.textContent = "";
        const arabicNumber = parseInt(arabicNumberInput.value);
        try {
            oldRomanResult.textContent = convertToOldRoman(arabicNumber);
        } catch (err) {
            oldRomanResult.textContent = "";
        }
    });

    /*
     * When the user actually submits the form, send a request to the API described
     * here to convert the number to a "modern" Roman numeral:
     *
     * https://helloacm.com/tools/romans/
     *
     * If an error occurs in the translation, an error message is displayed.
     */
    form.addEventListener("submit", async function (event) {
        event.preventDefault();
        clearErrorMessages();
        const arabicNumber = arabicNumberInput.value;
        try {
            const response = await fetch(
                `https://romans.justyy.workers.dev/api/romans/?n=${arabicNumber}`
            );
            const data = await response.json();
            if (data.error) {
                displayError(data.error);
            } else {
                modernRomanResult.textContent = data.result;
            }
        } catch (err) {
            displayError(err.message);
        }
    });

    /*
     * This function displays an error message to the user if the translation
     * request failed for any reason.
     */
    function displayError(errorMsg) {
        const errorDiv = document.createElement("div");
        errorDiv.classList.add("error");
        errorDiv.setAttribute("role", "alert");
        errorDiv.innerHTML = "<h3>❌ Error</h3>";

        /*
         * The error message may have come from the outside world, so we have to
         * treat it cautiously, making sure it's not executed as HTML code.
         */
        const errorMsgP = document.createElement("p");
        errorMsgP.textContent = errorMsg;
        errorDiv.appendChild(errorMsgP);

        form.appendChild(errorDiv);
    }

    /*
     * This function removes any error message currently being displayed to the
     * user.
     */
    function clearErrorMessages() {
        const errors = form.querySelectorAll(".error");
        errors.forEach(function (error) {
            error.remove();
        });
    }

    /*
     * This table represents the conversions between Roman digits and Arabic values.
     */
    const conversionTable = {
        "M": 1000,
        "C": 100,
        "L": 50,
        "X": 10,
        "V": 5,
        "I": 1
    };

    /**
     * This function converts an Arabic number into the corresponding "old" Roman
     * numeral.  Old Roman numerals are based only on addition.  For example, the
     * Arabic number 9 is "VIIII" in old Roman numerals (it's "IX" in modern Roman
     * numerals).
     *
     * @param {number} input A numeric value representing the Arabic number to
     *   convert to old Roman numerals.  Must be in the range 1-3999.  Any decimal
     *   part of the number is ignored.
     *
     * @throws {RangeError} Throws a RangeError if the input value is a number
     *   outside the range 1-3999.
     * @throws {Error} Throws an Error if the input is not a number.
     *
     * @returns {string} Returns a string containing the old Roman numeral
     *   conversion for the specified input value.
     */
    function convertToOldRoman(input) {
        if (input === undefined || typeof input !== "number") {
            throw Error("Expected a number parameter");
        }
        if (input < 1 || input > 3999) {
            throw RangeError("Input must be in range 1-3999");
        }

        /*
         * Cycle through Roman digits from greatest (M) to least (I).  For each
         * digit, subtract the corresponding Arabic value from the input number
         * as many times as possible, adding an instance of the current Roman
         * to the resultint translation for each subtraction.
         */
        const romanDigits = Object.keys(conversionTable);
        let currRomanIdx = 0;
        let result = "";
        while (input > 0 && currRomanIdx < romanDigits.length) {
            const currRomanDigit = romanDigits[currRomanIdx];
            const currArabicValue = conversionTable[currRomanDigit];
            while (input >= currArabicValue) {
                result += currRomanDigit;
                input -= currArabicValue;
            }
            currRomanIdx++;
        }
        return result;
    }

});

这是我的 romanNumerals.test.js 文件

/**
 * @jest-environment jsdom
 */

// Polyfill TextEncoder
global.TextEncoder = require('util').TextEncoder;
global.TextDecoder = require('util').TextDecoder;

const fs = require("fs");
const { JSDOM } = require("jsdom");
const { fireEvent, waitFor } = require("@testing-library/dom");
const userEvent = require("@testing-library/user-event").default;
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");

// Load HTML content
const htmlContent = fs.readFileSync("./romanNumerals/romanNumerals.html", "utf8");
const { document } = new JSDOM(htmlContent).window;

// Mock the API response for conversion to "modern" Roman numerals
const mock = new MockAdapter(axios);
mock.onGet("https://romans.justyy.workers.dev/api/romans/?n=123").reply(200, { result: "CXXIII" });

function initDomFromFiles() {
    document.body.innerHTML = htmlContent;
    require("./romanNumerals.js");
}

test("should update 'modern' Roman numeral result on form submission", async () => {
    // Arrange
    initDomFromFiles();
    const arabicNumberInput = document.getElementById("arabic-number");
    const convertButton = document.querySelector("button");
    const modernRomanResult = document.getElementById("modern-roman-result");

    // Act:
    const user = userEvent.setup();
    await user.type(arabicNumberInput, "123");
    await user.click(convertButton);
    // Assert
    await waitFor(() => {
        expect(document.getElementById("modern-roman-result").textContent).toBe("CXXIII");
    });
});

我完全不知所措。我运行 npx jest。测试失败。因为实际值没什么,但应该是

CXXIII
我尝试使用API,我尝试使用从js文件导入的函数。没有什么对我有用。如果我能得到任何帮助,我将不胜感激。

javascript jestjs jsdom
1个回答
0
投票

您可以通过将您希望提交触发的功能与实际提交分开来解决这个问题。因此它成为一个可测试的单元,您可以

await
。您遇到的问题是,您单击了按钮并期望文本发生更改,但它尚未更改。请求被发送到 API,一旦到达目的地,目的地就会对其进行处理、发送响应并且您的浏览器收到它,文本就会更新。但点击按钮并不会等待这一切。

/**
 * This function initializes the JavaScript functionality after the HTML content is loaded.
 */
window.addEventListener('DOMContentLoaded', () => {
    const arabicNumberInput = document.getElementById("arabic-number");
    const form = document.getElementById("arabic-number-form");
    const oldRomanResult = document.getElementById("old-roman-result");
    const modernRomanResult = document.getElementById("modern-roman-result");

    /*
     * Clear Arabic number input field when the page first loads.
     */
    arabicNumberInput.value = "";

    /*
     * Add a listener to the Arabic number input field to listen for typing and
     * update the "old" Roman numeral result "live" as the user types.  If the
     * value input by the user can't be converted to an "old" Roman numeral,
     * don't display any value.
     */
    arabicNumberInput.addEventListener("input", function () {
        modernRomanResult.textContent = "";
        const arabicNumber = parseInt(arabicNumberInput.value);
        try {
            oldRomanResult.textContent = convertToOldRoman(arabicNumber);
        } catch (err) {
            oldRomanResult.textContent = "";
        }
    });

    /*
     * When the user actually submits the form, send a request to the API described
     * here to convert the number to a "modern" Roman numeral:
     *
     * https://helloacm.com/tools/romans/
     *
     * If an error occurs in the translation, an error message is displayed.
     */
    async function mysubmit() {
        clearErrorMessages();
        const arabicNumber = arabicNumberInput.value;
        try {
            const response = await fetch(
                `https://romans.justyy.workers.dev/api/romans/?n=${arabicNumber}`
            );
            const data = await response.json();
            if (data.error) {
                displayError(data.error);
            } else {
                modernRomanResult.textContent = data.result;
                console.log(modernRomanResult.textContent);
            }
        } catch (err) {
            displayError(err.message);
        }
    }
    form.addEventListener("submit", async function (event) {
        event.preventDefault();
        mysubmit();
    });

    /*
     * This function displays an error message to the user if the translation
     * request failed for any reason.
     */
    function displayError(errorMsg) {
        const errorDiv = document.createElement("div");
        errorDiv.classList.add("error");
        errorDiv.setAttribute("role", "alert");
        errorDiv.innerHTML = "<h3>❌ Error</h3>";

        /*
         * The error message may have come from the outside world, so we have to
         * treat it cautiously, making sure it's not executed as HTML code.
         */
        const errorMsgP = document.createElement("p");
        errorMsgP.textContent = errorMsg;
        errorDiv.appendChild(errorMsgP);

        form.appendChild(errorDiv);
    }

    /*
     * This function removes any error message currently being displayed to the
     * user.
     */
    function clearErrorMessages() {
        const errors = form.querySelectorAll(".error");
        errors.forEach(function (error) {
            error.remove();
        });
    }

    /*
     * This table represents the conversions between Roman digits and Arabic values.
     */
    const conversionTable = {
        "M": 1000,
        "C": 100,
        "L": 50,
        "X": 10,
        "V": 5,
        "I": 1
    };

    /**
     * This function converts an Arabic number into the corresponding "old" Roman
     * numeral.  Old Roman numerals are based only on addition.  For example, the
     * Arabic number 9 is "VIIII" in old Roman numerals (it's "IX" in modern Roman
     * numerals).
     *
     * @param {number} input A numeric value representing the Arabic number to
     *   convert to old Roman numerals.  Must be in the range 1-3999.  Any decimal
     *   part of the number is ignored.
     *
     * @throws {RangeError} Throws a RangeError if the input value is a number
     *   outside the range 1-3999.
     * @throws {Error} Throws an Error if the input is not a number.
     *
     * @returns {string} Returns a string containing the old Roman numeral
     *   conversion for the specified input value.
     */
    function convertToOldRoman(input) {
        if (input === undefined || typeof input !== "number") {
            throw Error("Expected a number parameter");
        }
        if (input < 1 || input > 3999) {
            throw RangeError("Input must be in range 1-3999");
        }

        /*
         * Cycle through Roman digits from greatest (M) to least (I).  For each
         * digit, subtract the corresponding Arabic value from the input number
         * as many times as possible, adding an instance of the current Roman
         * to the resultint translation for each subtraction.
         */
        const romanDigits = Object.keys(conversionTable);
        let currRomanIdx = 0;
        let result = "";
        while (input > 0 && currRomanIdx < romanDigits.length) {
            const currRomanDigit = romanDigits[currRomanIdx];
            const currArabicValue = conversionTable[currRomanDigit];
            while (input >= currArabicValue) {
                result += currRomanDigit;
                input -= currArabicValue;
            }
            currRomanIdx++;
        }
        return result;
    }

    async function foo() {
        const arabicNumberInput = document.getElementById("arabic-number");
        const convertButton = document.querySelector("button");
        const modernRomanResult = document.getElementById("modern-roman-result");

        // Act:
        arabicNumberInput.value = "123";
        //convertButton.click();
        await mysubmit();
        // Assert
            console.log(modernRomanResult.textContent);//.toBe("CXXIII");
    };
    foo();

});
<!DOCTYPE html>
<html lang="en">
    <head>
        <link rel="stylesheet" href="romanNumerals.css">
        <script src="romanNumerals.js" defer></script>
    </head>
    <body>
        <div class="results">
            <div class="result">
                <div id="old-roman-result"></div>
                "Old" Roman Numeral
            </div>
            <div class="result">
                <div id="modern-roman-result"></div>
                "Modern" Roman Numeral
            </div>
        </div>
        <form id="arabic-number-form">
            <label>
                Arabic number (1-3999)
                <input type="number" min="1" max="3999" id="arabic-number" name="arabic-number" />
            </label>
            <button>Convert to "modern" Roman</button>
        </form>
    </body>
</html>

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