From 120bb9ed1a12f6daea5c15f83f44b61d0be1a667 Mon Sep 17 00:00:00 2001 From: Pete Nicholls Date: Wed, 3 Apr 2024 10:29:46 +1300 Subject: [PATCH] Add examples (and run them in CI) --- README.md | 18 ++++++++---- examples/app-metadata.js | 10 +++++++ examples/app-metadata.test.js | 53 +++++++++++++++++++++++++++++++++++ package.json | 4 ++- tsconfig.json | 19 +++++++------ 5 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 examples/app-metadata.js create mode 100644 examples/app-metadata.test.js diff --git a/README.md b/README.md index 09008c0..417fdf8 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,12 @@ exports.onExecutePostLogin = async (event, api) => { } ``` -Here's how you can test it: +There are two scenarios to test: +1. When the metadata hasn't been set, we should generate a new lucky number +2. When the metadata has been set previously, we should leave the lucky number intact + +Here's how we can test them: ```js const test = require("node:test"); @@ -81,8 +85,9 @@ test("onExecutePostLogin", async (t) => { }), }); - const { user } = await action.simulate(onExecutePostLogin); - const { lucky_number } = user.app_metadata; + await action.simulate(onExecutePostLogin); + + const { lucky_number } = action.user.app_metadata; ok( typeof lucky_number === 'number', @@ -103,8 +108,9 @@ test("onExecutePostLogin", async (t) => { }), }); - const { user } = await action.simulate(onExecutePostLogin); - const { lucky_number } = user.app_metadata; + await action.simulate(onExecutePostLogin); + + const { lucky_number } = action.user.app_metadata; strictEqual( lucky_number, 17, `Expected the user's lucky number to be unchanged` @@ -120,6 +126,8 @@ Run this test with: node --test ``` +For more examples, see [the examples directory](examples). + ## Working with `a0deploy` While you can copy and paste Actions by hand, we recommend exporting and importing Actions with Auth0's [`a0deploy`](https://auth0.com/docs/deploy-monitor/deploy-cli-tool) command-line interface. diff --git a/examples/app-metadata.js b/examples/app-metadata.js new file mode 100644 index 0000000..5662797 --- /dev/null +++ b/examples/app-metadata.js @@ -0,0 +1,10 @@ +exports.onExecutePostLogin = async (event, api) => { + if (event.user.app_metadata["lucky_number"]) { + // Do nothing. User already has a lucky number. + return; + } + + const diceRoll = Math.round(Math.random() * event.secrets.MAX_LUCKY_NUMBER); + + api.user.setAppMetadata("lucky_number", diceRoll); +}; diff --git a/examples/app-metadata.test.js b/examples/app-metadata.test.js new file mode 100644 index 0000000..ab69b79 --- /dev/null +++ b/examples/app-metadata.test.js @@ -0,0 +1,53 @@ +const test = require("node:test"); +const { ok, strictEqual } = require("node:assert"); +const { onExecutePostLogin } = require("./app-metadata"); + +const { + actionTestSetup, +} = require("@kilterset/auth0-actions-testing/node-test-runner"); + +test("onExecutePostLogin", async (t) => { + const { auth0 } = await actionTestSetup(t); + + await t.test("records a lucky number", async () => { + const action = auth0.mock.actions.postLogin({ + secrets: { MAX_LUCKY_NUMBER: 42 }, + user: auth0.mock.user({ + app_metadata: {}, + }), + }); + + await action.simulate(onExecutePostLogin); + + const { lucky_number } = action.user.app_metadata; + + ok( + typeof lucky_number === "number", + `Expected the user's lucky number to be a number (got ${lucky_number})` + ); + + ok( + lucky_number < 42, + `Expected lucky number not to exceed the maximum allowed (got ${lucky_number})` + ); + }); + + await t.test("does not overwrite lucky numbers", async () => { + const action = auth0.mock.actions.postLogin({ + secrets: { MAX_LUCKY_NUMBER: 42 }, + user: auth0.mock.user({ + app_metadata: { lucky_number: 17 }, + }), + }); + + await action.simulate(onExecutePostLogin); + + const { lucky_number } = action.user.app_metadata; + + strictEqual( + lucky_number, + 17, + `Expected the user's lucky number to be unchanged` + ); + }); +}); diff --git a/package.json b/package.json index b5f4c95..1e158ab 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "version": "0.0.2", "description": "Test and develop Auth0 Actions or Okta CIC Actions locally.", "scripts": { - "test": "node --test $(find dist -name *.test.js)", + "test": "npm run test:src && npm run test:examples", + "test:src": "node --test $(find dist -name *.test.js)", + "test:examples": "node --test examples", "build": "tsc --build", "build:watch": "tsc --watch", "clean": "tsc --build --clean" diff --git a/tsconfig.json b/tsconfig.json index d0b7b28..1888f16 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ @@ -25,8 +25,8 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - "rootDir": "./src", /* Specify the root folder within your source files. */ + "module": "commonjs" /* Specify what module code is generated. */, + "rootDir": "./src" /* Specify the root folder within your source files. */, // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ @@ -44,7 +44,7 @@ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ - "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */, // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ @@ -55,7 +55,7 @@ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./dist", /* Specify an output folder for all emitted files. */ + "outDir": "./dist" /* Specify an output folder for all emitted files. */, // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ @@ -77,12 +77,12 @@ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ @@ -104,6 +104,7 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, + "exclude": ["examples", "dist", "node_modules"] }