Skip to content

Commit 796ba74

Browse files
committed
fix(gv-schema-form): wait browser refresh before update
gravitee-io/issues#6514
1 parent 5e79eba commit 796ba74

File tree

5 files changed

+112
-68
lines changed

5 files changed

+112
-68
lines changed

src/mixins/update-after-browser.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (C) 2021 The Gravitee team (http://gravitee.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
/**
17+
* This is a mixin for update component after browser
18+
* @mixinFunction
19+
*/
20+
export function UpdateAfterBrowser(ParentClass) {
21+
/**
22+
* @mixinClass
23+
*/
24+
return class extends ParentClass {
25+
async performUpdate() {
26+
await new Promise((resolve) => requestAnimationFrame(() => resolve()));
27+
super.performUpdate();
28+
}
29+
};
30+
}

src/organisms/gv-schema-form-array.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ import { canInline } from '../lib/schema-form';
1818
import { dispatchCustomEvent } from '../lib/events';
1919
import { classMap } from 'lit-html/directives/class-map';
2020
import { skeleton } from '../styles/skeleton';
21+
import { UpdateAfterBrowser } from '../mixins/update-after-browser';
2122

2223
/**
2324
* Schema form array component
2425
*
2526
*/
26-
export class GvSchemaFormArray extends LitElement {
27+
export class GvSchemaFormArray extends UpdateAfterBrowser(LitElement) {
2728
static get properties() {
2829
return {
2930
schema: { type: Object },

src/organisms/gv-schema-form-control-object.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ import { canInline, canGrid } from '../lib/schema-form';
1818
import { classMap } from 'lit-html/directives/class-map';
1919
import { skeleton } from '../styles/skeleton';
2020
import '../molecules/gv-expandable';
21+
import { UpdateAfterBrowser } from '../mixins/update-after-browser';
2122

2223
/**
2324
* Schema form control object component
2425
*/
25-
export class GvSchemaFormControlObject extends LitElement {
26+
export class GvSchemaFormControlObject extends UpdateAfterBrowser(LitElement) {
2627
static get properties() {
2728
return {
2829
schema: { type: Object },

src/organisms/gv-schema-form-control.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ import '../atoms/gv-autocomplete';
2828
import '../organisms/gv-schema-form-array';
2929
import '../organisms/gv-schema-form-control-object';
3030
import { isCodemirror, isObject, isComplexArray } from '../lib/schema-form';
31+
import { UpdateAfterBrowser } from '../mixins/update-after-browser';
3132

32-
export class GvSchemaFormControl extends LitElement {
33+
export class GvSchemaFormControl extends UpdateAfterBrowser(LitElement) {
3334
static get properties() {
3435
return {
3536
type: { type: String },
@@ -297,8 +298,8 @@ export class GvSchemaFormControl extends LitElement {
297298
}
298299
}
299300

300-
async getUpdateComplete() {
301-
await super.getUpdateComplete();
301+
async _getUpdateComplete() {
302+
await super._getUpdateComplete();
302303
await Promise.all(this.getControls().map((e) => e.updateComplete));
303304
}
304305

stories/organisms/gv-schema-form.test.js

Lines changed: 74 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ describe('S C H E M A F O R M', () => {
346346
});
347347
});
348348

349-
test('should reset initial values', () => {
349+
test('should reset initial values', (done) => {
350350
const preventDefault = jest.fn();
351351
const stopPropagation = jest.fn();
352352
const values = {
@@ -358,48 +358,53 @@ describe('S C H E M A F O R M', () => {
358358
multiselect: ['a'],
359359
};
360360
component.values = deepClone(values);
361+
component.updateComplete.then(() => {
362+
const pathOperatorControl = component.getControl('path-operator');
363+
364+
expect(pathOperatorControl).not.toBeNull();
365+
pathOperatorControl._onInput({
366+
preventDefault,
367+
stopPropagation,
368+
target: { id: 'path-operator.path' },
369+
detail: '/updated-path',
370+
});
361371

362-
const pathOperatorControl = component.getControl('path-operator');
363-
expect(pathOperatorControl).not.toBeNull();
364-
pathOperatorControl._onInput({
365-
preventDefault,
366-
stopPropagation,
367-
target: { id: 'path-operator.path' },
368-
detail: '/updated-path',
369-
});
370-
371-
const timeToLiveSeconds = component.getControl('timeToLiveSeconds');
372-
expect(timeToLiveSeconds).not.toBeNull();
373-
timeToLiveSeconds._onInput({
374-
preventDefault,
375-
stopPropagation,
376-
target: { id: 'timeToLiveSeconds' },
377-
detail: 12,
378-
});
372+
const timeToLiveSeconds = component.getControl('timeToLiveSeconds');
373+
expect(timeToLiveSeconds).not.toBeNull();
374+
timeToLiveSeconds._onInput({
375+
preventDefault,
376+
stopPropagation,
377+
target: { id: 'timeToLiveSeconds' },
378+
detail: 12,
379+
});
379380

380-
const multiselect = component.getControl('multiselect');
381-
multiselect._onInput({
382-
preventDefault,
383-
stopPropagation,
384-
target: { id: 'multiselect' },
385-
detail: ['a', 'b'],
386-
});
381+
const multiselect = component.getControl('multiselect');
382+
multiselect._onInput({
383+
preventDefault,
384+
stopPropagation,
385+
target: { id: 'multiselect' },
386+
detail: ['a', 'b'],
387+
});
387388

388-
expect(component.values).toEqual({
389-
'path-operator': {
390-
operator: 'STARTS_WITH',
391-
path: '/updated-path',
392-
},
393-
timeToLiveSeconds: 12,
394-
multiselect: ['a', 'b'],
395-
});
389+
expect(component.values).toEqual({
390+
'path-operator': {
391+
operator: 'STARTS_WITH',
392+
path: '/updated-path',
393+
},
394+
readonly: 'Should not edit my value',
395+
timeToLiveSeconds: 12,
396+
writeonly: 'Should not read my value',
397+
multiselect: ['a', 'b'],
398+
});
396399

397-
component.reset();
400+
component.reset();
398401

399-
expect(component.values).toEqual(values);
402+
expect(component.values).toEqual(values);
403+
done();
404+
});
400405
});
401406

402-
test('should remove value with empty string & empty array', () => {
407+
test('should remove value with empty string & empty array', (done) => {
403408
const preventDefault = jest.fn();
404409
const stopPropagation = jest.fn();
405410
const values = {
@@ -412,36 +417,42 @@ describe('S C H E M A F O R M', () => {
412417
};
413418
component.values = deepClone(values);
414419

415-
const pathOperatorControl = component.getControl('path-operator');
416-
expect(pathOperatorControl).not.toBeNull();
417-
pathOperatorControl._onInput({
418-
preventDefault,
419-
stopPropagation,
420-
target: { id: 'path-operator.path' },
421-
detail: '',
422-
});
420+
component.updateComplete.then(() => {
421+
const pathOperatorControl = component.getControl('path-operator');
422+
expect(pathOperatorControl).not.toBeNull();
423+
pathOperatorControl._onInput({
424+
preventDefault,
425+
stopPropagation,
426+
target: { id: 'path-operator.path' },
427+
detail: '',
428+
});
423429

424-
const timeToLiveSeconds = component.getControl('timeToLiveSeconds');
425-
expect(timeToLiveSeconds).not.toBeNull();
426-
timeToLiveSeconds._onInput({
427-
preventDefault,
428-
stopPropagation,
429-
target: { id: 'timeToLiveSeconds' },
430-
detail: '',
431-
});
430+
const timeToLiveSeconds = component.getControl('timeToLiveSeconds');
431+
expect(timeToLiveSeconds).not.toBeNull();
432+
timeToLiveSeconds._onInput({
433+
preventDefault,
434+
stopPropagation,
435+
target: { id: 'timeToLiveSeconds' },
436+
detail: '',
437+
});
432438

433-
const multiselect = component.getControl('multiselect');
434-
multiselect._onInput({
435-
preventDefault,
436-
stopPropagation,
437-
target: { id: 'multiselect' },
438-
detail: [],
439-
});
439+
const multiselect = component.getControl('multiselect');
440+
multiselect._onInput({
441+
preventDefault,
442+
stopPropagation,
443+
target: { id: 'multiselect' },
444+
detail: [],
445+
});
440446

441-
expect(component.values).toEqual({
442-
'path-operator': {
443-
operator: 'STARTS_WITH',
444-
},
447+
expect(component.values).toEqual({
448+
'path-operator': {
449+
operator: 'STARTS_WITH',
450+
},
451+
readonly: 'Should not edit my value',
452+
writeonly: 'Should not read my value',
453+
});
454+
455+
done();
445456
});
446457
});
447458

0 commit comments

Comments
 (0)