cubx-dependency-resolver
Version:
Npm package to resolve the dependencies of a list of artifacts
1,038 lines (1,027 loc) • 70.5 kB
JavaScript
/* globals describe, beforeEach, afterEach, it, expect, before, __dirname, sinon, after */
/* eslint no-unused-expressions: "off" */
(function () {
'use strict';
describe('ArtifactsDepsResolver', function () {
var fs = require('fs-extra');
var path = require('path');
var DependencyTree = require('../../lib/DependencyTree');
var DepReference = require('../../lib/DepReference');
var ArtifactsDepsResolver = require('../../lib/cubx-dependency-resolver.js');
var artifactsDepsResolver;
var resourcesPath;
var pkg1;
var pkg2;
var pkg3;
var pkg4;
var pkg5;
var pkg6;
var rootDepList;
before(function () {
resourcesPath = path.join(__dirname, '../resources');
pkg1 = fs.readFileSync(path.join(resourcesPath, 'dependencyPackage1.json'), 'utf8');
pkg2 = fs.readFileSync(path.join(resourcesPath, 'dependencyPackage2.json'), 'utf8');
pkg3 = fs.readFileSync(path.join(resourcesPath, 'dependencyPackage3.json'), 'utf8');
pkg4 = fs.readFileSync(path.join(resourcesPath, 'dependencyPackage4.json'), 'utf8');
pkg5 = fs.readFileSync(path.join(resourcesPath, 'dependencyPackage5.json'), 'utf8');
pkg6 = fs.readFileSync(path.join(resourcesPath, 'dependencyPackage6.json'), 'utf8');
});
beforeEach(function () {
rootDepList = JSON.parse(fs.readFileSync(path.join(resourcesPath, 'rootDependencies.json'), 'utf8'));
});
describe('#buildRawDependencyTree', function () {
var baseUrl;
var stub;
before(function () {
baseUrl = 'https://cubbles.world/sandbox/';
artifactsDepsResolver = new ArtifactsDepsResolver();
stub = sinon.stub(artifactsDepsResolver, '_resolveDepReferenceDependencies').callsFake(function (dep) {
return new Promise(function (resolve, reject) {
var requestedPkg;
var dependencies = [];
switch (dep.getId()) {
case 'package1@1.0.0/util1':
requestedPkg = JSON.parse(pkg1);
dependencies = artifactsDepsResolver._createDepReferenceListFromArtifactDependencies(
requestedPkg.artifacts.utilities[0].dependencies, {
webpackageId: 'package1@1.0.0',
artifactId: 'util1'
});
break;
case 'package2@1.0.0/util2':
requestedPkg = JSON.parse(pkg2);
dependencies = artifactsDepsResolver._createDepReferenceListFromArtifactDependencies(
requestedPkg.artifacts.utilities[0].dependencies, {
webpackageId: 'package2@1.0.0',
artifactId: 'util2'
});
break;
case 'package3@1.0.0/util3':
requestedPkg = JSON.parse(pkg3);
dependencies = artifactsDepsResolver._createDepReferenceListFromArtifactDependencies(
requestedPkg.artifacts.utilities[0].dependencies, {
webpackageId: 'package3@1.0.0',
artifactId: 'util3'
});
break;
case 'package4@1.0.0/util4':
requestedPkg = JSON.parse(pkg4);
break;
case 'package5@1.0.0/util5':
requestedPkg = JSON.parse(pkg5);
dependencies = artifactsDepsResolver._createDepReferenceListFromArtifactDependencies(
requestedPkg.artifacts.utilities[0].dependencies, {
webpackageId: 'package5@1.0.0',
artifactId: 'util5'
});
break;
case 'package6@1.0.0/util6':
requestedPkg = JSON.parse(pkg6);
}
if (requestedPkg) {
setTimeout(function () {
resolve({dependencies: dependencies, resources: requestedPkg.artifacts.utilities[0].resources});
}, 200);
} else if (!(dep instanceof DepReference)) {
throw new TypeError();
} else {
setTimeout(function () {
reject({message: 'Error while resolving...'}); // eslint-disable-line prefer-promise-reject-errors
}, 100);
}
});
});
});
after(function () {
stub.restore();
});
it('should return a promise', function () {
expect(artifactsDepsResolver.buildRawDependencyTree(rootDepList, baseUrl)).to.be.an.instanceOf(Promise);
});
it('should resolve the returned promise with an instance of DependencyTree', function () {
this.timeout(15000);
return artifactsDepsResolver.buildRawDependencyTree(rootDepList, baseUrl).then(function (result) {
result.should.be.an.instanceOf(DependencyTree);
});
});
it('should create a DependencyTree representing the raw dependency structure for given rootDependency list', function () {
/**
* Check if raw dependency tree has the following structure:
*
* package1@1.0.0/util1 package2@1.0.0/util2
* / \ / \
* / \ / \
* package3@1.0.0/util3 package4@1.0.0/util4 package3@1.0.0/util3 package5@1.0.0/util5
* | | |
* | | |
* package5@1.0.0/util5 package5@1.0.0/util5 package6@1.0.0/util6
* | |
* | |
* package6@1.0.0/util6 package6@1.0.0/util6
*/
return artifactsDepsResolver.buildRawDependencyTree(rootDepList, baseUrl).then(function (tree) {
expect(tree._rootNodes).to.have.lengthOf(2);
// check first (root) level of tree
expect(tree._rootNodes[0].data.getId()).to.equal('package1@1.0.0/util1');
expect(tree._rootNodes[1].data.getId()).to.equal('package2@1.0.0/util2');
// check second level of tree
expect(tree._rootNodes[0].children[0].data.getId()).to.equal('package3@1.0.0/util3');
expect(tree._rootNodes[0].children[1].data.getId()).to.equal('package4@1.0.0/util4');
expect(tree._rootNodes[1].children[0].data.getId()).to.equal('package3@1.0.0/util3');
expect(tree._rootNodes[1].children[1].data.getId()).to.equal('package5@1.0.0/util5');
// check third level of tree
expect(tree._rootNodes[0].children[0].children[0].data.getId()).to.equal('package5@1.0.0/util5');
expect(tree._rootNodes[1].children[0].children[0].data.getId()).to.equal('package5@1.0.0/util5');
expect(tree._rootNodes[1].children[1].children[0].data.getId()).to.equal('package6@1.0.0/util6');
// check 4th level of tree
expect(tree._rootNodes[0].children[0].children[0].children[0].data.getId()).to.equal('package6@1.0.0/util6');
expect(tree._rootNodes[1].children[0].children[0].children[0].data.getId()).to.equal('package6@1.0.0/util6');
});
});
describe('Error Handling', function () {
it('should throw an TypeError if \'dependencies\' parameter is not an Array', function () {
try {
artifactsDepsResolver.buildRawDependencyTree({});
} catch (error) {
expect(error).to.be.an.instanceOf(TypeError);
}
});
it('should reject returned promise if there is an error resolving single depenencies', function () {
rootDepList.push({webpackageId: 'error', artifactId: 'util'});
return artifactsDepsResolver.buildRawDependencyTree(rootDepList, baseUrl).then(function (result) {
throw new Error('Promise was unexpectedly fulfilled. Result: ' + result);
}, function (error) {
error.should.have.ownProperty('message', 'Error while resolving...');
});
});
});
});
describe('#_fetchManifest()', function () {
var axiosStub;
before(function () {
artifactsDepsResolver = new ArtifactsDepsResolver();
axiosStub = sinon.stub(artifactsDepsResolver._axios, 'request').callsFake(function (url) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, 250);
});
});
});
it('should call _axios.request method with given url', function (done) {
artifactsDepsResolver._fetchManifest('https://www.example.test').then(function () {
expect(axiosStub.calledWith({url: 'https://www.example.test'})).to.be.equal(true);
done();
});
});
it('should return a promise', function () {
var promise = artifactsDepsResolver._fetchManifest('https://www.example.test');
expect(promise).to.be.an.instanceOf(Promise);
});
after(function () {
axiosStub.restore();
});
});
describe('#_resolveDepReferenceDependencies()', function () {
var _fetchManifestStub;
var depRefItem;
var baseUrl;
before(function () {
artifactsDepsResolver = new ArtifactsDepsResolver();
baseUrl = 'https://cubbles.world/sandbox/';
});
beforeEach(function () {
artifactsDepsResolver._responseCache.invalidate();
depRefItem = new DepReference({webpackageId: 'package1@1.0.0', artifactId: 'util1', referrer: null});
// mock _fetchManifest method
_fetchManifestStub = sinon.stub(artifactsDepsResolver, '_fetchManifest').callsFake(function (url) {
return new Promise(function (resolve, reject) {
var response = {};
if (url.indexOf('package1@1.0.0') >= 0) {
response.data = JSON.parse(pkg1);
}
if (url.indexOf('package2@1.0.0') >= 0) {
response.data = JSON.parse(pkg2);
}
if (url.indexOf('package3@1.0.0') >= 0) {
response.data = JSON.parse(pkg3);
}
if (url.indexOf('package4@1.0.0') >= 0) {
response.data = JSON.parse(pkg4);
}
if (url.indexOf('package5@1.0.0') >= 0) {
response.data = JSON.parse(pkg5);
}
if (url.indexOf('package6@1.0.0') >= 0) {
response.data = JSON.parse(pkg6);
}
if (response.hasOwnProperty('data')) {
setTimeout(function () {
resolve(response);
}, 200);
} else {
setTimeout(function () {
reject({message: 'Error while requesting ' + url}); // eslint-disable-line prefer-promise-reject-errors
}, 100);
}
});
});
});
afterEach(function () {
_fetchManifestStub.restore();
});
it('should return a promise', function () {
expect(artifactsDepsResolver._resolveDepReferenceDependencies(depRefItem, baseUrl)).to.be.an.instanceOf(Promise);
});
it('should resolve the returned promise with an object containing an array of the dependencies of given depRef item and all the resources for the given depRefItem', function () {
return artifactsDepsResolver._resolveDepReferenceDependencies(depRefItem, baseUrl).then(function (result) {
result.should.be.an.instanceOf(Object);
result.should.have.property('resources');
result.should.have.property('dependencies');
result.resources.should.eql(['js/pack1.js', 'css/pack1.css']);
result.dependencies.should.have.lengthOf(2);
result.dependencies[0].should.be.an.instanceOf(DepReference);
result.dependencies[1].should.be.an.instanceOf(DepReference);
expect(result.dependencies[0].getId()).to.equal('package3@1.0.0/util3');
expect(result.dependencies[1].getId()).to.equal('package4@1.0.0/util4');
});
});
it('should use inline manifest from given dependency if there is any', function () {
depRefItem.manifest = JSON.parse(pkg1);
return artifactsDepsResolver._resolveDepReferenceDependencies(depRefItem, baseUrl).then(function (result) {
expect(_fetchManifestStub.callCount).to.equal(0);
result.dependencies.should.have.lengthOf(2);
result.dependencies[0].should.be.an.instanceOf(DepReference);
result.dependencies[1].should.be.an.instanceOf(DepReference);
expect(result.dependencies[0].getId()).to.equal('package3@1.0.0/util3');
expect(result.dependencies[1].getId()).to.equal('package4@1.0.0/util4');
});
});
it('should use manifest from responseCache if there is already one for given webpackageId', function () {
artifactsDepsResolver._responseCache.addItem(depRefItem.webpackageId, JSON.parse(pkg1));
return artifactsDepsResolver._resolveDepReferenceDependencies(depRefItem, baseUrl).then(function (result) {
expect(_fetchManifestStub.callCount).to.equal(0);
result.dependencies.should.have.lengthOf(2);
result.dependencies[0].should.be.an.instanceOf(DepReference);
result.dependencies[1].should.be.an.instanceOf(DepReference);
expect(result.dependencies[0].getId()).to.equal('package3@1.0.0/util3');
expect(result.dependencies[1].getId()).to.equal('package4@1.0.0/util4');
});
});
it('should add inline or requested manifest to response cache if there is no entry for corresponding webpackageId', function () {
return artifactsDepsResolver._resolveDepReferenceDependencies(depRefItem, baseUrl).then(function (result) {
expect(artifactsDepsResolver._responseCache.get(depRefItem.webpackageId)).to.eql(JSON.parse(pkg1));
});
});
it('should request manifest files from given baseUrl', function () {
var baseUrl = 'https://www.example.test/';
return artifactsDepsResolver._resolveDepReferenceDependencies(depRefItem, baseUrl).then(function (result) {
expect(_fetchManifestStub.calledWith(baseUrl + depRefItem.webpackageId + '/manifest.webpackage'));
});
});
it('should append \'/\' to baseUrl if not present', function () {
var baseUrl = 'https://www.example.test';
return artifactsDepsResolver._resolveDepReferenceDependencies(depRefItem, baseUrl).then(function (result) {
expect(_fetchManifestStub.calledWith(baseUrl + '/' + depRefItem.webpackageId + '/manifest.webpackage'));
});
});
describe('Error handling', function () {
it('should throw an TypeError if parameter baseUrl is not given or a not of type string', function () {
try {
artifactsDepsResolver._resolveDepReferenceDependencies(depRefItem, {});
} catch (error) {
expect(error).to.be.an.instanceOf(TypeError);
}
});
it('should throw an TypeError if parameter depReference is not an instance of DependencyMgr.DepReference', function () {
try {
artifactsDepsResolver._resolveDepReferenceDependencies({}, baseUrl);
} catch (error) {
expect(error).to.be.an.instanceOf(TypeError);
}
});
it('should reject returned promise if there is an error while fetching the manifest', function () {
depRefItem.webpackageId = 'error';
return artifactsDepsResolver._resolveDepReferenceDependencies(depRefItem, baseUrl).then(function (result) {
throw new Error('Promise was unexpectedly fulfilled. Result: ' + result);
}, function (error) {
error.should.have.ownProperty('message');
});
});
});
});
describe('#_extractArtifact()', function () {
var depRefItem;
before(function () {
artifactsDepsResolver = new ArtifactsDepsResolver();
depRefItem = new DepReference({webpackageId: 'package1@1.0.0', artifactId: 'util1', referrer: null});
});
it('should return require artifact', function () {
var artifact = artifactsDepsResolver._extractArtifact(depRefItem, JSON.parse(pkg1));
expect(artifact).to.deep.equal(JSON.parse(pkg1).artifacts.utilities[0]);
});
it('should return null since artifact is not in manifest', function () {
var artifact = artifactsDepsResolver._extractArtifact(depRefItem, JSON.parse(pkg2));
expect(artifact).to.be.equal(undefined);
});
});
describe('#_createDepReferenceListFromArtifactDependencies()', function () {
beforeEach(function () {
artifactsDepsResolver = new ArtifactsDepsResolver();
});
it('should create a list of DepReference items from given list of dependencies', function () {
var referrer = {
webpackageId: 'testWebpackagePackageId',
artifactId: 'testArtifactId'
};
var depList = artifactsDepsResolver._createDepReferenceListFromArtifactDependencies(rootDepList, referrer);
expect(depList).to.have.lengthOf(2);
var item = depList[0];
item.artifactId.should.equal('util1');
item.webpackageId.should.equal('package1@1.0.0');
item.referrer[0].should.eql(referrer);
item.dependencyExcludes.should.eql([]);
item = depList[1];
item.artifactId.should.equal('util2');
item.webpackageId.should.equal('package2@1.0.0');
item.referrer[0].should.eql(referrer);
item.dependencyExcludes.should.eql([]);
});
it('should set referrer to "root" if param referrer is set to null', function () {
var item = artifactsDepsResolver._createDepReferenceListFromArtifactDependencies(rootDepList, null)[0];
item.referrer[0].should.equal('root');
});
});
describe('#_determineWebpackageId()', function () {
var referrer;
var dependency;
before(function () {
artifactsDepsResolver = new ArtifactsDepsResolver();
referrer = {
webpackageId: 'testWebpackagePackageId',
artifactId: 'testArtifactId'
};
});
it('should determine webpackageId from dependency', function () {
dependency = {
webpackageId: 'testWebpackagePackageId2',
artifactId: 'testArtifactId2'
};
var webpackageId = artifactsDepsResolver._determineWebpackageId(dependency, referrer);
expect(webpackageId).to.be.equal(dependency.webpackageId);
});
it('should determine webpackageId from referrer', function () {
dependency = {};
var webpackageId = artifactsDepsResolver._determineWebpackageId(dependency, referrer);
expect(webpackageId).to.be.equal(referrer.webpackageId);
});
describe('Error Handling', function () {
var consoleSpy;
before(function () {
dependency = {};
referrer = null;
});
beforeEach(function () {
consoleSpy = sinon.spy(console, 'error');
});
afterEach(function () {
consoleSpy.restore();
});
it('should return \'\'since webpackageId could not be determined', function () {
var webpackageId = artifactsDepsResolver._determineWebpackageId(dependency, referrer);
expect(webpackageId).to.be.equal('');
});
it('should log an error since webpackageId could not be determined', function () {
artifactsDepsResolver._determineWebpackageId(dependency, referrer);
expect(consoleSpy).to.be.calledOnce;
});
});
});
describe('#_checkDepTreeForExcludes()', function () {
var baseUrl;
var depTree;
var spy;
var spy2;
var stub;
beforeEach(function () {
rootDepList = JSON.parse(fs.readFileSync(path.join(resourcesPath, 'rootDependencies.json'), 'utf8'));
// add an dependencyExclude to rootDependencies
rootDepList[0].dependencyExcludes = [
{webpackageId: 'packageToExclude', artifactId: 'artifactToExclude'}
];
artifactsDepsResolver = new ArtifactsDepsResolver();
artifactsDepsResolver.rootDependencies = rootDepList;
baseUrl = 'https://cubbles.world/sandbox/';
// spy _checkAndAddExcludesToDepReference()
spy = sinon.spy(Object.getPrototypeOf(artifactsDepsResolver), '_checkAndAddExcludesToDepReference');
// spy _checkAndAddExcludesForRootDependencies()
spy2 = sinon.spy(Object.getPrototypeOf(artifactsDepsResolver), '_checkAndAddExcludesForRootDependencies');
// stub _getManifestForDepReference()
stub = sinon.stub(Object.getPrototypeOf(artifactsDepsResolver), '_getManifestForDepReference').callsFake(function (depRefItem, baseUrl) {
var manifest;
switch (depRefItem.webpackageId) {
case 'package1@1.0.0':
manifest = JSON.parse(pkg1);
// add some excludes
manifest.artifacts.utilities[0].dependencyExcludes = [
{webpackageId: 'anotherPackageExclude', artifactId: 'anotherArtifactExclude'}
];
break;
case 'package3@1.0.0':
manifest = JSON.parse(pkg3);
// add some excludes
manifest.artifacts.utilities[0].dependencyExcludes = [
{webpackageId: 'packageToExclude', artifactId: 'artifactToExclude'},
{webpackageId: 'packageToExclude_2', artifactId: 'artifactToExclude_2'}
];
break;
case 'package4@1.0.0':
manifest = JSON.parse(pkg4);
break;
case 'package5@1.0.0':
manifest = JSON.parse(pkg5);
}
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (manifest) {
resolve(manifest);
} else {
reject(); // eslint-disable-line prefer-promise-reject-errors
}
}, 200);
});
});
/**
* Build the following tree:
*
* package1@1.0.0/util1
* / \
* / \
* package3@1.0.0/util3 package4@1.0.0/util4
* |
* |
* package5@1.0.0/util5
*/
depTree = new DependencyTree();
var root = new DependencyTree.Node();
root.data = new DepReference({webpackageId: 'package1@1.0.0', artifactId: 'util1', referrer: null});
depTree.insertNode(root);
var childA = new DependencyTree.Node();
childA.data = new DepReference({
webpackageId: 'package3@1.0.0',
artifactId: 'util3',
referrer: {webpackageId: 'package1@1.0.0', artifactId: 'util1'}
});
depTree.insertNode(childA, root);
var childB = new DependencyTree.Node();
childB.data = new DepReference({
webpackageId: 'package4@1.0.0',
artifactId: 'util4',
referrer: {webpackageId: 'package1@1.0.0', artifactId: 'util1'}
});
depTree.insertNode(childB, root);
var childA1 = new DependencyTree.Node();
childA1.data = new DepReference({
webpackageId: 'package5@1.0.0',
artifactId: 'util5',
referrer: {webpackageId: 'package4@1.0.0', artifactId: 'util4'}
});
depTree.insertNode(childA1, childA);
});
afterEach(function () {
spy.restore();
spy2.restore();
stub.restore();
});
it('should return promise which will be resolved with given DependencyTree', function () {
var promise = artifactsDepsResolver._checkDepTreeForExcludes(depTree, baseUrl);
expect(promise).to.be.an.instanceOf(Promise);
return promise.then(function (result) {
result.should.be.an.instanceof(DependencyTree);
});
});
it('should call _checkAndAddExcludesToDepReference() for each Node in DependencyTree and assign dependencyExcludes if there are any', function () {
return artifactsDepsResolver._checkDepTreeForExcludes(depTree, baseUrl).then(function () {
expect(spy.callCount).to.eql(4);
expect(spy.getCall(0).args[0].getId()).to.equal('package1@1.0.0/util1');
expect(spy.getCall(1).args[0].getId()).to.equal('package3@1.0.0/util3');
expect(spy.getCall(2).args[0].getId()).to.equal('package4@1.0.0/util4');
expect(spy.getCall(3).args[0].getId()).to.equal('package5@1.0.0/util5');
depTree._rootNodes[0].data.should.have.ownProperty('dependencyExcludes');
depTree._rootNodes[0].data.dependencyExcludes.should.eql([
{webpackageId: 'packageToExclude', artifactId: 'artifactToExclude'},
{webpackageId: 'anotherPackageExclude', artifactId: 'anotherArtifactExclude'}
]);
depTree._rootNodes[0].children[0].data.should.have.ownProperty('dependencyExcludes');
depTree._rootNodes[0].children[0].data.dependencyExcludes.should.eql([
{webpackageId: 'packageToExclude', artifactId: 'artifactToExclude'},
{webpackageId: 'packageToExclude_2', artifactId: 'artifactToExclude_2'}
]);
// console.log(depTree);
});
});
it('should call _checkAndAddExcludesForRootDependencies() for each rootNode in DependencyTree', function () {
return artifactsDepsResolver._checkDepTreeForExcludes(depTree, baseUrl).then(function () {
expect(spy2.callCount).to.eql(1);
expect(spy2.getCall(0).args[0]).to.equal(depTree._rootNodes[0]);
});
});
describe('Error handling', function () {
it('should throw an TypeError if first parameter is not an instance of DependencyMgr.DependencyTree', function () {
var errorThrown = false;
try {
artifactsDepsResolver._checkDepTreeForExcludes({}, 'http://www.example.de/test');
} catch (error) {
errorThrown = true;
error.should.be.an.instanceOf(TypeError);
} finally {
expect(errorThrown).to.be.true;
}
});
it('should throw an TypeError if second parameter is not a string', function () {
var errorThrown = false;
try {
artifactsDepsResolver._checkDepTreeForExcludes(new DependencyTree(), 123);
} catch (error) {
errorThrown = true;
error.should.be.an.instanceOf(TypeError);
} finally {
expect(errorThrown).to.be.true;
}
});
});
});
describe('#_checkAndAddExcludesForRootDependencies', function () {
var node;
beforeEach(function () {
rootDepList = JSON.parse(fs.readFileSync(path.join(resourcesPath, 'rootDependencies.json'), 'utf8'));
// add an dependencyExclude to rootDependencies
rootDepList[0].dependencyExcludes = [
{webpackageId: 'packageToExclude', artifactId: 'artifactToExclude'}
];
artifactsDepsResolver = new ArtifactsDepsResolver();
artifactsDepsResolver.rootDependencies = rootDepList;
node = new DependencyTree.Node();
node.data = new DepReference({artifactId: 'util1', webpackageId: 'package1@1.0.0', referrer: null});
});
it('should return given DependencyTree.Node', function () {
var result = artifactsDepsResolver._checkAndAddExcludesForRootDependencies(node);
result.should.equal(node);
});
it('should add dependencyExcludes from corresponding rootDependency to given node', function () {
artifactsDepsResolver._checkAndAddExcludesForRootDependencies(node);
node.data.dependencyExcludes.should.eql([{
webpackageId: 'packageToExclude',
artifactId: 'artifactToExclude'
}]);
});
describe('Error handling', function () {
it('should throw an TypeError if given parameter is not of type DependencyTree.Node', function () {
var errorThrown = false;
try {
artifactsDepsResolver._checkAndAddExcludesForRootDependencies({});
} catch (error) {
errorThrown = true;
error.should.be.an.instanceOf(TypeError);
} finally {
expect(errorThrown).to.be.true;
}
});
});
});
describe('#_getManifestForDepReference()', function () {
var baseUrl;
var depRefItem;
var fetchManifestStub;
var getItemFromCacheSpy;
beforeEach(function () {
rootDepList = JSON.parse(fs.readFileSync(path.join(resourcesPath, 'rootDependencies.json'), 'utf8'));
// add an dependencyExclude to rootDependencies
artifactsDepsResolver = new ArtifactsDepsResolver();
artifactsDepsResolver.rootDependencies = rootDepList;
baseUrl = 'http://www.example.de/';
depRefItem = new DepReference({webpackageId: 'package1@1.0.0', artifactId: 'util1', referrer: null});
fetchManifestStub = sinon.stub(Object.getPrototypeOf(artifactsDepsResolver), '_fetchManifest').callsFake(function (url) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (url.indexOf('package1@1.0.0') >= 0) {
resolve({data: JSON.parse(pkg1)});
} else {
reject({response: {status: 'timeout'}}); // eslint-disable-line prefer-promise-reject-errors
}
}, 200);
});
});
getItemFromCacheSpy = sinon.spy(artifactsDepsResolver._responseCache, 'get');
artifactsDepsResolver._responseCache.invalidate();
});
afterEach(function () {
fetchManifestStub.restore();
getItemFromCacheSpy.restore();
artifactsDepsResolver._responseCache.invalidate();
});
it('should return a promise', function () {
expect(artifactsDepsResolver._getManifestForDepReference(depRefItem, baseUrl)).to.be.an.instanceOf(Promise);
});
it('should resolve returned promise with manifest from responseCache if there is one', function () {
// put a manifest in responseCache
artifactsDepsResolver._responseCache.addItem('package1@1.0.0', JSON.parse(pkg1));
return artifactsDepsResolver._getManifestForDepReference(depRefItem).then(function (result) {
result.should.be.eql(JSON.parse(pkg1));
expect(getItemFromCacheSpy.calledOnce);
expect(fetchManifestStub.callCount).to.be.equal(0);
});
});
it('should resolve returned promise with inline manifest from depReference if there is one ' +
'and no manifest was found in responseCache', function () {
depRefItem.manifest = JSON.parse(pkg1);
return artifactsDepsResolver._getManifestForDepReference(depRefItem).then(function (result) {
result.should.be.eql(depRefItem.manifest);
expect(getItemFromCacheSpy.callCount.calledOnce);
expect(fetchManifestStub.callCount).to.be.equal(0);
});
});
it('should resolve returned promise with requested manifest from baseUrl if there is ' +
'neither a manifest in responseCache nor in inline manifest', function () {
return artifactsDepsResolver._getManifestForDepReference(depRefItem, baseUrl).then(function (result) {
result.should.be.eql(JSON.parse(pkg1));
expect(getItemFromCacheSpy.calledOnce);
expect(fetchManifestStub.calledOnce);
expect(fetchManifestStub.calledWith(baseUrl + 'package1@1.0.0/webpackage.manifest'));
});
});
describe('Error handling', function () {
it('should reject returned promise if there is an error while fetching manifest', function () {
depRefItem.webpackageId = 'timeout';
return artifactsDepsResolver._getManifestForDepReference(depRefItem, baseUrl).then(function (resolved) {
throw new Error('Promise was unexpectedly fulfilled: ', resolved);
}, function (rejected) {
rejected.should.have.property('response');
rejected.response.should.eql({status: 'timeout'});
});
});
it('should reject returned promise if baseUrl is not given when fetching manifest needs to be called', function () {
return artifactsDepsResolver._getManifestForDepReference(depRefItem).then(function (resolved) {
throw new Error('Promise was unexpectedly fulfilled: ', resolved);
}, function (rejected) {
rejected.should.be.an.instanceof(TypeError);
});
});
it('should throw a TypeError if first given parameter is not an instanceOf DepReference', function () {
var errorThrown = false;
try {
artifactsDepsResolver._getManifestForDepReference({});
} catch (e) {
errorThrown = true;
expect(e).to.be.instanceOf(TypeError);
} finally {
errorThrown.should.be.true;
}
});
});
});
describe('#_checkAndAddExcludesToDepReference()', function () {
var depRefItem;
var manifest;
beforeEach(function () {
rootDepList = JSON.parse(fs.readFileSync(path.join(resourcesPath, 'rootDependencies.json'), 'utf8'));
// add an dependencyExclude to rootDependencies
artifactsDepsResolver = new ArtifactsDepsResolver();
artifactsDepsResolver.rootDependencies = rootDepList;
manifest = {
name: 'testPackage',
groupId: 'com.test',
version: '1.0.0',
modelVersion: '9.1.0',
docType: 'webpackage',
artifacts: {
utilities: [
{
artifactId: 'testArtifact',
dependencyExcludes: [
{webpackageId: 'exclude@1', artifactId: 'util1'},
{webpackageId: 'exclude@2', artifactId: 'util2', endpointId: 'main'}
]
}
]
}
};
depRefItem = new DepReference({
webpackageId: 'com.test.testPackage@1.0.0',
artifactId: 'testArtifact',
referrer: null
});
depRefItem.dependencyExcludes = [{webpackageId: 'exludedPackage', artifactId: 'excludedArtifact'}];
});
it('should return the given DepReference instance', function () {
expect(artifactsDepsResolver._checkAndAddExcludesToDepReference(depRefItem, manifest)).to.eql(depRefItem);
});
it('should append all dependencyExcludes defined in given manifest for corresponding artifact to excludes of given DepReference', function () {
artifactsDepsResolver._checkAndAddExcludesToDepReference(depRefItem, manifest);
depRefItem.should.have.ownProperty('dependencyExcludes');
depRefItem.dependencyExcludes.should.be.eql([
{webpackageId: 'exludedPackage', artifactId: 'excludedArtifact'},
{webpackageId: 'exclude@1', artifactId: 'util1'},
{webpackageId: 'exclude@2', artifactId: 'util2', endpointId: 'main'}
]);
});
describe('Error handling', function () {
it('should throw an TypeError if first given parameter is not an instance of DepReference', function () {
var errorThrown = false;
try {
artifactsDepsResolver._checkAndAddExcludesToDepReference({}, manifest);
} catch (error) {
errorThrown = true;
error.should.be.an.instanceOf(TypeError);
} finally {
errorThrown.should.be.true;
}
});
it('should throw an TypeError if second given parameter is not an object', function () {
var errorThrown = false;
try {
artifactsDepsResolver._checkAndAddExcludesToDepReference(depRefItem, 123);
} catch (error) {
errorThrown = true;
error.should.be.an.instanceOf(TypeError);
} finally {
errorThrown.should.be.true;
}
});
});
});
describe('#_getDependencyListFromTree', function () {
var depTree;
var dep1;
var dep2;
var dep3;
var dep4;
var dep5;
var dep6;
beforeEach(function () {
artifactsDepsResolver = new ArtifactsDepsResolver();
// we need to provide a valid dependencyTree which has already excludes and duplicates removed
depTree = new DependencyTree();
dep1 = new DependencyTree.Node();
dep1.data = new DepReference({webpackageId: 'package1@1.0.0', artifactId: 'util1', referrer: null});
dep2 = new DependencyTree.Node();
dep2.data = new DepReference({webpackageId: 'package2@1.0.0', artifactId: 'util2', referrer: null});
dep3 = new DependencyTree.Node();
dep3.data = new DepReference({webpackageId: 'package3@1.0.0', artifactId: 'util3', referrer: {webpackageId: 'package1@1.0.0', artifactId: 'util1'}});
dep4 = new DependencyTree.Node();
dep4.data = new DepReference({webpackageId: 'package4@1.0.0', artifactId: 'util4', referrer: {webpackageId: 'package1@1.0.0', artifactId: 'util1'}});
dep5 = new DependencyTree.Node();
dep5.data = new DepReference({webpackageId: 'package5@1.0.0', artifactId: 'util5', referrer: {webpackageId: 'package2@1.0.0', artifactId: 'util2'}});
dep6 = new DependencyTree.Node();
dep6.data = new DepReference({webpackageId: 'package6@1.0.0', artifactId: 'util6', referrer: {webpackageId: 'package5@1.0.0', artifactId: 'util5'}});
// build dependency tree structure
depTree.insertNode(dep1);
depTree.insertNode(dep2);
depTree.insertNode(dep3, dep1);
depTree.insertNode(dep4, dep1);
depTree.insertNode(dep5, dep2);
depTree.insertNode(dep6, dep5);
dep2.usesExisting = [dep3];
dep3.usedBy = [dep2];
dep3.usesExisting = [dep5];
dep5.usedBy = [dep3];
});
it('should return an array of DepReference items', function () {
var list = artifactsDepsResolver._getDependencyListFromTree(depTree);
list.should.be.an.instanceof(Array);
list.forEach(function (item) { item.should.be.an.instanceOf(DepReference); });
});
it('should order the items in the returned array so that all dependencies of an item have a lower index the item itself', function () {
var list = artifactsDepsResolver._getDependencyListFromTree(depTree);
list[0].webpackageId.should.equal('package6@1.0.0');
list[0].artifactId.should.equal('util6');
list[1].webpackageId.should.equal('package5@1.0.0');
list[1].artifactId.should.equal('util5');
list[2].webpackageId.should.equal('package3@1.0.0');
list[2].artifactId.should.equal('util3');
list[3].webpackageId.should.equal('package4@1.0.0');
list[3].artifactId.should.equal('util4');
list[4].webpackageId.should.equal('package1@1.0.0');
list[4].artifactId.should.equal('util1');
list[5].webpackageId.should.equal('package2@1.0.0');
list[5].artifactId.should.equal('util2');
});
});
describe('#_calculateResourceList()', function () {
var internalDepList = [];
var item1;
var item2;
var item3;
const baseUrl = 'https://cubbles.world/sandbox/';
before(function () {
// add an dependencyExclude to rootDependencies
artifactsDepsResolver = new ArtifactsDepsResolver();
artifactsDepsResolver.setBaseUrl(baseUrl);
artifactsDepsResolver._runtimeMode = 'prod';
});
beforeEach(function () {
var testReferrer = {
webpackageId: 'testWebpackage',
artifactId: 'testArtifactId'
};
var items = artifactsDepsResolver._createDepReferenceListFromArtifactDependencies([
{webpackageId: 'package1@1.0.0', artifactId: 'generic1'},
{webpackageId: 'package2@1.0.0', artifactId: 'generic2'},
{webpackageId: 'package3@1.0.0', artifactId: 'util#main'}
], testReferrer);
item1 = items[ 0 ];
item2 = items[ 1 ];
item3 = items[ 2 ];
item1.resources = [
'test1_1.js',
{
prod: 'test1_2.min.css',
dev: 'test1_2.css'
},
'test1_3.html'
];
item2.resources = [
{
prod: 'test2_1.min.js',
dev: 'test2_1.js'
},
'test2_2.js',
'test2_3.html'
];
item3.resources = [
'test3-1.js'
];
internalDepList.push(item1);
internalDepList.push(item2);
internalDepList.push(item3);
});
it('should return a list of all resources in correct order for given list of DepReference items',
function () {
var resourceList = artifactsDepsResolver._calculateResourceList(internalDepList);
resourceList.should.have.length(7);
resourceList[ 0 ].should.have.property('path',
baseUrl + item1.webpackageId + '/' + item1.artifactId + '/' + item1.resources[ 0 ]);
resourceList[ 1 ].should.have.property('path',
baseUrl + item1.webpackageId + '/' + item1.artifactId + '/' +
item1.resources[ 1 ].prod);
resourceList[ 2 ].should.have.property('path',
baseUrl + item1.webpackageId + '/' + item1.artifactId + '/' + item1.resources[ 2 ]);
resourceList[ 3 ].should.have.property('path',
baseUrl + item2.webpackageId + '/' + item2.artifactId + '/' +
item2.resources[ 0 ].prod);
resourceList[ 4 ].should.have.property('path',
baseUrl + item2.webpackageId + '/' + item2.artifactId + '/' + item2.resources[ 1 ]);
resourceList[ 5 ].should.have.property('path',
baseUrl + item2.webpackageId + '/' + item2.artifactId + '/' + item2.resources[ 2 ]);
});
it('should ignore endpointId appendix on artifacts that where converted by the manifestConverter', function () {
var resourceList = artifactsDepsResolver._calculateResourceList(internalDepList);
resourceList[ 6 ].should.have.property('path',
baseUrl + item3.webpackageId + '/util/' + item3.resources[ 0 ]);
});
afterEach(function () {
internalDepList = [];
});
after(function () {
artifactsDepsResolver._depJson = null;
});
});
describe('#_calculateWpList()', function () {
var internalDepList = [];
var item1;
var item2;
var item3;
var expectedWpList = [];
before(function () {
// add an dependencyExclude to rootDependencies
artifactsDepsResolver = new ArtifactsDepsResolver();
artifactsDepsResolver.setBaseUrl('https://cubbles.world/sandbox/');
});
beforeEach(function () {
var testReferrer = {
webpackageId: 'testWebpackage',
artifactId: 'testArtifactId'
};
var items = artifactsDepsResolver._createDepReferenceListFromArtifactDependencies([
{webpackageId: 'package1@1.0.0', artifactId: 'generic1'},
{webpackageId: 'package2@1.0.0', artifactId: 'generic2'},
{webpackageId: 'package3@1.0.0', artifactId: 'util#main'}
], testReferrer);
item1 = items[ 0 ];
item2 = items[ 1 ];
item3 = items[ 2 ];
internalDepList.push(item1);
internalDepList.push(item2);
internalDepList.push(item3);
expectedWpList.push(item1.webpackageId);
expectedWpList.push(item2.webpackageId);
expectedWpList.push(item3.webpackageId);
});
it('should return a list of all wp in correct order for given list of DepReference items',
function () {
var wpList = artifactsDepsResolver._calculateWpList(internalDepList);
expect(wpList).be.deep.equal(expectedWpList);
});
});
describe('#_createResourceFromItem()', function () {
var item = {
prod: 'test.min.js',
dev: 'test.js'
};
var id = 'package1-1.0.0/my-artifact';
var stringItem = 'test.css';
before(function () {
artifactsDepsResolver = new ArtifactsDepsResolver();
artifactsDepsResolver.setBaseUrl('');
});
it('should throw TypeError', function () {
expect(artifactsDepsResolver._createResourceFromItem).to.throw(TypeError);
});
it('should create a new resource containing file and type for item given as object', function () {
var resource = artifactsDepsResolver._createResourceFromItem(id, item, 'prod');
expect(resource).to.have.property('path');
expect(resource).to.have.property('type');
expect(resource.path).to.equal('/' + id + '/' + item.prod);
expect(resource.type).to.equal('javascript');
});
it('should create a new resource containing file and type for item given as string', function () {
var resource = artifactsDepsResolver._createResourceFromItem(id, stringItem, 'prod');
expect(resource).to.have.property('path');
expect(resource).to.have.property('type');
expect(resource.path).to.equal('/' + id + '/' + stringItem);
expect(resource.type).to.equal('stylesheet');
});
it('should use "prod" file path if parameter "runtimeMode" has value "prod"', function () {
var resource = artifactsDepsResolver._createResourceFromItem(id, item, 'prod');
expect(resource.path).to.equal('/' + id + '/' + item.prod);
});
it('should use "dev" file path if parameter "runtimeMode" has value "dev"', function () {
var resource = artifactsDepsResolver._createResourceFromItem(id, item, 'dev');
expect(resource.path).to.equal('/' + id + '/' + item.dev);
});
it('should add the baseUrl as prefix for all files if some url is given', function () {
const baseUrl = 'https://cubbles.world/sandbox/';
artifactsDepsResolver.setBaseUrl(baseUrl);
var resource = artifactsDepsResolver._createResourceFromItem(id, item, 'prod');
resource.should.have.property('path', baseUrl + id + '/' + item.prod);
resource.should.have.property('type', 'javascript');
artifactsDepsResolver.setBaseUrl('');
});
});
describe('#_determineResourceType()', function () {
before(function () {
artifactsDepsResolver = new ArtifactsDepsResolver();
});
it('should associate fileEnding ".js" with type "javascript"', function () {
var fileName = 'test.min.js';
var erg = artifactsDepsResolver._determineResourceType(fileName);
erg.fileType.name.should.eql('javascript');
});
it('should associate fileEnding ".css" with type "stylesheet"', function () {
var fileName = 'test.min.css';
var erg = artifactsDepsResolver._determineResourceType(fileName);
erg.fileType.name.should.eql('stylesheet');
});
it('should associate fileEnding ".html" and ".htm" with type "htmlImport"', function () {
var fileName = 'import.html';
var erg = artifactsDepsResolver._determineResourceType(fileName);
erg.fileType.name.should.eql('htmlImport');
fileName = 'import.htm';
erg = artifactsDepsResolver._determineResourceType(fileName);
erg.fileType.name.should.eql('htmlImport');
});
it('should associate type parameter "js" with type "javascript"', function () {
var fileName = 'blob:http://xxxxxx?type=js';
var erg = artifactsDepsResolver._determineResourceType(fileName);
erg.fileType.name.should.eql('javascript');
erg.fileName.should.equal('blob:http://xxxxxx');
});
it('should associate type parameter "html" with type "htmlImport"', function () {
var fileName = 'blob:http://xxxxxx?type=html';
var erg = artifactsDepsResolver._determineResourceType(fileName);
erg.fileType.name.should.eql('htmlImport');
erg.fileName.should.equal('blob:http://xxxxxx');
});
it('should associate type parameter "css" with type "stylesheet"', function () {
var fileName = 'blob:http://xxxxxx?type=css';
var erg = artifactsDepsResolver._determineResourceType(fileName);
erg.fileType.name.should.eql('stylesheet');
erg.fileName.should.equal('blob:http://xxxxxx');
});
it('should associate type parameter "js" with type "javascript"', function () {
var fileName = 'blob:http://xxxxxx?type=xxx';
var erg = artifactsDepsResolver._determineResourceType(fileName);
erg.should.have.property('fileType', undefined);
erg.fileName.should.equal('blob:http://xxxxxx');
});
it('should associate type parameter "js" with type "javascript"', function () {
var fileName = 'blob:http://xxxxxx';
var erg = artifactsDepsResolver._determineResourceType(fileName);
erg.should.have.property('fileType', undefined);
erg.fileName.should.equal('blob:http://xxxxxx');
});
it('should associate type parameter "js" with type "javascript"', function () {
var fileName = 'blob:http://xxxxxx?yyy';
var erg = artifactsDepsResolver._determineResourceType(fileName);
erg.should.have.property('fileType', undefined);
erg.fileName.should.equal('blob: