/* eslint-disable max-len, no-return-assign, */ /* global inject, sinon */ // TODO: This file was created by bulk-decaffeinate. // Fix any style issues and re-enable lint. /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ import HistoryV2Manager from '../../../../frontend/js/ide/history/HistoryV2Manager' export default describe('HistoryV2Manager', function () { beforeEach(function (done) { this.defaultHistoryScope = { isV2: true, updates: [], viewMode: 'point_in_time', nextBeforeTimestamp: null, loading: false, atEnd: false, userHasFullFeature: undefined, freeHistoryLimitHit: false, selection: { docs: {}, pathname: null, range: { fromV: null, toV: null, }, hoveredRange: { fromV: null, toV: null, }, diff: null, files: [], file: null, }, error: null, showOnlyLabels: false, labels: null, loadingFileTree: true, } this.sampleUpdates = [ { fromV: 4, toV: 5, meta: { users: [ { first_name: 'john.doe', last_name: '', email: 'john.doe@domain.tld', id: '5b57299087712202fb599ab4', hue: 200, }, ], start_ts: 1544021278346, end_ts: 1544021278346, }, labels: [ { id: '5c07e822042e67003b448f18', comment: 'My first label', version: 5, user_id: '5b57299087712202fb599ab4', created_at: '2018-12-05T15:00:50.688Z', }, ], pathnames: [], project_ops: [ { add: { pathname: 'chapters/chapter1.tex', }, atV: 4, }, ], }, { fromV: 3, toV: 4, meta: { users: [ { first_name: 'john.doe', last_name: '', email: 'john.doe@domain.tld', id: '5b57299087712202fb599ab4', hue: 200, }, ], start_ts: 1544021262622, end_ts: 1544021262622, }, labels: [], pathnames: ['main.tex'], project_ops: [], }, { fromV: 0, toV: 3, meta: { users: [ { first_name: 'john.doe', last_name: '', email: 'john.doe@domain.tld', id: '5b57299087712202fb599ab4', hue: 200, }, ], start_ts: 1544021213540, end_ts: 1544021213618, }, labels: [], pathnames: [], project_ops: [ { add: { pathname: 'universe.jpg', }, atV: 2, }, { add: { pathname: 'references.bib', }, atV: 1, }, { add: { pathname: 'main.tex', }, atV: 0, }, ], }, ] inject(($q, $http, $filter, $rootScope) => { this.$scope = $rootScope.$new() this.$scope.project = { features: { versioning: true, }, } this.$scope.user = { isAdmin: false, } this.ide = { globalEditorWatchdogManager: { attachToEditor() {} }, $q, $http, $filter, } this.eventTracking = { sendMB: () => {}, } this.localStorage = sinon.stub().returns(null) this.historyManager = new HistoryV2Manager( this.ide, this.$scope, this.localStorage, this.eventTracking ) done() }) }) it('should setup the history scope on initialization', function () { expect(this.$scope.history).to.deep.equal(this.defaultHistoryScope) }) it('should keep history updates after performing a soft reset', function () { const historyScopeWithUpdates = Object.assign( {}, this.defaultHistoryScope, { updates: this.sampleUpdates, } ) this.$scope.history.updates = this.sampleUpdates this.historyManager.softReset() expect(this.$scope.history).to.deep.equal(historyScopeWithUpdates) }) it('should discard history updates after performing a hard reset', function () { this.$scope.history.updates = this.sampleUpdates this.historyManager.hardReset() expect(this.$scope.history).to.deep.equal(this.defaultHistoryScope) }) it('should setup history with full access to the feature if the project has versioning', function () { this.$scope.$digest() expect(this.$scope.history.userHasFullFeature).to.equal(true) }) it('should setup history without full access to the feature if the project does not have versioning', function () { this.$scope.project.features.versioning = false this.historyManager = new HistoryV2Manager( this.ide, this.$scope, this.localStorage ) this.$scope.$digest() expect(this.$scope.history.userHasFullFeature).to.equal(false) }) it('should setup history with full access to the feature for admin users even if the project does not have versioning', function () { this.$scope.project.features.versioning = false this.$scope.user.isAdmin = true this.historyManager = new HistoryV2Manager( this.ide, this.$scope, this.localStorage ) this.$scope.$digest() expect(this.$scope.history.userHasFullFeature).to.equal(true) }) describe('autoSelectFile', function () { describe('for compare mode', function () { beforeEach(function () { this.mockedFilesList = [ { pathname: 'main.tex', }, { pathname: 'references.bib', }, { pathname: 'universe.jpg', }, { pathname: 'chapters/chapter2.tex', }, { pathname: 'chapters/draft.tex', operation: 'removed', deletedAtV: 47, }, { pathname: 'chapters/chapter3.tex', operation: 'added', }, { pathname: 'chapters/chapter1.tex', operation: 'edited', }, { pathname: 'chapters/foo.tex', oldPathname: 'chapters/bar.tex', operation: 'renamed', }, ] this.mockedMainTex = this.mockedFilesList[0] this.mockedReferencesFile = this.mockedFilesList[1] this.mockedRemovedFile = this.mockedFilesList[4] this.mockedAddedFile = this.mockedFilesList[5] this.mockedEditedFile = this.mockedFilesList[6] this.mockedRenamedFile = this.mockedFilesList[7] this.$scope.history.viewMode = 'compare' this.$scope.history.selection.files = this.mockedFilesList }) describe('with a previously selected file', function () { it('should prefer the previously selected file if it is available and has operations', function () { this.historyManager._previouslySelectedPathname = this.mockedAddedFile.pathname this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( this.mockedAddedFile ) }) it('should prefer a file with ops if the previously selected file is available but has no operations', function () { this.historyManager._previouslySelectedPathname = this.mockedReferencesFile.pathname this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.operation).to.exist }) it('should ignore the previously selected file if it is not available', function () { this.historyManager._previouslySelectedPathname = 'non/existent.file' this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.pathname).to.not.equal( 'non/existent.file' ) }) }) describe('without a previously selected file, with a list of files containing operations', function () { it('should prefer edited files', function () { this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( this.mockedEditedFile ) }) it('should prefer added files if no edited files are present', function () { const indexOfEditedFile = this.$scope.history.selection.files.indexOf( this.mockedEditedFile ) this.$scope.history.selection.files.splice(indexOfEditedFile, 1) this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( this.mockedAddedFile ) }) it('should prefer renamed files if no edited or added files are present', function () { const indexOfEditedFile = this.$scope.history.selection.files.indexOf( this.mockedEditedFile ) this.$scope.history.selection.files.splice(indexOfEditedFile, 1) const indexOfAddedFile = this.$scope.history.selection.files.indexOf( this.mockedAddedFile ) this.$scope.history.selection.files.splice(indexOfAddedFile, 1) this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( this.mockedRenamedFile ) }) it('should prefer removed files if no edited, added or renamed files are present', function () { const indexOfEditedFile = this.$scope.history.selection.files.indexOf( this.mockedEditedFile ) this.$scope.history.selection.files.splice(indexOfEditedFile, 1) const indexOfAddedFile = this.$scope.history.selection.files.indexOf( this.mockedAddedFile ) this.$scope.history.selection.files.splice(indexOfAddedFile, 1) const indexOfRenamedFile = this.$scope.history.selection.files.indexOf(this.mockedRenamedFile) this.$scope.history.selection.files.splice(indexOfRenamedFile, 1) this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( this.mockedRemovedFile ) }) }) describe('without a previously selected file, with a list of files without operations', function () { beforeEach(function () { this.mockedFilesListWithNoOps = [ { pathname: 'main.tex', }, { pathname: 'references.bib', }, { pathname: 'other.tex', }, { pathname: 'universe.jpg', }, ] this.mockedMainTex = this.mockedFilesListWithNoOps[0] this.mockedReferencesFile = this.mockedFilesListWithNoOps[1] this.mockedOtherTexFile = this.mockedFilesListWithNoOps[2] this.$scope.history.selection.files = this.mockedFilesListWithNoOps }) it('should prefer main.tex if it exists', function () { this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( this.mockedMainTex ) }) it('should prefer another tex file if main.tex does not exist', function () { const indexOfMainTex = this.$scope.history.selection.files.indexOf( this.mockedMainTex ) this.$scope.history.selection.files.splice(indexOfMainTex, 1) this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( this.mockedOtherTexFile ) }) it('should pick the first available file if no tex files are available', function () { const indexOfMainTex = this.$scope.history.selection.files.indexOf( this.mockedMainTex ) this.$scope.history.selection.files.splice(indexOfMainTex, 1) const indexOfOtherTexFile = this.$scope.history.selection.files.indexOf(this.mockedOtherTexFile) this.$scope.history.selection.files.splice(indexOfOtherTexFile, 1) this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( this.mockedReferencesFile ) }) }) }) describe('for point-in-time mode', function () { beforeEach(function () { this.$scope.history.viewMode = 'point_in_time' this.sampleUpdates[0] = { fromV: 4, toV: 5, meta: { users: [ { first_name: 'john.doe', last_name: '', email: 'john.doe@domain.tld', id: '5b57299087712202fb599ab4', hue: 200, }, ], start_ts: 1544021278346, end_ts: 1544021278346, }, pathnames: ['main.tex'], project_ops: [ { add: { pathname: 'chapters/chapter1.tex', }, atV: 4, }, { rename: { pathname: 'foo.tex', newPathname: 'bar.tex', }, }, ], } this.sampleUpdateEditedFile = this.sampleUpdates[0].pathnames[0] this.sampleUpdateAddedFile = this.sampleUpdates[0].project_ops[0].add.pathname this.sampleUpdateRenamedFile = this.sampleUpdates[0].project_ops[1].rename.newPathname this.$scope.history.updates = this.sampleUpdates this.$scope.history.selection.range = { fromV: this.sampleUpdates[0].toV, toV: this.sampleUpdates[0].toV, } this.mockedFilesList = [ { pathname: 'main.tex', }, { pathname: 'references.bib', }, { pathname: 'universe.jpg', }, { pathname: 'chapters/chapter2.tex', }, { pathname: 'chapters/draft.tex', }, { pathname: 'chapters/chapter3.tex', }, { pathname: 'chapters/chapter1.tex', }, { pathname: 'bar.tex', }, ] this.$scope.history.selection.files = this.mockedFilesList }) describe('with a previously selected file', function () { it('should prefer the previously selected file if it is available and has operations', function () { this.historyManager._previouslySelectedPathname = 'main.tex' this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.pathname).to.equal( this.sampleUpdateEditedFile ) }) it('should prefer a file with ops if the previously selected file is available but has no operations', function () { this.historyManager._previouslySelectedPathname = 'main.tex' this.sampleUpdates[0].pathnames = [] this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.pathname).to.equal( this.sampleUpdateAddedFile ) }) it('should ignore the previously selected file if it is not available', function () { this.historyManager._previouslySelectedPathname = 'non/existent.file' this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.pathname).to.not.equal( 'non/existent.file' ) }) }) describe('without a previously selected file, with a list of files containing operations', function () { it('should prefer edited files', function () { this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.pathname).to.equal( this.sampleUpdateEditedFile ) }) it('should prefer added files if no edited files are present', function () { this.sampleUpdates[0].pathnames = [] this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.pathname).to.equal( this.sampleUpdateAddedFile ) }) it('should prefer renamed files if no edited or added files are present', function () { this.sampleUpdates[0].pathnames = [] this.sampleUpdates[0].project_ops.shift() this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.pathname).to.equal( this.sampleUpdateRenamedFile ) }) }) describe('without a previously selected file, with a list of files without operations', function () { beforeEach(function () { this.sampleUpdates[0].pathnames = [] this.sampleUpdates[0].project_ops = [] this.mockedMainTex = this.mockedFilesList[0] this.mockedReferencesFile = this.mockedFilesList[1] }) it('should prefer main.tex if it exists', function () { this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.pathname).to.equal( this.mockedMainTex.pathname ) }) it('should prefer another tex file if main.tex does not exist', function () { const indexOfMainTex = this.$scope.history.selection.files.indexOf( this.mockedMainTex ) this.$scope.history.selection.files.splice(indexOfMainTex, 1) this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.pathname).to.match(/.tex$/) }) }) }) describe('_loadLabels', function () { it('should return labels list as is if there is a label for the last version', function () { const labels = [ { id: '1', version: 1, comment: 'foo', created_at: new Date().toISOString(), }, { id: '2', version: 2, comment: 'bar', created_at: new Date().toISOString(), }, { id: '3', version: 3, comment: 'baz', created_at: new Date().toISOString(), }, ] const lastUpdate = 3 const labelsResult = this.historyManager._loadLabels(labels, lastUpdate) expect(labelsResult).to.have.members(labels) }) it('should return a labels list with a pseudo current state label if there is no label for the last version', function () { const labels = [ { id: '1', version: 1, comment: 'foo', created_at: new Date().toISOString(), }, { id: '2', version: 2, comment: 'bar', created_at: new Date().toISOString(), }, { id: '3', version: 3, comment: 'baz', created_at: new Date().toISOString(), }, ] const lastUpdate = 5 const labelsResult = this.historyManager._loadLabels(labels, lastUpdate) expect(labelsResult).to.include.members(labels) expect(labelsResult[0].isPseudoCurrentStateLabel).to.equal(true) expect(labelsResult[0].version).to.equal(5) }) it('should keep pseudo label when deleting label', function () { this.historyManager.$scope.history.labels = [ { id: '1', version: 1, comment: 'foo', created_at: new Date().toISOString(), }, ] const lastUpdate = 5 this.historyManager.$scope.history.labels = this.historyManager._loadLabels( this.historyManager.$scope.history.labels, lastUpdate ) expect( this.historyManager.$scope.history.labels[0].isPseudoCurrentStateLabel ).to.equal(true) this.historyManager.$scope.history.labels = this.historyManager._loadLabels([], lastUpdate) expect( this.historyManager.$scope.history.labels[0].isPseudoCurrentStateLabel ).to.equal(true) expect(this.historyManager.$scope.history.labels[0].version).to.equal(5) }) }) }) })