1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 const path = require("path");
6 require('cypress-plugin-tab')
8 describe("Collection panel tests", function () {
14 // Only set up common users once. These aren't set up as aliases because
15 // aliases are cleaned up after every test. Also it doesn't make sense
16 // to set the same users on beforeEach() over and over again, so we
17 // separate a little from Cypress' 'Best Practices' here.
18 cy.getUser("admin", "Admin", "User", true, true)
21 adminUser = this.adminUser;
23 cy.getUser("collectionuser1", "Collection", "User", false, true)
26 activeUser = this.activeUser;
28 downloadsFolder = Cypress.config("downloadsFolder");
31 it('shows the appropriate buttons in the toolbar', () => {
33 const msButtonTooltips = [
36 'Copy link to clipboard',
37 'Open with 3rd party client',
47 cy.loginAs(activeUser);
48 const name = `Test collection ${Math.floor(Math.random() * 999999)}`;
49 cy.get("[data-cy=side-panel-button]").click({force: true});
50 cy.get("[data-cy=side-panel-new-collection]").click();
51 cy.get("[data-cy=form-dialog]")
52 .should("contain", "New collection")
54 cy.get("[data-cy=name-field]").within(() => {
55 cy.get("input").type(name);
57 cy.get("[data-cy=form-submit-btn]").click();
59 cy.get("[data-cy=side-panel-tree]").contains("Home Projects").click();
61 cy.get('[data-cy=data-table-row]').contains(name).should('exist').parents('td').click()
63 cy.get('[data-cy=multiselect-button]').should('have.length', msButtonTooltips.length)
64 msButtonTooltips.forEach((tooltip, index) => {
65 cy.get('[data-cy=multiselect-button]').eq(index).parent().should('have.attr', 'aria-label', tooltip)
69 it("allows to download mountain duck config for a collection", () => {
70 cy.createCollection(adminUser.token, {
71 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
72 owner_uuid: activeUser.user.uuid,
73 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
76 .then(function (testCollection) {
77 cy.loginAs(activeUser);
78 cy.goToPath(`/collections/${testCollection.uuid}`);
80 cy.get("[data-cy=collection-panel-options-btn]").click();
81 cy.get("[data-cy=context-menu]").contains("Open with 3rd party client").click();
82 cy.get("[data-cy=download-button").click();
84 const filename = path.join(downloadsFolder, `${testCollection.name}.duck`);
86 cy.readFile(filename, { timeout: 15000 })
88 const childrenCollection = Array.prototype.slice.call(Cypress.$(body).find("dict")[0].children);
93 for (i = 0; i < childrenCollection.length; i += j) {
94 map[childrenCollection[i].outerText] = childrenCollection[i + 1].outerText;
97 cy.get("#simple-tabpanel-0")
100 const [host, port] = a.text().split("@")[1].split("/")[0].split(":");
101 expect(map["Protocol"]).to.equal("davs");
102 expect(map["UUID"]).to.equal(testCollection.uuid);
103 expect(map["Username"]).to.equal(activeUser.user.username);
104 expect(map["Port"]).to.equal(port);
105 expect(map["Hostname"]).to.equal(host);
107 expect(map["Path"]).to.equal(`/c=${testCollection.uuid}`);
111 .then(() => cy.task("clearDownload", { filename }));
115 it("attempts to use a preexisting name creating or updating a collection", function () {
116 const name = `Test collection ${Math.floor(Math.random() * 999999)}`;
117 cy.createCollection(adminUser.token, {
119 owner_uuid: activeUser.user.uuid,
120 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
122 cy.loginAs(activeUser);
123 cy.goToPath(`/projects/${activeUser.user.uuid}`);
124 cy.get("[data-cy=breadcrumb-first]").should("contain", "Projects");
125 cy.get("[data-cy=breadcrumb-last]").should("not.exist");
126 // Attempt to create new collection with a duplicate name
127 cy.get("[data-cy=side-panel-button]").click();
128 cy.get("[data-cy=side-panel-new-collection]").click();
129 cy.get("[data-cy=form-dialog]")
130 .should("contain", "New collection")
132 cy.get("[data-cy=name-field]").within(() => {
133 cy.get("input").type(name);
135 cy.get("[data-cy=form-submit-btn]").click();
137 // Error message should display, allowing editing the name
138 cy.get("[data-cy=form-dialog]")
140 .and("contain", "Collection with the same name already exists")
142 cy.get("[data-cy=name-field]").within(() => {
143 cy.get("input").type(" renamed");
145 cy.get("[data-cy=form-submit-btn]").click({timeout: 10000});
147 cy.get("[data-cy=form-dialog]").should("not.exist");
148 // Attempt to rename the collection with the duplicate name
149 cy.get("[data-cy=collection-panel-options-btn]").click();
150 cy.get("[data-cy=context-menu]").contains("Edit collection").click();
151 cy.get("[data-cy=form-dialog]")
152 .should("contain", "Edit Collection")
154 cy.get("[data-cy=name-field]").within(() => {
155 cy.get("input").type("{selectall}{backspace}").type(name);
157 cy.get("[data-cy=form-submit-btn]").click();
159 cy.get("[data-cy=form-dialog]").should("exist").and("contain", "Collection with the same name already exists");
162 it("uses the property editor (from edit dialog) with vocabulary terms", function () {
163 cy.createCollection(adminUser.token, {
164 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
165 owner_uuid: activeUser.user.uuid,
166 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
168 .as("testCollection")
170 cy.loginAs(activeUser);
171 cy.goToPath(`/collections/${this.testCollection.uuid}`);
173 cy.get("[data-cy=collection-info-panel").should("contain", this.testCollection.name).and("not.contain", "Color: Magenta");
175 cy.get("[data-cy=collection-panel-options-btn]").click();
176 cy.get("[data-cy=context-menu]").contains("Edit collection").click();
177 cy.get("[data-cy=form-dialog]").should("contain", "Properties");
179 // Key: Color (IDTAGCOLORS) - Value: Magenta (IDVALCOLORS3)
180 cy.get("[data-cy=resource-properties-form]").within(() => {
181 cy.get("[data-cy=property-field-key]").within(() => {
182 cy.get("input").type("Color");
184 cy.get("[data-cy=property-field-value]").within(() => {
185 cy.get("input").type("Magenta");
189 // Confirm proper vocabulary labels are displayed on the UI.
190 cy.get("[data-cy=form-dialog]").should("contain", "Color: Magenta");
191 cy.get("[data-cy=form-dialog]").contains("Save").click();
192 cy.get("[data-cy=form-dialog]").should("not.exist");
193 // Confirm proper vocabulary IDs were saved on the backend.
194 cy.doRequest("GET", `/arvados/v1/collections/${this.testCollection.uuid}`)
198 expect(this.collection.properties.IDTAGCOLORS).to.equal("IDVALCOLORS3");
200 // Confirm the property is displayed on the UI.
201 cy.get("[data-cy=collection-info-panel").should("contain", this.testCollection.name).and("contain", "Color: Magenta");
205 it("uses the editor (from details panel) with vocabulary terms", function () {
206 cy.createCollection(adminUser.token, {
207 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
208 owner_uuid: activeUser.user.uuid,
209 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
211 .as("testCollection")
213 cy.loginAs(activeUser);
214 cy.goToPath(`/collections/${this.testCollection.uuid}`);
216 cy.get("[data-cy=collection-info-panel")
217 .should("contain", this.testCollection.name)
218 .and("not.contain", "Color: Magenta")
219 .and("not.contain", "Size: S");
220 cy.get("[data-cy=additional-info-icon]").click();
222 cy.get("[data-cy=details-panel]").within(() => {
223 cy.get("[data-cy=details-panel-edit-btn]").click();
225 cy.get("[data-cy=form-dialog").contains("Edit Collection");
227 // Key: Color (IDTAGCOLORS) - Value: Magenta (IDVALCOLORS3)
228 cy.get("[data-cy=resource-properties-form]").within(() => {
229 cy.get("[data-cy=property-field-key]").within(() => {
230 cy.get("input").type("Color");
232 cy.get("[data-cy=property-field-value]").within(() => {
233 cy.get("input").type("Magenta");
237 // Confirm proper vocabulary labels are displayed on the UI.
238 cy.get("[data-cy=form-dialog]").should("contain", "Color: Magenta");
240 // Case-insensitive on-blur auto-selection test
241 // Key: Size (IDTAGSIZES) - Value: Small (IDVALSIZES2)
242 cy.get("[data-cy=resource-properties-form]").within(() => {
243 cy.get("[data-cy=property-field-key]").within(() => {
244 cy.get("input").type("sIzE");
246 cy.get("[data-cy=property-field-value]").within(() => {
247 cy.get("input").type("sMaLL");
249 // simulate tabbing out of the value field
254 // Confirm proper vocabulary labels are displayed on the UI.
255 cy.get("[data-cy=form-dialog]").should("contain", "Size: S");
257 cy.get("[data-cy=form-dialog]").contains("Save").click();
258 cy.get("[data-cy=form-dialog]").should("not.exist");
260 // Confirm proper vocabulary IDs were saved on the backend.
261 cy.doRequest("GET", `/arvados/v1/collections/${this.testCollection.uuid}`)
265 expect(this.collection.properties.IDTAGCOLORS).to.equal("IDVALCOLORS3");
266 expect(this.collection.properties.IDTAGSIZES).to.equal("IDVALSIZES2");
269 // Confirm properties display on the UI.
270 cy.get("[data-cy=collection-info-panel")
271 .should("contain", this.testCollection.name)
272 .and("contain", "Color: Magenta")
273 .and("contain", "Size: S");
277 it("shows collection by URL", function () {
278 cy.loginAs(activeUser);
279 [true, false].map(function (isWritable) {
280 // Using different file names to avoid test flakyness: the second iteration
281 // on this loop may pass an assertion from the first iteration by looking
282 // for the same file name.
283 const fileName = isWritable ? "bar" : "foo";
284 const subDirName = "subdir";
285 cy.createGroup(adminUser.token, {
286 name: "Shared project",
287 group_class: "project",
291 // Creates the collection using the admin token so we can set up
292 // a bogus manifest text without block signatures.
293 cy.doRequest("GET", "/arvados/v1/config", null, null)
295 .should(clusterConfig => {
296 expect(clusterConfig.Collections, "clusterConfig").to.have.property("TrustAllContent", true);
297 expect(clusterConfig.Services, "clusterConfig").to.have.property("WebDAV").have.property("ExternalURL");
298 expect(clusterConfig.Services, "clusterConfig").to.have.property("WebDAVDownload").have.property("ExternalURL");
300 clusterConfig.Services.WebDAV.ExternalURL !== ""
301 ? clusterConfig.Services.WebDAV.ExternalURL
302 : clusterConfig.Services.WebDAVDownload.ExternalURL;
303 expect(inlineUrl).to.not.contain("*");
305 .createCollection(adminUser.token, {
306 name: "Test collection",
307 owner_uuid: this.sharedGroup.uuid,
308 properties: { someKey: "someValue" },
309 manifest_text: `. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n./${subDirName} 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n`,
311 .as("testCollection")
313 // Share the group with active user.
314 cy.createLink(adminUser.token, {
315 name: isWritable ? "can_write" : "can_read",
316 link_class: "permission",
317 head_uuid: this.sharedGroup.uuid,
318 tail_uuid: activeUser.user.uuid,
320 cy.goToPath(`/collections/${this.testCollection.uuid}`);
322 // Check that name & uuid are correct.
323 cy.get("[data-cy=collection-info-panel]")
324 .should("contain", this.testCollection.name)
325 .and("contain", this.testCollection.uuid)
326 .and("not.contain", "This is an old version");
327 // Check for the read-only icon
328 cy.get("[data-cy=read-only-icon]").should(`${isWritable ? "not." : ""}exist`);
329 // Check that both read and write operations are available on
330 // the 'More options' menu.
331 cy.get("[data-cy=collection-panel-options-btn]").click();
332 cy.get("[data-cy=context-menu]")
333 .should("contain", "Add to favorites")
334 .and(`${isWritable ? "" : "not."}contain`, "Edit collection");
335 cy.get("body").click(); // Collapse the menu avoiding details panel expansion
336 cy.get("[data-cy=collection-info-panel]")
337 .should("contain", "someKey: someValue")
338 .and("not.contain", "anotherKey: anotherValue");
339 // Check that the file listing show both read & write operations
341 .get("[data-cy=collection-files-panel]")
343 cy.get("[data-cy=collection-files-right-panel]", { timeout: 5000 }).should("contain", fileName);
345 cy.get("[data-cy=upload-button]").should(`${isWritable ? "" : "not."}contain`, "Upload data");
348 // Test context menus
349 cy.get("[data-cy=collection-files-panel]").contains(fileName).rightclick();
350 cy.get("[data-cy=context-menu]")
351 .should("contain", "Download")
352 .and("contain", "Open in new tab")
353 .and("contain", "Copy link to clipboard")
354 .and(`${isWritable ? "" : "not."}contain`, "Rename")
355 .and(`${isWritable ? "" : "not."}contain`, "Remove");
356 cy.get("body").click(); // Collapse the menu
357 cy.get("[data-cy=collection-files-panel]").contains(subDirName).rightclick();
358 cy.get("[data-cy=context-menu]")
359 .should("not.contain", "Download")
360 .and("contain", "Open in new tab")
361 .and("contain", "Copy link to clipboard")
362 .and(`${isWritable ? "" : "not."}contain`, "Rename")
363 .and(`${isWritable ? "" : "not."}contain`, "Remove");
364 cy.get("body").click(); // Collapse the menu
365 // File/dir item 'more options' button
366 cy.get("[data-cy=file-item-options-btn").first().click();
367 cy.get("[data-cy=context-menu]").should(`${isWritable ? "" : "not."}contain`, "Remove");
368 cy.get("body").click(); // Collapse the menu
369 // Hamburger 'more options' menu button
370 cy.get("[data-cy=collection-files-panel-options-btn]").click();
371 cy.get("[data-cy=context-menu]").should("contain", "Select all").click();
372 cy.get("[data-cy=collection-files-panel-options-btn]").click();
373 cy.get("[data-cy=context-menu]").should(`${isWritable ? "" : "not."}contain`, "Remove selected");
374 cy.get("body").click(); // Collapse the menu
380 it("renames a file using valid names", function () {
381 function eachPair(lst, func) {
382 for (var i = 0; i < lst.length - 1; i++) {
383 func(lst[i], lst[i + 1]);
386 // Creates the collection using the admin token so we can set up
387 // a bogus manifest text without block signatures.
388 cy.createCollection(adminUser.token, {
389 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
390 owner_uuid: activeUser.user.uuid,
391 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
393 .as("testCollection")
395 cy.loginAs(activeUser);
396 cy.goToPath(`/collections/${this.testCollection.uuid}`);
399 "bar", // initial name already set
406 "some name with whitespaces",
408 "is this name legal? I hope it is",
416 "G%C3%BCnter's%20file.pdf",
418 "bar", // make sure we can go back to the original name as a last step
420 cy.intercept({ method: "PUT", url: "**/arvados/v1/collections/*" }).as("renameRequest");
421 eachPair(names, (from, to) => {
422 cy.waitForDom().get("[data-cy=collection-files-panel]").contains(`${from}`).rightclick();
423 cy.get("[data-cy=context-menu]").contains("Rename").click();
424 cy.get("[data-cy=form-dialog]")
425 .should("contain", "Rename")
427 cy.get("input").type("{selectall}{backspace}").type(to, { parseSpecialCharSequences: false });
429 cy.get("[data-cy=form-submit-btn]").click();
430 cy.wait("@renameRequest");
431 cy.get("[data-cy=collection-files-panel]").should("not.contain", `${from}`).and("contain", `${to}`);
436 it("renames a file to a different directory", function () {
437 // Creates the collection using the admin token so we can set up
438 // a bogus manifest text without block signatures.
439 cy.createCollection(adminUser.token, {
440 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
441 owner_uuid: activeUser.user.uuid,
442 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
444 .as("testCollection")
446 cy.loginAs(activeUser);
447 cy.goToPath(`/collections/${this.testCollection.uuid}`);
449 ["subdir", "G%C3%BCnter's%20file", "table%&?*2"].forEach(subdir => {
450 cy.waitForDom().get("[data-cy=collection-files-panel]").contains("bar").rightclick();
451 cy.get("[data-cy=context-menu]").contains("Rename").click();
452 cy.get("[data-cy=form-dialog]")
453 .should("contain", "Rename")
455 cy.get("input").type(`{selectall}{backspace}${subdir}/foo`);
457 cy.get("[data-cy=form-submit-btn]").click();
458 cy.get("[data-cy=collection-files-panel]").should("not.contain", "bar").and("contain", subdir);
459 cy.get("[data-cy=collection-files-panel]").contains(subdir).click();
461 // Rename 'subdir/foo' to 'bar'
463 cy.get("[data-cy=collection-files-panel]").contains("foo").rightclick();
464 cy.get("[data-cy=context-menu]").contains("Rename").click();
465 cy.get("[data-cy=form-dialog]")
466 .should("contain", "Rename")
468 cy.get("input").should("have.value", `${subdir}/foo`).type(`{selectall}{backspace}bar`);
470 cy.get("[data-cy=form-submit-btn]").click();
472 // need to wait for dialog to dismiss
473 cy.get("[data-cy=form-dialog]").should("not.exist");
475 cy.waitForDom().get("[data-cy=collection-files-panel]").contains("Home").click();
478 cy.get("[data-cy=collection-files-panel]")
479 .should("contain", subdir) // empty dir kept
480 .and("contain", "bar");
482 cy.get("[data-cy=collection-files-panel]").contains(subdir).rightclick();
483 cy.get("[data-cy=context-menu]").contains("Remove").click();
484 cy.get("[data-cy=confirmation-dialog-ok-btn]").click();
485 cy.get("[data-cy=form-dialog]").should("not.exist");
490 it("shows collection owner", () => {
491 cy.createCollection(adminUser.token, {
492 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
493 owner_uuid: activeUser.user.uuid,
494 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
496 .as("testCollection")
497 .then(testCollection => {
498 cy.loginAs(activeUser);
499 cy.goToPath(`/collections/${testCollection.uuid}`);
501 cy.get("[data-cy=collection-info-panel]").contains(`Collection User`);
505 it("tries to rename a file with illegal names", function () {
506 // Creates the collection using the admin token so we can set up
507 // a bogus manifest text without block signatures.
508 cy.createCollection(adminUser.token, {
509 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
510 owner_uuid: activeUser.user.uuid,
511 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
513 .as("testCollection")
515 cy.loginAs(activeUser);
516 cy.goToPath(`/collections/${this.testCollection.uuid}`);
518 const illegalNamesFromUI = [
519 [".", "Name cannot be '.' or '..'"],
520 ["..", "Name cannot be '.' or '..'"],
521 ["", "This field is required"],
522 [" ", "Leading/trailing whitespaces not allowed"],
523 [" foo", "Leading/trailing whitespaces not allowed"],
524 ["foo ", "Leading/trailing whitespaces not allowed"],
525 ["//foo", "Empty dir name not allowed"],
527 illegalNamesFromUI.forEach(([name, errMsg]) => {
528 cy.get("[data-cy=collection-files-panel]").contains("bar").rightclick();
529 cy.get("[data-cy=context-menu]").contains("Rename").click();
530 cy.get("[data-cy=form-dialog]")
531 .should("contain", "Rename")
533 cy.get("input").type(`{selectall}{backspace}${name}`);
535 cy.get("[data-cy=form-dialog]")
536 .should("contain", "Rename")
538 cy.contains(`${errMsg}`);
540 cy.get("[data-cy=form-cancel-btn]").click();
545 it("can correctly display old versions", function () {
546 const colName = `Versioned Collection ${Math.floor(Math.random() * 999999)}`;
548 let oldVersionUuid = "";
549 // Make sure no other collections with this name exist
550 cy.doRequest("GET", "/arvados/v1/collections", null, {
551 filters: `[["name", "=", "${colName}"]]`,
552 include_old_versions: true,
557 expect(this.collections).to.be.empty;
559 // Creates the collection using the admin token so we can set up
560 // a bogus manifest text without block signatures.
561 cy.createCollection(adminUser.token, {
563 owner_uuid: activeUser.user.uuid,
564 preserve_version: true,
565 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
567 .as("originalVersion")
569 // Change the file name to create a new version.
570 cy.updateCollection(adminUser.token, this.originalVersion.uuid, {
571 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo\n",
573 colUuid = this.originalVersion.uuid;
575 // Confirm that there are 2 versions of the collection
576 cy.doRequest("GET", "/arvados/v1/collections", null, {
577 filters: `[["name", "=", "${colName}"]]`,
578 include_old_versions: true,
583 expect(this.collections).to.have.lengthOf(2);
584 this.collections.map(function (aCollection) {
585 expect(aCollection.current_version_uuid).to.equal(colUuid);
586 if (aCollection.uuid !== aCollection.current_version_uuid) {
587 oldVersionUuid = aCollection.uuid;
590 // Check the old version displays as what it is.
591 cy.loginAs(activeUser);
592 cy.goToPath(`/collections/${oldVersionUuid}`);
594 cy.get("[data-cy=collection-info-panel]").should("contain", "This is an old version");
595 cy.get("[data-cy=read-only-icon]").should("exist");
596 cy.get("[data-cy=collection-info-panel]").should("contain", colName);
597 cy.get("[data-cy=collection-files-panel]").should("contain", "bar");
601 it("views & edits storage classes data", function () {
602 const colName = `Test Collection ${Math.floor(Math.random() * 999999)}`;
603 cy.createCollection(adminUser.token, {
605 owner_uuid: activeUser.user.uuid,
606 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:some-file\n",
610 expect(this.collection.storage_classes_desired).to.deep.equal(["default"]);
612 cy.loginAs(activeUser);
613 cy.goToPath(`/collections/${this.collection.uuid}`);
615 // Initial check: it should show the 'default' storage class
616 cy.get("[data-cy=collection-info-panel]")
617 .should("contain", "Storage classes")
618 .and("contain", "default")
619 .and("not.contain", "foo")
620 .and("not.contain", "bar");
621 // Edit collection: add storage class 'foo'
622 cy.get("[data-cy=collection-panel-options-btn]").click();
623 cy.get("[data-cy=context-menu]").contains("Edit collection").click();
624 cy.get("[data-cy=form-dialog]")
625 .should("contain", "Edit Collection")
626 .and("contain", "Storage classes")
627 .and("contain", "default")
628 .and("contain", "foo")
629 .and("contain", "bar")
631 cy.get("[data-cy=checkbox-foo]").click();
633 cy.get("[data-cy=form-submit-btn]").click();
634 cy.get("[data-cy=collection-info-panel]").should("contain", "default").and("contain", "foo").and("not.contain", "bar");
635 cy.doRequest("GET", `/arvados/v1/collections/${this.collection.uuid}`)
637 .as("updatedCollection")
639 expect(this.updatedCollection.storage_classes_desired).to.deep.equal(["default", "foo"]);
641 // Edit collection: remove storage class 'default'
642 cy.get("[data-cy=collection-panel-options-btn]").click();
643 cy.get("[data-cy=context-menu]").contains("Edit collection").click();
644 cy.get("[data-cy=form-dialog]")
645 .should("contain", "Edit Collection")
646 .and("contain", "Storage classes")
647 .and("contain", "default")
648 .and("contain", "foo")
649 .and("contain", "bar")
651 cy.get("[data-cy=checkbox-default]").click();
653 cy.get("[data-cy=form-submit-btn]").click();
654 cy.get("[data-cy=collection-info-panel]").should("not.contain", "default").and("contain", "foo").and("not.contain", "bar");
655 cy.doRequest("GET", `/arvados/v1/collections/${this.collection.uuid}`)
657 .as("updatedCollection")
659 expect(this.updatedCollection.storage_classes_desired).to.deep.equal(["foo"]);
664 it("moves a collection to a different project", function () {
665 const collName = `Test Collection ${Math.floor(Math.random() * 999999)}`;
666 const projName = `Test Project ${Math.floor(Math.random() * 999999)}`;
667 const fileName = `Test_File_${Math.floor(Math.random() * 999999)}`;
669 cy.createCollection(adminUser.token, {
671 owner_uuid: activeUser.user.uuid,
672 manifest_text: `. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n`,
673 }).as("testCollection");
674 cy.createGroup(adminUser.token, {
676 group_class: "project",
677 owner_uuid: activeUser.user.uuid,
678 }).as("testProject");
680 cy.getAll("@testCollection", "@testProject").then(function ([testCollection, testProject]) {
681 cy.loginAs(activeUser);
682 cy.goToPath(`/collections/${testCollection.uuid}`);
683 cy.get("[data-cy=collection-files-panel]").should("contain", fileName);
684 cy.get("[data-cy=collection-info-panel]").should("not.contain", projName).and("not.contain", testProject.uuid);
685 cy.get("[data-cy=collection-panel-options-btn]").click();
686 cy.get("[data-cy=context-menu]").contains("Move to").click();
687 cy.get("[data-cy=form-dialog]")
688 .should("contain", "Move to")
690 // must use .then to avoid selecting instead of expanding https://github.com/cypress-io/cypress/issues/5529
691 cy.get("[data-cy=projects-tree-home-tree-picker]")
693 .then(el => el.click());
694 cy.get("[data-cy=projects-tree-home-tree-picker]").contains(projName).click();
696 cy.get("[data-cy=form-submit-btn]").click();
697 cy.get("[data-cy=snackbar]").contains("Collection has been moved");
698 cy.get("[data-cy=collection-info-panel]").contains(projName).and("contain", testProject.uuid);
699 // Double check that the collection is in the project
700 cy.goToPath(`/projects/${testProject.uuid}`);
701 cy.waitForDom().get("[data-cy=project-panel]").should("contain", collName);
705 it("automatically updates the collection UI contents without using the Refresh button", function () {
706 const collName = `Test Collection ${Math.floor(Math.random() * 999999)}`;
708 cy.createCollection(adminUser.token, {
710 owner_uuid: activeUser.user.uuid,
711 }).as("testCollection");
713 cy.getAll("@testCollection").then(function ([testCollection]) {
714 cy.loginAs(activeUser);
716 const files = ["foobar", "anotherFile", "", "finalName"];
718 cy.goToPath(`/collections/${testCollection.uuid}`);
719 cy.get("[data-cy=collection-files-panel]").should("contain", "This collection is empty");
720 cy.get("[data-cy=collection-files-panel]").should("not.contain", files[0]);
721 cy.get("[data-cy=collection-info-panel]").should("contain", collName);
723 files.map((fileName, i, files) => {
724 cy.updateCollection(adminUser.token, testCollection.uuid, {
725 name: `${collName + " updated"}`,
726 manifest_text: fileName ? `. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n` : "",
727 }).as("updatedCollection");
728 cy.getAll("@updatedCollection").then(function ([updatedCollection]) {
729 expect(updatedCollection.name).to.equal(`${collName + " updated"}`);
730 cy.get("[data-cy=collection-info-panel]").should("contain", updatedCollection.name);
732 ? cy.get("[data-cy=collection-files-panel]").should("contain", fileName)
733 : cy.get("[data-cy=collection-files-panel]").should("not.contain", files[i - 1]);
739 it("makes a copy of an existing collection", function () {
740 const collName = `Test Collection ${Math.floor(Math.random() * 999999)}`;
741 const copyName = `Copy of: ${collName}`;
743 cy.createCollection(adminUser.token, {
745 owner_uuid: activeUser.user.uuid,
746 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:some-file\n",
750 cy.loginAs(activeUser);
751 cy.goToPath(`/collections/${this.collection.uuid}`);
752 cy.get("[data-cy=collection-files-panel]").should("contain", "some-file");
753 cy.get("[data-cy=collection-panel-options-btn]").click();
754 cy.get("[data-cy=context-menu]").contains("Make a copy").click();
755 cy.get("[data-cy=form-dialog]")
756 .should("contain", "Make a copy")
758 cy.get("[data-cy=projects-tree-home-tree-picker]").contains("Projects").click();
759 cy.get("[data-cy=form-submit-btn]").click();
761 cy.get("[data-cy=snackbar]").contains("Collection has been copied.");
762 cy.get("[data-cy=snackbar-goto-action]").click();
763 cy.get("[data-cy=project-panel]").contains(copyName).click();
764 cy.get("[data-cy=collection-files-panel]").should("contain", "some-file");
768 it("uses the collection version browser to view a previous version", function () {
769 const colName = `Test Collection ${Math.floor(Math.random() * 999999)}`;
771 // Creates the collection using the admin token so we can set up
772 // a bogus manifest text without block signatures.
773 cy.createCollection(adminUser.token, {
775 owner_uuid: activeUser.user.uuid,
776 preserve_version: true,
777 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo 0:3:bar\n",
781 // Visit collection, check basic information
782 cy.loginAs(activeUser);
783 cy.goToPath(`/collections/${this.collection.uuid}`);
785 cy.get("[data-cy=collection-info-panel]").should("not.contain", "This is an old version");
786 cy.get("[data-cy=read-only-icon]").should("not.exist");
787 cy.get("[data-cy=collection-version-number]").should("contain", "1");
788 cy.get("[data-cy=collection-info-panel]").should("contain", colName);
789 cy.get("[data-cy=collection-files-panel]").should("contain", "foo").and("contain", "bar");
791 // Modify collection, expect version number change
792 cy.get("[data-cy=collection-files-panel]").contains("foo").rightclick();
793 cy.get("[data-cy=context-menu]").contains("Remove").click();
794 cy.get("[data-cy=confirmation-dialog]").should("contain", "Removing file");
795 cy.get("[data-cy=confirmation-dialog-ok-btn]").click();
796 cy.get("[data-cy=collection-version-number]").should("contain", "2");
797 cy.get("[data-cy=collection-files-panel]").should("not.contain", "foo").and("contain", "bar");
799 // Click on version number, check version browser. Click on past version.
800 cy.get("[data-cy=collection-version-browser]").should("not.exist");
801 cy.get("[data-cy=collection-version-number]").contains("2").click();
802 cy.get("[data-cy=collection-version-browser]")
803 .should("contain", "Nr")
804 .and("contain", "Size")
805 .and("contain", "Date")
807 // Version 1: 6 bytes in size
808 cy.get("[data-cy=collection-version-browser-select-1]")
809 .should("contain", "1")
810 .and("contain", "6 B")
811 .and("contain", adminUser.user.full_name);
812 // Version 2: 3 bytes in size (one file removed)
813 cy.get("[data-cy=collection-version-browser-select-2]")
814 .should("contain", "2")
815 .and("contain", "3 B")
816 .and("contain", activeUser.user.full_name);
817 cy.get("[data-cy=collection-version-browser-select-3]").should("not.exist");
818 cy.get("[data-cy=collection-version-browser-select-1]").click();
820 cy.get("[data-cy=collection-info-panel]").should("contain", "This is an old version");
821 cy.get("[data-cy=read-only-icon]").should("exist");
822 cy.get("[data-cy=collection-version-number]").should("contain", "1");
823 cy.get("[data-cy=collection-info-panel]").should("contain", colName);
824 cy.get("[data-cy=collection-files-panel]").should("contain", "foo").and("contain", "bar");
826 // Check that only old collection action are available on context menu
827 cy.get("[data-cy=collection-panel-options-btn]").click();
828 cy.get("[data-cy=context-menu]").should("contain", "Restore version").and("not.contain", "Add to favorites");
829 cy.get("body").click(); // Collapse the menu avoiding details panel expansion
831 // Click on "head version" link, confirm that it's the latest version.
832 cy.get("[data-cy=collection-info-panel]").contains("head version").click();
833 cy.get("[data-cy=collection-info-panel]").should("not.contain", "This is an old version");
834 cy.get("[data-cy=read-only-icon]").should("not.exist");
835 cy.get("[data-cy=collection-version-number]").should("contain", "2");
836 cy.get("[data-cy=collection-info-panel]").should("contain", colName);
837 cy.get("[data-cy=collection-files-panel]").should("not.contain", "foo").and("contain", "bar");
839 // Check that old collection action isn't available on context menu
840 cy.get("[data-cy=collection-panel-options-btn]").click();
841 cy.get("[data-cy=context-menu]").should("not.contain", "Restore version");
842 cy.get("body").click(); // Collapse the menu avoiding details panel expansion
844 // Make another change, confirm new version.
845 cy.get("[data-cy=collection-panel-options-btn]").click();
846 cy.get("[data-cy=context-menu]").contains("Edit collection").click();
847 cy.get("[data-cy=form-dialog]")
848 .should("contain", "Edit Collection")
851 cy.get("input").first().type(" renamed");
853 cy.get("[data-cy=form-submit-btn]").click();
854 cy.get("[data-cy=collection-info-panel]").should("not.contain", "This is an old version");
855 cy.get("[data-cy=read-only-icon]").should("not.exist");
856 cy.get("[data-cy=collection-version-number]").should("contain", "3");
857 cy.get("[data-cy=collection-info-panel]").should("contain", colName + " renamed");
858 cy.get("[data-cy=collection-files-panel]").should("not.contain", "foo").and("contain", "bar");
859 cy.get("[data-cy=collection-version-browser-select-3]").should("contain", "3").and("contain", "3 B");
861 // Check context menus on version browser
863 cy.get("[data-cy=collection-version-browser-select-3]").rightclick();
864 cy.get("[data-cy=context-menu]")
865 .should("contain", "Add to favorites")
866 .and("contain", "Make a copy")
867 .and("contain", "Edit collection");
868 cy.get("body").click();
869 // (and now an old version...)
870 cy.get("[data-cy=collection-version-browser-select-1]").rightclick();
871 cy.get("[data-cy=context-menu]")
872 .should("not.contain", "Add to favorites")
873 .and("contain", "Make a copy")
874 .and("not.contain", "Edit collection");
875 cy.get("body").click();
877 // Restore first version
878 cy.get("[data-cy=collection-version-browser]").within(() => {
879 cy.get("[data-cy=collection-version-browser-select-1]").click();
881 cy.get("[data-cy=collection-panel-options-btn]").click();
882 cy.get("[data-cy=context-menu]").contains("Restore version").click();
883 cy.get("[data-cy=confirmation-dialog]").should("contain", "Restore version");
884 cy.get("[data-cy=confirmation-dialog-ok-btn]").click();
885 cy.get("[data-cy=collection-info-panel]").should("not.contain", "This is an old version");
886 cy.get("[data-cy=collection-version-number]").should("contain", "4");
887 cy.get("[data-cy=collection-info-panel]").should("contain", colName);
888 cy.get("[data-cy=collection-files-panel]").should("contain", "foo").and("contain", "bar");
892 it("copies selected files into new collection", () => {
893 cy.createCollection(adminUser.token, {
894 name: `Test Collection ${Math.floor(Math.random() * 999999)}`,
895 owner_uuid: activeUser.user.uuid,
896 preserve_version: true,
897 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo 0:3:bar\n",
901 // Visit collection, check basic information
902 cy.loginAs(activeUser);
903 cy.goToPath(`/collections/${this.collection.uuid}`);
905 cy.get("[data-cy=collection-files-panel]").within(() => {
906 cy.get("input[type=checkbox]").first().click();
909 cy.get("[data-cy=collection-files-panel-options-btn]").click();
910 cy.get("[data-cy=context-menu]").contains("Copy selected into new collection").click();
912 cy.get("[data-cy=form-dialog]").contains("Projects").click();
914 cy.get("[data-cy=form-submit-btn]").click();
916 cy.waitForDom().get(".layout-pane-primary", { timeout: 12000 }).contains("Projects").click();
918 cy.waitForDom().get("main").contains(`Files extracted from: ${this.collection.name}`).click();
919 cy.get("[data-cy=collection-files-panel]").and("contain", "bar");
923 it("copies selected files into existing collection", () => {
924 cy.createCollection(adminUser.token, {
925 name: `Test Collection ${Math.floor(Math.random() * 999999)}`,
926 owner_uuid: activeUser.user.uuid,
927 preserve_version: true,
928 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo 0:3:bar\n",
929 }).as("sourceCollection");
931 cy.createCollection(adminUser.token, {
932 name: `Destination Collection ${Math.floor(Math.random() * 999999)}`,
933 owner_uuid: activeUser.user.uuid,
934 preserve_version: true,
936 }).as("destinationCollection");
938 cy.getAll("@sourceCollection", "@destinationCollection").then(function ([sourceCollection, destinationCollection]) {
939 // Visit collection, check basic information
940 cy.loginAs(activeUser);
941 cy.goToPath(`/collections/${sourceCollection.uuid}`);
943 cy.get("[data-cy=collection-files-panel]").within(() => {
944 cy.get("input[type=checkbox]").first().click();
947 cy.get("[data-cy=collection-files-panel-options-btn]").click();
948 cy.get("[data-cy=context-menu]").contains("Copy selected into existing collection").click();
950 cy.get("[data-cy=form-dialog]").contains(destinationCollection.name).click();
952 cy.get("[data-cy=form-submit-btn]").click();
955 cy.goToPath(`/collections/${destinationCollection.uuid}`);
957 cy.get("main").contains(destinationCollection.name).should("exist");
958 cy.get("[data-cy=collection-files-panel]").and("contain", "bar");
962 it("copies selected files into separate collections", () => {
963 cy.createCollection(adminUser.token, {
964 name: `Test Collection ${Math.floor(Math.random() * 999999)}`,
965 owner_uuid: activeUser.user.uuid,
966 preserve_version: true,
967 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo 0:3:bar\n",
968 }).as("sourceCollection");
970 cy.getAll("@sourceCollection").then(function ([sourceCollection]) {
971 // Visit collection, check basic information
972 cy.loginAs(activeUser);
973 cy.goToPath(`/collections/${sourceCollection.uuid}`);
977 .get("[data-cy=collection-files-panel]")
979 cy.get("input[type=checkbox]").first().click();
980 cy.get("input[type=checkbox]").last().click();
983 // Copy to separate collections
984 cy.get("[data-cy=collection-files-panel-options-btn]").click();
985 cy.get("[data-cy=context-menu]").contains("Copy selected into separate collections").click();
986 cy.get("[data-cy=form-dialog]").contains("Projects").click();
987 cy.get("[data-cy=form-submit-btn]").click();
989 // Verify created collections
990 cy.waitForDom().get(".layout-pane-primary", { timeout: 12000 }).contains("Projects").click();
991 cy.get("main").contains(`File copied from collection ${sourceCollection.name}/foo`).click();
992 cy.get("[data-cy=collection-files-panel]").and("contain", "foo");
993 cy.get(".layout-pane-primary").contains("Projects").click();
994 cy.get("main").contains(`File copied from collection ${sourceCollection.name}/bar`).click();
995 cy.get("[data-cy=collection-files-panel]").and("contain", "bar");
997 // Verify separate collection menu items not present when single file selected
998 // Wait for dom for collection to re-render
1000 .get("[data-cy=collection-files-panel]")
1002 cy.get("input[type=checkbox]").first().click();
1004 cy.get("[data-cy=collection-files-panel-options-btn]").click();
1005 cy.get("[data-cy=context-menu]").should("not.contain", "Copy selected into separate collections");
1006 cy.get("[data-cy=context-menu]").should("not.contain", "Move selected into separate collections");
1010 it("moves selected files into new collection", () => {
1011 cy.createCollection(adminUser.token, {
1012 name: `Test Collection ${Math.floor(Math.random() * 999999)}`,
1013 owner_uuid: activeUser.user.uuid,
1014 preserve_version: true,
1015 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo 0:3:bar\n",
1019 // Visit collection, check basic information
1020 cy.loginAs(activeUser);
1021 cy.goToPath(`/collections/${this.collection.uuid}`);
1023 cy.get("[data-cy=collection-files-panel]").within(() => {
1024 cy.get("input[type=checkbox]").first().click();
1027 cy.get("[data-cy=collection-files-panel-options-btn]").click();
1028 cy.get("[data-cy=context-menu]").contains("Move selected into new collection").click();
1030 cy.get("[data-cy=form-dialog]").contains("Projects").click();
1032 cy.get("[data-cy=form-submit-btn]").click();
1034 cy.waitForDom().get(".layout-pane-primary", { timeout: 12000 }).contains("Projects").click();
1036 cy.get("main").contains(`Files moved from: ${this.collection.name}`).click();
1037 cy.get("[data-cy=collection-files-panel]").and("contain", "bar");
1041 it("moves selected files into existing collection", () => {
1042 cy.createCollection(adminUser.token, {
1043 name: `Test Collection ${Math.floor(Math.random() * 999999)}`,
1044 owner_uuid: activeUser.user.uuid,
1045 preserve_version: true,
1046 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo 0:3:bar\n",
1047 }).as("sourceCollection");
1049 cy.createCollection(adminUser.token, {
1050 name: `Destination Collection ${Math.floor(Math.random() * 999999)}`,
1051 owner_uuid: activeUser.user.uuid,
1052 preserve_version: true,
1054 }).as("destinationCollection");
1056 cy.getAll("@sourceCollection", "@destinationCollection").then(function ([sourceCollection, destinationCollection]) {
1057 // Visit collection, check basic information
1058 cy.loginAs(activeUser);
1059 cy.goToPath(`/collections/${sourceCollection.uuid}`);
1061 cy.get("[data-cy=collection-files-panel]").within(() => {
1062 cy.get("input[type=checkbox]").first().click();
1065 cy.get("[data-cy=collection-files-panel-options-btn]").click();
1066 cy.get("[data-cy=context-menu]").contains("Move selected into existing collection").click();
1068 cy.get("[data-cy=form-dialog]").contains(destinationCollection.name).click();
1070 cy.get("[data-cy=form-submit-btn]").click();
1073 cy.goToPath(`/collections/${destinationCollection.uuid}`);
1075 cy.get("main").contains(destinationCollection.name).should("exist");
1076 cy.get("[data-cy=collection-files-panel]").and("contain", "bar");
1080 it("moves selected files into separate collections", () => {
1081 cy.createCollection(adminUser.token, {
1082 name: `Test Collection ${Math.floor(Math.random() * 999999)}`,
1083 owner_uuid: activeUser.user.uuid,
1084 preserve_version: true,
1085 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo 0:3:bar\n",
1086 }).as("sourceCollection");
1088 cy.getAll("@sourceCollection").then(function ([sourceCollection]) {
1089 // Visit collection, check basic information
1090 cy.loginAs(activeUser);
1091 cy.goToPath(`/collections/${sourceCollection.uuid}`);
1093 // Select both files
1094 cy.get("[data-cy=collection-files-panel]").within(() => {
1095 cy.get("input[type=checkbox]").first().click();
1096 cy.get("input[type=checkbox]").last().click();
1099 // Copy to separate collections
1100 cy.get("[data-cy=collection-files-panel-options-btn]").click();
1101 cy.get("[data-cy=context-menu]").contains("Move selected into separate collections").click();
1102 cy.get("[data-cy=form-dialog]").contains("Projects").click();
1103 cy.get("[data-cy=form-submit-btn]").click();
1105 // Verify created collections
1106 cy.waitForDom().get(".layout-pane-primary", { timeout: 12000 }).contains("Projects").click();
1107 cy.get("main").contains(`File moved from collection ${sourceCollection.name}/foo`).click();
1108 cy.get("[data-cy=collection-files-panel]").and("contain", "foo");
1109 cy.get(".layout-pane-primary").contains("Projects").click();
1110 cy.get("main").contains(`File moved from collection ${sourceCollection.name}/bar`).click();
1111 cy.get("[data-cy=collection-files-panel]").and("contain", "bar");
1115 it("creates new collection with properties on home project", function () {
1116 cy.loginAs(activeUser);
1117 cy.goToPath(`/projects/${activeUser.user.uuid}`);
1118 cy.get("[data-cy=breadcrumb-first]").should("contain", "Projects");
1119 cy.get("[data-cy=breadcrumb-last]").should("not.exist");
1120 // Create new collection
1121 cy.get("[data-cy=side-panel-button]").click();
1122 cy.get("[data-cy=side-panel-new-collection]").click();
1123 // Name between brackets tests bugfix #17582
1124 const collName = `[Test collection (${Math.floor(999999 * Math.random())})]`;
1126 // Select a storage class.
1127 cy.get("[data-cy=form-dialog]")
1128 .should("contain", "New collection")
1129 .and("contain", "Storage classes")
1130 .and("contain", "default")
1131 .and("contain", "foo")
1132 .and("contain", "bar")
1134 cy.get("[data-cy=parent-field]").within(() => {
1135 cy.get("input").should("have.value", "Home project");
1137 cy.get("[data-cy=name-field]").within(() => {
1138 cy.get("input").type(collName);
1140 cy.get("[data-cy=checkbox-foo]").click();
1144 // Key: Color (IDTAGCOLORS) - Value: Magenta (IDVALCOLORS3)
1145 cy.get("[data-cy=form-dialog]").should("not.contain", "Color: Magenta");
1146 cy.get("[data-cy=resource-properties-form]").within(() => {
1147 cy.get("[data-cy=property-field-key]").within(() => {
1148 cy.get("input").type("Color");
1150 cy.get("[data-cy=property-field-value]").within(() => {
1151 cy.get("input").type("Magenta");
1155 // Confirm proper vocabulary labels are displayed on the UI.
1156 cy.get("[data-cy=form-dialog]").should("contain", "Color: Magenta");
1158 // Value field should not complain about being required just after
1159 // adding a new property. See #19732
1160 cy.get("[data-cy=form-dialog]").should("not.contain", "This field is required");
1162 cy.get("[data-cy=form-submit-btn]").click();
1163 // Confirm that the user was taken to the newly created collection
1164 cy.get("[data-cy=form-dialog]").should("not.exist");
1165 cy.get("[data-cy=breadcrumb-first]").should("contain", "Projects");
1167 cy.get("[data-cy=breadcrumb-last]").should('exist', { timeout: 10000 });
1168 cy.get("[data-cy=breadcrumb-last]").should("contain", collName);
1169 cy.get("[data-cy=collection-info-panel]")
1170 .should("contain", "default")
1171 .and("contain", "foo")
1172 .and("contain", "Color: Magenta")
1173 .and("not.contain", "bar");
1174 // Confirm that the collection's properties has the real values.
1175 cy.doRequest("GET", "/arvados/v1/collections", null, {
1176 filters: `[["name", "=", "${collName}"]]`,
1181 expect(this.collections).to.have.lengthOf(1);
1182 expect(this.collections[0].properties).to.have.property("IDTAGCOLORS", "IDVALCOLORS3");
1186 it("shows responsible person for collection if available", () => {
1187 cy.createCollection(adminUser.token, {
1188 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
1189 owner_uuid: activeUser.user.uuid,
1190 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
1191 }).as("testCollection1");
1193 cy.createCollection(adminUser.token, {
1194 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
1195 owner_uuid: adminUser.user.uuid,
1196 manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
1198 .as("testCollection2")
1199 .then(function (testCollection2) {
1200 cy.shareWith(adminUser.token, activeUser.user.uuid, testCollection2.uuid, "can_write");
1203 cy.getAll("@testCollection1", "@testCollection2").then(function ([testCollection1, testCollection2]) {
1204 cy.loginAs(activeUser);
1206 cy.goToPath(`/collections/${testCollection1.uuid}`);
1207 cy.get("[data-cy=responsible-person-wrapper]").contains(activeUser.user.uuid);
1209 cy.goToPath(`/collections/${testCollection2.uuid}`);
1210 cy.get("[data-cy=responsible-person-wrapper]").contains(adminUser.user.uuid);
1214 describe("file upload", () => {
1216 cy.createCollection(adminUser.token, {
1217 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
1218 owner_uuid: activeUser.user.uuid,
1219 manifest_text: "./subdir 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo\n. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
1220 }).as("testCollection1");
1223 it("uploads a file and checks the collection UI to be fresh", () => {
1224 cy.getAll("@testCollection1").then(function ([testCollection1]) {
1225 cy.loginAs(activeUser);
1226 cy.goToPath(`/collections/${testCollection1.uuid}`);
1227 cy.get("[data-cy=upload-button]").click();
1228 cy.get("[data-cy=collection-files-panel]").contains("5mb_a.bin").should("not.exist");
1229 cy.get("[data-cy=collection-file-count]").should("contain", "2");
1230 cy.fixture("files/5mb.bin", "base64").then(content => {
1231 cy.get("[data-cy=drag-and-drop]").upload(content, "5mb_a.bin");
1232 cy.get("[data-cy=form-submit-btn]").click();
1233 cy.get("[data-cy=form-submit-btn]").should("not.exist");
1234 cy.get("[data-cy=collection-files-panel]").contains("5mb_a.bin").should("exist");
1235 cy.get("[data-cy=collection-file-count]").should("contain", "3");
1237 cy.get("[data-cy=collection-files-panel]").contains("subdir").click();
1238 cy.get("[data-cy=upload-button]").click();
1239 cy.fixture("files/5mb.bin", "base64").then(content => {
1240 cy.get("[data-cy=drag-and-drop]").upload(content, "5mb_b.bin");
1241 cy.get("[data-cy=form-submit-btn]").click();
1242 cy.waitForDom().get("[data-cy=form-submit-btn]").should("not.exist");
1243 // subdir gets unselected, I think this is a bug but
1244 // for the time being let's just make sure the test works.
1245 cy.get("[data-cy=collection-files-panel]").contains("subdir").click();
1246 cy.waitForDom().get("[data-cy=collection-files-right-panel]").contains("5mb_b.bin").should("exist");
1252 it("allows to cancel running upload", () => {
1253 cy.getAll("@testCollection1").then(function ([testCollection1]) {
1254 cy.loginAs(activeUser);
1256 cy.goToPath(`/collections/${testCollection1.uuid}`);
1258 cy.get("[data-cy=upload-button]").click();
1260 cy.fixture("files/5mb.bin", "base64").then(content => {
1261 cy.get("[data-cy=drag-and-drop]").upload(content, "5mb_a.bin");
1262 cy.get("[data-cy=drag-and-drop]").upload(content, "5mb_b.bin");
1264 cy.get("[data-cy=form-submit-btn]").click();
1266 cy.get("button").contains("Cancel").click();
1268 cy.get("[data-cy=form-submit-btn]").should("not.exist");
1273 it("allows to cancel single file from the running upload", () => {
1274 cy.getAll("@testCollection1").then(function ([testCollection1]) {
1275 cy.loginAs(activeUser);
1277 cy.goToPath(`/collections/${testCollection1.uuid}`);
1279 cy.get("[data-cy=upload-button]").click();
1281 cy.fixture("files/5mb.bin", "base64").then(content => {
1282 cy.get("[data-cy=drag-and-drop]").upload(content, "5mb_a.bin");
1283 cy.get("[data-cy=drag-and-drop]").upload(content, "5mb_b.bin");
1285 cy.get("[data-cy=form-submit-btn]").click();
1287 cy.get("button[aria-label=Remove]").eq(1).click();
1289 cy.get("[data-cy=form-submit-btn]").should("not.exist");
1291 cy.get("[data-cy=collection-files-panel]").contains("5mb_a.bin").should("exist");
1296 it("allows to cancel all files from the running upload", () => {
1297 cy.getAll("@testCollection1").then(function ([testCollection1]) {
1298 cy.loginAs(activeUser);
1300 cy.goToPath(`/collections/${testCollection1.uuid}`);
1302 // Confirm initial collection state.
1303 cy.get("[data-cy=collection-files-panel]").contains("bar").should("exist");
1304 cy.get("[data-cy=collection-files-panel]").contains("15mb_a.bin").should("not.exist");
1305 cy.get("[data-cy=collection-files-panel]").contains("15mb_b.bin").should("not.exist");
1307 cy.get("[data-cy=upload-button]").click();
1309 cy.fixture("files/15mb.bin", "base64").then(content => {
1310 cy.get("[data-cy=drag-and-drop]").upload(content, "15mb_a.bin");
1311 cy.get("[data-cy=drag-and-drop]").upload(content, "15mb_b.bin");
1313 cy.get("[data-cy=form-submit-btn]").click();
1315 cy.get("button[aria-label=Remove]").should("exist").click({ multiple: true});
1317 cy.get("[data-cy=form-submit-btn]").should("not.exist");
1319 // Confirm final collection state.
1320 cy.get("[data-cy=collection-files-panel]").contains("bar").should("exist");
1321 // The following fails, but doesn't seem to happen
1322 // in the real world. Maybe there's a race between
1323 // the PUT request finishing and the 'Remove' button
1324 // dissapearing, because sometimes just one of the 2
1325 // files gets uploaded.
1326 // Maybe this will be needed to simulate a slow network:
1327 // https://docs.cypress.io/api/commands/intercept#Convenience-functions-1
1328 // cy.get('[data-cy=collection-files-panel]')
1329 // .contains('5mb_a.bin').should('not.exist');
1330 // cy.get('[data-cy=collection-files-panel]')
1331 // .contains('5mb_b.bin').should('not.exist');