[gjs/ewlsh/whatwg-console] Add Console tests




commit 642a72a9752dd6ec3360d8e58f1b37d37ac87a5b
Author: Evan Welsh <contact evanwelsh com>
Date:   Fri Aug 13 21:38:07 2021 -0700

    Add Console tests

 installed-tests/js/.eslintrc.yml  |   1 +
 installed-tests/js/matchers.js    |  36 +++++++++-
 installed-tests/js/meson.build    |   1 +
 installed-tests/js/testConsole.js | 143 ++++++++++++++++++++++++++++++++++++++
 modules/esm/console.js            |   3 +-
 5 files changed, 182 insertions(+), 2 deletions(-)
---
diff --git a/installed-tests/js/.eslintrc.yml b/installed-tests/js/.eslintrc.yml
index cdf5cf9f..abc9c527 100644
--- a/installed-tests/js/.eslintrc.yml
+++ b/installed-tests/js/.eslintrc.yml
@@ -33,6 +33,7 @@ overrides:
   - files:
       - matchers.js
       - testCairoModule.js
+      - testConsole.js
       - testESModules.js
       - testEncoding.js
       - testGLibLogWriter.js
diff --git a/installed-tests/js/matchers.js b/installed-tests/js/matchers.js
index 6a2848f6..14fa161d 100644
--- a/installed-tests/js/matchers.js
+++ b/installed-tests/js/matchers.js
@@ -26,7 +26,41 @@ export function arrayLikeWithExactContents(elements) {
          * @returns {string}
          */
         jasmineToString() {
-            return `${JSON.stringify(elements)}`;
+            return `<arrayLikeWithExactContents(${
+                elements.constructor.name
+            }[${JSON.stringify(Array.from(elements))}]>)`;
+        },
+    };
+}
+
+/**
+ * A jasmine asymmetric matcher which compares a given string to an
+ * array-like object of bytes. The compared bytes are decoded using
+ * TextDecoder and then compared using jasmine.stringMatching.
+ *
+ * @param {string | RegExp} text the text or regular expression to compare decoded bytes to
+ * @param {string} [encoding] the encoding of elements
+ * @returns
+ */
+export function decodedStringMatching(text, encoding = 'utf-8') {
+    const matcher = jasmine.stringMatching(text);
+
+    return {
+        /**
+         * @param {ArrayLike<number>} compareTo an array of bytes to decode and compare to
+         * @returns {boolean}
+         */
+        asymmetricMatch(compareTo) {
+            const decoder = new TextDecoder(encoding);
+            const decoded = decoder.decode(new Uint8Array(Array.from(compareTo)));
+
+            return matcher.asymmetricMatch(decoded, []);
+        },
+        /**
+         * @returns {string}
+         */
+        jasmineToString() {
+            return `<decodedStringMatching(${text})`;
         },
     };
 }
diff --git a/installed-tests/js/meson.build b/installed-tests/js/meson.build
index f85b9586..b42f3b20 100644
--- a/installed-tests/js/meson.build
+++ b/installed-tests/js/meson.build
@@ -241,6 +241,7 @@ endif
 # minijasmine flag
 
 modules_tests = [
+    'Console',
     'ESModules',
     'Encoding',
     'GLibLogWriter',
diff --git a/installed-tests/js/testConsole.js b/installed-tests/js/testConsole.js
new file mode 100644
index 00000000..869ee1ac
--- /dev/null
+++ b/installed-tests/js/testConsole.js
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
+// SPDX-FileCopyrightText: 2021 Evan Welsh <contact evanwelsh com>
+
+// eslint-disable-next-line
+/// <reference types="jasmine" />
+
+import GLib from 'gi://GLib';
+import {DEFAULT_LOG_DOMAIN} from 'console';
+
+import {decodedStringMatching} from './matchers.js';
+
+function objectContainingLogMessage(
+    message,
+    domain = DEFAULT_LOG_DOMAIN,
+    fields = {}
+) {
+    return jasmine.objectContaining({
+        MESSAGE: decodedStringMatching(message),
+        GLIB_DOMAIN: decodedStringMatching(domain),
+        ...fields,
+    });
+}
+
+describe('Console', function () {
+    /** @type {jasmine.Spy<(_level: any, _fields: any) => any>} */
+    let writer_func;
+
+    /**
+     * @param {RegExp | string} message _
+     * @param {*} [logLevel] _
+     * @param {*} [domain] _
+     * @param {*} [fields] _
+     * @param {boolean} [resetCalls] whether to reset the mock calls after expecting
+     */
+    function expectLog(
+        message,
+        logLevel = GLib.LogLevelFlags.LEVEL_MESSAGE,
+        domain = DEFAULT_LOG_DOMAIN,
+        fields = {},
+        resetCalls = true
+    ) {
+        expect(writer_func).toHaveBeenCalledWith(
+            logLevel,
+            objectContainingLogMessage(message, domain, fields)
+        );
+
+        if (resetCalls)
+            // Reset the calls if needed
+            writer_func.calls.reset();
+    }
+
+    beforeAll(function () {
+        writer_func = jasmine.createSpy(
+            'Console test writer func',
+            function (_level, _fields) {
+                return GLib.LogWriterOutput.HANDLED;
+            }
+        );
+
+        writer_func.and.callThrough();
+
+        // @ts-expect-error The existing binding doesn't accept any parameters because
+        // it is a raw pointer.
+        GLib.log_set_writer_func(writer_func);
+    });
+
+    beforeEach(function () {
+        writer_func.calls.reset();
+    });
+
+    it('logs a message', function () {
+        console.log('a log');
+
+        expect(writer_func).toHaveBeenCalledWith(
+            GLib.LogLevelFlags.LEVEL_MESSAGE,
+            objectContainingLogMessage('a log')
+        );
+    });
+
+    it('logs a warning', function () {
+        console.warn('a warning');
+
+        expect(writer_func).toHaveBeenCalledWith(
+            GLib.LogLevelFlags.LEVEL_WARNING,
+            objectContainingLogMessage('a warning')
+        );
+    });
+
+    it('logs an informative message', function () {
+        console.info('an informative message');
+
+        expect(writer_func).toHaveBeenCalledWith(
+            GLib.LogLevelFlags.LEVEL_INFO,
+            objectContainingLogMessage('an informative message')
+        );
+    });
+
+    it('clear has no effect', function () {
+        console.clear();
+    });
+
+    describe('console.time()', function () {
+        it('ends correctly', function (done) {
+            console.time('testing time');
+
+            // console.time logs nothing.
+            expect(writer_func).not.toHaveBeenCalled();
+
+            setTimeout(() => {
+                console.timeLog('testing time');
+
+                expectLog(/testing time: (.*)ms/);
+
+                console.timeEnd('testing time');
+
+                expectLog(/testing time: (.*)ms/);
+
+                console.timeLog('testing time');
+
+                expectLog(
+                    "No time log found for label: 'testing time'.",
+                    GLib.LogLevelFlags.LEVEL_WARNING
+                );
+
+                done();
+            }, 10);
+        });
+
+        it("doesn't log initially", function (done) {
+            console.time('testing time');
+
+            // console.time logs nothing.
+            expect(writer_func).not.toHaveBeenCalled();
+
+            setTimeout(() => {
+                console.timeEnd('testing time');
+                expectLog(/testing time: (.*)ms/);
+
+                done();
+            }, 10);
+        });
+    });
+});
diff --git a/modules/esm/console.js b/modules/esm/console.js
index a4ace025..c4c529d1 100644
--- a/modules/esm/console.js
+++ b/modules/esm/console.js
@@ -871,7 +871,8 @@ const globalConsole = Object.create({});
 
 const propertyNames =
     /** @type {['constructor', ...Array<string & keyof Console>]} */
-    Object.getOwnPropertyNames(Console.prototype);
+    // eslint-disable-next-line no-extra-parens
+    (Object.getOwnPropertyNames(Console.prototype));
 const propertyDescriptors = Object.getOwnPropertyDescriptors(Console.prototype);
 for (const key of propertyNames) {
     if (key === 'constructor')


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]