Skip to content

Commit

Permalink
Merge pull request #15 from kilterset/post-user-registration
Browse files Browse the repository at this point in the history
Post User Registration
  • Loading branch information
matt-wratt authored Apr 11, 2024
2 parents 9f88c73 + 3aa7935 commit 3db38b3
Show file tree
Hide file tree
Showing 17 changed files with 249 additions and 14 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ This library provides you with the setup to test complex actions. Customise test

The following [Flows](https://auth0.com/docs/customize/actions/flows-and-triggers) are supported:

| Flow | Support |
| ---------------------- | ------- |
| Login | |
| Machine to Machine | |
| Password Reset | |
| Pre User Registration | |
| Post User Registration | planned |
| Post Change Password | planned |
| Send Phone Message | planned |
| Flow | Support |
| ---------------------- | ----------------- |
| Login |from v0.1.0 |
| Machine to Machine |pending release |
| Password Reset |pending release |
| Pre User Registration |pending release |
| Post User Registration | ✓ pending release |
| Post Change Password | planned |
| Send Phone Message | planned |


## Getting started
Expand Down
14 changes: 14 additions & 0 deletions examples/notify-slack-post-user-registration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Notify a Slack channel when a new user registers.
*/
exports.onExecutePostUserRegistration = async (event) => {
const payload = {
text: `New User: ${event.user.email}`,
};

await fetch(event.secrets.SLACK_WEBHOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
};
42 changes: 42 additions & 0 deletions examples/notify-slack-post-user-registration.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const test = require("node:test");
const { strictEqual, deepStrictEqual } = require("node:assert");
const {
onExecutePostUserRegistration,
} = require("./notify-slack-post-user-registration");
const { nodeTestRunner } = require("@kilterset/auth0-actions-testing");

test("post user registration", async (t) => {
const { auth0, fetchMock } = await nodeTestRunner.actionTestSetup(t);

await t.test("service is notified when user logs in", async (t) => {
fetchMock.mock("https://slack/hook", 201);

const action = auth0.mock.actions.postUserRegistration({
secrets: { SLACK_WEBHOOK_URL: "https://slack/hook" },
user: auth0.mock.user({ email: "[email protected]" }),
});

await action.simulate(onExecutePostUserRegistration);

const calls = fetchMock.calls();

strictEqual(calls.length, 1, "Expected 1 fetch call to be made.");

const [url, options] = calls[0];

strictEqual(url, "https://slack/hook", "Unexpected URL");
strictEqual(options.method, "POST", "Unexpected request method");

deepStrictEqual(
options.headers,
{ "Content-Type": "application/json" },
"Unexpected headers"
);

deepStrictEqual(
JSON.parse(options.body),
{ text: "New User: [email protected]" },
"Unexpected body"
);
});
});
1 change: 1 addition & 0 deletions src/mock/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./credentials-exchange";
export * from "./post-challenge";
export * from "./post-login";
export * from "./post-user-registration";
export * from "./pre-user-registration";
44 changes: 44 additions & 0 deletions src/mock/actions/post-user-registration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { api, events } from "..";
import Auth0 from "../../types";
import { PostChallengeOptions } from "../api";

type Handler = (
event: Auth0.Events.PostUserRegistration,
api: Auth0.API.PostUserRegistration
) => Promise<void>;

export function postUserRegistration({
cache,
...attributes
}: Parameters<typeof events.postUserRegistration>[0] &
Omit<PostChallengeOptions, "user" | "request"> = {}) {
const event = events.postUserRegistration(attributes);

const { implementation, state } = api.postUserRegistration({ cache });

async function simulate(handler: Handler) {
await handler(event, implementation);
}

return new Proxy(
{
event,
simulate,
},
{
get(target, prop) {
if (typeof prop !== "string") {
return;
}

if (prop in target) {
return target[prop as keyof typeof target];
}

if (prop in state) {
return state[prop as keyof typeof state];
}
},
}
);
}
1 change: 1 addition & 0 deletions src/mock/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from "./cache";
export * from "./credentials-exchange";
export * from "./post-challenge";
export * from "./post-login";
export * from "./post-user-registration";
export * from "./pre-user-registration";
29 changes: 29 additions & 0 deletions src/mock/api/post-user-registration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Auth0 from "../../types";
import { cache as mockCache } from "./cache";

export interface PostUserRegistrationOptions {
cache?: Record<string, string>;
}

export interface PostUserRegistrationState {
cache: Auth0.API.Cache;
}

export function postUserRegistration({
cache,
}: PostUserRegistrationOptions = {}) {
const apiCache = mockCache(cache);

const state: PostUserRegistrationState = {
cache: apiCache,
};

const api: Auth0.API.PostUserRegistration = {
cache: apiCache,
};

return {
implementation: api,
state,
};
}
1 change: 1 addition & 0 deletions src/mock/events/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./post-login";
export * from "./credentials-exchange";
export * from "./post-user-registration";
export * from "./pre-user-registration";
2 changes: 1 addition & 1 deletion src/mock/events/post-challenge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { identity } from "../identity";

export const postChallenge = define<Auth0.Events.PostChallenge>(
({ params }) => {
const tenantId = params.tenant?.id || chance.n(chance.word, 2).join("-");
const tenantId = params.tenant?.id || chance.auth0().tenantId();
const hostname = params.request?.hostname || `${tenantId}.auth0.com`;

const connectionValue = params.connection
Expand Down
2 changes: 1 addition & 1 deletion src/mock/events/post-login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { chance } from "../chance";
import { identity } from "../identity";

export const postLogin = define<Auth0.Events.PostLogin>(({ params }) => {
const tenantId = params.tenant?.id || chance.n(chance.word, 2).join("-");
const tenantId = params.tenant?.id || chance.auth0().tenantId();
const hostname = params.request?.hostname || `${tenantId}.auth0.com`;

const connectionValue = params.connection
Expand Down
53 changes: 53 additions & 0 deletions src/mock/events/post-user-registration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { define } from "../define";
import Auth0, { Connection } from "../../types";
import { user } from "../user";
import { request } from "../request";
import { transaction } from "../transaction";
import { connection } from "../connection";
import { chance } from "../chance";
import { identity } from "../identity";

export const postUserRegistration = define<Auth0.Events.PostUserRegistration>(
({ params }): Auth0.Events.PostUserRegistration => {
const tenantId = params.tenant?.id || chance.auth0().tenantId();
const hostname = params.request?.hostname || `${tenantId}.auth0.com`;

const connectionValue = params.connection
? (params.connection as Connection)
: connection();

const identities = params.user?.identities || [];

identities.splice(
0,
1,
identity({
connection: connectionValue.name,
provider: connectionValue.strategy,
...(identities[0] || {}),
})
);

const userValue = user({ ...params.user, identities });

const requestValue = request({
hostname,
...params.request,
query: {
connection: connectionValue.name,
...params.request?.query,
},
});

const transactionValue = transaction();

return {
transaction: transactionValue,
connection: connectionValue,
tenant: { id: tenantId },
request: requestValue,
user: userValue,
secrets: {},
};
}
);
4 changes: 1 addition & 3 deletions src/mock/events/pre-user-registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { define } from "../define";
import Auth0, { Connection } from "../../types";
import { user } from "../user";
import { request } from "../request";
import { authentication } from "../authentication";
import { transaction } from "../transaction";
import { session } from "../session";
import { connection } from "../connection";
Expand All @@ -13,7 +12,7 @@ import { identity } from "../identity";

export const preUserRegistration = define<Auth0.Events.PreUserRegistration>(
({ params }) => {
const tenantId = params.tenant?.id || chance.n(chance.word, 2).join("-");
const tenantId = params.tenant?.id || chance.auth0().tenantId();
const hostname = params.request?.hostname || `${tenantId}.auth0.com`;

const connectionValue = params.connection
Expand Down Expand Up @@ -47,7 +46,6 @@ export const preUserRegistration = define<Auth0.Events.PreUserRegistration>(

return {
transaction: transactionValue,
authentication: authentication(),
authorization: {
roles: [],
},
Expand Down
22 changes: 22 additions & 0 deletions src/test/api/post-user-registration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import test from "node:test";
import { strictEqual, deepStrictEqual } from "node:assert";
import { postUserRegistration } from "../../mock/api";

test("Post User Registration API", async (t) => {
await t.test("cache", async (t) => {
await t.test("can set cache", async (t) => {
const { implementation: api, state } = postUserRegistration();
strictEqual(api.cache.set("location", "Ōtautahi").type, "success");
deepStrictEqual(state.cache.get("location"), "Ōtautahi");
});

await t.test("can get cache", async (t) => {
const { implementation: api, state } = postUserRegistration({
cache: { location: "Ōtautahi" },
});

strictEqual(state.cache.get("location"), "Ōtautahi");
strictEqual(state.cache.get("nonexistent"), undefined);
});
});
});
1 change: 1 addition & 0 deletions src/types/api/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from "./cache";
export * from "./credentials-exchange";
export * from "./post-challenge";
export * from "./post-login";
export * from "./post-user-registration";
export * from "./pre-user-registration";
9 changes: 9 additions & 0 deletions src/types/api/post-user-registration.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { User } from "../user";
import { Cache } from "./cache";

export interface PostUserRegistration {
/**
* Store and retrieve data that persists across executions.
*/
readonly cache: Cache;
}
1 change: 1 addition & 0 deletions src/types/events/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./credentials-exchange";
export * from "./post-challenge";
export * from "./post-login";
export * from "./post-user-registration";
export * from "./pre-user-registration";
19 changes: 19 additions & 0 deletions src/types/events/post-user-registration.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Authentication } from "../authentication";
import { Client } from "../client";
import { Connection } from "../connection";
import { Request } from "../request";
import { Transaction } from "../transaction";
import { User } from "../user";

export interface PostUserRegistration {
connection: Connection;
request?: Request;
tenant: {
id: string;
};
transaction?: Transaction;
user: User;
secrets: {
[key: string]: string;
};
}

0 comments on commit 3db38b3

Please sign in to comment.