@jaypie/testkit 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/.eslintrc.cjs +40 -0
- package/.github/workflows/npm-deploy.yml +55 -0
- package/.vscode/settings.json +23 -0
- package/README.md +29 -0
- package/_templates/jaypie/hygen/jest.command.ejs.t +14 -0
- package/_templates/jaypie/hygen/new.ejs.t +31 -0
- package/_templates/jaypie/hygen/prompt.cjs +37 -0
- package/_templates/jaypie/hygen/prompt.ejs.t +44 -0
- package/_templates/jaypie/hygen/test.ejs.t +52 -0
- package/_templates/jaypie/vite/new.ejs.t +28 -0
- package/_templates/jaypie/vite/prompt.cjs +35 -0
- package/_templates/jaypie/vite/test.ejs.t +49 -0
- package/_templates/jaypie/vite/vitest.command.ejs.t +11 -0
- package/_templates/jaypie/vitest/jest.command.ejs.t +11 -0
- package/_templates/jaypie/vitest/prompt.cjs +41 -0
- package/_templates/jaypie/vitest/test.ejs.t +49 -0
- package/_templates/jaypie/workflow-npm/npm-deploy.ejs.t +58 -0
- package/_templates/jaypie/workflow-npm/prompt.cjs +32 -0
- package/package.json +30 -0
- package/src/__tests__/index.spec.js +17 -0
- package/src/__tests__/mockLog.module.spec.js +95 -0
- package/src/index.js +6 -0
- package/src/mockLog.module.js +91 -0
- package/testSetup.js +3 -0
- package/vite.config.js +10 -0
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
root: true,
|
|
3
|
+
env: {
|
|
4
|
+
es6: true,
|
|
5
|
+
node: true,
|
|
6
|
+
},
|
|
7
|
+
extends: [
|
|
8
|
+
"eslint:recommended",
|
|
9
|
+
"plugin:import/errors",
|
|
10
|
+
// "Add plugin:prettier/recommended as the last item in the extends array in your .eslintrc* config file, so that eslint-config-prettier has the opportunity to override other configs"
|
|
11
|
+
"plugin:prettier/recommended",
|
|
12
|
+
],
|
|
13
|
+
overrides: [
|
|
14
|
+
{
|
|
15
|
+
files: ["__tests__/**", "**/*.spec.js", "**/*.test.js"],
|
|
16
|
+
plugins: ["vitest"],
|
|
17
|
+
extends: ["plugin:vitest/recommended"],
|
|
18
|
+
rules: {
|
|
19
|
+
"vitest/no-focused-tests": "error",
|
|
20
|
+
"vitest/no-disabled-tests": "warn",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
files: ["*.cjs"],
|
|
25
|
+
rules: {
|
|
26
|
+
"import/no-commonjs": "off",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
parserOptions: {
|
|
31
|
+
ecmaVersion: "latest",
|
|
32
|
+
sourceType: "module",
|
|
33
|
+
},
|
|
34
|
+
plugins: ["prettier"],
|
|
35
|
+
rules: {
|
|
36
|
+
"import/extensions": ["error", "ignorePackages"],
|
|
37
|
+
"import/no-commonjs": "error",
|
|
38
|
+
"no-console": "warn",
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: NPM Deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- v*
|
|
7
|
+
|
|
8
|
+
env:
|
|
9
|
+
PROJECT_ENV: meta
|
|
10
|
+
PROJECT_SERVICE: libraries
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
deploy:
|
|
14
|
+
name: NPM Deploy
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write # for aws-actions/configure-aws-credentials
|
|
17
|
+
contents: read # for actions/checkout
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout Code
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
- name: NPM Install (`npm install`)
|
|
23
|
+
run: npm install
|
|
24
|
+
- name: NPM Deploy
|
|
25
|
+
run: |
|
|
26
|
+
npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
|
|
27
|
+
npm publish --access public
|
|
28
|
+
lint:
|
|
29
|
+
name: Lint (in parallel)
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- name: Checkout code
|
|
33
|
+
uses: actions/checkout@v4
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: npm ci
|
|
36
|
+
- name: Run ESLint
|
|
37
|
+
run: npm run lint
|
|
38
|
+
# run: npx eslint . --max-warnings=0
|
|
39
|
+
test:
|
|
40
|
+
name: Unit Test (in parallel)
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
strategy:
|
|
43
|
+
matrix:
|
|
44
|
+
node-version: [18.x, 20.x]
|
|
45
|
+
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
49
|
+
uses: actions/setup-node@v4
|
|
50
|
+
with:
|
|
51
|
+
node-version: ${{ matrix.node-version }}
|
|
52
|
+
cache: 'npm'
|
|
53
|
+
- run: npm ci
|
|
54
|
+
- run: |
|
|
55
|
+
npm test
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cSpell.words": [
|
|
3
|
+
"certificatemanager",
|
|
4
|
+
"clonedeep",
|
|
5
|
+
"composables",
|
|
6
|
+
"Finlayson",
|
|
7
|
+
"fontface",
|
|
8
|
+
"hygen",
|
|
9
|
+
"iconsets",
|
|
10
|
+
"initzero",
|
|
11
|
+
"jaypie",
|
|
12
|
+
"knowdev",
|
|
13
|
+
"oidc",
|
|
14
|
+
"pinia",
|
|
15
|
+
"roboto",
|
|
16
|
+
"testkit",
|
|
17
|
+
"unplugin",
|
|
18
|
+
"vendia",
|
|
19
|
+
"vuekit",
|
|
20
|
+
"vuetify",
|
|
21
|
+
"wght"
|
|
22
|
+
]
|
|
23
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Jaypie Testkit 🐦⬛🫒
|
|
2
|
+
|
|
3
|
+
TODO: update the project header and optionally write a description here
|
|
4
|
+
|
|
5
|
+
## 📋 Usage
|
|
6
|
+
|
|
7
|
+
### Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install --save-dev @jaypie/testkit
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Example
|
|
14
|
+
|
|
15
|
+
TODO: Example should include one trivial and possibly one thorough example of using the library
|
|
16
|
+
|
|
17
|
+
## 📖 Reference
|
|
18
|
+
|
|
19
|
+
TODO: Reference should be a complete list of everything in the package
|
|
20
|
+
|
|
21
|
+
## 📝 Changelog
|
|
22
|
+
|
|
23
|
+
| Date | Version | Summary |
|
|
24
|
+
| ---------- | ------- | -------------- |
|
|
25
|
+
| 3/15/2024 | 0.0.1 | Initial commit |
|
|
26
|
+
|
|
27
|
+
## 📜 License
|
|
28
|
+
|
|
29
|
+
Published by Finlayson Studio. All rights reserved
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: <%= hygen %>/<%= generator %>/<%= action %>/jest.command.ejs.t
|
|
3
|
+
---
|
|
4
|
+
---
|
|
5
|
+
inject: true
|
|
6
|
+
to: package.json
|
|
7
|
+
after: scripts
|
|
8
|
+
skip_if: spec<%- '<' %>%= colonSubspec %<%- '>' %>.+<%- '<' %>%= path %<%- '>' %>/__tests__/<%- '<' %>%= name %<%- '>' %><%- '<' %>%= dotSubtype %<%- '>' %>.spec.js
|
|
9
|
+
sh: |
|
|
10
|
+
if jq -e '.scripts["format:package"]' package.json <%- '>' %> /dev/null; then
|
|
11
|
+
npm run format:package 2<%- '>' %> /dev/null || true
|
|
12
|
+
fi
|
|
13
|
+
---
|
|
14
|
+
"test:spec<%- '<' %>%= colonSubspec %<%- '>' %>:<%- '<' %>%= name %<%- '>' %><%- '<' %>%= dotSubtype %<%- '>' %>": "vitest run ./<%- '<' %>%= path %<%- '>' %>/__tests__/<%- '<' %>%= name %<%- '>' %><%- '<' %>%= dotSubtype %<%- '>' %>.spec.js",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: <%= hygen %>/<%= generator %>/<%= action %>/new.ejs.t
|
|
3
|
+
---
|
|
4
|
+
---
|
|
5
|
+
to: <%- '<' %>%= path %<%- '>' %>/<%- '<' %>%= name %<%- '>' %><%- '<' %>%= dotSubtype %<%- '>' %>.js
|
|
6
|
+
---
|
|
7
|
+
//
|
|
8
|
+
//
|
|
9
|
+
// Constants
|
|
10
|
+
//
|
|
11
|
+
|
|
12
|
+
//
|
|
13
|
+
//
|
|
14
|
+
// Helper Functions
|
|
15
|
+
//
|
|
16
|
+
|
|
17
|
+
//
|
|
18
|
+
//
|
|
19
|
+
// Main
|
|
20
|
+
//
|
|
21
|
+
|
|
22
|
+
const <%- '<' %>%= name %<%- '>' %> = () =<%- '>' %> {
|
|
23
|
+
//
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
//
|
|
27
|
+
//
|
|
28
|
+
// Export
|
|
29
|
+
//
|
|
30
|
+
|
|
31
|
+
export default <%- '<' %>%= name %<%- '>' %>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// see types of prompts:
|
|
2
|
+
// https://github.com/enquirer/enquirer/tree/master/examples
|
|
3
|
+
//
|
|
4
|
+
module.exports = [
|
|
5
|
+
{
|
|
6
|
+
type: "input",
|
|
7
|
+
name: "actionInput",
|
|
8
|
+
message: "Action name (e.g., 'file'):",
|
|
9
|
+
onSubmit: (name, value, input) => {
|
|
10
|
+
// Remove leading './' and trailing '/'
|
|
11
|
+
value = value.replace(/^\.?\/|\/$/g, "");
|
|
12
|
+
input.state.answers.action = value;
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
type: "input",
|
|
17
|
+
name: "generatorInput",
|
|
18
|
+
initial: "project",
|
|
19
|
+
message: "Hygen generator directory (e.g., 'jaypie'):",
|
|
20
|
+
onSubmit: (name, value, input) => {
|
|
21
|
+
// Remove leading './' and trailing '/'
|
|
22
|
+
value = value.replace(/^\.?\/|\/$/g, "");
|
|
23
|
+
input.state.answers.generator = value;
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: "input",
|
|
28
|
+
name: "hygenInput",
|
|
29
|
+
initial: "_templates",
|
|
30
|
+
message: "Hygen template directory (always '_templates'):",
|
|
31
|
+
onSubmit: (name, value, input) => {
|
|
32
|
+
// Remove leading './' and trailing '/'
|
|
33
|
+
value = value.replace(/^\.?\/|\/$/g, "");
|
|
34
|
+
input.state.answers.hygen = value;
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: <%= hygen %>/<%= generator %>/<%= action %>/prompt.cjs
|
|
3
|
+
---
|
|
4
|
+
// see types of prompts:
|
|
5
|
+
// https://github.com/enquirer/enquirer/tree/master/examples
|
|
6
|
+
//
|
|
7
|
+
module.exports = [
|
|
8
|
+
{
|
|
9
|
+
type: "input",
|
|
10
|
+
name: "pathInput",
|
|
11
|
+
initial: "src/util",
|
|
12
|
+
message: "Path (e.g., 'cdk/lib'):",
|
|
13
|
+
onSubmit: (name, value, input) =<%- '>' %> {
|
|
14
|
+
input.state.answers.path = value;
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
type: "input",
|
|
19
|
+
name: "nameInput",
|
|
20
|
+
message: "File name (e.g., 'sum'):",
|
|
21
|
+
onSubmit: (name, value, input) =<%- '>' %> {
|
|
22
|
+
input.state.answers.name = value;
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
type: "input",
|
|
27
|
+
name: "subtypeInput",
|
|
28
|
+
message: "Subtype (optional; e.g., 'function'):",
|
|
29
|
+
onSubmit: (name, value, input) =<%- '>' %> {
|
|
30
|
+
input.state.answers.subtype = value;
|
|
31
|
+
input.state.answers.dotSubtype = value ? `.${value}` : "";
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: "input",
|
|
36
|
+
name: "subspecInput",
|
|
37
|
+
message:
|
|
38
|
+
"Sub-spec test, for `npm run test:spec:SUBSPEC:sum.function` command (e.g., 'express' or 'lib:project'):",
|
|
39
|
+
onSubmit: (name, value, input) =<%- '>' %> {
|
|
40
|
+
input.state.answers.subspec = value;
|
|
41
|
+
input.state.answers.colonSubspec = value ? `:${value}` : "";
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: <%= hygen %>/<%= generator %>/<%= action %>/test.ejs.t
|
|
3
|
+
---
|
|
4
|
+
---
|
|
5
|
+
to: <%- '<' %>%= path %<%- '>' %>/__tests__/<%- '<' %>%= name %<%- '>' %><%- '<' %>%= dotSubtype %<%- '>' %>.spec.js
|
|
6
|
+
---
|
|
7
|
+
// eslint-disable-next-line no-unused-vars
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
9
|
+
|
|
10
|
+
// Subject
|
|
11
|
+
import <%- '<' %>%= name %<%- '>' %> from "../<%- '<' %>%= name %<%- '>' %><%- '<' %>%= dotSubtype %<%- '>' %>.js";
|
|
12
|
+
|
|
13
|
+
//
|
|
14
|
+
//
|
|
15
|
+
// Mock constants
|
|
16
|
+
//
|
|
17
|
+
|
|
18
|
+
//
|
|
19
|
+
//
|
|
20
|
+
// Mock modules
|
|
21
|
+
//
|
|
22
|
+
|
|
23
|
+
//
|
|
24
|
+
//
|
|
25
|
+
// Mock environment
|
|
26
|
+
//
|
|
27
|
+
|
|
28
|
+
const DEFAULT_ENV = process.env;
|
|
29
|
+
beforeEach(() =<%- '>' %> {
|
|
30
|
+
process.env = { ...process.env };
|
|
31
|
+
});
|
|
32
|
+
afterEach(() =<%- '>' %> {
|
|
33
|
+
process.env = DEFAULT_ENV;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
//
|
|
37
|
+
//
|
|
38
|
+
// Run tests
|
|
39
|
+
//
|
|
40
|
+
|
|
41
|
+
<%- '<' %>%_
|
|
42
|
+
let Subtype = "";
|
|
43
|
+
// If subtype is defined, capitalize the first letter
|
|
44
|
+
if(subtype) Subtype = " " + subtype.charAt(0).toUpperCase() + subtype.slice(1);
|
|
45
|
+
_%<%- '>' %>
|
|
46
|
+
describe("<%- '<' %>%= Name %<%- '>' %><%- '<' %>%= Subtype %<%- '>' %>", () =<%- '>' %> {
|
|
47
|
+
it("Works", () =<%- '>' %> {
|
|
48
|
+
const response = <%- '<' %>%= name %<%- '>' %>();
|
|
49
|
+
console.log("response :<%- '>' %><%- '>' %> ", response);
|
|
50
|
+
expect(response).not.toBeUndefined();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: <%= path %>/<%= name %><%= dotSubtype %>.js
|
|
3
|
+
---
|
|
4
|
+
//
|
|
5
|
+
//
|
|
6
|
+
// Constants
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
//
|
|
10
|
+
//
|
|
11
|
+
// Helper Functions
|
|
12
|
+
//
|
|
13
|
+
|
|
14
|
+
//
|
|
15
|
+
//
|
|
16
|
+
// Main
|
|
17
|
+
//
|
|
18
|
+
|
|
19
|
+
const <%= name %> = () => {
|
|
20
|
+
//
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
//
|
|
24
|
+
//
|
|
25
|
+
// Export
|
|
26
|
+
//
|
|
27
|
+
|
|
28
|
+
export default <%= name %>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// see types of prompts:
|
|
2
|
+
// https://github.com/enquirer/enquirer/tree/master/examples
|
|
3
|
+
//
|
|
4
|
+
module.exports = [
|
|
5
|
+
{
|
|
6
|
+
type: "input",
|
|
7
|
+
name: "path",
|
|
8
|
+
initial: "src",
|
|
9
|
+
message: "Path (e.g., 'src/util' no leading './' or trailing '/'):",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
type: "input",
|
|
13
|
+
name: "name",
|
|
14
|
+
message: "File name (e.g., 'sum' not 'sum.function'):",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
type: "input",
|
|
18
|
+
name: "subtype",
|
|
19
|
+
message: "Subtype (optional; e.g., 'function'):",
|
|
20
|
+
onSubmit: (name, value, input) => {
|
|
21
|
+
// eslint-disable-next-line no-param-reassign
|
|
22
|
+
input.state.answers.dotSubtype = value ? `.${value}` : "";
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
type: "input",
|
|
27
|
+
name: "subspec",
|
|
28
|
+
message:
|
|
29
|
+
"Sub-spec test, for `npm run test:spec:SUBSPEC:sum.function` command (e.g., 'express'):",
|
|
30
|
+
onSubmit: (name, value, input) => {
|
|
31
|
+
// eslint-disable-next-line no-param-reassign
|
|
32
|
+
input.state.answers.colonSubspec = value ? `:${value}` : "";
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: <%= path %>/__tests__/<%= name %><%= dotSubtype %>.spec.js
|
|
3
|
+
---
|
|
4
|
+
// eslint-disable-next-line no-unused-vars
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
|
|
7
|
+
// Subject
|
|
8
|
+
import <%= name %> from "../<%= name %><%= dotSubtype %>.js";
|
|
9
|
+
|
|
10
|
+
//
|
|
11
|
+
//
|
|
12
|
+
// Mock constants
|
|
13
|
+
//
|
|
14
|
+
|
|
15
|
+
//
|
|
16
|
+
//
|
|
17
|
+
// Mock modules
|
|
18
|
+
//
|
|
19
|
+
|
|
20
|
+
//
|
|
21
|
+
//
|
|
22
|
+
// Mock environment
|
|
23
|
+
//
|
|
24
|
+
|
|
25
|
+
const DEFAULT_ENV = process.env;
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
process.env = { ...process.env };
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
process.env = DEFAULT_ENV;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
//
|
|
34
|
+
//
|
|
35
|
+
// Run tests
|
|
36
|
+
//
|
|
37
|
+
|
|
38
|
+
<%_
|
|
39
|
+
let Subtype = "";
|
|
40
|
+
// If subtype is defined, capitalize the first letter
|
|
41
|
+
if(subtype) Subtype = " " + subtype.charAt(0).toUpperCase() + subtype.slice(1);
|
|
42
|
+
_%>
|
|
43
|
+
describe("<%= Name %><%= Subtype %>", () => {
|
|
44
|
+
it("Works", () => {
|
|
45
|
+
const response = <%= name %>();
|
|
46
|
+
console.log("response :>> ", response);
|
|
47
|
+
expect(response).not.toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
inject: true
|
|
3
|
+
to: package.json
|
|
4
|
+
after: scripts
|
|
5
|
+
skip_if: spec<%= colonSubspec %>.+<%= path %>/__tests__/<%= name %><%= dotSubtype %>.spec.js
|
|
6
|
+
sh: |
|
|
7
|
+
if jq -e '.scripts["format:package"]' package.json > /dev/null; then
|
|
8
|
+
npm run format:package 2> /dev/null || true
|
|
9
|
+
fi
|
|
10
|
+
---
|
|
11
|
+
"test:spec<%= colonSubspec %>:<%= name %><%= dotSubtype %>": "vitest run ./<%= path %>/__tests__/<%= name %><%= dotSubtype %>.spec.js",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
inject: true
|
|
3
|
+
to: package.json
|
|
4
|
+
after: scripts
|
|
5
|
+
skip_if: spec<%= colonSubspec %>.+<%= path %>/__tests__/<%= name %><%= dotSubtype %>.spec.js
|
|
6
|
+
sh: |
|
|
7
|
+
if jq -e '.scripts["format:package"]' package.json > /dev/null; then
|
|
8
|
+
npm run format:package 2> /dev/null || true
|
|
9
|
+
fi
|
|
10
|
+
---
|
|
11
|
+
"test:spec<%= colonSubspec %>:<%= name %><%= dotSubtype %>": "vitest run ./<%= path %>/__tests__/<%= name %><%= dotSubtype %>.spec.js",
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// see types of prompts:
|
|
2
|
+
// https://github.com/enquirer/enquirer/tree/master/examples
|
|
3
|
+
//
|
|
4
|
+
module.exports = [
|
|
5
|
+
{
|
|
6
|
+
type: "input",
|
|
7
|
+
name: "pathInput",
|
|
8
|
+
initial: "src",
|
|
9
|
+
message: "Path (e.g., 'src/util'):",
|
|
10
|
+
onSubmit: (name, value, input) => {
|
|
11
|
+
input.state.answers.path = value;
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
type: "input",
|
|
16
|
+
name: "nameInput",
|
|
17
|
+
message: "File name (e.g., 'sum'):",
|
|
18
|
+
onSubmit: (name, value, input) => {
|
|
19
|
+
input.state.answers.name = value;
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
type: "input",
|
|
24
|
+
name: "subtypeInput",
|
|
25
|
+
message: "Subtype (optional; e.g., 'function'):",
|
|
26
|
+
onSubmit: (name, value, input) => {
|
|
27
|
+
input.state.answers.subtype = value;
|
|
28
|
+
input.state.answers.dotSubtype = value ? `.${value}` : "";
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
type: "input",
|
|
33
|
+
name: "subspecInput",
|
|
34
|
+
message:
|
|
35
|
+
"Sub-spec test, for `npm run test:spec:SUBSPEC:sum.function` command (e.g., 'express' or 'lib:project'):",
|
|
36
|
+
onSubmit: (name, value, input) => {
|
|
37
|
+
input.state.answers.subspec = value;
|
|
38
|
+
input.state.answers.colonSubspec = value ? `:${value}` : "";
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: <%= path %>/__tests__/<%= name %><%= dotSubtype %>.spec.js
|
|
3
|
+
---
|
|
4
|
+
// eslint-disable-next-line no-unused-vars
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
|
|
7
|
+
// Subject
|
|
8
|
+
import <%= name %> from "../<%= name %><%= dotSubtype %>.js";
|
|
9
|
+
|
|
10
|
+
//
|
|
11
|
+
//
|
|
12
|
+
// Mock constants
|
|
13
|
+
//
|
|
14
|
+
|
|
15
|
+
//
|
|
16
|
+
//
|
|
17
|
+
// Mock modules
|
|
18
|
+
//
|
|
19
|
+
|
|
20
|
+
//
|
|
21
|
+
//
|
|
22
|
+
// Mock environment
|
|
23
|
+
//
|
|
24
|
+
|
|
25
|
+
const DEFAULT_ENV = process.env;
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
process.env = { ...process.env };
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
process.env = DEFAULT_ENV;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
//
|
|
34
|
+
//
|
|
35
|
+
// Run tests
|
|
36
|
+
//
|
|
37
|
+
|
|
38
|
+
<%_
|
|
39
|
+
let Subtype = "";
|
|
40
|
+
// If subtype is defined, capitalize the first letter
|
|
41
|
+
if(subtype) Subtype = " " + subtype.charAt(0).toUpperCase() + subtype.slice(1);
|
|
42
|
+
_%>
|
|
43
|
+
describe("<%= Name %><%= Subtype %>", () => {
|
|
44
|
+
it("Works", () => {
|
|
45
|
+
const response = <%= name %>();
|
|
46
|
+
console.log("response :>> ", response);
|
|
47
|
+
expect(response).not.toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: <%= path %>/<%= name %>.yml
|
|
3
|
+
---
|
|
4
|
+
name: NPM Deploy
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags:
|
|
9
|
+
- v*
|
|
10
|
+
|
|
11
|
+
env:
|
|
12
|
+
PROJECT_ENV: meta
|
|
13
|
+
PROJECT_SERVICE: libraries
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
deploy:
|
|
17
|
+
name: NPM Deploy
|
|
18
|
+
permissions:
|
|
19
|
+
id-token: write # for aws-actions/configure-aws-credentials
|
|
20
|
+
contents: read # for actions/checkout
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout Code
|
|
24
|
+
uses: actions/checkout@v4
|
|
25
|
+
- name: NPM Install (`npm install`)
|
|
26
|
+
run: npm install
|
|
27
|
+
- name: NPM Deploy
|
|
28
|
+
run: |
|
|
29
|
+
npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
|
|
30
|
+
npm publish --access <%= access %>
|
|
31
|
+
lint:
|
|
32
|
+
name: Lint (in parallel)
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- name: Checkout code
|
|
36
|
+
uses: actions/checkout@v4
|
|
37
|
+
- name: Install dependencies
|
|
38
|
+
run: npm ci
|
|
39
|
+
- name: Run ESLint
|
|
40
|
+
run: npm run lint
|
|
41
|
+
# run: npx eslint . --max-warnings=0
|
|
42
|
+
test:
|
|
43
|
+
name: Unit Test (in parallel)
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
strategy:
|
|
46
|
+
matrix:
|
|
47
|
+
node-version: [18.x, 20.x]
|
|
48
|
+
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@v4
|
|
51
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
52
|
+
uses: actions/setup-node@v4
|
|
53
|
+
with:
|
|
54
|
+
node-version: ${{ matrix.node-version }}
|
|
55
|
+
cache: 'npm'
|
|
56
|
+
- run: npm ci
|
|
57
|
+
- run: |
|
|
58
|
+
npm test
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// see types of prompts:
|
|
2
|
+
// https://github.com/enquirer/enquirer/tree/master/examples
|
|
3
|
+
//
|
|
4
|
+
module.exports = [
|
|
5
|
+
{
|
|
6
|
+
type: "input",
|
|
7
|
+
name: "accessInput",
|
|
8
|
+
initial: "public",
|
|
9
|
+
message: "Access ('public' or 'restricted'):",
|
|
10
|
+
onSubmit: (name, value, input) => {
|
|
11
|
+
input.state.answers.access = value;
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
type: "input",
|
|
16
|
+
name: "pathInput",
|
|
17
|
+
initial: ".github/workflows",
|
|
18
|
+
message: "Path (always '.github/workflows'):",
|
|
19
|
+
onSubmit: (name, value, input) => {
|
|
20
|
+
input.state.answers.path = value;
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
type: "input",
|
|
25
|
+
name: "nameInput",
|
|
26
|
+
initial: "npm-deploy",
|
|
27
|
+
message: "File name, no extension (always 'npm-deploy'):",
|
|
28
|
+
onSubmit: (name, value, input) => {
|
|
29
|
+
input.state.answers.name = value;
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jaypie/testkit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"author": "Finlayson Studio",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"format": "npm run format:package && npm run format:lint",
|
|
9
|
+
"format:lint": "eslint --fix .",
|
|
10
|
+
"format:package": "sort-package-json ./package.json",
|
|
11
|
+
"init:deploy": "hygen jaypie workflow-npm",
|
|
12
|
+
"lint": "eslint .",
|
|
13
|
+
"new": "hygen jaypie vite",
|
|
14
|
+
"test": "vitest",
|
|
15
|
+
"test:spec:index": "vitest run ./src/__tests__/index.spec.js",
|
|
16
|
+
"test:spec:mockLog.module": "vitest run ./src/__tests__/mockLog.module.spec.js"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"eslint": "^8.57.0",
|
|
20
|
+
"eslint-config-prettier": "^9.1.0",
|
|
21
|
+
"eslint-plugin-import": "^2.29.1",
|
|
22
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
23
|
+
"eslint-plugin-vitest": "^0.3.26",
|
|
24
|
+
"hygen": "^6.2.11",
|
|
25
|
+
"jest-extended": "^4.0.2",
|
|
26
|
+
"prettier": "^3.2.5",
|
|
27
|
+
"sort-package-json": "^2.8.0",
|
|
28
|
+
"vitest": "^1.4.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
// Subject
|
|
4
|
+
import { mockLogFactory, restoreLog, spyLog } from "../index.js";
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
//
|
|
8
|
+
// Run tests
|
|
9
|
+
//
|
|
10
|
+
|
|
11
|
+
describe("Index", () => {
|
|
12
|
+
it("Exports functions", () => {
|
|
13
|
+
expect(mockLogFactory).toBeFunction();
|
|
14
|
+
expect(restoreLog).toBeFunction();
|
|
15
|
+
expect(spyLog).toBeFunction();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
// Subject
|
|
4
|
+
import { mockLogFactory, restoreLog, spyLog } from "../mockLog.module.js";
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
//
|
|
8
|
+
// Mock environment
|
|
9
|
+
//
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
vi.clearAllMocks();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
//
|
|
16
|
+
//
|
|
17
|
+
// Run tests
|
|
18
|
+
//
|
|
19
|
+
|
|
20
|
+
describe("Mock Log Function", () => {
|
|
21
|
+
it("Exports functions", () => {
|
|
22
|
+
expect(mockLogFactory).toBeFunction();
|
|
23
|
+
expect(restoreLog).toBeFunction();
|
|
24
|
+
expect(spyLog).toBeFunction();
|
|
25
|
+
});
|
|
26
|
+
describe("Features", () => {
|
|
27
|
+
it("mockLogFactory produces a Jaypie logger", () => {
|
|
28
|
+
const log = mockLogFactory();
|
|
29
|
+
expect(log).toBeObject();
|
|
30
|
+
expect(log.debug).toBeFunction();
|
|
31
|
+
expect(log.error).toBeFunction();
|
|
32
|
+
expect(log.fatal).toBeFunction();
|
|
33
|
+
expect(log.info).toBeFunction();
|
|
34
|
+
expect(log.tag).toBeFunction();
|
|
35
|
+
expect(log.trace).toBeFunction();
|
|
36
|
+
expect(log.untag).toBeFunction();
|
|
37
|
+
expect(log.var).toBeFunction();
|
|
38
|
+
expect(log.warn).toBeFunction();
|
|
39
|
+
expect(log.with).toBeFunction();
|
|
40
|
+
});
|
|
41
|
+
it("spyLog swaps out log functions", () => {
|
|
42
|
+
const log = mockLogFactory();
|
|
43
|
+
const original = { ...log };
|
|
44
|
+
spyLog(log);
|
|
45
|
+
expect(log).toBeObject();
|
|
46
|
+
expect(log.debug).toBeFunction();
|
|
47
|
+
expect(log.error).toBeFunction();
|
|
48
|
+
expect(log.fatal).toBeFunction();
|
|
49
|
+
expect(log.info).toBeFunction();
|
|
50
|
+
expect(log.tag).toBeFunction();
|
|
51
|
+
expect(log.trace).toBeFunction();
|
|
52
|
+
expect(log.untag).toBeFunction();
|
|
53
|
+
expect(log.var).toBeFunction();
|
|
54
|
+
expect(log.warn).toBeFunction();
|
|
55
|
+
expect(log.with).toBeFunction();
|
|
56
|
+
expect(log.debug).not.toEqual(original.debug);
|
|
57
|
+
expect(log.error).not.toEqual(original.error);
|
|
58
|
+
expect(log.fatal).not.toEqual(original.fatal);
|
|
59
|
+
expect(log.info).not.toEqual(original.info);
|
|
60
|
+
expect(log.tag).not.toEqual(original.tag);
|
|
61
|
+
expect(log.trace).not.toEqual(original.trace);
|
|
62
|
+
expect(log.untag).not.toEqual(original.untag);
|
|
63
|
+
expect(log.var).not.toEqual(original.var);
|
|
64
|
+
expect(log.warn).not.toEqual(original.warn);
|
|
65
|
+
expect(log.with).not.toEqual(original.with);
|
|
66
|
+
});
|
|
67
|
+
it("restoreLog swaps back original log functions", () => {
|
|
68
|
+
const log = mockLogFactory();
|
|
69
|
+
const original = { ...log };
|
|
70
|
+
spyLog(log);
|
|
71
|
+
restoreLog(log);
|
|
72
|
+
expect(log).toBeObject();
|
|
73
|
+
expect(log.debug).toBeFunction();
|
|
74
|
+
expect(log.error).toBeFunction();
|
|
75
|
+
expect(log.fatal).toBeFunction();
|
|
76
|
+
expect(log.info).toBeFunction();
|
|
77
|
+
expect(log.tag).toBeFunction();
|
|
78
|
+
expect(log.trace).toBeFunction();
|
|
79
|
+
expect(log.untag).toBeFunction();
|
|
80
|
+
expect(log.var).toBeFunction();
|
|
81
|
+
expect(log.warn).toBeFunction();
|
|
82
|
+
expect(log.with).toBeFunction();
|
|
83
|
+
expect(log.debug).toEqual(original.debug);
|
|
84
|
+
expect(log.error).toEqual(original.error);
|
|
85
|
+
expect(log.fatal).toEqual(original.fatal);
|
|
86
|
+
expect(log.info).toEqual(original.info);
|
|
87
|
+
expect(log.tag).toEqual(original.tag);
|
|
88
|
+
expect(log.trace).toEqual(original.trace);
|
|
89
|
+
expect(log.untag).toEqual(original.untag);
|
|
90
|
+
expect(log.var).toEqual(original.var);
|
|
91
|
+
expect(log.warn).toEqual(original.warn);
|
|
92
|
+
expect(log.with).toEqual(original.with);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
package/src/index.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
export function mockLogFactory() {
|
|
4
|
+
// Create skeleton of mock objects, as much as possible
|
|
5
|
+
const mock = {
|
|
6
|
+
debug: vi.fn(),
|
|
7
|
+
error: vi.fn(),
|
|
8
|
+
fatal: vi.fn(),
|
|
9
|
+
info: vi.fn(),
|
|
10
|
+
tag: vi.fn(),
|
|
11
|
+
trace: vi.fn(),
|
|
12
|
+
untag: vi.fn(),
|
|
13
|
+
var: vi.fn(),
|
|
14
|
+
warn: vi.fn(),
|
|
15
|
+
with: vi.fn(),
|
|
16
|
+
};
|
|
17
|
+
// Fill out nested mocks
|
|
18
|
+
mock.debug.var = mock.var;
|
|
19
|
+
mock.error.var = mock.var;
|
|
20
|
+
mock.fatal.var = mock.var;
|
|
21
|
+
mock.info.var = mock.var;
|
|
22
|
+
mock.trace.var = mock.var;
|
|
23
|
+
mock.warn.var = mock.var;
|
|
24
|
+
// Have modules return correct objects
|
|
25
|
+
mock.with.mockReturnValue(mock);
|
|
26
|
+
|
|
27
|
+
// Create something in the shape of the module
|
|
28
|
+
const module = {
|
|
29
|
+
debug: mock.debug,
|
|
30
|
+
error: mock.error,
|
|
31
|
+
fatal: mock.fatal,
|
|
32
|
+
info: mock.info,
|
|
33
|
+
tag: mock.tag,
|
|
34
|
+
trace: mock.trace,
|
|
35
|
+
untag: mock.untag,
|
|
36
|
+
var: mock.var,
|
|
37
|
+
warn: mock.warn,
|
|
38
|
+
with: mock.with,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Pin mocks to the module
|
|
42
|
+
module.mock = mock;
|
|
43
|
+
|
|
44
|
+
// return the module
|
|
45
|
+
return module;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// export default mockLogFactory();
|
|
49
|
+
|
|
50
|
+
const logMethodNames = [
|
|
51
|
+
"debug",
|
|
52
|
+
"error",
|
|
53
|
+
"fatal",
|
|
54
|
+
"info",
|
|
55
|
+
"tag",
|
|
56
|
+
"trace",
|
|
57
|
+
"untag",
|
|
58
|
+
"var",
|
|
59
|
+
"warn",
|
|
60
|
+
"with",
|
|
61
|
+
];
|
|
62
|
+
const originalLogMethods = new WeakMap();
|
|
63
|
+
|
|
64
|
+
export function spyLog(log) {
|
|
65
|
+
if (!originalLogMethods.has(log)) {
|
|
66
|
+
const mockLog = mockLogFactory();
|
|
67
|
+
const originalMethods = {};
|
|
68
|
+
logMethodNames.forEach((method) => {
|
|
69
|
+
originalMethods[method] = log[method];
|
|
70
|
+
log[method] = mockLog[method];
|
|
71
|
+
});
|
|
72
|
+
// Add custom properties
|
|
73
|
+
originalMethods.mock = log.mock;
|
|
74
|
+
log.mock = mockLog.mock;
|
|
75
|
+
|
|
76
|
+
originalLogMethods.set(log, originalMethods);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function restoreLog(log) {
|
|
81
|
+
const originalMethods = originalLogMethods.get(log);
|
|
82
|
+
if (originalMethods) {
|
|
83
|
+
logMethodNames.forEach((method) => {
|
|
84
|
+
log[method] = originalMethods[method];
|
|
85
|
+
});
|
|
86
|
+
// Restore custom properties
|
|
87
|
+
log.mock = originalMethods.mock;
|
|
88
|
+
|
|
89
|
+
originalLogMethods.delete(log);
|
|
90
|
+
}
|
|
91
|
+
}
|
package/testSetup.js
ADDED