@operato/shell 10.29.52 → 10.29.60

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@operato/shell",
3
3
  "description": "WebApplication architecturing shell following open-wc recommendations",
4
4
  "author": "heartyoh",
5
- "version": "10.29.52",
5
+ "version": "10.29.60",
6
6
  "type": "module",
7
7
  "main": "dist/src/index.js",
8
8
  "module": "dist/src/index.js",
@@ -62,7 +62,7 @@
62
62
  "@material/web": "^2.0.0",
63
63
  "@operato/graphql": "^10.29.49",
64
64
  "@operato/i18n": "^10.29.27",
65
- "@operato/popup": "^10.29.52",
65
+ "@operato/popup": "^10.29.59",
66
66
  "@operato/styles": "^10.29.30",
67
67
  "@operato/utils": "^10.29.49",
68
68
  "@webcomponents/scoped-custom-element-registry": "^0.0.9",
@@ -103,5 +103,5 @@
103
103
  "prettier --write"
104
104
  ]
105
105
  },
106
- "gitHead": "2e34202735031117c1f096297dee7e48d3595144"
106
+ "gitHead": "aa25a78fc85445ead63a305c1fd7c973551a0d24"
107
107
  }
@@ -0,0 +1,166 @@
1
+ import { expect, fixture } from '@open-wc/testing'
2
+ import { html } from 'lit'
3
+
4
+ import { PageView } from '../src/app/pages/page-view.js'
5
+
6
+ /**
7
+ * A page refresh (ADR-0174) reads the page again as if it had just been opened at its address: every way a page
8
+ * reads - once at initialization, on activation, on new route arguments - runs again, and so does a grid the page
9
+ * left to read itself. Unsaved edits follow the rule of a route change on the page on screen.
10
+ */
11
+
12
+ class FakeGrist extends HTMLElement {
13
+ reads = 0
14
+ dirtyRecords: unknown[] = []
15
+ async fetch() {
16
+ this.reads++
17
+ }
18
+ reset() {
19
+ this.dirtyRecords = []
20
+ }
21
+ flushEdits() {}
22
+ }
23
+ customElements.define('ox-grist', FakeGrist)
24
+
25
+ const frame = () => new Promise(resolve => requestAnimationFrame(resolve))
26
+
27
+ class ReadingPage extends PageView {
28
+ initialized = 0
29
+ seen: string[][] = []
30
+ /** Reads the first grid on new route arguments only, as Office's ledger does. */
31
+ readsOnParams = true
32
+ answer = true
33
+ asked = 0
34
+
35
+ render() {
36
+ return html`<ox-grist id="own"></ox-grist><ox-grist id="self"></ox-grist>`
37
+ }
38
+
39
+ pageInitialized() {
40
+ this.initialized++
41
+ }
42
+
43
+ pageUpdated(changes: any) {
44
+ this.seen.push(Object.keys(changes).sort())
45
+ if (this.readsOnParams && changes.params) void this.grid('own').fetch()
46
+ }
47
+
48
+ async canDeactivate() {
49
+ this.asked++
50
+ return this.answer
51
+ }
52
+
53
+ grid(id: string) {
54
+ return this.renderRoot.querySelector(`#${id}`) as FakeGrist
55
+ }
56
+ }
57
+ customElements.define('refresh-reading-page', ReadingPage)
58
+
59
+ const open = async () => {
60
+ const page = await fixture<ReadingPage>(html`<refresh-reading-page></refresh-reading-page>`)
61
+ page.lifecycle = { active: true, params: { year: '2026' } }
62
+ page.active = true
63
+ await page.updateComplete
64
+ await frame()
65
+ await frame()
66
+ return page
67
+ }
68
+
69
+ describe('page refresh', () => {
70
+ it('opening the page again at the same address reads nothing: the reason a refresh is needed', async () => {
71
+ const page = await open()
72
+ const seen = page.seen.length
73
+ page.lifecycle = { active: true, params: { year: '2026' } }
74
+ await page.updateComplete
75
+ await frame()
76
+ expect(page.seen.length).to.equal(seen)
77
+ })
78
+
79
+ it('plays the lifecycle from nothing: initialization and every change a page reads on', async () => {
80
+ const page = await open()
81
+ expect(await page.refresh()).to.equal(true)
82
+ expect(page.initialized).to.equal(2)
83
+ expect(page.seen[page.seen.length - 1]).to.include.members(['initialized', 'active', 'params'])
84
+ })
85
+
86
+ it('a grid the page read again is not read twice; a grid that reads itself is read again', async () => {
87
+ const page = await open()
88
+ page.grid('self').reads = 1
89
+ const own = page.grid('own').reads
90
+ await page.refresh()
91
+ expect(page.grid('own').reads).to.equal(own + 1)
92
+ expect(page.grid('self').reads).to.equal(2)
93
+ })
94
+
95
+ it('a grid never read is left alone: it may be waiting for a selection', async () => {
96
+ const page = await open()
97
+ await page.refresh()
98
+ expect(page.grid('self').reads).to.equal(0)
99
+ })
100
+
101
+ it('unsaved grid edits no draft keeps are asked about; on "keep" nothing is read', async () => {
102
+ const page = await open()
103
+ page.grid('self').dirtyRecords = [{}]
104
+ page.answer = false
105
+ const initialized = page.initialized
106
+ expect(await page.refresh()).to.equal(false)
107
+ expect(page.asked).to.equal(1)
108
+ expect(page.initialized).to.equal(initialized)
109
+ expect(page.grid('self').dirtyRecords.length).to.equal(1)
110
+ })
111
+
112
+ it('a refresh nobody asked for never asks: with unsaved edits it reads nothing', async () => {
113
+ const page = await open()
114
+ page.grid('self').dirtyRecords = [{}]
115
+ const initialized = page.initialized
116
+ expect(await page.refresh({ ask: false })).to.equal(false)
117
+ expect(page.asked).to.equal(0)
118
+ expect(page.initialized).to.equal(initialized)
119
+ expect(page.grid('self').dirtyRecords.length).to.equal(1)
120
+ })
121
+
122
+ it('a refresh nobody asked for reads nothing even over edits a draft keeps: no restore offer follows', async () => {
123
+ const page = await open()
124
+ page.grid('self').dirtyRecords = [{}]
125
+ Object.defineProperty(page, 'addressEditsKept', { get: () => true })
126
+ const initialized = page.initialized
127
+ expect(await page.refresh({ ask: false })).to.equal(false)
128
+ expect(page.initialized).to.equal(initialized)
129
+
130
+ expect(await page.refresh()).to.equal(true)
131
+ expect(page.asked).to.equal(0)
132
+ expect(page.initialized).to.equal(initialized + 1)
133
+ })
134
+
135
+ it('without unsaved edits it reads like any refresh', async () => {
136
+ const page = await open()
137
+ expect(await page.refresh({ ask: false })).to.equal(true)
138
+ expect(page.initialized).to.equal(2)
139
+ })
140
+
141
+ it('on "discard" the edits are reset and the page is read', async () => {
142
+ const page = await open()
143
+ page.grid('self').dirtyRecords = [{}]
144
+ expect(await page.refresh()).to.equal(true)
145
+ expect(page.grid('self').dirtyRecords.length).to.equal(0)
146
+ expect(page.initialized).to.equal(2)
147
+ })
148
+
149
+ it('a page not on screen is read when it is next shown', async () => {
150
+ const page = await open()
151
+ page.grid('self').reads = 1
152
+ page.active = false
153
+ await page.updateComplete
154
+ await page.refresh()
155
+ expect(page.initialized).to.equal(1)
156
+
157
+ page.active = true
158
+ await page.updateComplete
159
+ await frame()
160
+ await frame()
161
+ await frame()
162
+ expect(page.initialized).to.equal(2)
163
+ expect(page.seen[page.seen.length - 1]).to.include.members(['initialized', 'active', 'params'])
164
+ expect(page.grid('self').reads).to.equal(2)
165
+ })
166
+ })