@scalvert/bin-tester 0.0.5 → 0.1.0

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.
package/README.md CHANGED
@@ -53,15 +53,14 @@ describe('Some tests', () => {
53
53
  expect(result.stdout).toBe('Did some stuff');
54
54
  });
55
55
 
56
- // Write a file with contents to the tmp directory
57
56
  test('another test', () => {
58
- project.write({
57
+ // Write a file with contents to the tmp directory
58
+ await project.writeJSON({
59
59
  'some/file.txt': 'some content',
60
60
  });
61
61
 
62
- const result = await runBin({
63
- args: ['--path', 'some/file.txt'], // pass some args to the bin that will be used for only this invocation
64
- });
62
+ // pass some args to the bin that will be used for only this invocation
63
+ const result = await runBin('--path', 'some/file.txt');
65
64
 
66
65
  expect(result.stdout).toBe('Read "some/file.txt"');
67
66
  });
package/dist/index.cjs CHANGED
@@ -53,6 +53,7 @@ var import_execa2 = __toESM(require("execa"), 1);
53
53
  // src/project.ts
54
54
  var import_execa = __toESM(require("execa"), 1);
55
55
  var import_fixturify_project = require("fixturify-project");
56
+ var import_deepmerge = __toESM(require("deepmerge"), 1);
56
57
  var ROOT = process.cwd();
57
58
  var BinTesterProject = class extends import_fixturify_project.Project {
58
59
  constructor(name = "fake-project", version, cb) {
@@ -67,13 +68,14 @@ var BinTesterProject = class extends import_fixturify_project.Project {
67
68
  gitInit() {
68
69
  return (0, import_execa.default)(`git init -q ${this.baseDir}`);
69
70
  }
70
- chdir() {
71
+ async chdir() {
71
72
  this._dirChanged = true;
73
+ await this.write();
72
74
  process.chdir(this.baseDir);
73
75
  }
74
76
  writeJSON(dirJSON) {
75
- this.files = __spreadValues(__spreadValues({}, this.files), dirJSON);
76
- return super.write();
77
+ this.files = (0, import_deepmerge.default)(this.files, dirJSON);
78
+ return this.write();
77
79
  }
78
80
  dispose() {
79
81
  if (this._dirChanged) {
@@ -88,22 +90,32 @@ var DEFAULT_BIN_TESTER_OPTIONS = {
88
90
  staticArgs: [],
89
91
  projectConstructor: BinTesterProject
90
92
  };
91
- var DEFAULT_RUN_OPTIONS = {
92
- args: [],
93
- execaOptions: {}
94
- };
93
+ function parseArgs(args) {
94
+ if (args.length > 0 && typeof args[args.length - 1] === "object") {
95
+ const execaOptions = args.pop();
96
+ return {
97
+ args,
98
+ execaOptions
99
+ };
100
+ } else {
101
+ return {
102
+ args,
103
+ execaOptions: {}
104
+ };
105
+ }
106
+ }
95
107
  function createBinTester(options) {
96
108
  let project;
97
109
  const mergedOptions = __spreadValues(__spreadValues({}, DEFAULT_BIN_TESTER_OPTIONS), options);
98
- function runBin(runOptions = {}) {
99
- const mergedRunOptions = __spreadValues(__spreadValues({}, DEFAULT_RUN_OPTIONS), runOptions);
110
+ function runBin(...args) {
111
+ const mergedRunOptions = parseArgs(args);
100
112
  return (0, import_execa2.default)(process.execPath, [mergedOptions.binPath, ...mergedOptions.staticArgs, ...mergedRunOptions.args], __spreadValues({
101
113
  reject: false,
102
114
  cwd: project.baseDir
103
115
  }, mergedRunOptions.execaOptions));
104
116
  }
105
117
  async function setupProject() {
106
- project = new mergedOptions.projectConstructor();
118
+ project = "createProject" in mergedOptions ? await mergedOptions.createProject() : new BinTesterProject();
107
119
  await project.write();
108
120
  return project;
109
121
  }
package/dist/index.d.ts CHANGED
@@ -1,14 +1,39 @@
1
1
  import execa from 'execa';
2
- import { Constructor } from 'type-fest';
3
2
  import fixturify from 'fixturify';
4
3
  import { Project } from 'fixturify-project';
5
4
 
6
5
  declare class BinTesterProject extends Project {
7
6
  private _dirChanged;
7
+ /**
8
+ * Constructs an instance of a BinTesterProject.
9
+ *
10
+ * @param {string} name - The name of the project. Used within the package.json as the name property.
11
+ * @param {string} version - The version of the project. Used within the package.json as the version property.
12
+ * @param {(project: Project) => void} cb - An optional callback for additional setup steps after the project is constructed.
13
+ */
8
14
  constructor(name?: string, version?: string, cb?: (project: Project) => void);
15
+ /**
16
+ * Runs `git init` inside a project.
17
+ *
18
+ * @returns {*} {execa.ExecaChildProcess<string>}
19
+ */
9
20
  gitInit(): execa.ExecaChildProcess<string>;
10
- chdir(): void;
21
+ /**
22
+ * Changes a directory from inside the project.
23
+ */
24
+ chdir(): Promise<void>;
25
+ /**
26
+ * Writes a directory struture in the project directory.
27
+ *
28
+ * @param {fixturify.DirJSON} dirJSON - A JSON object representing the directory structure to create.
29
+ * @returns {*} {Promise<void>}
30
+ */
11
31
  writeJSON(dirJSON: fixturify.DirJSON): Promise<void>;
32
+ /**
33
+ * Correctly disposes of the project, observing when the directory has been changed.
34
+ *
35
+ * @returns {void}
36
+ */
12
37
  dispose(): void;
13
38
  }
14
39
 
@@ -22,31 +47,52 @@ interface BinTesterOptions<TProject> {
22
47
  */
23
48
  staticArgs?: string[];
24
49
  /**
25
- * An optional class to use to create the project
50
+ * An optional function to use to create the project. Use this if you want to provide a custom implementation of a BinTesterProject.
26
51
  */
27
- projectConstructor?: Constructor<TProject>;
52
+ createProject?: () => TProject;
28
53
  }
29
- interface RunOptions {
54
+ interface RunBin {
30
55
  /**
31
- * Arguments to provide to the bin script.
56
+ * A runBin implementation that takes no parameters.
57
+ *
58
+ * @returns {*} {execa.ExecaChildProcess<string>}
59
+ * @memberof RunBin
32
60
  */
33
- args?: string[];
61
+ (): execa.ExecaChildProcess<string>;
34
62
  /**
35
- * Options to provide to execa. @see https://github.com/sindresorhus/execa#options
63
+ * A runBin implementation that takes varargs.
64
+ *
65
+ * @param {...RunBinArgs} args
66
+ * @returns {*} {execa.ExecaChildProcess<string>}
67
+ * @memberof RunBin
36
68
  */
37
- execaOptions?: execa.Options<string>;
69
+ (...args: RunBinArgs): execa.ExecaChildProcess<string>;
38
70
  }
39
71
  interface CreateBinTesterResult<TProject extends BinTesterProject> {
40
- runBin: (runOptions?: RunOptions) => execa.ExecaChildProcess<string>;
72
+ /**
73
+ * Runs the configured bin function via execa.
74
+ */
75
+ runBin: RunBin;
76
+ /**
77
+ * Sets up the specified project for use within tests.
78
+ */
41
79
  setupProject: () => Promise<TProject>;
80
+ /**
81
+ * Sets up a tmp directory for use within tests.
82
+ */
42
83
  setupTmpDir: () => Promise<string>;
84
+ /**
85
+ * Tears the project down, ensuring the tmp directory is removed. Shoud be paired with setupProject.
86
+ */
43
87
  teardownProject: () => void;
44
88
  }
89
+ declare type RunBinArgs = [...binArgs: string[], execaOptions: execa.Options<string>];
45
90
  /**
46
91
  * Creates the bin tester API functions to use within tests.
47
92
  *
48
- * @param options - An object of bin tester options
49
- * @returns - A project instance.
93
+ * @typedef TProject - The type of BinTesterProject used.
94
+ * @param {BinTesterOptions<TProject>} options - An object of bin tester options
95
+ * @returns {CreateBinTesterResult<TProject>} - A project instance.
50
96
  */
51
97
  declare function createBinTester<TProject extends BinTesterProject>(options: BinTesterOptions<TProject>): CreateBinTesterResult<TProject>;
52
98
 
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ import execa2 from "execa";
21
21
  // src/project.ts
22
22
  import execa from "execa";
23
23
  import { Project } from "fixturify-project";
24
+ import deepmerge from "deepmerge";
24
25
  var ROOT = process.cwd();
25
26
  var BinTesterProject = class extends Project {
26
27
  constructor(name = "fake-project", version, cb) {
@@ -35,13 +36,14 @@ var BinTesterProject = class extends Project {
35
36
  gitInit() {
36
37
  return execa(`git init -q ${this.baseDir}`);
37
38
  }
38
- chdir() {
39
+ async chdir() {
39
40
  this._dirChanged = true;
41
+ await this.write();
40
42
  process.chdir(this.baseDir);
41
43
  }
42
44
  writeJSON(dirJSON) {
43
- this.files = __spreadValues(__spreadValues({}, this.files), dirJSON);
44
- return super.write();
45
+ this.files = deepmerge(this.files, dirJSON);
46
+ return this.write();
45
47
  }
46
48
  dispose() {
47
49
  if (this._dirChanged) {
@@ -56,22 +58,32 @@ var DEFAULT_BIN_TESTER_OPTIONS = {
56
58
  staticArgs: [],
57
59
  projectConstructor: BinTesterProject
58
60
  };
59
- var DEFAULT_RUN_OPTIONS = {
60
- args: [],
61
- execaOptions: {}
62
- };
61
+ function parseArgs(args) {
62
+ if (args.length > 0 && typeof args[args.length - 1] === "object") {
63
+ const execaOptions = args.pop();
64
+ return {
65
+ args,
66
+ execaOptions
67
+ };
68
+ } else {
69
+ return {
70
+ args,
71
+ execaOptions: {}
72
+ };
73
+ }
74
+ }
63
75
  function createBinTester(options) {
64
76
  let project;
65
77
  const mergedOptions = __spreadValues(__spreadValues({}, DEFAULT_BIN_TESTER_OPTIONS), options);
66
- function runBin(runOptions = {}) {
67
- const mergedRunOptions = __spreadValues(__spreadValues({}, DEFAULT_RUN_OPTIONS), runOptions);
78
+ function runBin(...args) {
79
+ const mergedRunOptions = parseArgs(args);
68
80
  return execa2(process.execPath, [mergedOptions.binPath, ...mergedOptions.staticArgs, ...mergedRunOptions.args], __spreadValues({
69
81
  reject: false,
70
82
  cwd: project.baseDir
71
83
  }, mergedRunOptions.execaOptions));
72
84
  }
73
85
  async function setupProject() {
74
- project = new mergedOptions.projectConstructor();
86
+ project = "createProject" in mergedOptions ? await mergedOptions.createProject() : new BinTesterProject();
75
87
  await project.write();
76
88
  return project;
77
89
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalvert/bin-tester",
3
- "version": "0.0.5",
3
+ "version": "0.1.0",
4
4
  "description": "A test harness to invoke a CLI in a tmp directory",
5
5
  "keywords": [
6
6
  "cli",
@@ -39,6 +39,7 @@
39
39
  "dist"
40
40
  ],
41
41
  "dependencies": {
42
+ "deepmerge": "^4.2.2",
42
43
  "execa": "^5.1.1",
43
44
  "fixturify-project": "^4.1.0"
44
45
  },
@@ -48,9 +49,9 @@
48
49
  "@typescript-eslint/parser": "^5.14.0",
49
50
  "eslint": "^8.10.0",
50
51
  "eslint-config-prettier": "^8.5.0",
52
+ "eslint-plugin-jsdoc": "^38.0.4",
51
53
  "eslint-plugin-node": "^11.1.0",
52
54
  "eslint-plugin-prettier": "^4.0.0",
53
- "eslint-plugin-tsdoc": "^0.2.14",
54
55
  "eslint-plugin-unicorn": "^41.0.0",
55
56
  "fixturify": "^2.1.1",
56
57
  "prettier": "^2.5.1",