-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Render array moves with arrows #333
Changes from all commits
0738cf6
4357884
eac213a
38f0c46
8966ca6
accb2f2
2110adf
b9839d8
917723b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1044,59 +1044,68 @@ module.exports = function (expect) { | |
if (subjectType.indent) { | ||
output.indentLines(); | ||
} | ||
changes.forEach(function (diffItem, index) { | ||
var packing = utils.packArrows(changes); // NOTE: Will have side effects in changes if the packing results in too many arrow lanes | ||
output.arrowsAlongsideChangeOutputs(packing, changes.map(function (diffItem, index) { | ||
var delimiterOutput = subjectType.delimiter(output.clone(), index, indexOfLastNonInsert + 1); | ||
output.nl(index > 0 ? 1 : 0).i().block(function () { | ||
var type = diffItem.type; | ||
if (type === 'insert') { | ||
this.annotationBlock(function () { | ||
var index = typeof diffItem.actualIndex !== 'undefined' ? diffItem.actualIndex : diffItem.expectedIndex; | ||
if (expect.findTypeOf(diffItem.value).is('function')) { | ||
this.error('missing: ') | ||
.property(index, output.clone().block(function () { | ||
this.omitSubject = undefined; | ||
var promise = keyPromises[diffItem.expectedIndex]; | ||
if (promise.isRejected()) { | ||
this.appendErrorMessage(promise.reason()); | ||
} else { | ||
this.appendInspected(diffItem.value); | ||
} | ||
}), true); | ||
} else { | ||
this.error('missing ').property(index, inspect(diffItem.value), true); | ||
} | ||
}); | ||
} else { | ||
this.property(diffItem.actualIndex, output.clone().block(function () { | ||
if (type === 'remove') { | ||
this.append(inspect(diffItem.value).amend(delimiterOutput.sp()).error('// should be removed')); | ||
} else if (type === 'equal') { | ||
this.append(inspect(diffItem.value).amend(delimiterOutput)); | ||
} else { | ||
var toSatisfyResult = toSatisfyMatrix[diffItem.actualIndex][diffItem.expectedIndex]; | ||
var valueDiff = toSatisfyResult && toSatisfyResult !== true && toSatisfyResult.getDiff({ output: output.clone() }); | ||
if (valueDiff && valueDiff.inline) { | ||
this.append(valueDiff.amend(delimiterOutput)); | ||
var type = diffItem.type; | ||
if (type === 'moveTarget') { | ||
return output.clone(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It feels like there should be a magicpen construct to map over an array of items and produce output for each item. I know you are just cloning the output, but it feels a bit unsafe that you might append to the outside output by accident. This is just thoughts on how we might refactor later. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed! |
||
} else { | ||
return output.clone().block(function () { | ||
if (type === 'moveSource') { | ||
this.property(diffItem.actualIndex, inspect(diffItem.value), true) | ||
.amend(delimiterOutput.sp()).error('// should be moved'); | ||
} else if (type === 'insert') { | ||
this.annotationBlock(function () { | ||
var index = typeof diffItem.actualIndex !== 'undefined' ? diffItem.actualIndex : diffItem.expectedIndex; | ||
if (expect.findTypeOf(diffItem.value).is('function')) { | ||
this.error('missing: ') | ||
.property(index, output.clone().block(function () { | ||
this.omitSubject = undefined; | ||
var promise = keyPromises[diffItem.expectedIndex]; | ||
if (promise.isRejected()) { | ||
this.appendErrorMessage(promise.reason()); | ||
} else { | ||
this.appendInspected(diffItem.value); | ||
} | ||
}), true); | ||
} else { | ||
this.error('missing ').property(index, inspect(diffItem.value), true); | ||
} | ||
}); | ||
} else { | ||
this.property(diffItem.actualIndex, output.clone().block(function () { | ||
if (type === 'remove') { | ||
this.append(inspect(diffItem.value).amend(delimiterOutput.sp()).error('// should be removed')); | ||
} else if (type === 'equal') { | ||
this.append(inspect(diffItem.value).amend(delimiterOutput)); | ||
} else { | ||
this.append(inspect(diffItem.value).amend(delimiterOutput)).sp().annotationBlock(function () { | ||
this.omitSubject = diffItem.value; | ||
var label = toSatisfyResult.getLabel(); | ||
if (label) { | ||
this.error(label).sp() | ||
.block(inspect(diffItem.expected)); | ||
if (valueDiff) { | ||
this.nl(2).append(valueDiff); | ||
var toSatisfyResult = toSatisfyMatrix[diffItem.actualIndex][diffItem.expectedIndex]; | ||
var valueDiff = toSatisfyResult && toSatisfyResult !== true && toSatisfyResult.getDiff({ output: output.clone() }); | ||
if (valueDiff && valueDiff.inline) { | ||
this.append(valueDiff.amend(delimiterOutput)); | ||
} else { | ||
this.append(inspect(diffItem.value).amend(delimiterOutput)).sp().annotationBlock(function () { | ||
this.omitSubject = diffItem.value; | ||
var label = toSatisfyResult.getLabel(); | ||
if (label) { | ||
this.error(label).sp() | ||
.block(inspect(diffItem.expected)); | ||
if (valueDiff) { | ||
this.nl(2).append(valueDiff); | ||
} | ||
} else { | ||
this.appendErrorMessage(toSatisfyResult); | ||
} | ||
} else { | ||
this.appendErrorMessage(toSatisfyResult); | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
} | ||
}), true); | ||
} | ||
}); | ||
}); | ||
}), true); | ||
} | ||
}); | ||
} | ||
})); | ||
|
||
if (subjectType.indent) { | ||
output.outdentLines(); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -347,4 +347,118 @@ module.exports = function (expect) { | |
} | ||
}, this); | ||
}); | ||
|
||
expect.addStyle('arrow', function (options) { | ||
options = options || {}; | ||
var styles = options.styles || []; | ||
var i; | ||
this.nl(options.top || 0).sp(options.left || 0).text('┌', styles); | ||
for (i = 1 ; i < options.width ; i += 1) { | ||
this.text(i === options.width - 1 && options.direction === 'up' ? '▷' : '─', styles); | ||
} | ||
this.nl(); | ||
for (i = 1 ; i < options.height - 1 ; i += 1) { | ||
this.sp(options.left || 0).text('│', styles).nl(); | ||
} | ||
this.sp(options.left || 0).text('└', styles); | ||
for (i = 1 ; i < options.width ; i += 1) { | ||
this.text(i === options.width - 1 && options.direction === 'down' ? '▷' : '─', styles); | ||
} | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably make a magicpen-arrow plugin. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we can make it a bit more generic, and if unexpected-htmllike/-react cannot reach this feature through the array-like type, I agree. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But it might also mean implementing a lot of features that we wont use. |
||
|
||
var flattenBlocksInLines = require('magicpen/lib/flattenBlocksInLines'); | ||
expect.addStyle('merge', function (pens) { | ||
var flattenedPens = pens.map(function (pen) { | ||
return flattenBlocksInLines(pen.output); | ||
}).reverse(); | ||
var maxHeight = flattenedPens.reduce(function (maxHeight, pen) { | ||
return Math.max(maxHeight, pen.length); | ||
}, 0); | ||
var blockNumbers = new Array(flattenedPens.length); | ||
var blockOffsets = new Array(flattenedPens.length); | ||
// As long as there's at least one pen with a line left: | ||
for (var lineNumber = 0 ; lineNumber < maxHeight ; lineNumber += 1) { | ||
if (lineNumber > 0) { | ||
this.nl(); | ||
} | ||
var i; | ||
for (i = 0 ; i < blockNumbers.length ; i += 1) { | ||
blockNumbers[i] = 0; | ||
blockOffsets[i] = 0; | ||
} | ||
var contentLeft; | ||
do { | ||
contentLeft = false; | ||
var hasOutputChar = false; | ||
for (i = 0 ; i < flattenedPens.length ; i += 1) { | ||
var currentLine = flattenedPens[i][lineNumber]; | ||
if (currentLine) { | ||
while (currentLine[blockNumbers[i]] && blockOffsets[i] >= currentLine[blockNumbers[i]].args.content.length) { | ||
blockNumbers[i] += 1; | ||
blockOffsets[i] = 0; | ||
} | ||
var currentBlock = currentLine[blockNumbers[i]]; | ||
if (currentBlock) { | ||
contentLeft = true; | ||
if (!hasOutputChar) { | ||
var ch = currentBlock.args.content.charAt(blockOffsets[i]); | ||
if (ch !== ' ') { | ||
this.text(ch, currentBlock.args.styles); | ||
hasOutputChar = true; | ||
} | ||
} | ||
blockOffsets[i] += 1; | ||
} | ||
} | ||
} | ||
if (!hasOutputChar && contentLeft) { | ||
this.sp(); | ||
} | ||
} while (contentLeft); | ||
} | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As we talked about, this style should move to magicpen core when it has proven it's stability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
expect.addStyle('arrowsAlongsideChangeOutputs', function (packing, changeOutputs) { | ||
if (packing) { | ||
var topByChangeNumber = {}; | ||
var top = 0; | ||
changeOutputs.forEach(function (changeOutput, index) { | ||
topByChangeNumber[index] = top; | ||
top += changeOutput.size().height; | ||
}); | ||
var that = this; | ||
|
||
var arrows = []; | ||
packing.forEach(function (columnSet, i, packing) { | ||
columnSet.forEach(function (entry) { | ||
arrows.push(that.clone().arrow({ | ||
left: i * 2, | ||
top: topByChangeNumber[entry.start], | ||
width: 1 + (packing.length - i) * 2, | ||
height: topByChangeNumber[entry.end] - topByChangeNumber[entry.start] + 1, | ||
direction: entry.direction | ||
})); | ||
}); | ||
}); | ||
|
||
if (arrows.length === 1) { | ||
this.block(arrows[0]); | ||
} else if (arrows.length > 1) { | ||
this.block(function () { | ||
this.merge(arrows); | ||
}); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If would be better if this was just: this.block(function () {
this.merge(arrows);
}); Magicpen should be smart enough to avoid the extra block. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and merge should be smart enough to handle one pen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The way There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ohh I though it worked that way. That is probably how I want it to work in magicpen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I agree that would be the most useful API-wise. |
||
} else { | ||
this.i(); | ||
} | ||
|
||
this.block(function () { | ||
changeOutputs.forEach(function (changeOutput, index) { | ||
this.nl(index > 0 ? 1 : 0); | ||
if (!changeOutput.isEmpty()) { | ||
this.sp(packing ? 1 : 0).append(changeOutput); | ||
} | ||
}, this); | ||
}); | ||
}); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It really has nothing to do with the PR, but I think we have crossed the line where we should split up the assertions in separates files (Not in this PR - but after). After we split the assertions into separate files, I think something like this would be much more readable if it was split into some more helper methods.