@teambit/lanes
Version:
624 lines (613 loc) • 25.3 kB
JavaScript
"use strict";
function _chai() {
const data = require("chai");
_chai = function () {
return data;
};
return data;
}
function _fsExtra() {
const data = _interopRequireDefault(require("fs-extra"));
_fsExtra = function () {
return data;
};
return data;
}
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
function _harmonyTesting() {
const data = require("@teambit/harmony.testing.load-aspect");
_harmonyTesting = function () {
return data;
};
return data;
}
function _remove() {
const data = require("@teambit/remove");
_remove = function () {
return data;
};
return data;
}
function _snapping() {
const data = require("@teambit/snapping");
_snapping = function () {
return data;
};
return data;
}
function _workspace() {
const data = require("@teambit/workspace");
_workspace = function () {
return data;
};
return data;
}
function _export() {
const data = require("@teambit/export");
_export = function () {
return data;
};
return data;
}
function _workspaceTesting() {
const data = require("@teambit/workspace.testing.mock-workspace");
_workspaceTesting = function () {
return data;
};
return data;
}
function _componentTesting() {
const data = require("@teambit/component.testing.mock-components");
_componentTesting = function () {
return data;
};
return data;
}
function _lanesEntities() {
const data = require("@teambit/lanes.entities.lane-diff");
_lanesEntities = function () {
return data;
};
return data;
}
function _lanes() {
const data = require("./lanes.aspect");
_lanes = function () {
return data;
};
return data;
}
function _mergeLanes() {
const data = require("@teambit/merge-lanes");
_mergeLanes = function () {
return data;
};
return data;
}
function _graphql() {
const data = require("@teambit/graphql");
_graphql = function () {
return data;
};
return data;
}
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
describe('LanesAspect', function () {
this.timeout(0);
describe('getLanes()', () => {
let lanes;
let workspaceData;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
await (0, _componentTesting().mockComponents)(workspacePath);
lanes = await (0, _harmonyTesting().loadAspect)(_lanes().LanesAspect, workspacePath);
await lanes.createLane('stage');
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('should list all lanes', async () => {
const currentLanes = await lanes.getLanes({});
(0, _chai().expect)(currentLanes).to.have.lengthOf(1);
(0, _chai().expect)(currentLanes[0].name).to.equal('stage');
});
});
describe('isLaneUpToDate', () => {
let lanes;
let snapping;
let workspaceData;
let harmony;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
await (0, _componentTesting().mockComponents)(workspacePath);
harmony = await (0, _harmonyTesting().loadManyAspects)([_snapping().SnappingAspect, _export().ExportAspect, _lanes().LanesAspect, _workspace().WorkspaceAspect], workspacePath);
snapping = harmony.get(_snapping().SnappingAspect.id);
await snapping.tag({
ids: ['comp1'],
build: false,
ignoreIssues: 'MissingManuallyConfiguredPackages'
});
const exporter = harmony.get(_export().ExportAspect.id);
await exporter.export();
lanes = harmony.get(_lanes().LanesAspect.id);
await lanes.createLane('stage');
await (0, _componentTesting().modifyMockedComponents)(workspacePath, 'v2');
const result = await snapping.snap({
pattern: 'comp1',
build: false,
ignoreIssues: 'MissingManuallyConfiguredPackages'
});
// intermediate step, make sure it is snapped
(0, _chai().expect)(result?.snappedComponents.length).to.equal(1);
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('should return that the lane is up to date when the lane is ahead of main', async () => {
const currentLane = await lanes.getCurrentLane();
if (!currentLane) throw new Error('unable to get the current lane');
const isUpToDate = (await lanes.diffStatus(currentLane.toLaneId(), undefined, {
skipChanges: true
})).componentsStatus.every(c => c.upToDate);
(0, _chai().expect)(isUpToDate).to.be.true;
});
it('should return that the lane is not up to date when main is ahead', async () => {
const currentLane = await lanes.getCurrentLane();
if (!currentLane) throw new Error('unable to get the current lane');
await lanes.switchLanes('main', {
skipDependencyInstallation: true
});
await snapping.snap({
pattern: 'comp1',
build: false,
unmodified: true,
ignoreIssues: 'MissingManuallyConfiguredPackages'
});
const isUpToDate = (await lanes.diffStatus(currentLane.toLaneId(), undefined, {
skipChanges: true
})).componentsStatus.every(c => c.upToDate);
(0, _chai().expect)(isUpToDate).to.be.false;
});
});
describe('laneDiff', () => {
let harmony;
let lanes;
let snapping;
let workspaceData;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
await (0, _componentTesting().mockComponents)(workspacePath);
harmony = await (0, _harmonyTesting().loadManyAspects)([_snapping().SnappingAspect, _export().ExportAspect, _lanes().LanesAspect, _workspace().WorkspaceAspect], workspacePath);
snapping = harmony.get(_snapping().SnappingAspect.id);
await snapping.tag({
ids: ['comp1'],
build: false
});
const exporter = harmony.get(_export().ExportAspect.id);
await exporter.export();
lanes = harmony.get(_lanes().LanesAspect.id);
await lanes.createLane('stage');
const result = await snapping.snap({
pattern: 'comp1',
build: false,
unmodified: true
});
// intermediate step, make sure it is snapped
(0, _chai().expect)(result?.snappedComponents.length).to.equal(1);
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('should return that the lane is up to date when the lane is ahead of main', async () => {
const currentLane = await lanes.getCurrentLane();
if (!currentLane) throw new Error('unable to get the current lane');
const laneDiffResults = await lanes.diffStatus(currentLane.toLaneId());
(0, _chai().expect)(laneDiffResults.componentsStatus[0].upToDate).to.be.true;
(0, _chai().expect)(laneDiffResults.componentsStatus[0].changeType).to.equal(_lanesEntities().ChangeType.NONE);
});
it('should return that the lane is not up to date when main is ahead', async () => {
const currentLane = await lanes.getCurrentLane();
if (!currentLane) throw new Error('unable to get the current lane');
await lanes.switchLanes('main', {
skipDependencyInstallation: true
});
await snapping.snap({
pattern: 'comp1',
build: false,
unmodified: true
});
const laneDiffResults = await lanes.diffStatus(currentLane.toLaneId());
(0, _chai().expect)(laneDiffResults.componentsStatus[0].upToDate).to.be.false;
(0, _chai().expect)(laneDiffResults.componentsStatus[0].changeType).to.equal(_lanesEntities().ChangeType.NONE);
});
});
describe('restoreLane()', () => {
let lanes;
let workspaceData;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
await (0, _componentTesting().mockComponents)(workspacePath);
lanes = await (0, _harmonyTesting().loadAspect)(_lanes().LanesAspect, workspacePath);
await lanes.createLane('stage');
// as an intermediate step, make sure the lane was created
const currentLanes = await lanes.getLanes({});
(0, _chai().expect)(currentLanes).to.have.lengthOf(1);
await lanes.switchLanes('main', {
skipDependencyInstallation: true
});
await lanes.removeLanes(['stage']);
// as an intermediate step, make sure the lane was removed
const lanesAfterDelete = await lanes.getLanes({});
(0, _chai().expect)(lanesAfterDelete).to.have.lengthOf(0);
await lanes.restoreLane(currentLanes[0].hash);
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('should restore the deleted lane', async () => {
const currentLanes = await lanes.getLanes({});
(0, _chai().expect)(currentLanes).to.have.lengthOf(1);
(0, _chai().expect)(currentLanes[0].id.name).to.equal('stage');
});
describe('delete restored lane', () => {
let output;
before(async () => {
output = await lanes.removeLanes(['stage']);
});
it('should not throw', () => {
(0, _chai().expect)(output).to.have.lengthOf(1);
});
});
});
describe('restore lane when an existing lane has the same id', () => {
let lanes;
let workspaceData;
let laneHash;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
await (0, _componentTesting().mockComponents)(workspacePath);
lanes = await (0, _harmonyTesting().loadAspect)(_lanes().LanesAspect, workspacePath);
await lanes.createLane('stage');
// as an intermediate step, make sure the lane was created
const currentLanes = await lanes.getLanes({});
(0, _chai().expect)(currentLanes).to.have.lengthOf(1);
await lanes.switchLanes('main', {
skipDependencyInstallation: true
});
await lanes.removeLanes(['stage']);
await lanes.createLane('stage');
laneHash = currentLanes[0].hash;
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('should throw when restoring the lane', async () => {
let error;
try {
await lanes.restoreLane(laneHash);
} catch (err) {
error = err;
}
(0, _chai().expect)(error).to.be.instanceOf(Error);
(0, _chai().expect)(error?.message).to.include('unable to restore lane');
});
});
describe('lane history', () => {
let lanes;
let workspaceData;
let snapping;
let laneId;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
await (0, _componentTesting().mockComponents)(workspacePath);
lanes = await (0, _harmonyTesting().loadAspect)(_lanes().LanesAspect, workspacePath);
await lanes.createLane('stage');
snapping = await (0, _harmonyTesting().loadAspect)(_snapping().SnappingAspect, workspacePath);
const currentLaneId = lanes.getCurrentLaneId();
if (!currentLaneId) throw new Error('unable to get the current lane-id');
laneId = currentLaneId;
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('should create lane history object when creating a new lane', async () => {
const laneHistory = await lanes.getLaneHistory(laneId);
const history = laneHistory.getHistory();
(0, _chai().expect)(Object.keys(history).length).to.equal(1);
});
describe('snapping', () => {
let snappingResult;
before(async () => {
snappingResult = await snapping.snap({
pattern: 'comp1',
build: false,
message: 'first snap'
});
});
it('should add a record to LaneHistory when snapping', async () => {
const laneHistory = await lanes.getLaneHistory(laneId);
const history = laneHistory.getHistory();
(0, _chai().expect)(Object.keys(history).length).to.equal(2);
const snapHistory = history[Object.keys(history)[1]];
(0, _chai().expect)(snapHistory.log.message).to.equal('snap (first snap)');
(0, _chai().expect)(snapHistory.components.length).to.equal(1);
(0, _chai().expect)(snapHistory.components[0]).to.equal(snappingResult?.snappedComponents[0].id.toString());
});
describe('snap again and export', () => {
let exportResults;
before(async () => {
const compFile = _path().default.join(workspaceData.workspacePath, 'comp1/index.js');
await _fsExtra().default.appendFile(compFile, `\nconsole.log('second-snap');`);
// make another snap to check to test the checkout later.
await snapping.snap({
pattern: 'comp1',
build: false,
message: 'second snap'
});
const laneHistory = await lanes.getLaneHistory(laneId);
const history = laneHistory.getHistory();
(0, _chai().expect)(Object.keys(history).length).to.equal(3);
const exporter = await (0, _harmonyTesting().loadAspect)(_export().ExportAspect, workspaceData.workspacePath);
exportResults = await exporter.export();
});
it('should export successfully', () => {
(0, _chai().expect)(exportResults.componentsIds.length).to.equal(1);
(0, _chai().expect)(exportResults.exportedLanes.length).to.equal(1);
});
describe('import to another workspace', () => {
let newWorkspace;
before(async () => {
newWorkspace = (0, _workspaceTesting().mockWorkspace)({
bareScopeName: workspaceData.remoteScopeName
});
lanes = await (0, _harmonyTesting().loadAspect)(_lanes().LanesAspect, newWorkspace.workspacePath);
await lanes.switchLanes(laneId.toString(), {
skipDependencyInstallation: true
});
await lanes.importLaneObject(laneId, true, true);
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(newWorkspace);
});
it('should not add a record to the lane-history', async () => {
const laneHistory = await lanes.getLaneHistory(laneId);
const history = laneHistory.getHistory();
(0, _chai().expect)(Object.keys(history).length).to.equal(3);
});
it('should be able to checkout to a previous state of the lane', async () => {
const laneHistory = await lanes.getLaneHistory(laneId);
const history = laneHistory.getHistory();
const snapHistoryId = Object.keys(history).find(key => history[key].log.message?.includes('first snap'));
if (!snapHistoryId) throw new Error('unable to find snap history of the first snap');
const results = await lanes.checkoutHistory(snapHistoryId, {
skipDependencyInstallation: true
});
(0, _chai().expect)(results.components?.length).to.equal(1);
(0, _chai().expect)(results.failedComponents?.length).to.equal(0);
});
it('should be able to revert to a previous history id', async () => {
const revertWorkspace = (0, _workspaceTesting().mockWorkspace)({
bareScopeName: workspaceData.remoteScopeName
});
lanes = await (0, _harmonyTesting().loadAspect)(_lanes().LanesAspect, revertWorkspace.workspacePath);
await lanes.switchLanes(laneId.toString(), {
skipDependencyInstallation: true
});
await lanes.importLaneObject(laneId, true, true);
const laneHistory = await lanes.getLaneHistory(laneId);
const history = laneHistory.getHistory();
const snapHistoryId = Object.keys(history).find(key => history[key].log.message?.includes('first snap'));
if (!snapHistoryId) throw new Error('unable to find snap history of the first snap');
const results = await lanes.revertHistory(snapHistoryId, {
skipDependencyInstallation: true
});
(0, _chai().expect)(results.components?.length).to.equal(1);
(0, _chai().expect)(results.failedComponents?.length).to.equal(0);
const compFile = _path().default.join(revertWorkspace.workspacePath, revertWorkspace.remoteScopeName, 'comp1/index.js');
const compFileContent = await _fsExtra().default.readFile(compFile, 'utf8');
// make sure it reverts to the first snap.
(0, _chai().expect)(compFileContent).to.not.include('second-snap');
// make sure it keeps the version in .bitmap intact and doesn't change it to the first snap. (as with checkout)
const secondSnapHistoryId = Object.keys(history).find(key => history[key].log.message?.includes('second snap'));
if (!secondSnapHistoryId) throw new Error('unable to find snap history of the second snap');
const secondSnapHistory = history[secondSnapHistoryId];
const workspace = await (0, _harmonyTesting().loadAspect)(_workspace().WorkspaceAspect, revertWorkspace.workspacePath);
const ids = await workspace.listIds();
(0, _chai().expect)(ids[0].toString()).to.equal(secondSnapHistory.components[0]);
await (0, _workspaceTesting().destroyWorkspace)(revertWorkspace);
});
});
});
});
});
describe('create lanes with the same name different scope', () => {
let lanes;
let workspaceData;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
await (0, _componentTesting().mockComponents)(workspacePath);
lanes = await (0, _harmonyTesting().loadAspect)(_lanes().LanesAspect, workspacePath);
await lanes.createLane('stage');
await lanes.switchLanes('main', {
skipDependencyInstallation: true
});
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('should not throw when creating the second lane', async () => {
await lanes.createLane('stage', {
scope: 'new-scope'
});
const currentLanes = await lanes.getLanes({});
(0, _chai().expect)(currentLanes.length).to.equal(2);
(0, _chai().expect)(currentLanes[0].id.name).to.equal('stage');
(0, _chai().expect)(currentLanes[1].id.name).to.equal('stage');
});
});
// todo: fix after deleting teambit.legacy
// for some reason it is trying to add the core-aspect teambit.component/remove to the graph and then
// it complains that it has no version. from the cli it doesn't happen.
describe.skip('delete component on a lane after export', () => {
let lanes;
let workspaceData;
let snapping;
let laneId;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
await (0, _componentTesting().mockComponents)(workspacePath);
const harmony = await (0, _harmonyTesting().loadManyAspects)([_snapping().SnappingAspect, _export().ExportAspect, _remove().RemoveAspect, _workspace().WorkspaceAspect, _lanes().LanesAspect], workspaceData.workspacePath);
lanes = harmony.get(_lanes().LanesAspect.id);
await lanes.createLane('stage');
const currentLaneId = lanes.getCurrentLaneId();
if (!currentLaneId) throw new Error('unable to get the current lane-id');
laneId = currentLaneId;
snapping = harmony.get(_snapping().SnappingAspect.id);
await snapping.snap({
build: false
});
const exporter = harmony.get(_export().ExportAspect.id);
await exporter.export();
const remove = harmony.get(_remove().RemoveAspect.id);
await remove.deleteComps('comp1');
await snapping.snap({
build: false
});
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('should save the deleted data into the lane object', async () => {
const lane = await lanes.getCurrentLane();
(0, _chai().expect)(lane?.components[0].isDeleted).to.be.true;
});
it('should save the deleted data into lane history', async () => {
const laneHistory = await lanes.getLaneHistory(laneId);
const history = laneHistory.getHistory();
(0, _chai().expect)(Object.keys(history).length).to.equal(3);
const snapHistory = history[Object.keys(history)[2]];
(0, _chai().expect)(snapHistory.deleted?.length).to.equal(1);
});
});
describe('create comps on a lane then switch to main with --head', () => {
let lanes;
let workspaceData;
let snapping;
let laneId;
let harmony;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
await (0, _componentTesting().mockComponents)(workspacePath);
harmony = await (0, _harmonyTesting().loadManyAspects)([_snapping().SnappingAspect, _export().ExportAspect, _remove().RemoveAspect, _workspace().WorkspaceAspect, _lanes().LanesAspect], workspaceData.workspacePath);
lanes = harmony.get(_lanes().LanesAspect.id);
await lanes.createLane('stage');
const currentLaneId = lanes.getCurrentLaneId();
if (!currentLaneId) throw new Error('unable to get the current lane-id');
laneId = currentLaneId;
snapping = harmony.get(_snapping().SnappingAspect.id);
await snapping.snap({
build: false
});
const exporter = harmony.get(_export().ExportAspect.id);
await exporter.export();
// in another workspace, merge the lane into main.
const workspaceData2 = (0, _workspaceTesting().mockWorkspace)({
bareScopeName: workspaceData.remoteScopeName
});
const harmony2 = await (0, _harmonyTesting().loadManyAspects)([_snapping().SnappingAspect, _export().ExportAspect, _remove().RemoveAspect, _workspace().WorkspaceAspect, _lanes().LanesAspect, _mergeLanes().MergeLanesAspect], workspaceData2.workspacePath);
const mergeLanes2 = harmony2.get(_mergeLanes().MergeLanesAspect.id);
const lanes2 = harmony2.get(_lanes().LanesAspect.id);
const currentLaneId2 = lanes2.getCurrentLaneId();
await mergeLanes2.mergeLane(laneId, currentLaneId2, {
mergeStrategy: 'manual',
skipDependencyInstallation: true
});
const export2 = harmony2.get(_export().ExportAspect.id);
await export2.export();
// reload harmony, otherwise, the "lanes" aspect has the workspace of harmony2.
harmony = await (0, _harmonyTesting().loadManyAspects)([_lanes().LanesAspect], workspaceData.workspacePath);
lanes = harmony.get(_lanes().LanesAspect.id);
await lanes.switchLanes('main', {
head: true,
skipDependencyInstallation: true
});
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('the components should be available on main', () => {
const workspace = harmony.get(_workspace().WorkspaceAspect.id);
const ids = workspace.listIds();
(0, _chai().expect)(ids.length).to.equal(1);
});
});
});
/**
* TODO: this should not be here. It belongs to the GraphQL aspect.
* The reason it was moved here is that otherwise, it forms circular dependencies.
* we should think of a better way to handle this.
*/
describe('GraphQL Aspect', function () {
this.timeout(0);
describe('getSchemas and getSchema APIs', () => {
let graphql;
let workspaceData;
before(async () => {
workspaceData = (0, _workspaceTesting().mockWorkspace)();
const {
workspacePath
} = workspaceData;
const harmony = await (0, _harmonyTesting().loadManyAspects)([_workspace().WorkspaceAspect, _graphql().GraphqlAspect, _lanes().LanesAspect], workspacePath);
graphql = harmony.get(_graphql().GraphqlAspect.id);
});
after(async () => {
await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
});
it('should bring the schemas when calling getSchemas API', async () => {
const schemas = graphql.getSchemas([_lanes().LanesAspect.id]);
(0, _chai().expect)(schemas).to.be.an('array');
(0, _chai().expect)(schemas).to.have.lengthOf(1);
(0, _chai().expect)(schemas[0]).to.be.an('object');
(0, _chai().expect)(schemas[0]).to.not.be.an('function');
});
it('should bring the schemas when calling getSchema API', async () => {
const schema = graphql.getSchema(_lanes().LanesAspect.id);
(0, _chai().expect)(schema).to.be.an('object');
(0, _chai().expect)(schema).to.not.be.an('function');
});
});
});
//# sourceMappingURL=lanes.spec.js.map