# Test Helper
-Helpers for writing tests which use vvarious Squeep packages.
+Helpers for writing tests which use various Squeep packages.
Provides stub-builders for:
- [Squeep Structured Logger](https://www.npmjs.com/package/@squeep/logger-json-console)
-- [Squeep Database Abstractor](https://git.squeep.com/?p=squeep-db-helper;a=tree)
+ Provides a simple console-like logger object with spies attached.
+ Actual console output can be enabled by setting the `VERBOSE_TESTS` environment variable, or passing a flag to the stub constructor.
## Usage
```javascript
-const { StubDatabase, StubLogger } = require('@squeep/test-helper');
-const assert = require('node:assert);
+const { StubLogger } = require('@squeep/test-helper');
+const assert = require('node:assert');
const sinon = require('sinon');
-class AppDB extends StubDatabase {
- constructor() {
- super(sinon);
+class App {
+ constructor(logger) {
+ this.logger = logger;
}
- get _stubFns() {
- return [
- ...super._stubFns,
- // Add database interface functions.
- 'valueGet',
- 'valueSet',
- ];
+ doAThing() {
+ this.logger.error('doAThing', 'oh no', { data: true });
}
}
-const logger = new StubLogger(sinon);
-const db = new AppDB();
-
describe('App Test', function () {
+ let app, logger;
beforeEach(function () {
- db._reset();
- logger._reset();
+ logger = new StubLogger(sinon);
+ app = new App(logger);
+ });
+ afterEach(function () {
+ sinon.restore();
});
it('uses stubs', function () {
- const app = new App(logger, db);
app.doAThing();
assert(logger.error.called);
- assert(db.valueGet.called);
});
});
```
'use strict';
-const StubDatabase = require('./lib/stub-database');
const StubLogger = require('./lib/stub-logger');
module.exports = {
- StubDatabase,
StubLogger,
};
+++ /dev/null
-/* eslint-disable class-methods-use-this */
-'use strict';
-
-class StubDatabase {
- constructor(sinon) {
- this._sinon = sinon;
- this._implementation.forEach((fn) => {
- if (!(fn in this)) {
- this[fn] = async () => undefined; // eslint-disable-line security/detect-object-injection
- }
- });
- }
-
- get _implementation() {
- return [
- ...this._spyFns,
- ...this._stubFns,
- ];
- }
-
- get _spyFns() {
- return [
- 'context',
- 'transaction',
- ];
- }
-
- get _stubFns() {
- return [
- 'initialize',
- 'healthCheck',
- ];
- }
-
- _reset() {
- this._spyFns.forEach((fn) => {
- this._sinon.spy(this, fn);
- });
- this._stubFns.forEach((fn) => {
- this._sinon.stub(this, fn);
- });
- }
-
- async context(fn) {
- await fn({});
- }
-
- async transaction(dbCtx, fn) {
- await fn(dbCtx);
- }
-
-}
-
-module.exports = StubDatabase;
class StubLogger {
constructor(sinon, verbose = false) {
this.sinon = sinon;
- const logger = (process.env.VERBOSE_TESTS || verbose) ? console : StubLogger._nullLogger;
- Object.keys(StubLogger._nullLogger).forEach((level) => {
+ const logger = (process.env.VERBOSE_TESTS || verbose) ? console : this.constructor._nullLogger;
+ Object.keys(this.constructor._nullLogger).forEach((level) => {
this[level] = logger[level]; // eslint-disable-line security/detect-object-injection
this.sinon.spy(this, level);
});
}
static get _levels() {
- return Object.keys(StubLogger._nullLogger);
+ return Object.keys(this._nullLogger);
}
_reset() {
- StubLogger._levels.forEach((level) => this[level].resetHistory()); // eslint-disable-line security/detect-object-injection
+ this.constructor._levels.forEach((level) => this[level].resetHistory()); // eslint-disable-line security/detect-object-injection
}
}
'use strict';
-const { StubDatabase, StubLogger } = require('../index');
+const { StubLogger } = require('../index');
const sinon = require('sinon');
const assert = require('node:assert');
class App {
- constructor(logger, db) {
+ constructor(logger) {
this.logger = logger;
- this.db = db;
}
doAThing() {
- this.db.valueGet();
- this.logger.error('doAThing', 'oh no');
+ this.logger.error('doAThing', 'oh no', { data: true });
}
}
-class AppDB extends StubDatabase {
- constructor() {
- super(sinon);
- }
- get _stubFns() {
- return [
- ...super._stubFns,
- 'valueGet',
- 'valueSet',
- ];
- }
-}
-
-const logger = new StubLogger(sinon);
-const db = new AppDB();
-
describe('App Test', function () {
+ let app, logger;
beforeEach(function () {
- db._reset();
- logger._reset();
+ logger = new StubLogger(sinon);
+ app = new App(logger);
+ });
+ afterEach(function () {
+ sinon.restore();
});
it('uses stubs', function () {
- const app = new App(logger, db);
app.doAThing();
assert(logger.error.called);
- assert(db.valueGet.called);
});
});
+++ /dev/null
-/* eslint-disable security/detect-object-injection */
-'use strict';
-
-const assert = require('node:assert');
-const sinon = require('sinon');
-const StubDatabase = require('../../lib/stub-database');
-
-describe('StubDatabase', function () {
- let db;
- async function invokeAllImplementation() {
- Promise.all(db._implementation.map(async (fn) => {
- await db[fn]();
- assert(db[fn].called, fn);
- }));
- }
-
- describe('Base', function () {
- beforeEach(function () {
- db = new StubDatabase(sinon);
- db._reset();
- });
- it('covers implementation', invokeAllImplementation);
- }); // Base
-
- describe('Extended', function () {
- class DB extends StubDatabase {
- constructor() {
- super(sinon);
- }
- get _stubFns() {
- return [
- ...super._stubFns,
- 'valueGet',
- 'valueSet',
- ];
- }
- async valueSet() {
- return this;
- }
- }
- beforeEach(function () {
- db = new DB();
- db._reset();
- });
- it('covers implementation', invokeAllImplementation);
- it('covers missing methods', async function () {
- db = new DB();
- await db.valueGet();
- });
- }); // Extended
-}); // StubDatabase
function logAllLevels() {
StubLogger._levels.forEach((level) => {
logger[level]('scope', 'msg', {});
- assert(logger[level].called);
+ });
+ }
+ function assertAllLevels(property) {
+ StubLogger._levels.forEach((level) => {
+ assert(logger[level][property]);
});
}
describe('null logger', function () {
beforeEach(function () {
logger = new StubLogger(sinon);
- logger._reset();
});
- it('covers levels', logAllLevels);
+ it('covers levels', function () {
+ assertAllLevels('notCalled');
+ logAllLevels();
+ assertAllLevels('called');
+ });
it('covers reset', function () {
+ assertAllLevels('notCalled');
logAllLevels();
+ assertAllLevels('called');
logger._reset();
+ assertAllLevels('notCalled');
logAllLevels();
+ assertAllLevels('called');
logger._reset();
+ assertAllLevels('notCalled');
});
}); // null logger
describe('console logger', function () {
beforeEach(function () {
logger = new StubLogger(sinon, true);
- logger._reset();
});
- it('covers levels', logAllLevels);
+ it('covers levels', function () {
+ assertAllLevels('notCalled');
+ logAllLevels();
+ assertAllLevels('called');
+ });
it('covers reset', function () {
+ assertAllLevels('notCalled');
logAllLevels();
+ assertAllLevels('called');
logger._reset();
+ assertAllLevels('notCalled');
logAllLevels();
+ assertAllLevels('called');
logger._reset();
+ assertAllLevels('notCalled');
});
- }); // null logger
+ }); // console logger
}); // StubLogger
\ No newline at end of file