/** * Copyright (C) 2019-2020 The Software Heritage developers * See the AUTHORS file at the top-level directory of this distribution * License: GNU Affero General Public License version 3, or any later version * See top-level LICENSE file for more information */ 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 swh; describe('Test Revision View', function() { it('should add/remove #swh-revision-changes url fragment when switching tab', function() { const url = this.Urls.browse_revision(revision) + `?origin=${origin}`; cy.visit(url); cy.get('a[data-toggle="tab"]') .contains('Changes') .click(); cy.hash().should('be.equal', '#swh-revision-changes'); cy.get('a[data-toggle="tab"]') .contains('Files') .click(); cy.hash().should('be.equal', ''); }); it('should display Changes tab by default when url ends with #swh-revision-changes', function() { const url = this.Urls.browse_revision(revision) + `?origin=${origin}`; cy.visit(url + '#swh-revision-changes'); cy.get('#swh-revision-changes-list') .should('be.visible'); }); }); describe('Test Diffs View', function() { 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) .then(res => { diffData = res.body; }); }); cy.get('a[data-toggle="tab"]') .contains('Changes') .click(); }); it('should list all files with changes', function() { const files = new Set([]); for (const change of diffData.changes) { files.add(change.from_path); files.add(change.to_path); } for (const file of files) { cy.get('#swh-revision-changes-list a') .contains(file) .should('be.visible'); } }); it('should load diffs when scrolled down', function() { cy.get('#swh-revision-changes-list a') .each($el => { cy.get($el.attr('href')) .scrollIntoView() .find('.swh-content') .should('be.visible'); }); }); it('should compute all diffs when selected', function() { cy.get('#swh-compute-all-diffs') .click(); cy.get('#swh-revision-changes-list a') .each($el => { cy.get($el.attr('href')) .find('.swh-content') .should('be.visible'); }); }); it('should have correct links in diff file names', function() { for (const change of diffData.changes) { cy.get(`#swh-revision-changes-list a[href="#diff_${change.id}"`) .should('be.visible'); } }); it('should load unified diff by default', function() { cy.get('#swh-compute-all-diffs') .click(); for (const change of diffData.changes) { cy.get(`#${change.id}-unified-diff`) .should('be.visible'); cy.get(`#${change.id}-split-diff`) .should('not.be.visible'); } }); it('should switch between unified and side-by-side diff when selected', function() { // Test for first diff const id = diffData.changes[0].id; cy.get(`#diff_${id}`) .contains('label', 'Side-by-side') .click(); cy.get(`#${id}-split-diff`) .should('be.visible') .get(`#${id}-unified-diff`) .should('not.be.visible'); }); function checkDiffHighlighted(diffId, start, end) { cy.get(`#${diffId} .hljs-ln-line`) .then(lines => { let inHighlightedRange = false; for (const line of lines) { const lnNumber = $(line).data('line-number'); if (lnNumber === start || lnNumber === end) { inHighlightedRange = true; } const backgroundColor = $(line).css('background-color'); const mixBlendMode = $(line).css('mix-blend-mode'); if (inHighlightedRange && parseInt(lnNumber)) { assert.equal(mixBlendMode, 'multiply'); assert.notEqual(backgroundColor, 'rgba(0, 0, 0, 0)'); } else { assert.equal(mixBlendMode, 'normal'); assert.equal(backgroundColor, 'rgba(0, 0, 0, 0)'); } 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 const startElt = `#${diffId}-unified-diff .hljs-ln-numbers[data-line-number="${startLinesStr}"]`; const endElt = `#${diffId}-unified-diff .hljs-ln-numbers[data-line-number="${endLinesStr}"]`; cy.get(startElt).click(); cy.get(endElt).click({shiftKey: true}); // 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; const startLines = diffHighlightingData.startLines; const 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; const startLines = diffHighlightingData.startLines; const 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 const startElt = `#${singleDiffId} .hljs-ln-numbers[data-line-number="${startLine}"]`; const endElt = `#${singleDiffId} .hljs-ln-numbers[data-line-number="${endLine}"]`; cy.get(startElt).click(); cy.get(endElt).click({shiftKey: true}); 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; const startLines = diffHighlightingData.startLines; const 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; const startLines = diffHighlightingData.startLines; const 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; const startLines = diffHighlightingData.startLines; const 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; const startLines = diffHighlightingData.startLines; const 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 fromBackgroundColor = $(fromLn).css('background-color'); const fromMixBlendMode = $(fromLn).css('mix-blend-mode'); if (inHighlightedRange && fromLnNumber) { assert.equal(fromMixBlendMode, 'multiply'); assert.notEqual(fromBackgroundColor, 'rgba(0, 0, 0, 0)'); } else { assert.equal(fromMixBlendMode, 'normal'); assert.equal(fromBackgroundColor, 'rgba(0, 0, 0, 0)'); } } if (toLn) { const toBackgroundColor = $(toLn).css('background-color'); const toMixBlendMode = $(toLn).css('mix-blend-mode'); if (inHighlightedRange && toLnNumber) { assert.equal(toMixBlendMode, 'multiply'); assert.notEqual(toBackgroundColor, 'rgba(0, 0, 0, 0)'); } else { assert.equal(toMixBlendMode, 'normal'); assert.equal(toBackgroundColor, 'rgba(0, 0, 0, 0)'); } } 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(endElt).click({shiftKey: true}); 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; const startLines = diffHighlightingData.startLines; const 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; const startLines = diffHighlightingData.startLines; const 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; const startLines = diffHighlightingData.startLines; const 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; const startLines = diffHighlightingData.startLines; const endLines = diffHighlightingData.endLines; splitDiffHighlightingTest(diffId, endLines, startLines); }); it('should highlight diff lines properly when a content is browsed in the Files tab', function() { const url = this.Urls.browse_revision(revision) + `?origin=${origin}&path=README.md`; cy.visit(url); cy.get('a[data-toggle="tab"]') .contains('Changes') .click(); const diffHighlightingData = diffsHighlightingData['unified']; const diffId = diffHighlightingData.diffId; const startLines = diffHighlightingData.startLines; const endLines = diffHighlightingData.endLines; unifiedDiffHighlightingTest(diffId, startLines, endLines); }); });