Changeset View
Changeset View
Standalone View
Standalone View
cypress/integration/revision-diff.spec.js
/** | /** | ||||
* Copyright (C) 2019 The Software Heritage developers | * Copyright (C) 2019-2020 The Software Heritage developers | ||||
* See the AUTHORS file at the top-level directory of this distribution | * See the AUTHORS file at the top-level directory of this distribution | ||||
* License: GNU Affero General Public License version 3, or any later version | * License: GNU Affero General Public License version 3, or any later version | ||||
* See top-level LICENSE file for more information | * See top-level LICENSE file for more information | ||||
*/ | */ | ||||
let origin; | const $ = Cypress.$; | ||||
const origin = 'https://github.com/memononen/libtess2'; | |||||
const revision = '98c65dad5e47ad888032b6cdf556f192e0e028d0'; | |||||
const diffsHighlightingData = { | |||||
'unified': { | |||||
diffId: '3d4c0797cf0e89430410e088339aac384dfa4d82', | |||||
startLines: [913, 915], | |||||
endLines: [0, 979] | |||||
}, | |||||
'split-from': { | |||||
diffId: '602cec77c3d3f41d396d9e1083a0bbce0796b505', | |||||
startLines: [192, 0], | |||||
endLines: [198, 0] | |||||
}, | |||||
'split-to': { | |||||
diffId: '602cec77c3d3f41d396d9e1083a0bbce0796b505', | |||||
startLines: [0, 120], | |||||
endLines: [0, 130] | |||||
}, | |||||
'split-from-top-to-bottom': { | |||||
diffId: 'a00c33990655a93aa2c821c4008bbddda812a896', | |||||
startLines: [63, 0], | |||||
endLines: [0, 68] | |||||
}, | |||||
'split-to-top-from-bottom': { | |||||
diffId: 'a00c33990655a93aa2c821c4008bbddda812a896', | |||||
startLines: [0, 63], | |||||
endLines: [67, 0] | |||||
} | |||||
}; | |||||
let diffData; | let diffData; | ||||
let swh; | |||||
describe('Test Diffs View', function() { | describe('Test Diffs View', function() { | ||||
before(function() { | |||||
origin = this.origin[0]; | |||||
const url = this.Urls.browse_revision(origin.revisions[0]) + `?origin=${origin.url}`; | |||||
cy.visit(url).window().then(win => { | beforeEach(function() { | ||||
const url = this.Urls.browse_revision(revision) + `?origin=${origin}`; | |||||
cy.visit(url); | |||||
cy.window().then(win => { | |||||
swh = win.swh; | |||||
cy.request(win.diffRevUrl) | cy.request(win.diffRevUrl) | ||||
.then(res => { | .then(res => { | ||||
diffData = res.body; | diffData = res.body; | ||||
}); | }); | ||||
}); | }); | ||||
}); | |||||
beforeEach(function() { | |||||
const url = this.Urls.browse_revision(origin.revisions[0]) + `?origin=${origin.url}`; | |||||
cy.visit(url); | |||||
cy.get('a[data-toggle="tab"]') | cy.get('a[data-toggle="tab"]') | ||||
.contains('Changes') | .contains('Changes') | ||||
.click(); | .click(); | ||||
}); | }); | ||||
it('should list all files with changes', function() { | it('should list all files with changes', function() { | ||||
let files = new Set([]); | let files = new Set([]); | ||||
for (let change of diffData.changes) { | for (let change of diffData.changes) { | ||||
Show All 25 Lines | cy.get('#swh-revision-changes-list a') | ||||
cy.get($el.attr('href')) | cy.get($el.attr('href')) | ||||
.find('.swh-content') | .find('.swh-content') | ||||
.should('be.visible'); | .should('be.visible'); | ||||
}); | }); | ||||
}); | }); | ||||
it('should have correct links in diff file names', function() { | it('should have correct links in diff file names', function() { | ||||
for (let change of diffData.changes) { | for (let change of diffData.changes) { | ||||
cy.get(`#swh-revision-changes-list a[href="#panel_${change.id}"`) | cy.get(`#swh-revision-changes-list a[href="#diff_${change.id}"`) | ||||
.should('be.visible'); | .should('be.visible'); | ||||
} | } | ||||
}); | }); | ||||
it('should load unified diff by default', function() { | it('should load unified diff by default', function() { | ||||
cy.get('#swh-compute-all-diffs') | cy.get('#swh-compute-all-diffs') | ||||
.click(); | .click(); | ||||
for (let change of diffData.changes) { | for (let change of diffData.changes) { | ||||
cy.get(`#${change.id}-unified-diff`) | cy.get(`#${change.id}-unified-diff`) | ||||
.should('be.visible'); | .should('be.visible'); | ||||
cy.get(`#${change.id}-splitted-diff`) | cy.get(`#${change.id}-split-diff`) | ||||
.should('not.be.visible'); | .should('not.be.visible'); | ||||
} | } | ||||
}); | }); | ||||
it('should switch between unified and side-by-side diff when selected', function() { | it('should switch between unified and side-by-side diff when selected', function() { | ||||
// Test for first diff | // Test for first diff | ||||
const id = diffData.changes[0].id; | const id = diffData.changes[0].id; | ||||
cy.get(`#panel_${id}`) | cy.get(`#diff_${id}`) | ||||
.contains('label', 'Side-by-side') | .contains('label', 'Side-by-side') | ||||
.click(); | .click(); | ||||
cy.get(`#${id}-splitted-diff`) | cy.get(`#${id}-split-diff`) | ||||
.should('be.visible') | .should('be.visible') | ||||
.get(`#${id}-unified-diff`) | .get(`#${id}-unified-diff`) | ||||
.should('not.be.visible'); | .should('not.be.visible'); | ||||
}); | }); | ||||
function checkDiffHighlighted(diffId, start, end) { | |||||
cy.get(`#${diffId} .hljs-ln-line`) | |||||
.then(lines => { | |||||
let inHighlightedRange = false; | |||||
for (let line of lines) { | |||||
const lnNumber = $(line).data('line-number'); | |||||
if (lnNumber === start || lnNumber === end) { | |||||
inHighlightedRange = true; | |||||
} | |||||
const mixBlendMode = $(line).css('mix-blend-mode'); | |||||
if (inHighlightedRange && parseInt(lnNumber)) { | |||||
assert.equal(mixBlendMode, 'multiply'); | |||||
} else { | |||||
assert.equal(mixBlendMode, 'normal'); | |||||
} | |||||
if (lnNumber === end) { | |||||
inHighlightedRange = false; | |||||
} | |||||
} | |||||
}); | |||||
} | |||||
function unifiedDiffHighlightingTest(diffId, startLines, endLines) { | |||||
// render diff | |||||
cy.get(`#diff_${diffId}`) | |||||
.scrollIntoView() | |||||
.get(`#${diffId}-unified-diff`) | |||||
.should('be.visible') | |||||
// ensure all asynchronous treatments in the page have been performed | |||||
// before testing diff highlighting | |||||
.then(() => { | |||||
let startLinesStr = swh.revision.formatDiffLineNumbers(diffId, startLines[0], startLines[1]); | |||||
let endLinesStr = swh.revision.formatDiffLineNumbers(diffId, endLines[0], endLines[1]); | |||||
// highlight a range of lines | |||||
let startElt = `#${diffId}-unified-diff .hljs-ln-numbers[data-line-number="${startLinesStr}"]`; | |||||
let endElt = `#${diffId}-unified-diff .hljs-ln-numbers[data-line-number="${endLinesStr}"]`; | |||||
cy.get(startElt).click(); | |||||
cy.get('body').type(`{shift}`, { | |||||
release: false | |||||
}); | |||||
cy.get(endElt).click(); | |||||
// check URL fragment has been updated | |||||
const selectedLinesFragment = | |||||
swh.revision.selectedDiffLinesToFragment(startLines, endLines, true); | |||||
cy.hash().should('be.equal', `#diff_${diffId}+${selectedLinesFragment}`); | |||||
if ($(endElt).position().top < $(startElt).position().top) { | |||||
[startLinesStr, endLinesStr] = [endLinesStr, startLinesStr]; | |||||
} | |||||
// check lines range is highlighted | |||||
checkDiffHighlighted(`${diffId}-unified-diff`, startLinesStr, endLinesStr); | |||||
// check selected diff lines get highlighted when reloading page | |||||
// with highlighting info in URL fragment | |||||
cy.reload(); | |||||
cy.get(`#diff_${diffId}`) | |||||
.get(`#${diffId}-unified-diff`) | |||||
.should('be.visible'); | |||||
checkDiffHighlighted(`${diffId}-unified-diff`, startLinesStr, endLinesStr); | |||||
}); | |||||
} | |||||
it('should highlight unified diff lines when selecting them from top to bottom', function() { | |||||
const diffHighlightingData = diffsHighlightingData['unified']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
unifiedDiffHighlightingTest(diffId, startLines, endLines); | |||||
}); | |||||
it('should highlight unified diff lines when selecting them from bottom to top', function() { | |||||
const diffHighlightingData = diffsHighlightingData['unified']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
unifiedDiffHighlightingTest(diffId, endLines, startLines); | |||||
}); | |||||
function singleSpitDiffHighlightingTest(diffId, startLines, endLines, to) { | |||||
let singleDiffId = `${diffId}-from`; | |||||
if (to) { | |||||
singleDiffId = `${diffId}-to`; | |||||
} | |||||
let startLine = startLines[0] || startLines[1]; | |||||
let endLine = endLines[0] || endLines[1]; | |||||
// render diff | |||||
cy.get(`#diff_${diffId}`) | |||||
.scrollIntoView() | |||||
.get(`#${diffId}-unified-diff`) | |||||
.should('be.visible'); | |||||
cy.get(`#diff_${diffId}`) | |||||
.contains('label', 'Side-by-side') | |||||
.click() | |||||
// ensure all asynchronous treatments in the page have been performed | |||||
// before testing diff highlighting | |||||
.then(() => { | |||||
// highlight a range of lines | |||||
let startElt = `#${singleDiffId} .hljs-ln-numbers[data-line-number="${startLine}"]`; | |||||
let endElt = `#${singleDiffId} .hljs-ln-numbers[data-line-number="${endLine}"]`; | |||||
cy.get(startElt).click(); | |||||
cy.get('body').type(`{shift}`, { | |||||
release: false | |||||
}); | |||||
cy.get(endElt).click(); | |||||
const selectedLinesFragment = | |||||
swh.revision.selectedDiffLinesToFragment(startLines, endLines, false); | |||||
// check URL fragment has been updated | |||||
cy.hash().should('be.equal', `#diff_${diffId}+${selectedLinesFragment}`); | |||||
if ($(endElt).position().top < $(startElt).position().top) { | |||||
[startLine, endLine] = [endLine, startLine]; | |||||
} | |||||
// check lines range is highlighted | |||||
checkDiffHighlighted(`${singleDiffId}`, startLine, endLine); | |||||
// check selected diff lines get highlighted when reloading page | |||||
// with highlighting info in URL fragment | |||||
cy.reload(); | |||||
cy.get(`#diff_${diffId}`) | |||||
.get(`#${diffId}-split-diff`) | |||||
.get(`#${singleDiffId}`) | |||||
.should('be.visible'); | |||||
checkDiffHighlighted(`${singleDiffId}`, startLine, endLine); | |||||
}); | |||||
} | |||||
it('should highlight split diff from lines when selecting them from top to bottom', function() { | |||||
const diffHighlightingData = diffsHighlightingData['split-from']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
singleSpitDiffHighlightingTest(diffId, startLines, endLines, false); | |||||
}); | |||||
it('should highlight split diff from lines when selecting them from bottom to top', function() { | |||||
const diffHighlightingData = diffsHighlightingData['split-from']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
singleSpitDiffHighlightingTest(diffId, endLines, startLines, false); | |||||
}); | |||||
it('should highlight split diff to lines when selecting them from top to bottom', function() { | |||||
const diffHighlightingData = diffsHighlightingData['split-to']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
singleSpitDiffHighlightingTest(diffId, startLines, endLines, true); | |||||
}); | |||||
it('should highlight split diff to lines when selecting them from bottom to top', function() { | |||||
const diffHighlightingData = diffsHighlightingData['split-to']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
singleSpitDiffHighlightingTest(diffId, endLines, startLines, true); | |||||
}); | |||||
function checkSplitDiffHighlighted(diffId, startLines, endLines) { | |||||
let left, right; | |||||
if (startLines[0] && endLines[1]) { | |||||
left = startLines[0]; | |||||
right = endLines[1]; | |||||
} else { | |||||
left = endLines[0]; | |||||
right = startLines[1]; | |||||
} | |||||
cy.get(`#${diffId}-from .hljs-ln-line`) | |||||
.then(fromLines => { | |||||
cy.get(`#${diffId}-to .hljs-ln-line`) | |||||
.then(toLines => { | |||||
const leftLine = $(`#${diffId}-from .hljs-ln-line[data-line-number="${left}"]`); | |||||
const rightLine = $(`#${diffId}-to .hljs-ln-line[data-line-number="${right}"]`); | |||||
const leftLineAbove = $(leftLine).position().top < $(rightLine).position().top; | |||||
let inHighlightedRange = false; | |||||
for (let i = 0; i < Math.max(fromLines.length, toLines.length); ++i) { | |||||
const fromLn = fromLines[i]; | |||||
const toLn = toLines[i]; | |||||
const fromLnNumber = $(fromLn).data('line-number'); | |||||
const toLnNumber = $(toLn).data('line-number'); | |||||
if ((leftLineAbove && fromLnNumber === left) || | |||||
(!leftLineAbove && toLnNumber === right) || | |||||
(leftLineAbove && toLnNumber === right) || | |||||
(!leftLineAbove && fromLnNumber === left)) { | |||||
inHighlightedRange = true; | |||||
} | |||||
if (fromLn) { | |||||
const fromMixBlendMode = $(fromLn).css('mix-blend-mode'); | |||||
if (inHighlightedRange && fromLnNumber) { | |||||
assert.equal(fromMixBlendMode, 'multiply'); | |||||
} else { | |||||
assert.equal(fromMixBlendMode, 'normal'); | |||||
} | |||||
} | |||||
if (toLn) { | |||||
const toMixBlendMode = $(toLn).css('mix-blend-mode'); | |||||
if (inHighlightedRange && toLnNumber) { | |||||
assert.equal(toMixBlendMode, 'multiply'); | |||||
} else { | |||||
assert.equal(toMixBlendMode, 'normal'); | |||||
} | |||||
} | |||||
if ((leftLineAbove && toLnNumber === right) || | |||||
(!leftLineAbove && fromLnNumber === left)) { | |||||
inHighlightedRange = false; | |||||
} | |||||
} | |||||
}); | |||||
}); | |||||
} | |||||
function splitDiffHighlightingTest(diffId, startLines, endLines) { | |||||
// render diff | |||||
cy.get(`#diff_${diffId}`) | |||||
.scrollIntoView() | |||||
.find(`#${diffId}-unified-diff`) | |||||
.should('be.visible'); | |||||
cy.get(`#diff_${diffId}`) | |||||
.contains('label', 'Side-by-side') | |||||
.click() | |||||
// ensure all asynchronous treatments in the page have been performed | |||||
// before testing diff highlighting | |||||
.then(() => { | |||||
// select lines range in diff | |||||
let startElt; | |||||
if (startLines[0]) { | |||||
startElt = `#${diffId}-from .hljs-ln-numbers[data-line-number="${startLines[0]}"]`; | |||||
} else { | |||||
startElt = `#${diffId}-to .hljs-ln-numbers[data-line-number="${startLines[1]}"]`; | |||||
} | |||||
let endElt; | |||||
if (endLines[0]) { | |||||
endElt = `#${diffId}-from .hljs-ln-numbers[data-line-number="${endLines[0]}"]`; | |||||
} else { | |||||
endElt = `#${diffId}-to .hljs-ln-numbers[data-line-number="${endLines[1]}"]`; | |||||
} | |||||
cy.get(startElt).click(); | |||||
cy.get('body').type(`{shift}`, { | |||||
release: false | |||||
}); | |||||
cy.get(endElt).click(); | |||||
const selectedLinesFragment = | |||||
swh.revision.selectedDiffLinesToFragment(startLines, endLines, false); | |||||
// check URL fragment has been updated | |||||
cy.hash().should('be.equal', `#diff_${diffId}+${selectedLinesFragment}`); | |||||
// check lines range is highlighted | |||||
checkSplitDiffHighlighted(diffId, startLines, endLines); | |||||
// check selected diff lines get highlighted when reloading page | |||||
// with highlighting info in URL fragment | |||||
cy.reload(); | |||||
cy.get(`#diff_${diffId}`) | |||||
.get(`#${diffId}-split-diff`) | |||||
.get(`#${diffId}-to`) | |||||
.should('be.visible'); | |||||
checkSplitDiffHighlighted(diffId, startLines, endLines); | |||||
}); | |||||
} | |||||
it('should highlight split diff from and to lines when selecting them from top-left to bottom-right', function() { | |||||
const diffHighlightingData = diffsHighlightingData['split-from-top-to-bottom']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
splitDiffHighlightingTest(diffId, startLines, endLines); | |||||
}); | |||||
it('should highlight split diff from and to lines when selecting them from bottom-right to top-left', function() { | |||||
const diffHighlightingData = diffsHighlightingData['split-from-top-to-bottom']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
splitDiffHighlightingTest(diffId, endLines, startLines); | |||||
}); | |||||
it('should highlight split diff from and to lines when selecting them from top-right to bottom-left', function() { | |||||
const diffHighlightingData = diffsHighlightingData['split-to-top-from-bottom']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
splitDiffHighlightingTest(diffId, startLines, endLines); | |||||
}); | |||||
it('should highlight split diff from and to lines when selecting them from bottom-left to top-right', function() { | |||||
const diffHighlightingData = diffsHighlightingData['split-to-top-from-bottom']; | |||||
const diffId = diffHighlightingData.diffId; | |||||
let startLines = diffHighlightingData.startLines; | |||||
let endLines = diffHighlightingData.endLines; | |||||
splitDiffHighlightingTest(diffId, endLines, startLines); | |||||
}); | |||||
}); | }); |