@operato/shell 10.29.68 → 10.29.70
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 +33 -0
- package/dist/src/app/pages/page-view.d.ts +2 -1
- package/dist/src/app/pages/page-view.js +25 -7
- package/dist/src/app/pages/page-view.js.map +1 -1
- package/dist/src/drafts/draft-controller.d.ts +74 -0
- package/dist/src/drafts/draft-controller.js +164 -0
- package/dist/src/drafts/draft-controller.js.map +1 -0
- package/dist/src/drafts/draft-owner.d.ts +6 -0
- package/dist/src/drafts/draft-owner.js +10 -0
- package/dist/src/drafts/draft-owner.js.map +1 -0
- package/dist/src/drafts/unsaved-draft-controller.d.ts +5 -0
- package/dist/src/drafts/unsaved-draft-controller.js +19 -0
- package/dist/src/drafts/unsaved-draft-controller.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/test/draft-controller.test.d.ts +1 -0
- package/dist/test/draft-controller.test.js +168 -0
- package/dist/test/draft-controller.test.js.map +1 -0
- package/dist/test/draft-owner.test.d.ts +1 -0
- package/dist/test/draft-owner.test.js +100 -0
- package/dist/test/draft-owner.test.js.map +1 -0
- package/dist/test/page-drafts.test.d.ts +1 -0
- package/dist/test/page-drafts.test.js +24 -0
- package/dist/test/page-drafts.test.js.map +1 -0
- package/dist/test/page-refresh-queries.test.d.ts +1 -0
- package/dist/test/page-refresh-queries.test.js +89 -0
- package/dist/test/page-refresh-queries.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/test/draft-controller.test.ts +186 -0
- package/test/draft-owner.test.ts +109 -0
- package/test/page-drafts.test.ts +23 -0
- package/test/page-refresh-queries.test.ts +96 -0
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.
|
|
5
|
+
"version": "10.29.70",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/src/index.js",
|
|
8
8
|
"module": "dist/src/index.js",
|
|
@@ -60,11 +60,11 @@
|
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@material/web": "^2.0.0",
|
|
63
|
-
"@operato/graphql": "^10.29.
|
|
63
|
+
"@operato/graphql": "^10.29.69",
|
|
64
64
|
"@operato/i18n": "^10.29.27",
|
|
65
|
-
"@operato/popup": "^10.29.
|
|
66
|
-
"@operato/styles": "^10.29.
|
|
67
|
-
"@operato/utils": "^10.29.
|
|
65
|
+
"@operato/popup": "^10.29.70",
|
|
66
|
+
"@operato/styles": "^10.29.70",
|
|
67
|
+
"@operato/utils": "^10.29.69",
|
|
68
68
|
"@webcomponents/scoped-custom-element-registry": "^0.0.9",
|
|
69
69
|
"lit": "^3.1.2",
|
|
70
70
|
"lodash-es": "^4.17.21",
|
|
@@ -103,5 +103,5 @@
|
|
|
103
103
|
"prettier --write"
|
|
104
104
|
]
|
|
105
105
|
},
|
|
106
|
-
"gitHead": "
|
|
106
|
+
"gitHead": "7451d7242ca5e396bbdeb89fc46470d52c89e8cd"
|
|
107
107
|
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { expect, fixture } from '@open-wc/testing'
|
|
2
|
+
import { html, LitElement } from 'lit'
|
|
3
|
+
|
|
4
|
+
import { QUERY_ANSWERED } from '@operato/graphql'
|
|
5
|
+
import { DraftController, draftsOn } from '../src/drafts/draft-controller.js'
|
|
6
|
+
import { draftKey, readDraft, removeDraft } from '../src/drafts/draft-store.js'
|
|
7
|
+
import { UnsavedDraftController } from '../src/drafts/unsaved-draft-controller.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* An edit form over what was read (ADR-0190 decision 2): a field shows its edit, else the read; a save clears only
|
|
11
|
+
* the edits still as sent; another record drops the edits.
|
|
12
|
+
*/
|
|
13
|
+
type Rule = { name: string; body: string }
|
|
14
|
+
|
|
15
|
+
class RuleForm extends LitElement {
|
|
16
|
+
static properties = { read: { attribute: false }, recordId: {} }
|
|
17
|
+
read?: Rule
|
|
18
|
+
recordId = 'a'
|
|
19
|
+
draft = new DraftController<Rule>(this, { read: () => this.read, key: () => this.recordId })
|
|
20
|
+
}
|
|
21
|
+
customElements.define('rule-form', RuleForm)
|
|
22
|
+
|
|
23
|
+
const open = async () => {
|
|
24
|
+
const form = await fixture<RuleForm>(html`<rule-form .read=${{ name: 'A', body: 'old' }}></rule-form>`)
|
|
25
|
+
await form.updateComplete
|
|
26
|
+
return form
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('DraftController', () => {
|
|
30
|
+
it('shows an edit, else what was read', async () => {
|
|
31
|
+
const form = await open()
|
|
32
|
+
expect(form.draft.value('name')).to.equal('A')
|
|
33
|
+
form.draft.set('name', 'A2')
|
|
34
|
+
expect(form.draft.value('name')).to.equal('A2')
|
|
35
|
+
expect(form.draft.value('body')).to.equal('old')
|
|
36
|
+
expect(form.draft.dirty).to.equal(true)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('a save clears only what it sent and is still as sent; a failed save clears nothing', async () => {
|
|
40
|
+
const form = await open()
|
|
41
|
+
form.draft.set('name', 'A2')
|
|
42
|
+
let release!: (answer: string | undefined) => void
|
|
43
|
+
const saving = form.draft.submit(sent => {
|
|
44
|
+
expect(sent).to.deep.equal({ name: 'A2' })
|
|
45
|
+
return new Promise<string | undefined>(resolve => (release = resolve))
|
|
46
|
+
})
|
|
47
|
+
form.draft.set('body', 'typed while saving')
|
|
48
|
+
release('saved')
|
|
49
|
+
await saving
|
|
50
|
+
expect(form.draft.edits).to.deep.equal({ body: 'typed while saving' })
|
|
51
|
+
|
|
52
|
+
form.draft.set('name', 'A3')
|
|
53
|
+
await form.draft.submit(async () => undefined)
|
|
54
|
+
expect(form.draft.edits).to.deep.equal({ body: 'typed while saving', name: 'A3' })
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('a value put back to what was read is no edit', async () => {
|
|
58
|
+
const form = await open()
|
|
59
|
+
form.draft.set('name', 'A2')
|
|
60
|
+
form.draft.set('name', 'A')
|
|
61
|
+
expect(form.draft.dirty).to.equal(false)
|
|
62
|
+
expect(form.draft.value('name')).to.equal('A')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('a field typed back to what was read while a save is out stays an edit after the answer', async () => {
|
|
66
|
+
const form = await open()
|
|
67
|
+
form.draft.set('name', 'B')
|
|
68
|
+
let release!: (answer: string | undefined) => void
|
|
69
|
+
const saving = form.draft.submit(() => new Promise<string | undefined>(resolve => (release = resolve)))
|
|
70
|
+
form.draft.set('name', 'A')
|
|
71
|
+
release('saved')
|
|
72
|
+
await saving
|
|
73
|
+
expect(form.draft.edits).to.deep.equal({ name: 'A' })
|
|
74
|
+
expect(form.draft.value('name')).to.equal('A')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('another record drops the edits', async () => {
|
|
78
|
+
const form = await open()
|
|
79
|
+
form.draft.set('name', 'A2')
|
|
80
|
+
form.recordId = 'b'
|
|
81
|
+
await form.updateComplete
|
|
82
|
+
expect(form.draft.dirty).to.equal(false)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('is known to its host while connected', async () => {
|
|
86
|
+
const form = await open()
|
|
87
|
+
expect(draftsOn(form)).to.deep.equal([form.draft])
|
|
88
|
+
form.remove()
|
|
89
|
+
expect(draftsOn(form)).to.deep.equal([])
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
class KeptForm extends LitElement {
|
|
94
|
+
static properties = { read: { attribute: false }, recordId: {} }
|
|
95
|
+
read?: Rule
|
|
96
|
+
recordId = 'a'
|
|
97
|
+
draft = new DraftController<Rule>(this, {
|
|
98
|
+
read: () => this.read,
|
|
99
|
+
key: () => this.recordId,
|
|
100
|
+
keep: { address: () => ({ user: 'u', domain: 'd', screen: '/rules', target: this.recordId }) }
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
customElements.define('kept-rule-form', KeptForm)
|
|
104
|
+
|
|
105
|
+
describe('DraftController keep', () => {
|
|
106
|
+
const at = (target: string) => draftKey({ user: 'u', domain: 'd', screen: '/rules', target })
|
|
107
|
+
let wait: number
|
|
108
|
+
beforeEach(async () => {
|
|
109
|
+
wait = UnsavedDraftController.WAIT_MS
|
|
110
|
+
UnsavedDraftController.WAIT_MS = 0
|
|
111
|
+
await removeDraft(at('a'))
|
|
112
|
+
await removeDraft(at('b'))
|
|
113
|
+
})
|
|
114
|
+
afterEach(() => (UnsavedDraftController.WAIT_MS = wait))
|
|
115
|
+
const settle = () => new Promise(resolve => setTimeout(resolve, 50))
|
|
116
|
+
|
|
117
|
+
it('writes the edits for the record, and keeps them when the form moves to another', async () => {
|
|
118
|
+
const form = await fixture<KeptForm>(html`<kept-rule-form .read=${{ name: 'A', body: 'old' }}></kept-rule-form>`)
|
|
119
|
+
form.draft.set('name', 'A2')
|
|
120
|
+
await settle()
|
|
121
|
+
expect((await readDraft(at('a')))?.value).to.deep.equal({ name: 'A2' })
|
|
122
|
+
expect(form.draft.kept).to.equal(true)
|
|
123
|
+
/* Typed and moved at once: what was typed is written for the record left, not lost or written for the next. */
|
|
124
|
+
form.draft.set('name', 'A3')
|
|
125
|
+
form.recordId = 'b'
|
|
126
|
+
await form.updateComplete
|
|
127
|
+
await settle()
|
|
128
|
+
expect(form.draft.dirty).to.equal(false)
|
|
129
|
+
expect((await readDraft(at('a')))?.value).to.deep.equal({ name: 'A3' })
|
|
130
|
+
expect(await readDraft(at('b'))).to.equal(undefined)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('a save that clears the edits drops what was kept', async () => {
|
|
134
|
+
const form = await fixture<KeptForm>(html`<kept-rule-form .read=${{ name: 'A', body: 'old' }}></kept-rule-form>`)
|
|
135
|
+
form.draft.set('name', 'A2')
|
|
136
|
+
await settle()
|
|
137
|
+
await form.draft.submit(async () => 'saved')
|
|
138
|
+
await settle()
|
|
139
|
+
expect(await readDraft(at('a'))).to.equal(undefined)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('a save that answers after a move clears what was kept for the record it was sent from, and nothing else', async () => {
|
|
143
|
+
const form = await fixture<KeptForm>(html`<kept-rule-form .read=${{ name: 'A', body: 'old' }}></kept-rule-form>`)
|
|
144
|
+
form.draft.set('name', 'A2')
|
|
145
|
+
await settle()
|
|
146
|
+
let answer!: (value: string) => void
|
|
147
|
+
const saving = form.draft.submit(() => new Promise<string>(resolve => (answer = resolve)))
|
|
148
|
+
form.recordId = 'b'
|
|
149
|
+
await form.updateComplete
|
|
150
|
+
form.draft.set('name', 'A2')
|
|
151
|
+
await settle()
|
|
152
|
+
answer('saved')
|
|
153
|
+
await saving
|
|
154
|
+
await settle()
|
|
155
|
+
expect(await readDraft(at('a'))).to.equal(undefined)
|
|
156
|
+
expect(form.draft.edits).to.deep.equal({ name: 'A2' }, "b's edit equal to what was sent stays")
|
|
157
|
+
expect((await readDraft(at('b')))?.value).to.deep.equal({ name: 'A2' })
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('a save that answers after the form came back to its record leaves what is edited there now kept', async () => {
|
|
161
|
+
const form = await fixture<KeptForm>(html`<kept-rule-form .read=${{ name: 'A', body: 'old' }}></kept-rule-form>`)
|
|
162
|
+
form.draft.set('name', 'A2')
|
|
163
|
+
await settle()
|
|
164
|
+
let answer!: (value: string) => void
|
|
165
|
+
const saving = form.draft.submit(() => new Promise<string>(resolve => (answer = resolve)))
|
|
166
|
+
form.recordId = 'b'
|
|
167
|
+
await form.updateComplete
|
|
168
|
+
form.recordId = 'a'
|
|
169
|
+
await form.updateComplete
|
|
170
|
+
form.draft.set('name', 'A2')
|
|
171
|
+
await settle()
|
|
172
|
+
answer('saved')
|
|
173
|
+
await saving
|
|
174
|
+
await settle()
|
|
175
|
+
expect(form.draft.edits).to.deep.equal({ name: 'A2' })
|
|
176
|
+
expect((await readDraft(at('a')))?.value).to.deep.equal({ name: 'A2' })
|
|
177
|
+
expect(form.draft.kept).to.equal(true)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('offers nothing when the record answers with nothing kept', async () => {
|
|
181
|
+
const form = await fixture<KeptForm>(html`<kept-rule-form .read=${{ name: 'A', body: 'old' }}></kept-rule-form>`)
|
|
182
|
+
form.dispatchEvent(new Event(QUERY_ANSWERED))
|
|
183
|
+
await settle()
|
|
184
|
+
expect(form.draft.dirty).to.equal(false)
|
|
185
|
+
})
|
|
186
|
+
})
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { expect, fixture } from '@open-wc/testing'
|
|
2
|
+
import { html, LitElement } from 'lit'
|
|
3
|
+
import { OxPrompt } from '@operato/popup'
|
|
4
|
+
|
|
5
|
+
import { QUERY_ANSWERED } from '@operato/graphql'
|
|
6
|
+
import { DraftController } from '../src/drafts/draft-controller.js'
|
|
7
|
+
import { draftOwner } from '../src/drafts/draft-owner.js'
|
|
8
|
+
import { draftKey, readDraft, removeDraftsOf } from '../src/drafts/draft-store.js'
|
|
9
|
+
import { UnsavedDraftController } from '../src/drafts/unsaved-draft-controller.js'
|
|
10
|
+
import { store } from '../src/store.js'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A draft belongs to the signed-in person (ADR-0190): kept and offered back to them, never to someone else, and
|
|
14
|
+
* taken away when they sign out. With no one signed in nothing is written.
|
|
15
|
+
*/
|
|
16
|
+
let signedIn: { id?: string } | null = null
|
|
17
|
+
store.addReducers({ auth: () => ({ user: signedIn }) })
|
|
18
|
+
const signIn = (user: { id?: string } | null) => {
|
|
19
|
+
signedIn = user
|
|
20
|
+
store.dispatch({ type: 'test-sign-in' })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type Note = { body: string }
|
|
24
|
+
|
|
25
|
+
class OwnedForm extends LitElement {
|
|
26
|
+
read?: Note = { body: 'old' }
|
|
27
|
+
draft = new DraftController<Note>(this, {
|
|
28
|
+
read: () => this.read,
|
|
29
|
+
key: () => 'n-1',
|
|
30
|
+
keep: {
|
|
31
|
+
address: () => {
|
|
32
|
+
const user = draftOwner()
|
|
33
|
+
return user ? { user, domain: 'd', screen: '/notes', target: 'n-1' } : undefined
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
customElements.define('owned-note-form', OwnedForm)
|
|
39
|
+
|
|
40
|
+
describe('draftOwner', () => {
|
|
41
|
+
const settle = () => new Promise(resolve => setTimeout(resolve, 50))
|
|
42
|
+
const keyOf = (user: string) => draftKey({ user, domain: 'd', screen: '/notes', target: 'n-1' })
|
|
43
|
+
const open = OxPrompt.open
|
|
44
|
+
let wait: number
|
|
45
|
+
beforeEach(async () => {
|
|
46
|
+
wait = UnsavedDraftController.WAIT_MS
|
|
47
|
+
UnsavedDraftController.WAIT_MS = 0
|
|
48
|
+
await removeDraftsOf('kim')
|
|
49
|
+
await removeDraftsOf('lee')
|
|
50
|
+
})
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
UnsavedDraftController.WAIT_MS = wait
|
|
53
|
+
;(OxPrompt as any).open = open
|
|
54
|
+
signIn(null)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('is the signed-in id, and nobody while no one is signed in', () => {
|
|
58
|
+
signIn({ id: 'kim' })
|
|
59
|
+
expect(draftOwner()).to.equal('kim')
|
|
60
|
+
signIn({})
|
|
61
|
+
expect(draftOwner()).to.equal(undefined)
|
|
62
|
+
signIn(null)
|
|
63
|
+
expect(draftOwner()).to.equal(undefined)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('a draft is written for its owner and offered back to them', async () => {
|
|
67
|
+
signIn({ id: 'kim' })
|
|
68
|
+
const form = await fixture<OwnedForm>(html`<owned-note-form></owned-note-form>`)
|
|
69
|
+
form.draft.set('body', 'typed')
|
|
70
|
+
await settle()
|
|
71
|
+
expect((await readDraft(keyOf('kim')))?.value).to.deep.equal({ body: 'typed' })
|
|
72
|
+
form.remove()
|
|
73
|
+
|
|
74
|
+
;(OxPrompt as any).open = async () => true
|
|
75
|
+
const again = await fixture<OwnedForm>(html`<owned-note-form></owned-note-form>`)
|
|
76
|
+
again.dispatchEvent(new Event(QUERY_ANSWERED))
|
|
77
|
+
await settle()
|
|
78
|
+
expect(again.draft.value('body')).to.equal('typed')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('someone else is offered nothing, and signing out takes the draft away', async () => {
|
|
82
|
+
signIn({ id: 'kim' })
|
|
83
|
+
const form = await fixture<OwnedForm>(html`<owned-note-form></owned-note-form>`)
|
|
84
|
+
form.draft.set('body', 'typed')
|
|
85
|
+
await settle()
|
|
86
|
+
form.remove()
|
|
87
|
+
|
|
88
|
+
signIn({ id: 'lee' })
|
|
89
|
+
let asked = false
|
|
90
|
+
;(OxPrompt as any).open = async () => (asked = true)
|
|
91
|
+
const theirs = await fixture<OwnedForm>(html`<owned-note-form></owned-note-form>`)
|
|
92
|
+
theirs.dispatchEvent(new Event(QUERY_ANSWERED))
|
|
93
|
+
await settle()
|
|
94
|
+
expect(asked).to.equal(false)
|
|
95
|
+
expect(theirs.draft.value('body')).to.equal('old')
|
|
96
|
+
|
|
97
|
+
await removeDraftsOf('kim')
|
|
98
|
+
expect(await readDraft(keyOf('kim'))).to.equal(undefined)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('with no one signed in nothing is written', async () => {
|
|
102
|
+
signIn(null)
|
|
103
|
+
const form = await fixture<OwnedForm>(html`<owned-note-form></owned-note-form>`)
|
|
104
|
+
form.draft.set('body', 'typed')
|
|
105
|
+
await settle()
|
|
106
|
+
expect(await readDraft(keyOf('kim'))).to.equal(undefined)
|
|
107
|
+
expect(form.draft.kept).to.equal(false)
|
|
108
|
+
})
|
|
109
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { expect, fixture } from '@open-wc/testing'
|
|
2
|
+
import { html } from 'lit'
|
|
3
|
+
|
|
4
|
+
import { DraftController } from '../src/drafts/draft-controller.js'
|
|
5
|
+
import { PageView } from '../src/app/pages/page-view.js'
|
|
6
|
+
|
|
7
|
+
/** A page's drafts (ADR-0190) are its unsaved state: the shell asks before they are lost, and drops them on discard. */
|
|
8
|
+
class EditingPage extends PageView {
|
|
9
|
+
draft = new DraftController<{ name: string }>(this, { read: () => ({ name: 'A' }) })
|
|
10
|
+
}
|
|
11
|
+
customElements.define('editing-page', EditingPage)
|
|
12
|
+
|
|
13
|
+
describe('page drafts', () => {
|
|
14
|
+
it('an edited draft makes the page dirty; a discard drops it', async () => {
|
|
15
|
+
const page = await fixture<EditingPage>(html`<editing-page></editing-page>`)
|
|
16
|
+
expect(page.addressDirty).to.equal(false)
|
|
17
|
+
page.draft.set('name', 'A2')
|
|
18
|
+
expect(page.addressDirty).to.equal(true)
|
|
19
|
+
page.discardAddressEdits({ route: false })
|
|
20
|
+
expect(page.addressDirty).to.equal(false)
|
|
21
|
+
expect(page.draft.value('name')).to.equal('A')
|
|
22
|
+
})
|
|
23
|
+
})
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { expect, fixture } from '@open-wc/testing'
|
|
2
|
+
import gql from 'graphql-tag'
|
|
3
|
+
import { html } from 'lit'
|
|
4
|
+
|
|
5
|
+
import { QueryController } from '@operato/graphql'
|
|
6
|
+
import { PageView } from '../src/app/pages/page-view.js'
|
|
7
|
+
|
|
8
|
+
/** A page refresh (ADR-0174) reads again what the page declared it reads (ADR-0190), as it reads its grids again. */
|
|
9
|
+
|
|
10
|
+
const frame = () => new Promise(resolve => requestAnimationFrame(resolve))
|
|
11
|
+
const settle = () => new Promise(resolve => setTimeout(resolve, 20))
|
|
12
|
+
|
|
13
|
+
class DeclaringPage extends PageView {
|
|
14
|
+
contexts: string[] = []
|
|
15
|
+
get context() {
|
|
16
|
+
return { title: this.rule?.data?.rule?.name ?? '' }
|
|
17
|
+
}
|
|
18
|
+
updateContext() {
|
|
19
|
+
this.contexts.push(this.context.title)
|
|
20
|
+
}
|
|
21
|
+
rule = new QueryController(
|
|
22
|
+
this,
|
|
23
|
+
gql`
|
|
24
|
+
query {
|
|
25
|
+
rule {
|
|
26
|
+
name
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`
|
|
30
|
+
)
|
|
31
|
+
render() {
|
|
32
|
+
return html`${this.rule.data?.rule?.name ?? ''}`
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
customElements.define('declaring-page', DeclaringPage)
|
|
36
|
+
|
|
37
|
+
describe('page refresh and declared queries', () => {
|
|
38
|
+
let asked = 0
|
|
39
|
+
let fetched: typeof window.fetch
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
asked = 0
|
|
42
|
+
fetched = window.fetch
|
|
43
|
+
window.fetch = async () => {
|
|
44
|
+
asked++
|
|
45
|
+
return new Response(JSON.stringify({ data: { rule: { name: `read ${asked}` } } }), {
|
|
46
|
+
headers: { 'content-type': 'application/json' }
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
afterEach(() => (window.fetch = fetched))
|
|
51
|
+
|
|
52
|
+
it('reads the declared query again', async () => {
|
|
53
|
+
const page = await fixture<DeclaringPage>(html`<declaring-page></declaring-page>`)
|
|
54
|
+
page.lifecycle = { active: true, params: {} }
|
|
55
|
+
page.active = true
|
|
56
|
+
await page.updateComplete
|
|
57
|
+
await frame()
|
|
58
|
+
await settle()
|
|
59
|
+
expect(asked).to.equal(1)
|
|
60
|
+
await page.refresh()
|
|
61
|
+
await settle()
|
|
62
|
+
expect(asked).to.equal(2)
|
|
63
|
+
expect(page.rule.data?.rule.name).to.equal('read 2')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('says its context again once a declared query answered - a title read from the data', async () => {
|
|
67
|
+
const answer = window.fetch
|
|
68
|
+
window.fetch = async (...args) => (await new Promise(resolve => setTimeout(resolve, 150)), answer(...args))
|
|
69
|
+
const page = await fixture<DeclaringPage>(html`<declaring-page></declaring-page>`)
|
|
70
|
+
page.lifecycle = { active: true, params: {} }
|
|
71
|
+
page.active = true
|
|
72
|
+
await page.updateComplete
|
|
73
|
+
await frame()
|
|
74
|
+
expect(page.contexts[page.contexts.length - 1]).to.equal('')
|
|
75
|
+
await new Promise(resolve => setTimeout(resolve, 300))
|
|
76
|
+
expect(page.contexts[page.contexts.length - 1]).to.equal('read 1')
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('reads the declared query again when the page is shown again, not on its first opening', async () => {
|
|
80
|
+
const page = await fixture<DeclaringPage>(html`<declaring-page></declaring-page>`)
|
|
81
|
+
page.lifecycle = { active: true, params: {} }
|
|
82
|
+
page.active = true
|
|
83
|
+
await page.updateComplete
|
|
84
|
+
await frame()
|
|
85
|
+
await settle()
|
|
86
|
+
expect(asked).to.equal(1)
|
|
87
|
+
page.active = false
|
|
88
|
+
await page.updateComplete
|
|
89
|
+
await settle()
|
|
90
|
+
expect(asked).to.equal(1)
|
|
91
|
+
page.active = true
|
|
92
|
+
await page.updateComplete
|
|
93
|
+
await settle()
|
|
94
|
+
expect(asked).to.equal(2)
|
|
95
|
+
})
|
|
96
|
+
})
|