@json-editor/json-editor 2.5.4 → 2.6.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.
@@ -75,7 +75,6 @@
75
75
  "enum":[
76
76
  "color",
77
77
  "date",
78
- "datetime",
79
78
  "datetime-local",
80
79
  "email",
81
80
  "month",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@json-editor/json-editor",
3
3
  "title": "JSONEditor",
4
4
  "description": "JSON Schema based editor",
5
- "version": "2.5.4",
5
+ "version": "2.6.0",
6
6
  "main": "dist/jsoneditor.js",
7
7
  "author": {
8
8
  "name": "Jeremy Dorn",
@@ -53,48 +53,49 @@
53
53
  "node": ">= 0.8.0"
54
54
  },
55
55
  "devDependencies": {
56
- "@babel/core": "^7.9.6",
57
- "@babel/plugin-transform-runtime": "^7.12.1",
58
- "@babel/preset-env": "^7.9.6",
59
- "@babel/runtime": "^7.12.1",
60
- "ace-builds": "^1.4.11",
61
- "babel-loader": "^8.1.0",
56
+ "@babel/core": "^7.14.0",
57
+ "@babel/plugin-transform-runtime": "^7.13.15",
58
+ "@babel/preset-env": "^7.14.1",
59
+ "@babel/runtime": "^7.14.0",
60
+ "ace-builds": "^1.4.12",
61
+ "babel-loader": "^8.2.2",
62
62
  "clean-webpack-plugin": "^3.0.0",
63
- "cleave.js": "^1.5.10",
64
- "codeceptjs": "^2.6.2",
65
- "css-loader": "^3.5.3",
63
+ "cleave.js": "^1.6.0",
64
+ "codeceptjs": "^2.6.11",
65
+ "css-loader": "^3.6.0",
66
66
  "css2json": "^1.1.1",
67
- "cssnano": "^4.1.10",
67
+ "cssnano": "^4.1.11",
68
68
  "eslint": "^6.8.0",
69
69
  "eslint-loader": "^2.2.1",
70
+ "fast-deep-equal": "^3.1.3",
70
71
  "http-server": "^0.12.3",
71
- "jasmine": "^3.5.0",
72
- "jasmine-core": "^3.5.0",
73
- "jodit": "^3.3.24",
74
- "jquery": "^3.5.0",
75
- "karma": "^5.0.4",
72
+ "jasmine": "^3.7.0",
73
+ "jasmine-core": "^3.7.1",
74
+ "jodit": "~3.3.24",
75
+ "jquery": "^3.6.0",
76
+ "karma": "^5.2.3",
76
77
  "karma-chrome-launcher": "^3.1.0",
77
78
  "karma-jasmine": "^2.0.1",
78
- "karma-jasmine-html-reporter": "^1.5.3",
79
- "karma-sourcemap-loader": "^0.3.7",
79
+ "karma-jasmine-html-reporter": "^1.6.0",
80
+ "karma-sourcemap-loader": "^0.3.8",
80
81
  "karma-webpack": "^4.0.2",
81
- "mathjs": "^6.6.4",
82
+ "mathjs": "^7.5.1",
82
83
  "mini-css-extract-plugin": "^0.8.2",
83
84
  "mocha": "^6.2.2",
84
85
  "mochawesome": "^4.1.0",
85
- "postcss-loader": "^3.0.0",
86
+ "postcss-loader": "^5.2.0",
86
87
  "puppeteer": "^1.20.0",
87
88
  "remove-strict-webpack-plugin": "^0.1.2",
88
89
  "sceditor": "^2.1.3",
89
90
  "sinon": "^8.1.1",
90
- "standard": "^14.3.3",
91
- "style-loader": "^1.2.1",
92
- "webpack": "^4.43.0",
93
- "webpack-cli": "^3.3.11",
94
- "webpack-dev-server": "^3.11.0",
91
+ "standard": "^14.3.4",
92
+ "style-loader": "^1.3.0",
93
+ "webpack": "^4.46.0",
94
+ "webpack-cli": "^3.3.12",
95
+ "webpack-dev-server": "^3.11.2",
95
96
  "webpack-merge": "^4.2.2"
96
97
  },
97
98
  "dependencies": {
98
- "core-js": "^3.6.5"
99
+ "core-js": "^3.12.1"
99
100
  }
100
101
  }
package/release-notes.md CHANGED
@@ -79,10 +79,10 @@ For now I have passed in `JSONEditor.defaults` as `defaults`.
79
79
 
80
80
  ### NPM Release
81
81
 
82
- 1. Switch to `release` branch and `merge master into release`
83
- 2. Update `CHANGELOG.md`
82
+ 1. Update `CHANGELOG.md`
83
+ 2. Switch to `release` branch and `merge master into release`
84
84
  3. NPM login: `npm login`
85
- 4. Build new version: `npm version x.x.x`
85
+ 4. Build new version: `npm version 2.x.x`
86
86
 
87
87
  The `npm version` command will automatically build the source files & test the new generated script files.
88
88
  On success the `postversion` script will push the source to GitHub and publish the version on NPM.
package/src/editor.js CHANGED
@@ -206,7 +206,11 @@ export class AbstractEditor {
206
206
  })
207
207
 
208
208
  /* append active/deactive checkbox if show_opt_in is true */
209
- if (this.jsoneditor.options.show_opt_in || this.options.show_opt_in) {
209
+ const globalOptIn = this.jsoneditor.options.show_opt_in
210
+ const parentOptInDefined = (typeof this.parent.options.show_opt_in !== 'undefined')
211
+ const parentOptInEnabled = (parentOptInDefined && this.parent.options.show_opt_in === true)
212
+ const parentOptInDisabled = (parentOptInDefined && this.parent.options.show_opt_in === false)
213
+ if (parentOptInEnabled || (!parentOptInDisabled && globalOptIn) || (!parentOptInDefined && globalOptIn)) {
210
214
  /* and control to type object editors if they are not required */
211
215
  if (this.parent && this.parent.schema.type === 'object' && !this.isRequired() && this.header) {
212
216
  this.header.appendChild(this.optInCheckbox)
@@ -267,6 +267,8 @@ export class MultipleEditor extends AbstractEditor {
267
267
  if (fitTestResult !== null) {
268
268
  validVal.match = fitTestResult.match
269
269
  }
270
+ } else {
271
+ fitTestVal = validVal
270
272
  }
271
273
  })
272
274
  let finalI = validVal.i
@@ -793,7 +793,11 @@ export class ObjectEditor extends AbstractEditor {
793
793
 
794
794
  deactivateNonRequiredProperties () {
795
795
  /* the show_opt_in editor option is for backward compatibility */
796
- if (this.jsoneditor.options.show_opt_in || this.options.show_opt_in) {
796
+ const globalOptIn = this.jsoneditor.options.show_opt_in
797
+ const editorOptInDefined = (typeof this.options.show_opt_in !== 'undefined')
798
+ const editorOptInEnabled = (editorOptInDefined && this.options.show_opt_in === true)
799
+ const editorOptInDisabled = (editorOptInDefined && this.options.show_opt_in === false)
800
+ if (editorOptInEnabled || (!editorOptInDisabled && globalOptIn) || (!editorOptInDefined && globalOptIn)) {
797
801
  Object.entries(this.editors).forEach(([key, editor]) => {
798
802
  if (!this.isRequiredObject(editor)) {
799
803
  this.editors[key].deactivate()
@@ -993,7 +997,8 @@ export class ObjectEditor extends AbstractEditor {
993
997
  this.editors[name].register()
994
998
  /* New property */
995
999
  } else {
996
- if (!this.canHaveAdditionalProperties() && (!this.schema.properties || !this.schema.properties[name])) {
1000
+ if (!this.canHaveAdditionalProperties() && (!this.schema.properties || !this.schema.properties[name]) &&
1001
+ (!this.schema.patternProperties || !(Object.keys(this.schema.patternProperties).find(i => new RegExp(i).test(name))))) {
997
1002
  return
998
1003
  }
999
1004
 
@@ -2,7 +2,6 @@ import { SelectEditor } from './select.js'
2
2
 
3
3
  export class RadioEditor extends SelectEditor {
4
4
  preBuild () {
5
- this.schema.required = true /* force editor into required mode to prevent creation of empty radio button */
6
5
  super.preBuild()
7
6
  }
8
7
 
@@ -22,6 +21,12 @@ export class RadioEditor extends SelectEditor {
22
21
  this.onChange(true)
23
22
  }
24
23
 
24
+ if (!this.isRequired()) {
25
+ this.enum_display.shift()
26
+ this.enum_options.shift()
27
+ this.enum_values.shift()
28
+ }
29
+
25
30
  for (let i = 0; i < this.enum_values.length; i++) {
26
31
  /* form radio elements */
27
32
  this.input = this.theme.getFormRadio({
@@ -6,12 +6,14 @@ export class StringEditor extends AbstractEditor {
6
6
  super.register()
7
7
  if (!this.input) return
8
8
  this.input.setAttribute('name', this.formname)
9
+ this.input.setAttribute('aria-label', this.formname)
9
10
  }
10
11
 
11
12
  unregister () {
12
13
  super.unregister()
13
14
  if (!this.input) return
14
15
  this.input.removeAttribute('name')
16
+ this.input.removeAttribute('aria-label')
15
17
  }
16
18
 
17
19
  setValue (value, initial, fromTemplate) {
@@ -201,7 +203,7 @@ export class StringEditor extends AbstractEditor {
201
203
  input = this.theme.getRangeControl(this.input, this.theme.getRangeOutput(this.input, this.schema.default || Math.max(this.schema.minimum || 0, 0)))
202
204
  }
203
205
 
204
- this.control = this.theme.getFormControl(this.label, input, this.description, this.infoButton)
206
+ this.control = this.theme.getFormControl(this.label, input, this.description, this.infoButton, this.formname)
205
207
  this.container.appendChild(this.control)
206
208
 
207
209
  /* Any special formatting that needs to happen after the input is added to the dom */
@@ -99,6 +99,7 @@ export class TableEditor extends ArrayEditor {
99
99
 
100
100
  /* Row Controls column */
101
101
  this.controls_header_cell = this.theme.getTableHeaderCell(' ')
102
+ this.controls_header_cell.setAttribute('aria-hidden', 'true')
102
103
  this.header_row.appendChild(this.controls_header_cell)
103
104
 
104
105
  /* Add controls */
@@ -136,7 +136,7 @@ export class SchemaLoader {
136
136
 
137
137
  _expandSubSchema (subschema) {
138
138
  /* Array of types */
139
- if (Array.isArray(subschema)) return subschema.map(m => typeof value === 'object' ? this.expandSchema(m) : m)
139
+ if (Array.isArray(subschema)) return subschema.map(m => typeof m === 'object' ? this.expandSchema(m) : m)
140
140
 
141
141
  /* Schema */
142
142
  return this.expandSchema(subschema)
package/src/theme.js CHANGED
@@ -325,10 +325,13 @@ export class AbstractTheme {
325
325
 
326
326
  }
327
327
 
328
- getFormControl (label, input, description, infoText) {
328
+ getFormControl (label, input, description, infoText, formName) {
329
329
  const el = document.createElement('div')
330
330
  el.classList.add('form-control')
331
- if (label) el.appendChild(label)
331
+ if (label) {
332
+ el.appendChild(label)
333
+ if (formName) label.setAttribute('for', formName)
334
+ }
332
335
  if ((input.type === 'checkbox' || input.type === 'radio') && label) {
333
336
  input.style.width = 'auto'
334
337
  label.insertBefore(input, label.firstChild)
@@ -172,14 +172,14 @@ export class bootstrap3Theme extends AbstractTheme {
172
172
  getTabHolder (propertyName) {
173
173
  const pName = (typeof propertyName === 'undefined') ? '' : propertyName
174
174
  const el = document.createElement('div')
175
- el.innerHTML = `<ul class='col-md-2 nav nav-pills nav-stacked' id='${pName}' role='tablist'></ul><div class='col-md-10 tab-content well well-small' id='${pName}'></div>`
175
+ el.innerHTML = `<ul class='col-md-2 nav nav-pills nav-stacked' id='${pName}' role='tablist'></ul><div class='col-md-10 tab-content active well well-small' id='${pName}'></div>`
176
176
  return el
177
177
  }
178
178
 
179
179
  getTopTabHolder (propertyName) {
180
180
  const pName = (typeof propertyName === 'undefined') ? '' : propertyName
181
181
  const el = document.createElement('div')
182
- el.innerHTML = `<ul class='nav nav-tabs' id='${pName}' role='tablist'></ul><div class='tab-content well well-small' id='${pName}'></div>`
182
+ el.innerHTML = `<ul class='nav nav-tabs' id='${pName}' role='tablist'></ul><div class='tab-content active well well-small' id='${pName}'></div>`
183
183
  return el
184
184
  }
185
185
 
@@ -135,6 +135,12 @@ export class bootstrap4Theme extends AbstractTheme {
135
135
  const min = input.getAttribute('min')
136
136
  const max = input.getAttribute('max')
137
137
 
138
+ input.addEventListener('change', () => {
139
+ if (!input.getAttribute('initialized')) {
140
+ input.setAttribute('initialized', '1')
141
+ }
142
+ })
143
+
138
144
  minusBtn.addEventListener('click', () => {
139
145
  if (!input.getAttribute('initialized')) {
140
146
  initialize(input, min)
@@ -405,6 +411,7 @@ export class bootstrap4Theme extends AbstractTheme {
405
411
 
406
412
  const el = document.createElement('h3')
407
413
  el.classList.add('card-title')
414
+ el.classList.add('level-' + pathDepth)
408
415
 
409
416
  if (typeof text === 'string') {
410
417
  el.textContent = text
package/src/validator.js CHANGED
@@ -350,6 +350,7 @@ export class Validator {
350
350
  schema.required.forEach(e => {
351
351
  if (typeof value[e] !== 'undefined') return
352
352
  const editor = this.jsoneditor.getEditor(`${path}.${e}`)
353
+ if (editor && editor.dependenciesFulfilled === false) return
353
354
  /* Ignore required error if editor is of type "button" or "info" */
354
355
  if (editor && ['button', 'info'].includes(editor.schema.format || editor.schema.type)) return
355
356
  errors.push({
@@ -527,20 +528,35 @@ export class Validator {
527
528
  const fit = { match: 0, extra: 0 }
528
529
  if (typeof value === 'object' && value !== null) {
529
530
  /* Work on a copy of the schema */
530
- const properties = this._getSchema(givenSchema).properties
531
-
532
- for (const i in properties) {
533
- if (!hasOwnProperty(properties, i)) {
534
- fit.extra += weight
535
- continue
536
- }
537
- if (typeof value[i] === 'object' && typeof properties[i] === 'object' && typeof properties[i].properties === 'object') {
538
- const result = this.fitTest(value[i], properties[i], weight / 100)
539
- fit.match += result.match
540
- fit.extra += result.extra
531
+ const schema = this._getSchema(givenSchema)
532
+ /* If the schema is an anyOf declaration, do use the properties of the allowed sub schemata instead.
533
+ Of these sub schemata, the best fit is selected */
534
+ if (schema.anyOf) {
535
+ let bestFit = { ...fit }
536
+ for (const subSchema of schema.anyOf) {
537
+ const subFit = this.fitTest(value, subSchema, weight)
538
+ /* The best fit is the one with the best value for match. If there are multiple results
539
+ with the same match value, use the one with the least number of extra properties */
540
+ if ((subFit.match > bestFit.match) || (subFit.match === bestFit.match && subFit.extra < bestFit.extra)) {
541
+ bestFit = subFit
542
+ }
541
543
  }
542
- if (typeof value[i] !== 'undefined') {
543
- fit.match += weight
544
+ return bestFit
545
+ } else {
546
+ const properties = this._getSchema(givenSchema).properties
547
+ for (const i in properties) {
548
+ if (!hasOwnProperty(properties, i)) {
549
+ fit.extra += weight
550
+ continue
551
+ }
552
+ if (typeof value[i] === 'object' && typeof properties[i] === 'object' && typeof properties[i].properties === 'object') {
553
+ const result = this.fitTest(value[i], properties[i], weight / 100)
554
+ fit.match += result.match
555
+ fit.extra += result.extra
556
+ }
557
+ if (typeof value[i] !== 'undefined') {
558
+ fit.match += weight
559
+ }
544
560
  }
545
561
  }
546
562
  }
@@ -12,7 +12,7 @@ Scenario('should work with button editor callbacks', async (I) => {
12
12
  Scenario('should work with option "validated"', async (I) => {
13
13
  I.amOnPage('button-callbacks.html');
14
14
  I.seeElement('[data-schemapath="root.button1"] button');
15
- I.seeDisabledAttribute('[data-schemapath="root.button2"] button');
15
+ I.retry({ retries: 3, minTimeout: 500 }).seeDisabledAttribute('[data-schemapath="root.button2"] button');
16
16
 
17
17
  await I.fillField('[name="root[textinput]"]', 'Hello World');
18
18
 
@@ -68,16 +68,23 @@ Scenario('opt in optional properties @show_opt_in', async (I) => {
68
68
  // if an editor type "object" is disabled, also the child editors opt-in controls will be disabled.
69
69
  I.seeDisabledAttribute('[data-schemapath="root.object.number"] .json-editor-opt-in')
70
70
  I.seeDisabledAttribute('[data-schemapath="root.object.boolean"] .json-editor-opt-in')
71
+ I.seeDisabledAttribute('[data-schemapath="root.object.radio"] .json-editor-opt-in')
71
72
 
72
73
  // tests merged from master 17.9.2019
73
74
  I.dontSeeCheckedAttribute('[data-schemapath="root.string"] .json-editor-opt-in')
74
75
  I.dontSeeDisabledAttribute('[data-schemapath="root.string"] .json-editor-opt-in')
75
76
  I.seeDisabledAttribute('[name="root[string]"]')
77
+ I.dontSeeCheckedAttribute('[data-schemapath="root.radio"] .json-editor-opt-in')
78
+ I.dontSeeDisabledAttribute('[data-schemapath="root.radio"] .json-editor-opt-in')
79
+ I.seeDisabledAttribute('[id="root[radio][0]"]')
80
+ I.seeDisabledAttribute('[id="root[radio][1]"]')
76
81
  I.dontSeeCheckedAttribute('[data-schemapath="root.object.number"] .json-editor-opt-in')
77
82
  I.seeDisabledAttribute('[data-schemapath="root.object.number"] .json-editor-opt-in')
78
83
  I.seeDisabledAttribute('[name="root[object][number]"]')
79
84
  I.dontSeeCheckedAttribute('[data-schemapath="root.object.boolean"] .json-editor-opt-in')
80
85
  I.seeDisabledAttribute('[data-schemapath="root.object.boolean"] .json-editor-opt-in')
86
+ I.dontSeeCheckedAttribute('[data-schemapath="root.object.radio"] .json-editor-opt-in')
87
+ I.seeDisabledAttribute('[data-schemapath="root.object.radio"] .json-editor-opt-in')
81
88
 
82
89
  I.click('.get-value')
83
90
  assert.equal(await I.grabValueFrom('.value'), '{"number":0,"boolean":false}')
@@ -86,16 +93,22 @@ Scenario('opt in optional properties @show_opt_in', async (I) => {
86
93
 
87
94
  I.click('[data-schemapath="root"] .json-editor-btn-edit')
88
95
  I.click('[data-schemapath="root"] .json-editor-btn-edit')
89
-
90
96
  I.dontSeeCheckedAttribute('[data-schemapath="root.string"] .json-editor-opt-in')
91
97
  I.dontSeeDisabledAttribute('[data-schemapath="root.string"] .json-editor-opt-in')
92
98
  I.seeDisabledAttribute('[name="root[string]"]')
99
+ I.dontSeeCheckedAttribute('[data-schemapath="root.radio"] .json-editor-opt-in')
100
+ I.dontSeeDisabledAttribute('[data-schemapath="root.radio"] .json-editor-opt-in')
101
+ I.seeDisabledAttribute('[id="root[radio][0]"]')
102
+ I.seeDisabledAttribute('[id="root[radio][1]"]')
93
103
  I.dontSeeCheckedAttribute('[data-schemapath="root.object.number"] .json-editor-opt-in')
94
104
  I.seeDisabledAttribute('[data-schemapath="root.object.number"] .json-editor-opt-in')
95
105
  I.seeDisabledAttribute('[name="root[object][number]"]')
96
106
  I.dontSeeCheckedAttribute('[data-schemapath="root.object.boolean"] .json-editor-opt-in')
97
107
  I.seeDisabledAttribute('[data-schemapath="root.object.boolean"] .json-editor-opt-in')
98
108
  I.seeDisabledAttribute('[name="root[object][boolean]"]')
109
+ I.seeDisabledAttribute('[data-schemapath="root.object.boolean"] .json-editor-opt-in')
110
+ I.dontSeeCheckedAttribute('[data-schemapath="root.object.radio"] .json-editor-opt-in')
111
+ I.seeDisabledAttribute('[data-schemapath="root.object.radio"] .json-editor-opt-in')
99
112
 
100
113
  I.click('.get-value')
101
114
  assert.equal(await I.grabValueFrom('.value'), '{"number":0,"boolean":false}')
@@ -103,24 +116,26 @@ Scenario('opt in optional properties @show_opt_in', async (I) => {
103
116
  // opt-in string property
104
117
 
105
118
  I.click('[data-schemapath="root.string"] .json-editor-opt-in')
119
+ I.click('[data-schemapath="root.radio"] .json-editor-opt-in')
106
120
  I.click('.get-value')
107
- assert.equal(await I.grabValueFrom('.value'), '{"string":"","number":0,"boolean":false}')
121
+ assert.equal(await I.grabValueFrom('.value'), '{"string":"","number":0,"boolean":false,"radio":"Home"}')
108
122
 
109
123
  // opt-in array property
110
124
 
111
125
  I.click('[data-schemapath="root.array"] .json-editor-opt-in')
112
126
  I.click('.get-value')
113
- assert.equal(await I.grabValueFrom('.value'), '{"string":"","number":0,"boolean":false,"array":[]}')
127
+ assert.equal(await I.grabValueFrom('.value'), '{"string":"","number":0,"boolean":false,"radio":"Home","array":[]}')
114
128
 
115
129
  // opt-in object property
116
130
 
117
131
  I.click('[data-schemapath="root.object"] .json-editor-opt-in')
118
132
  I.click('.get-value')
119
- assert.equal(await I.grabValueFrom('.value'), '{"string":"","number":0,"boolean":false,"array":[],"object":{"string":"","array":[]}}')
133
+ assert.equal(await I.grabValueFrom('.value'), '{"string":"","number":0,"boolean":false,"radio":"Home","array":[],"object":{"string":"","array":[]}}')
120
134
 
121
135
  // if an editor type "object" is enabled, also the child editors opt-in controls will be enabled.
122
136
  I.dontSeeDisabledAttribute('[data-schemapath="root.object.number"] .json-editor-opt-in')
123
137
  I.dontSeeDisabledAttribute('[data-schemapath="root.object.boolean"] .json-editor-opt-in')
138
+ I.dontSeeDisabledAttribute('[data-schemapath="root.object.radio"] .json-editor-opt-in')
124
139
  })
125
140
 
126
141
  Scenario('set value opt in optional properties @show_opt_in', async (I) => {
@@ -130,11 +145,13 @@ Scenario('set value opt in optional properties @show_opt_in', async (I) => {
130
145
  I.waitForElement('[data-schemapath="root.string"]', 5)
131
146
  I.waitForElement('[data-schemapath="root.number"]', 5)
132
147
  I.waitForElement('[data-schemapath="root.boolean"]', 5)
148
+ I.waitForElement('[data-schemapath="root.radio"]', 5)
133
149
  I.waitForElement('[data-schemapath="root.array"]', 5)
134
150
  I.waitForElement('[data-schemapath="root.object"]', 5)
135
151
  I.waitForElement('[data-schemapath="root.object.string"]', 5)
136
152
  I.waitForElement('[data-schemapath="root.object.number"]', 5)
137
153
  I.waitForElement('[data-schemapath="root.object.boolean"]', 5)
154
+ I.waitForElement('[data-schemapath="root.object.radio"]', 5)
138
155
 
139
156
  // set values
140
157
  I.click('.set-value')
@@ -150,11 +167,45 @@ Scenario('set value opt in optional properties @show_opt_in', async (I) => {
150
167
  I.waitForElement('[data-schemapath="root.string"]', 5)
151
168
  I.waitForElement('[data-schemapath="root.number"]', 5)
152
169
  I.waitForElement('[data-schemapath="root.boolean"]', 5)
170
+ I.waitForElement('[data-schemapath="root.radio"]', 5)
153
171
  I.waitForElement('[data-schemapath="root.array"]', 5)
154
172
  I.waitForElement('[data-schemapath="root.object"]', 5)
155
173
  I.waitForElement('[data-schemapath="root.object.string"]', 5)
156
174
  I.waitForElement('[data-schemapath="root.object.number"]', 5)
157
175
  I.waitForElement('[data-schemapath="root.object.boolean"]', 5)
176
+ I.waitForElement('[data-schemapath="root.object.radio"]', 5)
177
+ })
178
+
179
+ Scenario('set value opt in optional properties @show_opt_in_schema', async (I) => {
180
+ I.amOnPage('object-show-opt-in.html')
181
+
182
+ // all editors visible
183
+ I.waitForElement('[data-schemapath="root"]', 5)
184
+ I.waitForElement('[data-schemapath="root.option_show_opt_in_undefined"]', 5)
185
+ I.waitForElement('[data-schemapath="root.option_show_opt_in_undefined.string"]', 5)
186
+ I.waitForElement('[data-schemapath="root.option_show_opt_in_true"]', 5)
187
+ I.waitForElement('[data-schemapath="root.option_show_opt_in_true.string"]', 5)
188
+ I.waitForElement('[data-schemapath="root.option_show_opt_in_false"]', 5)
189
+ I.waitForElement('[data-schemapath="root.option_show_opt_in_false.string"]', 5)
190
+
191
+ // checkboxes for optional properties should appear only when
192
+ // case 1) the parent option show_opt_in is enabled
193
+ // OR
194
+ // case 2) the parent option show_opt_in is disabled and the global option show_opt_in is enabled
195
+ // OR
196
+ // case 3) the parent option show_opt_in is not defined and the global option show_opt_in is enabled
197
+
198
+ // global show_opt_in true
199
+ I.dontSeeCheckedAttribute('#show-opt-in')
200
+ I.dontSeeElement('[data-schemapath="root.option_show_opt_in_undefined.string"] .json-editor-opt-in') // global show_opt_in: false && parent editor show_opt_in: 'undefined'
201
+ I.waitForElement('[data-schemapath="root.option_show_opt_in_true.string"] .json-editor-opt-in', 5) // global show_opt_in: false && parent editor show_opt_in: true
202
+ I.dontSeeElement('[data-schemapath="root.option_show_opt_in_false.string"] .json-editor-opt-in') // global show_opt_in: false && parent editor show_opt_in: false
203
+
204
+ // global show_opt_in false
205
+ I.click('#show-opt-in')
206
+ I.waitForElement('[data-schemapath="root.option_show_opt_in_undefined.string"] .json-editor-opt-in') // global show_opt_in: true && parent editor show_opt_in: 'undefined'
207
+ I.waitForElement('[data-schemapath="root.option_show_opt_in_true.string"] .json-editor-opt-in', 5) // global show_opt_in: true && parent editor show_opt_in: true
208
+ I.dontSeeElement('[data-schemapath="root.option_show_opt_in_false.string"] .json-editor-opt-in') // global show_opt_in: true && parent editor show_opt_in: false
158
209
  })
159
210
 
160
211
  Scenario('objects should contain properties defined with the properties keyword unless the property "additionalProperties: true" is specified in the object schema @additional-properties', async (I) => {
@@ -25,3 +25,15 @@ Scenario('should be constrained to maximun and minimun values when stepped @step
25
25
  I.click('.get-value')
26
26
  assert.equal(await I.grabValueFrom('.value'), '{"stepper":5}')
27
27
  })
28
+
29
+ Scenario('should be correct initialized when manually set @stepper', async (I) => {
30
+ I.amOnPage('stepper-manual.html')
31
+ I.fillField('[name="root[stepper]"]', 10)
32
+ I.click('.stepper-up')
33
+ I.click('.get-value')
34
+ assert.equal(await I.grabValueFrom('.value'), '{"stepper":11}')
35
+ I.click('.stepper-down')
36
+ I.click('.stepper-down')
37
+ I.click('.get-value')
38
+ assert.equal(await I.grabValueFrom('.value'), '{"stepper":9}')
39
+ })
@@ -6,7 +6,7 @@ Feature('Validations')
6
6
 
7
7
  Scenario('test validations in validation.html', (I) => {
8
8
  I.amOnPage('validation.html')
9
- var numberOfTestItemsExpected = 152
9
+ var numberOfTestItemsExpected = 158
10
10
  I.waitForElement('#output div:nth-child(' + numberOfTestItemsExpected + ')', 10)
11
11
  I.seeNumberOfElements('#output div', numberOfTestItemsExpected)
12
12
  I.see('success')