• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmcelhaney / counterfact / 8836544464

25 Apr 2024 05:02PM UTC coverage: 87.36% (+0.6%) from 86.733%
8836544464

Pull #865

github

pmcelhaney
refactor and improve debug logs
Pull Request #865: reload everything when a file changes

896 of 989 branches covered (90.6%)

Branch coverage included in aggregate %.

55 of 57 new or added lines in 3 files covered. (96.49%)

3 existing lines in 2 files now uncovered.

2919 of 3378 relevant lines covered (86.41%)

45.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.06
/src/server/registry.ts
1
import createDebugger from "debug";
2✔
2

2✔
3
import { ModuleTree } from "./module-tree.js";
2✔
4
import type { Tools } from "./tools.js";
2✔
5
import type { MediaType, ResponseBuilderFactory } from "./types.d.ts";
2✔
6

2✔
7
const debug = createDebugger("counterfact:server:registry");
2✔
8

2✔
9
type HttpMethods =
2✔
10
  | "DELETE"
2✔
11
  | "GET"
2✔
12
  | "HEAD"
2✔
13
  | "OPTIONS"
2✔
14
  | "PATCH"
2✔
15
  | "POST"
2✔
16
  | "PUT"
2✔
17
  | "TRACE";
2✔
18

2✔
19
interface RequestData {
2✔
20
  context: unknown;
2✔
21
  headers: { [key: string]: number | string };
2✔
22
  matchedPath?: string;
2✔
23
  path?: { [key: string]: number | string };
2✔
24
  proxy: (url: string) => Promise<{
2✔
25
    body: string;
2✔
26
    contentType: string;
2✔
27
    headers: { [key: string]: string };
2✔
28
    status: number;
2✔
29
  }>;
2✔
30
  query: { [key: string]: number | string };
2✔
31
  response: ResponseBuilderFactory;
2✔
32
  tools: Tools;
2✔
33
  user?: {
2✔
34
    password?: string;
2✔
35
    username?: string;
2✔
36
  };
2✔
37
}
2✔
38

2✔
39
interface RequestDataWithBody extends RequestData {
2✔
40
  body?: unknown;
2✔
41
}
2✔
42

2✔
43
interface Module {
2✔
44
  DELETE?: (requestData: RequestData) => CounterfactResponse | undefined;
2✔
45
  GET?: (requestData: RequestData) => CounterfactResponse | undefined;
2✔
46
  HEAD?: (requestData: RequestData) => CounterfactResponse | undefined;
2✔
47
  OPTIONS?: (requestData: RequestData) => CounterfactResponse | undefined;
2✔
48
  PATCH?: (requestData: RequestData) => CounterfactResponse | undefined;
2✔
49
  POST?: (requestData: RequestDataWithBody) => CounterfactResponse | undefined;
2✔
50
  PUT?: (requestData: RequestDataWithBody) => CounterfactResponse | undefined;
2✔
51
  TRACE?: (requestData: RequestData) => CounterfactResponse | undefined;
2✔
52
}
2✔
53

2✔
54
type CounterfactResponseObject =
2✔
55
  | string
2✔
56
  | {
2✔
57
      body?: string;
2✔
58
      content?: {
2✔
59
        body: unknown;
2✔
60
        type: MediaType;
2✔
61
      }[];
2✔
62
      contentType?: string;
2✔
63
      headers?: { [key: string]: number | string };
2✔
64
      status?: number;
2✔
65
    };
2✔
66

2✔
67
type CounterfactResponse =
2✔
68
  | CounterfactResponseObject
2✔
69
  | Promise<CounterfactResponseObject>;
2✔
70

2✔
71
interface NormalizedCounterfactResponseObject {
2✔
72
  body?: string;
2✔
73
  content?: {
2✔
74
    body: unknown;
2✔
75
    type: MediaType;
2✔
76
  }[];
2✔
77
  contentType?: string;
2✔
78
  headers?: { [key: string]: number | string };
2✔
79
  status?: number;
2✔
80
}
2✔
81

2✔
82
function castParameters(
216✔
83
  parameters: { [key: string]: number | string },
216✔
84
  parameterTypes?: { [key: string]: string },
216✔
85
) {
216✔
86
  const copy: { [key: string]: number | string } = { ...parameters };
216✔
87

216✔
88
  Object.entries(copy).forEach(([key, value]) => {
216✔
89
    copy[key] =
56✔
90
      parameterTypes?.[key] === "number"
56✔
91
        ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
6✔
92
          Number.parseInt(value as string, 10)
6✔
93
        : value;
50✔
94
  });
56✔
95

216✔
96
  return copy;
216✔
97
}
216✔
98

2✔
99
export class Registry {
2✔
100
  private moduleTree = new ModuleTree();
98✔
101

98✔
102
  public get routes() {
98✔
103
    return this.moduleTree.routes;
2✔
104
  }
2✔
105

98✔
106
  public add(url: string, module: Module) {
98✔
107
    this.moduleTree.add(url, module);
104✔
108
  }
104✔
109

98✔
110
  public remove(url: string) {
98✔
UNCOV
111
    this.moduleTree.remove(url);
×
UNCOV
112
  }
×
113

98✔
114
  public clear() {
98✔
115
    this.moduleTree = new ModuleTree();
24✔
116
  }
24✔
117

98✔
118
  public exists(method: HttpMethods, url: string) {
98✔
119
    return Boolean(this.handler(url).module?.[method]);
34✔
120
  }
34✔
121

98✔
122
  public handler(url: string) {
98✔
123
    const match = this.moduleTree.match(url);
170✔
124

170✔
125
    return {
170✔
126
      matchedPath: match?.matchedPath ?? "",
170✔
127
      module: match?.module,
170✔
128
      path: match?.pathVariables ?? {},
170✔
129
    };
170✔
130
  }
170✔
131

98✔
132
  public endpoint(
98✔
133
    httpRequestMethod: HttpMethods,
74✔
134
    url: string,
74✔
135
    parameterTypes: {
74✔
136
      header?: { [key: string]: string };
74✔
137
      path?: { [key: string]: string };
74✔
138
      query?: { [key: string]: string };
74✔
139
    } = {},
74✔
140
  ) {
74✔
141
    const handler = this.handler(url);
74✔
142

74✔
143
    debug("handler for %s: %o", url, handler);
74✔
144
    const execute = handler.module?.[httpRequestMethod];
74✔
145

74✔
146
    if (!execute) {
74✔
147
      return () => ({
2✔
148
        body: `Could not find a ${httpRequestMethod} method matching ${url}\n`,
2✔
149
        contentType: "text/plain",
2✔
150
        headers: {},
2✔
151
        status: 404,
2✔
152
      });
2✔
153
    }
2✔
154

72✔
155
    return async ({ ...requestData }: RequestDataWithBody) => {
72✔
156
      const operationArgument: RequestDataWithBody & {
72✔
157
        x?: RequestDataWithBody;
72✔
158
      } = {
72✔
159
        ...requestData,
72✔
160
        headers: castParameters(requestData.headers, parameterTypes.header),
72✔
161
        matchedPath: handler.matchedPath,
72✔
162
        path: castParameters(handler.path, parameterTypes.path),
72✔
163
        query: castParameters(requestData.query, parameterTypes.query),
72✔
164
      };
72✔
165

72✔
166
      // eslint-disable-next-line id-length
72✔
167
      operationArgument.x = operationArgument;
72✔
168

72✔
169
      return await execute(operationArgument);
72✔
170
    };
72✔
171
  }
72✔
172
}
98✔
173

2✔
174
export type {
2✔
175
  CounterfactResponseObject,
2✔
176
  HttpMethods,
2✔
177
  Module,
2✔
178
  NormalizedCounterfactResponseObject,
2✔
179
  RequestDataWithBody,
2✔
180
};
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc