@adcops/autocore-react 3.5.7 → 3.5.11
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/components/forms/useEditDraft.d.ts +49 -0
- package/dist/components/forms/useEditDraft.d.ts.map +1 -0
- package/dist/components/forms/useEditDraft.js +1 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/tis/TestDataView.d.ts +8 -0
- package/dist/components/tis/TestDataView.d.ts.map +1 -1
- package/dist/components/tis/TestDataView.js +1 -1
- package/dist/components/tis/TestRawDataView.d.ts.map +1 -1
- package/dist/components/tis/TestRawDataView.js +1 -1
- package/dist/components/tis/chartViews.d.ts +57 -0
- package/dist/components/tis/chartViews.d.ts.map +1 -0
- package/dist/components/tis/chartViews.js +1 -0
- package/dist/components/tis-editor/TisConfigEditor.css +11 -0
- package/dist/components/tis-editor/TisConfigEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/TisConfigEditor.js +1 -1
- package/dist/components/tis-editor/editor/AuthoringContext.d.ts +37 -0
- package/dist/components/tis-editor/editor/AuthoringContext.d.ts.map +1 -0
- package/dist/components/tis-editor/editor/AuthoringContext.js +1 -0
- package/dist/components/tis-editor/editor/ChartViewDialog.d.ts +11 -0
- package/dist/components/tis-editor/editor/ChartViewDialog.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/ChartViewDialog.js +1 -1
- package/dist/components/tis-editor/editor/FieldArrayEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/FieldArrayEditor.js +1 -1
- package/dist/components/tis-editor/editor/RawDataEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/RawDataEditor.js +1 -1
- package/dist/components/tis-editor/editor/TestFieldDialog.d.ts +7 -0
- package/dist/components/tis-editor/editor/TestFieldDialog.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/TestFieldDialog.js +1 -1
- package/dist/components/tis-editor/editor/ViewsEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/ViewsEditor.js +1 -1
- package/dist/components/tis-editor/types.d.ts +6 -0
- package/dist/components/tis-editor/types.d.ts.map +1 -1
- package/dist/components/varpick/VariableInput.d.ts +41 -0
- package/dist/components/varpick/VariableInput.d.ts.map +1 -0
- package/dist/components/varpick/VariableInput.js +1 -0
- package/dist/components/varpick/VariablePicker.d.ts +45 -0
- package/dist/components/varpick/VariablePicker.d.ts.map +1 -0
- package/dist/components/varpick/VariablePicker.js +1 -0
- package/dist/components/varpick/index.d.ts +16 -0
- package/dist/components/varpick/index.d.ts.map +1 -0
- package/dist/components/varpick/index.js +1 -0
- package/dist/components/varpick/tisCatalogs.d.ts +85 -0
- package/dist/components/varpick/tisCatalogs.d.ts.map +1 -0
- package/dist/components/varpick/tisCatalogs.js +1 -0
- package/dist/components/varpick/varpick.css +167 -0
- package/dist/core/AutoCoreTagContext.d.ts.map +1 -1
- package/dist/core/AutoCoreTagContext.js +1 -1
- package/dist/core/AutoCoreTagTypes.d.ts +13 -0
- package/dist/core/AutoCoreTagTypes.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useGmVariables.d.ts +57 -0
- package/dist/hooks/useGmVariables.d.ts.map +1 -0
- package/dist/hooks/useGmVariables.js +1 -0
- package/dist/hooks/useSequenceProducers.d.ts +38 -0
- package/dist/hooks/useSequenceProducers.d.ts.map +1 -0
- package/dist/hooks/useSequenceProducers.js +1 -0
- package/package.json +7 -2
- package/src/components/forms/useEditDraft.ts +0 -0
- package/src/components/index.ts +20 -0
- package/src/components/tis/TestDataView.tsx +16 -10
- package/src/components/tis/TestRawDataView.tsx +6 -7
- package/src/components/tis/chartViews.ts +104 -0
- package/src/components/tis-editor/TisConfigEditor.css +11 -0
- package/src/components/tis-editor/TisConfigEditor.tsx +31 -0
- package/src/components/tis-editor/editor/AuthoringContext.tsx +43 -0
- package/src/components/tis-editor/editor/ChartViewDialog.tsx +48 -17
- package/src/components/tis-editor/editor/FieldArrayEditor.tsx +1 -0
- package/src/components/tis-editor/editor/RawDataEditor.tsx +7 -2
- package/src/components/tis-editor/editor/TestFieldDialog.tsx +90 -23
- package/src/components/tis-editor/editor/ViewsEditor.tsx +56 -5
- package/src/components/tis-editor/types.ts +6 -0
- package/src/components/varpick/VariableInput.tsx +126 -0
- package/src/components/varpick/VariablePicker.tsx +168 -0
- package/src/components/varpick/index.ts +22 -0
- package/src/components/varpick/tisCatalogs.ts +235 -0
- package/src/components/varpick/varpick.css +167 -0
- package/src/core/AutoCoreTagContext.tsx +3 -1
- package/src/core/AutoCoreTagTypes.ts +14 -0
- package/src/hooks/index.ts +11 -0
- package/src/hooks/useGmVariables.ts +142 -0
- package/src/hooks/useSequenceProducers.ts +104 -0
- package/tools/tests/dist/TestFieldDialog-C4mKVh7q.js +32817 -0
- package/tools/tests/dist/autocore-react.css +257 -0
- package/tools/tests/dist/tis-editor.entry.js +9295 -0
- package/tools/tests/dist/varpick.entry.js +113 -0
- package/tools/tests/live-server.probe.mjs +172 -0
- package/tools/tests/tis-editor.entry.tsx +46 -0
- package/tools/tests/tis-editor.test.mjs +133 -0
- package/tools/tests/varpick.entry.tsx +81 -0
- package/tools/tests/varpick.test.mjs +208 -0
- package/tools/tests/vite.config.mjs +35 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Variable-picker regression test — `npm run test:varpick`.
|
|
3
|
+
*
|
|
4
|
+
* Two halves:
|
|
5
|
+
*
|
|
6
|
+
* 1. The catalogs. Each field in the method editor wants a different list,
|
|
7
|
+
* spelled differently, and every way of getting it wrong fails SILENTLY —
|
|
8
|
+
* a `source` that names nothing never binds, a bound that resolves to
|
|
9
|
+
* nothing is simply unlimited, a cycle column with no producer is blank on
|
|
10
|
+
* every row forever.
|
|
11
|
+
* 2. The dialog, driven end to end in jsdom: open the picker, search, select,
|
|
12
|
+
* Insert, and check what landed in the field. That is the part a unit test
|
|
13
|
+
* of the model cannot cover — it is where the spelling is chosen.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { JSDOM } from 'jsdom';
|
|
17
|
+
|
|
18
|
+
const dom = new JSDOM('<!doctype html><html><body><div id="root"></div></body></html>', {
|
|
19
|
+
url: 'http://localhost/', pretendToBeVisual: true,
|
|
20
|
+
});
|
|
21
|
+
global.window = dom.window;
|
|
22
|
+
global.document = dom.window.document;
|
|
23
|
+
Object.defineProperty(global, 'navigator', { value: dom.window.navigator, configurable: true });
|
|
24
|
+
global.HTMLElement = dom.window.HTMLElement;
|
|
25
|
+
global.Element = dom.window.Element;
|
|
26
|
+
global.Node = dom.window.Node;
|
|
27
|
+
global.Event = dom.window.Event;
|
|
28
|
+
global.KeyboardEvent = dom.window.KeyboardEvent;
|
|
29
|
+
global.MouseEvent = dom.window.MouseEvent;
|
|
30
|
+
global.getComputedStyle = dom.window.getComputedStyle;
|
|
31
|
+
global.requestAnimationFrame = (cb) => setTimeout(() => cb(Date.now()), 0);
|
|
32
|
+
global.cancelAnimationFrame = (id) => clearTimeout(id);
|
|
33
|
+
global.IS_REACT_ACT_ENVIRONMENT = true;
|
|
34
|
+
dom.window.IS_REACT_ACT_ENVIRONMENT = true;
|
|
35
|
+
global.matchMedia = dom.window.matchMedia ?? (() => ({
|
|
36
|
+
matches: false, addListener() {}, removeListener() {},
|
|
37
|
+
addEventListener() {}, removeEventListener() {},
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
await import('./dist/varpick.entry.js');
|
|
41
|
+
const { act } = await import('react');
|
|
42
|
+
|
|
43
|
+
const tick = async () => { await act(async () => { await new Promise(r => setTimeout(r, 20)); }); };
|
|
44
|
+
|
|
45
|
+
let passed = 0;
|
|
46
|
+
const check = (name, got, want) => {
|
|
47
|
+
const g = JSON.stringify(got);
|
|
48
|
+
const w = JSON.stringify(want);
|
|
49
|
+
if (g === w) { passed++; console.log(`PASS ${name}: ${g}`); }
|
|
50
|
+
else { console.error(`FAIL ${name}\n got ${g}\n want ${w}`); process.exitCode = 1; }
|
|
51
|
+
};
|
|
52
|
+
const ok = (name, cond, detail = '') => {
|
|
53
|
+
if (cond) { passed++; console.log(`PASS ${name}`); }
|
|
54
|
+
else { console.error(`FAIL ${name} ${detail}`); process.exitCode = 1; }
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// ── 1. the catalogs ─────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
const C = window.__catalogs;
|
|
60
|
+
const ctx = { variables: C.VARIABLES, unitFor: (q) => ({ position: 'mm', force: 'N' })[q] };
|
|
61
|
+
const flat = (cat) => cat.flatMap(g => g.entries);
|
|
62
|
+
const inserts = (cat) => flat(cat).map(e => e.insert);
|
|
63
|
+
const groupIds = (cat) => cat.map(g => g.id);
|
|
64
|
+
|
|
65
|
+
{
|
|
66
|
+
// A config field's Source is WRITTEN by the setup form, so a variable a
|
|
67
|
+
// module republishes every scan must not be offered: the operator's entry
|
|
68
|
+
// would be overwritten before anything read it.
|
|
69
|
+
const cat = C.configSourceCatalog(ctx);
|
|
70
|
+
check('config source omits hardware-owned variables', inserts(cat),
|
|
71
|
+
['gm.press_preload_n', 'gm.press_force_min_n']);
|
|
72
|
+
ok('config source spells an FQDN', inserts(cat).every(i => i.startsWith('gm.')));
|
|
73
|
+
|
|
74
|
+
const bounds = C.boundCatalog(ctx);
|
|
75
|
+
check('a bound is spelled as a token', inserts(bounds).slice(0, 1), ['${gm.press_position}']);
|
|
76
|
+
ok('a bound may read a hardware-owned variable',
|
|
77
|
+
inserts(bounds).includes('${gm.press_position}'));
|
|
78
|
+
check('units come from the machine, not the name',
|
|
79
|
+
flat(bounds).find(e => e.name === 'press_position').unit, 'mm');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
{
|
|
83
|
+
// The two-producer case. A cycle field on gen4_ac is filled by a
|
|
84
|
+
// `store_value` matched by NAME, with `source` left empty — so a picker
|
|
85
|
+
// that only offered FQDNs would wire a binding that never fills.
|
|
86
|
+
const cat = C.cycleSourceCatalog(ctx, { producedNames: C.PRODUCED, fieldName: 'preload_load' });
|
|
87
|
+
check('the sequence is offered first', groupIds(cat)[0], 'sequence');
|
|
88
|
+
ok('GM variables are still offered', groupIds(cat).includes('measured'));
|
|
89
|
+
|
|
90
|
+
const seq = cat[0].entries;
|
|
91
|
+
check('choosing a sequence value CLEARS the source', seq.map(e => e.insert), ['', '', '']);
|
|
92
|
+
check('the matching name is called out',
|
|
93
|
+
seq.find(e => e.name === 'preload_load').note, undefined);
|
|
94
|
+
ok('a mismatched name says what to do',
|
|
95
|
+
/Rename this field to "test_load"/.test(seq.find(e => e.name === 'test_load').note),
|
|
96
|
+
seq.find(e => e.name === 'test_load').note);
|
|
97
|
+
|
|
98
|
+
// No sequence read → no group, rather than an empty one claiming nothing
|
|
99
|
+
// produces anything.
|
|
100
|
+
const none = C.cycleSourceCatalog(ctx, {});
|
|
101
|
+
ok('an unread sequence adds no group', !groupIds(none).includes('sequence'));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
{
|
|
105
|
+
const raw = C.chartFieldCatalog({
|
|
106
|
+
viewType: 'raw_trace', rawColumns: ['t', 'force'], cycleFields: ['peak'], resultsFields: [],
|
|
107
|
+
});
|
|
108
|
+
check('a raw_trace offers trace columns first', groupIds(raw), ['raw', 'cycle']);
|
|
109
|
+
const scatter = C.chartFieldCatalog({
|
|
110
|
+
viewType: 'cycle_scatter', rawColumns: ['t'], cycleFields: ['peak'], testFields: ['operator'],
|
|
111
|
+
});
|
|
112
|
+
check('a cycle_scatter offers cycle columns first', groupIds(scatter), ['cycle', 'raw', 'test']);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
{
|
|
116
|
+
// A repeated measurement lives inside a `cycle` body, so a walk that
|
|
117
|
+
// stopped at the top level would miss the methods that record the most.
|
|
118
|
+
const method = {
|
|
119
|
+
steps: [
|
|
120
|
+
{ type: 'store_value', name: 'a', expr: 'x' },
|
|
121
|
+
{ type: 'cycle', count: '3', body: [{ type: 'store_value', name: 'b', expr: 'y' }] },
|
|
122
|
+
{ type: 'store_value', name: 'a', expr: 'z' },
|
|
123
|
+
{ type: 'store_value', name: '', expr: 'q' },
|
|
124
|
+
{ type: 'push_row' },
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
check('stored names include cycle bodies, deduped, blanks dropped',
|
|
128
|
+
C.collectStoredNames(method), ['a', 'b']);
|
|
129
|
+
check('a non-method reads as no names', C.collectStoredNames({ steps: null }), []);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ── 2. the dialog, end to end ───────────────────────────────────────────────
|
|
133
|
+
|
|
134
|
+
await act(async () => { window.__mount(); });
|
|
135
|
+
await tick();
|
|
136
|
+
|
|
137
|
+
const q = (sel) => [...document.querySelectorAll(sel)];
|
|
138
|
+
const dialogs = () => q('.p-dialog');
|
|
139
|
+
const rowLabelled = (label) =>
|
|
140
|
+
q('.ac-formrow').find(r => r.querySelector('.ac-formrow__label')?.textContent?.startsWith(label));
|
|
141
|
+
const inputIn = (label) => rowLabelled(label)?.querySelector('input');
|
|
142
|
+
const pickerButtonIn = (label) => rowLabelled(label)?.querySelector('button');
|
|
143
|
+
const setValue = (el, v) => {
|
|
144
|
+
const desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(el), 'value');
|
|
145
|
+
desc.set.call(el, v);
|
|
146
|
+
el.dispatchEvent(new dom.window.Event('input', { bubbles: true }));
|
|
147
|
+
};
|
|
148
|
+
const click = async (el) => {
|
|
149
|
+
await act(async () => { el.dispatchEvent(new dom.window.MouseEvent('click', { bubbles: true })); });
|
|
150
|
+
await tick();
|
|
151
|
+
};
|
|
152
|
+
/** The picker dialog is the last one opened, over the field dialog. */
|
|
153
|
+
const picker = () => dialogs().at(-1);
|
|
154
|
+
const pickerRows = () => [...picker().querySelectorAll('.ac-varpick__row')];
|
|
155
|
+
const buttonLabelled = (root, text) =>
|
|
156
|
+
[...root.querySelectorAll('button')].find(b => b.textContent?.trim() === text);
|
|
157
|
+
|
|
158
|
+
ok('every field dialog input still renders', inputIn('Source') !== undefined);
|
|
159
|
+
ok('Source has a picker button',
|
|
160
|
+
pickerButtonIn('Source')?.getAttribute('aria-label') === 'Choose a source for this field');
|
|
161
|
+
|
|
162
|
+
// -- a cycle field picks a SEQUENCE producer, which clears Source ------------
|
|
163
|
+
setValue(inputIn('Source'), 'gm.stale_binding');
|
|
164
|
+
await tick();
|
|
165
|
+
check('typing still works', inputIn('Source').value, 'gm.stale_binding');
|
|
166
|
+
|
|
167
|
+
await click(pickerButtonIn('Source'));
|
|
168
|
+
ok('the picker opened', dialogs().length > 1, `dialogs=${dialogs().length}`);
|
|
169
|
+
ok('the sequence group is present',
|
|
170
|
+
picker().textContent.includes('Recorded by the sequence'));
|
|
171
|
+
|
|
172
|
+
const preloadRow = pickerRows().find(r => r.querySelector('code')?.textContent === 'preload_load');
|
|
173
|
+
ok('the matching produced name is listed', preloadRow !== undefined);
|
|
174
|
+
await click(preloadRow);
|
|
175
|
+
await click(buttonLabelled(picker(), 'Insert'));
|
|
176
|
+
check('picking a sequence producer clears Source', inputIn('Source').value, '');
|
|
177
|
+
|
|
178
|
+
// -- a bound picks a token --------------------------------------------------
|
|
179
|
+
await click(pickerButtonIn('Min'));
|
|
180
|
+
const searchBox = picker().querySelector('.ac-varpick__search');
|
|
181
|
+
setValue(searchBox, 'lower force bound');
|
|
182
|
+
await tick();
|
|
183
|
+
check('a variable is findable by what it MEANS',
|
|
184
|
+
pickerRows().map(r => r.querySelector('code').textContent), ['press_force_min_n']);
|
|
185
|
+
await click(pickerRows()[0]);
|
|
186
|
+
await click(buttonLabelled(picker(), 'Insert'));
|
|
187
|
+
check('a bound is inserted as a token', inputIn('Min').value, '${gm.press_force_min_n}');
|
|
188
|
+
|
|
189
|
+
// -- the saved field carries both -------------------------------------------
|
|
190
|
+
const dialogRoot = dialogs()[0];
|
|
191
|
+
await click(buttonLabelled(dialogRoot, 'Save'));
|
|
192
|
+
const saved = window.__saved();
|
|
193
|
+
ok('the field saved', saved !== null);
|
|
194
|
+
check('source stayed cleared', saved?.source, undefined);
|
|
195
|
+
check('min saved as a token', saved?.min, '${gm.press_force_min_n}');
|
|
196
|
+
|
|
197
|
+
// -- a config field offers only writable variables ---------------------------
|
|
198
|
+
await act(async () => { window.__setArray('config_fields'); });
|
|
199
|
+
await tick();
|
|
200
|
+
await click(pickerButtonIn('Source'));
|
|
201
|
+
ok('a config field is not offered the sequence',
|
|
202
|
+
!picker().textContent.includes('Recorded by the sequence'));
|
|
203
|
+
ok('a config field is not offered a hardware-owned variable',
|
|
204
|
+
!pickerRows().some(r => r.querySelector('code')?.textContent === 'press_position'),
|
|
205
|
+
pickerRows().map(r => r.querySelector('code')?.textContent).join(','));
|
|
206
|
+
|
|
207
|
+
console.log(`\nvarpick: ${passed} checks passed`);
|
|
208
|
+
if (process.exitCode) console.error('varpick: FAILURES');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundles the TIS-editor regression entry for the jsdom run.
|
|
3
|
+
*
|
|
4
|
+
* Points at `src`, not `dist`, so a failure names a real source line, and
|
|
5
|
+
* bundles React/PrimeReact in so the jsdom run has exactly one copy of React.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { defineConfig } from 'vite';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import { dirname, resolve } from 'node:path';
|
|
11
|
+
|
|
12
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
|
|
14
|
+
export default defineConfig({
|
|
15
|
+
root: here,
|
|
16
|
+
build: {
|
|
17
|
+
outDir: resolve(here, 'dist'),
|
|
18
|
+
emptyOutDir: true,
|
|
19
|
+
lib: {
|
|
20
|
+
// Named entries so each test file imports its own bundle by name;
|
|
21
|
+
// shared code (React, PrimeReact) is hoisted into one chunk, which
|
|
22
|
+
// is what keeps a single copy of React in the jsdom run.
|
|
23
|
+
entry: {
|
|
24
|
+
'tis-editor.entry': resolve(here, 'tis-editor.entry.tsx'),
|
|
25
|
+
'varpick.entry': resolve(here, 'varpick.entry.tsx'),
|
|
26
|
+
},
|
|
27
|
+
formats: ['es'],
|
|
28
|
+
},
|
|
29
|
+
minify: false,
|
|
30
|
+
target: 'node20',
|
|
31
|
+
},
|
|
32
|
+
// PrimeReact and React both branch on this; the development build gives
|
|
33
|
+
// the act() warnings that catch an un-awaited state update.
|
|
34
|
+
define: { 'process.env.NODE_ENV': '"development"' },
|
|
35
|
+
});
|