@contentful/field-editor-slug 1.2.0 → 1.3.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.
Files changed (39) hide show
  1. package/dist/cjs/SlugEditor.js +139 -0
  2. package/dist/cjs/SlugEditor.test.js +508 -0
  3. package/dist/cjs/SlugEditorField.js +186 -0
  4. package/dist/cjs/TrackingFieldConnector.js +137 -0
  5. package/dist/cjs/index.js +24 -0
  6. package/dist/cjs/services/makeSlug.js +42 -0
  7. package/dist/cjs/services/makeSlug.test.js +14 -0
  8. package/dist/cjs/services/slugify.js +64 -0
  9. package/dist/cjs/services/slugify.test.js +30 -0
  10. package/dist/cjs/styles.js +68 -0
  11. package/dist/esm/SlugEditor.js +90 -0
  12. package/dist/esm/SlugEditor.test.js +460 -0
  13. package/dist/esm/SlugEditorField.js +129 -0
  14. package/dist/esm/TrackingFieldConnector.js +88 -0
  15. package/dist/esm/index.js +3 -0
  16. package/dist/esm/services/makeSlug.js +24 -0
  17. package/dist/esm/services/makeSlug.test.js +10 -0
  18. package/dist/esm/services/slugify.js +49 -0
  19. package/dist/esm/services/slugify.test.js +26 -0
  20. package/dist/esm/styles.js +33 -0
  21. package/dist/{SlugEditor.d.ts → types/SlugEditor.d.ts} +24 -24
  22. package/dist/types/SlugEditor.test.d.ts +1 -0
  23. package/dist/{SlugEditorField.d.ts → types/SlugEditorField.d.ts} +18 -18
  24. package/dist/{TrackingFieldConnector.d.ts → types/TrackingFieldConnector.d.ts} +29 -29
  25. package/dist/{index.d.ts → types/index.d.ts} +3 -3
  26. package/dist/{services → types/services}/makeSlug.d.ts +8 -8
  27. package/dist/types/services/makeSlug.test.d.ts +1 -0
  28. package/dist/{services → types/services}/slugify.d.ts +12 -12
  29. package/dist/types/services/slugify.test.d.ts +1 -0
  30. package/dist/{styles.d.ts → types/styles.d.ts} +6 -6
  31. package/package.json +25 -11
  32. package/CHANGELOG.md +0 -206
  33. package/dist/field-editor-slug.cjs.development.js +0 -463
  34. package/dist/field-editor-slug.cjs.development.js.map +0 -1
  35. package/dist/field-editor-slug.cjs.production.min.js +0 -2
  36. package/dist/field-editor-slug.cjs.production.min.js.map +0 -1
  37. package/dist/field-editor-slug.esm.js +0 -454
  38. package/dist/field-editor-slug.esm.js.map +0 -1
  39. package/dist/index.js +0 -8
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "SlugEditor", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return SlugEditor;
9
+ }
10
+ });
11
+ const _react = _interop_require_wildcard(require("react"));
12
+ const _fieldeditorshared = require("@contentful/field-editor-shared");
13
+ const _SlugEditorField = require("./SlugEditorField");
14
+ const _TrackingFieldConnector = require("./TrackingFieldConnector");
15
+ function _getRequireWildcardCache(nodeInterop) {
16
+ if (typeof WeakMap !== "function") return null;
17
+ var cacheBabelInterop = new WeakMap();
18
+ var cacheNodeInterop = new WeakMap();
19
+ return (_getRequireWildcardCache = function(nodeInterop) {
20
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
21
+ })(nodeInterop);
22
+ }
23
+ function _interop_require_wildcard(obj, nodeInterop) {
24
+ if (!nodeInterop && obj && obj.__esModule) {
25
+ return obj;
26
+ }
27
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
28
+ return {
29
+ default: obj
30
+ };
31
+ }
32
+ var cache = _getRequireWildcardCache(nodeInterop);
33
+ if (cache && cache.has(obj)) {
34
+ return cache.get(obj);
35
+ }
36
+ var newObj = {};
37
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
38
+ for(var key in obj){
39
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
40
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
41
+ if (desc && (desc.get || desc.set)) {
42
+ Object.defineProperty(newObj, key, desc);
43
+ } else {
44
+ newObj[key] = obj[key];
45
+ }
46
+ }
47
+ }
48
+ newObj.default = obj;
49
+ if (cache) {
50
+ cache.set(obj, newObj);
51
+ }
52
+ return newObj;
53
+ }
54
+ function isSupportedFieldTypes(val) {
55
+ return val === 'Symbol';
56
+ }
57
+ function FieldConnectorCallback({ Component , value , disabled , setValue , errors , titleValue , isOptionalLocaleWithFallback , locale , createdAt , performUniqueCheck }) {
58
+ const safeSetValue = _react.useCallback(async (...args)=>{
59
+ try {
60
+ await setValue(...args);
61
+ } catch (e) {}
62
+ }, [
63
+ setValue
64
+ ]);
65
+ return _react.createElement("div", {
66
+ "data-test-id": "slug-editor"
67
+ }, _react.createElement(Component, {
68
+ locale: locale,
69
+ createdAt: createdAt,
70
+ performUniqueCheck: performUniqueCheck,
71
+ hasError: errors.length > 0,
72
+ value: value,
73
+ isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
74
+ isDisabled: disabled,
75
+ titleValue: titleValue,
76
+ setValue: safeSetValue
77
+ }));
78
+ }
79
+ function SlugEditor(props) {
80
+ const { field , parameters } = props;
81
+ const { locales , entry , space } = props.baseSdk;
82
+ if (!isSupportedFieldTypes(field.type)) {
83
+ throw new Error(`"${field.type}" field type is not supported by SlugEditor`);
84
+ }
85
+ const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
86
+ const entrySys = entry.getSys();
87
+ const isLocaleOptional = locales.optional[field.locale];
88
+ const localeFallbackCode = locales.fallbacks[field.locale];
89
+ const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);
90
+ const isOptionalLocaleWithFallback = Boolean(isOptionalFieldLocale && localeFallbackCode && locales.available.includes(localeFallbackCode));
91
+ const performUniqueCheck = _react.useCallback((value)=>{
92
+ const searchQuery = {
93
+ content_type: entrySys?.contentType?.sys?.id,
94
+ [`fields.${field.id}.${field.locale}`]: value,
95
+ 'sys.id[ne]': entrySys.id,
96
+ 'sys.publishedAt[exists]': true,
97
+ limit: 0
98
+ };
99
+ return space.getEntries(searchQuery).then((res)=>{
100
+ return res.total === 0;
101
+ });
102
+ }, [
103
+ entrySys?.contentType?.sys?.id,
104
+ field.id,
105
+ field.locale,
106
+ entrySys.id,
107
+ space
108
+ ]);
109
+ return _react.createElement(_TrackingFieldConnector.TrackingFieldConnector, {
110
+ sdk: props.baseSdk,
111
+ field: field,
112
+ defaultLocale: locales.default,
113
+ isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
114
+ trackingFieldId: trackingFieldId
115
+ }, ({ titleValue , isPublished , isSame })=>_react.createElement(_fieldeditorshared.FieldConnector, {
116
+ field: field,
117
+ isInitiallyDisabled: props.isInitiallyDisabled,
118
+ throttle: 0
119
+ }, ({ value , errors , disabled , setValue , externalReset })=>{
120
+ const shouldTrackTitle = isPublished === false && isSame === false;
121
+ const Component = shouldTrackTitle ? _SlugEditorField.SlugEditorField : _SlugEditorField.SlugEditorFieldStatic;
122
+ return _react.createElement(FieldConnectorCallback, {
123
+ Component: Component,
124
+ titleValue: titleValue,
125
+ value: value,
126
+ errors: errors,
127
+ disabled: disabled,
128
+ setValue: setValue,
129
+ isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
130
+ createdAt: entrySys.createdAt,
131
+ locale: field.locale,
132
+ performUniqueCheck: performUniqueCheck,
133
+ key: `slug-editor-${externalReset}`
134
+ });
135
+ }));
136
+ }
137
+ SlugEditor.defaultProps = {
138
+ isInitiallyDisabled: true
139
+ };
@@ -0,0 +1,508 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ const _react = _interop_require_wildcard(require("react"));
6
+ const _fieldeditortestutils = require("@contentful/field-editor-test-utils");
7
+ const _react1 = require("@testing-library/react");
8
+ const _identity = _interop_require_default(require("lodash/identity"));
9
+ require("@testing-library/jest-dom/extend-expect");
10
+ const _SlugEditor = require("./SlugEditor");
11
+ function _interop_require_default(obj) {
12
+ return obj && obj.__esModule ? obj : {
13
+ default: obj
14
+ };
15
+ }
16
+ function _getRequireWildcardCache(nodeInterop) {
17
+ if (typeof WeakMap !== "function") return null;
18
+ var cacheBabelInterop = new WeakMap();
19
+ var cacheNodeInterop = new WeakMap();
20
+ return (_getRequireWildcardCache = function(nodeInterop) {
21
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
22
+ })(nodeInterop);
23
+ }
24
+ function _interop_require_wildcard(obj, nodeInterop) {
25
+ if (!nodeInterop && obj && obj.__esModule) {
26
+ return obj;
27
+ }
28
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
29
+ return {
30
+ default: obj
31
+ };
32
+ }
33
+ var cache = _getRequireWildcardCache(nodeInterop);
34
+ if (cache && cache.has(obj)) {
35
+ return cache.get(obj);
36
+ }
37
+ var newObj = {};
38
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
39
+ for(var key in obj){
40
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
41
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
42
+ if (desc && (desc.get || desc.set)) {
43
+ Object.defineProperty(newObj, key, desc);
44
+ } else {
45
+ newObj[key] = obj[key];
46
+ }
47
+ }
48
+ }
49
+ newObj.default = obj;
50
+ if (cache) {
51
+ cache.set(obj, newObj);
52
+ }
53
+ return newObj;
54
+ }
55
+ (0, _react1.configure)({
56
+ testIdAttribute: 'data-test-id'
57
+ });
58
+ jest.mock('lodash/throttle', ()=>({
59
+ default: _identity.default
60
+ }), {
61
+ virtual: true
62
+ });
63
+ jest.mock('use-debounce', ()=>({
64
+ useDebounce: (text)=>[
65
+ text
66
+ ]
67
+ }));
68
+ function createMocks(initialValues = {}) {
69
+ const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)((field)=>({
70
+ ...field,
71
+ id: 'slug-id',
72
+ onValueChanged: jest.fn().mockImplementation(field.onValueChanged),
73
+ setValue: jest.fn().mockImplementation(field.setValue)
74
+ }), initialValues.field || '');
75
+ const [titleField] = (0, _fieldeditortestutils.createFakeFieldAPI)((field)=>({
76
+ ...field,
77
+ id: 'title-id',
78
+ setValue: jest.fn().mockImplementation(field.setValue),
79
+ getValue: jest.fn().mockImplementation(field.getValue),
80
+ onValueChanged: jest.fn().mockImplementation(field.onValueChanged)
81
+ }), initialValues.titleField || '');
82
+ const [descriptionField] = (0, _fieldeditortestutils.createFakeFieldAPI)((field)=>({
83
+ ...field,
84
+ id: 'description-id',
85
+ setValue: jest.fn().mockImplementation(field.setValue),
86
+ getValue: jest.fn().mockImplementation(field.getValue),
87
+ onValueChanged: jest.fn().mockImplementation(field.onValueChanged)
88
+ }), initialValues.descriptionField || '');
89
+ const sdk = {
90
+ locales: (0, _fieldeditortestutils.createFakeLocalesAPI)(),
91
+ space: {
92
+ getEntries: jest.fn().mockResolvedValue({
93
+ total: 0
94
+ })
95
+ },
96
+ entry: {
97
+ getSys: jest.fn().mockReturnValue({
98
+ id: 'entry-id',
99
+ publishedVersion: undefined,
100
+ createdAt: '2020-01-24T15:33:47.906Z',
101
+ contentType: {
102
+ sys: {
103
+ id: 'content-type-id'
104
+ }
105
+ }
106
+ }),
107
+ onSysChanged: jest.fn(),
108
+ fields: {
109
+ 'title-id': titleField,
110
+ 'entry-id': field,
111
+ 'description-id': descriptionField
112
+ }
113
+ },
114
+ contentType: {
115
+ displayField: 'title-id'
116
+ }
117
+ };
118
+ return {
119
+ field,
120
+ titleField,
121
+ descriptionField,
122
+ sdk
123
+ };
124
+ }
125
+ describe('SlugEditor', ()=>{
126
+ afterEach(_react1.cleanup);
127
+ describe('should not subscribe to title changes', ()=>{
128
+ it('when entry is published', async ()=>{
129
+ const { field , titleField , sdk } = createMocks();
130
+ sdk.entry.getSys.mockReturnValue({
131
+ publishedVersion: 2
132
+ });
133
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
134
+ field: field,
135
+ baseSdk: sdk,
136
+ isInitiallyDisabled: false
137
+ }));
138
+ await (0, _react1.wait)();
139
+ expect(field.setValue).not.toHaveBeenCalled();
140
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('en-US', expect.any(Function));
141
+ expect(sdk.space.getEntries).not.toHaveBeenCalled();
142
+ expect(sdk.entry.fields['title-id'].getValue).toHaveBeenCalledTimes(1);
143
+ expect(sdk.entry.getSys).toHaveBeenCalledTimes(2);
144
+ });
145
+ it('when title and slug are the same field', async ()=>{
146
+ const { field , titleField , sdk } = createMocks();
147
+ sdk.contentType.displayField = 'entry-id';
148
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
149
+ field: field,
150
+ baseSdk: sdk,
151
+ isInitiallyDisabled: false
152
+ }));
153
+ await (0, _react1.wait)();
154
+ expect(titleField.onValueChanged).not.toHaveBeenCalled();
155
+ expect(field.setValue).not.toHaveBeenCalled();
156
+ });
157
+ it('when a saved slug is different from a title at the render', async ()=>{
158
+ const { field , titleField , sdk } = createMocks({
159
+ titleField: 'Hello world!',
160
+ field: 'something-different'
161
+ });
162
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
163
+ field: field,
164
+ baseSdk: sdk,
165
+ isInitiallyDisabled: false
166
+ }));
167
+ await (0, _react1.wait)();
168
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('en-US', expect.any(Function));
169
+ expect(field.setValue).not.toHaveBeenCalled();
170
+ });
171
+ });
172
+ describe('should check for uniqueness', ()=>{
173
+ it('if it is published', async ()=>{
174
+ const { field , titleField , sdk } = createMocks({
175
+ titleField: 'Slug value',
176
+ field: 'slug-value'
177
+ });
178
+ sdk.entry.getSys.mockReturnValue({
179
+ id: 'entry-id',
180
+ publishedVersion: 2,
181
+ contentType: {
182
+ sys: {
183
+ id: 'content-type-id'
184
+ }
185
+ }
186
+ });
187
+ sdk.space.getEntries.mockResolvedValue({
188
+ total: 0
189
+ });
190
+ const { queryByTestId , queryByText } = (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
191
+ field: field,
192
+ baseSdk: sdk,
193
+ isInitiallyDisabled: false
194
+ }));
195
+ await (0, _react1.wait)();
196
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('en-US', expect.any(Function));
197
+ expect(sdk.space.getEntries).toHaveBeenLastCalledWith({
198
+ content_type: 'content-type-id',
199
+ 'fields.slug-id.en-US': 'slug-value',
200
+ limit: 0,
201
+ 'sys.id[ne]': 'entry-id',
202
+ 'sys.publishedAt[exists]': true
203
+ });
204
+ expect(sdk.space.getEntries).toHaveBeenCalledTimes(1);
205
+ expect(queryByTestId('slug-editor-spinner')).not.toBeInTheDocument();
206
+ expect(queryByText('This slug has already been published in another entry')).not.toBeInTheDocument();
207
+ });
208
+ it('if it is not published', async ()=>{
209
+ const { field , titleField , sdk } = createMocks({
210
+ titleField: 'Slug value',
211
+ field: 'slug-value'
212
+ });
213
+ sdk.entry.getSys.mockReturnValue({
214
+ id: 'entry-id',
215
+ publishedVersion: undefined,
216
+ contentType: {
217
+ sys: {
218
+ id: 'content-type-id'
219
+ }
220
+ }
221
+ });
222
+ sdk.space.getEntries.mockResolvedValue({
223
+ total: 2
224
+ });
225
+ const { queryByTestId , queryByText , getByTestId } = (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
226
+ field: field,
227
+ baseSdk: sdk,
228
+ isInitiallyDisabled: false
229
+ }));
230
+ await (0, _react1.wait)();
231
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('en-US', expect.any(Function));
232
+ expect(sdk.space.getEntries).toHaveBeenLastCalledWith({
233
+ content_type: 'content-type-id',
234
+ 'fields.slug-id.en-US': 'slug-value',
235
+ limit: 0,
236
+ 'sys.id[ne]': 'entry-id',
237
+ 'sys.publishedAt[exists]': true
238
+ });
239
+ expect(sdk.space.getEntries).toHaveBeenCalledTimes(1);
240
+ expect(queryByTestId('slug-editor-spinner')).not.toBeInTheDocument();
241
+ expect(queryByText('This slug has already been published in another entry')).toBeInTheDocument();
242
+ expect(getByTestId('cf-ui-text-input')).toHaveValue('slug-value');
243
+ sdk.space.getEntries.mockResolvedValue({
244
+ total: 0
245
+ });
246
+ _react1.fireEvent.change(getByTestId('cf-ui-text-input'), {
247
+ target: {
248
+ value: '123'
249
+ }
250
+ });
251
+ await (0, _react1.wait)();
252
+ expect(field.setValue).toHaveBeenCalledTimes(1);
253
+ expect(field.setValue).toHaveBeenCalledWith('123');
254
+ expect(sdk.space.getEntries).toHaveBeenCalledTimes(2);
255
+ expect(sdk.space.getEntries).toHaveBeenLastCalledWith({
256
+ content_type: 'content-type-id',
257
+ 'fields.slug-id.en-US': '123',
258
+ limit: 0,
259
+ 'sys.id[ne]': 'entry-id',
260
+ 'sys.publishedAt[exists]': true
261
+ });
262
+ expect(queryByText('This slug has already been published in another entry')).not.toBeInTheDocument();
263
+ });
264
+ });
265
+ describe('should react to title changes', ()=>{
266
+ it('when field is disabled', async ()=>{
267
+ const { field , titleField , sdk } = createMocks({
268
+ field: '',
269
+ titleField: ''
270
+ });
271
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
272
+ field: field,
273
+ baseSdk: sdk,
274
+ isInitiallyDisabled: true
275
+ }));
276
+ await (0, _react1.wait)();
277
+ expect(field.setValue).toHaveBeenCalled();
278
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('en-US', expect.any(Function));
279
+ expect(sdk.space.getEntries).toHaveBeenCalled();
280
+ expect(sdk.entry.fields['title-id'].getValue).toHaveBeenCalledTimes(1);
281
+ expect(sdk.entry.getSys).toHaveBeenCalledTimes(2);
282
+ });
283
+ it('should generate unique value with date if title is empty', async ()=>{
284
+ const { field , titleField , sdk } = createMocks({
285
+ field: '',
286
+ titleField: ''
287
+ });
288
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
289
+ field: field,
290
+ baseSdk: sdk,
291
+ isInitiallyDisabled: false
292
+ }));
293
+ await (0, _react1.wait)();
294
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('en-US', expect.any(Function));
295
+ expect(field.setValue).toHaveBeenCalledTimes(1);
296
+ expect(field.setValue).toHaveBeenLastCalledWith('untitled-entry-2020-01-24-at-15-33-47');
297
+ await sdk.entry.fields['title-id'].setValue('Hello world!');
298
+ await (0, _react1.wait)();
299
+ expect(field.setValue).toHaveBeenCalledTimes(2);
300
+ expect(field.setValue).toHaveBeenLastCalledWith('hello-world');
301
+ expect(sdk.space.getEntries).toHaveBeenCalledTimes(2);
302
+ await sdk.entry.fields['title-id'].setValue('фраза написанная по русски');
303
+ await (0, _react1.wait)();
304
+ expect(field.setValue).toHaveBeenCalledTimes(3);
305
+ expect(field.setValue).toHaveBeenLastCalledWith('fraza-napisannaya-po-russki');
306
+ expect(sdk.space.getEntries).toHaveBeenCalledTimes(3);
307
+ });
308
+ it('should generate value from title if it is not empty', async ()=>{
309
+ const { field , titleField , sdk } = createMocks({
310
+ field: '',
311
+ titleField: 'This is initial title value'
312
+ });
313
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
314
+ field: field,
315
+ baseSdk: sdk,
316
+ isInitiallyDisabled: false
317
+ }));
318
+ await (0, _react1.wait)();
319
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('en-US', expect.any(Function));
320
+ expect(field.setValue).toHaveBeenCalledTimes(1);
321
+ expect(field.setValue).toHaveBeenLastCalledWith('this-is-initial-title-value');
322
+ await sdk.entry.fields['title-id'].setValue('Hello world!');
323
+ await (0, _react1.wait)();
324
+ expect(field.setValue).toHaveBeenCalledTimes(2);
325
+ expect(field.setValue).toHaveBeenLastCalledWith('hello-world');
326
+ expect(sdk.space.getEntries).toHaveBeenCalledTimes(2);
327
+ });
328
+ it('should stop tracking value after user intentionally changes slug value', async ()=>{
329
+ const { field , titleField , sdk } = createMocks({
330
+ field: '',
331
+ titleField: ''
332
+ });
333
+ const { getByTestId } = (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
334
+ field: field,
335
+ baseSdk: sdk,
336
+ isInitiallyDisabled: false
337
+ }));
338
+ await (0, _react1.wait)();
339
+ await sdk.entry.fields['title-id'].setValue('Hello world!');
340
+ await (0, _react1.wait)();
341
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('en-US', expect.any(Function));
342
+ expect(field.setValue).toHaveBeenCalledTimes(2);
343
+ expect(field.setValue).toHaveBeenCalledWith('untitled-entry-2020-01-24-at-15-33-47');
344
+ expect(field.setValue).toHaveBeenLastCalledWith('hello-world');
345
+ expect(sdk.space.getEntries).toHaveBeenCalledTimes(2);
346
+ _react1.fireEvent.change(getByTestId('cf-ui-text-input'), {
347
+ target: {
348
+ value: 'new-custom-slug'
349
+ }
350
+ });
351
+ await (0, _react1.wait)();
352
+ expect(field.setValue).toHaveBeenCalledTimes(3);
353
+ expect(field.setValue).toHaveBeenLastCalledWith('new-custom-slug');
354
+ await sdk.entry.fields['title-id'].setValue('I decided to update my title');
355
+ await (0, _react1.wait)();
356
+ expect(field.setValue).toHaveBeenCalledTimes(3);
357
+ await sdk.entry.fields['title-id'].setValue('I decided to update my title again');
358
+ await (0, _react1.wait)();
359
+ expect(field.setValue).toHaveBeenCalledTimes(3);
360
+ });
361
+ it('should start tracking again after potential slug equals real one', async ()=>{
362
+ const { field , sdk } = createMocks({
363
+ field: '',
364
+ titleField: ''
365
+ });
366
+ const { getByTestId } = (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
367
+ field: field,
368
+ baseSdk: sdk,
369
+ isInitiallyDisabled: false
370
+ }));
371
+ await (0, _react1.wait)();
372
+ await sdk.entry.fields['title-id'].setValue('ABC DEF');
373
+ await (0, _react1.wait)();
374
+ expect(field.setValue).toHaveBeenLastCalledWith('abc-def');
375
+ expect(field.setValue).toHaveBeenCalledTimes(2);
376
+ _react1.fireEvent.change(getByTestId('cf-ui-text-input'), {
377
+ target: {
378
+ value: 'abc'
379
+ }
380
+ });
381
+ await sdk.entry.fields['title-id'].setValue('ABC D');
382
+ await (0, _react1.wait)();
383
+ expect(field.setValue).toHaveBeenLastCalledWith('abc');
384
+ expect(field.setValue).toHaveBeenCalledTimes(3);
385
+ await sdk.entry.fields['title-id'].setValue('ABC');
386
+ await sdk.entry.fields['title-id'].setValue('ABC ABC');
387
+ await (0, _react1.wait)();
388
+ expect(field.setValue).toHaveBeenLastCalledWith('abc-abc');
389
+ expect(field.setValue).toHaveBeenCalledTimes(4);
390
+ await (0, _react1.wait)();
391
+ });
392
+ });
393
+ describe('for non default locales', ()=>{
394
+ it('locale is not optional and has no fallback then it should track default locale changes & current locale changes', async ()=>{
395
+ const { sdk , field , titleField } = createMocks();
396
+ field.locale = 'ru-RU';
397
+ field.required = false;
398
+ sdk.locales.available = [
399
+ 'de-DE',
400
+ 'ru-RU'
401
+ ];
402
+ sdk.locales.default = 'de-DE';
403
+ sdk.locales.optional = {
404
+ 'de-DE': false,
405
+ 'ru-RU': false
406
+ };
407
+ sdk.locales.fallbacks = {
408
+ 'de-DE': undefined,
409
+ 'ru-RU': undefined
410
+ };
411
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
412
+ field: field,
413
+ baseSdk: sdk,
414
+ isInitiallyDisabled: false
415
+ }));
416
+ await (0, _react1.wait)();
417
+ expect(field.setValue).toHaveBeenCalledWith('untitled-entry-2020-01-24-at-15-33-47');
418
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('ru-RU', expect.any(Function));
419
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('de-DE', expect.any(Function));
420
+ });
421
+ it('locale is optional and has a fallback then it should track only current locale changes', async ()=>{
422
+ const { sdk , field , titleField } = createMocks();
423
+ field.locale = 'ru-RU';
424
+ field.required = false;
425
+ sdk.locales.available = [
426
+ 'de-DE',
427
+ 'ru-RU'
428
+ ];
429
+ sdk.locales.default = 'de-DE';
430
+ sdk.locales.optional = {
431
+ 'de-DE': false,
432
+ 'ru-RU': true
433
+ };
434
+ sdk.locales.fallbacks = {
435
+ 'de-DE': undefined,
436
+ 'ru-RU': 'de-DE'
437
+ };
438
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
439
+ field: field,
440
+ baseSdk: sdk,
441
+ isInitiallyDisabled: false
442
+ }));
443
+ await (0, _react1.wait)();
444
+ expect(field.setValue).not.toHaveBeenCalled();
445
+ expect(titleField.onValueChanged).toHaveBeenCalledWith('ru-RU', expect.any(Function));
446
+ expect(titleField.onValueChanged).not.toHaveBeenCalledWith('de-DE', expect.any(Function));
447
+ });
448
+ });
449
+ it('slug suggestion is limited to 75 symbols', async ()=>{
450
+ const { field , sdk } = createMocks({
451
+ field: '',
452
+ titleField: ''
453
+ });
454
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
455
+ field: field,
456
+ baseSdk: sdk,
457
+ isInitiallyDisabled: false
458
+ }));
459
+ await (0, _react1.wait)();
460
+ await sdk.entry.fields['title-id'].setValue('a'.repeat(80));
461
+ await (0, _react1.wait)();
462
+ const expectedSlug = 'a'.repeat(75);
463
+ expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
464
+ });
465
+ it('slug suggestion does not contain cut-off words', async ()=>{
466
+ const { field , sdk } = createMocks({
467
+ field: '',
468
+ titleField: ''
469
+ });
470
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
471
+ field: field,
472
+ baseSdk: sdk,
473
+ isInitiallyDisabled: false
474
+ }));
475
+ await (0, _react1.wait)();
476
+ await sdk.entry.fields['title-id'].setValue(`one two three ${'a'.repeat(80)}`);
477
+ await (0, _react1.wait)();
478
+ const expectedSlug = 'one-two-three';
479
+ expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
480
+ });
481
+ it('should subscribe for changes in custom field id', async ()=>{
482
+ const { field , titleField , descriptionField , sdk } = createMocks({
483
+ field: '',
484
+ titleField: 'This is initial title value',
485
+ descriptionField: 'This is initial description value'
486
+ });
487
+ (0, _react1.render)(_react.createElement(_SlugEditor.SlugEditor, {
488
+ field: field,
489
+ baseSdk: sdk,
490
+ isInitiallyDisabled: false,
491
+ parameters: {
492
+ instance: {
493
+ trackingFieldId: 'description-id'
494
+ }
495
+ }
496
+ }));
497
+ await (0, _react1.wait)();
498
+ expect(titleField.onValueChanged).not.toHaveBeenCalled();
499
+ expect(descriptionField.onValueChanged).toHaveBeenCalledWith('en-US', expect.any(Function));
500
+ expect(field.setValue).toHaveBeenCalledTimes(1);
501
+ expect(field.setValue).toHaveBeenLastCalledWith('this-is-initial-description-value');
502
+ await sdk.entry.fields['description-id'].setValue('Hello world!');
503
+ await (0, _react1.wait)();
504
+ expect(field.setValue).toHaveBeenCalledTimes(2);
505
+ expect(field.setValue).toHaveBeenLastCalledWith('hello-world');
506
+ expect(sdk.space.getEntries).toHaveBeenCalledTimes(2);
507
+ });
508
+ });