Skip to content
This repository has been archived by the owner on Apr 24, 2023. It is now read-only.

Commit

Permalink
Enforce Function File Contract earlier (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamBergamin authored Feb 2, 2023
1 parent daf2b41 commit 1f79e7a
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 8 deletions.
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ _**Note:** The examples below use version `0.1.0` of `deno-slack-builder`; check

In a directory that contains a valid manifest file (`manifest.json`, `manifest.js`, or `manifest.ts`), run the following:

```
```bash
deno run --allow-write --allow-read "https://deno.land/x/[email protected]/mod.ts"
```

Expand All @@ -31,12 +31,14 @@ The top level `mod.ts` file is executed as a Deno program, and takes up to three
### Example Usage

**Only generate a valid Run On Slack manifest file:**
```

```bash
deno run --allow-write --allow-read "https://deno.land/x/[email protected]/mod.ts" --manifest
```

**Generate a Run On Slack project from a /src directory:**
```

```bash
deno run --allow-write --allow-read "https://deno.land/x/[email protected]/mod.ts" --source src
```

Expand All @@ -55,6 +57,7 @@ Allows for flexibility with how you define your manifest.
* If no `manifest.ts` exists, looks for a `manifest.js` file, and follows the same logic as `manifest.ts` does.

## Function Bundling

* For each entry in the `functions` where `remote_environment=slack` it looks for a `source_file` property, which should be a relative path to the corresponding function file. This is then bundled for the Run on Slack Deno runtime. The `reverse` function defined below indicates there should be a corresponding function file in the project located at `functions/reverse.ts`.

```json
Expand Down Expand Up @@ -89,11 +92,15 @@ Allows for flexibility with how you define your manifest.

If you make changes to this repo, or just want to make sure things are working as desired, you can run:

deno task test
```bash
deno task test
```

To get a full test coverage report, run:

deno task coverage
```bash
deno task coverage
```

---

Expand Down
4 changes: 2 additions & 2 deletions deno.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
}
},
"tasks": {
"test": "deno fmt --check && deno lint && deno test src",
"coverage": "deno test --coverage=.coverage src && deno coverage --exclude=fixtures --exclude=test .coverage"
"test": "deno fmt --check && deno lint && deno test --allow-read src",
"coverage": "deno test --coverage=.coverage --allow-read src && deno coverage --exclude=fixtures --exclude=test .coverage"
}
}
1 change: 1 addition & 0 deletions src/dev_deps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export {
assertEquals,
assertExists,
assertRejects,
} from "https://deno.land/[email protected]/testing/asserts.ts";
15 changes: 15 additions & 0 deletions src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ export const validateAndCreateFunctions = async (
}
};

const functionPathHasDefaultExport = async (
functionFilePath: string,
) => {
const functionModule = await import(`file://${functionFilePath}`);
return functionModule.default
? typeof functionModule.default == "function"
: false;
};

const getValidFunctionPath = async (
options: Options,
fnId: string,
Expand Down Expand Up @@ -70,6 +79,12 @@ const getValidFunctionPath = async (
}
throw new Error(e);
}

if (!await functionPathHasDefaultExport(fnFilePath)) {
throw new Error(
`File: ${fnFilePath}, containing your function does not define a default export handler.`,
);
}
return fnFilePath;
};

Expand Down
3 changes: 3 additions & 0 deletions src/tests/functions/test_function_file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default () => {
console.log("this is my slack function");
};
3 changes: 3 additions & 0 deletions src/tests/functions/test_function_no_export_file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const func = () => {
console.log("this is my slack function");
};
1 change: 1 addition & 0 deletions src/tests/functions/test_function_not_function_file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default "hello";
103 changes: 102 additions & 1 deletion src/tests/functions_test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,107 @@
import { validateAndCreateFunctions } from "../functions.ts";
import { assertExists } from "../dev_deps.ts";
import { assertEquals, assertExists, assertRejects } from "../dev_deps.ts";
import { Options } from "../types.ts";

Deno.test("validateAndCreateFunctions", () => {
assertExists(validateAndCreateFunctions);
});

Deno.test("validateAndCreateFunctions should not throw an exception when fed a function file that has a default export", async () => {
const captured_log: string[] = [];
const options: Options = {
manifestOnly: true,
workingDirectory: Deno.cwd(),
log: (x) => {
captured_log.push(x);
},
};
const manifest = {
"functions": {
"test_function": {
"title": "Test function",
"description": "this is a test",
"source_file": "src/tests/functions/test_function_file.ts",
"input_parameters": {
"required": [],
"properties": {},
},
"output_parameters": {
"required": [],
"properties": {},
},
},
},
};

await validateAndCreateFunctions(
options,
manifest,
);
assertEquals("", captured_log.join(""));
});

Deno.test("Function files with no default export should get an error", async () => {
const captured_log: string[] = [];
const options: Options = {
manifestOnly: true,
workingDirectory: Deno.cwd(),
log: (x) => {
captured_log.push(x);
},
};
const manifest = {
"functions": {
"test_function": {
"title": "Test function",
"description": "this is a test",
"source_file": "src/tests/functions/test_function_no_export_file.ts",
"input_parameters": {
"required": [],
"properties": {},
},
"output_parameters": {
"required": [],
"properties": {},
},
},
},
};
await assertRejects(
() => validateAndCreateFunctions(options, manifest),
Error,
"default export handler",
);
});

Deno.test("Function files not exporting a function should get an error", async () => {
const captured_log: string[] = [];
const options: Options = {
manifestOnly: true,
workingDirectory: Deno.cwd(),
log: (x) => {
captured_log.push(x);
},
};
const manifest = {
"functions": {
"test_function": {
"title": "Test function",
"description": "this is a test",
"source_file": "src/tests/functions/test_function_not_function_file.ts",
"input_parameters": {
"required": [],
"properties": {},
},
"output_parameters": {
"required": [],
"properties": {},
},
},
},
};
await assertRejects(
() => validateAndCreateFunctions(options, manifest),
Error,
"default export handler",
);
});

0 comments on commit 1f79e7a

Please sign in to comment.