import { encrypt, decrypt } from '#src/index.js';
import { WINDOW_EXPIRATION_DURATION } from '#src/getPrf.js';
-import { setupPlaywright, setupEnv, assertConsole, MockLogger, fileEqual, fileNotEqual } from '#test/setup.js';
+import { setupPlaywright, setupEnv, MockLogger, fileEqual, fileNotEqual } from '#test/setup.js';
/** Standard value of the .env file used for most setups. */
const STD_ENV = 'A=123\nB=456\nC=789\n';
test('encrypt and decrypt .env', async (t) => {
const { page } = await setupPlaywright(t);
const envFile = await setupEnv(t, STD_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
await fileEqual(envFile, STD_ENV);
await encrypt({ inFile: envFile, getPrfOptions: { onListening: url => page.goto(url) } });
await decrypt({ inFile: envFile, getPrfOptions: { onListening: url => page.goto(url) } });
await fileEqual(envFile, STD_ENV);
});
- test('console logger works', async (t) => {
+ test('logger works', async (t) => {
const { page } = await setupPlaywright(t);
const envFile = await setupEnv(t, STD_ENV);
- assertConsole(t, { debug: 24, info: 6, warn: 0, error: 0 });
-
- await fileEqual(envFile, STD_ENV);
- await encrypt({ inFile: envFile, logger: console, getPrfOptions: { onListening: url => page.goto(url) } });
- await encrypt({ inFile: envFile, logger: console, alreadyEncryptedValue: 'log', getPrfOptions: { onListening: url => page.goto(url) } });
- await fileNotEqual(envFile, STD_ENV);
- await decrypt({ inFile: envFile, logger: console, getPrfOptions: { onListening: url => page.goto(url) } });
- await decrypt({ inFile: envFile, logger: console, notEncryptedValue: 'log', getPrfOptions: { onListening: url => page.goto(url) } });
- await fileEqual(envFile, STD_ENV);
- });
- test('alternate logger works', async (t) => {
- const { page } = await setupPlaywright(t);
- const envFile = await setupEnv(t, STD_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
const logger = new MockLogger();
await fileEqual(envFile, STD_ENV);
test('does nothing to empty .env file', async (t) => {
const { page } = await setupPlaywright(t);
const envFile = await setupEnv(t, '');
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
await fileEqual(envFile, '');
await encrypt({ inFile: envFile, getPrfOptions: { onListening: url => page.goto(url) } });
test('does nothing to empty .env file (with logs)', async (t) => {
const { page } = await setupPlaywright(t);
const envFile = await setupEnv(t, '');
- assertConsole(t, { debug: 1, info: 1, warn: 0, error: 0 });
+ const logger = new MockLogger();
await fileEqual(envFile, '');
- await encrypt({ inFile: envFile, logger: console, getPrfOptions: { onListening: url => page.goto(url) } });
+ await encrypt({ inFile: envFile, logger, getPrfOptions: { onListening: url => page.goto(url) } });
await fileEqual(envFile, '');
+ logger.assertCounts({ debug: 1, info: 1, warn: 0, error: 0 });
});
test('does nothing when all variables are already encrypted', async (t) => {
const envFile = await setupEnv(t, ENCRYPTED_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
await encrypt({ inFile: envFile });
test("encrypts again when alreadyEncryptedValue: 'encrypt'", async (t) => {
const { page } = await setupPlaywright(t);
const envFile = await setupEnv(t, ENCRYPTED_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
await encrypt({ inFile: envFile, alreadyEncryptedValue: 'encrypt', getPrfOptions: { onListening: url => page.goto(url) } });
});
test("throws when alreadyEncryptedValue: 'error'", async (t) => {
const envFile = await setupEnv(t, ENCRYPTED_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
await rejects(encrypt({ inFile: envFile, alreadyEncryptedValue: 'error' }), /Environment variable ".+" is already encrypted\./);
});
const { page, setAutomaticSignIn } = await setupPlaywright(t);
await setAutomaticSignIn(false);
const envFile = await setupEnv(t, STD_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
const { promise: opened, resolve } = /** @type {PromiseWithResolvers<void>}*/(Promise.withResolvers());
/** @type {(url: string) => Promise<void>} */
const onListening = async url => {
test('does nothing to empty .env file', async (t) => {
await setupPlaywright(t);
const envFile = await setupEnv(t, '');
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
await fileEqual(envFile, '');
await decrypt({ inFile: envFile });
});
test('does nothing to empty .env file (with logs)', async (t) => {
const envFile = await setupEnv(t, '');
- assertConsole(t, { debug: 1, info: 1, warn: 0, error: 0 });
+ const logger = new MockLogger();
await fileEqual(envFile, '');
- await decrypt({ inFile: envFile, logger: console });
+ await decrypt({ inFile: envFile, logger });
await fileEqual(envFile, '');
+ logger.assertCounts({ debug: 1, info: 1, warn: 0, error: 0 });
});
test('does nothing when all variables are already decrypted', async (t) => {
const envFile = await setupEnv(t, STD_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
await decrypt({ inFile: envFile });
});
test("throws error when notEncryptedValue='error'", async (t) => {
const envFile = await setupEnv(t, STD_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
await rejects(decrypt({ inFile: envFile, notEncryptedValue: 'error' }), /Environment variable ".+" is not encrypted\./);
});
await setAutomaticSignIn(false);
const env = 'A=envpass:v1:AAA\nB=envpass:v1:BBB\nC=envpass:v1:CCC\n';
const envFile = await setupEnv(t, env);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
const { promise: opened, resolve } = /** @type {PromiseWithResolvers<void>}*/(Promise.withResolvers());
/** @type {(url: string) => Promise<void>} */
const onListening = async url => {
});
test('injects environment variables', async (t) => {
const envFile = await setupEnv(t, INJECTED_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
deepStrictEqual(process.env.INJECTION_TEST, undefined);
await decrypt({ inFile: envFile, injectInProcess: true });
});
test('injects environment variables (with logs)', async (t) => {
const envFile = await setupEnv(t, INJECTED_ENV);
- assertConsole(t, { debug: 3, info: 0, warn: 0, error: 0 });
+ const logger = new MockLogger();
deepStrictEqual(process.env.INJECTION_TEST, undefined);
- await decrypt({ inFile: envFile, injectInProcess: true, logger: console });
+ await decrypt({ inFile: envFile, injectInProcess: true, logger });
deepStrictEqual(process.env.INJECTION_TEST, 'INJECTED');
delete process.env.INJECTION_TEST;
+ logger.assertCounts({ debug: 3, info: 0, warn: 0, error: 0 });
});
test('passes through excess args to execute', async (t) => {
const execMock = t.mock.method(childProcess, 'execSync', () => { });
const envFile = await setupEnv(t, STD_ENV);
- assertConsole(t, { debug: 0, info: 0, warn: 0, error: 0 });
await decrypt({ inFile: envFile }, { args: ['test', 'test', 'test'] });
deepStrictEqual(execMock.mock.calls.length, 1);
test('passes through excess args to execute (with logs)', async (t) => {
const execMock = t.mock.method(childProcess, 'execSync', () => { });
const envFile = await setupEnv(t, STD_ENV);
- assertConsole(t, { debug: 4, info: 0, warn: 0, error: 0 });
+ const logger = new MockLogger();
- await decrypt({ inFile: envFile, logger: console }, { args: ['test', 'test', 'test'] });
+ await decrypt({ inFile: envFile, logger }, { args: ['test', 'test', 'test'] });
deepStrictEqual(execMock.mock.calls.length, 1);
+ logger.assertCounts({ debug: 4, info: 0, warn: 0, error: 0 });
});
});
}
/**
- * @typedef AssertConsoleCounts The total number of times `console.debug`, `console.info`, `console.warn`, and
- * `console.error` are expected to be called.
- * @property {number} [debug] The number of times `console.debug` is expected to be called. The default value is 0.
- * @property {number} [info] The number of times `console.info` is expected to be called. The default value is 0.
- * @property {number} [warn] The number of times `console.warn` is expected to be called. The default value is 0.
- * @property {number} [error] The number of times `console.error` is expected to be called. The default value is 0.
+ * @typedef AssertLoggerCounts The total number of times `Logger.debug`, `Logger.info`, `Logger.warn`, and
+ * `Logger.error` are expected to be called.
+ * @property {number} [debug] The number of times `Logger.debug` is expected to be called. The default value is 0.
+ * @property {number} [info] The number of times `Logger.info` is expected to be called. The default value is 0.
+ * @property {number} [warn] The number of times `Logger.warn` is expected to be called. The default value is 0.
+ * @property {number} [error] The number of times `Logger.error` is expected to be called. The default value is 0.
*/
-/**
- * Silences console functions during a test and asserts a given number of calls were made during the test.
- *
- * 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} t Test context to mock the `console` functions for.
- * @param {AssertConsoleCounts} [expected] Counts for the total number of times console functions are expected
- * to be called.
- */
-export function assertConsole(t, expected = {}) {
- const actual = { debug: 0, info: 0, warn: 0, error: 0 };
- expected = { ...actual, ...expected };
-
- for (const m of /** @type {Array<keyof typeof actual>} */(Object.keys(actual))) {
- t.mock.method(console, m, () => actual[m]++);
- t.after(() => deepStrictEqual(actual[m], expected[m], `expected ${expected[m]} console.${m} calls, got ${actual[m]}`));
- }
-}
-
/** @typedef {'debug'|'info'|'warn'|'error'} LoggerMethod A supported logger method. */
/** @typedef {unknown[]} LoggerCall The arguments passed to a single logger method invocation. */
/**
/**
* Asserts that each logger method was called the expected number of times.
- * @param {AssertConsoleCounts} counts
+ * @param {AssertLoggerCounts} counts
*/
assertCounts(counts) {
for (const method of /** @type {const} */(['debug', 'info', 'warn', 'error'])) {