libmodulor 0.19.0 → 0.21.0
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/CHANGELOG.md +36 -0
- package/README.md +1 -1
- package/dist/esm/apps/Helper/src/lib/project.js +7 -7
- package/dist/esm/convention.d.ts +2 -0
- package/dist/esm/convention.js +2 -0
- package/dist/esm/dt/Validation.js +1 -1
- package/dist/esm/dt/final/TGitSSHURL.d.ts +4 -3
- package/dist/esm/dt/final/TGitSSHURL.js +1 -1
- package/dist/esm/dt/final/TSSHPrivateKey.js +1 -3
- package/dist/esm/std/ShellCommandExecutor.d.ts +1 -0
- package/dist/esm/std/impl/ConsoleLogger.js +2 -2
- package/dist/esm/std/impl/FetchHTTPAPICallExecutor.js +1 -1
- package/dist/esm/std/impl/NodeFormDataBuilder.js +3 -1
- package/dist/esm/std/impl/NodeSpawnShellCommandExecutor.js +6 -0
- package/dist/esm/std/impl/SimpleHTTPAPICaller.js +1 -1
- package/dist/esm/target/lib/cli/CommandExecutor.js +2 -2
- package/dist/esm/target/lib/react/UCContainer.js +1 -1
- package/dist/esm/target/lib/react/UCPanel.js +0 -4
- package/dist/esm/target/lib/react/form.d.ts +5 -6
- package/dist/esm/target/lib/react/form.js +7 -10
- package/dist/esm/target/lib/react/useUC.d.ts +4 -4
- package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.js +1 -0
- package/dist/esm/target/react-native-pure/UCForm.d.ts +1 -1
- package/dist/esm/target/react-native-pure/UCForm.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormField.d.ts +1 -1
- package/dist/esm/target/react-native-pure/UCFormField.js +3 -4
- package/dist/esm/target/react-native-pure/UCFormFieldControl.js +13 -7
- package/dist/esm/target/react-web-pure/UCForm.d.ts +1 -1
- package/dist/esm/target/react-web-pure/UCForm.js +2 -2
- package/dist/esm/target/react-web-pure/UCFormField.d.ts +1 -1
- package/dist/esm/target/react-web-pure/UCFormField.js +3 -4
- package/dist/esm/target/react-web-pure/UCFormFieldControl.js +7 -4
- package/dist/esm/testing/AppTester.d.ts +6 -3
- package/dist/esm/testing/AppTester.js +20 -6
- package/dist/esm/testing/impl/SimpleHTMLAppTestReportEmitter.js +1 -1
- package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +2 -2
- package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.js +135 -115
- package/dist/esm/testing/impl/VitestAppTestSuiteRunner.d.ts +2 -3
- package/dist/esm/testing/impl/VitestAppTestSuiteRunner.js +6 -8
- package/dist/esm/testing/uc-input.js +13 -12
- package/dist/esm/testing/workers/UCExecutor.js +2 -2
- package/dist/esm/testing/workers/checkers/UCDefChecker.d.ts +2 -0
- package/dist/esm/testing/workers/checkers/UCDefChecker.js +4 -1
- package/dist/esm/uc/UC.d.ts +7 -7
- package/dist/esm/uc/UC.js +4 -3
- package/dist/esm/uc/UCInputField.d.ts +6 -3
- package/dist/esm/uc/UCInputField.js +39 -29
- package/dist/esm/uc/index.d.ts +0 -1
- package/dist/esm/uc/index.js +0 -1
- package/dist/esm/uc/input-field.d.ts +2 -19
- package/dist/esm/uc/input-field.js +0 -19
- package/dist/esm/uc/input.d.ts +13 -7
- package/dist/esm/uc/utils/rInput.js +4 -3
- package/dist/esm/uc/utils/rVal.d.ts +5 -5
- package/dist/esm/uc/utils/rVal.js +1 -12
- package/dist/esm/uc/value.d.ts +1 -2
- package/dist/esm/uc/workers/UCInputFilesProcessor.js +3 -3
- package/package.json +16 -16
- package/pnpm-workspace.yaml +1 -1
- package/tsconfig.json +0 -1
|
@@ -13,7 +13,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
13
13
|
import { inject, injectable } from 'inversify';
|
|
14
14
|
import { I18nEN } from '../i18n/locales/en.js';
|
|
15
15
|
import { I18nFR } from '../i18n/locales/fr.js';
|
|
16
|
-
import { FAKE_USER_ADMIN, UCBuilder,
|
|
16
|
+
import { FAKE_USER_ADMIN, UCBuilder, ucHTTPContract, } from '../uc/index.js';
|
|
17
17
|
// We inject directly the implementation because we'll generate all the reports and not only the one that is bound to the interface.
|
|
18
18
|
// We can plan a setting à la Vitest where we specify the types of reports to generate though.
|
|
19
19
|
import { SimpleHTMLAppTestReportEmitter } from './impl/SimpleHTMLAppTestReportEmitter.js';
|
|
@@ -29,6 +29,7 @@ import { AppManifestChecker } from './workers/checkers/AppManifestChecker.js';
|
|
|
29
29
|
import { UCDefChecker } from './workers/checkers/UCDefChecker.js';
|
|
30
30
|
import { UCDefSourcesChecker, } from './workers/checkers/UCDefSourcesChecker.js';
|
|
31
31
|
import { UCExecutor, } from './workers/UCExecutor.js';
|
|
32
|
+
const ERR_UCD_NOT_FOUND = (ucName) => `Could not find a ucd for ${ucName}`;
|
|
32
33
|
let AppTester = class AppTester {
|
|
33
34
|
appDocsEmitter;
|
|
34
35
|
appFolderChecker;
|
|
@@ -50,6 +51,8 @@ let AppTester = class AppTester {
|
|
|
50
51
|
*/
|
|
51
52
|
safeSrcImporter;
|
|
52
53
|
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
54
|
+
ucds;
|
|
55
|
+
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
53
56
|
testResults;
|
|
54
57
|
testSummary;
|
|
55
58
|
ucDefSourcesCheckerOutput;
|
|
@@ -66,6 +69,7 @@ let AppTester = class AppTester {
|
|
|
66
69
|
this.ucDefChecker = ucDefChecker;
|
|
67
70
|
this.ucDefSourcesChecker = ucDefSourcesChecker;
|
|
68
71
|
this.ucExecutor = ucExecutor;
|
|
72
|
+
this.ucds = new Map();
|
|
69
73
|
this.testResults = [];
|
|
70
74
|
this.testSummary = {
|
|
71
75
|
counts: {
|
|
@@ -115,13 +119,13 @@ let AppTester = class AppTester {
|
|
|
115
119
|
});
|
|
116
120
|
}
|
|
117
121
|
async checkUC(ucdRef) {
|
|
118
|
-
const { errors } = await this.ucDefChecker.exec({ ucdRef });
|
|
122
|
+
const { errors, ucd } = await this.ucDefChecker.exec({ ucdRef });
|
|
119
123
|
if (errors.length > 0) {
|
|
120
124
|
throw new Error(errors[0]);
|
|
121
125
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
if (ucd) {
|
|
127
|
+
this.ucds.set(ucdRef.name, ucd);
|
|
128
|
+
}
|
|
125
129
|
}
|
|
126
130
|
async execFlow(flow) {
|
|
127
131
|
const output = [];
|
|
@@ -133,7 +137,8 @@ let AppTester = class AppTester {
|
|
|
133
137
|
if (inputOverride) {
|
|
134
138
|
const inputOverrides = inputOverride(output);
|
|
135
139
|
for (const [k, v] of Object.entries(inputOverrides)) {
|
|
136
|
-
|
|
140
|
+
// @ts-expect-error
|
|
141
|
+
uc.inputField(k).setVal(v);
|
|
137
142
|
}
|
|
138
143
|
}
|
|
139
144
|
};
|
|
@@ -226,6 +231,13 @@ let AppTester = class AppTester {
|
|
|
226
231
|
getCtx() {
|
|
227
232
|
return this.ctx;
|
|
228
233
|
}
|
|
234
|
+
getUCD(ucName) {
|
|
235
|
+
const ucd = this.ucds.get(ucName);
|
|
236
|
+
if (!ucd) {
|
|
237
|
+
throw new Error(ERR_UCD_NOT_FOUND(ucName));
|
|
238
|
+
}
|
|
239
|
+
return ucd;
|
|
240
|
+
}
|
|
229
241
|
async init({ appPath, configurator, serverClientSettings, srcImporter, }) {
|
|
230
242
|
this.configurator = configurator;
|
|
231
243
|
this.safeSrcImporter = (path) => Promise.race([
|
|
@@ -243,6 +255,8 @@ let AppTester = class AppTester {
|
|
|
243
255
|
await this.configurator.seed(this.ctx);
|
|
244
256
|
await this.bindI18n();
|
|
245
257
|
await this.bindServerClientSettings(serverClientSettings);
|
|
258
|
+
}
|
|
259
|
+
async initForUCExec() {
|
|
246
260
|
await this.initI18n();
|
|
247
261
|
await this.initServer();
|
|
248
262
|
}
|
|
@@ -140,7 +140,7 @@ const template = (appPath, testResults, testSummary) => `<!DOCTYPE html>
|
|
|
140
140
|
const search = new URLSearchParams(window.location.search);
|
|
141
141
|
const status = search.get('status');
|
|
142
142
|
if (status) {
|
|
143
|
-
document.querySelectorAll(\`table tbody tr:not(.\${status
|
|
143
|
+
document.querySelectorAll(\`table tbody tr:not(.\${status})\`).forEach((n) => n.remove());
|
|
144
144
|
}
|
|
145
145
|
</script>
|
|
146
146
|
</table>
|
|
@@ -92,9 +92,9 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
|
|
|
92
92
|
target)],
|
|
93
93
|
};
|
|
94
94
|
this.compilerOptions.incremental = false; // Otherwise it triggers the following error : Option '--incremental' can only be specified using tsconfig, emitting to single file or when option '--tsBuildInfoFile' is specified.
|
|
95
|
-
// @ts-
|
|
95
|
+
// @ts-expect-error
|
|
96
96
|
this.compilerOptions.jsx = undefined; // Otherwise it triggers the following error since TS 5.5 : jsx is a string value; tsconfig JSON must be parsed with parseJsonSourceFileConfigFileContent or getParsedCommandLineOfConfigFile before passing to createProgram
|
|
97
|
-
// @ts-
|
|
97
|
+
// @ts-expect-error
|
|
98
98
|
this.compilerOptions.lib = undefined; // Otherwise it triggers errors saying it does not find them
|
|
99
99
|
}
|
|
100
100
|
getTypeFields(node) {
|
|
@@ -52,14 +52,14 @@ const template = (serverPortRangeStart, idx, monkeyTestingTimeoutInMs) => `/*
|
|
|
52
52
|
import { join } from 'node:path';
|
|
53
53
|
|
|
54
54
|
import {
|
|
55
|
-
assert,
|
|
56
55
|
type Arbitrary,
|
|
57
56
|
type AsyncCommand,
|
|
58
|
-
type ModelRunSetup,
|
|
59
57
|
anything,
|
|
58
|
+
assert,
|
|
60
59
|
asyncModelRun,
|
|
61
60
|
asyncProperty,
|
|
62
61
|
commands,
|
|
62
|
+
type ModelRunSetup,
|
|
63
63
|
record,
|
|
64
64
|
} from 'fast-check';
|
|
65
65
|
import {
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
type UCInput,
|
|
71
71
|
} from 'libmodulor';
|
|
72
72
|
import { newNodeAppTester } from 'libmodulor/node-test';
|
|
73
|
-
import { afterAll, afterEach, describe, expect, test } from 'vitest';
|
|
73
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test } from 'vitest';
|
|
74
74
|
|
|
75
75
|
import { Configurator } from './Configurator.js';
|
|
76
76
|
|
|
@@ -84,116 +84,92 @@ const runner = await newNodeAppTester(${serverPortRangeStart}, ${idx}, {
|
|
|
84
84
|
const ctx = runner.getCtx();
|
|
85
85
|
const logger = ctx.container.get<Logger>('Logger');
|
|
86
86
|
|
|
87
|
+
const flows = await configurator.flows();
|
|
88
|
+
|
|
87
89
|
afterAll(async () => {
|
|
88
90
|
await runner.finalize();
|
|
89
91
|
});
|
|
90
92
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
test('Folder should be valid', async () => {
|
|
96
|
-
await runner.checkAppFolder();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test('${APP_MANIFEST_NAME} should be valid', async () => {
|
|
100
|
-
await runner.checkAppManifest();
|
|
101
|
-
});
|
|
93
|
+
describe('Check', () => {
|
|
94
|
+
test('Sources should be valid', async () => {
|
|
95
|
+
await runner.checkUCDSources();
|
|
96
|
+
});
|
|
102
97
|
|
|
103
|
-
test('
|
|
104
|
-
|
|
105
|
-
});
|
|
98
|
+
test('Folder should be valid', async () => {
|
|
99
|
+
await runner.checkAppFolder();
|
|
100
|
+
});
|
|
106
101
|
|
|
107
|
-
test('${
|
|
108
|
-
|
|
109
|
-
});
|
|
102
|
+
test('${APP_MANIFEST_NAME} should be valid', async () => {
|
|
103
|
+
await runner.checkAppManifest();
|
|
104
|
+
});
|
|
110
105
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
afterEach(async () => {
|
|
114
|
-
await configurator.clearExecution(ctx);
|
|
106
|
+
test('${APP_I18N_NAME} should be valid', async () => {
|
|
107
|
+
await runner.checkAppI18n();
|
|
115
108
|
});
|
|
116
109
|
|
|
117
|
-
test
|
|
118
|
-
|
|
110
|
+
test('${APP_INDEX_NAME} should be valid', async () => {
|
|
111
|
+
await runner.checkAppIndex();
|
|
112
|
+
});
|
|
119
113
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
}
|
|
114
|
+
describe.runIf(ctx.ucdRefs.length > 0)('Use Cases', () => {
|
|
115
|
+
describe.each(ctx.ucdRefs)('$name', async (ucdRef) => {
|
|
116
|
+
test('should be valid', async () => {
|
|
117
|
+
await runner.checkUC(ucdRef);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
128
120
|
});
|
|
129
121
|
});
|
|
130
122
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
123
|
+
describe('Run', async () => {
|
|
124
|
+
beforeAll(async () => {
|
|
125
|
+
await runner.initForUCExec();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe.runIf(flows.length > 0)('Flows', async () => {
|
|
134
129
|
afterEach(async () => {
|
|
135
130
|
await configurator.clearExecution(ctx);
|
|
136
131
|
});
|
|
137
132
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
test('should be valid', async () => {
|
|
142
|
-
ucd = await runner.checkUC(ucdRef);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
const data = await runner.ucTestData(ucdRef);
|
|
146
|
-
|
|
147
|
-
test.each(data)(
|
|
148
|
-
'should execute with auth $authName and input $inputFillerName',
|
|
149
|
-
async ({ auth, authName, inputFiller, inputFillerName }) => {
|
|
150
|
-
const { out, sideEffects } = await runner.execUC({
|
|
151
|
-
auth,
|
|
152
|
-
authName: authName as UCAuthSetterName,
|
|
153
|
-
inputFiller,
|
|
154
|
-
inputFillerName,
|
|
155
|
-
ucd,
|
|
156
|
-
});
|
|
133
|
+
test.each(flows)('should execute flow $name', async (flow) => {
|
|
134
|
+
const output = await runner.execFlow(flow);
|
|
157
135
|
|
|
136
|
+
for (const out of output) {
|
|
158
137
|
if (out.err !== null) {
|
|
159
138
|
if (!(out.err instanceof CustomError)) {
|
|
160
139
|
logger.error(out.err);
|
|
161
140
|
}
|
|
162
141
|
expect(out.err).toBeInstanceOf(CustomError);
|
|
163
142
|
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
164
146
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
\`hash = \${hash\}\`,
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
test('should execute with monkey testing', async () => {
|
|
180
|
-
// Given
|
|
181
|
-
// biome-ignore lint/complexity/noBannedTypes: nothing for now
|
|
182
|
-
type Model = {};
|
|
183
|
-
// biome-ignore lint/complexity/noBannedTypes: nothing for now
|
|
184
|
-
type RealSystem = {};
|
|
185
|
-
|
|
186
|
-
class MyCommand<I extends UCInput | undefined = undefined>
|
|
187
|
-
implements AsyncCommand<Model, RealSystem>
|
|
188
|
-
{
|
|
189
|
-
constructor(private input: I) {}
|
|
190
|
-
|
|
191
|
-
public check(_m: Readonly<Model>): boolean {
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
147
|
+
describe.runIf(ctx.ucdRefs.length > 0)('Use Cases', () => {
|
|
148
|
+
describe.each(ctx.ucdRefs)('$name', async (ucdRef) => {
|
|
149
|
+
afterEach(async () => {
|
|
150
|
+
await configurator.clearExecution(ctx);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
154
|
+
let ucd: UCDef<any, any, any>;
|
|
194
155
|
|
|
195
|
-
|
|
196
|
-
|
|
156
|
+
beforeAll(() => {
|
|
157
|
+
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
158
|
+
ucd = runner.getUCD<any, any, any>(ucdRef.name);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const data = await runner.ucTestData(ucdRef);
|
|
162
|
+
|
|
163
|
+
test.each(data)(
|
|
164
|
+
'should execute with auth $authName and input $inputFillerName',
|
|
165
|
+
async ({ auth, authName, inputFiller, inputFillerName }) => {
|
|
166
|
+
const { out, sideEffects } = await runner.execUC({
|
|
167
|
+
auth,
|
|
168
|
+
authName: authName as UCAuthSetterName,
|
|
169
|
+
inputFiller,
|
|
170
|
+
inputFillerName,
|
|
171
|
+
ucd,
|
|
172
|
+
});
|
|
197
173
|
|
|
198
174
|
if (out.err !== null) {
|
|
199
175
|
if (!(out.err instanceof CustomError)) {
|
|
@@ -201,41 +177,85 @@ describe.runIf(ucdRefs.length > 0)('Use Cases', () => {
|
|
|
201
177
|
}
|
|
202
178
|
expect(out.err).toBeInstanceOf(CustomError);
|
|
203
179
|
}
|
|
204
|
-
}
|
|
205
180
|
|
|
206
|
-
|
|
207
|
-
|
|
181
|
+
const { hash } = out;
|
|
182
|
+
const assertion = hash
|
|
183
|
+
? (await configurator.specificAssertions())?.get(hash)
|
|
184
|
+
: undefined;
|
|
185
|
+
if (assertion) {
|
|
186
|
+
expect(out).toSatisfy(assertion);
|
|
187
|
+
} else {
|
|
188
|
+
expect({ out, sideEffects }).toMatchSnapshot(
|
|
189
|
+
\`hash = \${hash}\`,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
test('should execute with monkey testing', async () => {
|
|
196
|
+
// Given
|
|
197
|
+
// biome-ignore lint/complexity/noBannedTypes: nothing for now
|
|
198
|
+
type Model = {};
|
|
199
|
+
// biome-ignore lint/complexity/noBannedTypes: nothing for now
|
|
200
|
+
type RealSystem = {};
|
|
201
|
+
|
|
202
|
+
class MyCommand<I extends UCInput | undefined = undefined>
|
|
203
|
+
implements AsyncCommand<Model, RealSystem>
|
|
204
|
+
{
|
|
205
|
+
constructor(private input: I) {}
|
|
206
|
+
|
|
207
|
+
public check(_m: Readonly<Model>): boolean {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
public async run(_m: Model, _r: RealSystem): Promise<void> {
|
|
212
|
+
const out = await runner.execMonkeyTest(
|
|
213
|
+
ucd,
|
|
214
|
+
this.input,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
if (out.err !== null) {
|
|
218
|
+
if (!(out.err instanceof CustomError)) {
|
|
219
|
+
logger.error(out.err);
|
|
220
|
+
}
|
|
221
|
+
expect(out.err).toBeInstanceOf(CustomError);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
public toString(): string {
|
|
226
|
+
return \`\${ucd.metadata.name}(\${JSON.stringify(this.input)})\`;
|
|
227
|
+
}
|
|
208
228
|
}
|
|
209
|
-
}
|
|
210
229
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
230
|
+
const inputFields = ucd.io.i?.fields;
|
|
231
|
+
if (!inputFields || Object.keys(inputFields).length > 0) {
|
|
232
|
+
// Mainly to prevent monkey testing from running indefinitely
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
216
235
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
236
|
+
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
237
|
+
const inputLike: Record<string, Arbitrary<any>> = {};
|
|
238
|
+
for (const k of Object.keys(inputFields)) {
|
|
239
|
+
inputLike[k] = anything();
|
|
240
|
+
}
|
|
241
|
+
const cmdArbs = record(inputLike, { requiredKeys: [] }).map(
|
|
242
|
+
(r) => new MyCommand(r),
|
|
243
|
+
);
|
|
225
244
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
245
|
+
const modelRunSetup: ModelRunSetup<Model, RealSystem> = () => ({
|
|
246
|
+
model: {},
|
|
247
|
+
real: {},
|
|
248
|
+
});
|
|
230
249
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
250
|
+
// When
|
|
251
|
+
const property = asyncProperty(commands([cmdArbs]), (cmds) =>
|
|
252
|
+
asyncModelRun(modelRunSetup, cmds),
|
|
253
|
+
);
|
|
235
254
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
255
|
+
// Then
|
|
256
|
+
await assert(property);
|
|
257
|
+
}, ${monkeyTestingTimeoutInMs});
|
|
258
|
+
});
|
|
239
259
|
});
|
|
240
260
|
});
|
|
241
261
|
`;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { FilePath } from '../../dt/index.js';
|
|
2
|
-
import type { FSManager,
|
|
2
|
+
import type { FSManager, ShellCommandExecutor } from '../../std/index.js';
|
|
3
3
|
import type { AppTestSuiteRunner, Input } from '../workers/AppTestSuiteRunner.js';
|
|
4
4
|
export declare class VitestAppTestSuiteRunner implements AppTestSuiteRunner {
|
|
5
5
|
private fsManager;
|
|
6
|
-
private logger;
|
|
7
6
|
private shellCommandExecutor;
|
|
8
|
-
constructor(fsManager: FSManager,
|
|
7
|
+
constructor(fsManager: FSManager, shellCommandExecutor: ShellCommandExecutor);
|
|
9
8
|
exec({ appPath, skipCoverage, updateSnapshots, }: Input): Promise<void>;
|
|
10
9
|
coverageReportEntrypointPath(appPath: FilePath): Promise<FilePath>;
|
|
11
10
|
private coverageReportPath;
|
|
@@ -14,17 +14,16 @@ import { inject, injectable } from 'inversify';
|
|
|
14
14
|
import { APP_TEST_DIR_NAME, APP_TEST_REPORTS_DIR_NAME, } from '../../convention.js';
|
|
15
15
|
let VitestAppTestSuiteRunner = class VitestAppTestSuiteRunner {
|
|
16
16
|
fsManager;
|
|
17
|
-
logger;
|
|
18
17
|
shellCommandExecutor;
|
|
19
|
-
constructor(fsManager,
|
|
18
|
+
constructor(fsManager, shellCommandExecutor) {
|
|
20
19
|
this.fsManager = fsManager;
|
|
21
|
-
this.logger = logger;
|
|
22
20
|
this.shellCommandExecutor = shellCommandExecutor;
|
|
23
21
|
}
|
|
24
22
|
async exec({ appPath, skipCoverage, updateSnapshots, }) {
|
|
25
23
|
const testPath = this.fsManager.path(appPath, APP_TEST_DIR_NAME);
|
|
26
24
|
const args = [
|
|
27
25
|
'run',
|
|
26
|
+
'--color',
|
|
28
27
|
'--dir',
|
|
29
28
|
appPath,
|
|
30
29
|
];
|
|
@@ -34,13 +33,13 @@ let VitestAppTestSuiteRunner = class VitestAppTestSuiteRunner {
|
|
|
34
33
|
if (updateSnapshots) {
|
|
35
34
|
args.push('--update');
|
|
36
35
|
}
|
|
37
|
-
|
|
36
|
+
await this.shellCommandExecutor.exec({
|
|
38
37
|
bin: './node_modules/.bin/vitest',
|
|
39
38
|
opts: {
|
|
40
39
|
args,
|
|
40
|
+
streamData: true,
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
|
-
this.logger.info(output);
|
|
44
43
|
}
|
|
45
44
|
async coverageReportEntrypointPath(appPath) {
|
|
46
45
|
return this.fsManager.path(this.coverageReportPath(appPath), 'index.html');
|
|
@@ -53,8 +52,7 @@ let VitestAppTestSuiteRunner = class VitestAppTestSuiteRunner {
|
|
|
53
52
|
VitestAppTestSuiteRunner = __decorate([
|
|
54
53
|
injectable(),
|
|
55
54
|
__param(0, inject('FSManager')),
|
|
56
|
-
__param(1, inject('
|
|
57
|
-
|
|
58
|
-
__metadata("design:paramtypes", [Object, Object, Object])
|
|
55
|
+
__param(1, inject('ShellCommandExecutor')),
|
|
56
|
+
__metadata("design:paramtypes", [Object, Object])
|
|
59
57
|
], VitestAppTestSuiteRunner);
|
|
60
58
|
export { VitestAppTestSuiteRunner };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TFile } from '../dt/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ucifIsMandatory, ucifMustBeFilledManually, ucifRepeatability, } from '../uc/index.js';
|
|
3
3
|
export const DEFAULT_UC_INPUT_FILLERS = [
|
|
4
4
|
'ALL_WITH_EXAMPLES',
|
|
5
5
|
'ONLY_MANDATORY_WITH_EXAMPLES',
|
|
@@ -36,19 +36,20 @@ export function onlySetProgrammaticallyWithExamples(uc) {
|
|
|
36
36
|
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
37
37
|
function fillWithExample(f) {
|
|
38
38
|
const { type } = f.def;
|
|
39
|
-
let val = type.getExamples()?.[0] ?? type.example();
|
|
40
39
|
if (type instanceof TFile) {
|
|
41
|
-
const
|
|
40
|
+
const example = type.getExamples()?.[0] ?? type.example();
|
|
42
41
|
// TODO : Consider building a real file with real data (e.g. image, pdf, txt, etc.)
|
|
43
|
-
val = new File(['01010101010101010101010101010101'],
|
|
44
|
-
type:
|
|
42
|
+
const val = new File(['01010101010101010101010101010101'], example.path, {
|
|
43
|
+
type: example.type,
|
|
45
44
|
});
|
|
45
|
+
const [isRepeatable] = ucifRepeatability(f.def);
|
|
46
|
+
if (isRepeatable) {
|
|
47
|
+
f.addVal(val);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
f.setVal(val);
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
46
53
|
}
|
|
47
|
-
|
|
48
|
-
if (isRepeatable) {
|
|
49
|
-
f.setValue(UCInputFieldChangeOperator.ADD, val);
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
f.setValue(UCInputFieldChangeOperator.SET, val);
|
|
53
|
-
}
|
|
54
|
+
f.fillWithExample();
|
|
54
55
|
}
|
|
@@ -92,13 +92,13 @@ let UCExecutor = class UCExecutor {
|
|
|
92
92
|
if (Array.isArray(v)) {
|
|
93
93
|
v.forEach((vv, idx) => {
|
|
94
94
|
if (vv instanceof File) {
|
|
95
|
-
// @ts-
|
|
95
|
+
// @ts-expect-error
|
|
96
96
|
input[k][idx] = this.derandomizeInputFile(vv);
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
else if (v instanceof File) {
|
|
101
|
-
// @ts-
|
|
101
|
+
// @ts-expect-error
|
|
102
102
|
input[k] = this.derandomizeInputFile(v);
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { ErrorMessage } from '../../../dt/index.js';
|
|
2
2
|
import type { Worker } from '../../../std/index.js';
|
|
3
|
+
import type { UCDef } from '../../../uc/index.js';
|
|
3
4
|
import type { AppTesterUCDRef } from '../../ctx.js';
|
|
4
5
|
export interface Input {
|
|
5
6
|
ucdRef: AppTesterUCDRef;
|
|
6
7
|
}
|
|
7
8
|
export interface Output {
|
|
8
9
|
errors: ErrorMessage[];
|
|
10
|
+
ucd: UCDef | null;
|
|
9
11
|
}
|
|
10
12
|
export declare class UCDefChecker implements Worker<Input, Promise<Output>> {
|
|
11
13
|
private output;
|
|
@@ -15,7 +15,7 @@ const ERR_UCD_NAMES = (fileName, name, ucdKey) => `The file name and the const n
|
|
|
15
15
|
let UCDefChecker = class UCDefChecker {
|
|
16
16
|
output;
|
|
17
17
|
constructor() {
|
|
18
|
-
this.output = { errors: [] };
|
|
18
|
+
this.output = { errors: [], ucd: null };
|
|
19
19
|
}
|
|
20
20
|
async exec({ ucdRef }) {
|
|
21
21
|
const { fileName, source } = ucdRef;
|
|
@@ -35,6 +35,9 @@ let UCDefChecker = class UCDefChecker {
|
|
|
35
35
|
name !== ucdKey.replaceAll(UC_DEF_SUFFIX, '')) {
|
|
36
36
|
this.output.errors.push(ERR_UCD_NAMES(fileName, name, ucdKey));
|
|
37
37
|
}
|
|
38
|
+
if (this.output.errors.length === 0) {
|
|
39
|
+
this.output.ucd = ucd;
|
|
40
|
+
}
|
|
38
41
|
return this.output;
|
|
39
42
|
}
|
|
40
43
|
};
|
package/dist/esm/uc/UC.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AppManifest } from '../app/index.js';
|
|
|
2
2
|
import { type DataType, Validation } from '../dt/index.js';
|
|
3
3
|
import type { UCAuth } from './auth.js';
|
|
4
4
|
import type { UCDef, UCFieldKey } from './def.js';
|
|
5
|
-
import type { UCInput } from './input.js';
|
|
5
|
+
import type { UCInput, UCInputKey, UCInputKeyDataType, UCInputPartial } from './input.js';
|
|
6
6
|
import type { UCOPIBase } from './opi.js';
|
|
7
7
|
import { UCInputField } from './UCInputField.js';
|
|
8
8
|
import type { reqVal0, rVal0, rValArr } from './utils/rVal.js';
|
|
@@ -16,15 +16,15 @@ export declare class UC<I extends UCInput | undefined = undefined, OPI0 extends
|
|
|
16
16
|
appManifest: AppManifest;
|
|
17
17
|
def: UCDef<I, OPI0, OPI1>;
|
|
18
18
|
auth: UCAuth | null;
|
|
19
|
-
inputFields: UCInputField<
|
|
19
|
+
inputFields: UCInputField<DataType>[];
|
|
20
20
|
constructor(appManifest: AppManifest, def: UCDef<I, OPI0, OPI1>, auth: UCAuth | null);
|
|
21
21
|
clear(): void;
|
|
22
22
|
clearSensitiveInputFields(): void;
|
|
23
|
-
fill(input:
|
|
23
|
+
fill(input: UCInputPartial<I>): this;
|
|
24
24
|
hasInputField(key: UCFieldKey): boolean;
|
|
25
25
|
hasMediaInInput(): boolean;
|
|
26
26
|
hasOutputParts(): boolean;
|
|
27
|
-
inputField<
|
|
27
|
+
inputField<K extends UCInputKey<I>>(key: K): UCInputField<UCInputKeyDataType<I, K>>;
|
|
28
28
|
inputFieldsForForm(): UCInputField<any>[];
|
|
29
29
|
inputFieldsOrdered(): UCInputField<any>[];
|
|
30
30
|
inputFieldsInsensitive(): UCInputField<any>[];
|
|
@@ -32,8 +32,8 @@ export declare class UC<I extends UCInput | undefined = undefined, OPI0 extends
|
|
|
32
32
|
needsInputFilling(): boolean;
|
|
33
33
|
needsOutputDisplay(): boolean;
|
|
34
34
|
operatesOnAggregate(): boolean;
|
|
35
|
-
rVal0<
|
|
36
|
-
reqVal0<
|
|
37
|
-
rValArr<
|
|
35
|
+
rVal0<K extends UCInputKey<I>>(key: K): ReturnType<typeof rVal0<UCInputKeyDataType<I, K>>>;
|
|
36
|
+
reqVal0<K extends UCInputKey<I>>(key: K): ReturnType<typeof reqVal0<UCInputKeyDataType<I, K>>>;
|
|
37
|
+
rValArr<K extends UCInputKey<I>>(key: K): ReturnType<typeof rValArr<UCInputKeyDataType<I, K>>>;
|
|
38
38
|
validate(): [UCInputField<any> | null, Validation] | null;
|
|
39
39
|
}
|
package/dist/esm/uc/UC.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TFile, Validation } from '../dt/index.js';
|
|
2
2
|
import { isBlank } from '../utils/index.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ucifIsMandatory, ucifIsSensitive, ucifMustBeFilledManually, } from './input-field.js';
|
|
4
4
|
import { AggregateInputDef } from './io/input/AggregateInput.js';
|
|
5
5
|
import { ListInputDef } from './io/input/ListInput.js';
|
|
6
6
|
import { UCInputField } from './UCInputField.js';
|
|
@@ -8,7 +8,6 @@ export class UC {
|
|
|
8
8
|
appManifest;
|
|
9
9
|
def;
|
|
10
10
|
auth;
|
|
11
|
-
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
12
11
|
inputFields;
|
|
13
12
|
constructor(appManifest, def, auth) {
|
|
14
13
|
this.appManifest = appManifest;
|
|
@@ -40,7 +39,8 @@ export class UC {
|
|
|
40
39
|
}
|
|
41
40
|
fill(input) {
|
|
42
41
|
for (const f of this.inputFields) {
|
|
43
|
-
|
|
42
|
+
const val = input[f.key];
|
|
43
|
+
f.setVal(val);
|
|
44
44
|
}
|
|
45
45
|
return this;
|
|
46
46
|
}
|
|
@@ -58,6 +58,7 @@ export class UC {
|
|
|
58
58
|
if (!field) {
|
|
59
59
|
throw new Error(`Input field ${key.toString()} does not exist`);
|
|
60
60
|
}
|
|
61
|
+
// @ts-expect-error
|
|
61
62
|
return field;
|
|
62
63
|
}
|
|
63
64
|
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|