@chidchanun/bcp 0.2.12 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -222
- package/docs/README.md +50 -54
- package/docs/api-manifest.json +32 -71
- package/docs/api-reference.md +165 -58
- package/docs/docs-web-manifest.json +9 -5
- package/docs/platform-manifest.json +33 -4
- package/docs/realtime-platform.md +447 -0
- package/docs/releases/0.2.13.md +122 -0
- package/docs/releases/0.2.14.md +241 -0
- package/docs/testing-platform.md +602 -0
- package/package.json +11 -1
- package/packages/bundler/src/client-boundary.ts +2 -0
- package/packages/client/src/realtime.mjs +973 -0
- package/packages/client/src/realtime.ts +31 -0
- package/packages/client/src/testing.mjs +2357 -0
- package/packages/client/src/testing.ts +52 -0
- package/packages/server/src/realtime.ts +1518 -0
- package/packages/server/src/testing-page.ts +274 -0
- package/packages/server/src/testing.ts +1884 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import {
|
|
2
|
+
executePageActionFunction,
|
|
3
|
+
normalizePageActionMethod,
|
|
4
|
+
type PageAction,
|
|
5
|
+
type PageActionExecution,
|
|
6
|
+
type PageActionMethod,
|
|
7
|
+
} from "./form-action.js";
|
|
8
|
+
import {
|
|
9
|
+
executePageGuardFunctions,
|
|
10
|
+
type PageGuard,
|
|
11
|
+
type PageGuardData,
|
|
12
|
+
type PageGuardDefinition,
|
|
13
|
+
type PageGuardExecution,
|
|
14
|
+
} from "./page-guard.js";
|
|
15
|
+
import {
|
|
16
|
+
executePageLoaderFunction,
|
|
17
|
+
type PageLoader,
|
|
18
|
+
type PageLoaderExecution,
|
|
19
|
+
} from "./page-loader.js";
|
|
20
|
+
|
|
21
|
+
export interface TestPageContextOptions {
|
|
22
|
+
params?: Record<string, any>;
|
|
23
|
+
url?: string | URL;
|
|
24
|
+
guardData?: PageGuardData;
|
|
25
|
+
hasGuard?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface TestPageGuardOptions
|
|
29
|
+
extends Omit<
|
|
30
|
+
TestPageContextOptions,
|
|
31
|
+
"guardData" | "hasGuard"
|
|
32
|
+
> {
|
|
33
|
+
label?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TestPageActionOptions
|
|
37
|
+
extends TestPageContextOptions {
|
|
38
|
+
actionName?: string;
|
|
39
|
+
method?: PageActionMethod | string;
|
|
40
|
+
formData?: FormData;
|
|
41
|
+
fields?: Record<
|
|
42
|
+
string,
|
|
43
|
+
string | Blob | Array<string | Blob>
|
|
44
|
+
>;
|
|
45
|
+
label?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function runTestPageLoader(
|
|
49
|
+
loader: PageLoader,
|
|
50
|
+
options: TestPageContextOptions = {}
|
|
51
|
+
): Promise<PageLoaderExecution> {
|
|
52
|
+
assertFunction(
|
|
53
|
+
loader,
|
|
54
|
+
"page loader"
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return executePageLoaderFunction(
|
|
58
|
+
loader,
|
|
59
|
+
{
|
|
60
|
+
...(options.params ?? {}),
|
|
61
|
+
},
|
|
62
|
+
resolveTestPageUrl(
|
|
63
|
+
options.url
|
|
64
|
+
),
|
|
65
|
+
"bcp/testing loader",
|
|
66
|
+
{
|
|
67
|
+
...(options.guardData ?? {}),
|
|
68
|
+
},
|
|
69
|
+
options.hasGuard ??
|
|
70
|
+
Object.keys(
|
|
71
|
+
options.guardData ?? {}
|
|
72
|
+
).length > 0
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function runTestPageGuards(
|
|
77
|
+
guards:
|
|
78
|
+
| PageGuard
|
|
79
|
+
| PageGuard[]
|
|
80
|
+
| PageGuardDefinition[],
|
|
81
|
+
options: TestPageGuardOptions = {}
|
|
82
|
+
): Promise<PageGuardExecution> {
|
|
83
|
+
const list =
|
|
84
|
+
Array.isArray(guards)
|
|
85
|
+
? guards
|
|
86
|
+
: [guards];
|
|
87
|
+
const definitions:
|
|
88
|
+
PageGuardDefinition[] =
|
|
89
|
+
list.map(
|
|
90
|
+
(candidate, index) => {
|
|
91
|
+
if (
|
|
92
|
+
typeof candidate === "object" &&
|
|
93
|
+
candidate !== null &&
|
|
94
|
+
"guard" in candidate
|
|
95
|
+
) {
|
|
96
|
+
const definition =
|
|
97
|
+
candidate as PageGuardDefinition;
|
|
98
|
+
assertFunction(
|
|
99
|
+
definition.guard,
|
|
100
|
+
`page guard ${index + 1}`
|
|
101
|
+
);
|
|
102
|
+
return {
|
|
103
|
+
filePath:
|
|
104
|
+
definition.filePath ||
|
|
105
|
+
`${options.label ?? "bcp/testing guard"}#${index + 1}`,
|
|
106
|
+
guard:
|
|
107
|
+
definition.guard,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
assertFunction(
|
|
112
|
+
candidate,
|
|
113
|
+
`page guard ${index + 1}`
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
filePath:
|
|
118
|
+
`${options.label ?? "bcp/testing guard"}#${index + 1}`,
|
|
119
|
+
guard:
|
|
120
|
+
candidate as PageGuard,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
return executePageGuardFunctions(
|
|
126
|
+
definitions,
|
|
127
|
+
{
|
|
128
|
+
...(options.params ?? {}),
|
|
129
|
+
},
|
|
130
|
+
resolveTestPageUrl(
|
|
131
|
+
options.url
|
|
132
|
+
)
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export async function runTestPageAction(
|
|
137
|
+
action: PageAction,
|
|
138
|
+
options: TestPageActionOptions = {}
|
|
139
|
+
): Promise<PageActionExecution> {
|
|
140
|
+
assertFunction(
|
|
141
|
+
action,
|
|
142
|
+
"page action"
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
if (
|
|
146
|
+
options.formData &&
|
|
147
|
+
options.fields
|
|
148
|
+
) {
|
|
149
|
+
throw new TypeError(
|
|
150
|
+
"BCP Testing: page action test cannot specify both formData and fields."
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const actionName =
|
|
155
|
+
normalizeText(
|
|
156
|
+
options.actionName ?? "action",
|
|
157
|
+
"page action name"
|
|
158
|
+
);
|
|
159
|
+
const method =
|
|
160
|
+
normalizePageActionMethod(
|
|
161
|
+
options.method ?? "POST"
|
|
162
|
+
);
|
|
163
|
+
const formData =
|
|
164
|
+
options.formData ??
|
|
165
|
+
createTestFormData(
|
|
166
|
+
options.fields ?? {}
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
return executePageActionFunction(
|
|
170
|
+
action,
|
|
171
|
+
actionName,
|
|
172
|
+
method,
|
|
173
|
+
formData,
|
|
174
|
+
{
|
|
175
|
+
...(options.params ?? {}),
|
|
176
|
+
},
|
|
177
|
+
resolveTestPageUrl(
|
|
178
|
+
options.url
|
|
179
|
+
),
|
|
180
|
+
{
|
|
181
|
+
...(options.guardData ?? {}),
|
|
182
|
+
},
|
|
183
|
+
options.hasGuard ??
|
|
184
|
+
Object.keys(
|
|
185
|
+
options.guardData ?? {}
|
|
186
|
+
).length > 0,
|
|
187
|
+
options.label ??
|
|
188
|
+
"bcp/testing actions"
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function createTestFormData(
|
|
193
|
+
fields: Record<
|
|
194
|
+
string,
|
|
195
|
+
string | Blob | Array<string | Blob>
|
|
196
|
+
> = {}
|
|
197
|
+
): FormData {
|
|
198
|
+
const formData =
|
|
199
|
+
new FormData();
|
|
200
|
+
|
|
201
|
+
for (
|
|
202
|
+
const [name, rawValue]
|
|
203
|
+
of Object.entries(fields)
|
|
204
|
+
) {
|
|
205
|
+
const values =
|
|
206
|
+
Array.isArray(rawValue)
|
|
207
|
+
? rawValue
|
|
208
|
+
: [rawValue];
|
|
209
|
+
|
|
210
|
+
for (const value of values) {
|
|
211
|
+
formData.append(
|
|
212
|
+
name,
|
|
213
|
+
value
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return formData;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function resolveTestPageUrl(
|
|
222
|
+
value?: string | URL
|
|
223
|
+
): URL {
|
|
224
|
+
if (value instanceof URL) {
|
|
225
|
+
return new URL(
|
|
226
|
+
value.href
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const candidate =
|
|
231
|
+
value ??
|
|
232
|
+
"http://bcp.test/";
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
return new URL(
|
|
236
|
+
candidate
|
|
237
|
+
);
|
|
238
|
+
} catch {
|
|
239
|
+
return new URL(
|
|
240
|
+
String(candidate).replace(
|
|
241
|
+
/^\//,
|
|
242
|
+
""
|
|
243
|
+
),
|
|
244
|
+
"http://bcp.test/"
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function assertFunction(
|
|
250
|
+
value: unknown,
|
|
251
|
+
label: string
|
|
252
|
+
): asserts value is (...args: any[]) => unknown {
|
|
253
|
+
if (typeof value !== "function") {
|
|
254
|
+
throw new TypeError(
|
|
255
|
+
`BCP Testing: ${label} must be a function.`
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function normalizeText(
|
|
261
|
+
value: unknown,
|
|
262
|
+
label: string
|
|
263
|
+
): string {
|
|
264
|
+
const text =
|
|
265
|
+
String(value ?? "").trim();
|
|
266
|
+
|
|
267
|
+
if (!text) {
|
|
268
|
+
throw new TypeError(
|
|
269
|
+
`BCP Testing: ${label} must be a non-empty string.`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return text;
|
|
274
|
+
}
|