@operato/layout 10.29.38 → 10.29.39
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 +9 -0
- package/coverage/lcov-report/index.html +89 -89
- package/coverage/lcov.info +33927 -33126
- package/dist/src/actions/entity360-registry.js +15 -9
- package/dist/src/actions/entity360-registry.js.map +1 -1
- package/dist/src/actions/entity360.d.ts +1 -1
- package/dist/src/actions/entity360.js +3 -2
- package/dist/src/actions/entity360.js.map +1 -1
- package/dist/src/actions/layout.d.ts +1 -1
- package/dist/src/actions/layout.js +68 -31
- package/dist/src/actions/layout.js.map +1 -1
- package/dist/src/components/ox-url-tabs.d.ts +3 -2
- package/dist/src/components/ox-url-tabs.js +20 -10
- package/dist/src/components/ox-url-tabs.js.map +1 -1
- package/dist/src/initializer.js +5 -46
- package/dist/src/initializer.js.map +1 -1
- package/dist/test/address-sequences.test.d.ts +1 -0
- package/dist/test/address-sequences.test.js +190 -0
- package/dist/test/address-sequences.test.js.map +1 -0
- package/dist/test/entity360.test.js +3 -3
- package/dist/test/entity360.test.js.map +1 -1
- package/dist/test/history-retention.test.d.ts +1 -0
- package/dist/test/history-retention.test.js +25 -0
- package/dist/test/history-retention.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/test/address-sequences.test.ts +185 -0
- package/test/entity360.test.ts +3 -3
- package/test/history-retention.test.ts +25 -0
package/dist/src/initializer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { store } from '@operato/shell';
|
|
2
|
+
import { closeOverlay, openOverlay, openPopup, toggleOverlay } from './actions/layout.js';
|
|
3
3
|
import layout from './reducers/layout.js';
|
|
4
4
|
import { showSnackbar } from './actions/snackbar.js';
|
|
5
5
|
import snackbar from './reducers/snackbar.js';
|
|
@@ -12,8 +12,9 @@ document.addEventListener('open-overlay', event => {
|
|
|
12
12
|
openOverlay(name, options);
|
|
13
13
|
});
|
|
14
14
|
document.addEventListener('close-overlay', event => {
|
|
15
|
-
const
|
|
16
|
-
closeOverlay(name);
|
|
15
|
+
const detail = event.detail;
|
|
16
|
+
detail.accepted = closeOverlay(detail.name);
|
|
17
|
+
event.preventDefault();
|
|
17
18
|
});
|
|
18
19
|
document.addEventListener('toggle-overlay', event => {
|
|
19
20
|
const { name, options } = event.detail;
|
|
@@ -51,47 +52,5 @@ document.addEventListener('notify', event => {
|
|
|
51
52
|
...option
|
|
52
53
|
}));
|
|
53
54
|
});
|
|
54
|
-
/* overlay handling */
|
|
55
|
-
var overlayStack = [];
|
|
56
|
-
function getLastSequence() {
|
|
57
|
-
return overlayStack.length > 0 ? overlayStack[overlayStack.length - 1].overlay.sequence : -1;
|
|
58
|
-
}
|
|
59
|
-
document.addEventListener('keydown', event => {
|
|
60
|
-
var _a, _b;
|
|
61
|
-
if (overlayStack.length > 0 && (event.key === 'Escape' || event.key === 'Esc')) {
|
|
62
|
-
((_b = (_a = history.state) === null || _a === void 0 ? void 0 : _a.overlay) === null || _b === void 0 ? void 0 : _b.escapable) && history.back();
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
const historyHandler = (location, event) => {
|
|
66
|
-
var navigated = event instanceof PopStateEvent;
|
|
67
|
-
var state = history.state;
|
|
68
|
-
var overlay = state === null || state === void 0 ? void 0 : state.overlay;
|
|
69
|
-
var sequence = (overlay === null || overlay === void 0 ? void 0 : overlay.sequence) || -1;
|
|
70
|
-
var lastSequence = getLastSequence();
|
|
71
|
-
if (overlayStack.length > 0 && sequence < lastSequence) {
|
|
72
|
-
/* overlay 관련 history가 아닌 경우. */
|
|
73
|
-
do {
|
|
74
|
-
let { overlay } = overlayStack.pop();
|
|
75
|
-
store.dispatch({
|
|
76
|
-
type: UPDATE_VIEWPART,
|
|
77
|
-
name: overlay.name,
|
|
78
|
-
override: { show: false }
|
|
79
|
-
});
|
|
80
|
-
lastSequence = getLastSequence();
|
|
81
|
-
} while (sequence < lastSequence);
|
|
82
|
-
}
|
|
83
|
-
if (!navigated && overlay) {
|
|
84
|
-
overlayStack.push({ ...state });
|
|
85
|
-
store.dispatch({
|
|
86
|
-
type: UPDATE_VIEWPART,
|
|
87
|
-
name: overlay.name,
|
|
88
|
-
override: { show: true }
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
store.dispatch({
|
|
93
|
-
type: REGISTER_NAVIGATION_CALLBACK,
|
|
94
|
-
callback: historyHandler
|
|
95
|
-
});
|
|
96
55
|
export default store;
|
|
97
56
|
//# sourceMappingURL=initializer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initializer.js","sourceRoot":"","sources":["../../src/initializer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"initializer.js","sourceRoot":"","sources":["../../src/initializer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAmB,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAE1G,OAAO,MAAM,MAAM,sBAAsB,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,QAAQ,MAAM,wBAAwB,CAAA;AAE7C,KAAK,CAAC,WAAW,CAAC;IAChB,MAAM;IACN,QAAQ;CACT,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,CAAC,cAAc,EAAE,KAAK,CAAC,EAAE;IAChD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAI,KAAqB,CAAC,MAAM,CAAA;IACvD,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AAC5B,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,CAAC,eAAe,EAAE,KAAK,CAAC,EAAE;IACjD,MAAM,MAAM,GAAI,KAAqB,CAAC,MAAM,CAAA;IAC5C,MAAM,CAAC,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC3C,KAAK,CAAC,cAAc,EAAE,CAAA;AACxB,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,KAAK,CAAC,EAAE;IAClD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAI,KAAqB,CAAC,MAAM,CAAA;IACvD,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AAC9B,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE;IAC9C,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAI,KAAqB,CAAC,MAAM,CAAA;IACrE,IAAI,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IACxC,IAAI,KAAK,IAAI,QAAQ;QAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;AACxC,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE;IAC1C,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,EAAE,MAAM,GAAG,EAAE,EAAE,GAAI,KAAqB,CAAC,MAAM,CAAA;IAEpF;;;;OAIG;IACH,MAAM,cAAc,GAAG,KAAK,IAAI,MAAM,CAAA;IAEtC,QAAQ,cAAc,EAAE,CAAC;QACvB,KAAK,OAAO;YACV,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;YAC1B,MAAK;QACP,KAAK,MAAM;YACT,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;YACzB,MAAK;QACP;YACE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACrB,MAAK;IACT,CAAC;IAED,KAAK,CAAC,QAAQ,CACZ,YAAY,CAAC,cAAc,EAAE;QAC3B,OAAO;QACP,MAAM;QACN,EAAE;QACF,GAAI,MAGF;KACH,CAAQ,CACV,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,eAAe,KAAK,CAAA","sourcesContent":["import { store } from '@operato/shell'\nimport { UPDATE_VIEWPART, closeOverlay, openOverlay, openPopup, toggleOverlay } from './actions/layout.js'\n\nimport layout from './reducers/layout.js'\nimport { showSnackbar } from './actions/snackbar.js'\nimport snackbar from './reducers/snackbar.js'\n\nstore.addReducers({\n layout,\n snackbar\n})\n\ndocument.addEventListener('open-overlay', event => {\n const { name, options } = (event as CustomEvent).detail\n openOverlay(name, options)\n})\n\ndocument.addEventListener('close-overlay', event => {\n const detail = (event as CustomEvent).detail\n detail.accepted = closeOverlay(detail.name)\n event.preventDefault()\n})\n\ndocument.addEventListener('toggle-overlay', event => {\n const { name, options } = (event as CustomEvent).detail\n toggleOverlay(name, options)\n})\n\ndocument.addEventListener('open-popup', event => {\n const { template, options, callback } = (event as CustomEvent).detail\n var popup = openPopup(template, options)\n if (popup && callback) callback(popup)\n})\n\ndocument.addEventListener('notify', event => {\n let { message, level, detail, ex = '', option = {} } = (event as CustomEvent).detail\n\n /*\n * 레벨을 주지 않은 호출이 210건 중 117건이다. 그대로 두면 성격 없는 알림이 되어 화면에서\n * 성공·안내가 구분되지 않으므로 info 로 정규화한다. (성공 알림은 호출부에서 점차\n * level: 'success' 로 옮긴다 — 기본값이 잡혀 있으면 그 전에도 화면은 일관된다.)\n */\n const effectiveLevel = level || 'info'\n\n switch (effectiveLevel) {\n case 'error':\n console.error(message, ex)\n break\n case 'warn':\n console.warn(message, ex)\n break\n default:\n console.info(message)\n break\n }\n\n store.dispatch(\n showSnackbar(effectiveLevel, {\n message,\n detail,\n ex,\n ...(option as {\n action?: any\n timer?: number\n })\n }) as any\n )\n})\n\nexport default store\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { expect, fixture } from '@open-wc/testing';
|
|
2
|
+
import { sendMouse } from '@web/test-runner-commands';
|
|
3
|
+
import { html } from 'lit';
|
|
4
|
+
import { addressController, writeAddress } from '@operato/utils/address.js';
|
|
5
|
+
import { closeOverlay, openPopup } from '../src/index.js';
|
|
6
|
+
const wait = () => new Promise(resolve => setTimeout(resolve, 10));
|
|
7
|
+
const navigation = () => window.navigation;
|
|
8
|
+
/** An independent product model: visible popups, the user's URL steps, and the cursor among them. */
|
|
9
|
+
class Expected {
|
|
10
|
+
constructor(url) {
|
|
11
|
+
this.index = 0;
|
|
12
|
+
this.popups = [];
|
|
13
|
+
this.entries = [url];
|
|
14
|
+
}
|
|
15
|
+
write(url, replace = false) {
|
|
16
|
+
if (this.popups.length)
|
|
17
|
+
return false;
|
|
18
|
+
if (url === this.entries[this.index])
|
|
19
|
+
return true;
|
|
20
|
+
if (replace)
|
|
21
|
+
this.entries[this.index] = url;
|
|
22
|
+
else {
|
|
23
|
+
this.entries.splice(++this.index);
|
|
24
|
+
this.entries.push(url);
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
open() {
|
|
29
|
+
const below = this.index;
|
|
30
|
+
const url = this.entries[this.index];
|
|
31
|
+
this.entries.splice(++this.index);
|
|
32
|
+
this.entries.push(url);
|
|
33
|
+
this.popups.push({ at: this.index, below });
|
|
34
|
+
}
|
|
35
|
+
close() {
|
|
36
|
+
const top = this.popups.pop();
|
|
37
|
+
if (top)
|
|
38
|
+
this.index = top.below;
|
|
39
|
+
}
|
|
40
|
+
move(delta) {
|
|
41
|
+
this.index += delta;
|
|
42
|
+
this.popups = this.popups.filter(popup => popup.at <= this.index);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
describe('address behaviour against an independent expected history', () => {
|
|
46
|
+
it('matches every step, including close followed immediately by a new committed query', async () => {
|
|
47
|
+
const events = [];
|
|
48
|
+
let phase = 'setup';
|
|
49
|
+
const snapshot = (kind, details) => events.push({
|
|
50
|
+
kind, phase, details, time: performance.now(), ready: document.readyState,
|
|
51
|
+
historyLength: history.length, activated: navigator.userActivation.hasBeenActive, current: navigation().currentEntry.key,
|
|
52
|
+
entries: navigation().entries().map((entry) => [entry.key, entry.index, new URL(entry.url).search])
|
|
53
|
+
});
|
|
54
|
+
const observed = new WeakSet();
|
|
55
|
+
const observeEntries = () => navigation().entries().forEach((entry) => {
|
|
56
|
+
if (observed.has(entry))
|
|
57
|
+
return;
|
|
58
|
+
observed.add(entry);
|
|
59
|
+
entry.addEventListener('dispose', () => snapshot('dispose', { key: entry.key, url: entry.url }));
|
|
60
|
+
});
|
|
61
|
+
const navigate = (event) => snapshot('navigate', { type: event.navigationType,
|
|
62
|
+
destination: event.destination.key, url: event.destination.url, cancelled: event.defaultPrevented });
|
|
63
|
+
const changed = (event) => {
|
|
64
|
+
snapshot('currententrychange', { type: event.navigationType, from: event.from.key });
|
|
65
|
+
observeEntries();
|
|
66
|
+
};
|
|
67
|
+
navigation().addEventListener('navigate', navigate);
|
|
68
|
+
navigation().addEventListener('currententrychange', changed);
|
|
69
|
+
const original = { pushState: history.pushState, replaceState: history.replaceState, traverseTo: navigation().traverseTo };
|
|
70
|
+
for (const method of ['pushState', 'replaceState']) {
|
|
71
|
+
history[method] = function (...args) {
|
|
72
|
+
snapshot(method, { url: String(args[2]), stack: new Error().stack });
|
|
73
|
+
return original[method].apply(this, args);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
navigation().traverseTo = function (...args) {
|
|
77
|
+
snapshot('traverseTo', { key: args[0] });
|
|
78
|
+
const result = original.traverseTo.apply(this, args);
|
|
79
|
+
for (const name of ['committed', 'finished'])
|
|
80
|
+
result[name].then(() => snapshot(name, { key: args[0] }), (error) => snapshot(name, { key: args[0], error: error.name }));
|
|
81
|
+
return result;
|
|
82
|
+
};
|
|
83
|
+
observeEntries();
|
|
84
|
+
snapshot('start');
|
|
85
|
+
try {
|
|
86
|
+
// The oracle models user actions. At Chrome's 50-entry limit, an unactivated document's
|
|
87
|
+
// entries are preferentially pruned, including a recently pushed baseline. See the native
|
|
88
|
+
// no-app control in operato-application/test/address-browser/native-retention.cjs.
|
|
89
|
+
const start = await fixture(html `<button>Start history sequence</button>`);
|
|
90
|
+
const bounds = start.getBoundingClientRect();
|
|
91
|
+
await sendMouse({ type: 'click', position: [Math.round(bounds.x + bounds.width / 2), Math.round(bounds.y + bounds.height / 2)] });
|
|
92
|
+
expect(navigator.userActivation.hasBeenActive, 'real user activation for the product oracle').to.equal(true);
|
|
93
|
+
start.remove();
|
|
94
|
+
await fixture(html `<ox-header-bar></ox-header-bar>`);
|
|
95
|
+
addressController().registerQuery();
|
|
96
|
+
for (let seed = 1; seed <= 10; seed++) {
|
|
97
|
+
let randomState = seed;
|
|
98
|
+
const random = () => (randomState = (Math.imul(1664525, randomState) + 1013904223) >>> 0) / 2 ** 32;
|
|
99
|
+
expect(await writeAddress(`?filters=seed-${seed}`)).to.equal(true);
|
|
100
|
+
let floorKey = navigation().currentEntry.key;
|
|
101
|
+
const floor = () => navigation()
|
|
102
|
+
.entries()
|
|
103
|
+
.findIndex((entry) => entry.key === floorKey);
|
|
104
|
+
const expected = new Expected(location.href);
|
|
105
|
+
let handles = [];
|
|
106
|
+
const trace = [];
|
|
107
|
+
const snapshots = [];
|
|
108
|
+
for (let step = 0; step < 30; step++) {
|
|
109
|
+
const action = Math.floor(random() * 7);
|
|
110
|
+
phase = `seed ${seed} step ${step} action ${action}`;
|
|
111
|
+
snapshot('action');
|
|
112
|
+
trace.push(String(action));
|
|
113
|
+
if (action === 0 || action === 1 || action === 6) {
|
|
114
|
+
if (action === 6 && handles.length) {
|
|
115
|
+
handles.pop().close();
|
|
116
|
+
expected.close();
|
|
117
|
+
}
|
|
118
|
+
const url = new URL(expected.entries[expected.index]);
|
|
119
|
+
url.searchParams.set(action === 1 ? 'f' : 'filters', `${seed}-${step}`);
|
|
120
|
+
const replace = action === 1;
|
|
121
|
+
const accepted = await writeAddress(url, { replace });
|
|
122
|
+
expect(accepted, `seed ${seed}, step ${step}`).to.equal(expected.write(url.href, replace));
|
|
123
|
+
if (accepted && replace && expected.index === 0)
|
|
124
|
+
floorKey = navigation().currentEntry.key;
|
|
125
|
+
}
|
|
126
|
+
else if (action === 2 && handles.length < 2) {
|
|
127
|
+
handles.push(openPopup(html `<div>picker</div>`, { backdrop: true, escapable: true }));
|
|
128
|
+
expected.open();
|
|
129
|
+
}
|
|
130
|
+
else if (action === 3 && handles.length) {
|
|
131
|
+
handles.pop().close();
|
|
132
|
+
expected.close();
|
|
133
|
+
}
|
|
134
|
+
else if (action === 4 && expected.index > 0) {
|
|
135
|
+
expected.move(-1);
|
|
136
|
+
await navigation().back().finished;
|
|
137
|
+
handles = handles.slice(0, expected.popups.length);
|
|
138
|
+
}
|
|
139
|
+
else if (action === 5 && expected.index + 1 < expected.entries.length) {
|
|
140
|
+
expected.move(1);
|
|
141
|
+
await navigation().forward().finished;
|
|
142
|
+
}
|
|
143
|
+
await addressController().whenSettled();
|
|
144
|
+
for (let attempt = 0; navigation().currentEntry.index !== floor() + expected.index; attempt++) {
|
|
145
|
+
if (attempt > 100)
|
|
146
|
+
throw new Error(`did not settle: seed ${seed}, step ${step}, trace ${trace}`);
|
|
147
|
+
await wait();
|
|
148
|
+
}
|
|
149
|
+
await wait();
|
|
150
|
+
snapshots.push({ step, action, floorKey, current: navigation().currentEntry.key,
|
|
151
|
+
entries: navigation().entries().map((entry) => [entry.key, entry.index, new URL(entry.url).search]) });
|
|
152
|
+
expect(floor(), `sequence retained: seed ${seed}, step ${step}, snapshots ${JSON.stringify(snapshots)}, trace ${trace}, entries ${navigation()
|
|
153
|
+
.entries()
|
|
154
|
+
.map((entry) => new URL(entry.url).search)}`).to.be.at.least(0);
|
|
155
|
+
const actual = navigation()
|
|
156
|
+
.entries()
|
|
157
|
+
.slice(floor())
|
|
158
|
+
.map((entry) => entry.url);
|
|
159
|
+
const detail = `seed ${seed}, step ${step}, trace ${trace}`;
|
|
160
|
+
expect(actual, detail).to.deep.equal(expected.entries);
|
|
161
|
+
expect(location.href, detail).to.equal(expected.entries[expected.index]);
|
|
162
|
+
const bar = document.querySelector('ox-header-bar').shadowRoot;
|
|
163
|
+
expect(bar.querySelectorAll('ox-floating-overlay').length, detail).to.equal(expected.popups.length);
|
|
164
|
+
}
|
|
165
|
+
while (handles.length) {
|
|
166
|
+
closeOverlay(handles.pop().name);
|
|
167
|
+
expected.close();
|
|
168
|
+
await addressController().whenSettled();
|
|
169
|
+
for (let attempt = 0; navigation().currentEntry.index !== floor() + expected.index; attempt++) {
|
|
170
|
+
if (attempt > 100)
|
|
171
|
+
throw new Error('popup cleanup did not settle');
|
|
172
|
+
await wait();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
console.error('ADDRESS_HISTORY_TRACE', JSON.stringify(events));
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
history.pushState = original.pushState;
|
|
183
|
+
history.replaceState = original.replaceState;
|
|
184
|
+
navigation().traverseTo = original.traverseTo;
|
|
185
|
+
navigation().removeEventListener('navigate', navigate);
|
|
186
|
+
navigation().removeEventListener('currententrychange', changed);
|
|
187
|
+
}
|
|
188
|
+
}).timeout(30000);
|
|
189
|
+
});
|
|
190
|
+
//# sourceMappingURL=address-sequences.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address-sequences.test.js","sourceRoot":"","sources":["../../test/address-sequences.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture } from '@open-wc/testing'\nimport { sendMouse } from '@web/test-runner-commands'\nimport { html } from 'lit'\nimport { addressController, writeAddress } from '@operato/utils/address.js'\nimport { closeOverlay, openPopup } from '../src/index.js'\nimport type { PopupHandle } from '@operato/popup'\n\nconst wait = () => new Promise(resolve => setTimeout(resolve, 10))\nconst navigation = () => (window as any).navigation\n\n/** An independent product model: visible popups, the user's URL steps, and the cursor among them. */\nclass Expected {\n entries: string[]\n index = 0\n popups: { at: number; below: number }[] = []\n constructor(url: string) {\n this.entries = [url]\n }\n write(url: string, replace = false) {\n if (this.popups.length) return false\n if (url === this.entries[this.index]) return true\n if (replace) this.entries[this.index] = url\n else {\n this.entries.splice(++this.index)\n this.entries.push(url)\n }\n return true\n }\n open() {\n const below = this.index\n const url = this.entries[this.index]\n this.entries.splice(++this.index)\n this.entries.push(url)\n this.popups.push({ at: this.index, below })\n }\n close() {\n const top = this.popups.pop()\n if (top) this.index = top.below\n }\n move(delta: number) {\n this.index += delta\n this.popups = this.popups.filter(popup => popup.at <= this.index)\n }\n}\n\ndescribe('address behaviour against an independent expected history', () => {\n it('matches every step, including close followed immediately by a new committed query', async () => {\n const events: unknown[] = []\n let phase = 'setup'\n const snapshot = (kind: string, details?: unknown) => events.push({\n kind, phase, details, time: performance.now(), ready: document.readyState,\n historyLength: history.length, activated: navigator.userActivation.hasBeenActive, current: navigation().currentEntry.key,\n entries: navigation().entries().map((entry: any) => [entry.key, entry.index, new URL(entry.url).search])\n })\n const observed = new WeakSet<object>()\n const observeEntries = () => navigation().entries().forEach((entry: any) => {\n if (observed.has(entry)) return\n observed.add(entry)\n entry.addEventListener('dispose', () => snapshot('dispose', { key: entry.key, url: entry.url }))\n })\n const navigate = (event: any) => snapshot('navigate', { type: event.navigationType,\n destination: event.destination.key, url: event.destination.url, cancelled: event.defaultPrevented })\n const changed = (event: any) => {\n snapshot('currententrychange', { type: event.navigationType, from: event.from.key })\n observeEntries()\n }\n navigation().addEventListener('navigate', navigate)\n navigation().addEventListener('currententrychange', changed)\n const original = { pushState: history.pushState, replaceState: history.replaceState, traverseTo: navigation().traverseTo }\n for (const method of ['pushState', 'replaceState'] as const) {\n history[method] = function (...args: Parameters<History[typeof method]>) {\n snapshot(method, { url: String(args[2]), stack: new Error().stack })\n return original[method].apply(this, args)\n }\n }\n navigation().traverseTo = function (...args: any[]) {\n snapshot('traverseTo', { key: args[0] })\n const result = original.traverseTo.apply(this, args)\n for (const name of ['committed', 'finished']) result[name].then(\n () => snapshot(name, { key: args[0] }),\n (error: Error) => snapshot(name, { key: args[0], error: error.name }))\n return result\n }\n observeEntries()\n snapshot('start')\n try {\n // The oracle models user actions. At Chrome's 50-entry limit, an unactivated document's\n // entries are preferentially pruned, including a recently pushed baseline. See the native\n // no-app control in operato-application/test/address-browser/native-retention.cjs.\n const start = await fixture<HTMLButtonElement>(html`<button>Start history sequence</button>`)\n const bounds = start.getBoundingClientRect()\n await sendMouse({ type: 'click', position: [Math.round(bounds.x + bounds.width / 2), Math.round(bounds.y + bounds.height / 2)] })\n expect(navigator.userActivation.hasBeenActive, 'real user activation for the product oracle').to.equal(true)\n start.remove()\n await fixture(html`<ox-header-bar></ox-header-bar>`)\n addressController().registerQuery()\n for (let seed = 1; seed <= 10; seed++) {\n let randomState = seed\n const random = () => (randomState = (Math.imul(1664525, randomState) + 1013904223) >>> 0) / 2 ** 32\n expect(await writeAddress(`?filters=seed-${seed}`)).to.equal(true)\n let floorKey = navigation().currentEntry.key\n const floor = () =>\n navigation()\n .entries()\n .findIndex((entry: { key: string }) => entry.key === floorKey)\n const expected = new Expected(location.href)\n let handles: PopupHandle[] = []\n const trace: string[] = []\n const snapshots: unknown[] = []\n for (let step = 0; step < 30; step++) {\n const action = Math.floor(random() * 7)\n phase = `seed ${seed} step ${step} action ${action}`\n snapshot('action')\n trace.push(String(action))\n if (action === 0 || action === 1 || action === 6) {\n if (action === 6 && handles.length) {\n handles.pop()!.close()\n expected.close()\n }\n const url = new URL(expected.entries[expected.index])\n url.searchParams.set(action === 1 ? 'f' : 'filters', `${seed}-${step}`)\n const replace = action === 1\n const accepted = await writeAddress(url, { replace })\n expect(accepted, `seed ${seed}, step ${step}`).to.equal(expected.write(url.href, replace))\n if (accepted && replace && expected.index === 0) floorKey = navigation().currentEntry.key\n } else if (action === 2 && handles.length < 2) {\n handles.push(openPopup(html`<div>picker</div>`, { backdrop: true, escapable: true }))\n expected.open()\n } else if (action === 3 && handles.length) {\n handles.pop()!.close()\n expected.close()\n } else if (action === 4 && expected.index > 0) {\n expected.move(-1)\n await navigation().back().finished\n handles = handles.slice(0, expected.popups.length)\n } else if (action === 5 && expected.index + 1 < expected.entries.length) {\n expected.move(1)\n await navigation().forward().finished\n }\n await addressController().whenSettled()\n for (let attempt = 0; navigation().currentEntry.index !== floor() + expected.index; attempt++) {\n if (attempt > 100) throw new Error(`did not settle: seed ${seed}, step ${step}, trace ${trace}`)\n await wait()\n }\n await wait()\n snapshots.push({ step, action, floorKey, current: navigation().currentEntry.key,\n entries: navigation().entries().map((entry: any) => [entry.key, entry.index, new URL(entry.url).search]) })\n expect(\n floor(),\n `sequence retained: seed ${seed}, step ${step}, snapshots ${JSON.stringify(snapshots)}, trace ${trace}, entries ${navigation()\n .entries()\n .map((entry: { url: string }) => new URL(entry.url).search)}`\n ).to.be.at.least(0)\n const actual = navigation()\n .entries()\n .slice(floor())\n .map((entry: { url: string }) => entry.url)\n const detail = `seed ${seed}, step ${step}, trace ${trace}`\n expect(actual, detail).to.deep.equal(expected.entries)\n expect(location.href, detail).to.equal(expected.entries[expected.index])\n const bar = document.querySelector('ox-header-bar')!.shadowRoot!\n expect(bar.querySelectorAll('ox-floating-overlay').length, detail).to.equal(expected.popups.length)\n }\n while (handles.length) {\n closeOverlay(handles.pop()!.name)\n expected.close()\n await addressController().whenSettled()\n for (let attempt = 0; navigation().currentEntry.index !== floor() + expected.index; attempt++) {\n if (attempt > 100) throw new Error('popup cleanup did not settle')\n await wait()\n }\n }\n }\n } catch (error) {\n console.error('ADDRESS_HISTORY_TRACE', JSON.stringify(events))\n throw error\n } finally {\n history.pushState = original.pushState\n history.replaceState = original.replaceState\n navigation().traverseTo = original.traverseTo\n navigation().removeEventListener('navigate', navigate)\n navigation().removeEventListener('currententrychange', changed)\n }\n }).timeout(30000)\n})\n"]}
|
|
@@ -101,17 +101,17 @@ describe('shared nonmodal entity 360 dock', () => {
|
|
|
101
101
|
await settle();
|
|
102
102
|
expect(dock()).to.exist;
|
|
103
103
|
});
|
|
104
|
-
it('records distinct targets and preserves unrelated address state', () => {
|
|
104
|
+
it('records distinct targets and preserves unrelated address state', async () => {
|
|
105
105
|
const initial = location.href;
|
|
106
106
|
history.replaceState({ userState: 42 }, '', initial);
|
|
107
107
|
const first = new URL(initial);
|
|
108
108
|
first.searchParams.set('f', 'testSpecifications:one');
|
|
109
109
|
first.searchParams.set('revision', 'r1');
|
|
110
|
-
navigateEntity360(first.href);
|
|
110
|
+
expect(await navigateEntity360(first.href)).to.equal(true);
|
|
111
111
|
expect(canGoBackEntity360()).to.equal(false);
|
|
112
112
|
const second = new URL(first);
|
|
113
113
|
second.searchParams.set('revision', 'r2');
|
|
114
|
-
navigateEntity360(second.href);
|
|
114
|
+
expect(await navigateEntity360(second.href)).to.equal(true);
|
|
115
115
|
expect(canGoBackEntity360()).to.equal(true);
|
|
116
116
|
expect(history.state.userState).to.equal(42);
|
|
117
117
|
expect(history.state.entity360Previous).to.equal(first.href);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity360.test.js","sourceRoot":"","sources":["../../test/entity360.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, elementUpdated } from '@open-wc/testing'\nimport { html } from 'lit'\nimport '../src/index.js'\nimport { showEntity360, hideEntity360, navigateEntity360, canGoBackEntity360, type OxEntity360Dock, type Entity360View } from '../src/index.js'\n\nconst owner = {}\nconst labels = { close: 'Close', expand: 'Expand', collapse: 'Collapse', resize: 'Resize', back: 'Back' }\nconst settle = () => new Promise(resolve => setTimeout(resolve, 50))\nlet bar: HTMLElement\nconst dock = () => bar.shadowRoot!.querySelector('ox-entity360-dock') as OxEntity360Dock\nfunction view(name = 'Revision 1'): Entity360View {\n return { key: name, title: 'Test specification', context: name, labels, content: html`<input value=${name}>`, onClose: () => hideEntity360(owner) }\n}\n\ndescribe('shared nonmodal entity 360 dock', () => {\n beforeEach(async () => { bar = await fixture(html`<ox-aside-bar></ox-aside-bar>`) })\n afterEach(() => hideEntity360(owner))\n\n it('uses the aside layout without a modal backdrop or duplicate close action', async () => {\n showEntity360(owner, view())\n await settle()\n expect(dock()).to.exist\n expect(bar.shadowRoot!.querySelector('ox-floating-overlay')).to.equal(null)\n expect(!!dock().shadowRoot!.querySelector('[aria-modal]')).to.equal(matchMedia('(max-width: 900px)').matches)\n expect(dock().shadowRoot!.querySelectorAll('[data-action=\"close\"]').length).to.equal(1)\n })\n\n it('switches the contents in one dock and retains expanded state', async () => {\n showEntity360(owner, view())\n await settle()\n const original = dock()\n original.expanded = true\n showEntity360(owner, view('Approval after · Revision 2'))\n await elementUpdated(original)\n expect(dock()).to.equal(original)\n expect(original.expanded).to.equal(true)\n expect(original.view!.context).to.equal('Approval after · Revision 2')\n expect(original.shadowRoot!.textContent).to.contain('Approval after · Revision 2')\n })\n\n it('refreshes all content while keeping the dock and its read context', async () => {\n showEntity360(owner, view())\n await settle()\n const original = dock()\n original.expanded = true\n const content = original.shadowRoot!.querySelector('ox-entity360-content') as HTMLElement\n const input = content.shadowRoot!.querySelector('input')!\n ;(original.shadowRoot!.querySelector('[data-action=\"refresh\"]') as HTMLElement).click()\n await settle()\n expect(dock()).to.equal(original)\n expect(original.expanded).to.equal(true)\n expect(original.view!.key).to.equal('Revision 1')\n expect(content.shadowRoot!.querySelector('input')).not.to.equal(input)\n expect(content.shadowRoot!.querySelector('input')!.value).to.equal('Revision 1')\n })\n\n it('uses compact header controls and the shared scrollbar theme without local overrides', async () => {\n bar.style.setProperty('--scrollbar-thumb-color', 'rgb(57, 78, 100)')\n showEntity360(owner, { ...view(), content: html`<div style=\"height:3000px\">Long detail</div>` })\n await settle()\n const el = dock()\n const close = el.shadowRoot!.querySelector('[data-action=\"close\"]') as HTMLElement\n expect(close.getBoundingClientRect().width).to.equal(matchMedia('(pointer: coarse)').matches ? 40 : 28)\n const body = el.shadowRoot!.querySelector('.body') as HTMLElement\n expect(getComputedStyle(body).scrollbarGutter).to.equal('stable')\n expect(getComputedStyle(body, '::-webkit-scrollbar').width).to.equal('5px')\n expect(getComputedStyle(body, '::-webkit-scrollbar-track').backgroundColor).to.equal('rgba(0, 0, 0, 0)')\n expect(getComputedStyle(body, '::-webkit-scrollbar-thumb').backgroundColor).to.equal('rgb(57, 78, 100)')\n bar.style.setProperty('--scrollbar-width', '7px')\n bar.style.setProperty('--scrollbar-thumb-border-radius', '2px')\n expect(getComputedStyle(body, '::-webkit-scrollbar').width).to.equal('7px')\n expect(getComputedStyle(body, '::-webkit-scrollbar-thumb').borderRadius).to.equal('2px')\n })\n\n it('closes through the common button and restores the invoking control', async () => {\n let restored = false\n showEntity360(owner, view(), () => { restored = true })\n await settle()\n ;(dock().shadowRoot!.querySelector('[data-action=\"close\"]') as HTMLElement).click()\n await settle()\n expect(dock()).to.equal(null)\n expect(restored).to.equal(true)\n })\n\n it('Escape does not close the dock underneath a modal', async () => {\n showEntity360(owner, view())\n await settle()\n const state = history.state\n history.replaceState({ ...state, overlay: { name: 'confirmation' } }, '')\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))\n expect(dock()).to.exist\n history.replaceState(state, '')\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))\n await settle()\n expect(dock()).to.equal(null)\n })\n\n it('resizes using the keyboard without changing the read context', async () => {\n showEntity360(owner, view())\n await settle()\n const el = dock()\n el.shadowRoot!.querySelector('[role=\"separator\"]')!.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))\n await elementUpdated(el)\n expect(el.style.getPropertyValue('--entity360-width')).to.equal('448px')\n expect(el.view!.context).to.equal('Revision 1')\n })\n\n it('also mounts in fullbleed layouts', async () => {\n bar.setAttribute('fullbleed', '')\n showEntity360(owner, view())\n await settle()\n expect(dock()).to.exist\n })\n\n it('records distinct targets and preserves unrelated address state', () => {\n const initial = location.href\n history.replaceState({ userState: 42 }, '', initial)\n const first = new URL(initial)\n first.searchParams.set('f', 'testSpecifications:one')\n first.searchParams.set('revision', 'r1')\n navigateEntity360(first.href)\n expect(canGoBackEntity360()).to.equal(false)\n const second = new URL(first)\n second.searchParams.set('revision', 'r2')\n navigateEntity360(second.href)\n expect(canGoBackEntity360()).to.equal(true)\n expect(history.state.userState).to.equal(42)\n expect(history.state.entity360Previous).to.equal(first.href)\n history.replaceState({}, '', initial)\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"entity360.test.js","sourceRoot":"","sources":["../../test/entity360.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC1B,OAAO,iBAAiB,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAA4C,MAAM,iBAAiB,CAAA;AAE/I,MAAM,KAAK,GAAG,EAAE,CAAA;AAChB,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACzG,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;AACpE,IAAI,GAAgB,CAAA;AACpB,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,UAAW,CAAC,aAAa,CAAC,mBAAmB,CAAoB,CAAA;AACxF,SAAS,IAAI,CAAC,IAAI,GAAG,YAAY;IAC/B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAA,gBAAgB,IAAI,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAA;AACrJ,CAAC;AAED,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,UAAU,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAA,+BAA+B,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;IACpF,SAAS,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAA;IAErC,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAA;QACvB,MAAM,CAAC,GAAG,CAAC,UAAW,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3E,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,CAAA;QAC7G,MAAM,CAAC,IAAI,EAAE,CAAC,UAAW,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACzF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,QAAQ,GAAG,IAAI,EAAE,CAAA;QACvB,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAA;QACxB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAA;QACzD,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAA;QAC9B,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACxC,MAAM,CAAC,QAAQ,CAAC,IAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAA;QACtE,MAAM,CAAC,QAAQ,CAAC,UAAW,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAA;IACpF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,QAAQ,GAAG,IAAI,EAAE,CAAA;QACvB,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAA;QACxB,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAW,CAAC,aAAa,CAAC,sBAAsB,CAAgB,CAAA;QACzF,MAAM,KAAK,GAAG,OAAO,CAAC,UAAW,CAAC,aAAa,CAAC,OAAO,CAAE,CACxD;QAAC,QAAQ,CAAC,UAAW,CAAC,aAAa,CAAC,yBAAyB,CAAiB,CAAC,KAAK,EAAE,CAAA;QACvF,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACxC,MAAM,CAAC,QAAQ,CAAC,IAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QACjD,MAAM,CAAC,OAAO,CAAC,UAAW,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACtE,MAAM,CAAC,OAAO,CAAC,UAAW,CAAC,aAAa,CAAC,OAAO,CAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IAClF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;QACnG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,yBAAyB,EAAE,kBAAkB,CAAC,CAAA;QACpE,aAAa,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAA,8CAA8C,EAAE,CAAC,CAAA;QAChG,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,EAAE,GAAG,IAAI,EAAE,CAAA;QACjB,MAAM,KAAK,GAAG,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,uBAAuB,CAAgB,CAAA;QAClF,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACvG,MAAM,IAAI,GAAG,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,OAAO,CAAgB,CAAA;QACjE,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACjE,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC3E,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;QACxG,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;QACxG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAA;QACjD,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAA;QAC/D,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC3E,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC1F,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,QAAQ,GAAG,IAAI,CAAA,CAAC,CAAC,CAAC,CAAA;QACvD,MAAM,MAAM,EAAE,CACb;QAAC,IAAI,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,uBAAuB,CAAiB,CAAC,KAAK,EAAE,CAAA;QACnF,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC7B,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;QAC3B,OAAO,CAAC,YAAY,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QACzE,QAAQ,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAA;QACvE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAA;QACvB,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;QAC/B,QAAQ,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAA;QACvE,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,EAAE,GAAG,IAAI,EAAE,CAAA;QACjB,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,oBAAoB,CAAE,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC,CAAA;QACtH,MAAM,cAAc,CAAC,EAAE,CAAC,CAAA;QACxB,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACxE,MAAM,CAAC,EAAE,CAAC,IAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;QACjC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAA;QAC7B,OAAO,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;QACpD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;QAC9B,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAA;QACrD,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC1D,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC5C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC7B,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;QACzC,MAAM,CAAC,MAAM,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3D,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC5C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC5D,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { expect, fixture, elementUpdated } from '@open-wc/testing'\nimport { html } from 'lit'\nimport '../src/index.js'\nimport { showEntity360, hideEntity360, navigateEntity360, canGoBackEntity360, type OxEntity360Dock, type Entity360View } from '../src/index.js'\n\nconst owner = {}\nconst labels = { close: 'Close', expand: 'Expand', collapse: 'Collapse', resize: 'Resize', back: 'Back' }\nconst settle = () => new Promise(resolve => setTimeout(resolve, 50))\nlet bar: HTMLElement\nconst dock = () => bar.shadowRoot!.querySelector('ox-entity360-dock') as OxEntity360Dock\nfunction view(name = 'Revision 1'): Entity360View {\n return { key: name, title: 'Test specification', context: name, labels, content: html`<input value=${name}>`, onClose: () => hideEntity360(owner) }\n}\n\ndescribe('shared nonmodal entity 360 dock', () => {\n beforeEach(async () => { bar = await fixture(html`<ox-aside-bar></ox-aside-bar>`) })\n afterEach(() => hideEntity360(owner))\n\n it('uses the aside layout without a modal backdrop or duplicate close action', async () => {\n showEntity360(owner, view())\n await settle()\n expect(dock()).to.exist\n expect(bar.shadowRoot!.querySelector('ox-floating-overlay')).to.equal(null)\n expect(!!dock().shadowRoot!.querySelector('[aria-modal]')).to.equal(matchMedia('(max-width: 900px)').matches)\n expect(dock().shadowRoot!.querySelectorAll('[data-action=\"close\"]').length).to.equal(1)\n })\n\n it('switches the contents in one dock and retains expanded state', async () => {\n showEntity360(owner, view())\n await settle()\n const original = dock()\n original.expanded = true\n showEntity360(owner, view('Approval after · Revision 2'))\n await elementUpdated(original)\n expect(dock()).to.equal(original)\n expect(original.expanded).to.equal(true)\n expect(original.view!.context).to.equal('Approval after · Revision 2')\n expect(original.shadowRoot!.textContent).to.contain('Approval after · Revision 2')\n })\n\n it('refreshes all content while keeping the dock and its read context', async () => {\n showEntity360(owner, view())\n await settle()\n const original = dock()\n original.expanded = true\n const content = original.shadowRoot!.querySelector('ox-entity360-content') as HTMLElement\n const input = content.shadowRoot!.querySelector('input')!\n ;(original.shadowRoot!.querySelector('[data-action=\"refresh\"]') as HTMLElement).click()\n await settle()\n expect(dock()).to.equal(original)\n expect(original.expanded).to.equal(true)\n expect(original.view!.key).to.equal('Revision 1')\n expect(content.shadowRoot!.querySelector('input')).not.to.equal(input)\n expect(content.shadowRoot!.querySelector('input')!.value).to.equal('Revision 1')\n })\n\n it('uses compact header controls and the shared scrollbar theme without local overrides', async () => {\n bar.style.setProperty('--scrollbar-thumb-color', 'rgb(57, 78, 100)')\n showEntity360(owner, { ...view(), content: html`<div style=\"height:3000px\">Long detail</div>` })\n await settle()\n const el = dock()\n const close = el.shadowRoot!.querySelector('[data-action=\"close\"]') as HTMLElement\n expect(close.getBoundingClientRect().width).to.equal(matchMedia('(pointer: coarse)').matches ? 40 : 28)\n const body = el.shadowRoot!.querySelector('.body') as HTMLElement\n expect(getComputedStyle(body).scrollbarGutter).to.equal('stable')\n expect(getComputedStyle(body, '::-webkit-scrollbar').width).to.equal('5px')\n expect(getComputedStyle(body, '::-webkit-scrollbar-track').backgroundColor).to.equal('rgba(0, 0, 0, 0)')\n expect(getComputedStyle(body, '::-webkit-scrollbar-thumb').backgroundColor).to.equal('rgb(57, 78, 100)')\n bar.style.setProperty('--scrollbar-width', '7px')\n bar.style.setProperty('--scrollbar-thumb-border-radius', '2px')\n expect(getComputedStyle(body, '::-webkit-scrollbar').width).to.equal('7px')\n expect(getComputedStyle(body, '::-webkit-scrollbar-thumb').borderRadius).to.equal('2px')\n })\n\n it('closes through the common button and restores the invoking control', async () => {\n let restored = false\n showEntity360(owner, view(), () => { restored = true })\n await settle()\n ;(dock().shadowRoot!.querySelector('[data-action=\"close\"]') as HTMLElement).click()\n await settle()\n expect(dock()).to.equal(null)\n expect(restored).to.equal(true)\n })\n\n it('Escape does not close the dock underneath a modal', async () => {\n showEntity360(owner, view())\n await settle()\n const state = history.state\n history.replaceState({ ...state, overlay: { name: 'confirmation' } }, '')\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))\n expect(dock()).to.exist\n history.replaceState(state, '')\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))\n await settle()\n expect(dock()).to.equal(null)\n })\n\n it('resizes using the keyboard without changing the read context', async () => {\n showEntity360(owner, view())\n await settle()\n const el = dock()\n el.shadowRoot!.querySelector('[role=\"separator\"]')!.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))\n await elementUpdated(el)\n expect(el.style.getPropertyValue('--entity360-width')).to.equal('448px')\n expect(el.view!.context).to.equal('Revision 1')\n })\n\n it('also mounts in fullbleed layouts', async () => {\n bar.setAttribute('fullbleed', '')\n showEntity360(owner, view())\n await settle()\n expect(dock()).to.exist\n })\n\n it('records distinct targets and preserves unrelated address state', async () => {\n const initial = location.href\n history.replaceState({ userState: 42 }, '', initial)\n const first = new URL(initial)\n first.searchParams.set('f', 'testSpecifications:one')\n first.searchParams.set('revision', 'r1')\n expect(await navigateEntity360(first.href)).to.equal(true)\n expect(canGoBackEntity360()).to.equal(false)\n const second = new URL(first)\n second.searchParams.set('revision', 'r2')\n expect(await navigateEntity360(second.href)).to.equal(true)\n expect(canGoBackEntity360()).to.equal(true)\n expect(history.state.userState).to.equal(42)\n expect(history.state.entity360Previous).to.equal(first.href)\n history.replaceState({}, '', initial)\n })\n})\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { expect, fixture } from '@open-wc/testing';
|
|
2
|
+
import { html } from 'lit';
|
|
3
|
+
import { openPopup } from '../src/index.js';
|
|
4
|
+
const wait = () => new Promise(resolve => setTimeout(resolve, 30));
|
|
5
|
+
describe('popup identity when the browser prunes old history', () => {
|
|
6
|
+
it('closing a nested popup keeps its parent even when entry indices have shifted', async () => {
|
|
7
|
+
await fixture(html `<ox-header-bar></ox-header-bar>`);
|
|
8
|
+
// Chrome retains a bounded session history. New entries can renumber existing entries.
|
|
9
|
+
for (let i = 0; i < 70; i++)
|
|
10
|
+
history.pushState({}, '', `?retention=${i}`);
|
|
11
|
+
const parent = openPopup(html `<div>parent</div>`, { backdrop: true });
|
|
12
|
+
await wait();
|
|
13
|
+
const child = openPopup(html `<div>child</div>`, { backdrop: true });
|
|
14
|
+
await wait();
|
|
15
|
+
child.close();
|
|
16
|
+
await child.result;
|
|
17
|
+
await wait();
|
|
18
|
+
expect(parent.closed, 'the parent is still open').to.equal(false);
|
|
19
|
+
const overlays = document.querySelector('ox-header-bar').shadowRoot.querySelectorAll('ox-floating-overlay');
|
|
20
|
+
expect(overlays.length).to.equal(1);
|
|
21
|
+
parent.close();
|
|
22
|
+
await parent.result;
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=history-retention.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-retention.test.js","sourceRoot":"","sources":["../../test/history-retention.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;AAElE,QAAQ,CAAC,oDAAoD,EAAE,GAAG,EAAE;IAClE,EAAE,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;QAC5F,MAAM,OAAO,CAAC,IAAI,CAAA,iCAAiC,CAAC,CAAA;QACpD,uFAAuF;QACvF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE;YAAE,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,CAAA;QACzE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAA,mBAAmB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;QACrE,MAAM,IAAI,EAAE,CAAA;QACZ,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAA,kBAAkB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;QACnE,MAAM,IAAI,EAAE,CAAA;QACZ,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,MAAM,KAAK,CAAC,MAAM,CAAA;QAClB,MAAM,IAAI,EAAE,CAAA;QACZ,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACjE,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAC,eAAe,CAAE,CAAC,UAAW,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;QAC7G,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACnC,MAAM,CAAC,KAAK,EAAE,CAAA;QACd,MAAM,MAAM,CAAC,MAAM,CAAA;IACrB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { expect, fixture } from '@open-wc/testing'\nimport { html } from 'lit'\nimport { openPopup } from '../src/index.js'\n\nconst wait = () => new Promise(resolve => setTimeout(resolve, 30))\n\ndescribe('popup identity when the browser prunes old history', () => {\n it('closing a nested popup keeps its parent even when entry indices have shifted', async () => {\n await fixture(html`<ox-header-bar></ox-header-bar>`)\n // Chrome retains a bounded session history. New entries can renumber existing entries.\n for (let i = 0; i < 70; i++) history.pushState({}, '', `?retention=${i}`)\n const parent = openPopup(html`<div>parent</div>`, { backdrop: true })\n await wait()\n const child = openPopup(html`<div>child</div>`, { backdrop: true })\n await wait()\n child.close()\n await child.result\n await wait()\n expect(parent.closed, 'the parent is still open').to.equal(false)\n const overlays = document.querySelector('ox-header-bar')!.shadowRoot!.querySelectorAll('ox-floating-overlay')\n expect(overlays.length).to.equal(1)\n parent.close()\n await parent.result\n })\n})\n"]}
|