jaypie 0.1.2 → 0.1.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.
@@ -14,6 +14,7 @@
14
14
  "oidc",
15
15
  "pinia",
16
16
  "roboto",
17
+ "testkit",
17
18
  "unplugin",
18
19
  "vendia",
19
20
  "vuekit",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaypie",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "author": "Finlayson Studio",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -20,6 +20,7 @@
20
20
  "@jaypie/core": "^0.4.0"
21
21
  },
22
22
  "devDependencies": {
23
+ "@jaypie/testkit": "^1.0.0",
23
24
  "eslint": "^8.57.0",
24
25
  "eslint-config-prettier": "^9.1.0",
25
26
  "eslint-plugin-import": "^2.29.1",
@@ -44,67 +44,109 @@ describe("Dynamic Export Function", () => {
44
44
  expect(dynamicExport).toBeFunction();
45
45
  });
46
46
  describe("Error Handling", () => {
47
- it("Throws if exports is not an array", () => {
48
- expect(() => dynamicExport({ exports: "string" })).toThrow();
47
+ it("Throws if functions is not an array", async () => {
48
+ try {
49
+ await dynamicExport({ functions: "default" });
50
+ } catch (error) {
51
+ expect(error).toBeJaypieError();
52
+ }
53
+ expect.assertions(1);
49
54
  });
50
- it("Throws if exports is an empty array", () => {
51
- expect(() => dynamicExport({ exports: [] })).toThrow();
55
+ it("Throws if functions is an empty array", async () => {
56
+ try {
57
+ await dynamicExport({ functions: [] });
58
+ } catch (error) {
59
+ expect(error).toBeJaypieError();
60
+ }
61
+ expect.assertions(1);
52
62
  });
53
- it("Throws if moduleImport is not a string", () => {
54
- expect(() => dynamicExport({ moduleImport: 123 })).toThrow();
63
+ it("Throws if moduleImport is not a string", async () => {
64
+ try {
65
+ await dynamicExport({ moduleImport: 12 });
66
+ } catch (error) {
67
+ expect(error).toBeJaypieError();
68
+ }
69
+ expect.assertions(1);
55
70
  });
56
71
  });
57
72
  describe("Happy Path", () => {
58
73
  it("Returns an object", () => {
59
74
  expect(dynamicExport({ moduleImport: MOCK.MODULE })).toBeObject();
60
75
  });
61
- it("Returns an object with the exports", () => {
62
- const exports = ["default", "named"];
63
- const result = dynamicExport({ exports, moduleImport: MOCK.MODULE });
64
- expect(result).toContainKeys(exports);
65
- });
66
- it("Returns an object with the exports as functions", () => {
67
- const exports = ["default", "named"];
68
- const result = dynamicExport({ exports, moduleImport: MOCK.MODULE });
69
- expect(result.default).toBeFunction();
70
- expect(result.named).toBeFunction();
76
+ it("Scalars are undefined when module is not found", async () => {
77
+ const vars = ["scalar"];
78
+ const result = await dynamicExport({
79
+ vars,
80
+ moduleImport: MOCK.MODULE,
81
+ });
82
+ expect(result.scalar).toBeUndefined();
71
83
  });
72
84
  it("Exported functions throw if the real module is not installed", async () => {
73
- const exports = ["default"];
74
- const result = dynamicExport({ exports, moduleImport: MOCK.MODULE });
75
- await expect(result.default()).rejects.toThrow();
85
+ const functions = ["default"];
86
+ const result = await dynamicExport({
87
+ functions,
88
+ moduleImport: MOCK.MODULE,
89
+ });
90
+ await expect(result.default).toThrow();
76
91
  });
77
92
  });
78
93
  describe("Features", () => {
79
94
  const mockDefaultFunction = vi.fn();
80
95
  const mockNamedFunction = vi.fn();
81
- const mockScalar = "scalar";
96
+ const mockVarName = "scalar";
97
+ const mockVarValue = "value";
82
98
  beforeAll(() => {
83
99
  vi.doMock(MOCK.MODULE, () => {
84
100
  return {
85
101
  default: mockDefaultFunction,
86
102
  named: mockNamedFunction,
87
- scalar: mockScalar,
103
+ [mockVarName]: mockVarValue,
88
104
  };
89
105
  });
90
106
  });
91
107
  it("Calls the default function", async () => {
92
- const exports = ["default", "named"];
93
- const result = dynamicExport({ exports, moduleImport: MOCK.MODULE });
108
+ const functions = ["default", "named"];
109
+ const result = await dynamicExport({
110
+ functions,
111
+ moduleImport: MOCK.MODULE,
112
+ });
94
113
  await result.default();
95
114
  expect(mockDefaultFunction).toHaveBeenCalled();
96
115
  });
97
116
  it("Calls the named function", async () => {
98
- const exports = ["default", "named"];
99
- const result = dynamicExport({ exports, moduleImport: MOCK.MODULE });
117
+ const functions = ["default", "named"];
118
+ const result = await dynamicExport({
119
+ functions,
120
+ moduleImport: MOCK.MODULE,
121
+ });
100
122
  await result.named();
101
123
  expect(mockNamedFunction).toHaveBeenCalled();
102
124
  });
103
- it.todo("Returns the scalar", async () => {
104
- const exports = ["scalar"];
105
- const result = dynamicExport({ exports, moduleImport: MOCK.MODULE });
106
- expect(result.scalar).not.toBeFunction();
107
- expect(result.scalar).toBe(mockScalar);
125
+ it("Returns the scalar", async () => {
126
+ const vars = [mockVarName];
127
+ const result = await dynamicExport({
128
+ vars,
129
+ moduleImport: MOCK.MODULE,
130
+ });
131
+ expect(result[mockVarName]).not.toBeFunction();
132
+ expect(result[mockVarName]).toBe(mockVarValue);
133
+ });
134
+ it("Returns an object with the functions", async () => {
135
+ const functions = ["default", "named"];
136
+ const result = await dynamicExport({
137
+ functions,
138
+ moduleImport: MOCK.MODULE,
139
+ });
140
+ expect(result).toContainKeys(functions);
141
+ });
142
+ it("Returns an object with the functions as functions", async () => {
143
+ const functions = ["default", "named"];
144
+ const result = await dynamicExport({
145
+ functions,
146
+ moduleImport: MOCK.MODULE,
147
+ });
148
+ expect(result.default).toBeFunction();
149
+ expect(result.named).toBeFunction();
108
150
  });
109
151
  });
110
152
  });
@@ -9,7 +9,7 @@ import {
9
9
  } from "vitest";
10
10
 
11
11
  // Subject
12
- import { connectFromSecretEnv, disconnect } from "../mongoose.package.js";
12
+ // * Subject is imported dynamically to allow `vi.resetModules()` to apply different mocks
13
13
 
14
14
  //
15
15
  //
@@ -41,6 +41,16 @@ afterEach(() => {
41
41
  //
42
42
 
43
43
  describe("Mongoose Package", () => {
44
+ let connectFromSecretEnv;
45
+ let disconnect;
46
+ beforeAll(async () => {
47
+ const {
48
+ connectFromSecretEnv: _connectFromSecretEnv,
49
+ disconnect: _disconnect,
50
+ } = await import("../mongoose.package.js");
51
+ connectFromSecretEnv = _connectFromSecretEnv;
52
+ disconnect = _disconnect;
53
+ });
44
54
  it("Works", () => {
45
55
  expect(connectFromSecretEnv).toBeFunction();
46
56
  expect(disconnect).toBeFunction();
@@ -58,7 +68,8 @@ describe("Mongoose Package", () => {
58
68
  describe("Features", () => {
59
69
  const mockConnectFromSecretEnv = vi.fn();
60
70
  const mockDisconnect = vi.fn();
61
- beforeAll(() => {
71
+ beforeAll(async () => {
72
+ // Setup mock of mongoose
62
73
  vi.doMock("@jaypie/mongoose", () => {
63
74
  return {
64
75
  connectFromSecretEnv: mockConnectFromSecretEnv,
@@ -68,6 +79,15 @@ describe("Mongoose Package", () => {
68
79
  },
69
80
  };
70
81
  });
82
+ // Preprocess
83
+ vi.resetModules();
84
+ const {
85
+ connectFromSecretEnv: _connectFromSecretEnv,
86
+ disconnect: _disconnect,
87
+ } = await import("../mongoose.package.js");
88
+ // Return
89
+ connectFromSecretEnv = _connectFromSecretEnv;
90
+ disconnect = _disconnect;
71
91
  });
72
92
  it("Calls @jaypie/mongoose for connectFromSecretEnv", async () => {
73
93
  await connectFromSecretEnv();
@@ -6,7 +6,7 @@ import dynamicExport from "./dynamicExport.function.js";
6
6
  // Export
7
7
  //
8
8
 
9
- export const { getSecret } = dynamicExport({
10
- exports: ["getSecret"],
9
+ export const { getSecret } = await dynamicExport({
10
+ functions: ["getSecret"],
11
11
  moduleImport: JAYPIE.LIB.AWS,
12
12
  });
@@ -36,20 +36,57 @@ async function dynamicImport(module) {
36
36
  // Main
37
37
  //
38
38
 
39
- export default ({ exports = ["default"], moduleImport } = {}) => {
39
+ export default async ({
40
+ functions = ["default"],
41
+ moduleImport,
42
+ vars = [],
43
+ } = {}) => {
40
44
  // Validate
41
- if (Array.isArray(exports) && !exports.length) {
42
- throw new ConfigurationError();
43
- }
44
45
  if (!moduleImport || typeof moduleImport !== "string") {
45
- throw new ConfigurationError();
46
+ throw new ConfigurationError("`moduleImport` must be a string");
47
+ }
48
+ if (!Array.isArray(functions)) {
49
+ throw new ConfigurationError("`functions` must be an array");
50
+ }
51
+ if (!Array.isArray(vars)) {
52
+ throw new ConfigurationError("`vars` must be an array");
53
+ }
54
+ if (!functions.length && !vars.length) {
55
+ throw new ConfigurationError(
56
+ "Either `functions` or `vars` must be provided",
57
+ );
46
58
  }
47
59
  // Setup
48
- return exports.reduce((acc, key) => {
49
- acc[key] = async () => {
50
- const imported = await dynamicImport(moduleImport);
51
- return await imported[key]();
52
- };
53
- return acc;
54
- }, {});
60
+ let imported;
61
+ const returning = {};
62
+ // Preprocess
63
+ try {
64
+ imported = await dynamicImport(moduleImport);
65
+ } catch (error) {
66
+ moduleLogger.trace(
67
+ `[jaypie] ${moduleImport} could not be imported; continuing`,
68
+ );
69
+ }
70
+ // Process
71
+ for (const key of functions) {
72
+ if (imported) {
73
+ returning[key] = imported[key];
74
+ } else {
75
+ returning[key] = () => {
76
+ throw new ConfigurationError(
77
+ `Function ${key} cannot be called because ${moduleImport} is not installed`,
78
+ );
79
+ };
80
+ }
81
+ }
82
+ for (const key of vars) {
83
+ if (imported) {
84
+ returning[key] = imported[key];
85
+ } else {
86
+ // TODO: make the not found vars throw only _when accessed_
87
+ returning[key] = undefined;
88
+ }
89
+ }
90
+ // Return
91
+ return returning;
55
92
  };
package/src/index.js CHANGED
@@ -3,8 +3,10 @@
3
3
  // Export
4
4
  //
5
5
 
6
+ // Required dependencies
6
7
  export * from "@jaypie/core";
7
8
 
9
+ // Optional dependencies are wrapped in a dynamic import
8
10
  export * from "./aws.package.js";
9
11
  export * from "./lambda.package.js";
10
12
  export * from "./mongoose.package.js";
@@ -6,7 +6,7 @@ import dynamicExport from "./dynamicExport.function.js";
6
6
  // Export
7
7
  //
8
8
 
9
- export const { lambdaHandler } = dynamicExport({
10
- exports: ["lambdaHandler"],
9
+ export const { lambdaHandler } = await dynamicExport({
10
+ functions: ["lambdaHandler"],
11
11
  moduleImport: JAYPIE.LIB.LAMBDA,
12
12
  });
@@ -6,7 +6,7 @@ import dynamicExport from "./dynamicExport.function.js";
6
6
  // Export
7
7
  //
8
8
 
9
- export const { connectFromSecretEnv, disconnect } = dynamicExport({
10
- exports: ["connectFromSecretEnv", "disconnect"],
9
+ export const { connectFromSecretEnv, disconnect } = await dynamicExport({
10
+ functions: ["connectFromSecretEnv", "disconnect"],
11
11
  moduleImport: JAYPIE.LIB.MONGOOSE,
12
12
  });
package/testSetup.js CHANGED
@@ -1,3 +1,6 @@
1
+ import { matchers as jaypieMatchers } from "@jaypie/testkit";
2
+ import * as extendedMatchers from "jest-extended";
1
3
  import { expect } from "vitest";
2
- import * as matchers from "jest-extended";
3
- expect.extend(matchers);
4
+
5
+ expect.extend(extendedMatchers);
6
+ expect.extend(jaypieMatchers);