Skip to content

Commit c07fa0c

Browse files
committed
refactor(geojs): use Vue's provide/inject API in the geojs layer mixin
This provides more flexibility in using the components compared to accessing the `$parent` component directly. This is particularly relevant because newer versions of `@vue/test-utils` broke how we were injecting the parent components in unit testing. Note: This also updates `@vue/test-utils`, but not to the latest version because there is a bug since `beta-18` causing props not to be updated. This may (or may not) be related to the following issue: vuejs/vue-test-utils#738
1 parent 948f6c3 commit c07fa0c

12 files changed

+3060
-3035
lines changed

package-lock.json

+2,955-2,955
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"devDependencies": {
2828
"@commitlint/cli": "^6.2.0",
2929
"@commitlint/config-conventional": "^6.1.3",
30-
"@vue/test-utils": "^1.0.0-beta.16",
30+
"@vue/test-utils": "1.0.0-beta.17",
3131
"autoprefixer": "^8.5.0",
3232
"axios-mock-adapter": "^1.15.0",
3333
"babel-core": "^6.26.3",

src/components/geojs/GeojsMapViewport.vue

+9
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ export default {
3535
ready: false,
3636
};
3737
},
38+
provide() {
39+
const provided = {
40+
$geojs: geo,
41+
};
42+
Object.defineProperty(provided, '$geojsMap', {
43+
get: () => this.$geojsMap,
44+
});
45+
return provided;
46+
},
3847
mounted() {
3948
this.$geojsViewport = true;
4049
this.$geojs = geo;

src/mixins/geojsLayer.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import bindWatchers from '../bindWatchers';
22

33
const layerMixin = {
4+
inject: ['$geojs', '$geojsMap'],
45
props: {
56
zIndex: {
67
type: Number,
@@ -24,16 +25,9 @@ const layerMixin = {
2425
this.$unwatch = new Map();
2526
},
2627
mounted() {
27-
// This is in place purely for testing because there is no way
28-
// in @vue/test-utils to put mocks in place *before* mount is called.
29-
// https://github.com/vuejs/vue-test-utils/issues/560
30-
this.$parent = this.$parent || this.$options.testParent;
31-
32-
if (!this.$parent || this.$parent.$geojsViewport !== true) {
28+
if (!this.$geojs) {
3329
throw new Error('A layer must be a child of a GeojsMapViewport');
3430
}
35-
this.$geojsMap = this.$parent.$geojsMap;
36-
this.$geojs = this.$parent.$geojs;
3731
},
3832
methods: {
3933
createLayer(type, options) {

test/ProvideGeojs.js

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import geo from 'geojs';
2+
import { mount } from '@vue/test-utils';
3+
4+
class ProvideGeojs {
5+
start() {
6+
this.element = document.createElement('div');
7+
this.element.style.width = '300px';
8+
this.element.style.height = '200px';
9+
document.body.appendChild(this.element);
10+
this.geojsMap = geo.map({ node: this.element });
11+
}
12+
13+
stop() {
14+
this.geojsMap.exit();
15+
this.element.remove();
16+
this.element = null;
17+
}
18+
19+
mountOptions() {
20+
return {
21+
provide: {
22+
$geojs: geo,
23+
$geojsMap: this.geojsMap,
24+
},
25+
};
26+
}
27+
28+
mountLayer(component, options = {}) {
29+
return mount(component, Object.assign(
30+
this.mountOptions(),
31+
options,
32+
));
33+
}
34+
}
35+
36+
export default ProvideGeojs;

test/specs/GeojsAnnotationLayer.spec.js

+11-17
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,21 @@ import geojs from 'geojs';
22
import { mount } from '@vue/test-utils';
33
import last from 'lodash-es/last';
44

5-
import GeojsMapViewport from '@/components/geojs/GeojsMapViewport';
65
import GeojsAnnotationLayer from '@/components/geojs/GeojsAnnotationLayer';
76

7+
import ProvideGeojs from '../ProvideGeojs';
8+
89
describe('GeojsAnnotationLayer.vue', () => {
9-
let mapWrapper;
10+
const provider = new ProvideGeojs();
1011
let interactor;
12+
1113
function mountAnnotationLayer(options = {}) {
12-
const wrapper = mount(GeojsAnnotationLayer, {
13-
testParent: mapWrapper.vm,
14-
...options,
15-
});
16-
return wrapper;
14+
return provider.mountLayer(GeojsAnnotationLayer, options);
1715
}
1816

1917
function interact(event, pt, button) {
2018
interactor.simulateEvent(event, {
21-
map: mapWrapper.vm.$geojsMap.gcsToDisplay(pt),
19+
map: provider.geojsMap.gcsToDisplay(pt),
2220
button,
2321
});
2422
}
@@ -42,13 +40,13 @@ describe('GeojsAnnotationLayer.vue', () => {
4240
beforeEach(() => {
4341
geojs.util.mockVGLRenderer();
4442
sinon.stub(console, 'warn');
45-
mapWrapper = mount(GeojsMapViewport);
46-
interactor = mapWrapper.vm.$geojsMap.interactor();
43+
provider.start();
44+
interactor = provider.geojsMap.interactor();
4745
});
4846

4947
afterEach(() => {
5048
console.warn.restore(); // eslint-disable-line no-console
51-
mapWrapper.destroy();
49+
provider.stop();
5250
geojs.util.restoreVGLRenderer();
5351
});
5452

@@ -87,9 +85,7 @@ describe('GeojsAnnotationLayer.vue', () => {
8785
});
8886

8987
it('draw a point', () => {
90-
const wrapper = mount(GeojsAnnotationLayer, {
91-
testParent: mapWrapper.vm,
92-
});
88+
const wrapper = mount(GeojsAnnotationLayer, provider.mountOptions());
9389
wrapper.setProps({ drawing: 'point' });
9490
expect(wrapper.vm.$geojsLayer.mode()).to.equal('point');
9591

@@ -211,9 +207,7 @@ describe('GeojsAnnotationLayer.vue', () => {
211207
});
212208

213209
it('do not trigger state changes for empty annotations', () => {
214-
const wrapper = mount(GeojsAnnotationLayer, {
215-
testParent: mapWrapper.vm,
216-
});
210+
const wrapper = mount(GeojsAnnotationLayer, provider.mountOptions());
217211
wrapper.setProps({ drawing: 'point' });
218212
expect(wrapper.vm.$geojsLayer.mode()).to.equal('point');
219213
expect(wrapper.vm.state).to.eql([]);

test/specs/GeojsGeojsonLayer.spec.js

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
import geojs from 'geojs';
2-
import { mount } from '@vue/test-utils';
32

4-
import GeojsMapViewport from '@/components/geojs/GeojsMapViewport';
53
import GeojsGeojsonLayer from '@/components/geojs/GeojsGeojsonLayer';
64

5+
import ProvideGeojs from '../ProvideGeojs';
6+
77
describe('GeojsTileLayer.vue', () => {
8-
let mapWrapper;
8+
const provider = new ProvideGeojs();
99
function mountLayer(options = {}) {
10-
return mount(GeojsGeojsonLayer, {
11-
testParent: mapWrapper.vm,
12-
...options,
13-
});
10+
return provider.mountLayer(GeojsGeojsonLayer, options);
1411
}
1512

1613
beforeEach(() => {
1714
geojs.util.mockVGLRenderer();
1815
sinon.stub(console, 'warn');
19-
mapWrapper = mount(GeojsMapViewport);
16+
provider.start();
2017
});
2118
afterEach(() => {
2219
console.warn.restore(); // eslint-disable-line no-console
23-
mapWrapper.destroy();
20+
provider.stop();
2421
geojs.util.restoreVGLRenderer();
2522
});
2623

test/specs/GeojsHeatmapLayer.spec.js

+7-11
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
1-
import { mount } from '@vue/test-utils';
2-
3-
import GeojsMapViewport from '@/components/geojs/GeojsMapViewport';
41
import GeojsHeatmapLayer from '@/components/geojs/GeojsHeatmapLayer';
52

3+
import ProvideGeojs from '../ProvideGeojs';
4+
65
describe('GeojsTileLayer.vue', () => {
7-
let mapWrapper;
6+
const provider = new ProvideGeojs();
87
function mountLayer(options = {}) {
9-
return mount(GeojsHeatmapLayer, {
10-
testParent: mapWrapper.vm,
11-
...options,
12-
});
8+
return provider.mountLayer(GeojsHeatmapLayer, options);
139
}
1410

1511
beforeEach(() => {
1612
sinon.stub(console, 'warn');
17-
mapWrapper = mount(GeojsMapViewport);
13+
provider.start();
1814
});
1915
afterEach(() => {
2016
console.warn.restore(); // eslint-disable-line no-console
21-
mapWrapper.destroy();
17+
provider.stop();
2218
});
2319

2420
it('validate intensity (null)', () => {
@@ -78,7 +74,7 @@ describe('GeojsTileLayer.vue', () => {
7874

7975
it('removes on destroy', () => {
8076
const wrapper = mountLayer();
81-
const spy = sinon.spy(mapWrapper.vm.$geojsMap, 'deleteLayer');
77+
const spy = sinon.spy(provider.geojsMap, 'deleteLayer');
8278
const layer = wrapper.vm.$geojsLayer;
8379
wrapper.destroy();
8480
spy.should.have.been.calledOnce;

test/specs/GeojsMapViewport.spec.js

+7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ describe('GeojsMapViewport.vue', () => {
2929
expect(map.rotation()).closeTo(0.5, delta);
3030
});
3131

32+
it('provides properties to child elements', () => {
33+
const wrapper = mount(GeojsMapViewport);
34+
const provides = wrapper.vm.$options.provide();
35+
expect(provides).to.have.property('$geojs');
36+
expect(provides).to.have.property('$geojsMap');
37+
});
38+
3239
it('respond to pan events (sync)', () => {
3340
const wrapper = mount(GeojsMapViewport, {
3441
propsData: {

test/specs/GeojsTileLayer.spec.js

+15-20
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
1-
import { mount } from '@vue/test-utils';
2-
3-
import GeojsMapViewport from '@/components/geojs/GeojsMapViewport';
41
import GeojsTileLayer from '@/components/geojs/GeojsTileLayer';
52

3+
import ProvideGeojs from '../ProvideGeojs';
4+
65
describe('GeojsTileLayer.vue', () => {
7-
let mapWrapper;
6+
const provider = new ProvideGeojs();
7+
function mountTileLayer(options) {
8+
return provider.mountLayer(GeojsTileLayer, options);
9+
}
810
beforeEach(() => {
911
sinon.stub(console, 'warn');
10-
mapWrapper = mount(GeojsMapViewport);
12+
provider.start();
1113
});
1214
afterEach(() => {
1315
console.warn.restore(); // eslint-disable-line no-console
14-
mapWrapper.destroy();
16+
provider.stop();
1517
});
1618

1719
it('url (string)', () => {
18-
const wrapper = mount(GeojsTileLayer, {
19-
propsData: {
20-
url: '/data/white.jpg',
21-
},
22-
testParent: mapWrapper.vm,
20+
const wrapper = mountTileLayer({
21+
propsData: { url: '/data/white.jpg' },
2322
});
2423
expect(wrapper.vm.$geojsLayer.url()).equal('/data/white.jpg');
2524

@@ -29,12 +28,11 @@ describe('GeojsTileLayer.vue', () => {
2928

3029
it('attribution', () => {
3130
const attribution = '<a href="www.example.com"></a>';
32-
const wrapper = mount(GeojsTileLayer, {
31+
const wrapper = mountTileLayer({
3332
propsData: {
3433
url: '/data/osm.png',
3534
attribution,
3635
},
37-
testParent: mapWrapper.vm,
3836
});
3937
expect(wrapper.vm.$geojsLayer.attribution()).equal(attribution);
4038

@@ -43,12 +41,11 @@ describe('GeojsTileLayer.vue', () => {
4341
});
4442

4543
it('opacity', () => {
46-
const wrapper = mount(GeojsTileLayer, {
44+
const wrapper = mountTileLayer({
4745
propsData: {
4846
url: '/data/osm.png',
4947
opacity: 0.5,
5048
},
51-
testParent: mapWrapper.vm,
5249
});
5350
expect(wrapper.vm.$geojsLayer.opacity()).equal(0.5);
5451

@@ -57,24 +54,22 @@ describe('GeojsTileLayer.vue', () => {
5754
});
5855

5956
it('wrapX', () => {
60-
const wrapper = mount(GeojsTileLayer, {
57+
const wrapper = mountTileLayer({
6158
propsData: {
6259
url: '/data/osm.png',
6360
wrapX: false,
6461
},
65-
testParent: mapWrapper.vm,
6662
});
6763
expect(wrapper.vm.$geojsLayer.options.wrapX).equal(false);
6864
});
6965

7066
it('removes on destroy', () => {
71-
const wrapper = mount(GeojsTileLayer, {
67+
const wrapper = mountTileLayer({
7268
propsData: {
7369
url: '/data/osm.png',
7470
},
75-
testParent: mapWrapper.vm,
7671
});
77-
const spy = sinon.spy(mapWrapper.vm.$geojsMap, 'deleteLayer');
72+
const spy = sinon.spy(wrapper.vm.$geojsMap, 'deleteLayer');
7873
const layer = wrapper.vm.$geojsLayer;
7974
wrapper.destroy();
8075
spy.should.have.been.calledOnce;

test/specs/GeojsWidgetLayer.spec.js

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { mount } from '@vue/test-utils';
21

3-
import GeojsMapViewport from '@/components/geojs/GeojsMapViewport';
42
import GeojsWidgetLayer from '@/components/geojs/GeojsWidgetLayer';
53

4+
import ProvideGeojs from '../ProvideGeojs';
5+
66
const TestComponent = {
77
functional: true,
88
render(createElement) {
@@ -11,29 +11,26 @@ const TestComponent = {
1111
};
1212

1313
describe('GeojsWidgetLayer.vue', () => {
14+
const provider = new ProvideGeojs();
1415
let displayPosition = { x: 10, y: 20 };
15-
let mapWrapper;
1616
let gcsToDisplay;
1717

1818
function mountLayer(options = {}) {
19-
return mount(GeojsWidgetLayer, {
20-
testParent: mapWrapper.vm,
21-
slots: {
22-
default: TestComponent,
23-
},
19+
return provider.mountLayer(GeojsWidgetLayer, {
20+
slots: { default: TestComponent },
2421
...options,
2522
});
2623
}
2724

2825
beforeEach(() => {
2926
sinon.stub(console, 'warn');
30-
mapWrapper = mount(GeojsMapViewport);
31-
gcsToDisplay = sinon.stub(mapWrapper.vm.$geojsMap, 'gcsToDisplay').callsFake(() => displayPosition);
27+
provider.start();
28+
gcsToDisplay = sinon.stub(provider.geojsMap, 'gcsToDisplay').callsFake(() => displayPosition);
3229
});
3330
afterEach(() => {
3431
console.warn.restore(); // eslint-disable-line no-console
3532
gcsToDisplay.restore();
36-
mapWrapper.destroy();
33+
provider.stop();
3734
});
3835

3936
it('mounted with default slot', () => {

yarn.lock

+3-3
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,9 @@
323323
source-map "^0.5.6"
324324
vue-template-es2015-compiler "^1.6.0"
325325

326-
"@vue/test-utils@^1.0.0-beta.16":
327-
version "1.0.0-beta.16"
328-
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.16.tgz#dcf7a30304391422e382b5f97db6eb9508112906"
326+
327+
version "1.0.0-beta.17"
328+
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.17.tgz#cdf4213d6f0aded2416465fd4829c162a48b876d"
329329
dependencies:
330330
lodash "^4.17.4"
331331

0 commit comments

Comments
 (0)