puty 0.1.1 → 0.1.2

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.
Files changed (3) hide show
  1. package/README.md +35 -6
  2. package/package.json +1 -1
  3. package/src/puty.js +21 -15
package/README.md CHANGED
@@ -11,6 +11,7 @@ Puty is ideal for testing pure functions - functions that always return the same
11
11
  - [Quick Start](#quick-start)
12
12
  - [Usage](#usage)
13
13
  - [Testing Functions](#testing-functions)
14
+ - [Async Functions and Methods](#async-functions-and-methods)
14
15
  - [Testing Classes](#testing-classes)
15
16
  - [Testing Factory Functions](#testing-factory-functions)
16
17
  - [Error Testing](#error-testing)
@@ -25,6 +26,7 @@ Puty is ideal for testing pure functions - functions that always return the same
25
26
  - 📦 Modular test organization with `!include` directive
26
27
  - 🎯 Clear separation of test data and test logic
27
28
  - 🧪 Mock support for testing functions with dependencies
29
+ - ⏳ Async support for functions, class methods, and factory method executions
28
30
  - ⚡ Powered by Vitest for fast test execution
29
31
 
30
32
  ## Installation
@@ -199,6 +201,32 @@ describe('math', () => {
199
201
 
200
202
  See the [YAML Structure](#yaml-structure) section for detailed documentation of all available fields.
201
203
 
204
+ ### Async Functions and Methods
205
+
206
+ Puty supports async functions and async method executions using the same YAML fields:
207
+
208
+ - `out` asserts the resolved return value
209
+ - `throws` asserts either a thrown error or a rejected promise
210
+
211
+ Example:
212
+
213
+ ```yaml
214
+ file: './async.js'
215
+ group: async
216
+ ---
217
+ suite: fetchUser
218
+ exportName: fetchUser
219
+ ---
220
+ case: resolves user
221
+ in: [1]
222
+ out:
223
+ id: 1
224
+ ---
225
+ case: rejects for missing user
226
+ in: [999]
227
+ throws: 'not found'
228
+ ```
229
+
202
230
  ### Testing Classes
203
231
 
204
232
  Puty also supports testing classes with method calls and state assertions:
@@ -334,7 +362,9 @@ The `__undefined__` keyword works in:
334
362
 
335
363
  ### Error Testing
336
364
 
337
- You can test that functions or methods throw expected errors:
365
+ You can test that functions or methods fail with expected errors:
366
+ - Sync functions/methods: thrown errors are supported
367
+ - Async functions/methods: rejected promises are supported
338
368
 
339
369
  ```yaml
340
370
  case: divide by zero
@@ -510,8 +540,8 @@ For function tests:
510
540
  ```yaml
511
541
  case: 'test description' # Required: Test case name
512
542
  in: [arg1, arg2] # Required: Input arguments (use $mock:name for mocks)
513
- out: expectedValue # Optional: Expected output (omit if testing for errors)
514
- throws: 'Error message' # Optional: Expected error message
543
+ out: expectedValue # Optional: Expected output (resolved value for async functions)
544
+ throws: 'Error message' # Optional: Expected error message (sync throw or async rejection)
515
545
  mocks: # Optional: Case-specific mocks
516
546
  mockName:
517
547
  calls: # Array of expected calls
@@ -526,8 +556,8 @@ case: 'test description'
526
556
  executions:
527
557
  - method: 'methodName' # Supports nested: 'user.api.getData'
528
558
  in: [arg1]
529
- out: expectedValue # Optional
530
- throws: 'Error msg' # Optional
559
+ out: expectedValue # Optional (resolved value for async methods)
560
+ throws: 'Error msg' # Optional (sync throw or async rejection)
531
561
  asserts:
532
562
  - property: 'prop' # Supports nested: 'user.profile.name'
533
563
  op: 'eq' # Currently only 'eq' is supported
@@ -563,4 +593,3 @@ executions:
563
593
  in: ['/users/123']
564
594
  out: 'GET /users/123'
565
595
  ```
566
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "puty",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "A tooling function to test javascript functions and classes.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/puty.js CHANGED
@@ -245,18 +245,20 @@ const setupFunctionTests = (suite) => {
245
245
  mockFunctions,
246
246
  executions,
247
247
  } = testCase;
248
- test(name, () => {
248
+ test(name, async () => {
249
249
  if (!functionUnderTest) {
250
250
  throw new Error(`Function not found for test case: ${name}`);
251
251
  }
252
252
 
253
253
  try {
254
254
  if (throws) {
255
- // Test expects an error to be thrown
256
- expect(() => functionUnderTest(...(inArg || []))).toThrow(throws);
255
+ // Supports both sync throws and async rejections
256
+ await expect(
257
+ Promise.resolve().then(() => functionUnderTest(...(inArg || []))),
258
+ ).rejects.toThrow(throws);
257
259
  } else {
258
260
  // Call the function
259
- const result = functionUnderTest(...(inArg || []));
261
+ const result = await functionUnderTest(...(inArg || []));
260
262
 
261
263
  // Assert return value if 'out' field is present in the test case
262
264
  if ("out" in testCase) {
@@ -276,11 +278,13 @@ const setupFunctionTests = (suite) => {
276
278
  } = execution;
277
279
 
278
280
  if (execThrows) {
279
- expect(() =>
280
- callNestedMethod(result, method, execInArg || []),
281
- ).toThrow(execThrows);
281
+ await expect(
282
+ Promise.resolve().then(() =>
283
+ callNestedMethod(result, method, execInArg || []),
284
+ ),
285
+ ).rejects.toThrow(execThrows);
282
286
  } else {
283
- const methodResult = callNestedMethod(
287
+ const methodResult = await callNestedMethod(
284
288
  result,
285
289
  method,
286
290
  execInArg || [],
@@ -304,7 +308,7 @@ const setupFunctionTests = (suite) => {
304
308
  expect(actualValue).toEqual(processedValue);
305
309
  }
306
310
  } else if (assertion.method) {
307
- const assertResult = callNestedMethod(
311
+ const assertResult = await callNestedMethod(
308
312
  result,
309
313
  assertion.method,
310
314
  assertion.in || [],
@@ -347,7 +351,7 @@ const setupClassTests = (suite) => {
347
351
  const { cases, ClassUnderTest, constructorArgs } = suite;
348
352
  for (const testCase of cases) {
349
353
  const { name, executions, mockFunctions } = testCase;
350
- test(name, () => {
354
+ test(name, async () => {
351
355
  if (!ClassUnderTest) {
352
356
  throw new Error(`Class not found for test suite: ${suite.name}`);
353
357
  }
@@ -366,11 +370,13 @@ const setupClassTests = (suite) => {
366
370
 
367
371
  // Execute the method and check its return value - supports nested methods
368
372
  if (throws) {
369
- expect(() =>
370
- callNestedMethod(instance, method, inArg || []),
371
- ).toThrow(throws);
373
+ await expect(
374
+ Promise.resolve().then(() =>
375
+ callNestedMethod(instance, method, inArg || []),
376
+ ),
377
+ ).rejects.toThrow(throws);
372
378
  } else {
373
- const result = callNestedMethod(instance, method, inArg || []);
379
+ const result = await callNestedMethod(instance, method, inArg || []);
374
380
  if (expectedOut !== undefined) {
375
381
  const processedExpectedOut = processUndefined(expectedOut);
376
382
  expect(result).toEqual(processedExpectedOut);
@@ -393,7 +399,7 @@ const setupClassTests = (suite) => {
393
399
  // Add more operators as needed
394
400
  } else if (assertion.method) {
395
401
  // Method assertion - supports nested methods like "user.api.getData"
396
- const result = callNestedMethod(
402
+ const result = await callNestedMethod(
397
403
  instance,
398
404
  assertion.method,
399
405
  assertion.in || [],