Repository: bokeh/bokeh

Issue:
Finalize typing plotting API and remove old declarations
PR #8085 allowed for removal of old type declarations, however I kept them because they still have valid type information (though incomplete and a bit outdated) regarding plotting API. When this API is fully typed (this may rely on issue #8615 and possibly other work), then old declarations can be finally removed. Just to note, currently we automatically generate declarations from *.ts files.



Discussion:

Resolving patch:
diff --git a/sphinx/source/docs/user_guide/examples/extensions_putting_together_ts.py b/sphinx/source/docs/user_guide/examples/extensions_putting_together_ts.py
--- a/sphinx/source/docs/user_guide/examples/extensions_putting_together_ts.py
+++ b/sphinx/source/docs/user_guide/examples/extensions_putting_together_ts.py
@@ -43,12 +43,9 @@
 }
 
 export namespace Custom {
-  export interface Attrs extends HTMLBox.Attrs {
-    text: string
-    slider: Slider
-  }
+  export type Attrs = p.AttrsOf<Props>
 
-  export interface Props extends HTMLBox.Props {
+  export type Props = HTMLBox.Props & {
     text: p.Property<string>
     slider: p.Property<Slider>
   }
@@ -76,7 +73,7 @@
     // types have counterparts, e.g. bokeh.core.properties.String will be
     // ``p.String`` in the JS implementation. Any time the JS type system is not
     // yet as complete, you can use ``p.Any`` as a "wildcard" property type.
-    this.define({
+    this.define<Custom.Props>({
       text:   [ p.String ],
       slider: [ p.Any    ],
     })


Test patch:
diff --git a/bokehjs/make/tasks/test.ts b/bokehjs/make/tasks/test.ts
--- a/bokehjs/make/tasks/test.ts
+++ b/bokehjs/make/tasks/test.ts
@@ -31,7 +31,7 @@ function mocha(files: string[]): Promise<void> {
     args = ["node_modules/.bin/istanbul", "cover", _mocha, "--"]
 
   if (argv.debug)
-    args.unshift("debug")
+    args.unshift("--inspect-brk")
 
   if (argv.k)
     args.push("--grep", argv.k)
diff --git a/bokehjs/src/lib/models/graphs/graph_hit_test_policy.ts b/bokehjs/src/lib/models/graphs/graph_hit_test_policy.ts
--- a/bokehjs/src/lib/models/graphs/graph_hit_test_policy.ts
+++ b/bokehjs/src/lib/models/graphs/graph_hit_test_policy.ts
@@ -3,20 +3,20 @@ import {indexOf} from "core/util/arrayable"
 import {contains, uniq} from "core/util/array"
 import {create_empty_hit_test_result, HitTestResult} from "core/hittest"
 import {Geometry} from "core/geometry"
+import * as p from "core/properties"
 import {Selection} from "../selections/selection"
 import {GraphRenderer, GraphRendererView} from "../renderers/graph_renderer"
 import {ColumnarDataSource} from "../sources/columnar_data_source"
 
 export namespace GraphHitTestPolicy {
-  export interface Attrs extends Model.Attrs {}
+  export type Attrs = p.AttrsOf<Props>
 
-  export interface Props extends Model.Props {}
+  export type Props = Model.Props
 }
 
 export interface GraphHitTestPolicy extends Model.Attrs {}
 
 export abstract class GraphHitTestPolicy extends Model {
-
   properties: GraphHitTestPolicy.Props
 
   constructor(attrs?: Partial<GraphHitTestPolicy.Attrs>) {
@@ -59,15 +59,14 @@ export abstract class GraphHitTestPolicy extends Model {
 }
 
 export namespace NodesOnly {
-  export interface Attrs extends GraphHitTestPolicy.Attrs {}
+  export type Attrs = p.AttrsOf<Props>
 
-  export interface Props extends GraphHitTestPolicy.Props {}
+  export type Props = GraphHitTestPolicy.Props
 }
 
 export interface NodesOnly extends NodesOnly.Attrs {}
 
 export class NodesOnly extends GraphHitTestPolicy {
-
   properties: NodesOnly.Props
 
   constructor(attrs?: Partial<NodesOnly.Attrs>) {
@@ -110,15 +109,14 @@ export class NodesOnly extends GraphHitTestPolicy {
 NodesOnly.initClass()
 
 export namespace NodesAndLinkedEdges {
-  export interface Attrs extends GraphHitTestPolicy.Attrs {}
+  export type Attrs = p.AttrsOf<Props>
 
-  export interface Props extends GraphHitTestPolicy.Props {}
+  export type Props = GraphHitTestPolicy.Props
 }
 
 export interface NodesAndLinkedEdges extends NodesAndLinkedEdges.Attrs {}
 
 export class NodesAndLinkedEdges extends GraphHitTestPolicy {
-
   properties: NodesAndLinkedEdges.Props
 
   constructor(attrs?: Partial<NodesAndLinkedEdges.Attrs>) {
@@ -193,15 +191,14 @@ export class NodesAndLinkedEdges extends GraphHitTestPolicy {
 NodesAndLinkedEdges.initClass()
 
 export namespace EdgesAndLinkedNodes {
-  export interface Attrs extends GraphHitTestPolicy.Attrs {}
+  export type Attrs = p.AttrsOf<Props>
 
-  export interface Props extends GraphHitTestPolicy.Props {}
+  export type Props = GraphHitTestPolicy.Props
 }
 
 export interface EdgesAndLinkedNodes extends EdgesAndLinkedNodes.Attrs {}
 
 export class EdgesAndLinkedNodes extends GraphHitTestPolicy {
-
   properties: EdgesAndLinkedNodes.Props
 
   constructor(attrs?: Partial<EdgesAndLinkedNodes.Attrs>) {
diff --git a/bokehjs/test/core/has_props.ts b/bokehjs/test/core/has_props.ts
--- a/bokehjs/test/core/has_props.ts
+++ b/bokehjs/test/core/has_props.ts
@@ -15,16 +15,16 @@ class SubclassWithProps extends HasProps {
   bar: boolean
 }
 SubclassWithProps.prototype.type = "SubclassWithProps"
-SubclassWithProps.define({
-  foo: [ p.Number, 0    ],
-  bar: [ p.Bool,   true ],
+SubclassWithProps.define<any>({
+  foo: [ p.Number,  0    ],
+  bar: [ p.Boolean, true ],
 })
 
 class SubSubclassWithProps extends SubclassWithProps {
   baz: string
 }
 SubSubclassWithProps.prototype.type = "SubSubclassWithProps"
-SubSubclassWithProps.define({
+SubSubclassWithProps.define<any>({
   baz: [ p.String, '' ],
 })
 
@@ -45,9 +45,9 @@ class SubclassWithNumberSpec extends HasProps {
   bar: boolean
 }
 SubclassWithNumberSpec.prototype.type = "SubclassWithNumberSpec"
-SubclassWithNumberSpec.define({
+SubclassWithNumberSpec.define<any>({
   foo: [ p.NumberSpec, {field: 'colname'} ],
-  bar: [ p.Bool,       true               ],
+  bar: [ p.Boolean,    true               ],
 })
 
 class SubclassWithDistanceSpec extends HasProps {
@@ -55,9 +55,9 @@ class SubclassWithDistanceSpec extends HasProps {
   bar: boolean
 }
 SubclassWithDistanceSpec.prototype.type = "SubclassWithDistanceSpec"
-SubclassWithDistanceSpec.define({
+SubclassWithDistanceSpec.define<any>({
   foo: [ p.DistanceSpec, {field: 'colname'} ],
-  bar: [ p.Bool,         true               ],
+  bar: [ p.Boolean,      true               ],
 })
 
 class SubclassWithTransformSpec extends HasProps {
@@ -65,9 +65,9 @@ class SubclassWithTransformSpec extends HasProps {
   bar: boolean
 }
 SubclassWithTransformSpec.prototype.type = "SubclassWithTransformSpec"
-SubclassWithTransformSpec.define({
+SubclassWithTransformSpec.define<any>({
   foo: [ p.NumberSpec, {field: 'colname', transform: new TestModel()} ],
-  bar: [ p.Bool,       true               ],
+  bar: [ p.Boolean,    true               ],
 })
 
 class SubclassWithOptionalSpec extends HasProps {
@@ -76,9 +76,9 @@ class SubclassWithOptionalSpec extends HasProps {
   baz: any // XXX
 }
 SubclassWithOptionalSpec.prototype.type = "SubclassWithOptionalSpec"
-SubclassWithOptionalSpec.define({
+SubclassWithOptionalSpec.define<any>({
   foo: [ p.NumberSpec, {value: null}      ],
-  bar: [ p.Bool,       true               ],
+  bar: [ p.Boolean,    true               ],
   baz: [ p.NumberSpec, {field: 'colname'} ],
 })
 
diff --git a/bokehjs/test/core/properties.ts b/bokehjs/test/core/properties.ts
--- a/bokehjs/test/core/properties.ts
+++ b/bokehjs/test/core/properties.ts
@@ -9,6 +9,8 @@ import {svg_colors} from  "core/util/svg_colors"
 import {Transform} from  "models/transforms/transform"
 import {Expression} from  "models/expressions/expression"
 
+class MyProperty extends p.Property<unknown> {}
+
 class TestTransform extends Transform {
   compute(x: number): number {
     return x+1
@@ -34,7 +36,7 @@ class SomeHasProps extends HasProps {
   a: any
   b: any
 }
-SomeHasProps.define({
+SomeHasProps.define<any>({
   a: [ p.Any ],
   b: [ p.Any ],
 })
@@ -44,14 +46,13 @@ class SomeSpecHasProps extends HasProps {
   a: any
   b: any
 }
-SomeSpecHasProps.define({
+SomeSpecHasProps.define<any>({
   a: [ p.NumberSpec ],
   b: [ p.Any ],
 })
-SomeSpecHasProps.prototype.type =  'SomeSpecHasProps'
+SomeSpecHasProps.prototype.type = 'SomeSpecHasProps'
 
-class DataSpecProperty extends p.Number {}
-DataSpecProperty.prototype.dataspec = true
+class DataSpecProperty extends p.DataSpec<number> {}
 
 describe("properties module", () => {
 
@@ -59,7 +60,7 @@ describe("properties module", () => {
     function fn(): void {
       prop.validate(x)
     }
-    expect(fn).to.throw(Error, /property '.*' given invalid value/)
+    expect(fn).to.throw(Error, /given invalid value/)
   }
 
   function enum_validation_errors(prop: any): void {
@@ -83,36 +84,6 @@ describe("properties module", () => {
   const spec_value_trans = {a: {value: 2, transform: new TestTransform()}}
   const spec_value_null  = {a: {value: null}}
 
-  const DATASPECS = [ "AngleSpec", "ColorSpec", "DistanceSpec", "FontSizeSpec", "NumberSpec", "StringSpec" ]
-
-  const PROPERTIES = [
-    "Any",
-    "Anchor",
-    "Angle",
-    "AngleUnits",
-    "Array",
-    "Bool",
-    "Color",
-    "Dimension",
-    "Direction",
-    "Font",
-    "FontStyle",
-    "Instance",
-    "LegendLocation",
-    "FontSize",
-    "FontStyle",
-    "LineCap",
-    "LineJoin",
-    "Location",
-    "Orientation",
-    "Number",
-    "RenderLevel",
-    "RenderMode",
-    "SpatialUnits",
-    "String",
-    "TextAlign",
-    "TextBaseline",
-  ]
   describe("isSpec", () => {
 
     it("should identify field specs", () => {
@@ -142,7 +113,6 @@ describe("properties module", () => {
       expect(p.isSpec({field: "foo", value:"bar"})).to.be.false
       expect(p.isSpec({field: "foo", value:"bar", expr: "baz"})).to.be.false
     })
-
   })
 
   describe("Property", () => {
@@ -151,95 +121,81 @@ describe("properties module", () => {
 
       it("should set undefined property attr value to null if no default is given", () => {
         const obj = new SomeHasProps({a: {}})
-        new p.Property(obj, 'b')
+        new MyProperty(obj, 'b')
         expect(obj.b).to.be.null
       })
 
       // it("should set undefined property attr value if a default is given", () => {
       //   const obj = new SomeHasProps({a: {}})
-      //   new p.Property(obj, 'b', function(): number { return 10 } )
+      //   new MyProperty(obj, 'b', function(): number { return 10 } )
       //   expect(obj.b).to.be.equal(10)
       // })
 
       // it("should throw an Error for missing specifications", () => {
       //   function fn(): void {
-      //     new p.Property(new SomeHasProps({a: {}}), 'a')
+      //     new MyProperty(new SomeHasProps({a: {}}), 'a')
       //   }
       //   expect(fn).to.throw(Error, /^Invalid property specifier .*, must have exactly one of/)
       // })
 
       // it("should throw an Error for too many specifications", () => {
       //   function fn(): void {
-      //     new p.Property(new SomeHasProps({a: {field: "foo", value:"bar"}}), 'a')
+      //     new MyProperty(new SomeHasProps({a: {field: "foo", value:"bar"}}), 'a')
       //   }
       //   expect(fn).to.throw(Error, /^Invalid property specifier .*, must have exactly one of/)
       // })
 
+      /*
       it("should throw an Error if a field spec is not a string", () => {
         function fn(): void {
-          new p.Property(new SomeSpecHasProps({a: {field: 10}}), 'a')
+          new MyProperty(new SomeSpecHasProps({a: {field: 10}}), 'a')
         }
         expect(fn).to.throw(Error, /^field value for property '.*' is not a string$/)
       })
+      */
 
       it("should set a spec for object attr values", () => {
-        const p1 = new p.Property(new SomeHasProps({a: {field: "foo"}}), 'a')
+        const p1 = new MyProperty(new SomeHasProps({a: {field: "foo"}}), 'a')
         expect(p1.spec).to.be.deep.equal({field: "foo"})
-        const p2 = new p.Property(new SomeHasProps({a: {value: "foo"}}), 'a')
+        const p2 = new MyProperty(new SomeHasProps({a: {value: "foo"}}), 'a')
         expect(p2.spec).to.be.deep.equal({value: "foo"})
       })
 
       it("should set a value spec for non-object attr values", () => {
-        const prop = new p.Property(new SomeHasProps({a: 10}), 'a')
+        const prop = new MyProperty(new SomeHasProps({a: 10}), 'a')
         expect(prop.spec).to.be.deep.equal({value: 10})
       })
-
     })
 
     describe("value", () => {
       it("should return a value if there is a value spec", () => {
-        const p1 = new p.Property(new SomeHasProps(fixed), 'a')
+        const p1 = new MyProperty(new SomeHasProps(fixed), 'a')
         expect(p1.value()).to.be.equal(1)
-        const p2 = new p.Property(new SomeHasProps(spec_value), 'a')
+        const p2 = new MyProperty(new SomeHasProps(spec_value), 'a')
         expect(p2.value()).to.be.equal(2)
       })
 
       it("should return a transformed value if there is a value spec with transform", () => {
-        const prop = new p.Property(new SomeHasProps(spec_value_trans), 'a')
+        const prop = new MyProperty(new SomeHasProps(spec_value_trans), 'a')
         expect(prop.value()).to.be.equal(3)
       })
 
       it("should allow a fixed null value", () => {
-        const prop = new p.Property(new SomeHasProps(spec_value_null), 'a')
+        const prop = new MyProperty(new SomeHasProps(spec_value_null), 'a')
         expect(prop.value()).to.be.null
       })
 
       it("should throw an Error otherwise", () => {
        function fn(): void {
-          const prop = new p.Property(new SomeHasProps(spec_field_only), 'a')
+          const prop = new MyProperty(new SomeHasProps(spec_field_only), 'a')
           prop.value()
        }
         expect(fn).to.throw(Error, "attempted to retrieve property value for property without value specification")
       })
-
     })
 
     describe("array", () => {
 
-      it("should throw an Error for non data-specs", () => {
-        function fn(): void {
-          const source = new ColumnDataSource({data: {foo: [0,1,2,3,10]}})
-          const prop = new p.Property(new SomeHasProps(spec_field), 'a')
-          prop.array(source)
-        }
-        expect(fn).to.throw(Error, /attempted to retrieve property array for non-dataspec property/)
-      })
-
-      // XXX TODO
-      it("should return a computed array if there is an expr spec", () => {
-
-      })
-
       it("should return an array if there is a value spec", () => {
         const source = new ColumnDataSource({data: {foo: [0,1,2,3,10]}})
         const p1 = new DataSpecProperty(new SomeSpecHasProps(fixed), 'a')
@@ -339,7 +295,7 @@ describe("properties module", () => {
 
     describe("init", () => {
       it("should return nothing by default", () => {
-        const prop = new p.Property(new SomeHasProps({a: {value: "foo"}}), 'a')
+        const prop = new MyProperty(new SomeHasProps({a: {value: "foo"}}), 'a')
         expect(prop.init()).to.be.undefined
       })
     })
@@ -361,7 +317,7 @@ describe("properties module", () => {
 
     describe("validate", () => {
       it("should return nothing by default", () => {
-        const prop = new p.Property(new SomeHasProps({a: {value: "foo"}}), 'a')
+        const prop = new MyProperty(new SomeHasProps({a: {value: "foo"}}), 'a')
         expect(prop.validate(undefined)).to.be.undefined
         expect(prop.validate(10)).to.be.undefined
         expect(prop.validate("foo")).to.be.undefined
@@ -386,9 +342,7 @@ describe("properties module", () => {
         obj.a = {value: "bar"}
         expect(prop.spec).to.be.deep.equal({value: "bar"})
       })
-
     })
-
   })
 
   describe("Anchor", () => {
@@ -414,7 +368,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("Any", () => {
@@ -436,23 +389,16 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("Angle", () => {
 
-    it("should be an instance of Number", () => {
-      const prop = new p.Angle(new SomeHasProps({a: {value: 10}}), 'a')
-      expect(prop).to.be.instanceof(p.Number)
-    })
-
     describe("transform", () => {
       it("should be Property.transform", () => {
         const prop = new p.Angle(new SomeHasProps({a: {value: 10}}), 'a')
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("AngleSpec", () => {
@@ -499,11 +445,10 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("Bool", () => {
-    const prop = new p.Bool(new SomeHasProps({a: {value: true}}), 'a')
+    const prop = new p.Boolean(new SomeHasProps({a: {value: true}}), 'a')
 
     it("should be an instance of Property", () => {
       expect(prop).to.be.instanceof(p.Property)
@@ -532,7 +477,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("Color", () => {
@@ -602,7 +546,6 @@ describe("properties module", () => {
         validation_error(prop, undefined)
       })
     })
-
   })
 
   describe("Dimension", () => {
@@ -628,7 +571,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("Direction", () => {
@@ -665,16 +607,10 @@ describe("properties module", () => {
         expect(result).to.be.deep.equal(new Uint8Array([0, 1]))
       })
     })
-
   })
 
   describe("DistanceSpec", () => {
 
-    it("should be an instance of Number", () => {
-      const prop = new p.DistanceSpec(new SomeHasProps({a: {value: 10}}), 'a')
-      expect(prop).to.be.instanceof(p.Number)
-    })
-
     describe("units", () => {
       it("should default to data units", () => {
         const prop = new p.DistanceSpec(new SomeHasProps({a: {value: 10}}), 'a')
@@ -693,9 +629,10 @@ describe("properties module", () => {
 
       it("should throw an Error on bad units", () => {
         function fn(): void {
-          new p.DistanceSpec(new SomeHasProps({a: {value: 10, units:"bad"}}), 'a')
+          const x = new SomeHasProps({a: {value: 10, units:"bad"}})
+          new p.DistanceSpec(x, 'a')
         }
-        expect(fn).to.throw(Error, "DistanceSpec units must be one of screen,data, given invalid value: bad")
+        expect(fn).to.throw(Error, "units must be one of screen, data; got: bad")
       })
     })
 
@@ -705,7 +642,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("Font", () => {
@@ -737,7 +673,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("FontStyle", () => {
@@ -763,7 +698,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("Instance", () => {
@@ -778,7 +712,7 @@ describe("properties module", () => {
         expect(prop.validate(new SomeHasProps({}))).to.be.undefined
       })
 
-      it("should throw an Error on other input", () => {
+      it.skip("should throw an Error on other input", () => {
         validation_error(prop, true)
         validation_error(prop, 10)
         validation_error(prop, 10.2)
@@ -793,7 +727,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("LegendLocation", () => {
@@ -819,7 +752,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("LineCap", () => {
@@ -845,7 +777,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("LineJoin", () => {
@@ -871,7 +802,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("Number", () => {
@@ -903,7 +833,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("Orientation", () => {
@@ -929,7 +858,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("RenderLevel", () => {
@@ -955,7 +883,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("RenderMode", () => {
@@ -981,7 +908,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("String", () => {
@@ -1014,7 +940,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("TextAlign", () => {
@@ -1040,7 +965,6 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
 
   describe("TextBaseline", () => {
@@ -1055,6 +979,7 @@ describe("properties module", () => {
         for (const x of enums.TextBaseline)
           expect(prop.validate(x)).to.be.undefined
       })
+
       it("should throw an Error on other input", () => {
         enum_validation_errors(prop)
       })
@@ -1065,49 +990,5 @@ describe("properties module", () => {
         expect(prop.transform).to.be.equal(p.Property.prototype.transform)
       })
     })
-
   })
-
-  describe("dataspec prototype property", () => {
-
-    for (const ds of DATASPECS) {
-      it(`DataSpec ${ds} should have dataspec attribute set true`, () => {
-        expect(((p as any)[ds] as any).prototype.dataspec).to.be.true
-      })
-    }
-
-    for (const prop of PROPERTIES) {
-      it(`Property ${prop} should have dataspec attribute set false`, () => {
-        expect(((p as any)[prop] as any).prototype.dataspec).to.be.false
-      })
-    }
-
-  })
-
-  describe("exports", () => {
-
-    for (const func of ["simple_prop", "enum_prop", "units_prop"]) {
-      it(`should have '${func}' property helper function`, () => {
-        expect(func in p).to.be.true
-      })
-    }
-
-    it("should have the Property base class", () => {
-      expect("Property" in p).to.be.true
-    })
-
-    for (const prop of PROPERTIES) {
-      it(`should have simple property ${prop}`, () => {
-        expect(prop in p).to.be.true
-      })
-    }
-
-    for (const ds of DATASPECS) {
-      it(`should have dataspec property ${ds}`, () => {
-        expect(ds in p).to.be.true
-      })
-    }
-
-  })
-
 })
diff --git a/bokehjs/test/document/events.ts b/bokehjs/test/document/events.ts
--- a/bokehjs/test/document/events.ts
+++ b/bokehjs/test/document/events.ts
@@ -28,7 +28,7 @@ class TestModelWithRefs extends HasProps {
   static initClass(): void {
     this.prototype.type = 'TestModelWithRefs'
 
-    this.define({
+    this.define<any>({
       foo: [ p.Any, [] ],
     })
   }
diff --git a/bokehjs/test/index.coffee b/bokehjs/test/index.coffee
--- a/bokehjs/test/index.coffee
+++ b/bokehjs/test/index.coffee
@@ -1,3 +1,5 @@
+require("source-map-support").install()
+
 # XXX: Patch jsdom/utils before importing main jsdom. Otherwise
 #      HTMLCanvasElement will detect no canvas and make tests
 #      fail with "unable to obtain 2D rendering context".
diff --git a/bokehjs/test/model.ts b/bokehjs/test/model.ts
--- a/bokehjs/test/model.ts
+++ b/bokehjs/test/model.ts
@@ -14,7 +14,7 @@ class SomeModel extends Model {
   static initClass(): void {
     this.prototype.type = 'SomeModel'
 
-    this.define({
+    this.define<any>({
       foo: [ p.Number, 2 ],
       bar: [ p.String    ],
       baz: [ p.Number, 1 ],
diff --git a/bokehjs/test/tsconfig.json b/bokehjs/test/tsconfig.json
--- a/bokehjs/test/tsconfig.json
+++ b/bokehjs/test/tsconfig.json
@@ -17,7 +17,7 @@
     "target": "ES6",
     "lib": ["es6", "dom"],
     "declaration": false,
-    "sourceMap": false,
+    "sourceMap": true,
     "importHelpers": false,
     "experimentalDecorators": true,
     "baseUrl": ".",
diff --git a/tests/baselines/bokehjs/examples/hierarchical/hierarchical b/tests/baselines/bokehjs/examples/hierarchical/hierarchical
new file mode 100644
--- /dev/null
+++ b/tests/baselines/bokehjs/examples/hierarchical/hierarchical
@@ -0,0 +1,4 @@
+Plot bbox=[0, 0, 600, 250]
+  CategoricalAxis bbox=[18, 195, 577, 55]
+  LinearAxis bbox=[0, 29, 18, 166]
+  Title bbox=[18, 0, 577, 29]