1bf2b5c3efb4b83a8bdd8324f751ffb67d7b53c5
[arvados.git] / services / workbench2 / cypress / e2e / search.cy.js
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 describe("Search tests", function () {
6     let activeUser;
7     let adminUser;
8
9     before(function () {
10         // Only set up common users once. These aren't set up as aliases because
11         // aliases are cleaned up after every test. Also it doesn't make sense
12         // to set the same users on beforeEach() over and over again, so we
13         // separate a little from Cypress' 'Best Practices' here.
14         cy.getUser("admin", "Admin", "User", true, true)
15             .as("adminUser")
16             .then(function () {
17                 adminUser = this.adminUser;
18             });
19         cy.getUser("collectionuser1", "Collection", "User", false, true)
20             .as("activeUser")
21             .then(function () {
22                 activeUser = this.activeUser;
23             });
24     });
25
26     it("can search for old collection versions", function () {
27         const colName = `Versioned Collection ${Math.floor(Math.random() * Math.floor(999999))}`;
28         let colUuid = "";
29         let oldVersionUuid = "";
30         // Make sure no other collections with this name exist
31         cy.doRequest("GET", "/arvados/v1/collections", null, {
32             filters: `[["name", "=", "${colName}"]]`,
33             include_old_versions: true,
34         })
35             .its("body.items")
36             .as("collections")
37             .then(function () {
38                 expect(this.collections).to.be.empty;
39             });
40         // Creates the collection using the admin token so we can set up
41         // a bogus manifest text without block signatures.
42         cy.createCollection(adminUser.token, {
43             name: colName,
44             owner_uuid: activeUser.user.uuid,
45             preserve_version: true,
46             manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
47         })
48             .as("originalVersion")
49             .then(function () {
50                 // Change the file name to create a new version.
51                 cy.updateCollection(adminUser.token, this.originalVersion.uuid, {
52                     manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo\n",
53                 });
54                 colUuid = this.originalVersion.uuid;
55             });
56         // Confirm that there are 2 versions of the collection
57         cy.doRequest("GET", "/arvados/v1/collections", null, {
58             filters: `[["name", "=", "${colName}"]]`,
59             include_old_versions: true,
60         })
61             .its("body.items")
62             .as("collections")
63             .then(function () {
64                 expect(this.collections).to.have.lengthOf(2);
65                 this.collections.map(function (aCollection) {
66                     expect(aCollection.current_version_uuid).to.equal(colUuid);
67                     if (aCollection.uuid !== aCollection.current_version_uuid) {
68                         oldVersionUuid = aCollection.uuid;
69                     }
70                 });
71                 cy.loginAs(activeUser);
72                 const searchQuery = `${colName} type:arvados#collection`;
73                 // Search for only collection's current version
74                 cy.doSearch(`${searchQuery}`);
75                 cy.get("[data-cy=search-results]").should("contain", "head version");
76                 cy.get("[data-cy=search-results]").should("not.contain", "version 1");
77                 // ...and then, include old versions.
78                 cy.doSearch(`${searchQuery} is:pastVersion`);
79                 cy.get("[data-cy=search-results]").should("contain", "head version");
80                 cy.get("[data-cy=search-results]").should("contain", "version 1");
81             });
82     });
83
84     it("can display path of the selected item", function () {
85         const colName = `Collection ${Math.floor(Math.random() * Math.floor(999999))}`;
86
87         // Creates the collection using the admin token so we can set up
88         // a bogus manifest text without block signatures.
89         cy.createCollection(adminUser.token, {
90             name: colName,
91             owner_uuid: activeUser.user.uuid,
92             preserve_version: true,
93             manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
94         }).then(function () {
95             cy.loginAs(activeUser);
96
97             cy.doSearch(colName);
98
99             cy.get("[data-cy=search-results]").should("contain", colName);
100
101             cy.get("[data-cy=search-results]").contains(colName).closest("tr").click();
102
103             cy.get("[data-cy=element-path]").should("contain", `/ Projects / ${colName}`);
104         });
105     });
106
107     it("can search items using quotes", function () {
108         const random = Math.floor(Math.random() * Math.floor(999999));
109         const colName = `Collection ${random}`;
110         const colName2 = `Collection test ${random}`;
111
112         // Creates the collection using the admin token so we can set up
113         // a bogus manifest text without block signatures.
114         cy.createCollection(adminUser.token, {
115             name: colName,
116             owner_uuid: activeUser.user.uuid,
117             preserve_version: true,
118             manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
119         }).as("collection1");
120
121         cy.createCollection(adminUser.token, {
122             name: colName2,
123             owner_uuid: activeUser.user.uuid,
124             preserve_version: true,
125             manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
126         }).as("collection2");
127
128         cy.getAll("@collection1", "@collection2").then(function () {
129             cy.loginAs(activeUser);
130
131             cy.doSearch(colName);
132             cy.get("[data-cy=search-results] table tbody tr").should("have.length", 2);
133
134             cy.doSearch(`"${colName}"`);
135             cy.get("[data-cy=search-results] table tbody tr").should("have.length", 1);
136         });
137     });
138
139     it("can display owner of the item", function () {
140         const colName = `Collection ${Math.floor(Math.random() * Math.floor(999999))}`;
141
142         cy.createCollection(adminUser.token, {
143             name: colName,
144             owner_uuid: activeUser.user.uuid,
145             preserve_version: true,
146             manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
147         }).then(function () {
148             cy.loginAs(activeUser);
149
150             cy.doSearch(colName);
151
152             cy.get("[data-cy=search-results]").should("contain", colName);
153
154             cy.get("[data-cy=search-results]")
155                 .contains(colName)
156                 .closest("tr")
157                 .within(() => {
158                     cy.get("p").contains(activeUser.user.uuid).should("contain", activeUser.user.full_name);
159                 });
160         });
161     });
162
163     // The following test is enabled on Electron only, as Chromium and Firefox
164     // require permissions to access the clipboard.
165     it("shows search context menu", { browser: 'electron' } , function () {
166         const colName = `Home Collection ${Math.floor(Math.random() * Math.floor(999999))}`;
167         const federatedColName = `Federated Collection ${Math.floor(Math.random() * Math.floor(999999))}`;
168         const federatedColUuid = "xxxxx-4zz18-000000000000000";
169
170         // Intercept config to insert remote cluster
171         cy.intercept({ method: "GET", hostname: "127.0.0.1", url: "**/arvados/v1/config?nocache=*" }, req => {
172             req.reply(res => {
173                 res.body.RemoteClusters = {
174                     "*": res.body.RemoteClusters["*"],
175                     xxxxx: {
176                         ActivateUsers: true,
177                         Host: "xxxxx.fakecluster.tld",
178                         Insecure: false,
179                         Proxy: true,
180                         Scheme: "",
181                     },
182                 };
183             });
184         });
185
186         // Fake remote cluster config
187         cy.intercept(
188             {
189                 method: "GET",
190                 hostname: "xxxxx.fakecluster.tld",
191                 url: "**/arvados/v1/config",
192             },
193             {
194                 statusCode: 200,
195                 body: {
196                     API: {},
197                     ClusterID: "xxxxx",
198                     Collections: {},
199                     Containers: {},
200                     InstanceTypes: {},
201                     Login: {},
202                     Mail: { SupportEmailAddress: "arvados@example.com" },
203                     RemoteClusters: {
204                         "*": {
205                             ActivateUsers: false,
206                             Host: "",
207                             Insecure: false,
208                             Proxy: false,
209                             Scheme: "https",
210                         },
211                     },
212                     Services: {
213                         Composer: { ExternalURL: "" },
214                         Controller: { ExternalURL: "https://xxxxx.fakecluster.tld:34763/" },
215                         DispatchCloud: { ExternalURL: "" },
216                         DispatchLSF: { ExternalURL: "" },
217                         DispatchSLURM: { ExternalURL: "" },
218                         GitHTTP: { ExternalURL: "https://xxxxx.fakecluster.tld:39105/" },
219                         GitSSH: { ExternalURL: "" },
220                         Health: { ExternalURL: "https://xxxxx.fakecluster.tld:42915/" },
221                         Keepbalance: { ExternalURL: "" },
222                         Keepproxy: { ExternalURL: "https://xxxxx.fakecluster.tld:46773/" },
223                         Keepstore: { ExternalURL: "" },
224                         RailsAPI: { ExternalURL: "" },
225                         WebDAV: { ExternalURL: "https://xxxxx.fakecluster.tld:36041/" },
226                         WebDAVDownload: { ExternalURL: "https://xxxxx.fakecluster.tld:42957/" },
227                         WebShell: { ExternalURL: "" },
228                         Websocket: { ExternalURL: "wss://xxxxx.fakecluster.tld:37121/websocket" },
229                         Workbench1: { ExternalURL: "https://wb1.xxxxx.fakecluster.tld/" },
230                         Workbench2: { ExternalURL: "https://wb2.xxxxx.fakecluster.tld/" },
231                     },
232                     StorageClasses: {
233                         default: { Default: true, Priority: 0 },
234                     },
235                     Users: {},
236                     Volumes: {},
237                     Workbench: {},
238                 },
239             }
240         );
241
242         cy.createCollection(adminUser.token, {
243             name: colName,
244             owner_uuid: activeUser.user.uuid,
245             preserve_version: true,
246             manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n",
247         }).then(function (testCollection) {
248             cy.loginAs(activeUser);
249
250             // Intercept search results to add federated result
251             cy.intercept({ method: "GET", url: "**/arvados/v1/groups/contents?*" }, req => {
252                 req.reply(res => {
253                     res.body.items = [
254                         res.body.items[0],
255                         {
256                             ...res.body.items[0],
257                             uuid: federatedColUuid,
258                             portable_data_hash: "00000000000000000000000000000000+0",
259                             name: federatedColName,
260                             href: res.body.items[0].href.replace(testCollection.uuid, federatedColUuid),
261                         },
262                     ];
263                     res.body.items_available += 1;
264                 });
265             });
266
267             cy.doSearch(colName);
268
269             // Stub new window
270             cy.window().then(win => {
271                 cy.stub(win, "open").as("Open");
272             });
273
274             // Check copy to clipboard
275             cy.get("[data-cy=search-results]").contains(colName).rightclick();
276             cy.get("[data-cy=context-menu]").within(ctx => {
277                 // Check that there are 4 items in the menu
278                 cy.get(ctx).children().should("have.length", 4);
279                 cy.contains("API Details");
280                 cy.contains("Copy to clipboard");
281                 cy.contains("Open in new tab");
282                 cy.contains("View details");
283
284                 cy.contains("Copy to clipboard").click();
285                 cy.waitForDom();
286                 cy.window().then(win =>
287                     win.navigator.clipboard.readText().then(text => {
288                         expect(text).to.match(new RegExp(`/collections/${testCollection.uuid}$`));
289                     })
290                 );
291             });
292
293             // Check open in new tab
294             cy.get("[data-cy=search-results]").contains(colName).rightclick();
295             cy.get("[data-cy=context-menu]").within(() => {
296                 cy.contains("Open in new tab").click();
297                 cy.waitForDom();
298                 cy.get("@Open").should("have.been.calledOnceWith", `${window.location.origin}/collections/${testCollection.uuid}`);
299             });
300
301             // Check federated result copy to clipboard
302             cy.get("[data-cy=search-results]").contains(federatedColName).rightclick();
303             cy.get("[data-cy=context-menu]").within(() => {
304                 cy.contains("Copy to clipboard").click();
305                 cy.waitForDom();
306                 cy.window().then(win =>
307                     win.navigator.clipboard.readText().then(text => {
308                         expect(text).to.equal(`https://wb2.xxxxx.fakecluster.tld/collections/${federatedColUuid}`);
309                     })
310                 );
311             });
312             // Check open in new tab
313             cy.get("[data-cy=search-results]").contains(federatedColName).rightclick();
314             cy.get("[data-cy=context-menu]").within(() => {
315                 cy.contains("Open in new tab").click();
316                 cy.waitForDom();
317                 cy.get("@Open").should("have.been.calledWith", `https://wb2.xxxxx.fakecluster.tld/collections/${federatedColUuid}`);
318             });
319         });
320     });
321 });