From a5af12ef2b9015f125361173645544c87bffd615 Mon Sep 17 00:00:00 2001
From: Kenny Gray
Date: Sun, 6 Feb 2022 10:47:59 +0000
Subject: [PATCH 01/14] refactor: move createExpressApp to server file and
simplify run file
---
src/index.ts | 3 +-
src/run.ts | 346 +-------------------------------------------------
src/server.ts | 345 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 350 insertions(+), 344 deletions(-)
create mode 100644 src/server.ts
diff --git a/src/index.ts b/src/index.ts
index ff72555..e1dda4d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -7,4 +7,5 @@ export {
HttpMock,
Scenario,
} from './types';
-export { run, createExpressApp } from './run';
+export { run } from './run';
+export { createExpressApp } from './server';
diff --git a/src/run.ts b/src/run.ts
index 869ecc8..bf1360c 100644
--- a/src/run.ts
+++ b/src/run.ts
@@ -1,41 +1,9 @@
-import cookieParser from 'cookie-parser';
-import cors from 'cors';
-import express, { Request, Response, NextFunction } from 'express';
-import path from 'path';
import { transform } from 'server-with-kill';
-import {
- modifyScenarios,
- resetScenarios,
- getScenarios as apiGetScenarios,
-} from './apis';
-import {
- getGraphQlMocks,
- getGraphQlMock,
- createGraphQlRequestHandler,
-} from './graph-ql';
-import {
- getHttpMocks,
- getHttpMockAndParams,
- createHttpRequestHandler,
-} from './http';
-import {
- Mock,
- Options,
- ScenarioMap,
- DefaultScenario,
- Context,
- Scenario,
- PartialContext,
-} from './types';
-import { getUi, updateUi } from './ui';
-import {
- getScenariosFromCookie,
- getContextFromCookie,
- setContextAndScenariosCookie,
-} from './cookies';
+import { createExpressApp } from './server';
+import { Options, ScenarioMap, DefaultScenario } from './types';
-export { createExpressApp, run };
+export { run };
function run({
default: defaultScenario,
@@ -58,311 +26,3 @@ function run({
}),
);
}
-
-function createExpressApp({
- default: defaultScenario,
- scenarios: scenarioMap = {},
- options = {},
-}: {
- default: DefaultScenario;
- scenarios?: ScenarioMap;
- options?: Options;
-}) {
- let selectedScenarioNames: string[] = [];
- let currentContext = getContextFromScenarios([defaultScenario]);
- const {
- uiPath = '/',
- modifyScenariosPath = '/modify-scenarios',
- resetScenariosPath = '/reset-scenarios',
- scenariosPath = '/scenarios',
- cookieMode = false,
- } = options;
-
- const app = express();
- const scenarioNames = Object.keys(scenarioMap);
- const groupNames = Object.values(scenarioMap).reduce(
- (result, mock) => {
- if (
- Array.isArray(mock) ||
- mock.group == null ||
- result.includes(mock.group)
- ) {
- return result;
- }
-
- result.push(mock.group);
- return result;
- },
- [],
- );
-
- app.use(cors({ credentials: true }));
- app.use(cookieParser());
- app.use(uiPath, express.static(path.join(__dirname, 'assets')));
- app.use(express.urlencoded({ extended: false }));
- app.use(express.json());
- app.use(express.text({ type: 'application/graphql' }));
-
- app.get(
- uiPath,
- getUi({
- uiPath,
- scenarioMap,
- getScenarioNames,
- }),
- );
-
- app.post(
- uiPath,
- updateUi({
- uiPath,
- groupNames,
- scenarioNames,
- scenarioMap,
- updateScenariosAndContext,
- }),
- );
-
- app.put(
- modifyScenariosPath,
- modifyScenarios({
- scenarioNames,
- scenarioMap,
- updateScenariosAndContext,
- }),
- );
-
- app.put(
- resetScenariosPath,
- resetScenarios({
- updateScenariosAndContext,
- }),
- );
-
- app.get(
- scenariosPath,
- apiGetScenarios({
- scenarioMap,
- getScenarioNames,
- }),
- );
-
- app.use(
- createRequestHandler({
- getScenarioNames,
- defaultScenario,
- scenarioMap,
- getContext: (
- req: Request,
- res: Response,
- selectedScenarios: Scenario[],
- ) => {
- if (cookieMode) {
- return getContextFromCookie({
- req,
- res,
- defaultValue: {
- scenarios: getScenarioNames(req, res),
- context: getContextFromScenarios(selectedScenarios),
- },
- });
- }
-
- return currentContext;
- },
- setContext: (req: Request, res: Response, context: Context) => {
- if (cookieMode) {
- setContextAndScenariosCookie(res, {
- scenarios: getScenarioNames(req, res),
- context,
- });
- } else {
- currentContext = context;
- }
- },
- }),
- );
-
- return app;
-
- function updateScenariosAndContext(
- res: Response,
- updatedScenarioNames: string[],
- ) {
- const updatedScenarios = getScenarios({
- defaultScenario,
- scenarioMap,
- scenarioNames: updatedScenarioNames,
- });
- const context = getContextFromScenarios(updatedScenarios);
-
- if (cookieMode) {
- setContextAndScenariosCookie(res, {
- context,
- scenarios: updatedScenarioNames,
- });
-
- return;
- }
-
- currentContext = context;
- selectedScenarioNames = updatedScenarioNames;
-
- return updatedScenarioNames;
- }
-
- function getScenarioNames(req: Request, res: Response) {
- if (cookieMode) {
- const defaultScenarios: string[] = [];
-
- return getScenariosFromCookie({
- req,
- res,
- defaultValue: {
- context: getContextFromScenarios(
- getScenarios({
- defaultScenario,
- scenarioMap,
- scenarioNames: defaultScenarios,
- }),
- ),
- scenarios: defaultScenarios,
- },
- });
- }
-
- return selectedScenarioNames;
- }
-}
-
-function updateContext(context: Context, partialContext: PartialContext) {
- const newContext = {
- ...context,
- ...(typeof partialContext === 'function'
- ? partialContext(context)
- : partialContext),
- };
-
- return newContext;
-}
-
-function mergeMocks(scenarioMap: ({ mocks: Mock[] } | Mock[])[]) {
- return scenarioMap.reduce(
- (result, scenarioMock) =>
- result.concat(
- Array.isArray(scenarioMock) ? scenarioMock : scenarioMock.mocks,
- ),
- [],
- );
-}
-
-function getMocksFromScenarios(scenarios: Scenario[]) {
- const mocks = mergeMocks(scenarios);
- const httpMocks = getHttpMocks(mocks);
- const graphQlMocks = getGraphQlMocks(mocks);
-
- return { httpMocks, graphQlMocks };
-}
-
-function getScenarios({
- defaultScenario,
- scenarioMap,
- scenarioNames,
-}: {
- defaultScenario: DefaultScenario;
- scenarioMap: ScenarioMap;
- scenarioNames: string[];
-}): Scenario[] {
- return [defaultScenario].concat(
- scenarioNames.map(scenario => scenarioMap[scenario]),
- );
-}
-
-function getContextFromScenarios(scenarios: Scenario[]) {
- let context: Context = {};
- scenarios.forEach(mock => {
- if (!Array.isArray(mock) && mock.context) {
- context = { ...context, ...mock.context };
- }
- });
-
- return context;
-}
-
-function createRequestHandler({
- getScenarioNames,
- defaultScenario,
- scenarioMap,
- getContext,
- setContext,
-}: {
- getScenarioNames: (req: Request, res: Response) => string[];
- defaultScenario: DefaultScenario;
- scenarioMap: ScenarioMap;
- getContext: (
- req: Request,
- res: Response,
- selectedScenarios: Scenario[],
- ) => Context;
- setContext: (req: Request, res: Response, context: Context) => void;
-}) {
- return (req: Request, res: Response, next: NextFunction) => {
- const scenarioNames = getScenarioNames(req, res);
- const selectedScenarios = getScenarios({
- defaultScenario,
- scenarioMap,
- scenarioNames,
- });
-
- const { httpMocks, graphQlMocks } = getMocksFromScenarios(
- selectedScenarios,
- );
- let context: Context = getContext(req, res, selectedScenarios);
-
- const graphQlMock = getGraphQlMock(req, graphQlMocks);
-
- if (graphQlMock) {
- const requestHandler = createGraphQlRequestHandler({
- graphQlMock,
- updateContext: localUpdateContext,
- getContext: localGetContext,
- });
-
- requestHandler(req, res, next);
-
- return;
- }
-
- const { httpMock, params } = getHttpMockAndParams(req, httpMocks);
- if (httpMock) {
- const requestHandler = createHttpRequestHandler({
- httpMock,
- params,
- getContext: localGetContext,
- updateContext: localUpdateContext,
- });
-
- requestHandler(req, res);
-
- return;
- }
-
- // Nothing matched - default 404 from express
- next();
-
- function localUpdateContext(partialContext: PartialContext) {
- // Although "setContext" below will ensure the context is set correctly
- // for the server/cookie, if response functions call "updateContext" multiple
- // times, the local version of "getContext" will return the wrong value
- context = updateContext(context, partialContext);
-
- setContext(req, res, context);
-
- return context;
- }
-
- function localGetContext() {
- return context;
- }
- };
-}
diff --git a/src/server.ts b/src/server.ts
new file mode 100644
index 0000000..0ca2bf3
--- /dev/null
+++ b/src/server.ts
@@ -0,0 +1,345 @@
+import cookieParser from 'cookie-parser';
+import cors from 'cors';
+import express, { Request, Response, NextFunction } from 'express';
+import path from 'path';
+
+import {
+ modifyScenarios,
+ resetScenarios,
+ getScenarios as apiGetScenarios,
+} from './apis';
+import {
+ getGraphQlMocks,
+ getGraphQlMock,
+ createGraphQlRequestHandler,
+} from './graph-ql';
+import {
+ getHttpMocks,
+ getHttpMockAndParams,
+ createHttpRequestHandler,
+} from './http';
+import {
+ Mock,
+ Options,
+ ScenarioMap,
+ DefaultScenario,
+ Context,
+ Scenario,
+ PartialContext,
+} from './types';
+import { getUi, updateUi } from './ui';
+import {
+ getScenariosFromCookie,
+ getContextFromCookie,
+ setContextAndScenariosCookie,
+} from './cookies';
+
+export { createExpressApp };
+
+function createExpressApp({
+ default: defaultScenario,
+ scenarios: scenarioMap = {},
+ options = {},
+}: {
+ default: DefaultScenario;
+ scenarios?: ScenarioMap;
+ options?: Options;
+}) {
+ let selectedScenarioNames: string[] = [];
+ let currentContext = getContextFromScenarios([defaultScenario]);
+ const {
+ uiPath = '/',
+ modifyScenariosPath = '/modify-scenarios',
+ resetScenariosPath = '/reset-scenarios',
+ scenariosPath = '/scenarios',
+ cookieMode = false,
+ } = options;
+
+ const app = express();
+ const scenarioNames = Object.keys(scenarioMap);
+ const groupNames = Object.values(scenarioMap).reduce(
+ (result, mock) => {
+ if (
+ Array.isArray(mock) ||
+ mock.group == null ||
+ result.includes(mock.group)
+ ) {
+ return result;
+ }
+
+ result.push(mock.group);
+ return result;
+ },
+ [],
+ );
+
+ app.use(cors({ credentials: true }));
+ app.use(cookieParser());
+ app.use(uiPath, express.static(path.join(__dirname, 'assets')));
+ app.use(express.urlencoded({ extended: false }));
+ app.use(express.json());
+ app.use(express.text({ type: 'application/graphql' }));
+
+ app.get(
+ uiPath,
+ getUi({
+ uiPath,
+ scenarioMap,
+ getScenarioNames,
+ }),
+ );
+
+ app.post(
+ uiPath,
+ updateUi({
+ uiPath,
+ groupNames,
+ scenarioNames,
+ scenarioMap,
+ updateScenariosAndContext,
+ }),
+ );
+
+ app.put(
+ modifyScenariosPath,
+ modifyScenarios({
+ scenarioNames,
+ scenarioMap,
+ updateScenariosAndContext,
+ }),
+ );
+
+ app.put(
+ resetScenariosPath,
+ resetScenarios({
+ updateScenariosAndContext,
+ }),
+ );
+
+ app.get(
+ scenariosPath,
+ apiGetScenarios({
+ scenarioMap,
+ getScenarioNames,
+ }),
+ );
+
+ app.use(
+ createRequestHandler({
+ getScenarioNames,
+ defaultScenario,
+ scenarioMap,
+ getContext: (
+ req: Request,
+ res: Response,
+ selectedScenarios: Scenario[],
+ ) => {
+ if (cookieMode) {
+ return getContextFromCookie({
+ req,
+ res,
+ defaultValue: {
+ scenarios: getScenarioNames(req, res),
+ context: getContextFromScenarios(selectedScenarios),
+ },
+ });
+ }
+
+ return currentContext;
+ },
+ setContext: (req: Request, res: Response, context: Context) => {
+ if (cookieMode) {
+ setContextAndScenariosCookie(res, {
+ scenarios: getScenarioNames(req, res),
+ context,
+ });
+ } else {
+ currentContext = context;
+ }
+ },
+ }),
+ );
+
+ return app;
+
+ function updateScenariosAndContext(
+ res: Response,
+ updatedScenarioNames: string[],
+ ) {
+ const updatedScenarios = getScenarios({
+ defaultScenario,
+ scenarioMap,
+ scenarioNames: updatedScenarioNames,
+ });
+ const context = getContextFromScenarios(updatedScenarios);
+
+ if (cookieMode) {
+ setContextAndScenariosCookie(res, {
+ context,
+ scenarios: updatedScenarioNames,
+ });
+
+ return;
+ }
+
+ currentContext = context;
+ selectedScenarioNames = updatedScenarioNames;
+
+ return updatedScenarioNames;
+ }
+
+ function getScenarioNames(req: Request, res: Response) {
+ if (cookieMode) {
+ const defaultScenarios: string[] = [];
+
+ return getScenariosFromCookie({
+ req,
+ res,
+ defaultValue: {
+ context: getContextFromScenarios(
+ getScenarios({
+ defaultScenario,
+ scenarioMap,
+ scenarioNames: defaultScenarios,
+ }),
+ ),
+ scenarios: defaultScenarios,
+ },
+ });
+ }
+
+ return selectedScenarioNames;
+ }
+}
+
+function updateContext(context: Context, partialContext: PartialContext) {
+ const newContext = {
+ ...context,
+ ...(typeof partialContext === 'function'
+ ? partialContext(context)
+ : partialContext),
+ };
+
+ return newContext;
+}
+
+function mergeMocks(scenarioMap: ({ mocks: Mock[] } | Mock[])[]) {
+ return scenarioMap.reduce(
+ (result, scenarioMock) =>
+ result.concat(
+ Array.isArray(scenarioMock) ? scenarioMock : scenarioMock.mocks,
+ ),
+ [],
+ );
+}
+
+function getMocksFromScenarios(scenarios: Scenario[]) {
+ const mocks = mergeMocks(scenarios);
+ const httpMocks = getHttpMocks(mocks);
+ const graphQlMocks = getGraphQlMocks(mocks);
+
+ return { httpMocks, graphQlMocks };
+}
+
+function getScenarios({
+ defaultScenario,
+ scenarioMap,
+ scenarioNames,
+}: {
+ defaultScenario: DefaultScenario;
+ scenarioMap: ScenarioMap;
+ scenarioNames: string[];
+}): Scenario[] {
+ return [defaultScenario].concat(
+ scenarioNames.map(scenario => scenarioMap[scenario]),
+ );
+}
+
+function getContextFromScenarios(scenarios: Scenario[]) {
+ let context: Context = {};
+ scenarios.forEach(mock => {
+ if (!Array.isArray(mock) && mock.context) {
+ context = { ...context, ...mock.context };
+ }
+ });
+
+ return context;
+}
+
+function createRequestHandler({
+ getScenarioNames,
+ defaultScenario,
+ scenarioMap,
+ getContext,
+ setContext,
+}: {
+ getScenarioNames: (req: Request, res: Response) => string[];
+ defaultScenario: DefaultScenario;
+ scenarioMap: ScenarioMap;
+ getContext: (
+ req: Request,
+ res: Response,
+ selectedScenarios: Scenario[],
+ ) => Context;
+ setContext: (req: Request, res: Response, context: Context) => void;
+}) {
+ return (req: Request, res: Response, next: NextFunction) => {
+ const scenarioNames = getScenarioNames(req, res);
+ const selectedScenarios = getScenarios({
+ defaultScenario,
+ scenarioMap,
+ scenarioNames,
+ });
+
+ const { httpMocks, graphQlMocks } = getMocksFromScenarios(
+ selectedScenarios,
+ );
+ let context: Context = getContext(req, res, selectedScenarios);
+
+ const graphQlMock = getGraphQlMock(req, graphQlMocks);
+
+ if (graphQlMock) {
+ const requestHandler = createGraphQlRequestHandler({
+ graphQlMock,
+ updateContext: localUpdateContext,
+ getContext: localGetContext,
+ });
+
+ requestHandler(req, res, next);
+
+ return;
+ }
+
+ const { httpMock, params } = getHttpMockAndParams(req, httpMocks);
+ if (httpMock) {
+ const requestHandler = createHttpRequestHandler({
+ httpMock,
+ params,
+ getContext: localGetContext,
+ updateContext: localUpdateContext,
+ });
+
+ requestHandler(req, res);
+
+ return;
+ }
+
+ // Nothing matched - default 404 from express
+ next();
+
+ function localUpdateContext(partialContext: PartialContext) {
+ // Although "setContext" below will ensure the context is set correctly
+ // for the server/cookie, if response functions call "updateContext" multiple
+ // times, the local version of "getContext" will return the wrong value
+ context = updateContext(context, partialContext);
+
+ setContext(req, res, context);
+
+ return context;
+ }
+
+ function localGetContext() {
+ return context;
+ }
+ };
+}
From 2fa89c8f83c81496bdc4cf95ccf35bb045e4b694 Mon Sep 17 00:00:00 2001
From: Kenny Gray
Date: Sun, 6 Feb 2022 10:58:07 +0000
Subject: [PATCH 02/14] refactor: simplify UI generation
---
src/Html.tsx | 78 ++++++++++++++++++++++++++++------------------------
src/types.ts | 9 ------
src/ui.tsx | 34 +++--------------------
3 files changed, 46 insertions(+), 75 deletions(-)
diff --git a/src/Html.tsx b/src/Html.tsx
index cc4e6fd..0464e54 100644
--- a/src/Html.tsx
+++ b/src/Html.tsx
@@ -1,6 +1,6 @@
import React from 'react';
-import { UiGroups } from './types';
+import { Groups } from './types';
function Html({
updatedScenarios,
@@ -9,8 +9,8 @@ function Html({
other,
}: {
uiPath: string;
- groups: UiGroups;
- other: Array<{ name: string; checked: boolean }>;
+ groups: Groups;
+ other: Array<{ id: string; selected: boolean }>;
updatedScenarios?: string[];
}) {
if (uiPath[uiPath.length - 1] !== '/') {
@@ -39,39 +39,45 @@ function Html({
Refresh page
- {groups.map(group => (
-