Skip to content

Commit 02c3cb4

Browse files
committed
better error handling when loading tasks using esm
1 parent d2aaac4 commit 02c3cb4

File tree

6 files changed

+69
-10
lines changed

6 files changed

+69
-10
lines changed

.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[*]
2+
indent_size = 2
3+
indent_style = space

.mocharc.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"require": ["./env.js"],
33
"extension": ["ts"],
4-
"recursive": true
4+
"recursive": true,
5+
"node-option": [
6+
"experimental-specifier-resolution=node",
7+
"loader=ts-node/esm"
8+
]
59
}

src/asyncAssignTasks.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ export default async function asyncAssignTasks<T>(thisObj: T, tasksDir: string):
1717

1818
async function loadTask(name: string) {
1919
const path = `${tasksDir}/${name}`
20-
try {
21-
// Typescript has issues with dynamic imports, even though node supports them
22-
// for both commonjs and esmodules. see: https://github.com/microsoft/TypeScript/issues/43329
23-
const task = await Function(`return import("${path}")`)()
24-
return task[name]
25-
} catch (err) {
26-
return () => {
27-
throw new Error(`No task in: ${path}.{ts,js,tsx,jsx}`)
28-
}
20+
// Typescript has issues with dynamic imports, even though node supports them
21+
// for both commonjs and esmodules. see: https://github.com/microsoft/TypeScript/issues/43329
22+
const task = await Function(`return import("${path}")`)()
23+
24+
// if typescript is using commonjs modules
25+
if (task.default) {
26+
return task.default[name]
2927
}
28+
29+
// if typescript is using es modules
30+
return task[name]
3031
}
3132
}

test/asyncTasks.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import assert = require('assert')
2+
import { Action, ActorWorld } from '../src'
3+
import type { IActorWorldOptions } from '../src/ActorWorld'
4+
import asyncAssignTasks from '../src/asyncAssignTasks'
5+
6+
describe(asyncAssignTasks.name, () => {
7+
const options: IActorWorldOptions = { parameters: {} } as IActorWorldOptions
8+
9+
// success
10+
it('successfully loads a task', async () => {
11+
class TestWorld extends ActorWorld {
12+
public goodtask: () => Action<void>
13+
}
14+
15+
const world = new TestWorld(options)
16+
17+
// Load the task
18+
await asyncAssignTasks(world, `${__dirname}/fixtures/tasks/goodtasks`)
19+
20+
// Execute the task
21+
world.goodtask()
22+
})
23+
24+
// error compiling
25+
it('fails with a helpful error message if the task could not be compiled', async () => {
26+
class TestWorld extends ActorWorld {
27+
public brokentask: () => Action<void>
28+
}
29+
30+
const world = new TestWorld(options)
31+
32+
// Try to load the task
33+
await assert.rejects(asyncAssignTasks(world, `${__dirname}/fixtures/tasks/brokentask`), {
34+
name: 'TSError',
35+
message: /Cannot find module '\.\/src'/,
36+
})
37+
})
38+
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// this import will fail
2+
import { type Action } from './src'
3+
4+
export const badtask = (): Action => {
5+
// eslint-disable-next-line @typescript-eslint/no-empty-function
6+
return () => {}
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { type Action } from '../../../../src'
2+
3+
export const goodtask = (): Action<void> => {
4+
// eslint-disable-next-line @typescript-eslint/no-empty-function
5+
return () => {}
6+
}

0 commit comments

Comments
 (0)