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