@eeacms/volto-eea-website-policy 1.15.0 → 2.1.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/CHANGELOG.md +44 -0
- package/package.json +1 -1
- package/src/customizations/volto/components/manage/Display/Display.jsx +0 -306
- package/src/customizations/volto/components/manage/Display/Readme.md +0 -1
- package/src/customizations/volto/components/manage/Toolbar/More.jsx +0 -541
- package/src/customizations/volto/components/manage/Workflow/README.txt +0 -1
- package/src/customizations/volto/components/manage/Workflow/Workflow.jsx +0 -421
- package/src/customizations/volto/components/manage/Workflow/Workflow.test.jsx +0 -81
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Workflow component.
|
|
3
|
-
* @module components/manage/Workflow/Workflow
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { FormFieldWrapper, Icon, Toast } from '@plone/volto/components';
|
|
7
|
-
import {
|
|
8
|
-
flattenToAppURL,
|
|
9
|
-
getCurrentStateMapping,
|
|
10
|
-
getWorkflowOptions,
|
|
11
|
-
} from '@plone/volto/helpers';
|
|
12
|
-
import { uniqBy } from 'lodash';
|
|
13
|
-
import PropTypes from 'prop-types';
|
|
14
|
-
import { Component, Fragment } from 'react';
|
|
15
|
-
import { defineMessages, injectIntl } from 'react-intl';
|
|
16
|
-
import { connect } from 'react-redux';
|
|
17
|
-
import { withRouter } from 'react-router-dom';
|
|
18
|
-
import { toast } from 'react-toastify';
|
|
19
|
-
import { compose } from 'redux';
|
|
20
|
-
|
|
21
|
-
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
22
|
-
|
|
23
|
-
import {
|
|
24
|
-
getContent,
|
|
25
|
-
getWorkflow,
|
|
26
|
-
transitionWorkflow,
|
|
27
|
-
} from '@plone/volto/actions';
|
|
28
|
-
|
|
29
|
-
import checkSVG from '@plone/volto/icons/check.svg';
|
|
30
|
-
import downSVG from '@plone/volto/icons/down-key.svg';
|
|
31
|
-
import upSVG from '@plone/volto/icons/up-key.svg';
|
|
32
|
-
|
|
33
|
-
const messages = defineMessages({
|
|
34
|
-
messageUpdated: {
|
|
35
|
-
id: 'Workflow updated.',
|
|
36
|
-
defaultMessage: 'Workflow updated.',
|
|
37
|
-
},
|
|
38
|
-
notAllowedToUpdateWorkflow: {
|
|
39
|
-
id: 'notAllowedToUpdateWorkflow',
|
|
40
|
-
defaultMessage: 'Please fill out all the required fields',
|
|
41
|
-
},
|
|
42
|
-
messageNoWorkflow: {
|
|
43
|
-
id: 'No workflow',
|
|
44
|
-
defaultMessage: 'No workflow',
|
|
45
|
-
},
|
|
46
|
-
state: {
|
|
47
|
-
id: 'State',
|
|
48
|
-
defaultMessage: 'State',
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const filter_remaining_steps = (values, key) => {
|
|
53
|
-
return values.filter((value) => {
|
|
54
|
-
const is_not_ready = !value.is_ready;
|
|
55
|
-
if (!is_not_ready) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
const states = value.states;
|
|
59
|
-
const required_for_all = states?.indexOf('all') !== -1;
|
|
60
|
-
return (
|
|
61
|
-
(is_not_ready && required_for_all) ||
|
|
62
|
-
(is_not_ready && states?.indexOf(key) !== -1)
|
|
63
|
-
);
|
|
64
|
-
});
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const SingleValue = injectLazyLibs('reactSelect')(({ children, ...props }) => {
|
|
68
|
-
const stateDecorator = {
|
|
69
|
-
marginRight: '10px',
|
|
70
|
-
display: 'inline-block',
|
|
71
|
-
backgroundColor: props.selectProps.value.color || null,
|
|
72
|
-
content: ' ',
|
|
73
|
-
height: '10px',
|
|
74
|
-
width: '10px',
|
|
75
|
-
borderRadius: '50%',
|
|
76
|
-
};
|
|
77
|
-
const { SingleValue } = props.reactSelect.components;
|
|
78
|
-
return (
|
|
79
|
-
<SingleValue {...props}>
|
|
80
|
-
<span style={stateDecorator} />
|
|
81
|
-
{children}
|
|
82
|
-
</SingleValue>
|
|
83
|
-
);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const Option = injectLazyLibs('reactSelect')((props) => {
|
|
87
|
-
const stateDecorator = {
|
|
88
|
-
marginRight: '10px',
|
|
89
|
-
display: 'inline-block',
|
|
90
|
-
backgroundColor:
|
|
91
|
-
props.selectProps.value.value === props.data.value
|
|
92
|
-
? props.selectProps.value.color
|
|
93
|
-
: null,
|
|
94
|
-
content: ' ',
|
|
95
|
-
height: '10px',
|
|
96
|
-
width: '10px',
|
|
97
|
-
borderRadius: '50%',
|
|
98
|
-
border:
|
|
99
|
-
props.selectProps.value.value !== props.data.value
|
|
100
|
-
? `1px solid ${props.data.color}`
|
|
101
|
-
: null,
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const { Option } = props['reactSelect'].components;
|
|
105
|
-
return (
|
|
106
|
-
<Option {...props}>
|
|
107
|
-
<span style={stateDecorator} />
|
|
108
|
-
<div style={{ marginRight: 'auto' }}>{props.label}</div>
|
|
109
|
-
{props.isFocused && !props.isSelected && (
|
|
110
|
-
<Icon name={checkSVG} size="18px" color="#b8c6c8" />
|
|
111
|
-
)}
|
|
112
|
-
{props.isSelected && <Icon name={checkSVG} size="18px" color="#007bc1" />}
|
|
113
|
-
</Option>
|
|
114
|
-
);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const DropdownIndicator = injectLazyLibs('reactSelect')((props) => {
|
|
118
|
-
const { DropdownIndicator } = props.reactSelect.components;
|
|
119
|
-
return (
|
|
120
|
-
<DropdownIndicator {...props} data-testid="workflow-select-dropdown">
|
|
121
|
-
{props.selectProps.menuIsOpen ? (
|
|
122
|
-
<Icon name={upSVG} size="24px" color="#007bc1" />
|
|
123
|
-
) : (
|
|
124
|
-
<Icon name={downSVG} size="24px" color="#007bc1" />
|
|
125
|
-
)}
|
|
126
|
-
</DropdownIndicator>
|
|
127
|
-
);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
const selectTheme = (theme) => ({
|
|
131
|
-
...theme,
|
|
132
|
-
borderRadius: 0,
|
|
133
|
-
colors: {
|
|
134
|
-
...theme.colors,
|
|
135
|
-
primary25: 'hotpink',
|
|
136
|
-
primary: '#b8c6c8',
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
const customSelectStyles = {
|
|
141
|
-
control: (styles, state) => ({
|
|
142
|
-
...styles,
|
|
143
|
-
border: 'none',
|
|
144
|
-
borderBottom: '2px solid #b8c6c8',
|
|
145
|
-
boxShadow: 'none',
|
|
146
|
-
borderBottomStyle: state.menuIsOpen ? 'dotted' : 'solid',
|
|
147
|
-
}),
|
|
148
|
-
menu: (styles, state) => ({
|
|
149
|
-
...styles,
|
|
150
|
-
top: null,
|
|
151
|
-
marginTop: 0,
|
|
152
|
-
boxShadow: 'none',
|
|
153
|
-
borderBottom: '2px solid #b8c6c8',
|
|
154
|
-
}),
|
|
155
|
-
indicatorSeparator: (styles) => ({
|
|
156
|
-
...styles,
|
|
157
|
-
width: null,
|
|
158
|
-
}),
|
|
159
|
-
valueContainer: (styles) => ({
|
|
160
|
-
...styles,
|
|
161
|
-
padding: 0,
|
|
162
|
-
}),
|
|
163
|
-
option: (styles, state) => ({
|
|
164
|
-
...styles,
|
|
165
|
-
backgroundColor: null,
|
|
166
|
-
minHeight: '50px',
|
|
167
|
-
display: 'flex',
|
|
168
|
-
justifyContent: 'space-between',
|
|
169
|
-
alignItems: 'center',
|
|
170
|
-
padding: '12px 12px',
|
|
171
|
-
color: state.isSelected
|
|
172
|
-
? '#007bc1'
|
|
173
|
-
: state.isFocused
|
|
174
|
-
? '#4a4a4a'
|
|
175
|
-
: 'inherit',
|
|
176
|
-
':active': {
|
|
177
|
-
backgroundColor: null,
|
|
178
|
-
},
|
|
179
|
-
span: {
|
|
180
|
-
flex: '0 0 auto',
|
|
181
|
-
},
|
|
182
|
-
svg: {
|
|
183
|
-
flex: '0 0 auto',
|
|
184
|
-
},
|
|
185
|
-
}),
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Workflow container class.
|
|
190
|
-
* @class Workflow
|
|
191
|
-
* @extends Component
|
|
192
|
-
*/
|
|
193
|
-
class Workflow extends Component {
|
|
194
|
-
/**
|
|
195
|
-
* Property types.
|
|
196
|
-
* @property {Object} propTypes Property types.
|
|
197
|
-
* @static
|
|
198
|
-
*/
|
|
199
|
-
static propTypes = {
|
|
200
|
-
getContent: PropTypes.func.isRequired,
|
|
201
|
-
getWorkflow: PropTypes.func.isRequired,
|
|
202
|
-
transitionWorkflow: PropTypes.func.isRequired,
|
|
203
|
-
workflowLoaded: PropTypes.bool,
|
|
204
|
-
loaded: PropTypes.bool.isRequired,
|
|
205
|
-
pathname: PropTypes.string.isRequired,
|
|
206
|
-
|
|
207
|
-
contentHistory: PropTypes.arrayOf(
|
|
208
|
-
PropTypes.shape({
|
|
209
|
-
review_state: PropTypes.string,
|
|
210
|
-
}),
|
|
211
|
-
),
|
|
212
|
-
transitions: PropTypes.arrayOf(
|
|
213
|
-
PropTypes.shape({
|
|
214
|
-
'@id': PropTypes.string,
|
|
215
|
-
title: PropTypes.string,
|
|
216
|
-
}),
|
|
217
|
-
),
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Default properties
|
|
222
|
-
* @property {Object} defaultProps Default properties.
|
|
223
|
-
* @static
|
|
224
|
-
*/
|
|
225
|
-
static defaultProps = {
|
|
226
|
-
history: [],
|
|
227
|
-
transitions: [],
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
state = {
|
|
231
|
-
selectedOption: this.props.currentStateValue,
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
componentDidMount() {
|
|
235
|
-
this.props.getWorkflow(this.props.pathname);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Component will receive props
|
|
240
|
-
* @method componentWillReceiveProps
|
|
241
|
-
* @param {Object} nextProps Next properties
|
|
242
|
-
* @returns {undefined}
|
|
243
|
-
*/
|
|
244
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
245
|
-
if (nextProps.pathname !== this.props.pathname) {
|
|
246
|
-
this.props.getWorkflow(nextProps.pathname);
|
|
247
|
-
}
|
|
248
|
-
if (!this.props.loaded && nextProps.loaded) {
|
|
249
|
-
this.props.getWorkflow(nextProps.pathname);
|
|
250
|
-
this.props.getContent(nextProps.pathname);
|
|
251
|
-
}
|
|
252
|
-
if (!this.props.workflowLoaded && nextProps.workflowLoaded) {
|
|
253
|
-
this.props.getContent(nextProps.pathname);
|
|
254
|
-
// #153145 - Redirect to the newly created version
|
|
255
|
-
if (this.state?.selectedOption?.value === 'createNewVersion') {
|
|
256
|
-
this.props.history.push(`${nextProps.pathname}.1`);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* On transition handler
|
|
263
|
-
* @method transition
|
|
264
|
-
* @param {string} event Event object
|
|
265
|
-
* @returns {undefined}
|
|
266
|
-
*/
|
|
267
|
-
transition = (selectedOption) => {
|
|
268
|
-
if (
|
|
269
|
-
filter_remaining_steps(
|
|
270
|
-
this.props.editingProgressSteps,
|
|
271
|
-
this.props?.content?.review_state || '',
|
|
272
|
-
).length === 0
|
|
273
|
-
) {
|
|
274
|
-
this.props.transitionWorkflow(flattenToAppURL(selectedOption.url));
|
|
275
|
-
this.setState({ selectedOption });
|
|
276
|
-
toast.success(
|
|
277
|
-
<Toast
|
|
278
|
-
success
|
|
279
|
-
title={this.props.intl.formatMessage(messages.messageUpdated)}
|
|
280
|
-
content=""
|
|
281
|
-
/>,
|
|
282
|
-
);
|
|
283
|
-
} else {
|
|
284
|
-
toast.error(
|
|
285
|
-
<Toast
|
|
286
|
-
error
|
|
287
|
-
title={this.props.intl.formatMessage(
|
|
288
|
-
messages.notAllowedToUpdateWorkflow,
|
|
289
|
-
)}
|
|
290
|
-
content=""
|
|
291
|
-
/>,
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
selectValue = (option) => {
|
|
297
|
-
const stateDecorator = {
|
|
298
|
-
marginLeft: '10px',
|
|
299
|
-
marginRight: '10px',
|
|
300
|
-
display: 'inline-block',
|
|
301
|
-
backgroundColor: option.color || null,
|
|
302
|
-
content: ' ',
|
|
303
|
-
height: '10px',
|
|
304
|
-
width: '10px',
|
|
305
|
-
borderRadius: '50%',
|
|
306
|
-
};
|
|
307
|
-
return (
|
|
308
|
-
<Fragment>
|
|
309
|
-
<span style={stateDecorator} />
|
|
310
|
-
<span className="Select-value-label">{option.label}</span>
|
|
311
|
-
</Fragment>
|
|
312
|
-
);
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
optionRenderer = (option) => {
|
|
316
|
-
const stateDecorator = {
|
|
317
|
-
marginLeft: '10px',
|
|
318
|
-
marginRight: '10px',
|
|
319
|
-
display: 'inline-block',
|
|
320
|
-
backgroundColor:
|
|
321
|
-
this.props.currentStateValue.value === option.value
|
|
322
|
-
? option.color
|
|
323
|
-
: null,
|
|
324
|
-
content: ' ',
|
|
325
|
-
height: '10px',
|
|
326
|
-
width: '10px',
|
|
327
|
-
borderRadius: '50%',
|
|
328
|
-
border:
|
|
329
|
-
this.props.currentStateValue.value !== option.value
|
|
330
|
-
? `1px solid ${option.color}`
|
|
331
|
-
: null,
|
|
332
|
-
};
|
|
333
|
-
|
|
334
|
-
return (
|
|
335
|
-
<Fragment>
|
|
336
|
-
<span style={stateDecorator} />
|
|
337
|
-
<span style={{ marginRight: 'auto' }}>{option.label}</span>
|
|
338
|
-
<Icon name={checkSVG} size="24px" />
|
|
339
|
-
</Fragment>
|
|
340
|
-
);
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
render() {
|
|
344
|
-
const { Placeholder } = this.props.reactSelect.components;
|
|
345
|
-
const Select = this.props.reactSelect.default;
|
|
346
|
-
// Remove markForDeletion transition if item is published
|
|
347
|
-
// in order not to un-publish items by mistake. This transition
|
|
348
|
-
// can still be executed from /contents - refs #256563, #153145
|
|
349
|
-
const transitions = this.props.transitions.filter((transition) => {
|
|
350
|
-
if (
|
|
351
|
-
transition?.['@id']?.endsWith('markForDeletion') &&
|
|
352
|
-
this.props?.content?.review_state === 'published'
|
|
353
|
-
) {
|
|
354
|
-
return false;
|
|
355
|
-
}
|
|
356
|
-
return true;
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
return (
|
|
360
|
-
<FormFieldWrapper
|
|
361
|
-
id="state-select"
|
|
362
|
-
title={this.props.intl.formatMessage(messages.state)}
|
|
363
|
-
{...this.props}
|
|
364
|
-
>
|
|
365
|
-
<Select
|
|
366
|
-
name="state-select"
|
|
367
|
-
className="react-select-container"
|
|
368
|
-
classNamePrefix="react-select"
|
|
369
|
-
isDisabled={
|
|
370
|
-
!this.props.content.review_state || transitions.length === 0
|
|
371
|
-
}
|
|
372
|
-
options={uniqBy(
|
|
373
|
-
transitions.map((transition) => getWorkflowOptions(transition)),
|
|
374
|
-
'label',
|
|
375
|
-
).concat(this.props.currentStateValue)}
|
|
376
|
-
styles={customSelectStyles}
|
|
377
|
-
theme={selectTheme}
|
|
378
|
-
components={{
|
|
379
|
-
DropdownIndicator,
|
|
380
|
-
Placeholder,
|
|
381
|
-
Option,
|
|
382
|
-
SingleValue,
|
|
383
|
-
}}
|
|
384
|
-
onChange={this.transition}
|
|
385
|
-
value={
|
|
386
|
-
this.props.content.review_state
|
|
387
|
-
? this.props.currentStateValue
|
|
388
|
-
: {
|
|
389
|
-
label: this.props.intl.formatMessage(
|
|
390
|
-
messages.messageNoWorkflow,
|
|
391
|
-
),
|
|
392
|
-
value: 'noworkflow',
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
isSearchable={false}
|
|
396
|
-
/>
|
|
397
|
-
</FormFieldWrapper>
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
export default compose(
|
|
403
|
-
injectIntl,
|
|
404
|
-
injectLazyLibs(['reactSelect']),
|
|
405
|
-
withRouter,
|
|
406
|
-
connect(
|
|
407
|
-
(state, props) => ({
|
|
408
|
-
loaded: state.workflow.transition.loaded,
|
|
409
|
-
content: state.content.data,
|
|
410
|
-
workflowLoaded: state.workflow.get?.loaded,
|
|
411
|
-
contentHistory: state.workflow.history,
|
|
412
|
-
transitions: state.workflow.transitions,
|
|
413
|
-
currentStateValue: getCurrentStateMapping(state.workflow.currentState),
|
|
414
|
-
editingProgressSteps:
|
|
415
|
-
state?.editingProgress?.editing?.loaded === true
|
|
416
|
-
? state?.editingProgress?.result?.steps
|
|
417
|
-
: [],
|
|
418
|
-
}),
|
|
419
|
-
{ getContent, getWorkflow, transitionWorkflow },
|
|
420
|
-
),
|
|
421
|
-
)(Workflow);
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import configureStore from 'redux-mock-store';
|
|
3
|
-
import { Provider } from 'react-intl-redux';
|
|
4
|
-
import { waitFor, render, screen } from '@testing-library/react';
|
|
5
|
-
import { MemoryRouter } from 'react-router-dom';
|
|
6
|
-
import config from '@plone/volto/registry';
|
|
7
|
-
|
|
8
|
-
import Workflow from './Workflow';
|
|
9
|
-
|
|
10
|
-
const mockStore = configureStore();
|
|
11
|
-
|
|
12
|
-
jest.mock('@plone/volto/helpers/Loadable/Loadable');
|
|
13
|
-
beforeAll(
|
|
14
|
-
async () =>
|
|
15
|
-
await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
config.settings.workflowMapping = {
|
|
20
|
-
published: { value: 'published', color: '#007bc1' },
|
|
21
|
-
publish: { value: 'publish', color: '#007bc1' },
|
|
22
|
-
private: { value: 'private', color: '#ed4033' },
|
|
23
|
-
pending: { value: 'pending', color: '#f6a808' },
|
|
24
|
-
send_back: { value: 'private', color: '#ed4033' },
|
|
25
|
-
retract: { value: 'private', color: '#ed4033' },
|
|
26
|
-
submit: { value: 'review', color: '#f4e037' },
|
|
27
|
-
};
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe('Workflow', () => {
|
|
31
|
-
it('renders an empty workflow component', async () => {
|
|
32
|
-
const store = mockStore({
|
|
33
|
-
workflow: {
|
|
34
|
-
currentState: { id: 'published', title: 'Published' },
|
|
35
|
-
history: [],
|
|
36
|
-
transition: { loaded: true },
|
|
37
|
-
transitions: [],
|
|
38
|
-
},
|
|
39
|
-
intl: {
|
|
40
|
-
locale: 'en',
|
|
41
|
-
messages: {},
|
|
42
|
-
},
|
|
43
|
-
content: { data: { review_state: 'published' } },
|
|
44
|
-
});
|
|
45
|
-
const { container } = render(
|
|
46
|
-
<Provider store={store}>
|
|
47
|
-
<MemoryRouter>
|
|
48
|
-
<Workflow pathname="/test" />
|
|
49
|
-
</MemoryRouter>
|
|
50
|
-
</Provider>,
|
|
51
|
-
);
|
|
52
|
-
await waitFor(() => screen.getByText(/Published/));
|
|
53
|
-
expect(container).toMatchSnapshot();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('renders a workflow component', async () => {
|
|
57
|
-
const store = mockStore({
|
|
58
|
-
workflow: {
|
|
59
|
-
currentState: { id: 'private', title: 'Private' },
|
|
60
|
-
history: [{ review_state: 'private' }],
|
|
61
|
-
transition: { loaded: true },
|
|
62
|
-
transitions: [{ '@id': 'http://publish', title: 'Publish' }],
|
|
63
|
-
},
|
|
64
|
-
intl: {
|
|
65
|
-
locale: 'en',
|
|
66
|
-
messages: {},
|
|
67
|
-
},
|
|
68
|
-
content: { data: { review_state: 'private' } },
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const { container } = render(
|
|
72
|
-
<Provider store={store}>
|
|
73
|
-
<MemoryRouter>
|
|
74
|
-
<Workflow pathname="/test" />
|
|
75
|
-
</MemoryRouter>
|
|
76
|
-
</Provider>,
|
|
77
|
-
);
|
|
78
|
-
await waitFor(() => screen.getByText('Private'));
|
|
79
|
-
expect(container).toMatchSnapshot();
|
|
80
|
-
});
|
|
81
|
-
});
|