@neurodevs/node-tdd 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,7 +30,7 @@ export default class TkTextWidget extends TkBaseWidget {
30
30
  async handleMouseDown(position) {
31
31
  const { x, y } = position;
32
32
  const line = this.text.content.split('\n')[y];
33
- await this.emit('click', {
33
+ this.emit('click', {
34
34
  text: line,
35
35
  row: y,
36
36
  column: x,
@@ -48,7 +48,12 @@ export default class TkTextWidget extends TkBaseWidget {
48
48
  width: newFrame.width ?? oldFrame.width,
49
49
  height: newFrame.height ?? oldFrame.height,
50
50
  });
51
- this.text.draw();
51
+ if (this.text.scrollable) {
52
+ this.text.scrollTo(null, this.text.scrollY);
53
+ }
54
+ else {
55
+ this.text.draw();
56
+ }
52
57
  }
53
58
  getText() {
54
59
  return this.text.content;
@@ -64,6 +69,9 @@ export default class TkTextWidget extends TkBaseWidget {
64
69
  getScrollY() {
65
70
  return this.text.scrollY;
66
71
  }
72
+ scrollToTop() {
73
+ this.text.scrollTo(null, 0);
74
+ }
67
75
  getScrollX() {
68
76
  return this.text.scrollX;
69
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TkTextWidget.js","sourceRoot":"","sources":["../../src/workspace/TkTextWidget.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,cAAc,CAAA;AAGvC,OAAO,UAAU,MAAM,uBAAuB,CAAA;AAC9C,OAAO,WAAW,MAAM,sBAAsB,CAAA;AAC9C,OAAO,YAAiC,MAAM,mBAAmB,CAAA;AACjE,MAAM,OAAO,GAAG,YAAmB,CAAA;AAEnC,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,YAAY;IAClC,IAAI,GAAG,MAAM,CAAA;IAErB,IAAI,CAAK;IACT,oCAAoC,CAAS;IAErD,YAAmB,OAA4C;QAC3D,KAAK,CAAC,OAAO,CAAC,CAAA;QAEd,MAAM,EACF,MAAM,EACN,IAAI,EACJ,eAAe,EAAE,YAAY,GAAG,KAAK,EACrC,oCAAoC,GAAG,IAAI,EAC3C,GAAG,IAAI,EACV,GAAG,OAAO,CAAA;QAEX,IAAI,CAAC,oCAAoC;YACrC,oCAAoC,CAAA;QAExC,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAErD,IAAI,CAAC,IAAI,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;YAC5B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,SAAS;YACvD,UAAU,EAAE,YAAY;YACxB,UAAU,EAAE,YAAY;YACxB,UAAU,EAAE,YAAY,IAAI,CAAC,IAAI,CAAC,QAAQ;YAC1C,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,GAAG,WAAW,CAAC,gCAAgC,CAAC,IAAI,CAAC;YACrD,GAAG,KAAK;SACX,CAAC,CAAA;QAEF,IAAI,CAAC,uBAAuB,EAAE,CAAA;QAE9B,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACzB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1D,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,QAAkC;QAC5D,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAA;QAEzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QAE7C,MAAO,IAAmB,CAAC,IAAI,CAAC,OAAO,EAAE;YACrC,IAAI,EAAE,IAAI;YACV,GAAG,EAAE,CAAC;YACN,MAAM,EAAE,CAAC;SACZ,CAAC,CAAA;IACN,CAAC;IAEM,iBAAiB;QACpB,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,QAAQ,CAAC,KAAkB;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;QAChC,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QAE1D,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;YACzB,CAAC,EAAE,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI;YACjC,CAAC,EAAE,QAAQ,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG;YAC/B,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK;YACvC,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM;SAC7C,CAAC,CAAA;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IACpB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAA;IAC5B,CAAC;IAEO,sBAAsB;QAC1B,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAA;QAC7C,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAA;QAC7C,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,CAAA;QAC9C,MAAM,iBAAiB,GACnB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,GAAG,aAAa,CAAA;QAC1D,MAAM,mBAAmB,GAAG,cAAc,IAAI,iBAAiB,CAAA;QAE/D,OAAO,mBAAmB,CAAA;IAC9B,CAAC;IAEM,UAAU;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAA;IAC5B,CAAC;IAEM,UAAU;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAA;IAC5B,CAAC;IAEM,OAAO,CAAC,OAAe;QAC1B,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC;YAC7B,OAAM;QACV,CAAC;QAED,MAAM,mBAAmB,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAA;QACzD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,iBAAiB,GACnB,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;QAEnE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAA;QAEnD,IAAI,IAAI,CAAC,oCAAoC,IAAI,mBAAmB,EAAE,CAAC;YACnE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAA;QAC9B,CAAC;IACL,CAAC;IAEO,UAAU,CAAC,OAAe;QAC9B,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC5C,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;QACxC,OAAO,UAAU,CAAA;IACrB,CAAC;IAEO,eAAe,CAAC,OAAe;QACnC,MAAM,UAAU,GAAG,cAAc,CAAA;QACjC,IAAI,MAAM,GAAG,EAAE,CAAA;QACf,IAAI,SAAS,GAAG,CAAC,CAAA;QAEjB,IAAI,KAA6B,CAAA;QAEjC,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;YACrD,IAAI,OAAO,EAAE,CAAC;gBACV,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;YACtC,CAAC;YAED,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAA;YAClB,SAAS,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;QAC7C,CAAC;QAED,IAAI,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAC7B,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAA;QACvD,CAAC;QAED,OAAO,MAAM,CAAA;IACjB,CAAC;IAEO,UAAU,CAAC,OAAe;QAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,OAAO,CAAA;QAClB,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,GAAG,OAAO,GAAG,CAAA;QACxB,CAAC;QAED,OAAO,OAAO,CAAA;IAClB,CAAC;CACJ"}
1
+ {"version":3,"file":"TkTextWidget.js","sourceRoot":"","sources":["../../src/workspace/TkTextWidget.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,cAAc,CAAA;AAGvC,OAAO,UAAU,MAAM,uBAAuB,CAAA;AAC9C,OAAO,WAAW,MAAM,sBAAsB,CAAA;AAC9C,OAAO,YAAiC,MAAM,mBAAmB,CAAA;AACjE,MAAM,OAAO,GAAG,YAAmB,CAAA;AAEnC,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,YAAY;IAClC,IAAI,GAAG,MAAM,CAAA;IAErB,IAAI,CAAK;IACT,oCAAoC,CAAS;IAErD,YAAmB,OAA4C;QAC3D,KAAK,CAAC,OAAO,CAAC,CAAA;QAEd,MAAM,EACF,MAAM,EACN,IAAI,EACJ,eAAe,EAAE,YAAY,GAAG,KAAK,EACrC,oCAAoC,GAAG,IAAI,EAC3C,GAAG,IAAI,EACV,GAAG,OAAO,CAAA;QAEX,IAAI,CAAC,oCAAoC;YACrC,oCAAoC,CAAA;QAExC,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAErD,IAAI,CAAC,IAAI,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;YAC5B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,SAAS;YACvD,UAAU,EAAE,YAAY;YACxB,UAAU,EAAE,YAAY;YACxB,UAAU,EAAE,YAAY,IAAI,CAAC,IAAI,CAAC,QAAQ;YAC1C,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,GAAG,WAAW,CAAC,gCAAgC,CAAC,IAAI,CAAC;YACrD,GAAG,KAAK;SACX,CAAC,CAAA;QAEF,IAAI,CAAC,uBAAuB,EAAE,CAAA;QAE9B,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACzB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1D,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,QAAkC;QAC5D,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAA;QAEzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QAE7C,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YACf,IAAI,EAAE,IAAI;YACV,GAAG,EAAE,CAAC;YACN,MAAM,EAAE,CAAC;SACZ,CAAC,CAAA;IACN,CAAC;IAEM,iBAAiB;QACpB,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,QAAQ,CAAC,KAAkB;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;QAChC,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QAE1D,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;YACzB,CAAC,EAAE,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI;YACjC,CAAC,EAAE,QAAQ,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG;YAC/B,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK;YACvC,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM;SAC7C,CAAC,CAAA;QAEF,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC/C,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;QACpB,CAAC;IACL,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAA;IAC5B,CAAC;IAEO,sBAAsB;QAC1B,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAA;QAC7C,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAA;QAC7C,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,CAAA;QAC9C,MAAM,iBAAiB,GACnB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,GAAG,aAAa,CAAA;QAC1D,MAAM,mBAAmB,GAAG,cAAc,IAAI,iBAAiB,CAAA;QAE/D,OAAO,mBAAmB,CAAA;IAC9B,CAAC;IAEM,UAAU;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAA;IAC5B,CAAC;IAEM,WAAW;QACd,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IAC/B,CAAC;IAEM,UAAU;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAA;IAC5B,CAAC;IAEM,OAAO,CAAC,OAAe;QAC1B,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC;YAC7B,OAAM;QACV,CAAC;QAED,MAAM,mBAAmB,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAA;QACzD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,iBAAiB,GACnB,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;QAEnE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAA;QAEnD,IAAI,IAAI,CAAC,oCAAoC,IAAI,mBAAmB,EAAE,CAAC;YACnE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAA;QAC9B,CAAC;IACL,CAAC;IAEO,UAAU,CAAC,OAAe;QAC9B,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC5C,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;QACxC,OAAO,UAAU,CAAA;IACrB,CAAC;IAEO,eAAe,CAAC,OAAe;QACnC,MAAM,UAAU,GAAG,cAAc,CAAA;QACjC,IAAI,MAAM,GAAG,EAAE,CAAA;QACf,IAAI,SAAS,GAAG,CAAC,CAAA;QAEjB,IAAI,KAA6B,CAAA;QAEjC,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;YACrD,IAAI,OAAO,EAAE,CAAC;gBACV,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;YACtC,CAAC;YAED,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAA;YAClB,SAAS,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;QAC7C,CAAC;QAED,IAAI,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAC7B,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAA;QACvD,CAAC;QAED,OAAO,MAAM,CAAA;IACjB,CAAC;IAEO,UAAU,CAAC,OAAe;QAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,OAAO,CAAA;QAClB,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,GAAG,OAAO,GAAG,CAAA;QACxB,CAAC;QAED,OAAO,OAAO,CAAA;IAClB,CAAC;CACJ"}
@@ -1,4 +1,5 @@
1
1
  import chokidar from 'chokidar';
2
+ import { spawn } from 'child_process';
2
3
  import path from 'path';
3
4
  import CommandServiceImpl from './CommandService.js';
4
5
  import TestReporter from './TestReporter.js';
@@ -62,6 +63,12 @@ const reporter = new TestReporter({
62
63
  currentWatchMode = currentWatchMode === 'smart' ? 'off' : 'smart';
63
64
  reporter.setWatchMode(currentWatchMode);
64
65
  },
66
+ handleOpenTestFile: (filePath) => {
67
+ const fullPath = path.isAbsolute(filePath)
68
+ ? filePath
69
+ : path.join(cwd, 'src', '__tests__', filePath);
70
+ spawn('code', [fullPath], { detached: true, stdio: 'ignore' }).unref();
71
+ },
65
72
  });
66
73
  async function runTests() {
67
74
  if (running) {
@@ -1 +1 @@
1
- {"version":3,"file":"testRunner.cli.js","sourceRoot":"","sources":["../../src/workspace/testRunner.cli.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,kBAAkB,MAAM,qBAAqB,CAAA;AACpD,OAAO,YAAY,MAAM,mBAAmB,CAAA;AAC5C,OAAO,UAAU,MAAM,iBAAiB,CAAA;AAExC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAClC,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,EAAE;IACzB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAC7C,CAAC,CAAA;AACD,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;AAEjD,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI,CAAA;AACxC,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,KAAK,CAAiC,CAAA;AAC/E,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,IAAI,CAAA;AACjE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;AAEzB,IAAI,cAAc,GAAG,OAAO,CAAA;AAC5B,IAAI,WAAW,GAAG,WAAW,KAAK,IAAI,CAAA;AACtC,IAAI,gBAAgB,GAAG,SAAS,CAAA;AAChC,IAAI,MAAM,GAAsB,IAAI,CAAA;AACpC,IAAI,OAAO,GAAG,KAAK,CAAA;AAEnB,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC;IAC9B,GAAG;IACH,aAAa,EAAE,OAAO,IAAI,SAAS;IACnC,SAAS;IACT,WAAW;IACX,MAAM,EAAE,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;IACxD,eAAe,EAAE,GAAG,EAAE;QAClB,IAAI,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,IAAI,EAAE,CAAA;QAClB,CAAC;aAAM,CAAC;YACJ,QAAQ,EAAE,CAAA;QACd,CAAC;IACL,CAAC;IACD,aAAa,EAAE,GAAG,EAAE;QAChB,MAAM,EAAE,IAAI,EAAE,CAAA;QACd,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IAC7B,CAAC;IACD,UAAU,EAAE,GAAG,EAAE;QACb,MAAM,EAAE,IAAI,EAAE,CAAA;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnB,CAAC;IACD,yBAAyB,EAAE,CAAC,CAAU,EAAE,EAAE;QACtC,cAAc,GAAG,CAAC,IAAI,IAAI,CAAA;QAC1B,IAAI,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,IAAI,EAAE,CAAA;YACd,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QAC7B,CAAC;aAAM,CAAC;YACJ,QAAQ,EAAE,CAAA;QACd,CAAC;IACL,CAAC;IACD,iBAAiB,EAAE,GAAG,EAAE;QACpB,WAAW,GAAG,CAAC,WAAW,CAAA;QAC1B,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAC,CAAA;IACxC,CAAC;IACD,yBAAyB,EAAE,GAAG,EAAE;QAC5B,gBAAgB,GAAG,gBAAgB,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAA;QACvE,QAAQ,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAA;IAC3C,CAAC;IACD,sBAAsB,EAAE,GAAG,EAAE;QACzB,gBAAgB,GAAG,gBAAgB,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAA;QACjE,QAAQ,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAA;IAC3C,CAAC;CACJ,CAAC,CAAA;AAEF,KAAK,UAAU,QAAQ;IACnB,IAAI,OAAO,EAAE,CAAC;QACV,OAAM;IACV,CAAC;IACD,OAAO,GAAG,IAAI,CAAA;IAEd,IAAI,CAAC;QACD,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,OAAO,GAAG,KAAK,CAAA;QACf,QAAQ,CAAC,WAAW,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAA;QAC/C,OAAM;IACV,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,kBAAkB,CAAC,GAAG,CAAC,CAAA;IAC9C,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,CAAA;IAE5D,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;QACpC,IAAI,CAAC;YACD,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,QAAQ,CAAC,WAAW,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAA;QACvD,CAAC;IACL,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;QACnC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IACjC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,GAAG,CAAC;YACb,OAAO,EAAE,cAAc;YACvB,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;SACxD,CAAC,CAAA;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,QAAQ,CAAC,WAAW,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAA;IACnD,CAAC;YAAS,CAAC;QACP,OAAO,GAAG,KAAK,CAAA;QACf,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;AACL,CAAC;AAED,IAAI,aAAa,GAAyC,IAAI,CAAA;AAE9D,SAAS,aAAa,CAAC,WAAoB;IACvC,IAAI,aAAa,EAAE,CAAC;QAChB,YAAY,CAAC,aAAa,CAAC,CAAA;IAC/B,CAAC;IAED,IAAI,gBAAgB,KAAK,OAAO,IAAI,WAAW,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;QAClD,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAA;QAC/B,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,cAAc,GAAG,IAAI,CAAA;YACrB,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAA;YAC/B,MAAM,EAAE,IAAI,EAAE,CAAA;YACd,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QAC7B,CAAC,EAAE,IAAI,CAAC,CAAA;IACZ,CAAC;SAAM,IAAI,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACzC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAA;QAC/B,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,MAAM,EAAE,IAAI,EAAE,CAAA;YACd,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QAC7B,CAAC,EAAE,IAAI,CAAC,CAAA;IACZ,CAAC;AACL,CAAC;AAED,KAAK,UAAU,IAAI;IACf,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAA;IAEtB,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;IAE3C,IAAI,CAAC,GAAG,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC9B,QAAQ,EAAE,CAAA;IACd,CAAC;IAED,IAAI,gBAAgB,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE;YAClD,OAAO,EAAE,cAAc;YACvB,aAAa,EAAE,IAAI;SACtB,CAAC,CAAA;QACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;QACnC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAA;IACpC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACnB,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"testRunner.cli.js","sourceRoot":"","sources":["../../src/workspace/testRunner.cli.ts"],"names":[],"mappings":"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"}
@@ -17,4 +17,5 @@ export interface TextWidget extends BaseWidget<TextEventContract> {
17
17
  setText(content: string): void;
18
18
  getScrollX(): number;
19
19
  getScrollY(): number;
20
+ scrollToTop(): void;
20
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neurodevs/node-tdd",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "A Node.js framework for test-driven development (TDD)",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -251,6 +251,333 @@ export default class TestReporterTest extends AbstractModuleTest {
251
251
  )
252
252
  }
253
253
 
254
+ @test()
255
+ protected static async setWatchModeSetsSmartWatchLabel() {
256
+ const reporter = this.TestReporter()
257
+ const captured: Record<string, string> = {}
258
+ reporter.menu = this.fakeMenu(captured)
259
+ reporter.setWatchMode('smart')
260
+ assert.isEqual(captured['watchDropdown'], 'Smart Watch ^k^#^g • ^')
261
+ }
262
+
263
+ @test()
264
+ protected static async setWatchModeSetsStandardWatchLabel() {
265
+ const reporter = this.TestReporter()
266
+ const captured: Record<string, string> = {}
267
+ reporter.menu = this.fakeMenu(captured)
268
+ reporter.setWatchMode('standard')
269
+ assert.isEqual(captured['watchDropdown'], 'Standard Watch ^k^#^g • ^')
270
+ }
271
+
272
+ @test()
273
+ protected static async setWatchModeSetsNotWatchingLabel() {
274
+ const reporter = this.TestReporter()
275
+ const captured: Record<string, string> = {}
276
+ reporter.menu = this.fakeMenu(captured)
277
+ reporter.setWatchMode('off')
278
+ assert.isEqual(captured['watchDropdown'], 'Not Watching ^w^#^r • ^')
279
+ }
280
+
281
+ @test()
282
+ protected static async setWatchModeSkipsLabelUpdateWhenCountdownActive() {
283
+ const reporter = this.TestReporter()
284
+ const captured: Record<string, string> = {}
285
+ reporter.menu = this.fakeMenu(captured)
286
+ reporter.countDownTimeInterval = setInterval(() => {}, 10000)
287
+ reporter.setWatchMode('smart')
288
+ clearInterval(reporter.countDownTimeInterval)
289
+ assert.isUndefined(
290
+ captured['watchDropdown'],
291
+ 'label must not update during countdown'
292
+ )
293
+ }
294
+
295
+ @test()
296
+ protected static async createsDropInMenuWidgetOnStart() {
297
+ const reporter = this.TestReporter() as any
298
+ let capturedMenuBarOptions: any
299
+
300
+ const fakeWidget: any = new Proxy(
301
+ {},
302
+ {
303
+ get: (_t, prop: string) => {
304
+ if (prop === 'getFrame') {
305
+ return () => ({
306
+ left: 0,
307
+ top: 0,
308
+ width: 100,
309
+ height: 50,
310
+ })
311
+ }
312
+ if (prop === 'getChildById') {
313
+ return () => null
314
+ }
315
+ if (prop === 'getRows') {
316
+ return () => [{}]
317
+ }
318
+ if (prop === 'getFocusedWidget') {
319
+ return () => null
320
+ }
321
+ if (prop === 'on') {
322
+ return () => fakeWidget
323
+ }
324
+ return () => fakeWidget
325
+ },
326
+ }
327
+ )
328
+
329
+ reporter.widgets = {
330
+ Widget: (type: string, options: any) => {
331
+ if (type === 'menuBar') {
332
+ capturedMenuBarOptions = options
333
+ }
334
+ return fakeWidget
335
+ },
336
+ }
337
+
338
+ await reporter.start()
339
+
340
+ assert.isEqualDeep(capturedMenuBarOptions, {
341
+ parent: reporter.window,
342
+ left: 0,
343
+ top: 0,
344
+ shouldLockWidthWithParent: true,
345
+ items: [
346
+ {
347
+ label: 'Restart ',
348
+ value: 'restart',
349
+ },
350
+ {
351
+ label: 'Debug ',
352
+ value: 'toggleDebug',
353
+ },
354
+ {
355
+ label: 'Not Watching ',
356
+ value: 'watchDropdown',
357
+ items: [
358
+ {
359
+ label: 'Watch all',
360
+ value: 'toggleStandardWatch',
361
+ },
362
+ {
363
+ label: 'Smart watch',
364
+ value: 'toggleSmartWatch',
365
+ },
366
+ ],
367
+ },
368
+ {
369
+ label: 'Quit',
370
+ value: 'quit',
371
+ },
372
+ ],
373
+ })
374
+
375
+ clearInterval(reporter.updateInterval)
376
+ }
377
+
378
+ @test()
379
+ protected static async createsTestLogWidgetOnStart() {
380
+ const reporter = this.TestReporter() as any
381
+ let capturedTextOptions: { type: string; options: any }[] = []
382
+
383
+ const fakeWidget: any = new Proxy(
384
+ {},
385
+ {
386
+ get: (_t, prop: string) => {
387
+ if (prop === 'getFrame') {
388
+ return () => ({
389
+ left: 0,
390
+ top: 0,
391
+ width: 100,
392
+ height: 50,
393
+ })
394
+ }
395
+ if (prop === 'getChildById') {
396
+ return () => null
397
+ }
398
+ if (prop === 'getRows') {
399
+ return () => [{}]
400
+ }
401
+ if (prop === 'getFocusedWidget') {
402
+ return () => null
403
+ }
404
+ if (prop === 'on') {
405
+ return () => fakeWidget
406
+ }
407
+ return () => fakeWidget
408
+ },
409
+ }
410
+ )
411
+
412
+ reporter.widgets = {
413
+ Widget: (type: string, options: any) => {
414
+ capturedTextOptions.push({ type, options })
415
+ return fakeWidget
416
+ },
417
+ }
418
+
419
+ await reporter.start()
420
+
421
+ const expectedOptions = {
422
+ isScrollEnabled: true,
423
+ wordWrap: false,
424
+ left: 0,
425
+ top: 0,
426
+ height: '100%',
427
+ width: '100%',
428
+ shouldLockHeightWithParent: true,
429
+ shouldLockWidthWithParent: true,
430
+ } as any
431
+
432
+ const entry = capturedTextOptions.find(
433
+ (o) =>
434
+ o.type === 'text' &&
435
+ Object.keys(expectedOptions).every(
436
+ (k) => o.options[k] === expectedOptions[k]
437
+ )
438
+ )
439
+
440
+ assert.isTruthy(entry, 'Test log widget must be created on start')
441
+
442
+ clearInterval(reporter.updateInterval)
443
+ }
444
+
445
+ @test()
446
+ protected static async createsSelectTestPopupWidgetOnStart() {
447
+ const reporter = this.TestReporter() as any
448
+ const capturedTextOptions: { type: string; options: any }[] = []
449
+ const popupWidth = 50
450
+
451
+ const fakePopup = {
452
+ getFrame: () => ({ width: popupWidth }),
453
+ on: () => fakePopup,
454
+ }
455
+
456
+ const fakeButton = { on: () => fakeButton }
457
+
458
+ reporter.window = {}
459
+ reporter.widgets = {
460
+ Widget: (type: string, options: any) => {
461
+ capturedTextOptions.push({ type, options })
462
+ if (type === 'popup') {
463
+ return fakePopup
464
+ }
465
+ return fakeButton
466
+ },
467
+ }
468
+
469
+ reporter.dropInSelectTestPopup({
470
+ testFile: 'src/foo/bar.test.ts',
471
+ row: 10,
472
+ column: 30,
473
+ })
474
+
475
+ const entry = capturedTextOptions.find(
476
+ (o) =>
477
+ o.type === 'text' &&
478
+ o.options?.text?.startsWith('Selected file:')
479
+ )
480
+
481
+ assert.isTruthy(entry, 'popup text widget must be created')
482
+
483
+ const { parent: _parent, ...restOptions } = entry!.options
484
+
485
+ assert.isEqualDeep(restOptions, {
486
+ left: 1,
487
+ top: 1,
488
+ height: 4,
489
+ width: popupWidth - 2,
490
+ text: 'Selected file:\n\nsrc/foo/bar.test.ts',
491
+ })
492
+ }
493
+
494
+ @test()
495
+ protected static async scrollsToTopWhenStatusSetToStopped() {
496
+ const reporter = this.TestReporter() as any
497
+ let scrollToTopCalled = false
498
+
499
+ reporter.menu = this.fakeMenu({})
500
+ reporter.bottomLayout = { updateLayout: () => {} }
501
+ reporter.statusBar = { setText: () => {} }
502
+ reporter.testLog = {
503
+ scrollToTop: () => {
504
+ scrollToTopCalled = true
505
+ },
506
+ setText: () => {},
507
+ getText: () => '',
508
+ }
509
+
510
+ reporter.setStatus('stopped')
511
+
512
+ assert.isTrue(
513
+ scrollToTopCalled,
514
+ 'scrollToTop must be called when status is stopped'
515
+ )
516
+ }
517
+
518
+ @test()
519
+ protected static async getFileForLineReturnsCorrectFileForRow() {
520
+ const reporter = this.TestReporter() as any
521
+
522
+ reporter.lastResults = {
523
+ testFiles: [
524
+ {
525
+ path: 'file1.ts',
526
+ status: 'passed',
527
+ tests: [{ name: 'test1' }, { name: 'test2' }],
528
+ },
529
+ {
530
+ path: 'file2.ts',
531
+ status: 'passed',
532
+ tests: [{ name: 'test3' }],
533
+ },
534
+ ],
535
+ }
536
+
537
+ reporter.testLog = { getScrollY: () => 0 }
538
+
539
+ // file1: rows 0–2 (header + 2 tests), file2: rows 3–4 (header + 1 test)
540
+ assert.isEqual(reporter.getFileForLine(0), 'file1.ts') // header
541
+ assert.isEqual(reporter.getFileForLine(2), 'file1.ts') // last test
542
+ assert.isEqual(reporter.getFileForLine(3), 'file2.ts') // file2 header
543
+ assert.isEqual(reporter.getFileForLine(4), 'file2.ts') // file2 last test
544
+ assert.isEqual(reporter.getFileForLine(5), undefined) // out of range
545
+ }
546
+
547
+ @test()
548
+ protected static async sortsFailedFilesToTopWhenStopped() {
549
+ const reporter = this.TestReporter() as any
550
+
551
+ reporter.status = 'stopped'
552
+ reporter.lastResults = { customErrors: [] }
553
+
554
+ const results = {
555
+ testFiles: [
556
+ { path: 'passing.ts', status: 'passed', tests: [] },
557
+ { path: 'failing.ts', status: 'failed', tests: [] },
558
+ ],
559
+ }
560
+
561
+ const { logContent } = reporter.resultsToLogContents(results)
562
+
563
+ const failingIdx = logContent.indexOf('failing.ts')
564
+ const passingIdx = logContent.indexOf('passing.ts')
565
+
566
+ assert.isBelow(
567
+ failingIdx,
568
+ passingIdx,
569
+ 'Failed file must appear before passing file when stopped'
570
+ )
571
+ }
572
+
573
+ private static fakeMenu(captured: Record<string, string>) {
574
+ return {
575
+ setTextForItem: (key: string, label: string) => {
576
+ captured[key] = label
577
+ },
578
+ }
579
+ }
580
+
254
581
  private static TestReporter(options?: TestReporterOptions) {
255
582
  return new TestReporter(options) as any
256
583
  }
@@ -79,6 +79,47 @@ export default class WidgetsTest extends AbstractModuleTest {
79
79
  assert.isTruthy(column)
80
80
  }
81
81
 
82
+ @test()
83
+ protected static async setFrameResyncsScrollPositionOnScrollableWidget() {
84
+ const text = this.buildScrollableText() as any
85
+ let capturedArgs: any[] | undefined
86
+
87
+ text.text.scrollable = true
88
+ text.text.scrollTo = (...args: any[]) => {
89
+ capturedArgs = args
90
+ }
91
+
92
+ const currentScrollY = text.text.scrollY
93
+
94
+ text.setFrame({ left: 0, top: 0, width: 20, height: 10 })
95
+
96
+ assert.isEqualDeep(capturedArgs, [null, currentScrollY])
97
+ }
98
+
99
+ @test()
100
+ protected static async scrollToTopCallsScrollToWithZero() {
101
+ const text = this.buildScrollableText() as any
102
+ let capturedArgs: any[] | undefined
103
+
104
+ text.text.scrollTo = (...args: any[]) => {
105
+ capturedArgs = args
106
+ }
107
+
108
+ text.scrollToTop()
109
+
110
+ assert.isEqualDeep(capturedArgs, [null, 0])
111
+ }
112
+
113
+ private static buildScrollableText() {
114
+ return this.factory.Widget('text', {
115
+ left: 0,
116
+ top: 0,
117
+ width: 20,
118
+ height: 10,
119
+ isScrollEnabled: true,
120
+ })
121
+ }
122
+
82
123
  private static buildText() {
83
124
  return this.factory.Widget('text', {
84
125
  left: 0,
@@ -86,9 +86,10 @@ export default class TestReporter {
86
86
  public setWatchMode(watchMode: WatchMode) {
87
87
  this.watchMode = watchMode
88
88
  if (!this.countDownTimeInterval) {
89
- let label = watchMode === 'smart' ? 'Smart Watch' : 'Standard Watch'
89
+ let label =
90
+ watchMode === 'smart' ? 'Smart Watch ' : 'Standard Watch'
90
91
  if (watchMode === 'off') {
91
- label = 'Not Watching'
92
+ label = 'Not Watching '
92
93
  }
93
94
  this.setWatchLabel(label)
94
95
  }
@@ -221,7 +222,7 @@ export default class TestReporter {
221
222
  value: 'toggleDebug',
222
223
  },
223
224
  {
224
- label: 'Not Watching ',
225
+ label: 'Not Watching ',
225
226
  value: 'watchDropdown',
226
227
  items: [
227
228
  {
@@ -255,6 +256,7 @@ export default class TestReporter {
255
256
  this.setStatusLabel('Starting...')
256
257
  } else if (this.status === 'stopped') {
257
258
  this.refreshResults()
259
+ this.testLog?.scrollToTop()
258
260
  this.setStatusLabel('')
259
261
  } else if (this.status === 'running') {
260
262
  this.setStatusLabel('Running tests...')
@@ -331,22 +333,21 @@ export default class TestReporter {
331
333
  }
332
334
 
333
335
  private dropInTestLog() {
334
- const parent = this.bottomLayout.getChildById('results')
336
+ const parent = this.bottomLayout.getChildById('results')!
335
337
 
336
- if (parent) {
337
- this.testLog = this.widgets.Widget('text', {
338
- parent,
339
- isScrollEnabled: true,
340
- left: 0,
341
- top: 0,
342
- height: '100%',
343
- width: '100%',
344
- shouldLockHeightWithParent: true,
345
- shouldLockWidthWithParent: true,
346
- })
338
+ this.testLog = this.widgets.Widget('text', {
339
+ parent,
340
+ isScrollEnabled: true,
341
+ wordWrap: false,
342
+ left: 0,
343
+ top: 0,
344
+ height: '100%',
345
+ width: '100%',
346
+ shouldLockHeightWithParent: true,
347
+ shouldLockWidthWithParent: true,
348
+ })
347
349
 
348
- void this.testLog.on('click', this.handleClickTestLog.bind(this))
349
- }
350
+ void this.testLog.on('click', this.handleClickTestLog.bind(this))
350
351
  }
351
352
 
352
353
  private async handleClickTestLog(payload: { row: number; column: number }) {
@@ -437,7 +438,7 @@ export default class TestReporter {
437
438
  top: 1,
438
439
  height: 4,
439
440
  width: this.selectTestPopup.getFrame().width - 2,
440
- text: `What do you wanna do with:\n\n${testFile}`,
441
+ text: `Selected file:\n\n${testFile}`,
441
442
  })
442
443
 
443
444
  const open = this.widgets.Widget('button', {
@@ -481,13 +482,17 @@ export default class TestReporter {
481
482
 
482
483
  for (const file of this.lastResults.testFiles ?? []) {
483
484
  const minRow = line
484
- const maxRow = line + (file.tests ?? []).length
485
+ const lineCount =
486
+ 1 +
487
+ (file.tests ?? []).length +
488
+ (file.status === 'running' ? 1 : 0)
489
+ const maxRow = line + lineCount - 1
485
490
 
486
491
  if (row >= minRow && row <= maxRow) {
487
492
  return file.path
488
493
  }
489
494
 
490
- line = maxRow
495
+ line = maxRow + 1
491
496
  }
492
497
 
493
498
  return undefined
@@ -657,7 +662,17 @@ export default class TestReporter {
657
662
  let logContent = ''
658
663
  let errorContent = ''
659
664
 
660
- results.testFiles?.forEach((file) => {
665
+ const files = [...(results.testFiles ?? [])]
666
+
667
+ if (this.status === 'stopped') {
668
+ files.sort((a, b) => {
669
+ const aFailed = a.status === 'failed' ? 0 : 1
670
+ const bFailed = b.status === 'failed' ? 0 : 1
671
+ return aFailed - bFailed
672
+ })
673
+ }
674
+
675
+ files.forEach((file) => {
661
676
  logContent += this.errorLogItemGenerator.generateLogItemForFile(
662
677
  file,
663
678
  this.status
@@ -50,7 +50,7 @@ export default class TkTextWidget extends TkBaseWidget implements TextWidget {
50
50
 
51
51
  const line = this.text.content.split('\n')[y]
52
52
 
53
- await (this as TextWidget).emit('click', {
53
+ this.emit('click', {
54
54
  text: line,
55
55
  row: y,
56
56
  column: x,
@@ -71,7 +71,12 @@ export default class TkTextWidget extends TkBaseWidget implements TextWidget {
71
71
  width: newFrame.width ?? oldFrame.width,
72
72
  height: newFrame.height ?? oldFrame.height,
73
73
  })
74
- this.text.draw()
74
+
75
+ if (this.text.scrollable) {
76
+ this.text.scrollTo(null, this.text.scrollY)
77
+ } else {
78
+ this.text.draw()
79
+ }
75
80
  }
76
81
 
77
82
  public getText(): string {
@@ -93,6 +98,10 @@ export default class TkTextWidget extends TkBaseWidget implements TextWidget {
93
98
  return this.text.scrollY
94
99
  }
95
100
 
101
+ public scrollToTop() {
102
+ this.text.scrollTo(null, 0)
103
+ }
104
+
96
105
  public getScrollX() {
97
106
  return this.text.scrollX
98
107
  }
@@ -1,4 +1,5 @@
1
1
  import chokidar from 'chokidar'
2
+ import { spawn } from 'child_process'
2
3
  import path from 'path'
3
4
  import CommandServiceImpl from './CommandService.js'
4
5
  import TestReporter from './TestReporter.js'
@@ -64,6 +65,12 @@ const reporter = new TestReporter({
64
65
  currentWatchMode = currentWatchMode === 'smart' ? 'off' : 'smart'
65
66
  reporter.setWatchMode(currentWatchMode)
66
67
  },
68
+ handleOpenTestFile: (filePath: string) => {
69
+ const fullPath = path.isAbsolute(filePath)
70
+ ? filePath
71
+ : path.join(cwd, 'src', '__tests__', filePath)
72
+ spawn('code', [fullPath], { detached: true, stdio: 'ignore' }).unref()
73
+ },
67
74
  })
68
75
 
69
76
  async function runTests() {
@@ -23,4 +23,5 @@ export interface TextWidget extends BaseWidget<TextEventContract> {
23
23
  setText(content: string): void
24
24
  getScrollX(): number
25
25
  getScrollY(): number
26
+ scrollToTop(): void
26
27
  }