Skip to content

Commit

Permalink
fix: ensure afterEach execution after a test failure (#598)
Browse files Browse the repository at this point in the history
* ci(tdd): include a failure case

* ci: fix test failure case

* chore: unify `it` and `test`

* ci: improve tests

* ci: fix tests

* chore: better name `hasIt` to `hasItOrTest`
  • Loading branch information
wellwelwel committed Jul 25, 2024
1 parent 897577c commit e6654c4
Show file tree
Hide file tree
Showing 14 changed files with 291 additions and 128 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ node_modules
.env
.nyc_output
/.temp
/.temp2
/test-src
/test-tests
/test-before-and-after-each.json
68 changes: 68 additions & 0 deletions fixtures/each-api/after-failure.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { readFile, writeFile, rm, mkdir } from 'node:fs/promises';
import {
beforeEach,
afterEach,
log,
test,
describe,
assert,
} from '../../src/modules/index.js';

const testDir = '../../.temp2';
const testFile = `${testDir}/each-hook`;

const clearFixture = async () => {
try {
await rm(testFile);
await rm(testDir, { recursive: true, force: true });
log(' - Cleaning');
} catch {}
};

const writeFixture = async () => {
await mkdir(testDir);
await writeFile(testFile, 'test', 'utf-8');
log(' - Writing');
};

const toTest = async (message: string) => {
await readFile(testFile, 'utf-8');
return message;
};

beforeEach(async () => {
log('- before beforeEach writeFixture');

await writeFixture();

log('- after beforeEach writeFixture');
});

afterEach(async () => {
log('- before afterEach clearFixture');

await clearFixture();

log('- after afterEach clearFixture');
});

describe(async () => {
await clearFixture();

await test('first test', async () => {
log(' before first test');

assert(true, await toTest('first test'));

log(' after first test');
});

await writeFixture();
await test('Force failure', async () => {
log(' before first test');

assert(true, await toTest('first test'));

log(' after first test');
});
});
54 changes: 54 additions & 0 deletions fixtures/no-runner/basic-logs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { assert } from '../../src/modules/essentials/assert.js';
import { test } from '../../src/modules/helpers/test.js';
import { describe } from '../../src/modules/helpers/describe.js';
import { it } from '../../src/modules/helpers/it.js';

assert(true, 'Should emit a basic assetion log');

test('Should emit a basic test scope log', () => {
// ...
});

describe('Should emit a basic test scope log', () => {
// ...
});

it('Should emit a basic it scope log', () => {
// ...
});

test('Should emit a basic test scope log', () => {
assert(true, 'Should emit a basic assetion log');
});

describe('Should emit a basic test scope log', () => {
assert(true, 'Should emit a basic assetion log');
});

it('Should emit a basic test scope log', () => {
assert(true, 'Should emit a basic assetion log');
});

describe('Should emit a basic test scope log', () => {
it('Should emit a basic it scope log', () => {
// ...
});
});

describe('Should emit a basic test scope log', () => {
test('Should emit a basic test scope log', () => {
// ...
});
});

describe('Should emit a basic test scope log', () => {
it('Should emit a basic it scope log', () => {
assert(true, 'Should emit a basic assetion log');
});
});

describe('Should emit a basic test scope log', () => {
test('Should emit a basic test scope log', () => {
assert(true, 'Should emit a basic assetion log');
});
});
3 changes: 1 addition & 2 deletions src/configs/indentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ export const indentation = {
test: ' ',
stdio: ' ',
hasDescribe: false,
hasTest: false,
hasIt: false,
hasItOrTest: false,
};
1 change: 0 additions & 1 deletion src/modules/helpers/describe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export async function describe(
indentation.hasDescribe = true;

const { background, icon } = options || {};
/* c8 ignore next */
const message = `${cb ? format('◌').dim() : icon || '☰'} ${cb ? format(isPoku ? `${title}${format(`${FILE}`).italic().gray()}` : title).dim() : format(title).bold() || ''}`;
const noBackground = !background;

Expand Down
95 changes: 54 additions & 41 deletions src/modules/helpers/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,61 +19,74 @@ export async function it(
(() => unknown | Promise<unknown>)?,
]
): Promise<void> {
let message: string | undefined;
let cb: () => unknown | Promise<unknown>;
try {
let message: string | undefined;
let cb: () => unknown | Promise<unknown>;

const isPoku = typeof env?.FILE === 'string' && env?.FILE.length > 0;
const FILE = env.FILE;
const isPoku = typeof env?.FILE === 'string' && env?.FILE.length > 0;
const FILE = env.FILE;

if (typeof args[0] === 'string') {
message = args[0];
cb = args[1] as () => unknown | Promise<unknown>;
} else {
cb = args[0] as () => unknown | Promise<unknown>;
}
if (typeof args[0] === 'string') {
message = args[0];
cb = args[1] as () => unknown | Promise<unknown>;
} else {
cb = args[0] as () => unknown | Promise<unknown>;
}

if (message) {
indentation.hasIt = true;
if (message) {
indentation.hasItOrTest = true;

Write.log(
isPoku && !indentation.hasDescribe
? /* c8 ignore next 2 */
`${indentation.hasDescribe ? ' ' : ''}${format(`◌ ${message}${format(`${FILE}`).italic().gray()}`).dim()}`
: `${indentation.hasDescribe ? ' ' : ''}${format(`◌ ${message}`).dim()}`
);
}
Write.log(
isPoku && !indentation.hasDescribe
? `${indentation.hasDescribe ? ' ' : ''}${format(`◌ ${message}${format(`${FILE}`).italic().gray()}`).dim()}`
: `${indentation.hasDescribe ? ' ' : ''}${format(`◌ ${message}`).dim()}`
);
}

if (typeof each.before.cb === 'function') {
const beforeResult = each.before.cb();
if (typeof each.before.cb === 'function') {
const beforeResult = each.before.cb();

if (beforeResult instanceof Promise) {
await beforeResult;
if (beforeResult instanceof Promise) {
await beforeResult;
}
}
}

const start = hrtime();
const resultCb = cb();
const start = hrtime();
const resultCb = cb();

if (resultCb instanceof Promise) {
await resultCb;
}
if (resultCb instanceof Promise) {
await resultCb;
}

const end = hrtime(start);
const end = hrtime(start);

if (typeof each.after.cb === 'function') {
const afterResult = each.after.cb();
if (typeof each.after.cb === 'function') {
const afterResult = each.after.cb();

if (afterResult instanceof Promise) {
await afterResult;
if (afterResult instanceof Promise) {
await afterResult;
}
}
}

if (message) {
const total = (end[0] * 1e3 + end[1] / 1e6).toFixed(6);
if (message) {
const total = (end[0] * 1e3 + end[1] / 1e6).toFixed(6);

indentation.hasItOrTest = false;
Write.log(
`${indentation.hasDescribe ? ' ' : ''}${format(`● ${message}`).success().bold()} ${format(`› ${total}ms`).success().dim()}`
);
}
} catch (error) {
indentation.hasItOrTest = false;

if (typeof each.after.cb === 'function') {
const afterResult = each.after.cb();

if (afterResult instanceof Promise) {
await afterResult;
}
}

indentation.hasIt = false;
Write.log(
`${indentation.hasDescribe ? ' ' : ''}${format(`● ${message}`).success().bold()} ${format(`› ${total}ms`).success().dim()}`
);
throw error;
}
}
78 changes: 2 additions & 76 deletions src/modules/helpers/test.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,5 @@
/* c8 ignore next */ // ?
import { hrtime, env } from 'node:process';
import { each } from '../../configs/each.js';
import { indentation } from '../../configs/indentation.js';
import { format } from '../../services/format.js';
import { Write } from '../../services/write.js';
import { it } from './it.js';

export async function test(
message: string,
cb: () => Promise<unknown>
): Promise<void>;
export function test(message: string, cb: () => unknown): void;
export async function test(cb: () => Promise<unknown>): Promise<void>;
export function test(cb: () => unknown): void;
/* c8 ignore next */ // ?
export async function test(
...args: [
string | (() => unknown | Promise<unknown>),
(() => unknown | Promise<unknown>)?,
]
): Promise<void> {
let message: string | undefined;
let cb: () => unknown | Promise<unknown>;

const isPoku = typeof env?.FILE === 'string' && env?.FILE.length > 0;
const FILE = env.FILE;

if (typeof args[0] === 'string') {
message = args[0];
cb = args[1] as () => unknown | Promise<unknown>;
} else {
cb = args[0] as () => unknown | Promise<unknown>;
}

if (message) {
indentation.hasTest = true;

Write.log(
isPoku
? /* c8 ignore next 2 */
format(`◌ ${message}${format(`${FILE}`).italic().gray()}`).dim()
: format(`◌ ${message}`).dim()
);
}

if (typeof each.before.cb === 'function') {
const beforeResult = each.before.cb();

if (beforeResult instanceof Promise) {
await beforeResult;
}
}

const start = hrtime();
const resultCb = cb();

if (resultCb instanceof Promise) {
await resultCb;
}

const end = hrtime(start);

if (typeof each.after.cb === 'function') {
const afterResult = each.after.cb();

if (afterResult instanceof Promise) {
await afterResult;
}
}

if (message) {
const total = (end[0] * 1e3 + end[1] / 1e6).toFixed(6);

indentation.hasTest = false;
Write.log(
`${format(`● ${message}`).success().bold()} ${format(`› ${total}ms`).success().dim()}`
);
}
}
export const test = it;
11 changes: 3 additions & 8 deletions src/services/assert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ export const processAssert = async (
const FILE = env.FILE;
let preIdentation = '';

if (indentation.hasDescribe || indentation.hasTest) {
if (indentation.hasDescribe) {
preIdentation += ' ';
}

if (indentation.hasIt) {
if (indentation.hasItOrTest) {
preIdentation += ' ';
}

Expand All @@ -40,11 +40,7 @@ export const processAssert = async (

if (typeof options.message === 'string') {
const message =
isPoku &&
!indentation.hasDescribe &&
!indentation.hasIt &&
/* c8 ignore next 2 */
!indentation.hasTest
isPoku && !indentation.hasDescribe && !indentation.hasItOrTest
? `${preIdentation}${format(`${format(`✔ ${options.message}`).bold()} ${format(`› ${FILE}`).success().dim()}`).success()}`
: `${preIdentation}${format(`✔ ${options.message}`).success().bold()}`;

Expand Down Expand Up @@ -115,7 +111,6 @@ export const processAssert = async (
// Non-assertion errors
throw error;
}
/* c8 ignore stop */
};

/* c8 ignore next */ // ?
Expand Down
Loading

0 comments on commit e6654c4

Please sign in to comment.