fix TSamNearest and fully support jump Keymap
All checks were successful
tests / test (push) Successful in 10s

This commit is contained in:
2026-01-05 08:58:48 +01:00
parent 7218ed0c4c
commit 29ddc34add
5 changed files with 736 additions and 169 deletions

View File

@@ -0,0 +1,139 @@
'use strict';
function reqFromCwd(id) {
// Resolve as if we required from the project root (where mocha is installed)
return require(require.resolve(id, { paths: [process.cwd()] }));
}
const Mocha = reqFromCwd('mocha');
const bdd = reqFromCwd('mocha/lib/interfaces/bdd');
function escapeRegExp(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function captureLocationForFile(file, stackStartFn) {
const err = new Error();
if (Error.captureStackTrace) Error.captureStackTrace(err, stackStartFn);
const lines = String(err.stack || '').split('\n').slice(1);
// Prefer exact match for current test file (absolute/normalized path as passed by mocha)
const fileRe = new RegExp(`\\(?(${escapeRegExp(file)}):(\\d+):(\\d+)\\)?$`);
for (const line of lines) {
const m = line.match(fileRe);
if (m) return { file: m[1], line: Number(m[2]), column: Number(m[3]) };
}
// Fallback: any frame containing this file path
const anyRe = /\(?(.+?):(\d+):(\d+)\)?$/;
for (const line of lines) {
const m = line.match(anyRe);
if (m && m[1] && m[1].includes(file)) {
return { file: m[1], line: Number(m[2]), column: Number(m[3]) };
}
}
return { file, line: null, column: null };
}
function markTest(test, loc, pendingType) {
if (!test) return;
test._akLocation = loc;
if (pendingType) test._akPendingType = pendingType; // 'todo' | 'skip'
}
function markSuite(suite, loc, pendingType) {
if (!suite) return;
suite._akLocation = loc;
if (pendingType) suite._akPendingType = pendingType; // 'skip'
}
// Register custom interface name
Mocha.interfaces['bdd-with-location'] = function (suite) {
// First install standard BDD globals
bdd(suite);
// Then wrap globals on pre-require (Mocha passes "file" for each loaded test file)
suite.on('pre-require', function (context, file) {
if (!context || !file) return;
function loc(stackStartFn) {
return captureLocationForFile(file, stackStartFn);
}
// -------------------------
// Wrap `it`
// -------------------------
const origIt = context.it;
function itWrapped(title, fn) {
const test = origIt.call(this, title, fn);
// "todo" detection: it('x') without a function
const pendingType = typeof fn !== 'function' ? 'todo' : null;
markTest(test, loc(itWrapped), pendingType);
return test;
}
// Copy properties like `.only`/`.skip` added by Mocha
Object.assign(itWrapped, origIt);
if (typeof origIt.only === 'function') {
itWrapped.only = function (title, fn) {
const test = origIt.only.call(this, title, fn);
const pendingType = typeof fn !== 'function' ? 'todo' : null;
markTest(test, loc(itWrapped.only), pendingType);
return test;
};
}
if (typeof origIt.skip === 'function') {
itWrapped.skip = function (title, fn) {
const test = origIt.skip.call(this, title, fn);
// Explicit skip
markTest(test, loc(itWrapped.skip), 'skip');
return test;
};
}
context.it = itWrapped;
if (context.specify) context.specify = itWrapped;
// -------------------------
// Wrap `describe`
// -------------------------
const origDescribe = context.describe;
function describeWrapped(title, fn) {
const s = origDescribe.call(this, title, fn);
markSuite(s, loc(describeWrapped), null);
return s;
}
Object.assign(describeWrapped, origDescribe);
if (typeof origDescribe.only === 'function') {
describeWrapped.only = function (title, fn) {
const s = origDescribe.only.call(this, title, fn);
markSuite(s, loc(describeWrapped.only), null);
return s;
};
}
if (typeof origDescribe.skip === 'function') {
describeWrapped.skip = function (title, fn) {
const s = origDescribe.skip.call(this, title, fn);
// Suite skip
markSuite(s, loc(describeWrapped.skip), 'skip');
return s;
};
}
context.describe = describeWrapped;
if (context.context) context.context = describeWrapped;
});
};
module.exports = Mocha.interfaces['bdd-with-location'];

View File

@@ -0,0 +1,131 @@
'use strict';
function reqFromCwd(id) {
return require(require.resolve(id, { paths: [process.cwd()] }));
}
const Mocha = reqFromCwd('mocha');
const {
EVENT_RUN_BEGIN,
EVENT_RUN_END,
EVENT_SUITE_BEGIN,
EVENT_TEST_PASS,
EVENT_TEST_FAIL,
EVENT_TEST_PENDING,
} = Mocha.Runner.constants;
function serializeError(err) {
if (!err) return null;
return {
name: err.name || null,
message: err.message || String(err),
stack: err.stack || null,
};
}
function safeTitlePath(entity) {
if (entity && typeof entity.titlePath === 'function') {
return entity.titlePath();
}
return null;
}
class NdjsonReporter {
constructor(runner /*, options */) {
runner
.once(EVENT_RUN_BEGIN, () => {
this.emit({ event: 'run-begin', total: runner.total });
})
// Optional suite-level event for describe.skip (helps jump to suite definition)
.on(EVENT_SUITE_BEGIN, (suite) => {
if (suite && suite.pending && suite.title) {
this.emit({
event: 'suite',
status: 'skipped',
pendingType: suite._akPendingType || 'skip',
title: suite.title,
fullTitle: typeof suite.fullTitle === 'function' ? suite.fullTitle() : suite.title,
titlePath: safeTitlePath(suite),
file: suite.file || (suite._akLocation && suite._akLocation.file) || null,
location: suite._akLocation || null,
});
}
})
.on(EVENT_TEST_PASS, (test) => {
this.emit(this.testPayload('passed', test, null));
})
.on(EVENT_TEST_FAIL, (test, err) => {
this.emit(this.testPayload('failed', test, serializeError(err)));
})
.on(EVENT_TEST_PENDING, (test) => {
// Mocha "pending" includes:
// - TODO tests (no function)
// - explicit it.skip / describe.skip
// - runtime this.skip()
// We'll classify:
// - pendingType === 'todo' => pending
// - otherwise => skipped
const inferredPendingType = this.inferPendingType(test);
const status = inferredPendingType === 'todo' ? 'pending' : 'skipped';
this.emit({
...this.testPayload(status, test, null),
pendingType: inferredPendingType,
});
})
.once(EVENT_RUN_END, () => {
this.emit({ event: 'run-end', stats: runner.stats || null });
});
}
inferPendingType(test) {
// Priority: explicit marker from UI wrappers
if (test && test._akPendingType) return test._akPendingType;
// Heuristic:
// - If there's no function (or it's missing), it's likely a TODO-style pending
// - If function exists but test ended as pending, it's likely skipped (this.skip())
if (!test) return null;
// In many Mocha versions, TODO tests have test.fn undefined/null
if (!test.fn) return 'todo';
return 'skip';
}
testPayload(status, test, errorObj) {
const location = (test && test._akLocation) || null;
const file =
(test && test.file) ||
(test && test.parent && test.parent.file) ||
(location && location.file) ||
null;
const payload = {
event: 'test',
status,
title: test ? test.title : null,
fullTitle: test && typeof test.fullTitle === 'function' ? test.fullTitle() : null,
titlePath: safeTitlePath(test),
file,
location,
duration: test && typeof test.duration === 'number' ? test.duration : null,
currentRetry: test && typeof test.currentRetry === 'function' ? test.currentRetry() : null,
};
if (status === 'failed') payload.error = errorObj;
return payload;
}
emit(obj) {
process.stdout.write(JSON.stringify(obj) + '\n');
}
}
module.exports = NdjsonReporter;