@lovett/ui 0.0.11 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-RBYWGBQ2.js +2752 -0
- package/dist/chunk-RBYWGBQ2.js.map +1 -0
- package/dist/index.d.ts +5574 -57
- package/dist/index.js +21650 -11206
- package/dist/index.js.map +1 -1
- package/dist/rich-composer-impl-5NO443A6.js +1859 -0
- package/dist/rich-composer-impl-5NO443A6.js.map +1 -0
- package/dist/styles.css +1570 -0
- package/dist/tokens.css +112 -0
- package/package.json +8 -1
- package/src/__tests__/avatar.test.tsx +272 -0
- package/src/__tests__/bar-chart.test.tsx +809 -0
- package/src/__tests__/board.test.tsx +420 -0
- package/src/__tests__/chart-math.test.ts +922 -0
- package/src/__tests__/chart-series.test.ts +339 -0
- package/src/__tests__/code-block.test.tsx +134 -0
- package/src/__tests__/display-popover.test.tsx +195 -0
- package/src/__tests__/display-store.test.tsx +307 -0
- package/src/__tests__/donut-chart.test.tsx +397 -0
- package/src/__tests__/dropdown-menu.test.tsx +156 -2
- package/src/__tests__/filter-menu.test.tsx +175 -0
- package/src/__tests__/gauge-ring.test.tsx +233 -0
- package/src/__tests__/line-chart.test.tsx +612 -0
- package/src/__tests__/ranked-bars.test.tsx +343 -0
- package/src/__tests__/remark-underline.test.ts +194 -0
- package/src/__tests__/sortable.test.tsx +394 -0
- package/src/__tests__/sparkline.test.tsx +368 -0
- package/src/__tests__/stat-layer.test.tsx +271 -0
- package/src/__tests__/stat-strip.test.tsx +175 -0
- package/src/__tests__/status.test.tsx +293 -0
- package/src/__tests__/tabs.test.tsx +303 -0
- package/src/__tests__/token-shape.test.ts +132 -2
- package/src/avatar.tsx +352 -0
- package/src/bar-chart.tsx +1214 -0
- package/src/board.tsx +658 -0
- package/src/chart-frame.tsx +960 -0
- package/src/chart-legend.tsx +304 -0
- package/src/chart-tooltip.tsx +267 -0
- package/src/code-block.tsx +62 -8
- package/src/delta-chip.tsx +263 -0
- package/src/detail/__tests__/activity-pane.test.tsx +369 -0
- package/src/detail/__tests__/detail-chrome.test.tsx +134 -0
- package/src/detail/__tests__/detail-surface.test.tsx +529 -0
- package/src/detail/__tests__/field-row.test.tsx +357 -0
- package/src/detail/activity-pane.tsx +611 -0
- package/src/detail/calendar.tsx +355 -0
- package/src/detail/detail-divider.tsx +261 -0
- package/src/detail/detail-header.tsx +287 -0
- package/src/detail/detail-menu.tsx +254 -0
- package/src/detail/detail-surface.tsx +1110 -0
- package/src/detail/field-list.tsx +196 -0
- package/src/detail/field-row.tsx +1131 -0
- package/src/detail/index.ts +58 -0
- package/src/detail/segmented-choice.tsx +94 -0
- package/src/detail/types.ts +129 -0
- package/src/display-popover.tsx +487 -0
- package/src/display-store.tsx +301 -0
- package/src/donut-chart.tsx +988 -0
- package/src/dropdown-menu.tsx +290 -19
- package/src/filter-core/EXPORTS.md +85 -0
- package/src/filter-core/__tests__/columns.test.ts +159 -0
- package/src/filter-core/__tests__/faceting.test.ts +193 -0
- package/src/filter-core/__tests__/filter-fns.test.ts +519 -0
- package/src/filter-core/__tests__/operators.test.ts +235 -0
- package/src/filter-core/__tests__/state.test.ts +268 -0
- package/src/filter-core/__tests__/url.test.ts +350 -0
- package/src/filter-core/columns.ts +134 -0
- package/src/filter-core/date-utils.ts +38 -0
- package/src/filter-core/examples/task-filter-columns.ts +121 -0
- package/src/filter-core/faceting.ts +120 -0
- package/src/filter-core/filter-fns.ts +335 -0
- package/src/filter-core/index.ts +105 -0
- package/src/filter-core/operators.ts +433 -0
- package/src/filter-core/state.ts +280 -0
- package/src/filter-core/types.ts +247 -0
- package/src/filter-core/url.ts +261 -0
- package/src/filter-dropdown.tsx +12 -0
- package/src/filter-menu.tsx +649 -0
- package/src/floating-drawer.tsx +19 -1
- package/src/gauge-ring.tsx +435 -0
- package/src/hue.ts +52 -0
- package/src/index.ts +303 -0
- package/src/kbd.tsx +27 -4
- package/src/lib/chart.ts +866 -0
- package/src/lib/focus.ts +43 -1
- package/src/lib/layer-stack.ts +30 -3
- package/src/lib/remark-underline.ts +443 -0
- package/src/lib/series.ts +169 -0
- package/src/line-chart.tsx +1176 -0
- package/src/markdown.tsx +26 -7
- package/src/modal.tsx +42 -18
- package/src/progress-ledger.tsx +304 -0
- package/src/ranked-bars.tsx +386 -0
- package/src/segmented-pill.tsx +32 -9
- package/src/sortable.tsx +520 -1
- package/src/sparkline.tsx +416 -0
- package/src/stat-card.tsx +376 -0
- package/src/stat-strip.tsx +327 -0
- package/src/status.tsx +215 -0
- package/src/styles.css +1570 -0
- package/src/tabs.tsx +206 -25
- package/src/task-card.tsx +610 -0
- package/src/thread/__tests__/comment-body-hostile.test.tsx +331 -0
- package/src/thread/__tests__/comment-tree.test.ts +151 -0
- package/src/thread/__tests__/emoji.test.ts +187 -0
- package/src/thread/__tests__/fixtures/thread-fixture.ts +252 -0
- package/src/thread/__tests__/link-preview-source.test.ts +120 -0
- package/src/thread/__tests__/link-preview.test.tsx +600 -0
- package/src/thread/__tests__/markdown-format.test.ts +82 -0
- package/src/thread/__tests__/markdown-spec.test.ts +469 -0
- package/src/thread/__tests__/relative-time.test.ts +71 -0
- package/src/thread/__tests__/rich-composer.test.tsx +799 -0
- package/src/thread/__tests__/scroll-caret.test.ts +58 -0
- package/src/thread/__tests__/suggestion-list.test.tsx +648 -0
- package/src/thread/__tests__/thread-scroll-ownership.test.tsx +88 -0
- package/src/thread/__tests__/thread.test.tsx +742 -0
- package/src/thread/__tests__/use-attachments.test.tsx +679 -0
- package/src/thread/actions.tsx +196 -0
- package/src/thread/attachments.tsx +1071 -0
- package/src/thread/comment-body.tsx +148 -0
- package/src/thread/comment-tree.ts +182 -0
- package/src/thread/comment.tsx +967 -0
- package/src/thread/composer-footer.tsx +125 -0
- package/src/thread/composer.tsx +319 -0
- package/src/thread/emoji.ts +283 -0
- package/src/thread/index.ts +153 -0
- package/src/thread/link-preview.tsx +341 -0
- package/src/thread/markdown-format.ts +155 -0
- package/src/thread/markdown-spec.ts +754 -0
- package/src/thread/rail.tsx +372 -0
- package/src/thread/reactions.tsx +415 -0
- package/src/thread/relative-time.tsx +94 -0
- package/src/thread/rich-composer-impl.tsx +1601 -0
- package/src/thread/rich-composer.tsx +195 -0
- package/src/thread/scroll-caret.ts +37 -0
- package/src/thread/suggestion-list.tsx +182 -0
- package/src/thread/thread.tsx +718 -0
- package/src/thread/types.ts +232 -0
- package/src/thread/use-attachments.ts +598 -0
- package/src/thread/use-now.ts +73 -0
- package/src/thread/use-thread.ts +316 -0
- package/src/tokens.css +112 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createDisplayStore — per-scope display settings, by context.
|
|
3
|
+
*
|
|
4
|
+
* Two contracts, both of them inversions of a source defect
|
|
5
|
+
* (`docs/design-briefs/tasks-board-header-primitives.md` §4):
|
|
6
|
+
*
|
|
7
|
+
* 1. TWO PROVIDERS ARE TWO PANELS. Their cards subscribe to a module-level
|
|
8
|
+
* singleton, so two boards on one page cannot hold different settings.
|
|
9
|
+
* The test below renders two and changes one.
|
|
10
|
+
* 2. PERSISTENCE IS PER SCOPE and VALIDATED. A key from another scope never
|
|
11
|
+
* leaks; a hand-edited value that is the wrong type or outside the
|
|
12
|
+
* allow-list falls back to the default instead of reaching a component.
|
|
13
|
+
*
|
|
14
|
+
* And one contract that is not an inversion but a PIN. `prefix` moves the key
|
|
15
|
+
* for a host that is not this workspace, and the default has to stay
|
|
16
|
+
* byte-identical: these keys hold operator preferences already on disk, so a
|
|
17
|
+
* changed default would not migrate them, it would lose them. The default is
|
|
18
|
+
* asserted as a literal, and asserted again through a value written by hand at
|
|
19
|
+
* the key an older build wrote.
|
|
20
|
+
*/
|
|
21
|
+
import { describe, expect, it, beforeEach } from 'vitest'
|
|
22
|
+
import { render, screen } from '@testing-library/react'
|
|
23
|
+
import userEvent from '@testing-library/user-event'
|
|
24
|
+
import { createDisplayStore, type DisplayStore } from '../display-store'
|
|
25
|
+
|
|
26
|
+
type Settings = {
|
|
27
|
+
readonly grouping: 'column' | 'assignee'
|
|
28
|
+
readonly showEmpty: boolean
|
|
29
|
+
/** A MEASUREMENT — a size the operator drags rather than picks. */
|
|
30
|
+
readonly panelSize: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const DEFAULTS: Settings = { grouping: 'column', showEmpty: true, panelSize: 560 }
|
|
34
|
+
|
|
35
|
+
const store = createDisplayStore<Settings>(
|
|
36
|
+
'test',
|
|
37
|
+
DEFAULTS,
|
|
38
|
+
{ grouping: ['column', 'assignee'] },
|
|
39
|
+
{
|
|
40
|
+
// An allow-list cannot express a RANGE, so a numeric setting sanitises on
|
|
41
|
+
// the migration seam and anything that is not a plausible size falls back
|
|
42
|
+
// to the default exactly as a bad enum would.
|
|
43
|
+
panelSize: (raw) =>
|
|
44
|
+
typeof raw === 'number' && Number.isFinite(raw) && raw >= 1 && raw <= 8000
|
|
45
|
+
? Math.round(raw)
|
|
46
|
+
: undefined,
|
|
47
|
+
},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The same store under a different PREFIX, and identical in every other way —
|
|
52
|
+
* same name, same defaults, same allow-list. The pair is what proves the
|
|
53
|
+
* option moves the key and touches nothing else: if the prefix were dropped
|
|
54
|
+
* these two would be one store sharing one key.
|
|
55
|
+
*/
|
|
56
|
+
const prefixedStore = createDisplayStore<Settings>(
|
|
57
|
+
'test',
|
|
58
|
+
DEFAULTS,
|
|
59
|
+
{ grouping: ['column', 'assignee'] },
|
|
60
|
+
undefined,
|
|
61
|
+
{ prefix: 'lightwork' },
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* A panel per store. `useDisplay` reaches the nearest provider, so a second
|
|
66
|
+
* store needs a component that calls the second store's hook — the panel is
|
|
67
|
+
* built from the store rather than closing over one.
|
|
68
|
+
*/
|
|
69
|
+
function panelFor(target: DisplayStore<Settings>) {
|
|
70
|
+
return function Panel({ name }: { name: string }) {
|
|
71
|
+
const { settings, set, reset, isDefault } = target.useDisplay()
|
|
72
|
+
return (
|
|
73
|
+
<div>
|
|
74
|
+
<span data-testid={`${name}-grouping`}>{settings.grouping}</span>
|
|
75
|
+
<span data-testid={`${name}-empty`}>{String(settings.showEmpty)}</span>
|
|
76
|
+
<span data-testid={`${name}-default`}>{String(isDefault)}</span>
|
|
77
|
+
<button type="button" onClick={() => set('grouping', 'assignee')}>
|
|
78
|
+
{`${name}: group by assignee`}
|
|
79
|
+
</button>
|
|
80
|
+
<button type="button" onClick={() => set('showEmpty', false)}>
|
|
81
|
+
{`${name}: hide empty`}
|
|
82
|
+
</button>
|
|
83
|
+
<span data-testid={`${name}-size`}>{String(settings.panelSize)}</span>
|
|
84
|
+
<button type="button" onClick={() => set('panelSize', 820)}>
|
|
85
|
+
{`${name}: widen`}
|
|
86
|
+
</button>
|
|
87
|
+
<button type="button" onClick={reset}>{`${name}: reset`}</button>
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const Panel = panelFor(store)
|
|
94
|
+
const PrefixedPanel = panelFor(prefixedStore)
|
|
95
|
+
|
|
96
|
+
describe('createDisplayStore', () => {
|
|
97
|
+
beforeEach(() => window.localStorage.clear())
|
|
98
|
+
|
|
99
|
+
it('namespaces its key by name and scope', () => {
|
|
100
|
+
expect(store.storageKey('brn_1')).toBe('workspace:test:brn_1:display')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('refuses an empty prefix rather than silently sharing the default namespace', () => {
|
|
104
|
+
// Both quiet alternatives are worse than a throw: defaulting hands a caller
|
|
105
|
+
// who asked for isolation the shared namespace, and accepting produces
|
|
106
|
+
// `:name:scope:display`, which collides with every other empty-prefix
|
|
107
|
+
// caller — the cross-product the option exists to prevent.
|
|
108
|
+
expect(() => createDisplayStore('board', { a: 1 }, undefined, undefined, { prefix: '' })).toThrow(
|
|
109
|
+
/prefix.*cannot be empty/i,
|
|
110
|
+
)
|
|
111
|
+
// And the default path is untouched by the guard.
|
|
112
|
+
expect(createDisplayStore('board', { a: 1 }).storageKey('ws_1')).toBe('workspace:board:ws_1:display')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('reads a key written before the prefix option existed', () => {
|
|
116
|
+
// The key is spelled out rather than taken from `storageKey`, because what
|
|
117
|
+
// is under test is that the two still agree. A store built without the
|
|
118
|
+
// option has to find exactly what the build before it left behind.
|
|
119
|
+
window.localStorage.setItem(
|
|
120
|
+
'workspace:test:brn_old:display',
|
|
121
|
+
JSON.stringify({ grouping: 'assignee', showEmpty: false, panelSize: 700 }),
|
|
122
|
+
)
|
|
123
|
+
render(
|
|
124
|
+
<store.Provider scope="brn_old">
|
|
125
|
+
<Panel name="old" />
|
|
126
|
+
</store.Provider>,
|
|
127
|
+
)
|
|
128
|
+
expect(screen.getByTestId('old-grouping')).toHaveTextContent('assignee')
|
|
129
|
+
expect(screen.getByTestId('old-empty')).toHaveTextContent('false')
|
|
130
|
+
expect(screen.getByTestId('old-size')).toHaveTextContent('700')
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('takes a prefix, and the prefix is the only segment it changes', () => {
|
|
134
|
+
expect(prefixedStore.storageKey('brn_1')).toBe('lightwork:test:brn_1:display')
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('a prefixed store writes its own key and never the unprefixed one', async () => {
|
|
138
|
+
const user = userEvent.setup()
|
|
139
|
+
render(
|
|
140
|
+
<prefixedStore.Provider scope="brn_p">
|
|
141
|
+
<PrefixedPanel name="p" />
|
|
142
|
+
</prefixedStore.Provider>,
|
|
143
|
+
)
|
|
144
|
+
await user.click(screen.getByRole('button', { name: 'p: group by assignee' }))
|
|
145
|
+
expect(window.localStorage.getItem('lightwork:test:brn_p:display')).toContain(
|
|
146
|
+
'assignee',
|
|
147
|
+
)
|
|
148
|
+
// The point of the option: another product on the same origin, using the
|
|
149
|
+
// same primitive under the same name, is not writing over this workspace.
|
|
150
|
+
expect(window.localStorage.getItem('workspace:test:brn_p:display')).toBeNull()
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('two prefixes over one name and one scope do not see each other', async () => {
|
|
154
|
+
const user = userEvent.setup()
|
|
155
|
+
const { unmount } = render(
|
|
156
|
+
<store.Provider scope="brn_shared">
|
|
157
|
+
<Panel name="host" />
|
|
158
|
+
</store.Provider>,
|
|
159
|
+
)
|
|
160
|
+
await user.click(screen.getByRole('button', { name: 'host: group by assignee' }))
|
|
161
|
+
unmount()
|
|
162
|
+
|
|
163
|
+
render(
|
|
164
|
+
<prefixedStore.Provider scope="brn_shared">
|
|
165
|
+
<PrefixedPanel name="guest" />
|
|
166
|
+
</prefixedStore.Provider>,
|
|
167
|
+
)
|
|
168
|
+
expect(screen.getByTestId('guest-grouping')).toHaveTextContent('column')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('persists a change and reads it back on the next mount', async () => {
|
|
172
|
+
const user = userEvent.setup()
|
|
173
|
+
const { unmount } = render(
|
|
174
|
+
<store.Provider scope="brn_1">
|
|
175
|
+
<Panel name="a" />
|
|
176
|
+
</store.Provider>,
|
|
177
|
+
)
|
|
178
|
+
await user.click(screen.getByRole('button', { name: 'a: group by assignee' }))
|
|
179
|
+
expect(screen.getByTestId('a-grouping')).toHaveTextContent('assignee')
|
|
180
|
+
unmount()
|
|
181
|
+
|
|
182
|
+
render(
|
|
183
|
+
<store.Provider scope="brn_1">
|
|
184
|
+
<Panel name="b" />
|
|
185
|
+
</store.Provider>,
|
|
186
|
+
)
|
|
187
|
+
expect(screen.getByTestId('b-grouping')).toHaveTextContent('assignee')
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('partitions by scope — one brand never sees another brand settings', async () => {
|
|
191
|
+
const user = userEvent.setup()
|
|
192
|
+
const { unmount } = render(
|
|
193
|
+
<store.Provider scope="brn_1">
|
|
194
|
+
<Panel name="a" />
|
|
195
|
+
</store.Provider>,
|
|
196
|
+
)
|
|
197
|
+
await user.click(screen.getByRole('button', { name: 'a: group by assignee' }))
|
|
198
|
+
unmount()
|
|
199
|
+
|
|
200
|
+
render(
|
|
201
|
+
<store.Provider scope="brn_2">
|
|
202
|
+
<Panel name="b" />
|
|
203
|
+
</store.Provider>,
|
|
204
|
+
)
|
|
205
|
+
expect(screen.getByTestId('b-grouping')).toHaveTextContent('column')
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('two providers hold independent settings', async () => {
|
|
209
|
+
const user = userEvent.setup()
|
|
210
|
+
render(
|
|
211
|
+
<>
|
|
212
|
+
<store.Provider>
|
|
213
|
+
<Panel name="left" />
|
|
214
|
+
</store.Provider>
|
|
215
|
+
<store.Provider>
|
|
216
|
+
<Panel name="right" />
|
|
217
|
+
</store.Provider>
|
|
218
|
+
</>,
|
|
219
|
+
)
|
|
220
|
+
await user.click(screen.getByRole('button', { name: 'left: group by assignee' }))
|
|
221
|
+
expect(screen.getByTestId('left-grouping')).toHaveTextContent('assignee')
|
|
222
|
+
// The singleton trap: with a module-level store this would read "assignee".
|
|
223
|
+
expect(screen.getByTestId('right-grouping')).toHaveTextContent('column')
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('drops a persisted value that is the wrong type or off the allow-list', () => {
|
|
227
|
+
window.localStorage.setItem(
|
|
228
|
+
store.storageKey('brn_3'),
|
|
229
|
+
JSON.stringify({ grouping: 'sideways', showEmpty: 'yes' }),
|
|
230
|
+
)
|
|
231
|
+
render(
|
|
232
|
+
<store.Provider scope="brn_3">
|
|
233
|
+
<Panel name="c" />
|
|
234
|
+
</store.Provider>,
|
|
235
|
+
)
|
|
236
|
+
expect(screen.getByTestId('c-grouping')).toHaveTextContent('column')
|
|
237
|
+
expect(screen.getByTestId('c-empty')).toHaveTextContent('true')
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('persists a numeric setting and reads it back', async () => {
|
|
241
|
+
const user = userEvent.setup()
|
|
242
|
+
const { unmount } = render(
|
|
243
|
+
<store.Provider scope="brn_n">
|
|
244
|
+
<Panel name="n" />
|
|
245
|
+
</store.Provider>,
|
|
246
|
+
)
|
|
247
|
+
await user.click(screen.getByRole('button', { name: 'n: widen' }))
|
|
248
|
+
expect(screen.getByTestId('n-size')).toHaveTextContent('820')
|
|
249
|
+
unmount()
|
|
250
|
+
|
|
251
|
+
render(
|
|
252
|
+
<store.Provider scope="brn_n">
|
|
253
|
+
<Panel name="n2" />
|
|
254
|
+
</store.Provider>,
|
|
255
|
+
)
|
|
256
|
+
expect(screen.getByTestId('n2-size')).toHaveTextContent('820')
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('drops a stored size that is not a size', () => {
|
|
260
|
+
// `NaN` is `typeof 'number'` and survives a hand edit; a pane laid out at
|
|
261
|
+
// `NaN` px has no width at all, so it is rejected like any other value
|
|
262
|
+
// that does not hold up.
|
|
263
|
+
for (const [scope, stored] of [
|
|
264
|
+
['brn_n1', Number.NaN],
|
|
265
|
+
['brn_n2', -40],
|
|
266
|
+
['brn_n3', 99999],
|
|
267
|
+
['brn_n4', '560'],
|
|
268
|
+
] as const) {
|
|
269
|
+
window.localStorage.setItem(
|
|
270
|
+
store.storageKey(scope),
|
|
271
|
+
JSON.stringify({ panelSize: stored }),
|
|
272
|
+
)
|
|
273
|
+
const view = render(
|
|
274
|
+
<store.Provider scope={scope}>
|
|
275
|
+
<Panel name={scope} />
|
|
276
|
+
</store.Provider>,
|
|
277
|
+
)
|
|
278
|
+
expect(screen.getByTestId(`${scope}-size`)).toHaveTextContent('560')
|
|
279
|
+
view.unmount()
|
|
280
|
+
}
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
it('survives a payload that is not an object at all', () => {
|
|
284
|
+
window.localStorage.setItem(store.storageKey('brn_4'), 'not json {{{')
|
|
285
|
+
render(
|
|
286
|
+
<store.Provider scope="brn_4">
|
|
287
|
+
<Panel name="d" />
|
|
288
|
+
</store.Provider>,
|
|
289
|
+
)
|
|
290
|
+
expect(screen.getByTestId('d-grouping')).toHaveTextContent('column')
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('reports isDefault, and reset returns to it', async () => {
|
|
294
|
+
const user = userEvent.setup()
|
|
295
|
+
render(
|
|
296
|
+
<store.Provider scope="brn_5">
|
|
297
|
+
<Panel name="e" />
|
|
298
|
+
</store.Provider>,
|
|
299
|
+
)
|
|
300
|
+
expect(screen.getByTestId('e-default')).toHaveTextContent('true')
|
|
301
|
+
await user.click(screen.getByRole('button', { name: 'e: hide empty' }))
|
|
302
|
+
expect(screen.getByTestId('e-default')).toHaveTextContent('false')
|
|
303
|
+
await user.click(screen.getByRole('button', { name: 'e: reset' }))
|
|
304
|
+
expect(screen.getByTestId('e-empty')).toHaveTextContent('true')
|
|
305
|
+
expect(screen.getByTestId('e-default')).toHaveTextContent('true')
|
|
306
|
+
})
|
|
307
|
+
})
|