openxiangda-cli 2.0.0-alpha.183 → 2.0.0-alpha.185
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/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +5 -3
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/spec.js +1 -1
- package/dist/commands/spec.js.map +1 -1
- package/package.json +5 -5
- package/template/AGENTS.md +2 -2
- package/template/apps/web/e2e/README.md +7 -0
- package/template/apps/web/package.json +2 -2
- package/template/apps/web/playwright.config.ts +3 -5
- package/template/apps/web/vite.config.ts +1 -9
- package/template/appspec/app.md +5 -1
- package/template/package.json +1 -1
- package/template/apps/web/data-api-live.e2e.html +0 -15
- package/template/apps/web/e2e/client-fixture.ts +0 -5
- package/template/apps/web/e2e/component-defaults-fixture.css +0 -15
- package/template/apps/web/e2e/data-api-live-fixture.tsx +0 -162
- package/template/apps/web/e2e/data-api-live.spec.ts +0 -144
- package/template/apps/web/e2e/field-protocol-fixture.tsx +0 -387
- package/template/apps/web/e2e/field-protocol.spec.ts +0 -285
- package/template/apps/web/e2e/mobile-files.spec.ts +0 -96
- package/template/apps/web/e2e/mobile-reference-fixture.tsx +0 -314
- package/template/apps/web/e2e/mobile-reference.spec.ts +0 -360
- package/template/apps/web/e2e/mobile-selection.spec.ts +0 -199
- package/template/apps/web/e2e/resource-experience-fixture.tsx +0 -491
- package/template/apps/web/e2e/resource-platform-mock.ts +0 -202
- package/template/apps/web/e2e/resources.spec.ts +0 -488
- package/template/apps/web/e2e/standard-admin.spec.ts +0 -511
- package/template/apps/web/e2e/workflow-entry-fixture.tsx +0 -107
- package/template/apps/web/e2e/workflow-entry.spec.ts +0 -556
- package/template/apps/web/e2e/workflow-experience-fixture.tsx +0 -338
- package/template/apps/web/e2e/workflow.spec.ts +0 -1265
- package/template/apps/web/field-protocol.e2e.html +0 -22
- package/template/apps/web/mobile-reference.e2e.html +0 -27
- package/template/apps/web/resource-experience.e2e.html +0 -16
- package/template/apps/web/scripts/check.mjs +0 -43
- package/template/apps/web/test/contracts.test.ts +0 -163
- package/template/apps/web/workflow-entry.e2e.html +0 -15
- package/template/apps/web/workflow-experience.e2e.html +0 -15
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<meta name="openxiangda-runtime-base" content="/" />
|
|
7
|
-
<meta name="openxiangda-app-code" content="field-protocol-fixture" />
|
|
8
|
-
<meta name="openxiangda-environment" content="preproduction" />
|
|
9
|
-
<title>Field protocol acceptance</title>
|
|
10
|
-
<style>
|
|
11
|
-
html { background-color: rgb(248, 249, 250); }
|
|
12
|
-
body { color: rgb(31, 32, 33); font-size: 17px; font-family: monospace; }
|
|
13
|
-
a { color: rgb(101, 42, 140); }
|
|
14
|
-
output[data-saved-values] { display: block; overflow-wrap: anywhere; }
|
|
15
|
-
</style>
|
|
16
|
-
</head>
|
|
17
|
-
<body>
|
|
18
|
-
<a id="outside-mobile" href="#root">页面外部链接</a>
|
|
19
|
-
<div id="root"></div>
|
|
20
|
-
<script type="module" src="/e2e/field-protocol-fixture.tsx"></script>
|
|
21
|
-
</body>
|
|
22
|
-
</html>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<meta name="openxiangda-runtime-base" content="/" />
|
|
7
|
-
<meta name="openxiangda-app-code" content="field-protocol-fixture" />
|
|
8
|
-
<meta name="openxiangda-environment" content="preproduction" />
|
|
9
|
-
<title>移动表单组件</title>
|
|
10
|
-
<style>
|
|
11
|
-
body { margin: 0; }
|
|
12
|
-
.reference-form { min-height: 100dvh; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
13
|
-
.reference-form .oxa-mobile-header { position: sticky; top: 0; z-index: 5; }
|
|
14
|
-
.reference-form .reference-group { margin: 0 12px 16px; padding: 0 16px; background: white; border-radius: 10px; }
|
|
15
|
-
.reference-form .reference-group > div:last-child .oxa-mobile-field { border-bottom: 0; }
|
|
16
|
-
.reference-form .reference-group-title { font-size: 14px; font-weight: 400; color: #888; padding: 0 24px; margin: 20px 0 10px; }
|
|
17
|
-
.reference-form .reference-content { padding-bottom: 86px; }
|
|
18
|
-
.reference-form [data-field-code] { scroll-margin-top: 82px; }
|
|
19
|
-
.reference-form output { display: none; }
|
|
20
|
-
.reference-form .reference-notice { padding: 8px 24px; color: #1677ff; }
|
|
21
|
-
</style>
|
|
22
|
-
</head>
|
|
23
|
-
<body>
|
|
24
|
-
<div id="root"></div>
|
|
25
|
-
<script type="module" src="/e2e/mobile-reference-fixture.tsx"></script>
|
|
26
|
-
</body>
|
|
27
|
-
</html>
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<meta name="openxiangda-runtime-base" content="/" />
|
|
7
|
-
<meta name="openxiangda-app-code" content="openxiangda-application" />
|
|
8
|
-
<meta name="openxiangda-environment" content="preproduction" />
|
|
9
|
-
<title>Resource experience acceptance</title>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div id="outside-ui" style="height:0;overflow:hidden;font-family:monospace;color:rgb(31,32,33);background:rgb(248,249,250)">宿主页面</div>
|
|
13
|
-
<div id="root"></div>
|
|
14
|
-
<script type="module" src="/e2e/resource-experience-fixture.tsx"></script>
|
|
15
|
-
</body>
|
|
16
|
-
</html>
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { readFileSync, readdirSync } from 'node:fs';
|
|
2
|
-
import { join, resolve } from 'node:path';
|
|
3
|
-
|
|
4
|
-
const root = resolve(import.meta.dirname, '..');
|
|
5
|
-
const files = [];
|
|
6
|
-
function visit(directory) {
|
|
7
|
-
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
8
|
-
const path = join(directory, entry.name);
|
|
9
|
-
if (entry.isDirectory() && !['.umi', '.umi-production', '.turbopack'].includes(entry.name)) visit(path);
|
|
10
|
-
else if (/\.(?:ts|tsx)$/.test(entry.name)) files.push(path);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
visit(join(root, 'src'));
|
|
14
|
-
const lines = files.reduce((total, file) => total + readFileSync(file, 'utf8').split(/\r?\n/).length, 0);
|
|
15
|
-
// The shared Surface renderer is deliberately counted as application source;
|
|
16
|
-
// keep its small budget explicit instead of hiding it in generated output.
|
|
17
|
-
// Field Kit families are separate modules so a semantic field does not add a
|
|
18
|
-
// branch to one universal renderer. Keep explicit ceilings while allowing the
|
|
19
|
-
// complete 30-field standard kit to remain decomposed.
|
|
20
|
-
if (files.length > 36) throw new Error(`WEB_SOURCE_FILE_BUDGET_EXCEEDED:${files.length}>36`);
|
|
21
|
-
if (lines > 10_000) throw new Error(`WEB_BUSINESS_LOC_BUDGET_EXCEEDED:${lines}>10000`);
|
|
22
|
-
const source = files.map((file) => readFileSync(file, 'utf8')).join('\n');
|
|
23
|
-
for (const marker of [
|
|
24
|
-
'@umijs/',
|
|
25
|
-
'openxiangda-' + 'admin',
|
|
26
|
-
'openxiangda-' + 'user',
|
|
27
|
-
'instrument_query',
|
|
28
|
-
'instrument_save',
|
|
29
|
-
'function.invoke',
|
|
30
|
-
'authorization' + '-mode',
|
|
31
|
-
'focused' + '_role',
|
|
32
|
-
'/native/current' + '-user',
|
|
33
|
-
'college-' + 'am',
|
|
34
|
-
'user-' + 'wang',
|
|
35
|
-
'dept-' + 'am-test',
|
|
36
|
-
]) {
|
|
37
|
-
if (source.includes(marker)) throw new Error(`WEB_FORBIDDEN_MARKER:${marker}`);
|
|
38
|
-
}
|
|
39
|
-
const playwright = readFileSync(join(root, 'playwright.config.ts'), 'utf8');
|
|
40
|
-
if (!playwright.includes('reuseExistingServer: false')) {
|
|
41
|
-
throw new Error('WEB_E2E_MUST_NOT_REUSE_UNKNOWN_SERVER');
|
|
42
|
-
}
|
|
43
|
-
process.stdout.write(`Verified Vite/Refine web source: ${files.length} files, ${lines} LOC.\n`);
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
3
|
-
import test from 'node:test';
|
|
4
|
-
import { readRuntimeMount, resolveApplicationBasename } from 'openxiangda/core';
|
|
5
|
-
import {
|
|
6
|
-
notificationTemplateCodes,
|
|
7
|
-
platformAuthManifest,
|
|
8
|
-
resourceCodes,
|
|
9
|
-
resourceDefinitions,
|
|
10
|
-
} from '../../../packages/contracts/src/generated.js';
|
|
11
|
-
|
|
12
|
-
test('clean template contains application declarations, document reset and one React entry', () => {
|
|
13
|
-
const config = readFileSync(
|
|
14
|
-
new URL('../../../openxiangda.config.ts', import.meta.url),
|
|
15
|
-
'utf8'
|
|
16
|
-
);
|
|
17
|
-
const source = readFileSync(new URL('../src/main.tsx', import.meta.url), 'utf8');
|
|
18
|
-
const productionSources = readdirSync(new URL('../src', import.meta.url), {
|
|
19
|
-
withFileTypes: true,
|
|
20
|
-
})
|
|
21
|
-
.filter(entry => entry.isFile())
|
|
22
|
-
.map(entry => entry.name)
|
|
23
|
-
.sort();
|
|
24
|
-
assert.deepEqual(productionSources, ['document.css', 'main.tsx']);
|
|
25
|
-
assert.deepEqual(Object.keys(resourceDefinitions).sort(), [...resourceCodes].sort());
|
|
26
|
-
assert.equal(
|
|
27
|
-
notificationTemplateCodes.applicationInformational,
|
|
28
|
-
'application.informational.standard'
|
|
29
|
-
);
|
|
30
|
-
assert.equal(platformAuthManifest?.protectedUserRouteCount, 2);
|
|
31
|
-
assert.equal(platformAuthManifest?.surfaces.length, 2);
|
|
32
|
-
assert.match(config, /defineOpenXiangdaApp/);
|
|
33
|
-
assert.match(source, /OpenXiangdaApplication/);
|
|
34
|
-
assert.match(source, /routes: appRoutes, authenticationSurfaces/);
|
|
35
|
-
assert.match(source, /DefaultDesktopApplicationLoginSurface/);
|
|
36
|
-
assert.match(source, /DefaultMobileApplicationLoginSurface/);
|
|
37
|
-
assert.match(source, /contributions=\{applicationContributions\}/);
|
|
38
|
-
assert.match(source, /publicAccess=\{anonymousPublicAccess\}/);
|
|
39
|
-
assert.match(source, /from 'openxiangda\/react'/);
|
|
40
|
-
assert.match(source, /openxiangda\/react\/styles\.css/);
|
|
41
|
-
const legacyMarkers = [
|
|
42
|
-
'instruments',
|
|
43
|
-
'colleges',
|
|
44
|
-
'仪器' + '资源管理',
|
|
45
|
-
'学院' + '字典',
|
|
46
|
-
'HGY',
|
|
47
|
-
'Instrument',
|
|
48
|
-
];
|
|
49
|
-
assert.doesNotMatch(`${config}\n${source}`, new RegExp(legacyMarkers.join('|')));
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('application manifests expose one direct OpenXiangda dependency', () => {
|
|
53
|
-
for (const relative of [
|
|
54
|
-
'../../../package.json',
|
|
55
|
-
'../package.json',
|
|
56
|
-
...(existsSync(new URL('../../server/package.json', import.meta.url)) ? ['../../server/package.json'] : []),
|
|
57
|
-
]) {
|
|
58
|
-
const manifest = JSON.parse(
|
|
59
|
-
readFileSync(new URL(relative, import.meta.url), 'utf8')
|
|
60
|
-
) as Record<string, Record<string, string>>;
|
|
61
|
-
const dependencies = Object.entries({
|
|
62
|
-
...(manifest.dependencies || {}),
|
|
63
|
-
...(manifest.devDependencies || {}),
|
|
64
|
-
...(manifest.peerDependencies || {}),
|
|
65
|
-
}).filter(([name]) =>
|
|
66
|
-
name === 'openxiangda' || name.startsWith('openxiangda-')
|
|
67
|
-
);
|
|
68
|
-
assert.deepEqual(
|
|
69
|
-
dependencies.map(([name]) => name),
|
|
70
|
-
dependencies.length ? ['openxiangda'] : []
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('runtime metadata stays mount-scoped', () => {
|
|
76
|
-
const mount = readRuntimeMount(
|
|
77
|
-
name =>
|
|
78
|
-
({
|
|
79
|
-
'openxiangda-runtime-base': '/view/example-app/',
|
|
80
|
-
'openxiangda-app-code': 'example-app',
|
|
81
|
-
'openxiangda-environment': 'preproduction',
|
|
82
|
-
})[name]
|
|
83
|
-
);
|
|
84
|
-
assert.equal(resolveApplicationBasename(mount), '/view/example-app');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test('resource E2E harness owns the standard export download response', () => {
|
|
88
|
-
const source = readFileSync(
|
|
89
|
-
new URL('../e2e/resource-platform-mock.ts', import.meta.url),
|
|
90
|
-
'utf8'
|
|
91
|
-
);
|
|
92
|
-
assert.match(source, /\/native\\\/data\\\/\(\[\^\/\]\+\)\\\/export\$/);
|
|
93
|
-
assert.match(source, /content-disposition/);
|
|
94
|
-
assert.match(source, /text\/csv/);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('published E2E harnesses do not write evidence into the platform source repository', () => {
|
|
98
|
-
const workflowSource = readFileSync(
|
|
99
|
-
new URL('../e2e/workflow.spec.ts', import.meta.url),
|
|
100
|
-
'utf8'
|
|
101
|
-
);
|
|
102
|
-
assert.doesNotMatch(workflowSource, /docs\/architecture|evidenceDirectory/);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test('E2E experience fixtures explicitly own every tested route', () => {
|
|
106
|
-
const resourceFixture = readFileSync(
|
|
107
|
-
new URL('../e2e/resource-experience-fixture.tsx', import.meta.url),
|
|
108
|
-
'utf8'
|
|
109
|
-
);
|
|
110
|
-
for (let index = 1; index <= 12; index += 1) {
|
|
111
|
-
const code = `resource-${String(index).padStart(2, '0')}`;
|
|
112
|
-
const pageCode = `resource:${code}:list`;
|
|
113
|
-
assert.match(resourceFixture, new RegExp(`pageCode: '${pageCode}'`));
|
|
114
|
-
assert.match(resourceFixture, new RegExp(`code: '${pageCode}'`));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const workflowFixture = readFileSync(
|
|
118
|
-
new URL('../e2e/workflow-experience-fixture.tsx', import.meta.url),
|
|
119
|
-
'utf8'
|
|
120
|
-
);
|
|
121
|
-
assert.match(workflowFixture, /code: 'workflow:work-center'/);
|
|
122
|
-
assert.match(workflowFixture, /code: 'workflow:task'/);
|
|
123
|
-
assert.match(workflowFixture, /code: 'workflow:instance'/);
|
|
124
|
-
assert.match(workflowFixture, /path: '\/work-center'/);
|
|
125
|
-
assert.match(workflowFixture, /path: '\/tasks\/:taskId'/);
|
|
126
|
-
assert.match(workflowFixture, /path: '\/workflows\/:instanceId'/);
|
|
127
|
-
assert.doesNotMatch(
|
|
128
|
-
workflowFixture,
|
|
129
|
-
/path: '\/(?:m\/)?admin\/(?:todos|work-center|tasks|workflows)/
|
|
130
|
-
);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test('browser acceptance serializes the prewarmed Vite HTML entrypoints', () => {
|
|
134
|
-
const viteConfig = readFileSync(new URL('../vite.config.ts', import.meta.url), 'utf8');
|
|
135
|
-
const playwrightConfig = readFileSync(
|
|
136
|
-
new URL('../playwright.config.ts', import.meta.url),
|
|
137
|
-
'utf8'
|
|
138
|
-
);
|
|
139
|
-
const htmlEntries = readdirSync(new URL('..', import.meta.url))
|
|
140
|
-
.filter(name => name.endsWith('.e2e.html'))
|
|
141
|
-
.sort();
|
|
142
|
-
assert.deepEqual(htmlEntries, [
|
|
143
|
-
'data-api-live.e2e.html',
|
|
144
|
-
'field-protocol.e2e.html',
|
|
145
|
-
'mobile-reference.e2e.html',
|
|
146
|
-
'resource-experience.e2e.html',
|
|
147
|
-
'workflow-entry.e2e.html',
|
|
148
|
-
'workflow-experience.e2e.html',
|
|
149
|
-
]);
|
|
150
|
-
for (const entry of htmlEntries) {
|
|
151
|
-
assert.ok(viteConfig.includes(`'${entry}'`), `missing optimizeDeps entry ${entry}`);
|
|
152
|
-
}
|
|
153
|
-
assert.match(playwrightConfig, /workers:\s*1/);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
test('the platform package owns Web build verification policy', () => {
|
|
157
|
-
const verifier = readFileSync(
|
|
158
|
-
new URL('../scripts/verify-build.mjs', import.meta.url),
|
|
159
|
-
'utf8'
|
|
160
|
-
);
|
|
161
|
-
assert.match(verifier, /verifyOpenXiangdaWebBuild/);
|
|
162
|
-
assert.doesNotMatch(verifier, /2_650_000|800_000|600_000/);
|
|
163
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<meta name="openxiangda-runtime-base" content="/" />
|
|
7
|
-
<meta name="openxiangda-app-code" content="openxiangda-application" />
|
|
8
|
-
<meta name="openxiangda-environment" content="preproduction" />
|
|
9
|
-
<title>Workflow entry acceptance</title>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div id="root"></div>
|
|
13
|
-
<script type="module" src="/e2e/workflow-entry-fixture.tsx"></script>
|
|
14
|
-
</body>
|
|
15
|
-
</html>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<meta name="openxiangda-runtime-base" content="/" />
|
|
7
|
-
<meta name="openxiangda-app-code" content="openxiangda-application" />
|
|
8
|
-
<meta name="openxiangda-environment" content="preproduction" />
|
|
9
|
-
<title>Workflow experience acceptance</title>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div id="root"></div>
|
|
13
|
-
<script type="module" src="/e2e/workflow-experience-fixture.tsx"></script>
|
|
14
|
-
</body>
|
|
15
|
-
</html>
|