/
githubmirror
/
meteor
Обзор
Документация
Войти
/
githubmirror
/
meteor
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
devel
packages/logging/logging_test.js
455 строк
13 KB
italo jose
test: add reactive coverage for Session and document zero-coverage utility test designs
10 апр 2026, 22:32
10 апр 2026, 22:32
502f685
Код
Авторство
О чём код?
import { Log } from "meteor/logging"; import { Meteor } from "meteor/meteor"; Tinytest.add("logging - _getCallerDetails", function (test) { const details = Log._getCallerDetails(); // Ignore this test for Opera, IE, Safari since this test would work only // in Chrome and Firefox, other browsers don't give us an ability to get // stacktrace. if (new Error().stack) { if (Meteor.isServer) { test.equal(details.file, "tinytest.js"); } else { // Note that we want this to work in --production too, so we need to allow // for the minified filename. test.matches(details.file, /^(?:tinytest\.js|[a-f0-9]{40}\.js)$/); } // evaled statements shouldn't crash const code = "Log._getCallerDetails().file"; // Note that we want this to work in --production too, so we need to allow // for the minified filename test.matches( eval(code), // oxlint-disable-line no-eval -- intentional eval for testing caller details /^(?:eval|local-test_logging\.js|[a-f0-9]{40}\.js)/, ); } }); Tinytest.add("logging - log", function (test) { const logBothMessageAndObject = function (log, level) { Log._intercept(3); // Tests for correctness log("message"); log({ property1: "foo", property2: "bar" }); log({ message: "mixed", property1: "foo", property2: "bar" }); let intercepted = Log._intercepted(); test.equal(intercepted.length, 3); const obj1 = EJSON.parse(intercepted[0]); test.equal(obj1.message, "message"); test.equal(obj1.level, level); test.instanceOf(obj1.time, Date); const obj2 = EJSON.parse(intercepted[1]); test.isFalse(obj2.message); test.equal(obj2.property1, "foo"); test.equal(obj2.property2, "bar"); test.equal(obj2.level, level); test.instanceOf(obj2.time, Date); const obj3 = EJSON.parse(intercepted[2]); test.equal(obj3.message, "mixed"); test.equal(obj3.property1, "foo"); test.equal(obj3.property2, "bar"); test.equal(obj3.level, level); test.instanceOf(obj3.time, Date); // Test logging falsy values, as well as single digits // and some other non-stringy things // In a format of testcase, expected result, name of the test. const testcases = [ [1, "1", "single digit"], [0, "0", "falsy - 0"], [null, "null", "falsy - null"], [undefined, "undefined", "falsy - undefined"], [new Date("2013-06-13T01:15:16.000Z"), new Date("2013-06-13T01:15:16.000Z"), "date"], [/[^regexp]{0,1}/g, "/[^regexp]{0,1}/g", "regexp"], [true, "true", "boolean - true"], [false, "false", "boolean - false"], [-Infinity, "-Infinity", "number - -Infinity"], ]; Log._intercept(testcases.length); testcases.forEach((testcase) => { log(testcase[0]); }); intercepted = Log._intercepted(); test.equal(intercepted.length, testcases.length); testcases.forEach((testcase, index) => { const expected = testcase[1]; const testName = testcase[2]; const recieved = intercepted[index]; const obj = EJSON.parse(recieved); // IE8 and old Safari don't support this date format. Skip it. if ( expected && expected.toString && (expected.toString() === "NaN" || expected.toString() === "Invalid Date") ) { return; } if (testcase[0] instanceof Date) { obj.message = new Date(obj.message); } test.equal(obj.message, expected, `Logging ${testName}`); }); // Tests for correct exceptions Log._intercept(6); test.throws(function () { log({ time: "not the right time" }); }); test.throws(function () { log({ level: "not the right level" }); }); ["file", "line", "program", "originApp", "satellite"].forEach(function (restrictedKey) { test.throws(function () { const obj = {}; obj[restrictedKey] = "usage of restricted key"; log(obj); }); }); // Can't pass numbers, objects, arrays, regexps or functions as message const throwingTestcases = [ 1, NaN, { foo: "bar" }, ["a", "r", "r"], null, undefined, new Date(), function () { return 42; }, /[regexp]/, ]; Log._intercept(throwingTestcases.length); throwingTestcases.forEach(function (testcase) { test.throws(function () { log({ message: testcase }); }); }); // Since all tests above should throw, nothing should be printed. // This call will set the logging interception to the clean state as well. test.equal(Log._intercepted().length, 0); }; logBothMessageAndObject(Log, "info"); ["info", "warn", "error"].forEach((level) => { logBothMessageAndObject(Log[level], level); }); }); Tinytest.add("logging - parse", function (test) { test.equal(Log.parse("message"), null); test.equal(Log.parse('{"foo": "bar"}'), null); const time = new Date(); test.equal(Log.parse(`{"foo": "bar", "time": ${EJSON.stringify(time)}}`), { foo: "bar", time, }); test.equal(Log.parse('{"foo": not json "bar"}'), null); test.equal(Log.parse('{"time": "not a date object"}'), null); }); Tinytest.add("logging - format", function (test) { const time = new Date(2012, 9 - 1 /*0-based*/, 8, 7, 6, 5, 4); const utcOffsetStr = `(${-(new Date().getTimezoneOffset() / 60)})`; ["debug", "info", "warn", "error"].forEach(function (level) { test.equal( Log.format({ message: "message", time, level }), `${level.charAt(0).toUpperCase()}20120908-07:06:05.004${utcOffsetStr} message`, ); test.equal( Log.format({ message: "message", time, timeInexact: true, level, }), `${level.charAt(0).toUpperCase()}20120908-07:06:05.004${utcOffsetStr}? message`, ); test.equal( Log.format({ foo1: "bar1", foo2: "bar2", time, level }), `${level .charAt(0) .toUpperCase()}20120908-07:06:05.004${utcOffsetStr} {"foo1":"bar1","foo2":"bar2"}`, ); test.equal( Log.format({ message: "message", foo: "bar", time, level }), `${level.charAt(0).toUpperCase()}20120908-07:06:05.004${utcOffsetStr} message {"foo":"bar"}`, ); // Has everything except stderr field test.equal( Log.format({ message: "message", foo: "bar", time, level, file: "app.js", line: 42, app: "myApp", originApp: "proxy", program: "server", }), `${level .charAt(0) .toUpperCase()}20120908-07:06:05.004${utcOffsetStr} [myApp via proxy] (server:app.js:42) message {"foo":"bar"}`, ); // stderr test.equal( Log.format({ message: "message from stderr", time, level, stderr: true, }), `${level .charAt(0) .toUpperCase()}20120908-07:06:05.004${utcOffsetStr} (STDERR) message from stderr`, ); // app/originApp test.equal( Log.format({ message: "message", time, level, app: "app", originApp: "app", }), `${level.charAt(0).toUpperCase()}20120908-07:06:05.004${utcOffsetStr} [app] message`, ); test.equal( Log.format({ message: "message", time, level, app: "app", originApp: "proxy", }), `${level .charAt(0) .toUpperCase()}20120908-07:06:05.004${utcOffsetStr} [app via proxy] message`, ); // source info test.equal( Log.format({ message: "message", time, level, file: "app.js", line: 42, program: "server", }), `${level .charAt(0) .toUpperCase()}20120908-07:06:05.004${utcOffsetStr} (server:app.js:42) message`, ); test.equal( Log.format({ message: "message", time, level, file: "app.js", line: 42, }), `${level.charAt(0).toUpperCase()}20120908-07:06:05.004${utcOffsetStr} (app.js:42) message`, ); }); test.matches( Log.format( { message: "oyez", time: new Date(), level: "error", }, { color: true, }, ), /oyez/, ); }); Tinytest.add("logging - Log() delegates to Log.info", function (test) { Log._intercept(1); Log("hello"); const intercepted = Log._intercepted(); test.equal(intercepted.length, 1); const obj = EJSON.parse(intercepted[0]); test.equal(obj.message, "hello"); test.equal(obj.level, "info"); }); Tinytest.add("logging - _suppress drops the next N calls", function (test) { Log._suppress(2); // These should be dropped — not intercepted, not printed. Log.info("dropped-1"); Log.info("dropped-2"); // Now an interception should capture the *next* line, not the suppressed ones. Log._intercept(1); Log.info("kept"); const intercepted = Log._intercepted(); test.equal(intercepted.length, 1); test.equal(EJSON.parse(intercepted[0]).message, "kept"); }); Tinytest.add("logging - objFromText contract and override merging", function (test) { const obj = Log.objFromText("raw line"); test.equal(obj.message, "raw line"); test.equal(obj.level, "info"); test.equal(obj.timeInexact, true); test.instanceOf(obj.time, Date); // Override wins for provided fields, leaves others intact. const overridden = Log.objFromText("raw line", { level: "error", extra: "payload", }); test.equal(overridden.level, "error"); test.equal(overridden.message, "raw line"); test.equal(overridden.timeInexact, true); test.equal(overridden.extra, "payload"); }); Tinytest.add("logging - format throws when time is not a Date", function (test) { test.throws(function () { Log.format({ message: "hi", level: "info", time: "not a date" }); }, /'time' must be a Date object/); }); Tinytest.add("logging - parse returns null for invalid payloads", function (test) { // Empty object has no time field — parse returns null. test.equal(Log.parse("{}"), null); // JSON with time present but not a Date → null. test.equal(Log.parse('{"time": 1234567890}'), null); // Doesn't start with '{' → not EJSON; not parsed. test.equal(Log.parse("plain string"), null); }); Tinytest.add("logging - formats - without time", function (test) { const time = new Date(2012, 9 - 1 /*0-based*/, 8, 7, 6, 5, 4); // even tho time and offset are provided they should not be included in the output Log.showTime = false; const levels = ["debug", "info", "warn", "error"]; for (const level of levels) { test.equal( Log.format({ message: "message", time, level }), `${level.charAt(0).toUpperCase()} message`, ); test.equal( Log.format({ message: "message", time, timeInexact: true, level, }), `${level.charAt(0).toUpperCase()} message`, ); test.equal( Log.format({ foo1: "bar1", foo2: "bar2", time, level }), `${level.charAt(0).toUpperCase()} {"foo1":"bar1","foo2":"bar2"}`, ); test.equal( Log.format({ message: "message", foo: "bar", time, level }), `${level.charAt(0).toUpperCase()} message {"foo":"bar"}`, ); // Has everything except stderr field test.equal( Log.format({ message: "message", foo: "bar", time, level, file: "app.js", line: 42, app: "myApp", originApp: "proxy", program: "server", }), `${level.charAt(0).toUpperCase()} [myApp via proxy] (server:app.js:42) message {"foo":"bar"}`, ); // stderr test.equal( Log.format({ message: "message from stderr", time, level, stderr: true, }), `${level.charAt(0).toUpperCase()} (STDERR) message from stderr`, ); // app/originApp test.equal( Log.format({ message: "message", time, level, app: "app", originApp: "app", }), `${level.charAt(0).toUpperCase()} [app] message`, ); test.equal( Log.format({ message: "message", time, level, app: "app", originApp: "proxy", }), `${level.charAt(0).toUpperCase()} [app via proxy] message`, ); // source info test.equal( Log.format({ message: "message", time, level, file: "app.js", line: 42, program: "server", }), `${level.charAt(0).toUpperCase()} (server:app.js:42) message`, ); test.equal( Log.format({ message: "message", time, level, file: "app.js", line: 42, }), `${level.charAt(0).toUpperCase()} (app.js:42) message`, ); } Log.showTime = true; // reset });