@things-factory/figure-ui 10.1.147 → 10.1.150
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/client/bootstrap.ts +10 -2
- package/client/graphql/index.ts +20 -0
- package/client/modeller/canvas.ts +6 -2
- package/client/modeller/carrier-declaration.ts +63 -0
- package/client/modeller/editor.ts +62 -27
- package/client/modeller/figure-carrier.ts +117 -0
- package/client/modeller/figure-cavity-drawing.ts +3 -9
- package/client/modeller/figure-first-save.ts +4 -7
- package/client/modeller/figure-history-panel.ts +2 -3
- package/client/modeller/figure-links.ts +46 -60
- package/client/modeller/figure-material-panel.ts +4 -14
- package/client/modeller/figure-mesh-choice.ts +68 -0
- package/client/modeller/figure-parts.ts +23 -1
- package/client/modeller/figure-preview.ts +2 -2
- package/client/modeller/figure-properties.ts +5 -3
- package/client/modeller/figure-section-editor.ts +12 -33
- package/client/modeller/figure-section-panel.ts +6 -7
- package/client/modeller/figure-slot-layout-panel.ts +208 -0
- package/client/modeller/figure-verdict.ts +21 -31
- package/client/modeller/first-save.ts +23 -0
- package/client/modeller/links.ts +52 -1
- package/client/modeller/material-edit.ts +38 -0
- package/client/modeller/maturity.ts +28 -0
- package/client/modeller/mesh-import.ts +77 -0
- package/client/modeller/modeller-route.ts +9 -0
- package/client/modeller/mounting-part.ts +15 -0
- package/client/modeller/newest-answer.ts +21 -0
- package/client/modeller/preview-model.ts +5 -0
- package/client/modeller/refusals.ts +168 -82
- package/client/modeller/section-controls.ts +25 -1
- package/client/modeller/section-drawing.ts +43 -1
- package/client/modeller/slot-layout-host.ts +140 -0
- package/client/pages/figure-modeller-page.ts +6 -5
- package/client/viewparts/detail-route.ts +7 -0
- package/client/viewparts/figure-detail-dock.ts +1 -3
- package/dist-client/bootstrap.d.ts +1 -1
- package/dist-client/bootstrap.js +9 -2
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/graphql/index.d.ts +5 -0
- package/dist-client/graphql/index.js +19 -0
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/modeller/canvas.d.ts +2 -0
- package/dist-client/modeller/canvas.js +10 -2
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/carrier-declaration.d.ts +31 -0
- package/dist-client/modeller/carrier-declaration.js +53 -0
- package/dist-client/modeller/carrier-declaration.js.map +1 -0
- package/dist-client/modeller/editor.d.ts +13 -0
- package/dist-client/modeller/editor.js +62 -27
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-carrier.d.ts +26 -0
- package/dist-client/modeller/figure-carrier.js +123 -0
- package/dist-client/modeller/figure-carrier.js.map +1 -0
- package/dist-client/modeller/figure-cavity-drawing.js +3 -11
- package/dist-client/modeller/figure-cavity-drawing.js.map +1 -1
- package/dist-client/modeller/figure-first-save.d.ts +4 -0
- package/dist-client/modeller/figure-first-save.js +5 -8
- package/dist-client/modeller/figure-first-save.js.map +1 -1
- package/dist-client/modeller/figure-history-panel.js +2 -4
- package/dist-client/modeller/figure-history-panel.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +4 -1
- package/dist-client/modeller/figure-links.js +47 -57
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-material-panel.d.ts +0 -1
- package/dist-client/modeller/figure-material-panel.js +4 -14
- package/dist-client/modeller/figure-material-panel.js.map +1 -1
- package/dist-client/modeller/figure-mesh-choice.d.ts +16 -0
- package/dist-client/modeller/figure-mesh-choice.js +75 -0
- package/dist-client/modeller/figure-mesh-choice.js.map +1 -0
- package/dist-client/modeller/figure-parts.d.ts +1 -1
- package/dist-client/modeller/figure-parts.js +22 -0
- package/dist-client/modeller/figure-parts.js.map +1 -1
- package/dist-client/modeller/figure-preview.js +2 -2
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-properties.d.ts +2 -1
- package/dist-client/modeller/figure-properties.js +5 -3
- package/dist-client/modeller/figure-properties.js.map +1 -1
- package/dist-client/modeller/figure-section-editor.d.ts +2 -2
- package/dist-client/modeller/figure-section-editor.js +12 -33
- package/dist-client/modeller/figure-section-editor.js.map +1 -1
- package/dist-client/modeller/figure-section-panel.js +6 -7
- package/dist-client/modeller/figure-section-panel.js.map +1 -1
- package/dist-client/modeller/figure-slot-layout-panel.d.ts +36 -0
- package/dist-client/modeller/figure-slot-layout-panel.js +198 -0
- package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -0
- package/dist-client/modeller/figure-verdict.d.ts +1 -1
- package/dist-client/modeller/figure-verdict.js +19 -37
- package/dist-client/modeller/figure-verdict.js.map +1 -1
- package/dist-client/modeller/first-save.d.ts +10 -0
- package/dist-client/modeller/first-save.js +16 -0
- package/dist-client/modeller/first-save.js.map +1 -1
- package/dist-client/modeller/links.d.ts +26 -1
- package/dist-client/modeller/links.js +43 -0
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/material-edit.d.ts +11 -0
- package/dist-client/modeller/material-edit.js +28 -0
- package/dist-client/modeller/material-edit.js.map +1 -0
- package/dist-client/modeller/maturity.d.ts +15 -0
- package/dist-client/modeller/maturity.js +23 -0
- package/dist-client/modeller/maturity.js.map +1 -1
- package/dist-client/modeller/mesh-import.d.ts +47 -0
- package/dist-client/modeller/mesh-import.js +47 -0
- package/dist-client/modeller/mesh-import.js.map +1 -0
- package/dist-client/modeller/modeller-route.d.ts +5 -0
- package/dist-client/modeller/modeller-route.js +9 -0
- package/dist-client/modeller/modeller-route.js.map +1 -1
- package/dist-client/modeller/mounting-part.d.ts +14 -0
- package/dist-client/modeller/mounting-part.js +10 -0
- package/dist-client/modeller/mounting-part.js.map +1 -0
- package/dist-client/modeller/newest-answer.d.ts +12 -0
- package/dist-client/modeller/newest-answer.js +21 -0
- package/dist-client/modeller/newest-answer.js.map +1 -0
- package/dist-client/modeller/preview-model.d.ts +2 -0
- package/dist-client/modeller/preview-model.js +4 -0
- package/dist-client/modeller/preview-model.js.map +1 -1
- package/dist-client/modeller/refusals.d.ts +26 -5
- package/dist-client/modeller/refusals.js +184 -86
- package/dist-client/modeller/refusals.js.map +1 -1
- package/dist-client/modeller/section-controls.d.ts +17 -1
- package/dist-client/modeller/section-controls.js +18 -0
- package/dist-client/modeller/section-controls.js.map +1 -1
- package/dist-client/modeller/section-drawing.d.ts +24 -1
- package/dist-client/modeller/section-drawing.js +42 -0
- package/dist-client/modeller/section-drawing.js.map +1 -1
- package/dist-client/modeller/slot-layout-host.d.ts +81 -0
- package/dist-client/modeller/slot-layout-host.js +105 -0
- package/dist-client/modeller/slot-layout-host.js.map +1 -0
- package/dist-client/pages/figure-modeller-page.js +5 -4
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/detail-route.d.ts +5 -0
- package/dist-client/viewparts/detail-route.js +8 -0
- package/dist-client/viewparts/detail-route.js.map +1 -0
- package/dist-client/viewparts/figure-detail-dock.d.ts +0 -1
- package/dist-client/viewparts/figure-detail-dock.js +1 -3
- package/dist-client/viewparts/figure-detail-dock.js.map +1 -1
- package/package.json +9 -8
- package/test/align.test.ts +0 -9
- package/test/browser/assistant-stand-in.js +32 -0
- package/test/browser/build.check.mjs +77 -0
- package/test/browser/build.mjs +31 -6
- package/test/browser/editing-page.js +224 -0
- package/test/browser/editing.check.mjs +550 -0
- package/test/browser/links-page.js +113 -0
- package/test/browser/links.check.mjs +568 -0
- package/test/browser/modeller.check.mjs +21 -0
- package/test/browser/parts-page.js +120 -0
- package/test/browser/parts.check.mjs +328 -0
- package/test/browser/places-mesh-page.js +36 -0
- package/test/browser/places-mesh.check.mjs +239 -0
- package/test/browser/product-page.check.mjs +682 -0
- package/test/browser/product-page.js +276 -0
- package/test/browser/screen-page.js +112 -0
- package/test/browser/screen-product-page.js +62 -0
- package/test/browser/screen.check.mjs +1003 -0
- package/test/browser/section-page.js +256 -0
- package/test/browser/section.check.mjs +719 -0
- package/test/browser/serve.mjs +20 -12
- package/test/carrier-declaration.test.ts +69 -0
- package/test/cavity-drawing.test.ts +2 -18
- package/test/clip-ai-proposal.test.ts +1 -5
- package/test/clip-consent.test.ts +0 -5
- package/test/clips.test.ts +0 -7
- package/test/command-preview.test.ts +0 -68
- package/test/controls.test.ts +0 -9
- package/test/detail-dock.test.ts +6 -25
- package/test/face-mapping.test.ts +1 -20
- package/test/fasten-drawing.test.ts +0 -23
- package/test/fields.test.ts +6 -33
- package/test/figure-assistant-surface.test.ts +32 -38
- package/test/first-minute.test.ts +3 -55
- package/test/first-save-suggest.test.ts +11 -8
- package/test/first-save.test.ts +4 -26
- package/test/gizmo.test.ts +0 -25
- package/test/joint-fan.test.ts +0 -10
- package/test/keys.test.ts +0 -7
- package/test/layout.test.ts +4 -73
- package/test/links.test.ts +48 -67
- package/test/live.test.ts +0 -34
- package/test/material.test.ts +17 -26
- package/test/maturity.test.ts +13 -16
- package/test/mesh-import.test.ts +76 -0
- package/test/modeller-route.test.ts +3 -19
- package/test/package-download.test.ts +6 -7
- package/test/parts-wiring.test.ts +9 -51
- package/test/preview.test.ts +5 -46
- package/test/properties.test.ts +11 -26
- package/test/proposal-record.test.ts +2 -19
- package/test/recipes.test.ts +0 -15
- package/test/refusals.test.ts +257 -151
- package/test/release-entry.test.ts +1 -9
- package/test/release-panel.test.ts +1 -22
- package/test/resize-with-placement.test.ts +0 -32
- package/test/revert-choice.test.ts +1 -22
- package/test/revert-keeping.test.ts +1 -12
- package/test/save-landed.test.ts +16 -14
- package/test/scene-canvas.test.ts +2 -13
- package/test/section-editor.test.ts +30 -83
- package/test/section-panel.test.ts +22 -17
- package/test/slot-layout-host.test.ts +117 -0
- package/test/theme.test.ts +5 -9
- package/test/verdict.test.ts +44 -41
- package/test/view.test.ts +5 -12
- package/translations/en.json +61 -1
- package/translations/es.json +61 -1
- package/translations/ja.json +61 -1
- package/translations/ko.json +61 -1
- package/translations/ms.json +61 -1
- package/translations/zh.json +61 -1
- package/test/thumbnail.test.ts +0 -29
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The section editor, the section panel, the inside's drawing, the fastening drawing and the face choice, driven in a
|
|
3
|
+
* real browser (ADR-0100). What the unit suite cannot prove lives here: that a value typed is drawn and not sent, that
|
|
4
|
+
* a command lands as one step, that keys go to the editor and not to the modeller behind it, that a refusal is held
|
|
5
|
+
* where the edit was made. The check does what a person does -- picks a part, presses, drags, types -- and reads what
|
|
6
|
+
* the screen shows and what the session holds.
|
|
7
|
+
*
|
|
8
|
+
* Run: node --test test/browser/section.check.mjs
|
|
9
|
+
*/
|
|
10
|
+
import { test, describe, before, after } from 'node:test'
|
|
11
|
+
import assert from 'node:assert/strict'
|
|
12
|
+
|
|
13
|
+
import { buildPage } from './build.mjs'
|
|
14
|
+
import { openPage } from './serve.mjs'
|
|
15
|
+
|
|
16
|
+
let opened
|
|
17
|
+
before(async () => {
|
|
18
|
+
opened = await openPage(await buildPage('section-page.js'))
|
|
19
|
+
})
|
|
20
|
+
after(async () => {
|
|
21
|
+
await opened?.close()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const page = () => opened.page
|
|
25
|
+
const read = (fn, ...args) => page().evaluate(fn, ...args)
|
|
26
|
+
const state = () => read(() => probe.state())
|
|
27
|
+
const editorNow = () => read(() => probe.sectionEditor())
|
|
28
|
+
const panelNow = () => read(() => probe.sectionPanel())
|
|
29
|
+
const drawn = id => read(id => probe.drawnShape(id), id)
|
|
30
|
+
const held = id => read(id => probe.heldShape(id), id)
|
|
31
|
+
const sleep = ms => new Promise(done => setTimeout(done, ms))
|
|
32
|
+
|
|
33
|
+
/** Waits until `fn` (run in the page) gives something truthy, and gives it; fails with `what` past the deadline. */
|
|
34
|
+
async function until(fn, what, arg, ms = 5000) {
|
|
35
|
+
const end = Date.now() + ms
|
|
36
|
+
for (;;) {
|
|
37
|
+
const got = await page().evaluate(fn, arg)
|
|
38
|
+
if (got) return got
|
|
39
|
+
if (Date.now() > end) assert.fail(`waited for: ${what}`)
|
|
40
|
+
await sleep(50)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** An element on the page (through shadow roots): see `findDeep` in section-page.js. */
|
|
45
|
+
async function element(selector, options = {}) {
|
|
46
|
+
const handle = await page().evaluateHandle((s, o) => findDeep(s, o), selector, options)
|
|
47
|
+
assert.ok(await handle.evaluate(e => !!e), `on the page: ${selector} ${JSON.stringify(options)}`)
|
|
48
|
+
return handle
|
|
49
|
+
}
|
|
50
|
+
const present = (selector, options = {}) => read((s, o) => !!findDeep(s, o), selector, options)
|
|
51
|
+
|
|
52
|
+
async function press(selector, options) {
|
|
53
|
+
await (await element(selector, options)).click()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Types `text` over what a field holds, then a key: Enter sends, Tab leaves, nothing keeps it typed. */
|
|
57
|
+
async function type(selector, options, text, key = 'Enter') {
|
|
58
|
+
const field = await element(selector, options)
|
|
59
|
+
await field.click({ clickCount: 3 })
|
|
60
|
+
await page().keyboard.type(text)
|
|
61
|
+
if (key) await page().keyboard.press(key)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function mount(name) {
|
|
65
|
+
await read(name => sectionHarness.mount(name), name)
|
|
66
|
+
/* Drawn in 3D before anything else: a board taken down while its 3D is still coming up throws in things-scene. */
|
|
67
|
+
await until(
|
|
68
|
+
() => {
|
|
69
|
+
/* Not drawn yet is not an error: until the canvas stands, reading it throws. */
|
|
70
|
+
try {
|
|
71
|
+
return !!probe.state() && probe.ids().some(id => !!probe.partOnPage(id))
|
|
72
|
+
} catch {
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
'the figure drawn in 3D',
|
|
77
|
+
undefined,
|
|
78
|
+
15000
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function pick(id) {
|
|
83
|
+
const at = await until(id => probe.row(id), `${id} in the parts list`, id)
|
|
84
|
+
await page().mouse.click(at.x, at.y)
|
|
85
|
+
await until(id => probe.state().selected === id, `${id} picked`, id)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function openEditor() {
|
|
89
|
+
await press('button[act]', { within: 'figure-section-panel' })
|
|
90
|
+
await until(() => !!probe.sectionEditor(), 'the section editor')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** A point's coordinate field in the section editor, by the number the point is shown by: 0 across, 1 down. */
|
|
94
|
+
async function typePoint(label, axis, text, key = 'Enter') {
|
|
95
|
+
const field = await page().evaluateHandle(
|
|
96
|
+
(label, axis) => [...(findDeep('figure-section-editor')?.shadowRoot.querySelectorAll('ol[points] li') ?? [])].find(li => li.querySelector('b').textContent.trim() === label)?.querySelectorAll('input')[axis] ?? null,
|
|
97
|
+
label,
|
|
98
|
+
axis
|
|
99
|
+
)
|
|
100
|
+
assert.ok(await field.evaluate(e => !!e), `point ${label}'s field`)
|
|
101
|
+
await field.click({ clickCount: 3 })
|
|
102
|
+
await page().keyboard.type(text)
|
|
103
|
+
if (key) await page().keyboard.press(key)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Drags a wall's handle in the inside's drawing in `within` by `dx` page pixels, in steps; `release` lets go. */
|
|
107
|
+
async function dragWall(within, side, dx, release = true) {
|
|
108
|
+
const handle = await element(`g[wall="${side}"] rect`, { within })
|
|
109
|
+
/* Where the handle stands once the panel has settled: a part picked restores the panel's scroll a frame later. */
|
|
110
|
+
const where = () =>
|
|
111
|
+
handle.evaluate(e => {
|
|
112
|
+
e.scrollIntoView({ block: 'center' })
|
|
113
|
+
const b = e.getBoundingClientRect()
|
|
114
|
+
return { x: b.left + b.width / 2, y: b.top + b.height / 2 }
|
|
115
|
+
})
|
|
116
|
+
let at = await where()
|
|
117
|
+
for (;;) {
|
|
118
|
+
await sleep(100)
|
|
119
|
+
const again = await where()
|
|
120
|
+
if (again.x === at.x && again.y === at.y) break
|
|
121
|
+
at = again
|
|
122
|
+
}
|
|
123
|
+
await page().mouse.move(at.x, at.y)
|
|
124
|
+
await page().mouse.down()
|
|
125
|
+
for (let i = 1; i <= 5; i++) await page().mouse.move(at.x + (dx * i) / 5, at.y)
|
|
126
|
+
if (release) await page().mouse.up()
|
|
127
|
+
return at
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const editorGone = () => until(() => !probe.sectionEditor(), 'the section editor closed')
|
|
131
|
+
|
|
132
|
+
describe('the section editor on a drawn section: typed, previewed, applied or let go', () => {
|
|
133
|
+
before(async () => {
|
|
134
|
+
await mount('quad')
|
|
135
|
+
await pick('wedge')
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test('the 단면 group opens the editor on the part', async () => {
|
|
139
|
+
assert.equal(await editorNow(), null)
|
|
140
|
+
await openEditor()
|
|
141
|
+
assert.equal((await editorNow()).points, 4)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('a point typed is drawn at once and not sent; while the sides cross, the last valid outline is drawn and said', async () => {
|
|
145
|
+
const start = await state()
|
|
146
|
+
await typePoint('3', 0, '350')
|
|
147
|
+
await until(() => probe.drawnShape('wedge').section.points.find(p => p.id === 'p3').x === 350, 'the moved point drawn')
|
|
148
|
+
assert.equal((await state()).revision, start.revision, 'nothing sent')
|
|
149
|
+
assert.equal((await held('wedge')).section.points.find(p => p.id === 'p3').x, 300, 'the figure keeps its point')
|
|
150
|
+
assert.equal((await editorNow()).lastValid, false)
|
|
151
|
+
|
|
152
|
+
await typePoint('2', 0, '-400')
|
|
153
|
+
const now = await until(() => probe.sectionEditor().lastValid && probe.sectionEditor(), 'the outline refused')
|
|
154
|
+
assert.equal(now.caption, 'figure.text.section-editor-last-valid')
|
|
155
|
+
assert.ok(now.issues.length > 0, 'the list says what is wrong')
|
|
156
|
+
const shown = (await drawn('wedge')).section.points
|
|
157
|
+
assert.deepEqual(
|
|
158
|
+
shown.map(p => [p.id, p.x]),
|
|
159
|
+
[['p1', -300], ['p4', -300], ['p3', 350], ['p2', 300]],
|
|
160
|
+
'the solid is the last valid outline, not the crossing one'
|
|
161
|
+
)
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
test('a refused outline is not applied: apply is held back, and pressing it sends nothing', async () => {
|
|
165
|
+
const start = await state()
|
|
166
|
+
const now = await editorNow()
|
|
167
|
+
assert.equal(now.apply.disabled, true)
|
|
168
|
+
await press('footer button[primary]', { within: 'figure-section-editor' })
|
|
169
|
+
await sleep(200)
|
|
170
|
+
assert.equal((await state()).revision, start.revision)
|
|
171
|
+
assert.ok(await editorNow(), 'the editor stays open')
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
test('Esc with changes asks; a refused outline is not offered to apply, and the reason is said', async () => {
|
|
175
|
+
/* A point chosen, for the keys while the question is asked. */
|
|
176
|
+
await press('g[point="p4"] circle', { within: 'figure-section-editor' })
|
|
177
|
+
await page().keyboard.press('Escape')
|
|
178
|
+
const choice = await until(() => probe.closeChoice(), 'the close question')
|
|
179
|
+
assert.deepEqual(choice.words, ['figure.text.section-editor-close-changed', 'figure.text.section-editor-close-invalid'])
|
|
180
|
+
assert.deepEqual(choice.buttons, ['figure.button.keep-editing', 'figure.button.section-editor-discard'], 'no apply-and-close')
|
|
181
|
+
assert.equal((await state()).selected, 'wedge', 'the part stays selected')
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
test('while it asks, the keys are the question\'s: Delete takes no point; kept editing, the changes stay', async () => {
|
|
185
|
+
await page().keyboard.press('Delete')
|
|
186
|
+
await sleep(100)
|
|
187
|
+
assert.equal((await editorNow()).points, 4, 'no point deleted behind the question')
|
|
188
|
+
await press('md-text-button', { within: 'figure-section-close-choice', text: 'figure.button.keep-editing' })
|
|
189
|
+
await until(() => !probe.closeChoice(), 'the question closed')
|
|
190
|
+
const now = await editorNow()
|
|
191
|
+
assert.ok(now, 'the editor stays open')
|
|
192
|
+
assert.equal(now.lastValid, true, 'the changes kept')
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
test('let go from the question: nothing sent, the editor closes, the figure is drawn as it stands', async () => {
|
|
196
|
+
const start = await state()
|
|
197
|
+
await press('footer button', { within: 'figure-section-editor', text: 'figure.button.section-editor-cancel' })
|
|
198
|
+
await until(() => probe.closeChoice(), 'the close question')
|
|
199
|
+
await press('md-text-button', { within: 'figure-section-close-choice', text: 'figure.button.section-editor-discard' })
|
|
200
|
+
await editorGone()
|
|
201
|
+
assert.equal((await state()).revision, start.revision)
|
|
202
|
+
assert.equal((await state()).selected, 'wedge')
|
|
203
|
+
await until(() => probe.drawnShape('wedge').section.points.find(p => p.id === 'p3').x === 300, 'the figure drawn as it stands')
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
test('Esc with nothing changed closes the editor at once, nothing asked; the part stays selected', async () => {
|
|
207
|
+
await openEditor()
|
|
208
|
+
await page().keyboard.press('Escape')
|
|
209
|
+
await editorGone()
|
|
210
|
+
assert.equal(await read(() => probe.closeChoice()), null)
|
|
211
|
+
assert.equal((await state()).selected, 'wedge')
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
test('apply sends the outline as one step, and the editor closes', async () => {
|
|
215
|
+
await openEditor()
|
|
216
|
+
const start = await state()
|
|
217
|
+
await typePoint('3', 0, '350')
|
|
218
|
+
await press('footer button[primary]', { within: 'figure-section-editor' })
|
|
219
|
+
await editorGone()
|
|
220
|
+
assert.equal((await state()).revision, start.revision + 1)
|
|
221
|
+
assert.equal((await held('wedge')).section.points.find(p => p.id === 'p3').x, 350)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
test('while the editor is open the modeller\'s keys step aside: Ctrl+Z does not undo the figure', async () => {
|
|
225
|
+
await openEditor()
|
|
226
|
+
const start = await state()
|
|
227
|
+
await page().keyboard.down('Control')
|
|
228
|
+
await page().keyboard.press('KeyZ')
|
|
229
|
+
await page().keyboard.up('Control')
|
|
230
|
+
await sleep(200)
|
|
231
|
+
assert.equal((await state()).revision, start.revision, 'the figure\'s history is not touched')
|
|
232
|
+
assert.equal((await held('wedge')).section.points.find(p => p.id === 'p3').x, 350)
|
|
233
|
+
assert.ok(await editorNow(), 'the editor stays open')
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
test('Backspace in a field deletes a character; Delete with a point chosen deletes the point, not the part', async () => {
|
|
237
|
+
const start = await state()
|
|
238
|
+
await typePoint('1', 0, '', null)
|
|
239
|
+
await page().keyboard.press('Backspace')
|
|
240
|
+
await sleep(100)
|
|
241
|
+
assert.equal((await editorNow()).points, 4, 'typing in a field')
|
|
242
|
+
await press('g[point="p4"] circle', { within: 'figure-section-editor' })
|
|
243
|
+
await page().keyboard.press('Delete')
|
|
244
|
+
await until(() => probe.sectionEditor().points === 3, 'the point deleted')
|
|
245
|
+
assert.ok((await read(() => probe.ids())).includes('wedge'), 'the part stays')
|
|
246
|
+
assert.equal((await state()).selected, 'wedge')
|
|
247
|
+
assert.equal((await state()).revision, start.revision, 'nothing sent')
|
|
248
|
+
await until(() => probe.drawnShape('wedge').section.points.length === 3, 'the solid drawn with three points')
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
test('picking another part with changes keeps the part until the editor is closed: asked, let go, then the pick goes on', async () => {
|
|
252
|
+
const start = await state()
|
|
253
|
+
const at = await read(() => probe.row('block'))
|
|
254
|
+
await page().mouse.click(at.x, at.y)
|
|
255
|
+
await until(() => probe.closeChoice(), 'the close question')
|
|
256
|
+
assert.equal((await state()).selected, 'wedge', 'the part stays selected while asked')
|
|
257
|
+
await press('md-text-button', { within: 'figure-section-close-choice', text: 'figure.button.section-editor-discard' })
|
|
258
|
+
await until(() => probe.state().selected === 'block', 'the pick goes on')
|
|
259
|
+
assert.equal(await editorNow(), null)
|
|
260
|
+
assert.equal((await state()).revision, start.revision)
|
|
261
|
+
assert.equal((await drawn('wedge')).section.points.length, 4, 'the figure drawn as it stands')
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
test('picking another part with nothing changed closes the editor; picked again, the part opens without it', async () => {
|
|
265
|
+
await pick('wedge')
|
|
266
|
+
await openEditor()
|
|
267
|
+
await pick('block')
|
|
268
|
+
await editorGone()
|
|
269
|
+
assert.equal(await read(() => probe.closeChoice()), null, 'nothing asked')
|
|
270
|
+
await pick('wedge')
|
|
271
|
+
await sleep(200)
|
|
272
|
+
assert.equal(await editorNow(), null, 'the editor does not come back')
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
test('the part removed while the editor has changes: there is nothing to go back to, and it closes without asking', async () => {
|
|
276
|
+
await openEditor()
|
|
277
|
+
await typePoint('3', 0, '360')
|
|
278
|
+
const at = await until(() => probe.partOp('wedge', 'remove-part'), 'the remove button in the parts list')
|
|
279
|
+
await page().mouse.click(at.x, at.y)
|
|
280
|
+
await editorGone()
|
|
281
|
+
assert.ok(!(await read(() => probe.ids())).includes('wedge'), 'the part removed')
|
|
282
|
+
await sleep(200)
|
|
283
|
+
assert.equal(await read(() => probe.closeChoice()), null, 'nothing asked')
|
|
284
|
+
})
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
describe('the section editor on a box: what follows, what is kept, and a figure changed while it is open', () => {
|
|
288
|
+
before(async () => {
|
|
289
|
+
await mount('floor-box')
|
|
290
|
+
await pick('box')
|
|
291
|
+
await openEditor()
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
test('the length says the face its placement keeps', async () => {
|
|
295
|
+
const now = await editorNow()
|
|
296
|
+
assert.equal(now.length.label, 'figure.label.section-editor-length')
|
|
297
|
+
assert.equal(now.length.disabled, false)
|
|
298
|
+
assert.equal(now.length.note, 'figure.text.section-editor-keeps')
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
test('the figure changed while the editor is open: apply is refused, and closing does not offer it', async () => {
|
|
302
|
+
const start = await state()
|
|
303
|
+
await type('input#corner', { within: 'figure-section-panel' }, '20')
|
|
304
|
+
await until(r => probe.state().revision === r + 1, 'the corner sent from the panel', start.revision)
|
|
305
|
+
const now = await until(() => probe.sectionEditor()?.stale && probe.sectionEditor(), 'the editor says the figure changed')
|
|
306
|
+
assert.equal(now.apply.disabled, true)
|
|
307
|
+
await type('div[sizes] label[mm] input', { within: 'figure-section-editor', index: 1 }, '500')
|
|
308
|
+
await page().keyboard.press('Escape')
|
|
309
|
+
const choice = await until(() => probe.closeChoice(), 'the close question')
|
|
310
|
+
assert.deepEqual(choice.words, ['figure.text.section-editor-close-changed', 'figure.text.section-editor-stale'])
|
|
311
|
+
assert.ok(!choice.buttons.includes('figure.button.section-editor-apply-and-close'))
|
|
312
|
+
await press('md-text-button', { within: 'figure-section-close-choice', text: 'figure.button.section-editor-discard' })
|
|
313
|
+
await editorGone()
|
|
314
|
+
assert.equal((await state()).revision, start.revision + 1, 'only the corner')
|
|
315
|
+
assert.equal((await held('box')).section.size.x, 400)
|
|
316
|
+
})
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
describe('the section editor on a box whose sizes follow the figure', () => {
|
|
320
|
+
before(async () => {
|
|
321
|
+
await mount('follows')
|
|
322
|
+
await pick('box')
|
|
323
|
+
await openEditor()
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
test('a measure that follows another value is shown and not offered', async () => {
|
|
327
|
+
const now = await editorNow()
|
|
328
|
+
assert.equal(now.length.disabled, true)
|
|
329
|
+
assert.equal(now.length.note, 'figure.text.section-editor-linked')
|
|
330
|
+
})
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
describe('a drawn section\'s end drawn to one point', () => {
|
|
334
|
+
test('turned on, the length is called the height', async () => {
|
|
335
|
+
await mount('wedge')
|
|
336
|
+
await pick('wedge')
|
|
337
|
+
await openEditor()
|
|
338
|
+
assert.deepEqual((await editorNow()).apex, { checked: false, disabled: false, words: '' }, 'nothing on its top: offered')
|
|
339
|
+
assert.equal((await editorNow()).length.label, 'figure.label.section-editor-length')
|
|
340
|
+
await press('label[apex] input', { within: 'figure-section-editor' })
|
|
341
|
+
await until(() => probe.sectionEditor().apex.checked, 'the apex on')
|
|
342
|
+
assert.equal((await editorNow()).length.label, 'figure.label.section-editor-height')
|
|
343
|
+
await until(() => !!probe.drawnShape('wedge').apex, 'the solid drawn as a pyramid')
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
test('something fastened to the end: drawing it to one point is not offered, and the face is said', async () => {
|
|
347
|
+
await mount('capped-wedge')
|
|
348
|
+
await pick('wedge')
|
|
349
|
+
await openEditor()
|
|
350
|
+
assert.deepEqual((await editorNow()).apex, { checked: false, disabled: true, words: 'figure.text.section-editor-apex-blocked' })
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
test('a pyramid in the 단면 group: its editor opens from there, and it has no corners and no inside', async () => {
|
|
354
|
+
await mount('pyramid')
|
|
355
|
+
await pick('wedge')
|
|
356
|
+
/* The group is drawn after the part is picked: read once it says what this part is. */
|
|
357
|
+
const panel = await until(() => {
|
|
358
|
+
const now = probe.sectionPanel()
|
|
359
|
+
return now?.edit && now.text.includes('figure.text.section-points-apex') ? now : null
|
|
360
|
+
}, 'the 단면 group of the pyramid, its edit button and its points and apex said')
|
|
361
|
+
assert.deepEqual(panel.inputs, [], 'no corner field')
|
|
362
|
+
assert.equal(panel.cavityToggle, false, 'no inside')
|
|
363
|
+
await openEditor()
|
|
364
|
+
const editor = await until(() => {
|
|
365
|
+
const now = probe.sectionEditor()
|
|
366
|
+
return now?.apex?.checked ? now : null
|
|
367
|
+
}, 'the editor open on the pyramid, its apex on')
|
|
368
|
+
assert.deepEqual(editor.apex, { checked: true, disabled: false, words: '' })
|
|
369
|
+
assert.equal(editor.length.label, 'figure.label.section-editor-height')
|
|
370
|
+
})
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
describe('the inside in the section editor: drawn on the widths being typed, sent with them in one step', () => {
|
|
374
|
+
before(async () => {
|
|
375
|
+
await mount('tray')
|
|
376
|
+
await pick('tray')
|
|
377
|
+
await openEditor()
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
test('a wall dragged in the editor is drawn on the solid while it fits; too thick, the solid keeps the last valid inside', async () => {
|
|
381
|
+
const start = await state()
|
|
382
|
+
assert.ok((await editorNow()).cavityDrawing, 'the inside\'s drawing in the editor')
|
|
383
|
+
const at = await dragWall('figure-section-editor', 'x-', 12, false)
|
|
384
|
+
await until(() => probe.drawnShape('tray').cavity.wall['x-'] > 40, 'the thicker wall drawn')
|
|
385
|
+
await page().mouse.move(at.x + 400, at.y)
|
|
386
|
+
await until(() => probe.cavityDrawing('figure-section-editor').refusal, 'too thick, said')
|
|
387
|
+
await until(() => probe.drawnShape('tray').cavity.wall['x-'] === 40, 'the last valid inside drawn')
|
|
388
|
+
await page().mouse.up()
|
|
389
|
+
await sleep(200)
|
|
390
|
+
assert.equal((await state()).revision, start.revision, 'nothing sent')
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
test('walls that fit only the wider section are taken with it, and go in one step with the widths', async () => {
|
|
394
|
+
const start = await state()
|
|
395
|
+
await type('div[sizes] label[mm] input', { within: 'figure-section-editor', index: 1 }, '600')
|
|
396
|
+
await type('div[sizes] label[mm] input', { within: 'figure-section-editor', index: 2 }, '400')
|
|
397
|
+
await press('g[wall="x-"] text', { within: 'figure-section-editor' })
|
|
398
|
+
await until(() => probe.cavityDrawing('figure-section-editor').typing?.focused, 'the wall\'s number field')
|
|
399
|
+
await page().keyboard.type('160')
|
|
400
|
+
await page().keyboard.press('Enter')
|
|
401
|
+
await until(() => probe.drawnShape('tray').cavity?.wall['x-'] === 160, 'the walls drawn on the solid')
|
|
402
|
+
assert.equal((await read(() => probe.cavityDrawing('figure-section-editor'))).refusal, '', 'judged on the widths being typed')
|
|
403
|
+
assert.equal((await state()).revision, start.revision, 'kept in the editor until applied')
|
|
404
|
+
await press('footer button[primary]', { within: 'figure-section-editor' })
|
|
405
|
+
await editorGone()
|
|
406
|
+
assert.equal((await state()).revision, start.revision + 1, 'one step')
|
|
407
|
+
const now = await held('tray')
|
|
408
|
+
assert.deepEqual(now.section.size, { x: 600, z: 400 })
|
|
409
|
+
assert.deepEqual(Object.values(now.cavity.wall), [160, 160, 160, 160])
|
|
410
|
+
})
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
describe('the 단면 group: a value typed is drawn, sent once, and stays typed while it is drawn', () => {
|
|
414
|
+
before(async () => {
|
|
415
|
+
await mount('floor-box')
|
|
416
|
+
await pick('box')
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
test('a corner typed is drawn and not sent, and the field keeps what was typed; Enter sends it as one step', async () => {
|
|
420
|
+
const start = await state()
|
|
421
|
+
await type('input#corner', { within: 'figure-section-panel' }, '40', null)
|
|
422
|
+
await until(() => probe.drawnShape('box').section.corner?.x === 40, 'the corner drawn')
|
|
423
|
+
assert.equal((await state()).revision, start.revision, 'nothing sent while typing')
|
|
424
|
+
await sleep(300)
|
|
425
|
+
assert.equal((await panelNow()).inputs.find(i => i.id === 'corner').value, '40', 'the drawn figure does not type over the field')
|
|
426
|
+
await page().keyboard.press('Enter')
|
|
427
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
428
|
+
assert.deepEqual((await held('box')).section.corner, { x: 40, z: 40 })
|
|
429
|
+
})
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
describe('the inside\'s drawing in the 단면 group', () => {
|
|
433
|
+
before(async () => {
|
|
434
|
+
await mount('tray')
|
|
435
|
+
await pick('tray')
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
test('the inside is said by what it makes and how deep, and drawn; no number fields repeat the drawing', async () => {
|
|
439
|
+
const panel = await panelNow()
|
|
440
|
+
assert.ok(panel.text.includes('figure.text.section-depth'))
|
|
441
|
+
assert.ok(panel.cavityDrawing)
|
|
442
|
+
assert.deepEqual(panel.inputs.map(i => i.id), ['corner'], 'the corner only')
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
test('a wall dragged and let go is one step; every wall together', async () => {
|
|
446
|
+
const start = await state()
|
|
447
|
+
await dragWall('figure-section-panel', 'x-', 12)
|
|
448
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
449
|
+
const walls = Object.values((await held('tray')).cavity.wall)
|
|
450
|
+
assert.ok(walls[0] > 40 && walls.every(w => w === walls[0]), `every wall thicker: ${walls}`)
|
|
451
|
+
})
|
|
452
|
+
|
|
453
|
+
test('dragged too thick, the reason is said and nothing is drawn; let go, nothing is sent and the reason stays', async () => {
|
|
454
|
+
const start = await state()
|
|
455
|
+
const was = (await held('tray')).cavity.wall['x-']
|
|
456
|
+
await dragWall('figure-section-panel', 'x-', 400, false)
|
|
457
|
+
await until(() => probe.cavityDrawing().refusal, 'the reason said')
|
|
458
|
+
assert.equal((await drawn('tray')).cavity.wall['x-'], was, 'the figure drawn as it stands')
|
|
459
|
+
await page().mouse.up()
|
|
460
|
+
await sleep(200)
|
|
461
|
+
assert.equal((await state()).revision, start.revision, 'nothing sent')
|
|
462
|
+
assert.equal((await state()).error, '', 'nothing sent to be refused')
|
|
463
|
+
assert.ok((await read(() => probe.cavityDrawing())).refusal, 'the reason stays said')
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
test('a wall\'s number pressed is typed: Enter sends one step', async () => {
|
|
467
|
+
const start = await state()
|
|
468
|
+
await press('g[wall="x+"] text', { within: 'figure-section-panel' })
|
|
469
|
+
const typing = await until(() => probe.cavityDrawing().typing?.focused && probe.cavityDrawing().typing, 'the number field')
|
|
470
|
+
assert.equal(typing.label, 'figure.label.section-wall')
|
|
471
|
+
await page().keyboard.type('50')
|
|
472
|
+
await page().keyboard.press('Enter')
|
|
473
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
474
|
+
assert.deepEqual(Object.values((await held('tray')).cavity.wall), [50, 50, 50, 50])
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
test('with walls one per side, a wall typed changes that wall only', async () => {
|
|
478
|
+
const start = await state()
|
|
479
|
+
await press('label[toggle] input', { within: 'figure-section-panel', index: 1 })
|
|
480
|
+
await press('g[wall="z+"] text', { within: 'figure-section-panel' })
|
|
481
|
+
await until(() => probe.cavityDrawing().typing?.focused && probe.cavityDrawing().typing, 'the number field')
|
|
482
|
+
await page().keyboard.type('70')
|
|
483
|
+
await page().keyboard.press('Enter')
|
|
484
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
485
|
+
assert.deepEqual((await held('tray')).cavity.wall, { 'x-': 50, 'x+': 50, 'z-': 50, 'z+': 70 })
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
test('a closed end\'s number is typed; the open end has none, and pressed it closes in one step', async () => {
|
|
489
|
+
const ends = (await read(() => probe.cavityDrawing())).ends
|
|
490
|
+
assert.equal(ends.start.typed, true)
|
|
491
|
+
assert.equal(ends.end.typed, false)
|
|
492
|
+
await press('g[end="start"] text', { within: 'figure-section-panel' })
|
|
493
|
+
assert.equal((await until(() => probe.cavityDrawing().typing?.focused && probe.cavityDrawing().typing, 'the number field')).label, 'figure.label.face-bottom')
|
|
494
|
+
await page().keyboard.press('Escape')
|
|
495
|
+
await until(() => !probe.cavityDrawing().typing, 'the field put away')
|
|
496
|
+
const start = await state()
|
|
497
|
+
await press('g[end="end"] text', { within: 'figure-section-panel' })
|
|
498
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
499
|
+
assert.equal((await read(() => probe.cavityDrawing())).typing, null, 'no number field for an open end')
|
|
500
|
+
assert.ok((await held('tray')).cavity.end.closed > 0, 'the open end closed')
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
test('a wall\'s number stands outside the section on its own side, clear of every handle', async () => {
|
|
504
|
+
const d = await read(() => probe.cavityDrawing())
|
|
505
|
+
const s = d.section
|
|
506
|
+
const { 'x-': l, 'x+': r, 'z-': t, 'z+': b } = d.walls
|
|
507
|
+
assert.ok(l.number.right <= s.left + 0.5, 'left of the section')
|
|
508
|
+
assert.ok(r.number.left >= s.right - 0.5, 'right of the section')
|
|
509
|
+
assert.ok(t.number.bottom <= s.top + 0.5, 'above the section')
|
|
510
|
+
assert.ok(b.number.top >= s.bottom - 0.5, 'below the section')
|
|
511
|
+
const meet = (a, c) => a.left < c.right && c.left < a.right && a.top < c.bottom && c.top < a.bottom
|
|
512
|
+
for (const one of Object.values(d.walls)) for (const other of Object.values(d.walls)) assert.ok(!meet(one.number, other.handle), 'a number clear of a handle')
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
test('across a shallow inside, the two walls\' handles step aside from each other', async () => {
|
|
516
|
+
await mount('shallow-tray')
|
|
517
|
+
await pick('tray')
|
|
518
|
+
const { 'z-': a, 'z+': b } = (await read(() => probe.cavityDrawing())).walls
|
|
519
|
+
const meet = a.handle.left < b.handle.right && b.handle.left < a.handle.right && a.handle.top < b.handle.bottom && b.handle.top < a.handle.bottom
|
|
520
|
+
assert.ok(!meet, `apart: ${JSON.stringify([a.handle, b.handle])}`)
|
|
521
|
+
})
|
|
522
|
+
})
|
|
523
|
+
|
|
524
|
+
describe('the fastening drawing in the fastening form', () => {
|
|
525
|
+
const labels = () => read(() => probe.fastenForm().map(s => s.label))
|
|
526
|
+
const target = () => read(() => probe.fastenForm().find(s => s.label === 'figure.label.target-part'))
|
|
527
|
+
|
|
528
|
+
test('the part\'s own face and the facing are not asked: the target, its face and how are drawn', async () => {
|
|
529
|
+
await mount('arm')
|
|
530
|
+
await pick('forearm')
|
|
531
|
+
const asked = await labels()
|
|
532
|
+
assert.ok(asked.includes('figure.label.target-part'))
|
|
533
|
+
assert.ok(!asked.includes('figure.label.my-face') && !asked.includes('figure.label.facing'), `asked: ${asked}`)
|
|
534
|
+
assert.ok(await read(() => !!probe.fastenDrawing()), 'the drawing in their place')
|
|
535
|
+
})
|
|
536
|
+
|
|
537
|
+
test('a fastened part: a face of the target pressed is one step', async () => {
|
|
538
|
+
const start = await state()
|
|
539
|
+
const was = await read(() => probe.fastening('forearm'))
|
|
540
|
+
const face = was.body0.face === 'front' ? 'right' : 'front'
|
|
541
|
+
await press(`[face="${face}"]`, { within: 'figure-fasten-drawing' })
|
|
542
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
543
|
+
assert.equal((await read(() => probe.fastening('forearm'))).body0.face, face)
|
|
544
|
+
})
|
|
545
|
+
|
|
546
|
+
test('a fastened part: flush pressed is one step, and the drawing shows it', async () => {
|
|
547
|
+
const start = await state()
|
|
548
|
+
await press('button[mode="flush"]', { within: 'figure-fasten-drawing' })
|
|
549
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
550
|
+
assert.equal(await read(() => probe.fastenMode()), 'flush')
|
|
551
|
+
})
|
|
552
|
+
|
|
553
|
+
test('a fastened part: the footprint dragged on the face and let go is one step', async () => {
|
|
554
|
+
const start = await state()
|
|
555
|
+
const foot = await element('g[footprint] rect', { within: 'figure-fasten-drawing' })
|
|
556
|
+
const at = await foot.evaluate(e => {
|
|
557
|
+
e.scrollIntoView({ block: 'center' })
|
|
558
|
+
const b = e.getBoundingClientRect()
|
|
559
|
+
return { x: b.left + b.width / 2, y: b.top + b.height / 2 }
|
|
560
|
+
})
|
|
561
|
+
await page().mouse.move(at.x, at.y)
|
|
562
|
+
await page().mouse.down()
|
|
563
|
+
for (let i = 1; i <= 5; i++) await page().mouse.move(at.x + 6 * i, at.y)
|
|
564
|
+
await page().mouse.up()
|
|
565
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
566
|
+
await sleep(300)
|
|
567
|
+
assert.equal((await state()).revision, start.revision + 1, 'and only one')
|
|
568
|
+
})
|
|
569
|
+
|
|
570
|
+
test('fastened to the plane: the plane is named by the placement, chosen, and set on only', async () => {
|
|
571
|
+
await mount('rollers')
|
|
572
|
+
await pick('bed')
|
|
573
|
+
const list = await target()
|
|
574
|
+
assert.equal(list.value, '__plane')
|
|
575
|
+
assert.equal(list.options.find(o => o.value === '__plane').text, 'figure.label.resize-place-floor')
|
|
576
|
+
assert.deepEqual((await read(() => probe.fastenDrawing())).modes, [], 'one way only: no choice offered')
|
|
577
|
+
})
|
|
578
|
+
|
|
579
|
+
test('a part that turns in place may have its centre on the face; a part that does not, not', async () => {
|
|
580
|
+
await pick('roller')
|
|
581
|
+
assert.deepEqual((await read(() => probe.fastenDrawing())).modes, ['meet', 'flush', 'centre'])
|
|
582
|
+
await pick('mark')
|
|
583
|
+
assert.deepEqual((await read(() => probe.fastenDrawing())).modes, ['meet', 'flush'])
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
test('a new fastening waits for 붙이기; the part\'s own face follows the target\'s face and how', async () => {
|
|
587
|
+
await mount('door')
|
|
588
|
+
await pick('leaf')
|
|
589
|
+
await press('button[act]', { has: 'figure.button.fasten-start' })
|
|
590
|
+
await until(() => probe.fastenForm().some(s => s.label === 'figure.label.target-part'), 'the target asked')
|
|
591
|
+
const targetSelect = await page().evaluateHandle(() => {
|
|
592
|
+
const deep = (root = document) => [...root.querySelectorAll('select')].concat(...[...root.querySelectorAll('*')].filter(e => e.shadowRoot).map(e => deep(e.shadowRoot)))
|
|
593
|
+
return deep().find(s => s.previousElementSibling?.textContent?.trim() === 'figure.label.target-part') ?? null
|
|
594
|
+
})
|
|
595
|
+
await targetSelect.select('frame')
|
|
596
|
+
await until(() => !!probe.fastenDrawing(), 'the fastening drawing')
|
|
597
|
+
const start = await state()
|
|
598
|
+
await press('[face="front"]', { within: 'figure-fasten-drawing' })
|
|
599
|
+
await sleep(300)
|
|
600
|
+
assert.equal((await state()).revision, start.revision, 'nothing sent before 붙이기')
|
|
601
|
+
await press('button[act]', { text: 'linkfigure.button.fasten' })
|
|
602
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
603
|
+
const joint = await read(() => probe.fastening('leaf'))
|
|
604
|
+
assert.deepEqual(joint.body0, { part: 'frame', face: 'front' })
|
|
605
|
+
assert.equal(joint.body1.face, 'back', 'set on the front, by its back')
|
|
606
|
+
})
|
|
607
|
+
})
|
|
608
|
+
|
|
609
|
+
describe('the face choice: asked where the edit was made, and the same edit goes again with it', () => {
|
|
610
|
+
before(async () => {
|
|
611
|
+
await mount('tote')
|
|
612
|
+
await pick('bin')
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
test('opening the floor under the divider in the 단면 group asks where the divider goes, there; nothing sent', async () => {
|
|
616
|
+
const start = await state()
|
|
617
|
+
await press('g[end="start"] rect', { within: 'figure-section-panel' })
|
|
618
|
+
await until(() => probe.sectionPanel().faceMapping, 'the choice in the 단면 group')
|
|
619
|
+
assert.equal((await state()).revision, start.revision)
|
|
620
|
+
assert.equal((await state()).error, '', 'asked, not refused')
|
|
621
|
+
assert.deepEqual(await read(() => probe.faceMapping()), { rows: 1, apply: { disabled: true } }, 'apply waits for every row')
|
|
622
|
+
})
|
|
623
|
+
|
|
624
|
+
test('another part picked lets the question go', async () => {
|
|
625
|
+
await pick('block')
|
|
626
|
+
await pick('bin')
|
|
627
|
+
assert.equal(await read(() => probe.faceMapping()), null)
|
|
628
|
+
})
|
|
629
|
+
|
|
630
|
+
test('chosen, the same edit goes in one step with where the divider goes', async () => {
|
|
631
|
+
const start = await state()
|
|
632
|
+
await press('g[end="start"] rect', { within: 'figure-section-panel' })
|
|
633
|
+
await until(() => probe.faceMapping(), 'the choice')
|
|
634
|
+
await (await element('select', { within: 'figure-face-mapping' })).select('top')
|
|
635
|
+
await until(() => !probe.faceMapping().apply.disabled, 'apply open')
|
|
636
|
+
await press('button[act]', { within: 'figure-face-mapping' })
|
|
637
|
+
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
638
|
+
assert.deepEqual((await read(() => probe.fastening('divider'))).body0, { part: 'bin', face: 'top' })
|
|
639
|
+
assert.equal((await held('bin')).cavity.start, 'open')
|
|
640
|
+
assert.equal(await read(() => probe.faceMapping()), null)
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
test('in the section editor: apply is held open with the choice in it; chosen, it goes and the editor closes', async () => {
|
|
644
|
+
await mount('tote')
|
|
645
|
+
await pick('bin')
|
|
646
|
+
await openEditor()
|
|
647
|
+
const start = await state()
|
|
648
|
+
await press('g[end="start"] rect', { within: 'figure-section-editor' })
|
|
649
|
+
await press('footer button[primary]', { within: 'figure-section-editor' })
|
|
650
|
+
await until(() => probe.sectionEditor()?.faceMapping, 'the choice in the editor')
|
|
651
|
+
assert.equal((await state()).revision, start.revision)
|
|
652
|
+
assert.equal((await panelNow()).faceMapping, false, 'asked where the edit was made only')
|
|
653
|
+
await (await element('select', { within: 'figure-face-mapping' })).select('top')
|
|
654
|
+
await press('button[act]', { within: 'figure-face-mapping' })
|
|
655
|
+
await editorGone()
|
|
656
|
+
assert.equal((await state()).revision, start.revision + 1)
|
|
657
|
+
assert.deepEqual((await read(() => probe.fastening('divider'))).body0, { part: 'bin', face: 'top' })
|
|
658
|
+
})
|
|
659
|
+
})
|
|
660
|
+
|
|
661
|
+
describe('the section editor\'s room: side by side when there is room, taking turns when there is not', () => {
|
|
662
|
+
before(async () => {
|
|
663
|
+
await page().setViewport({ width: 2400, height: 900 })
|
|
664
|
+
await mount('quad')
|
|
665
|
+
await pick('wedge')
|
|
666
|
+
await openEditor()
|
|
667
|
+
})
|
|
668
|
+
after(async () => {
|
|
669
|
+
await page().setViewport({ width: 1400, height: 900 })
|
|
670
|
+
})
|
|
671
|
+
|
|
672
|
+
test('with room beside it, no tabs, and apply and cancel stand at its foot inside it', async () => {
|
|
673
|
+
const now = await editorNow()
|
|
674
|
+
assert.equal(now.narrow, false)
|
|
675
|
+
assert.equal(now.tabs, false)
|
|
676
|
+
for (const b of now.footer) {
|
|
677
|
+
assert.ok(b.bottom <= now.host.bottom && b.top >= now.bodyBox.bottom - 0.5, `a footer button inside, under the body: ${JSON.stringify(b)}`)
|
|
678
|
+
}
|
|
679
|
+
})
|
|
680
|
+
|
|
681
|
+
test('the scene behind focused: Delete deletes the chosen point and Esc asks -- the scene does not take them', async () => {
|
|
682
|
+
await press('g[point="p4"] circle', { within: 'figure-section-editor' })
|
|
683
|
+
/* The part's right side, beside the editor: the editor stands over its middle. */
|
|
684
|
+
const at = await read(() => probe.partOnPage('wedge'))
|
|
685
|
+
await page().mouse.click((await editorNow()).host.right + 30, at.y)
|
|
686
|
+
await sleep(300)
|
|
687
|
+
assert.equal((await state()).selected, 'wedge')
|
|
688
|
+
const keys = await read(() => probe.activePath())
|
|
689
|
+
assert.ok(keys.includes('FIGURE-CANVAS'), `the scene has the keys: ${keys}`)
|
|
690
|
+
const start = await state()
|
|
691
|
+
await page().keyboard.press('Delete')
|
|
692
|
+
await until(() => probe.sectionEditor().points === 3, 'the point deleted')
|
|
693
|
+
assert.ok((await read(() => probe.ids())).includes('wedge'), 'the part stays')
|
|
694
|
+
await page().keyboard.press('Escape')
|
|
695
|
+
await until(() => probe.closeChoice(), 'the close question')
|
|
696
|
+
assert.equal((await state()).selected, 'wedge', 'the part stays selected')
|
|
697
|
+
await press('md-text-button', { within: 'figure-section-close-choice', text: 'figure.button.section-editor-discard' })
|
|
698
|
+
await editorGone()
|
|
699
|
+
assert.equal((await state()).revision, start.revision)
|
|
700
|
+
await openEditor()
|
|
701
|
+
})
|
|
702
|
+
|
|
703
|
+
test('too little room beside it (yet wider than itself): the outline and the solid take turns', async () => {
|
|
704
|
+
await page().setViewport({ width: 1400, height: 900 })
|
|
705
|
+
const now = await until(() => probe.sectionEditor().narrow && probe.sectionEditor(), 'narrow')
|
|
706
|
+
assert.ok(now.room.width > now.host.width, `the room is wider than the editor: ${now.room.width}`)
|
|
707
|
+
assert.equal(now.tabs, true)
|
|
708
|
+
await press('nav[tabs] button', { within: 'figure-section-editor', text: 'figure.label.section-editor-solid' })
|
|
709
|
+
const solid = await until(() => !probe.sectionEditor().body && probe.sectionEditor(), 'the outline put away')
|
|
710
|
+
assert.equal(solid.show, 'solid')
|
|
711
|
+
await page().setViewport({ width: 2400, height: 900 })
|
|
712
|
+
const wide = await until(() => !probe.sectionEditor().narrow && probe.sectionEditor(), 'side by side again')
|
|
713
|
+
assert.equal(wide.body, true)
|
|
714
|
+
})
|
|
715
|
+
})
|
|
716
|
+
|
|
717
|
+
test('the page raised no error', () => {
|
|
718
|
+
assert.deepEqual(opened.errors, [])
|
|
719
|
+
})
|