/ tests / RegisterValidatorJavascriptTest.php
<?php
/**
 * SeekQuarry/Yioop --
 * Open Source Pure PHP Search Engine, Crawler, and Indexer
 *
 * Copyright (C) 2009 - 2026  Chris Pollett chris@pollett.org
 *
 * LICENSE:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * END LICENSE
 *
 * @author Chris Pollett chris@pollett.org
 * @license https://www.gnu.org/licenses/ GPL3
 * @link https://www.seekquarry.com/
 * @copyright 2009 - 2026
 * @filesource
 */
namespace seekquarry\yioop\tests;

use seekquarry\yioop\library\JavascriptUnitTest;

/**
 * Tests how register_validator.js treats a password box that the site
 * drew holding a stand-in for a password nobody is changing, which is
 * what the Manage Users screen does. Such a box must not be judged
 * against the password rules and must not stop its form being sent,
 * since every other change to that account travels on the same form.
 *
 * @author Chris Pollett
 */
class RegisterValidatorJavascriptTest extends JavascriptUnitTest
{
    /**
     * Checks that a box still holding the stand-in shows no missing
     * requirement and lets its form be sent, that typing a password of
     * one's own brings the judging back, and that a box which carries no
     * stand-in is judged as it loads the way it always was.
     *
     * @return string html and Javascript that checks the answer in a
     *      browser or, from the command line, under node
     */
    public function standInPasswordIsLeftAloneTestCase()
    {
        ob_start();
        ?>
        <div id="passwordStandInTest"></div>
        <script src="../scripts/basic.js" ></script>
        <script src="../scripts/register_validator.js" ></script>
        <script>
        var unit_test_results = [];
        /* The stand-in the Manage Users screen draws in both of its
           password boxes, which the site reads back as "leave the
           password alone". */
        var stand_in = "5f4dcc3b5aa765d61d8327deb882cf99";
        var missing_upper = "an upper-case letter";
        /* The feedback opens the list of what is missing with a capital,
           so what is looked for here carries one. */
        var named_upper = "An upper-case letter";
        /* Stands in for the note beside the box, which is the only place
           the feedback is written. */
        function makeMessage()
        {
            return {innerHTML: ""};
        }
        /* Stands in for the password box and the form around it. A form
           keeps whatever was listened for so the check can call it and
           see whether the send would have been stopped. */
        function makeField(value)
        {
            var form = {
                handlers: [],
                addEventListener: function (kind, handler) {
                    this.handlers.push(handler);
                }
            };
            return {value: value, form: form,
                addEventListener: function () {},
                focus: function () {}};
        }
        /* Stands in for the hint the helper draws, whose attributes
           carry the rules and the wording. */
        function makeContainer(message, stands_in)
        {
            var attributes = {
                "data-pw-field": "pass-word",
                "data-pw-min": "8",
                "data-pw-max": "64",
                "data-pw-lower": "0",
                "data-pw-upper": "1",
                "data-pw-digit": "0",
                "data-pw-symbol": "0",
                "data-pw-forbidden": "",
                "data-pw-gate": "1",
                "data-pw-standin": stands_in,
                "data-pw-ok": "That password will do",
                "data-pw-phrase-short": "too short",
                "data-pw-phrase-lower": "a lower-case letter",
                "data-pw-phrase-upper": missing_upper,
                "data-pw-phrase-digit": "a digit",
                "data-pw-phrase-symbol": "a symbol",
                "data-pw-phrase-forbidden": "no space"
            };
            return {
                getAttribute: function (name) {
                    return attributes[name];
                },
                getElementsByClassName: function () {
                    return [message];
                }
            };
        }
        /* The page these functions would reach is not here, so the box
           is handed back directly and the two that only draw are made to
           do nothing. */
        var current_field = makeField(stand_in);
        elt = function () {
            return current_field;
        };
        setClass = function () {};
        doMessage = function () {};
        var message = makeMessage();
        var container = makeContainer(message, "1");
        wirePasswordRequirements(container);
        unit_test_results.push(
            {name: "a box holding the stand-in names nothing missing",
            pass: message.innerHTML === ""});
        var stopped = false;
        current_field.form.handlers[0]({preventDefault: function () {
            stopped = true;
        }});
        unit_test_results.push(
            {name: "a box holding the stand-in lets its form be sent",
            pass: stopped === false});
        current_field.value = "shortone";
        showPasswordFeedback(container);
        unit_test_results.push(
            {name: "a password typed in its place is judged again",
            pass: message.innerHTML.indexOf(named_upper) >= 0});
        stopped = false;
        current_field.form.handlers[0]({preventDefault: function () {
            stopped = true;
        }});
        unit_test_results.push(
            {name: "a typed password that breaks a rule is held back",
            pass: stopped === true});
        var plain_message = makeMessage();
        current_field = makeField("shortone");
        var plain_container = makeContainer(plain_message, "0");
        wirePasswordRequirements(plain_container);
        unit_test_results.push(
            {name: "a box carrying no stand-in is judged as it loads",
            pass: plain_message.innerHTML.indexOf(named_upper) >= 0});
        </script>
        <?php
        $out_data = ob_get_contents();
        ob_end_clean();
        return $out_data;
    }
}
X