X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/6a6a0ad3791c3d93f9881db8dc5bb30827af0898..082c1782d96a4b1c897df64d9b325d102a5c1144:/cypress/integration/collection.spec.js diff --git a/cypress/integration/collection.spec.js b/cypress/integration/collection.spec.js index dfc1c466..568121f1 100644 --- a/cypress/integration/collection.spec.js +++ b/cypress/integration/collection.spec.js @@ -2,9 +2,12 @@ // // SPDX-License-Identifier: AGPL-3.0 +const path = require('path'); + describe('Collection panel tests', function () { let activeUser; let adminUser; + let downloadsFolder; before(function () { // Only set up common users once. These aren't set up as aliases because @@ -21,6 +24,7 @@ describe('Collection panel tests', function () { activeUser = this.activeUser; } ); + downloadsFolder = Cypress.config('downloadsFolder'); }); beforeEach(function () { @@ -28,7 +32,50 @@ describe('Collection panel tests', function () { cy.clearLocalStorage(); }); - it('uses the property editor with vocabulary terms', function () { + it('allows to download mountain duck config for a collection', () => { + cy.createCollection(adminUser.token, { + name: `Test collection ${Math.floor(Math.random() * 999999)}`, + owner_uuid: activeUser.user.uuid, + manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n" + }) + .as('testCollection').then(function (testCollection) { + cy.loginAs(activeUser); + cy.goToPath(`/collections/${testCollection.uuid}`); + + cy.get('[data-cy=collection-panel-options-btn]').click(); + cy.get('[data-cy=context-menu]').contains('Open with 3rd party client').click(); + cy.get('[data-cy=download-button').click(); + + const filename = path.join(downloadsFolder, `${testCollection.name}.duck`); + + cy.readFile(filename, { timeout: 15000 }) + .then((body) => { + const childrenCollection = Array.prototype.slice.call(Cypress.$(body).find('dict')[0].children); + const map = {}; + let i, j = 2; + + for (i=0; i < childrenCollection.length; i += j) { + map[childrenCollection[i].outerText] = childrenCollection[i + 1].outerText; + } + + cy.get('#simple-tabpanel-0').find('a') + .then((a) => { + const [host, port] = a.text().split('@')[1].split('/')[0].split(':'); + expect(map['Protocol']).to.equal('davs'); + expect(map['UUID']).to.equal(testCollection.uuid); + expect(map['Username']).to.equal(activeUser.user.username); + expect(map['Port']).to.equal(port); + expect(map['Hostname']).to.equal(host); + if (map['Path']) { + expect(map['Path']).to.equal(`/c=${testCollection.uuid}`); + } + }); + }) + .then(() => cy.task('clearDownload', { filename })); + }); + }); + + it('uses the property editor (from edit dialog) with vocabulary terms', function () { cy.createCollection(adminUser.token, { name: `Test collection ${Math.floor(Math.random() * 999999)}`, owner_uuid: activeUser.user.uuid, @@ -36,7 +83,15 @@ describe('Collection panel tests', function () { }) .as('testCollection').then(function () { cy.loginAs(activeUser); - cy.doSearch(`${this.testCollection.uuid}`); + cy.goToPath(`/collections/${this.testCollection.uuid}`); + + cy.get('[data-cy=collection-info-panel') + .should('contain', this.testCollection.name) + .and('not.contain', 'Color: Magenta'); + + cy.get('[data-cy=collection-panel-options-btn]').click(); + cy.get('[data-cy=context-menu]').contains('Edit collection').click(); + cy.get('[data-cy=form-dialog]').should('contain', 'Properties'); // Key: Color (IDTAGCOLORS) - Value: Magenta (IDVALCOLORS3) cy.get('[data-cy=resource-properties-form]').within(() => { @@ -49,16 +104,91 @@ describe('Collection panel tests', function () { cy.root().submit(); }); // Confirm proper vocabulary labels are displayed on the UI. - cy.get('[data-cy=collection-properties-panel]') - .should('contain', 'Color') - .and('contain', 'Magenta'); + cy.get('[data-cy=form-dialog]').should('contain', 'Color: Magenta'); + cy.get('[data-cy=form-dialog]').contains('Save').click(); + cy.get('[data-cy=form-dialog]').should('not.exist'); + // Confirm proper vocabulary IDs were saved on the backend. + cy.doRequest('GET', `/arvados/v1/collections/${this.testCollection.uuid}`) + .its('body').as('collection') + .then(function () { + expect(this.collection.properties.IDTAGCOLORS).to.equal('IDVALCOLORS3'); + }); + // Confirm the property is displayed on the UI. + cy.get('[data-cy=collection-info-panel') + .should('contain', this.testCollection.name) + .and('contain', 'Color: Magenta'); + }); + }); + + it('uses the editor (from details panel) with vocabulary terms', function () { + cy.createCollection(adminUser.token, { + name: `Test collection ${Math.floor(Math.random() * 999999)}`, + owner_uuid: activeUser.user.uuid, + manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n" + }) + .as('testCollection').then(function () { + cy.loginAs(activeUser); + cy.goToPath(`/collections/${this.testCollection.uuid}`); + + cy.get('[data-cy=collection-info-panel') + .should('contain', this.testCollection.name) + .and('not.contain', 'Color: Magenta') + .and('not.contain', 'Size: S'); + cy.get('[data-cy=additional-info-icon]').click(); + + cy.get('[data-cy=details-panel]').within(() => { + cy.get('[data-cy=details-panel-edit-btn]').click(); + }); + cy.get('[data-cy=form-dialog').contains('Edit Collection'); + + // Key: Color (IDTAGCOLORS) - Value: Magenta (IDVALCOLORS3) + cy.get('[data-cy=resource-properties-form]').within(() => { + cy.get('[data-cy=property-field-key]').within(() => { + cy.get('input').type('Color'); + }); + cy.get('[data-cy=property-field-value]').within(() => { + cy.get('input').type('Magenta'); + }); + cy.root().submit(); + }); + // Confirm proper vocabulary labels are displayed on the UI. + cy.get('[data-cy=form-dialog]') + .should('contain', 'Color: Magenta'); + + // Case-insensitive on-blur auto-selection test + // Key: Size (IDTAGSIZES) - Value: Small (IDVALSIZES2) + cy.get('[data-cy=resource-properties-form]').within(() => { + cy.get('[data-cy=property-field-key]').within(() => { + cy.get('input').type('sIzE'); + }); + cy.get('[data-cy=property-field-value]').within(() => { + cy.get('input').type('sMaLL'); + }); + // Cannot "type()" TAB on Cypress so let's click another field + // to trigger the onBlur event. + cy.get('[data-cy=property-field-key]').click(); + cy.root().submit(); + }); + // Confirm proper vocabulary labels are displayed on the UI. + cy.get('[data-cy=form-dialog]') + .should('contain', 'Size: S'); + + cy.get('[data-cy=form-dialog]').contains('Save').click(); + cy.get('[data-cy=form-dialog]').should('not.exist'); + // Confirm proper vocabulary IDs were saved on the backend. cy.doRequest('GET', `/arvados/v1/collections/${this.testCollection.uuid}`) .its('body').as('collection') .then(function () { - expect(this.collection.properties).to.deep.equal( - { IDTAGCOLORS: 'IDVALCOLORS3' }); + expect(this.collection.properties.IDTAGCOLORS).to.equal('IDVALCOLORS3'); + expect(this.collection.properties.IDTAGSIZES).to.equal('IDVALSIZES2'); }); + + // Confirm properties display on the UI. + cy.get('[data-cy=collection-info-panel') + .should('contain', this.testCollection.name) + .and('contain', 'Color: Magenta') + .and('contain', 'Size: S'); }); }); @@ -69,18 +199,29 @@ describe('Collection panel tests', function () { // on this loop may pass an assertion from the first iteration by looking // for the same file name. const fileName = isWritable ? 'bar' : 'foo'; + const subDirName = 'subdir'; cy.createGroup(adminUser.token, { name: 'Shared project', group_class: 'project', }).as('sharedGroup').then(function () { // Creates the collection using the admin token so we can set up // a bogus manifest text without block signatures. - cy.createCollection(adminUser.token, { - name: 'Test collection', - owner_uuid: this.sharedGroup.uuid, - properties: { someKey: 'someValue' }, - manifest_text: `. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n` - }) + cy.doRequest('GET', '/arvados/v1/config', null, null) + .its('body').should((clusterConfig) => { + expect(clusterConfig.Collections, "clusterConfig").to.have.property("TrustAllContent", false); + expect(clusterConfig.Services, "clusterConfig").to.have.property("WebDAV").have.property("ExternalURL"); + expect(clusterConfig.Services, "clusterConfig").to.have.property("WebDAVDownload").have.property("ExternalURL"); + const inlineUrl = clusterConfig.Services.WebDAV.ExternalURL !== "" + ? clusterConfig.Services.WebDAV.ExternalURL + : clusterConfig.Services.WebDAVDownload.ExternalURL; + expect(inlineUrl).to.not.contain("*"); + }) + .createCollection(adminUser.token, { + name: 'Test collection', + owner_uuid: this.sharedGroup.uuid, + properties: { someKey: 'someValue' }, + manifest_text: `. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n./${subDirName} 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n` + }) .as('testCollection').then(function () { // Share the group with active user. cy.createLink(adminUser.token, { @@ -89,7 +230,7 @@ describe('Collection panel tests', function () { head_uuid: this.sharedGroup.uuid, tail_uuid: activeUser.user.uuid }) - cy.doSearch(`${this.testCollection.uuid}`); + cy.goToPath(`/collections/${this.testCollection.uuid}`); // Check that name & uuid are correct. cy.get('[data-cy=collection-info-panel]') @@ -106,42 +247,33 @@ describe('Collection panel tests', function () { .should('contain', 'Add to favorites') .and(`${isWritable ? '' : 'not.'}contain`, 'Edit collection'); cy.get('body').click(); // Collapse the menu avoiding details panel expansion - cy.get('[data-cy=collection-properties-panel]') - .should('contain', 'someKey') - .and('contain', 'someValue') - .and('not.contain', 'anotherKey') - .and('not.contain', 'anotherValue') - if (isWritable === true) { - // Check that properties can be added. - cy.get('[data-cy=resource-properties-form]').within(() => { - cy.get('[data-cy=property-field-key]').within(() => { - cy.get('input').type('anotherKey'); - }); - cy.get('[data-cy=property-field-value]').within(() => { - cy.get('input').type('anotherValue'); - }); - cy.root().submit(); - }) - cy.get('[data-cy=collection-properties-panel]') - .should('contain', 'anotherKey') - .and('contain', 'anotherValue') - } else { - // Properties form shouldn't be displayed. - cy.get('[data-cy=resource-properties-form]').should('not.exist'); - } + cy.get('[data-cy=collection-info-panel]') + .should('contain', 'someKey: someValue') + .and('not.contain', 'anotherKey: anotherValue'); // Check that the file listing show both read & write operations cy.get('[data-cy=collection-files-panel]').within(() => { - cy.root().should('contain', fileName); + cy.get('[data-cy=collection-files-right-panel]', { timeout: 5000 }) + .should('contain', fileName); if (isWritable) { cy.get('[data-cy=upload-button]') .should(`${isWritable ? '' : 'not.'}contain`, 'Upload data'); } }); + // Test context menus cy.get('[data-cy=collection-files-panel]') .contains(fileName).rightclick({ force: true }); cy.get('[data-cy=context-menu]') .should('contain', 'Download') - .and('contain', 'Open in new tab') + .and('not.contain', 'Open in new tab') + .and('contain', 'Copy to clipboard') + .and(`${isWritable ? '' : 'not.'}contain`, 'Rename') + .and(`${isWritable ? '' : 'not.'}contain`, 'Remove'); + cy.get('body').click(); // Collapse the menu + cy.get('[data-cy=collection-files-panel]') + .contains(subDirName).rightclick({ force: true }); + cy.get('[data-cy=context-menu]') + .should('not.contain', 'Download') + .and('not.contain', 'Open in new tab') .and('contain', 'Copy to clipboard') .and(`${isWritable ? '' : 'not.'}contain`, 'Rename') .and(`${isWritable ? '' : 'not.'}contain`, 'Remove'); @@ -155,22 +287,19 @@ describe('Collection panel tests', function () { cy.get('[data-cy=collection-files-panel-options-btn]') .click() cy.get('[data-cy=context-menu]') - // .should('contain', 'Download selected') .should(`${isWritable ? '' : 'not.'}contain`, 'Remove selected') cy.get('body').click(); // Collapse the menu - // File item 'more options' button - cy.get('[data-cy=file-item-options-btn') - .click() - cy.get('[data-cy=context-menu]') - .should('contain', 'Download') - .and(`${isWritable ? '' : 'not.'}contain`, 'Remove'); - cy.get('body').click(); // Collapse the menu }) }) }) }) it('renames a file using valid names', function () { + function eachPair(lst, func){ + for(var i=0; i < lst.length - 1; i++){ + func(lst[i], lst[i + 1]) + } + } // Creates the collection using the admin token so we can set up // a bogus manifest text without block signatures. cy.createCollection(adminUser.token, { @@ -180,17 +309,32 @@ describe('Collection panel tests', function () { }) .as('testCollection').then(function () { cy.loginAs(activeUser); - cy.doSearch(`${this.testCollection.uuid}`); - - const nameTransitions = [ - ['bar', '&'], - ['&', 'foo'], - ['foo', '&'], - ['&', 'I ❤️ ⛵️'], - ['I ❤️ ⛵️', '...'] + cy.goToPath(`/collections/${this.testCollection.uuid}`); + + const names = [ + 'bar', // initial name already set + '&', + 'foo', + '&', + 'I ❤️ ⛵️', + '...', + '#..', + 'some name with whitespaces', + 'some name with #2', + 'is this name legal? I hope it is', + 'some_file.pdf#', + 'some_file.pdf?', + '?some_file.pdf', + 'some%file.pdf', + 'some%2Ffile.pdf', + 'some%22file.pdf', + 'some%20file.pdf', + "G%C3%BCnter's%20file.pdf", + 'table%&?*2', + 'bar' // make sure we can go back to the original name as a last step ]; - nameTransitions.forEach(([from, to]) => { - cy.get('[data-cy=collection-files-panel]') + eachPair(names, (from, to) => { + cy.waitForDom().get('[data-cy=collection-files-panel]') .contains(`${from}`).rightclick(); cy.get('[data-cy=context-menu]') .contains('Rename') @@ -198,7 +342,9 @@ describe('Collection panel tests', function () { cy.get('[data-cy=form-dialog]') .should('contain', 'Rename') .within(() => { - cy.get('input').type(`{selectall}{backspace}${to}`); + cy.get('input') + .type('{selectall}{backspace}') + .type(to, { parseSpecialCharSequences: false }); }); cy.get('[data-cy=form-submit-btn]').click(); cy.get('[data-cy=collection-files-panel]') @@ -218,42 +364,58 @@ describe('Collection panel tests', function () { }) .as('testCollection').then(function () { cy.loginAs(activeUser); - cy.doSearch(`${this.testCollection.uuid}`); + cy.goToPath(`/collections/${this.testCollection.uuid}`); - // Rename 'bar' to 'subdir/foo' - cy.get('[data-cy=collection-files-panel]') - .contains('bar').rightclick(); - cy.get('[data-cy=context-menu]') - .contains('Rename') - .click(); - cy.get('[data-cy=form-dialog]') - .should('contain', 'Rename') - .within(() => { - cy.get('input').type(`{selectall}{backspace}subdir/foo`); - }); - cy.get('[data-cy=form-submit-btn]').click(); - cy.get('[data-cy=collection-files-panel]') - .should('not.contain', 'bar') - .and('contain', 'subdir'); - // Look for the "arrow icon" and expand the "subdir" directory. - cy.get('[data-cy=virtual-file-tree] > div > i').click(); - // Rename 'subdir/foo' to 'baz' - cy.get('[data-cy=collection-files-panel]') - .contains('foo').rightclick(); - cy.get('[data-cy=context-menu]') - .contains('Rename') - .click(); - cy.get('[data-cy=form-dialog]') - .should('contain', 'Rename') - .within(() => { - cy.get('input') - .should('have.value', 'subdir/foo') - .type(`{selectall}{backspace}baz`); - }); - cy.get('[data-cy=form-submit-btn]').click(); - cy.get('[data-cy=collection-files-panel]') - .should('contain', 'subdir') // empty dir kept - .and('contain', 'baz'); + ['subdir', 'G%C3%BCnter\'s%20file', 'table%&?*2'].forEach((subdir) => { + cy.get('[data-cy=collection-files-panel]') + .contains('bar').rightclick({force: true}); + cy.get('[data-cy=context-menu]') + .contains('Rename') + .click(); + cy.get('[data-cy=form-dialog]') + .should('contain', 'Rename') + .within(() => { + cy.get('input').type(`{selectall}{backspace}${subdir}/foo`); + }); + cy.get('[data-cy=form-submit-btn]').click(); + cy.get('[data-cy=collection-files-panel]') + .should('not.contain', 'bar') + .and('contain', subdir); + cy.wait(1000); + cy.get('[data-cy=collection-files-panel]').contains(subdir).click(); + // Rename 'subdir/foo' to 'foo' + cy.wait(1000); + cy.get('[data-cy=collection-files-panel]') + .contains('foo').rightclick(); + cy.get('[data-cy=context-menu]') + .contains('Rename') + .click(); + cy.get('[data-cy=form-dialog]') + .should('contain', 'Rename') + .within(() => { + cy.get('input') + .should('have.value', `${subdir}/foo`) + .type(`{selectall}{backspace}bar`); + }); + cy.get('[data-cy=form-submit-btn]').click(); + + cy.wait(1000); + cy.get('[data-cy=collection-files-panel]') + .contains('Home') + .click(); + + cy.wait(2000); + cy.get('[data-cy=collection-files-panel]') + .should('contain', subdir) // empty dir kept + .and('contain', 'bar'); + + cy.get('[data-cy=collection-files-panel]') + .contains(subdir).rightclick(); + cy.get('[data-cy=context-menu]') + .contains('Remove') + .click(); + cy.get('[data-cy=confirmation-dialog-ok-btn]').click(); + }); }); }); @@ -267,7 +429,7 @@ describe('Collection panel tests', function () { }) .as('testCollection').then(function () { cy.loginAs(activeUser); - cy.doSearch(`${this.testCollection.uuid}`); + cy.goToPath(`/collections/${this.testCollection.uuid}`); const illegalNamesFromUI = [ ['.', "Name cannot be '.' or '..'"], @@ -343,7 +505,7 @@ describe('Collection panel tests', function () { }); // Check the old version displays as what it is. cy.loginAs(activeUser) - cy.doSearch(`${oldVersionUuid}`); + cy.goToPath(`/collections/${oldVersionUuid}`); cy.get('[data-cy=collection-info-panel]').should('contain', 'This is an old version'); cy.get('[data-cy=read-only-icon]').should('exist'); @@ -352,33 +514,179 @@ describe('Collection panel tests', function () { }); }); - it('should display all filles within the collection even with the # sign within the file name', () => { - const colName = `Test Collection ${Math.floor(Math.random() * 999999)}`; - + it('views & edits storage classes data', function () { + const colName= `Test Collection ${Math.floor(Math.random() * 999999)}`; cy.createCollection(adminUser.token, { name: colName, owner_uuid: activeUser.user.uuid, - preserve_version: true, - manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:#foo 0:3:bar\n" + manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:some-file\n", + }).as('collection').then(function () { + expect(this.collection.storage_classes_desired).to.deep.equal(['default']) + + cy.loginAs(activeUser) + cy.goToPath(`/collections/${this.collection.uuid}`); + + // Initial check: it should show the 'default' storage class + cy.get('[data-cy=collection-info-panel]') + .should('contain', 'Storage classes') + .and('contain', 'default') + .and('not.contain', 'foo') + .and('not.contain', 'bar'); + // Edit collection: add storage class 'foo' + cy.get('[data-cy=collection-panel-options-btn]').click(); + cy.get('[data-cy=context-menu]').contains('Edit collection').click(); + cy.get('[data-cy=form-dialog]') + .should('contain', 'Edit Collection') + .and('contain', 'Storage classes') + .and('contain', 'default') + .and('contain', 'foo') + .and('contain', 'bar') + .within(() => { + cy.get('[data-cy=checkbox-foo]').click(); + }); + cy.get('[data-cy=form-submit-btn]').click(); + cy.get('[data-cy=collection-info-panel]') + .should('contain', 'default') + .and('contain', 'foo') + .and('not.contain', 'bar'); + cy.doRequest('GET', `/arvados/v1/collections/${this.collection.uuid}`) + .its('body').as('updatedCollection') + .then(function () { + expect(this.updatedCollection.storage_classes_desired).to.deep.equal(['default', 'foo']); + }); + // Edit collection: remove storage class 'default' + cy.get('[data-cy=collection-panel-options-btn]').click(); + cy.get('[data-cy=context-menu]').contains('Edit collection').click(); + cy.get('[data-cy=form-dialog]') + .should('contain', 'Edit Collection') + .and('contain', 'Storage classes') + .and('contain', 'default') + .and('contain', 'foo') + .and('contain', 'bar') + .within(() => { + cy.get('[data-cy=checkbox-default]').click(); + }); + cy.get('[data-cy=form-submit-btn]').click(); + cy.get('[data-cy=collection-info-panel]') + .should('not.contain', 'default') + .and('contain', 'foo') + .and('not.contain', 'bar'); + cy.doRequest('GET', `/arvados/v1/collections/${this.collection.uuid}`) + .its('body').as('updatedCollection') + .then(function () { + expect(this.updatedCollection.storage_classes_desired).to.deep.equal(['foo']); + }); }) - .as('collection') - .then((collection) => { - cy.loginAs(activeUser) - cy.doSearch(`${collection.uuid}`); - cy.get('[data-cy=collection-files-panel]').contains('#foo').closest('[data-cy=virtual-file-tree]').find('[type=checkbox]').click(); - cy.get('[data-cy=collection-files-panel-options-btn]').click(); - cy.get('[data-cy=context-menu]').contains('Remove selected').click(); - cy.get('[data-cy=confirmation-dialog-ok-btn]').click(); - cy.get('[data-cy=collection-files-panel]').contains('#foo').should('not.exist'); + }); + + it('moves a collection to a different project', function () { + const collName = `Test Collection ${Math.floor(Math.random() * 999999)}`; + const projName = `Test Project ${Math.floor(Math.random() * 999999)}`; + const fileName = `Test_File_${Math.floor(Math.random() * 999999)}`; + + cy.createCollection(adminUser.token, { + name: collName, + owner_uuid: activeUser.user.uuid, + manifest_text: `. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n`, + }).as('testCollection'); + cy.createGroup(adminUser.token, { + name: projName, + group_class: 'project', + owner_uuid: activeUser.user.uuid, + }).as('testProject'); - cy.get('[data-cy=collection-files-panel]').contains('bar').rightclick(); - cy.get('[data-cy=context-menu]').contains('Rename').click(); - cy.get('input[name=path]').type('bar 123 321 bar'); + cy.getAll('@testCollection', '@testProject') + .then(function ([testCollection, testProject]) { + cy.loginAs(activeUser); + cy.goToPath(`/collections/${testCollection.uuid}`); + cy.get('[data-cy=collection-files-panel]').should('contain', fileName); + cy.get('[data-cy=collection-info-panel]') + .should('not.contain', projName) + .and('not.contain', testProject.uuid); + cy.get('[data-cy=collection-panel-options-btn]').click(); + cy.get('[data-cy=context-menu]').contains('Move to').click(); + cy.get('[data-cy=form-dialog]') + .should('contain', 'Move to') + .within(() => { + cy.get('[data-cy=projects-tree-home-tree-picker]') + .find('i') + .click(); + cy.get('[data-cy=projects-tree-home-tree-picker]') + .contains(projName) + .click(); + }); cy.get('[data-cy=form-submit-btn]').click(); - cy.get('[data-cy=collection-files-panel]').contains('barbar 123 321 bar').should('exist'); + cy.get('[data-cy=snackbar]') + .contains('Collection has been moved') + cy.get('[data-cy=collection-info-panel]') + .contains(projName).and('contain', testProject.uuid); + // Double check that the collection is in the project + cy.goToPath(`/projects/${testProject.uuid}`); + cy.get('[data-cy=project-panel]').should('contain', collName); }); }); + it('automatically updates the collection UI contents without using the Refresh button', function () { + const collName = `Test Collection ${Math.floor(Math.random() * 999999)}`; + const fileName = 'foobar' + + cy.createCollection(adminUser.token, { + name: collName, + owner_uuid: activeUser.user.uuid, + }).as('testCollection'); + + cy.getAll('@testCollection').then(function ([testCollection]) { + cy.loginAs(activeUser); + cy.goToPath(`/collections/${testCollection.uuid}`); + cy.get('[data-cy=collection-files-panel]').should('contain', 'This collection is empty'); + cy.get('[data-cy=collection-files-panel]').should('not.contain', fileName); + cy.get('[data-cy=collection-info-panel]').should('contain', collName); + + cy.updateCollection(adminUser.token, testCollection.uuid, { + name: `${collName + ' updated'}`, + manifest_text: `. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n`, + }).as('updatedCollection'); + cy.getAll('@updatedCollection').then(function ([updatedCollection]) { + expect(updatedCollection.name).to.equal(`${collName + ' updated'}`); + cy.get('[data-cy=collection-info-panel]').should('contain', updatedCollection.name); + cy.get('[data-cy=collection-files-panel]').should('contain', fileName); + }); + }); + }) + + it('makes a copy of an existing collection', function() { + const collName = `Test Collection ${Math.floor(Math.random() * 999999)}`; + const copyName = `Copy of: ${collName}`; + + cy.createCollection(adminUser.token, { + name: collName, + owner_uuid: activeUser.user.uuid, + manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:some-file\n", + }).as('collection').then(function () { + cy.loginAs(activeUser) + cy.goToPath(`/collections/${this.collection.uuid}`); + cy.get('[data-cy=collection-files-panel]') + .should('contain', 'some-file'); + cy.get('[data-cy=collection-panel-options-btn]').click(); + cy.get('[data-cy=context-menu]').contains('Make a copy').click(); + cy.get('[data-cy=form-dialog]') + .should('contain', 'Make a copy') + .within(() => { + cy.get('[data-cy=projects-tree-home-tree-picker]') + .contains('Projects') + .click(); + cy.get('[data-cy=form-submit-btn]').click(); + }); + cy.get('[data-cy=snackbar]') + .contains('Collection has been copied.') + cy.get('[data-cy=snackbar-goto-action]').click(); + cy.get('[data-cy=project-panel]') + .contains(copyName).click(); + cy.get('[data-cy=collection-files-panel]') + .should('contain', 'some-file'); + }); + }); + it('uses the collection version browser to view a previous version', function () { const colName = `Test Collection ${Math.floor(Math.random() * 999999)}`; @@ -393,7 +701,7 @@ describe('Collection panel tests', function () { .as('collection').then(function () { // Visit collection, check basic information cy.loginAs(activeUser) - cy.doSearch(`${this.collection.uuid}`); + cy.goToPath(`/collections/${this.collection.uuid}`); cy.get('[data-cy=collection-info-panel]').should('not.contain', 'This is an old version'); cy.get('[data-cy=read-only-icon]').should('not.exist'); @@ -417,10 +725,14 @@ describe('Collection panel tests', function () { .within(() => { // Version 1: 6 bytes in size cy.get('[data-cy=collection-version-browser-select-1]') - .should('contain', '1').and('contain', '6 B'); + .should('contain', '1') + .and('contain', '6 B') + .and('contain', adminUser.user.uuid); // Version 2: 3 bytes in size (one file removed) cy.get('[data-cy=collection-version-browser-select-2]') - .should('contain', '2').and('contain', '3 B'); + .should('contain', '2') + .and('contain', '3 B') + .and('contain', activeUser.user.full_name); cy.get('[data-cy=collection-version-browser-select-3]') .should('not.exist'); cy.get('[data-cy=collection-version-browser-select-1]') @@ -507,29 +819,235 @@ describe('Collection panel tests', function () { }); }); - it('creates new collection on home project', function () { + it('creates collection from selected files of another collection', () => { + cy.createCollection(adminUser.token, { + name: `Test Collection ${Math.floor(Math.random() * 999999)}`, + owner_uuid: activeUser.user.uuid, + preserve_version: true, + manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo 0:3:bar\n" + }) + .as('collection').then(function () { + // Visit collection, check basic information + cy.loginAs(activeUser) + cy.goToPath(`/collections/${this.collection.uuid}`); + + cy.get('[data-cy=collection-files-panel]').within(() => { + cy.get('input[type=checkbox]').first().click(); + }); + + cy.get('[data-cy=collection-files-panel-options-btn]').click(); + cy.get('[data-cy=context-menu]').contains('Create a new collection with selected').click(); + + cy.get('[data-cy=form-dialog]').contains('Projects').click(); + + cy.get('[data-cy=form-submit-btn]').click(); + + cy.get('.layout-pane-primary', { timeout: 12000 }).contains('Projects').click(); + + cy.get('main').contains(`Files extracted from: ${this.collection.name}`).should('exist'); + }); + }); + + it('creates new collection with properties on home project', function () { cy.loginAs(activeUser); - cy.doSearch(`${activeUser.user.uuid}`); + cy.goToPath(`/projects/${activeUser.user.uuid}`); cy.get('[data-cy=breadcrumb-first]').should('contain', 'Projects'); cy.get('[data-cy=breadcrumb-last]').should('not.exist'); // Create new collection cy.get('[data-cy=side-panel-button]').click(); cy.get('[data-cy=side-panel-new-collection]').click(); - const collName = `Test collection (${Math.floor(999999 * Math.random())})`; + // Name between brackets tests bugfix #17582 + const collName = `[Test collection (${Math.floor(999999 * Math.random())})]`; + + // Select a storage class. cy.get('[data-cy=form-dialog]') .should('contain', 'New collection') + .and('contain', 'Storage classes') + .and('contain', 'default') + .and('contain', 'foo') + .and('contain', 'bar') .within(() => { cy.get('[data-cy=parent-field]').within(() => { cy.get('input').should('have.value', 'Home project'); - }) + }); cy.get('[data-cy=name-field]').within(() => { cy.get('input').type(collName); - }) + }); + cy.get('[data-cy=checkbox-foo]').click(); }) + + // Add a property. + // Key: Color (IDTAGCOLORS) - Value: Magenta (IDVALCOLORS3) + cy.get('[data-cy=form-dialog]').should('not.contain', 'Color: Magenta'); + cy.get('[data-cy=resource-properties-form]').within(() => { + cy.get('[data-cy=property-field-key]').within(() => { + cy.get('input').type('Color'); + }); + cy.get('[data-cy=property-field-value]').within(() => { + cy.get('input').type('Magenta'); + }); + cy.root().submit(); + }); + // Confirm proper vocabulary labels are displayed on the UI. + cy.get('[data-cy=form-dialog]').should('contain', 'Color: Magenta'); + cy.get('[data-cy=form-submit-btn]').click(); - // Confirm that the user was taken to the newly created thing + // Confirm that the user was taken to the newly created collection cy.get('[data-cy=form-dialog]').should('not.exist'); cy.get('[data-cy=breadcrumb-first]').should('contain', 'Projects'); cy.get('[data-cy=breadcrumb-last]').should('contain', collName); + cy.get('[data-cy=collection-info-panel]') + .should('contain', 'default') + .and('contain', 'foo') + .and('contain', 'Color: Magenta') + .and('not.contain', 'bar'); + // Confirm that the collection's properties has the real values. + cy.doRequest('GET', '/arvados/v1/collections', null, { + filters: `[["name", "=", "${collName}"]]`, + }) + .its('body.items').as('collections') + .then(function() { + expect(this.collections).to.have.lengthOf(1); + expect(this.collections[0].properties).to.have.property( + 'IDTAGCOLORS', 'IDVALCOLORS3'); + }); + }); + + it('shows responsible person for collection if available', () => { + cy.createCollection(adminUser.token, { + name: `Test collection ${Math.floor(Math.random() * 999999)}`, + owner_uuid: activeUser.user.uuid, + manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n" + }).as('testCollection1'); + + cy.createCollection(adminUser.token, { + name: `Test collection ${Math.floor(Math.random() * 999999)}`, + owner_uuid: adminUser.user.uuid, + manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n" + }).as('testCollection2').then(function (testCollection2) { + cy.shareWith(adminUser.token, activeUser.user.uuid, testCollection2.uuid, 'can_write'); + }); + + cy.getAll('@testCollection1', '@testCollection2') + .then(function ([testCollection1, testCollection2]) { + cy.loginAs(activeUser); + + cy.goToPath(`/collections/${testCollection1.uuid}`); + cy.get('[data-cy=responsible-person-wrapper]') + .contains(activeUser.user.uuid); + + cy.goToPath(`/collections/${testCollection2.uuid}`); + cy.get('[data-cy=responsible-person-wrapper]') + .contains(adminUser.user.uuid); + }); + }); + + describe('file upload', () => { + beforeEach(() => { + cy.createCollection(adminUser.token, { + name: `Test collection ${Math.floor(Math.random() * 999999)}`, + owner_uuid: activeUser.user.uuid, + manifest_text: "./subdir 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo\n. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n" + }).as('testCollection1'); + }); + + it('uploads a file and checks the collection UI to be fresh', () => { + cy.getAll('@testCollection1') + .then(function([testCollection1]) { + cy.loginAs(activeUser); + cy.goToPath(`/collections/${testCollection1.uuid}`); + cy.get('[data-cy=upload-button]').click(); + cy.get('[data-cy=collection-files-panel]') + .contains('5mb_a.bin').should('not.exist'); + cy.get('[data-cy=collection-file-count]').should('contain', '2'); + cy.fixture('files/5mb.bin', 'base64').then(content => { + cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_a.bin'); + cy.get('[data-cy=form-submit-btn]').click(); + cy.get('[data-cy=form-submit-btn]').should('not.exist'); + cy.get('[data-cy=collection-files-panel]') + .contains('5mb_a.bin').should('exist'); + cy.get('[data-cy=collection-file-count]').should('contain', '3'); + + cy.get('[data-cy=collection-files-panel]').contains('subdir').click(); + cy.get('[data-cy=upload-button]').click(); + cy.fixture('files/5mb.bin', 'base64').then(content => { + cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_b.bin'); + cy.get('[data-cy=form-submit-btn]').click(); + cy.get('[data-cy=form-submit-btn]').should('not.exist'); + cy.get('[data-cy=collection-files-right-panel]') + .contains('5mb_b.bin').should('exist'); + }); + }); + }); + }); + + it('allows to cancel running upload', () => { + cy.getAll('@testCollection1') + .then(function([testCollection1]) { + cy.loginAs(activeUser); + + cy.goToPath(`/collections/${testCollection1.uuid}`); + + cy.get('[data-cy=upload-button]').click(); + + cy.fixture('files/5mb.bin', 'base64').then(content => { + cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_a.bin'); + cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_b.bin'); + + cy.get('[data-cy=form-submit-btn]').click(); + + cy.get('button').contains('Cancel').click(); + + cy.get('[data-cy=form-submit-btn]').should('not.exist'); + }); + }); + }); + + it('allows to cancel single file from the running upload', () => { + cy.getAll('@testCollection1') + .then(function([testCollection1]) { + cy.loginAs(activeUser); + + cy.goToPath(`/collections/${testCollection1.uuid}`); + + cy.get('[data-cy=upload-button]').click(); + + cy.fixture('files/5mb.bin', 'base64').then(content => { + cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_a.bin'); + cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_b.bin'); + + cy.get('[data-cy=form-submit-btn]').click(); + + cy.get('button[aria-label=Remove]').eq(1).click(); + + cy.get('[data-cy=form-submit-btn]').should('not.exist'); + + cy.get('[data-cy=collection-files-panel]').contains('5mb_a.bin').should('exist'); + }); + }); + }); + + it('allows to cancel all files from the running upload', () => { + cy.getAll('@testCollection1') + .then(function([testCollection1]) { + cy.loginAs(activeUser); + + cy.goToPath(`/collections/${testCollection1.uuid}`); + + cy.get('[data-cy=upload-button]').click(); + + cy.fixture('files/5mb.bin', 'base64').then(content => { + cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_a.bin'); + cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_b.bin'); + + cy.get('[data-cy=form-submit-btn]').click(); + + cy.get('button[aria-label=Remove]').should('exist'); + cy.get('button[aria-label=Remove]').click({ multiple: true, force: true }); + + cy.get('[data-cy=form-submit-btn]').should('not.exist'); + }); + }); + }); }); })