]> git.ardis.lu - csvio/commitdiff
Silence console functions on stdout and instead assert they occurred
authorArdis Lu <ardisglu@gmail.com>
Sun, 9 Feb 2025 06:58:27 +0000 (22:58 -0800)
committerArdis Lu <ardisglu@gmail.com>
Sun, 9 Feb 2025 06:58:27 +0000 (22:58 -0800)
This approach makes the test runner output cleaner, and also tests the console calls occurred as expected.

test/normalization.test.js
test/utils.js

index cd52b5801a8e9308f6ee8d5f518272d3b644d4c6..3463a2312ece375637367b04301fb0dc817cb054 100644 (file)
@@ -1,7 +1,7 @@
 import { suite, test } from 'node:test';
 import { deepStrictEqual } from 'node:assert/strict';
 
-import { csvStreamEqual, csvStreamEqualWritable, createCSVMockStream } from './utils.js';
+import { csvStreamEqual, csvStreamEqualWritable, createCSVMockStream, assertConsole } from './utils.js';
 import { CSVReader } from '../src/core.js';
 import { toCamelCase, expandScientificNotation, CSVNormalizer, CSVDenormalizer } from '../src/normalization.js';
 
@@ -73,11 +73,14 @@ suite('CSVNormalizer.fixExcelNumber', { concurrency: true }, () => {
     { name: 'fixes accounting mangling integer', input: ' $123.00 ', output: 123 },
     { name: 'fixes accounting mangling number', input: ' $123.45 ', output: 123.45 },
     { name: 'fixes accounting mangling with commas', input: ' $10,000,000.00 ', output: 10000000 },
-    { name: 'passes through non-number value', input: 'abc', output: 'abc' },
+    { name: 'passes through non-number value', input: 'abc', output: 'abc', consoleCounts: { warn: 1 } },
     { name: 'passes through blank value', input: '', output: '' },
   ];
-  for (const { name, input, output } of vectors) {
-    test(name, { concurrency: true }, () => {
+  for (const { name, input, output, consoleCounts } of vectors) {
+    test(name, { concurrency: true }, (t) => {
+      if (consoleCounts !== undefined) {
+        assertConsole(t, consoleCounts);
+      }
       deepStrictEqual(CSVNormalizer.fixExcelNumber(input), output);
     });
   }
@@ -92,11 +95,14 @@ suite('CSVNormalizer.fixExcelBigInt', { concurrency: true }, () => {
     { name: 'fixes accounting mangling integer', input: ' $123.00 ', output: '123' },
     { name: 'fixes accounting mangling number (truncated)', input: ' $123.45 ', output: '123' },
     { name: 'fixes accounting mangling BigInt with commas', input: '  $1,123,123,123,123,123,123.12  ', output: '1123123123123123123' },
-    { name: 'passes through non-BigInt values', input: 'abc', output: 'abc' },
+    { name: 'passes through non-BigInt values', input: 'abc', output: 'abc', consoleCounts: { warn: 1 } },
     { name: 'passes through blank value', input: '', output: '' },
   ];
-  for (const { name, input, output } of vectors) {
-    test(name, { concurrency: true }, () => {
+  for (const { name, input, output, consoleCounts } of vectors) {
+    test(name, { concurrency: true }, (t) => {
+      if (consoleCounts !== undefined) {
+        assertConsole(t, consoleCounts);
+      }
       deepStrictEqual(CSVNormalizer.fixExcelBigInt(input), output);
     });
   }
@@ -116,11 +122,15 @@ suite('CSVNormalizer.fixExcelDate', { concurrency: true }, () => {
     { name: 'fixes number mangling (43915.31372)', input: '43915.31372', output: '2020-03-25T07:31:45.407Z' },
     { name: 'fixes number mangling (44067.63)', input: '44067.63', output: '2020-08-24T15:07:11.999Z' },
     { name: 'fixes number mangling (44309.63502)', input: '44309.63502', output: '2021-04-23T15:14:25.728Z' },
-    { name: 'passes through non-date values', input: 'abc', output: 'abc', raw: true },
+    { name: 'passes through non-date values', input: 'abc', output: 'abc', raw: true, consoleCounts: { warn: 1 } },
     { name: 'passes through blank value', input: '', output: '', raw: true },
   ];
-  for (const { name, input, output, raw = false } of vectors) {
-    test(name, { concurrency: true }, () => {
+  for (const { name, input, output, raw = false, consoleCounts } of vectors) {
+    test(name, { concurrency: true }, (t) => {
+      if (consoleCounts !== undefined) {
+        assertConsole(t, consoleCounts);
+      }
+
       if (raw) {
         deepStrictEqual(CSVNormalizer.fixExcelDate(input), output);
       }
@@ -197,7 +207,8 @@ suite('CSVNormalizer', { concurrency: true }, () => {
         ['a', 'b']
       ]));
   });
-  test('can ignore incorrect data types', { concurrency: true }, async () => {
+  test('can ignore incorrect data types', { concurrency: true }, async (t) => {
+    assertConsole(t, { warn: 2 });
     await createCSVMockStream([
       ['columnA', 'columnB'],
       ['a', 'b']
index a6998fb0bd07a38b2eb043fc1a63555a5738622d..ea1a7c45fb4bdfaa3b9883c3c64595f3421b0118 100644 (file)
@@ -2,6 +2,7 @@ import { deepStrictEqual, notStrictEqual } from 'node:assert/strict';
 import { tmpdir } from 'node:os';
 import { mkdtemp, open } from 'node:fs/promises';
 import { normalize } from 'node:path';
+/** @import { TestContext } from 'node:test'; */
 
 /**
  * Log an entire stream along with the field count for each row and the total row count.
@@ -103,6 +104,50 @@ export function csvStreamNotEqualWritable(csv) {
   });
 }
 
+/**
+ * @typedef AssertConsoleCounts Object containing the total number of times `console.log`, `console.info`, `console.warn`,
+ * and `console.error` are expected to be called.
+ * @property {number} [log=0] The number of times `console.log` is expected to be called.
+ * @property {number} [info=0] The number of times `console.info` is expected to be called.
+ * @property {number} [warn=0] The number of times `console.warn` is expected to be called.
+ * @property {number} [error=0] The number of times `console.error` is expected to be called.
+ */
+
+/**
+ * Silences console functions during a test and asserts a given number of calls were made during the test. 
+ * 
+ * **Important:** Console will only be silenced AFTER this function is called, and only until the test ends. Call this function
+ * early in the test to avoid unexpected console calls.
+ * 
+ * @param {TestContext} context A Node.js `TestContext` for a test case.
+ * @param {AssertConsoleCounts} [expected] Object containing counts for the total number of times console functions are expected
+ * to be called.
+ */
+export function assertConsole(context, expected = {}) {
+  expected.log ??= 0;
+  expected.info ??= 0;
+  expected.warn ??= 0;
+  expected.error ??= 0;
+  const actual = {
+    log: 0,
+    info: 0,
+    warn: 0,
+    error: 0
+  }
+
+  context.mock.method(console, 'log', () => actual.log++);
+  context.mock.method(console, 'info', () => actual.info++);
+  context.mock.method(console, 'warn', () => actual.warn++);
+  context.mock.method(console, 'error', () => actual.error++);
+
+  context.after(() => {
+    deepStrictEqual(actual.log, expected.log, `expected ${expected.log} console.log calls, got ${actual.log}`);
+    deepStrictEqual(actual.info, expected.info, `expected ${expected.info} console.info calls, got ${actual.info}`);
+    deepStrictEqual(actual.warn, expected.warn, `expected ${expected.warn} console.warn calls, got ${actual.warn}`);
+    deepStrictEqual(actual.error, expected.error, `expected ${expected.error} console.error calls, got ${actual.error}`);
+  });
+}
+
 /**
  * Simulate a stream of CSV data for test mocking purposes.
  * 
This page took 0.067509 seconds and 4 git commands to generate.