[FIX JENKINS-37516] - js-extensions tests were broken (#549)

* JENKINS-37516 - js-extensions tests were broken
This commit is contained in:
Keith Zantow 2016-11-17 11:09:30 -05:00 committed by GitHub
parent e29025df6a
commit 1ce912340a
15 changed files with 2781 additions and 6013 deletions

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,7 @@
"dependencies": {
"@jenkins-cd/blueocean-core-js": "0.0.22",
"@jenkins-cd/design-language": "0.0.86",
"@jenkins-cd/js-extensions": "0.0.27",
"@jenkins-cd/js-extensions": "0.0.30",
"@jenkins-cd/js-modules": "0.0.8",
"es6-promise": "4.0.5",
"immutable": "3.8.1",

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@
"dependencies": {
"@jenkins-cd/blueocean-core-js": "0.0.22",
"@jenkins-cd/design-language": "0.0.86",
"@jenkins-cd/js-extensions": "0.0.27",
"@jenkins-cd/js-extensions": "0.0.30",
"@jenkins-cd/js-modules": "0.0.8",
"immutable": "3.8.1",
"keymirror": "0.1.1",

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@
"dependencies": {
"@jenkins-cd/blueocean-core-js": "0.0.22",
"@jenkins-cd/design-language": "0.0.86",
"@jenkins-cd/js-extensions": "0.0.27",
"@jenkins-cd/js-extensions": "0.0.30",
"@jenkins-cd/js-modules": "0.0.8",
"history": "2.0.2",
"immutable": "3.8.1",

View File

@ -1,9 +1,20 @@
// Provide an ExtensionStore & ExtensionRenderer react component
exports.store = require('./dist/ExtensionStore.js').instance;
const ExtensionStore = require('./dist/ExtensionStore.js').default;
exports.store = new ExtensionStore();
exports.Renderer = require('./dist/ExtensionRenderer.js').ExtensionRenderer;
exports.Renderer = require('./dist/ExtensionRenderer.js').default;
exports.classMetadataStore = require('./dist/ClassMetadataStore.js').instance;
//in lieu of DI
const ResourceLoadTracker = require('./dist/ResourceLoadTracker.js').default;
const resourceLoadTracker = new ResourceLoadTracker();
exports.store.resourceLoadTracker = resourceLoadTracker;
//Put these in statics so we can mock them for testing. Ideally they would come from React scope.
exports.Renderer.extensionStore = exports.store;
exports.Renderer.resourceLoadTracker = resourceLoadTracker;
const ClassMetadataStore = require('./dist/ClassMetadataStore.js').default;
exports.classMetadataStore = new ClassMetadataStore();
exports.dataType = function dataType(dataType) { return exports.classMetadataStore.dataType(dataType); };

View File

@ -1,6 +1,6 @@
{
"name": "@jenkins-cd/js-extensions",
"version": "0.0.27",
"version": "0.0.30",
"description": "Jenkins Extension Store",
"main": "index.js",
"files": [
@ -37,7 +37,7 @@
"gulp-mocha": "^2.2.0",
"jsdom": "^9.5.0",
"react": "^0.14.7 || ^15.0.0",
"react-addons-test-utils": "15.3.2",
"react-addons-test-utils": "^15.3.2",
"react-dom": "^0.14.7 || ^15.0.0"
},
"dependencies": {

View File

@ -5,14 +5,11 @@ const jsTest = require('@jenkins-cd/js-test');
const assert = require('chai').assert;
const mount = require('enzyme').mount;
const jsdom = require('jsdom');
const ExtensionRenderer = require('../dist/ExtensionRenderer.js').ExtensionRenderer;
const extensionStoreInstance = require('../dist/ExtensionStore.js').instance;
const $ = React.createElement;
const ExtensionRenderer = require('../dist/ExtensionRenderer.js').default;
function mockExtension(props) {
return (
$('h1', {}, 'Extension is a H1')
React.createElement('h1', {}, 'Extension is a H1')
);
}
@ -61,13 +58,13 @@ describe('ExtensionRenderer', function () {
oldExtensionStore = ExtensionRenderer.ExtensionStore;
oldResourceLoadTracker = ExtensionRenderer.ResourceLoadTracker;
ExtensionRenderer.ExtensionStore = mockExtensionStore;
ExtensionRenderer.ResourceLoadTracker = mockResourceLoadTracker;
ExtensionRenderer.extensionStore = mockExtensionStore;
ExtensionRenderer.resourceLoadTracker = mockResourceLoadTracker;
});
afterEach(function () {
ExtensionRenderer.ExtensionStore = oldExtensionStore;
ExtensionRenderer.ResourceLoadTracker = oldResourceLoadTracker;
ExtensionRenderer.extensionStore = oldExtensionStore;
ExtensionRenderer.resourceLoadTracker = oldResourceLoadTracker;
});
after(function () {
@ -76,7 +73,7 @@ describe('ExtensionRenderer', function () {
});
it('should do nothing interesting by default', function () {
const result = mount($(ExtensionRenderer, {extensionPoint: 'foo.bar.baz'}));
const result = mount(React.createElement(ExtensionRenderer, {extensionPoint: 'foo.bar.baz'}));
assert.isTrue(result.is('ExtensionRenderer'), 'should be ExtensionRenderer');
assert.equal(result.length, 1, 'length');
assert.equal(result.children().length, 0, 'children.length');
@ -85,24 +82,24 @@ describe('ExtensionRenderer', function () {
});
it('should show default children if no extension found', function () {
const result = mount($(ExtensionRenderer, {extensionPoint: 'foo.bar.baz'}, 'Default text node'));
const result = mount(React.createElement(ExtensionRenderer, {extensionPoint: 'foo.bar.baz'}, 'Default text node'));
assert.isTrue(result.is('ExtensionRenderer'), 'should be ExtensionRenderer');
assert.equal(result.length, 1, 'length');
assert.equal(result.html(), '<div>Default text node</div>', 'html output');
});
it('should change the wrapping element', function () {
const result = mount($(ExtensionRenderer, {extensionPoint: 'ep1', wrappingElement: 'section'}));
const result = mount(React.createElement(ExtensionRenderer, {extensionPoint: 'ep1', wrappingElement: 'section'}));
assert.equal(result.html(), '<section><div><h1>Extension is a H1</h1></div></section>', 'html output');
});
it('should render the extension', function () {
const result = mount($(ExtensionRenderer, {extensionPoint: 'ep1'}));
const result = mount(React.createElement(ExtensionRenderer, {extensionPoint: 'ep1'}));
assert.equal(result.html(), '<div><div><h1>Extension is a H1</h1></div></div>', 'html output');
});
it('should should not show default children when extension is present', function () {
const result = mount($(ExtensionRenderer, {extensionPoint: 'ep1'}, 'Default text node'));
const result = mount(React.createElement(ExtensionRenderer, {extensionPoint: 'ep1'}, 'Default text node'));
assert.equal(result.html(), '<div><div><h1>Extension is a H1</h1></div></div>', 'html output');
});

View File

@ -1,7 +1,8 @@
var jsTest = require('@jenkins-cd/js-test');
var expect = require('chai').expect;
var ExtensionStore = require('../dist/ExtensionStore').ExtensionStore;
var ClassMetadataStore = require('../dist/ClassMetadataStore').instance;
var ExtensionStore = require('../dist/ExtensionStore').default;
var ClassMetadataStore = require('../dist/ClassMetadataStore').default;
var resourceLoadTracker = new (require('../dist/ResourceLoadTracker').default)();
var componentType = require('../dist/ComponentTypeFilter').componentType;
var javaScriptExtensionInfo = require('./javaScriptExtensionInfo-01.json');
@ -13,8 +14,15 @@ var jsModules = require('@jenkins-cd/js-modules');
var theRealImport = jsModules.importModule;
var makeClassMetadataStore = function(fn) {
ClassMetadataStore.init(fn);
return ClassMetadataStore;
var classMetadataStore = new ClassMetadataStore();
classMetadataStore.init(fn);
return classMetadataStore;
};
var makeExtensionStore = function() {
var store = new ExtensionStore();
store.resourceLoadTracker = resourceLoadTracker;
return store;
};
var mockDataLoad = function(extensionStore, out, componentMap) {
@ -65,7 +73,7 @@ describe("ExtensionStore.js", function () {
it("- fails if not initialized", function(done) {
jsTest.onPage(function() {
var extensionStore = new ExtensionStore();
var extensionStore = makeExtensionStore();
var plugins = {};
mockDataLoad(extensionStore, plugins);
@ -91,7 +99,7 @@ describe("ExtensionStore.js", function () {
it("- test plugins loaded not duplicated", function (done) {
jsTest.onPage(function() {
var extensionStore = new ExtensionStore();
var extensionStore = makeExtensionStore();
var plugins = {};
mockDataLoad(extensionStore, plugins);
@ -129,53 +137,57 @@ describe("ExtensionStore.js", function () {
});
});
//it("- handles types properly", function(done) {
// var extensionStore = new ExtensionStore();
//
// var plugins = {};
// mockDataLoad(extensionStore, plugins);
//
// var typeData = {};
// typeData['type-1'] = {
// "_class":"io.jenkins.blueocean.service.embedded.rest.ExtensionClassImpl",
// "_links":{
// "self":{"_class":"io.jenkins.blueocean.rest.hal.Link",
// "href":"/blue/rest/classes/hudson.tasks.junit.TestResultAction/"
// }
// },
// "classes":["supertype-1"]
// };
// typeData['type-2'] = {
// "_class":"io.jenkins.blueocean.service.embedded.rest.ExtensionClassImpl",
// "_links":{
// "self":{"_class":"io.jenkins.blueocean.rest.hal.Link",
// "href":"/blue/rest/classes/hudson.tasks.junit.TestResultAction/"
// }
// },
// "classes":["supertype-2"]
// };
//
// extensionStore.init({
// extensionDataProvider: function(cb) { cb(javaScriptExtensionInfo); },
// classMetadataStore: makeClassMetadataStore(function(type, cb) { cb(typeData[type]); })
// });
//
// extensionStore.getExtensions('ept-1', [ClassMetadataStore.dataType('type-1')], function(extensions) {
// expect(extensions.length).to.equal(1);
//
// expect(extensions[0]).to.equal('typed-component-1.1');
// });
//
// extensionStore.getExtensions('ept-2', [ClassMetadataStore.dataType('type-2')], function(extensions) {
// expect(extensions.length).to.equal(1);
// expect(extensions).to.include.members(["typed-component-1.2"]);
//
// done();
// });
//});
it("- handles types properly", function(done) {
var extensionStore = makeExtensionStore();
var plugins = {};
mockDataLoad(extensionStore, plugins);
var typeData = {};
typeData['type-1'] = {
"_class":"io.jenkins.blueocean.service.embedded.rest.ExtensionClassImpl",
"_links":{
"self":{"_class":"io.jenkins.blueocean.rest.hal.Link",
"href":"/blue/rest/classes/hudson.tasks.junit.TestResultAction/"
}
},
"classes":["supertype-1"]
};
typeData['type-2'] = {
"_class":"io.jenkins.blueocean.service.embedded.rest.ExtensionClassImpl",
"_links":{
"self":{"_class":"io.jenkins.blueocean.rest.hal.Link",
"href":"/blue/rest/classes/hudson.tasks.junit.TestResultAction/"
}
},
"classes":["supertype-2"]
};
var classMetadataStore = makeClassMetadataStore(function(type, cb) {
cb(typeData[type]);
});
extensionStore.init({
extensionDataProvider: function(cb) { cb(javaScriptExtensionInfo); },
classMetadataStore: classMetadataStore
});
extensionStore.getExtensions('ept-1', [classMetadataStore.dataType('type-1')], function(extensions) {
expect(extensions.length).to.equal(1);
expect(extensions[0]).to.equal('typed-component-1.1');
});
extensionStore.getExtensions('ept-2', [classMetadataStore.dataType('type-2')], function(extensions) {
expect(extensions.length).to.equal(1);
expect(extensions).to.include.members(["typed-component-1.2"]);
done();
});
});
it("- handles untyped extension points", function(done) {
var extensionStore = new ExtensionStore();
var extensionStore = makeExtensionStore();
var plugins = {};
mockDataLoad(extensionStore, plugins);
@ -200,17 +212,19 @@ describe("ExtensionStore.js", function () {
"classes":["supertype-2"]
};
var classMetadataStore = makeClassMetadataStore(function(type, cb) { cb(typeData[type]); });
extensionStore.init({
extensionDataProvider: function(cb) { cb(javaScriptExtensionInfo); },
classMetadataStore: makeClassMetadataStore(function(type, cb) { cb(typeData[type]); })
classMetadataStore: classMetadataStore
});
extensionStore.getExtensions('ep-1', [ClassMetadataStore.untyped()], function(extensions) {
extensionStore.getExtensions('ep-1', [classMetadataStore.untyped()], function(extensions) {
expect(extensions.length).to.equal(3);
expect(extensions).to.include.members(["component-1.1","component-1.2","component-2.1"]);
});
extensionStore.getExtensions('ept-2', [ClassMetadataStore.untyped()], function(extensions) {
extensionStore.getExtensions('ept-2', [classMetadataStore.untyped()], function(extensions) {
expect(extensions.length).to.equal(0);
expect(extensions).to.include.members([]);
@ -219,14 +233,16 @@ describe("ExtensionStore.js", function () {
});
it("- handles multi-key requests", function(done) {
var extensionStore = new ExtensionStore();
var extensionStore = makeExtensionStore();
var plugins = {};
mockDataLoad(extensionStore, plugins);
var classMetadataStore = makeClassMetadataStore(function(type, cb) { cb({}); });
extensionStore.init({
extensionDataProvider: function(cb) { cb(javaScriptExtensionInfo); },
classMetadataStore: makeClassMetadataStore(function(type, cb) { cb({}); })
classMetadataStore: classMetadataStore
});
extensionStore.getExtensions(['ep-1','ep-2'], function(ep1,ep2) {
@ -240,49 +256,49 @@ describe("ExtensionStore.js", function () {
done();
});
//it("- handles componentType", function(done) {
// var extensionStore = new ExtensionStore();
//
// class PretendReactClass {
// }
//
// class PretendComponent1 extends PretendReactClass {
// }
//
// class PretendComponent2 extends PretendReactClass {
// }
//
// var plugins = {};
// mockDataLoad(extensionStore, plugins, {
// 'component-1.3.1': PretendComponent1,
// 'component-2.3.1': PretendComponent2,
// });
//
// extensionStore.init({
// extensionDataProvider: function(cb) { cb(javaScriptExtensionInfo); },
// classMetadataStore: makeClassMetadataStore(function(type, cb) { cb({}); })
// });
//
// extensionStore.getExtensions('ep-3', [componentType(PretendComponent1)], function(extensions) {
// expect(extensions.length).to.equal(1);
// expect(extensions).to.include.members([PretendComponent1]);
// });
//
// extensionStore.getExtensions('ep-3', [componentType(PretendComponent2)], function(extensions) {
// expect(extensions.length).to.equal(1);
// expect(extensions).to.include.members([PretendComponent2]);
// });
//
// extensionStore.getExtensions('ep-3', [componentType(PretendReactClass)], function(extensions) {
// expect(extensions.length).to.equal(2);
// expect(extensions).to.include.members([PretendComponent1, PretendComponent2]);
// });
//
// extensionStore.getExtensions('ep-3', [componentType(PretendReactClass), componentType(PretendComponent1)], function(extensions) {
// expect(extensions.length).to.equal(1);
// expect(extensions).to.include.members([PretendComponent1]);
// });
//
// done();
//});
it("- handles componentType", function(done) {
var extensionStore = makeExtensionStore();
class PretendReactClass {
}
class PretendComponent1 extends PretendReactClass {
}
class PretendComponent2 extends PretendReactClass {
}
var plugins = {};
mockDataLoad(extensionStore, plugins, {
'component-1.3.1': PretendComponent1,
'component-2.3.1': PretendComponent2,
});
extensionStore.init({
extensionDataProvider: function(cb) { cb(javaScriptExtensionInfo); },
classMetadataStore: makeClassMetadataStore(function(type, cb) { cb({}); })
});
extensionStore.getExtensions('ep-3', [componentType(PretendComponent1)], function(extensions) {
expect(extensions.length).to.equal(1);
expect(extensions).to.include.members([PretendComponent1]);
});
extensionStore.getExtensions('ep-3', [componentType(PretendComponent2)], function(extensions) {
expect(extensions.length).to.equal(1);
expect(extensions).to.include.members([PretendComponent2]);
});
extensionStore.getExtensions('ep-3', [componentType(PretendReactClass)], function(extensions) {
expect(extensions.length).to.equal(2);
expect(extensions).to.include.members([PretendComponent1, PretendComponent2]);
});
extensionStore.getExtensions('ep-3', [componentType(PretendReactClass), componentType(PretendComponent1)], function(extensions) {
expect(extensions.length).to.equal(1);
expect(extensions).to.include.members([PretendComponent1]);
});
done();
});
});

View File

@ -1,7 +1,7 @@
var jsTest = require('@jenkins-cd/js-test');
var expect = require('chai').expect;
var ResourceLoadTracker = require('../dist/ResourceLoadTracker').instance;
var ResourceLoadTracker = new (require('../dist/ResourceLoadTracker').default)();
describe("ResourceLoadTracker.js", function () {

View File

@ -2,7 +2,7 @@
* ClassMetadataStore is responsible for maintaining extension metadata
* including type/capability info
*/
export class ClassMetadataStore {
export default class ClassMetadataStore {
init(classMetadataProvider) {
/**
* Type info cache
@ -36,7 +36,7 @@ export class ClassMetadataStore {
// This is the first request for this type. Initialise the
// callback cache and then issue the request to
// the classMetadataProvider.
callbacks = this.classMetadataOnloadCallbacks[type] = [];
callbacks = this.classMetadataOnloadCallbacks[type] = [onload];
this.classMetadataProvider(type, (data) => {
classMeta = this.classMetadata[type] = JSON.parse(JSON.stringify(data));
classMeta.classes = classMeta.classes || [];
@ -58,8 +58,8 @@ export class ClassMetadataStore {
} else {
// We already have an inflight request to get class metadata info about
// the requested type, so nothing to do except store the onload callback.
callbacks.push(onload);
}
callbacks.push(onload);
}
dataType(dataType) {
@ -105,5 +105,3 @@ export class ClassMetadataStore {
};
}
}
export const instance = new ClassMetadataStore();

View File

@ -1,7 +1,5 @@
var React = require('react');
var ReactDOM = require('react-dom');
var importedExtensionStore = require('./ExtensionStore.js').instance;
var importedResourceLoadTracker = require('./ResourceLoadTracker').instance;
/**
* An internal component that inserts things into the (separate) context of mounted extensions. We need this for our
@ -33,11 +31,10 @@ ContextBridge.propTypes = {
config: React.PropTypes.object
};
/**
* Renderer for react component extensions for which other plugins can provide an implementing Component.
*/
export class ExtensionRenderer extends React.Component {
export default class ExtensionRenderer extends React.Component {
constructor() {
super();
@ -50,7 +47,7 @@ export class ExtensionRenderer extends React.Component {
}
componentDidMount() {
ExtensionRenderer.ResourceLoadTracker.onMount(this.props.extensionPoint);
ExtensionRenderer.resourceLoadTracker.onMount(this.props.extensionPoint);
this._renderAllExtensions();
}
@ -63,7 +60,7 @@ export class ExtensionRenderer extends React.Component {
}
_setExtensions() {
ExtensionRenderer.ExtensionStore.getExtensions(this.props.extensionPoint, this.props.filter,
ExtensionRenderer.extensionStore.getExtensions(this.props.extensionPoint, this.props.filter,
extensions => this.setState({extensions: extensions})
);
}
@ -184,15 +181,12 @@ export class ExtensionRenderer extends React.Component {
}
}
// Put these in statics so we can mock them for testing. Ideally they would come from React scope.
ExtensionRenderer.ExtensionStore = importedExtensionStore;
ExtensionRenderer.ResourceLoadTracker = importedResourceLoadTracker;
ExtensionRenderer.defaultProps = {
wrappingElement: "div"
};
ExtensionRenderer.propTypes = {
children: React.PropTypes.any,
extensionPoint: React.PropTypes.string.isRequired,
filter: React.PropTypes.any,
wrappingElement: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.element])

View File

@ -2,7 +2,7 @@
* ExtensionStore is responsible for maintaining extension metadata
* including type/capability info
*/
export class ExtensionStore {
export default class ExtensionStore {
/**
* FIXME this is NOT a constructor, as there's no common way to
* pass around a DI singleton at the moment across everything
@ -157,8 +157,7 @@ export class ExtensionStore {
extensionPointMetadatas.push(extensionMetadata);
}
}
var ResourceLoadTracker = require('./ResourceLoadTracker').instance;
ResourceLoadTracker.setExtensionPointMetadata(this.extensionPointList);
this.resourceLoadTracker.setExtensionPointMetadata(this.extensionPointList);
if (oncomplete) oncomplete(this.extensionPointList);
});
}
@ -277,7 +276,3 @@ class LoadCountMonitor {
this.callback = callback;
}
}
// should figure out DI with singletons so we can move
// required providers to other injection points, ideally
export const instance = new ExtensionStore();

View File

@ -6,7 +6,7 @@ import jsModules from '@jenkins-cd/js-modules';
* Keeps track of page CSS, adding and removing CSS as ExtensionPoint components are
* mounted and unmounted.
*/
export class ResourceLoadTracker {
export default class ResourceLoadTracker {
constructor() {
// The CSS resources to be added for each Extension point.
// Key: Extension point name.
@ -135,6 +135,3 @@ export class ResourceLoadTracker {
}
}
}
// in lieu of DI
export const instance = new ResourceLoadTracker();