1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 describe('Process tests', 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;
19 cy.getUser('user', 'Active', 'User', false, true)
20 .as('activeUser').then(function() {
21 activeUser = this.activeUser;
26 beforeEach(function() {
28 cy.clearLocalStorage();
31 function setupDockerImage(image_name) {
32 // Create a collection that will be used as a docker image for the tests.
33 cy.createCollection(adminUser.token, {
35 manifest_text: ". d21353cfe035e3e384563ee55eadbb2f+67108864 5c77a43e329b9838cbec18ff42790e57+55605760 0:122714624:sha256:d8309758b8fe2c81034ffc8a10c36460b77db7bc5e7b448c4e5b684f9d95a678.tar\n"
36 }).as('dockerImage').then(function(dockerImage) {
37 // Give read permissions to the active user on the docker image.
38 cy.createLink(adminUser.token, {
39 link_class: 'permission',
41 tail_uuid: activeUser.user.uuid,
42 head_uuid: dockerImage.uuid
43 }).as('dockerImagePermission').then(function() {
44 // Set-up docker image collection tags
45 cy.createLink(activeUser.token, {
46 link_class: 'docker_image_repo+tag',
48 head_uuid: dockerImage.uuid,
49 }).as('dockerImageRepoTag');
50 cy.createLink(activeUser.token, {
51 link_class: 'docker_image_hash',
52 name: 'sha256:d8309758b8fe2c81034ffc8a10c36460b77db7bc5e7b448c4e5b684f9d95a678',
53 head_uuid: dockerImage.uuid,
54 }).as('dockerImageHash');
57 return cy.getAll('@dockerImage', '@dockerImageRepoTag', '@dockerImageHash',
58 '@dockerImagePermission').then(function([dockerImage]) {
63 function createContainerRequest(user, name, docker_image, command, reuse = false, state = 'Uncommitted') {
64 return setupDockerImage(docker_image).then(function(dockerImage) {
65 return cy.createContainerRequest(user.token, {
68 container_image: dockerImage.portable_data_hash, // for some reason, docker_image doesn't work here
69 output_path: 'stdout.txt',
71 runtime_constraints: {
87 it('shows process logs', function() {
88 const crName = 'test_container_request';
89 createContainerRequest(
93 ['echo', 'hello world'],
95 .then(function(containerRequest) {
96 cy.loginAs(activeUser);
97 cy.goToPath(`/processes/${containerRequest.uuid}`);
98 cy.get('[data-cy=process-details]').should('contain', crName);
99 cy.get('[data-cy=process-logs]')
100 .should('contain', 'No logs yet')
101 .and('not.contain', 'hello world');
102 cy.createLog(activeUser.token, {
103 object_uuid: containerRequest.container_uuid,
108 }).then(function(log) {
109 cy.get('[data-cy=process-logs]')
110 .should('not.contain', 'No logs yet')
111 .and('contain', 'hello world');
116 it('shows process details', function() {
117 createContainerRequest(
119 `test_container_request ${Math.floor(Math.random() * 999999)}`,
121 ['echo', 'hello world'],
123 .then(function(containerRequest) {
124 cy.loginAs(activeUser);
125 cy.goToPath(`/processes/${containerRequest.uuid}`);
126 cy.get('[data-cy=process-details]').should('contain', containerRequest.name);
127 cy.get('[data-cy=process-details-attributes-modifiedby-user]').contains(`Active User (${activeUser.user.uuid})`);
130 // Fake submitted by another user
131 cy.intercept({method: 'GET', url: '**/arvados/v1/container_requests/*'}, (req) => {
133 res.body.modified_by_user_uuid = 'zzzzz-tpzed-000000000000000';
137 createContainerRequest(
139 `test_container_request ${Math.floor(Math.random() * 999999)}`,
141 ['echo', 'hello world'],
143 .then(function(containerRequest) {
144 cy.loginAs(activeUser);
145 cy.goToPath(`/processes/${containerRequest.uuid}`);
146 cy.get('[data-cy=process-details]').should('contain', containerRequest.name);
147 cy.get('[data-cy=process-details-attributes-modifiedby-user]').contains(`zzzzz-tpzed-000000000000000`);
148 cy.get('[data-cy=process-details-attributes-runtime-user]').contains(`Active User (${activeUser.user.uuid})`);
152 it('filters process logs by event type', function() {
153 const nodeInfoLogs = [
155 'Linux compute-99cb150b26149780de44b929577e1aed-19rgca8vobuvc4p 5.4.0-1059-azure #62~18.04.1-Ubuntu SMP Tue Sep 14 17:53:18 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux',
158 'vendor_id : GenuineIntel',
161 'model name : Intel(R) Xeon(R) CPU E5-2673 v4 @ 2.30GHz'
163 const crunchRunLogs = [
164 '2022-03-22T13:56:22.542417997Z using local keepstore process (pid 3733) at http://localhost:46837, writing logs to keepstore.txt in log collection',
165 '2022-03-22T13:56:26.237571754Z crunch-run 2.4.0~dev20220321141729 (go1.17.1) started',
166 '2022-03-22T13:56:26.244704134Z crunch-run process has uid=0(root) gid=0(root) groups=0(root)',
167 '2022-03-22T13:56:26.244862836Z Executing container \'zzzzz-dz642-1wokwvcct9s9du3\' using docker runtime',
168 '2022-03-22T13:56:26.245037738Z Executing on host \'compute-99cb150b26149780de44b929577e1aed-19rgca8vobuvc4p\'',
171 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec dui nisi, hendrerit porta sapien a, pretium dignissim purus.',
172 'Integer viverra, mauris finibus aliquet ultricies, dui mauris cursus justo, ut venenatis nibh ex eget neque.',
173 'In hac habitasse platea dictumst.',
174 'Fusce fringilla turpis id accumsan faucibus. Donec congue congue ex non posuere. In semper mi quis tristique rhoncus.',
175 'Interdum et malesuada fames ac ante ipsum primis in faucibus.',
176 'Quisque fermentum tortor ex, ut suscipit velit feugiat faucibus.',
177 'Donec vitae porta risus, at luctus nulla. Mauris gravida iaculis ipsum, id sagittis tortor egestas ac.',
178 'Maecenas condimentum volutpat nulla. Integer lacinia maximus risus eu posuere.',
179 'Donec vitae leo id augue gravida bibendum.',
180 'Nam libero libero, pretium ac faucibus elementum, mattis nec ex.',
181 'Nullam id laoreet nibh. Vivamus tellus metus, pretium quis justo ut, bibendum varius metus. Pellentesque vitae accumsan lorem, quis tincidunt augue.',
182 'Aliquam viverra nisi nulla, et efficitur dolor mattis in.',
183 'Sed at enim sit amet nulla tincidunt mattis. Aenean eget aliquet ex, non ultrices ex. Nulla ex tortor, vestibulum aliquam tempor ac, aliquam vel est.',
184 'Fusce auctor faucibus libero id venenatis. Etiam sodales, odio eu cursus efficitur, quam sem blandit ex, quis porttitor enim dui quis lectus. In id tincidunt felis.',
185 'Phasellus non ex quis arcu tempus faucibus molestie in sapien.',
186 'Duis tristique semper dolor, vitae pulvinar risus.',
187 'Aliquam tortor elit, luctus nec tortor eget, porta tristique nulla.',
188 'Nulla eget mollis ipsum.',
191 createContainerRequest(
193 'test_container_request',
195 ['echo', 'hello world'],
197 .then(function(containerRequest) {
198 cy.logsForContainer(activeUser.token, containerRequest.container_uuid,
199 'node-info', nodeInfoLogs).as('nodeInfoLogs');
200 cy.logsForContainer(activeUser.token, containerRequest.container_uuid,
201 'crunch-run', crunchRunLogs).as('crunchRunLogs');
202 cy.logsForContainer(activeUser.token, containerRequest.container_uuid,
203 'stdout', stdoutLogs).as('stdoutLogs');
204 cy.getAll('@stdoutLogs', '@nodeInfoLogs', '@crunchRunLogs').then(function() {
205 cy.loginAs(activeUser);
206 cy.goToPath(`/processes/${containerRequest.uuid}`);
207 // Should show main logs by default
208 cy.get('[data-cy=process-logs-filter]').should('contain', 'Main logs');
209 cy.get('[data-cy=process-logs]')
210 .should('contain', stdoutLogs[Math.floor(Math.random() * stdoutLogs.length)])
211 .and('not.contain', nodeInfoLogs[Math.floor(Math.random() * nodeInfoLogs.length)])
212 .and('contain', crunchRunLogs[Math.floor(Math.random() * crunchRunLogs.length)]);
214 cy.get('[data-cy=process-logs-filter]').click();
215 cy.get('body').contains('li', 'All logs').click();
216 cy.get('[data-cy=process-logs]')
217 .should('contain', stdoutLogs[Math.floor(Math.random() * stdoutLogs.length)])
218 .and('contain', nodeInfoLogs[Math.floor(Math.random() * nodeInfoLogs.length)])
219 .and('contain', crunchRunLogs[Math.floor(Math.random() * crunchRunLogs.length)]);
220 // Select 'node-info' logs
221 cy.get('[data-cy=process-logs-filter]').click();
222 cy.get('body').contains('li', 'node-info').click();
223 cy.get('[data-cy=process-logs]')
224 .should('not.contain', stdoutLogs[Math.floor(Math.random() * stdoutLogs.length)])
225 .and('contain', nodeInfoLogs[Math.floor(Math.random() * nodeInfoLogs.length)])
226 .and('not.contain', crunchRunLogs[Math.floor(Math.random() * crunchRunLogs.length)]);
227 // Select 'stdout' logs
228 cy.get('[data-cy=process-logs-filter]').click();
229 cy.get('body').contains('li', 'stdout').click();
230 cy.get('[data-cy=process-logs]')
231 .should('contain', stdoutLogs[Math.floor(Math.random() * stdoutLogs.length)])
232 .and('not.contain', nodeInfoLogs[Math.floor(Math.random() * nodeInfoLogs.length)])
233 .and('not.contain', crunchRunLogs[Math.floor(Math.random() * crunchRunLogs.length)]);
238 it('should show runtime status indicators', function() {
239 // Setup running container with runtime_status error & warning messages
240 createContainerRequest(
242 'test_container_request',
244 ['echo', 'hello world'],
246 .as('containerRequest')
247 .then(function(containerRequest) {
248 expect(containerRequest.state).to.equal('Committed');
249 expect(containerRequest.container_uuid).not.to.be.equal('');
251 cy.getContainer(activeUser.token, containerRequest.container_uuid)
252 .then(function(queuedContainer) {
253 expect(queuedContainer.state).to.be.equal('Queued');
255 cy.updateContainer(adminUser.token, containerRequest.container_uuid, {
257 }).then(function(lockedContainer) {
258 expect(lockedContainer.state).to.be.equal('Locked');
260 cy.updateContainer(adminUser.token, lockedContainer.uuid, {
263 error: 'Something went wrong',
264 errorDetail: 'Process exited with status 1',
265 warning: 'Free disk space is low',
268 .as('runningContainer')
269 .then(function(runningContainer) {
270 expect(runningContainer.state).to.be.equal('Running');
271 expect(runningContainer.runtime_status).to.be.deep.equal({
272 'error': 'Something went wrong',
273 'errorDetail': 'Process exited with status 1',
274 'warning': 'Free disk space is low',
279 // Test that the UI shows the error and warning messages
280 cy.getAll('@containerRequest', '@runningContainer').then(function([containerRequest]) {
281 cy.loginAs(activeUser);
282 cy.goToPath(`/processes/${containerRequest.uuid}`);
283 cy.get('[data-cy=process-runtime-status-error]')
284 .should('contain', 'Something went wrong')
285 .and('contain', 'Process exited with status 1');
286 cy.get('[data-cy=process-runtime-status-warning]')
287 .should('contain', 'Free disk space is low')
288 .and('contain', 'No additional warning details available');
292 // Force container_count for testing
293 let containerCount = 2;
294 cy.intercept({method: 'GET', url: '**/arvados/v1/container_requests/*'}, (req) => {
296 res.body.container_count = containerCount;
300 cy.getAll('@containerRequest').then(function([containerRequest]) {
301 cy.goToPath(`/processes/${containerRequest.uuid}`);
302 cy.get('[data-cy=process-runtime-status-retry-warning]')
303 .should('contain', 'Process retried 1 time');
306 cy.getAll('@containerRequest').then(function([containerRequest]) {
308 cy.goToPath(`/processes/${containerRequest.uuid}`);
309 cy.get('[data-cy=process-runtime-status-retry-warning]')
310 .should('contain', 'Process retried 2 times');
318 "id": "#main/input_file",
319 "label": "Label Description",
324 "basename": "input1.tar",
326 "location": "keep:00000000000000000000000000000000+01/input1.tar",
329 "basename": "input1-2.txt",
331 "location": "keep:00000000000000000000000000000000+01/input1-2.txt"
334 "basename": "input1-3.txt",
336 "location": "keep:00000000000000000000000000000000+01/input1-3.txt"
339 "basename": "input1-4.txt",
341 "location": "keep:00000000000000000000000000000000+01/input1-4.txt"
349 "id": "#main/input_dir",
350 "doc": "Doc Description",
355 "basename": "11111111111111111111111111111111+01",
356 "class": "Directory",
357 "location": "keep:11111111111111111111111111111111+01"
363 "id": "#main/input_bool",
364 "doc": ["Doc desc 1", "Doc desc 2"],
373 "id": "#main/input_int",
382 "id": "#main/input_long",
391 "id": "#main/input_float",
400 "id": "#main/input_double",
409 "id": "#main/input_string",
413 "input_string": "Hello World",
418 "id": "#main/input_file_array",
425 "input_file_array": [
427 "basename": "input2.tar",
429 "location": "keep:00000000000000000000000000000000+02/input2.tar"
432 "basename": "input3.tar",
434 "location": "keep:00000000000000000000000000000000+03/input3.tar",
437 "basename": "input3-2.txt",
439 "location": "keep:00000000000000000000000000000000+03/input3-2.txt"
448 "id": "#main/input_dir_array",
450 "items": "Directory",
457 "basename": "11111111111111111111111111111111+02",
458 "class": "Directory",
459 "location": "keep:11111111111111111111111111111111+02"
462 "basename": "11111111111111111111111111111111+03",
463 "class": "Directory",
464 "location": "keep:11111111111111111111111111111111+03"
471 "id": "#main/input_int_array",
487 "id": "#main/input_long_array",
494 "input_long_array": [
502 "id": "#main/input_float_array",
509 "input_float_array": [
518 "id": "#main/input_double_array",
525 "input_double_array": [
534 "id": "#main/input_string_array",
541 "input_string_array": [
550 const testOutputs = [
553 "id": "#main/output_file",
554 "label": "Label Description",
559 "basename": "cat.png",
561 "location": "cat.png"
567 "id": "#main/output_file_with_secondary",
568 "doc": "Doc Description",
572 "output_file_with_secondary": {
573 "basename": "main.dat",
575 "location": "main.dat",
578 "basename": "secondary.dat",
580 "location": "secondary.dat"
583 "basename": "secondary2.dat",
585 "location": "secondary2.dat"
593 "id": "#main/output_dir",
594 "doc": ["Doc desc 1", "Doc desc 2"],
599 "basename": "outdir1",
600 "class": "Directory",
601 "location": "outdir1"
607 "id": "#main/output_bool",
616 "id": "#main/output_int",
625 "id": "#main/output_long",
634 "id": "#main/output_float",
638 "output_float": 100.5
643 "id": "#main/output_double",
647 "output_double": 100.3
652 "id": "#main/output_string",
656 "output_string": "Hello output"
661 "id": "#main/output_file_array",
668 "output_file_array": [
670 "basename": "output2.tar",
672 "location": "output2.tar"
675 "basename": "output3.tar",
677 "location": "output3.tar"
684 "id": "#main/output_dir_array",
686 "items": "Directory",
691 "output_dir_array": [
693 "basename": "outdir2",
694 "class": "Directory",
695 "location": "outdir2"
698 "basename": "outdir3",
699 "class": "Directory",
700 "location": "outdir3"
707 "id": "#main/output_int_array",
714 "output_int_array": [
723 "id": "#main/output_long_array",
730 "output_long_array": [
738 "id": "#main/output_float_array",
745 "output_float_array": [
754 "id": "#main/output_double_array",
761 "output_double_array": [
770 "id": "#main/output_string_array",
777 "output_string_array": [
786 const verifyIOParameter = (name, label, doc, val, collection, multipleRows) => {
787 cy.get('table tr').contains(name).parents('tr').within(($mainRow) => {
788 label && cy.contains(label);
791 cy.get($mainRow).nextUntil('[data-cy="process-io-param"]').as('secondaryRows');
793 if (Array.isArray(val)) {
794 val.forEach(v => cy.get('@secondaryRows').contains(v));
796 cy.get('@secondaryRows').contains(val);
800 cy.get('@secondaryRows').contains(collection);
804 if (Array.isArray(val)) {
805 val.forEach(v => cy.contains(v));
811 cy.contains(collection);
819 const verifyIOParameterImage = (name, url) => {
820 cy.get('table tr').contains(name).parents('tr').within(() => {
821 cy.get('[alt="Inline Preview"]')
822 .should('be.visible')
824 expect($img[0].naturalWidth).to.be.greaterThan(0);
825 expect($img[0].src).contains(url);
830 it('displays IO parameters with keep links and previews', function() {
831 // Create output collection for real files
832 cy.createCollection(adminUser.token, {
833 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
834 owner_uuid: activeUser.user.uuid,
835 }).then((testOutputCollection) => {
836 cy.loginAs(activeUser);
838 cy.goToPath(`/collections/${testOutputCollection.uuid}`);
840 cy.get('[data-cy=upload-button]').click();
842 cy.fixture('files/cat.png', 'base64').then(content => {
843 cy.get('[data-cy=drag-and-drop]').upload(content, 'cat.png');
844 cy.get('[data-cy=form-submit-btn]').click();
845 cy.waitForDom().get('[data-cy=form-submit-btn]').should('not.exist');
846 // Confirm final collection state.
847 cy.get('[data-cy=collection-files-panel]')
848 .contains('cat.png').should('exist');
851 cy.getCollection(activeUser.token, testOutputCollection.uuid).as('testOutputCollection');
854 // Get updated collection pdh
855 cy.getAll('@testOutputCollection').then(([testOutputCollection]) => {
856 // Add output uuid and inputs to container request
857 cy.intercept({method: 'GET', url: '**/arvados/v1/container_requests/*'}, (req) => {
859 res.body.output_uuid = testOutputCollection.uuid;
860 res.body.mounts["/var/lib/cwl/cwl.input.json"] = {
861 content: testInputs.map((param) => (param.input)).reduce((acc, val) => (Object.assign(acc, val)), {})
863 res.body.mounts["/var/lib/cwl/workflow.json"] = {
867 inputs: testInputs.map((input) => (input.definition)),
868 outputs: testOutputs.map((output) => (output.definition))
875 // Stub fake output collection
876 cy.intercept({method: 'GET', url: `**/arvados/v1/collections/${testOutputCollection.uuid}*`}, {
879 uuid: testOutputCollection.uuid,
880 portable_data_hash: testOutputCollection.portable_data_hash,
884 // Stub fake output json
885 cy.intercept({method: 'GET', url: '**/c%3Dzzzzz-4zz18-zzzzzzzzzzzzzzz/cwl.output.json'}, {
887 body: testOutputs.map((param) => (param.output)).reduce((acc, val) => (Object.assign(acc, val)), {})
890 // Stub webdav response, points to output json
891 cy.intercept({method: 'PROPFIND', url: '*'}, {
892 fixture: 'webdav-propfind-outputs.xml',
896 createContainerRequest(
898 'test_container_request',
900 ['echo', 'hello world'],
902 .as('containerRequest');
904 cy.getAll('@containerRequest', '@testOutputCollection').then(function([containerRequest, testOutputCollection]) {
905 cy.goToPath(`/processes/${containerRequest.uuid}`);
906 cy.get('[data-cy=process-io-card] h6').contains('Inputs')
907 .parents('[data-cy=process-io-card]').within(() => {
908 verifyIOParameter('input_file', null, "Label Description", 'input1.tar', '00000000000000000000000000000000+01');
909 verifyIOParameter('input_file', null, "Label Description", 'input1-2.txt', undefined, true);
910 verifyIOParameter('input_file', null, "Label Description", 'input1-3.txt', undefined, true);
911 verifyIOParameter('input_file', null, "Label Description", 'input1-4.txt', undefined, true);
912 verifyIOParameter('input_dir', null, "Doc Description", '/', '11111111111111111111111111111111+01');
913 verifyIOParameter('input_bool', null, "Doc desc 1, Doc desc 2", 'true');
914 verifyIOParameter('input_int', null, null, '1');
915 verifyIOParameter('input_long', null, null, '1');
916 verifyIOParameter('input_float', null, null, '1.5');
917 verifyIOParameter('input_double', null, null, '1.3');
918 verifyIOParameter('input_string', null, null, 'Hello World');
919 verifyIOParameter('input_file_array', null, null, 'input2.tar', '00000000000000000000000000000000+02');
920 verifyIOParameter('input_file_array', null, null, 'input3.tar', undefined, true);
921 verifyIOParameter('input_file_array', null, null, 'input3-2.txt', undefined, true);
922 verifyIOParameter('input_dir_array', null, null, '/', '11111111111111111111111111111111+02');
923 verifyIOParameter('input_dir_array', null, null, '/', '11111111111111111111111111111111+03', true);
924 verifyIOParameter('input_int_array', null, null, ["1", "3", "5"]);
925 verifyIOParameter('input_long_array', null, null, ["10", "20"]);
926 verifyIOParameter('input_float_array', null, null, ["10.2", "10.4", "10.6"]);
927 verifyIOParameter('input_double_array', null, null, ["20.1", "20.2", "20.3"]);
928 verifyIOParameter('input_string_array', null, null, ["Hello", "World", "!"]);
930 cy.get('[data-cy=process-io-card] h6').contains('Outputs')
931 .parents('[data-cy=process-io-card]').within((ctx) => {
932 cy.get(ctx).scrollIntoView();
933 cy.get('[data-cy="io-preview-image-toggle"]').click();
934 const outPdh = testOutputCollection.portable_data_hash;
936 verifyIOParameter('output_file', null, "Label Description", 'cat.png', `${outPdh}`);
937 verifyIOParameterImage('output_file', `/c=${outPdh}/cat.png`);
938 verifyIOParameter('output_file_with_secondary', null, "Doc Description", 'main.dat', `${outPdh}`);
939 verifyIOParameter('output_file_with_secondary', null, "Doc Description", 'secondary.dat', undefined, true);
940 verifyIOParameter('output_file_with_secondary', null, "Doc Description", 'secondary2.dat', undefined, true);
941 verifyIOParameter('output_dir', null, "Doc desc 1, Doc desc 2", 'outdir1', `${outPdh}`);
942 verifyIOParameter('output_bool', null, null, 'true');
943 verifyIOParameter('output_int', null, null, '1');
944 verifyIOParameter('output_long', null, null, '1');
945 verifyIOParameter('output_float', null, null, '100.5');
946 verifyIOParameter('output_double', null, null, '100.3');
947 verifyIOParameter('output_string', null, null, 'Hello output');
948 verifyIOParameter('output_file_array', null, null, 'output2.tar', `${outPdh}`);
949 verifyIOParameter('output_file_array', null, null, 'output3.tar', undefined, true);
950 verifyIOParameter('output_dir_array', null, null, 'outdir2', `${outPdh}`);
951 verifyIOParameter('output_dir_array', null, null, 'outdir3', undefined, true);
952 verifyIOParameter('output_int_array', null, null, ["10", "11", "12"]);
953 verifyIOParameter('output_long_array', null, null, ["51", "52"]);
954 verifyIOParameter('output_float_array', null, null, ["100.2", "100.4", "100.6"]);
955 verifyIOParameter('output_double_array', null, null, ["100.1", "100.2", "100.3"]);
956 verifyIOParameter('output_string_array', null, null, ["Hello", "Output", "!"]);
961 it('displays IO parameters with no value', function() {
963 const fakeOutputUUID = 'zzzzz-4zz18-abcdefghijklmno';
964 const fakeOutputPDH = '11111111111111111111111111111111+99/';
966 cy.loginAs(activeUser);
968 // Add output uuid and inputs to container request
969 cy.intercept({method: 'GET', url: '**/arvados/v1/container_requests/*'}, (req) => {
971 res.body.output_uuid = fakeOutputUUID;
972 res.body.mounts["/var/lib/cwl/cwl.input.json"] = {
975 res.body.mounts["/var/lib/cwl/workflow.json"] = {
979 inputs: testInputs.map((input) => (input.definition)),
980 outputs: testOutputs.map((output) => (output.definition))
987 // Stub fake output collection
988 cy.intercept({method: 'GET', url: `**/arvados/v1/collections/${fakeOutputUUID}*`}, {
991 uuid: fakeOutputUUID,
992 portable_data_hash: fakeOutputPDH,
996 // Stub fake output json
997 cy.intercept({method: 'GET', url: `**/c%3D${fakeOutputUUID}/cwl.output.json`}, {
1002 cy.readFile('cypress/fixtures/webdav-propfind-outputs.xml').then((data) => {
1003 // Stub webdav response, points to output json
1004 cy.intercept({method: 'PROPFIND', url: '*'}, {
1006 body: data.replace(/zzzzz-4zz18-zzzzzzzzzzzzzzz/g, fakeOutputUUID)
1010 createContainerRequest(
1012 'test_container_request',
1014 ['echo', 'hello world'],
1016 .as('containerRequest');
1018 cy.getAll('@containerRequest').then(function([containerRequest]) {
1019 cy.goToPath(`/processes/${containerRequest.uuid}`);
1020 cy.get('[data-cy=process-io-card] h6').contains('Inputs')
1021 .parents('[data-cy=process-io-card]').within(() => {
1024 cy.get('tbody tr').each((item) => {
1025 cy.wrap(item).contains('No value');
1028 cy.get('[data-cy=process-io-card] h6').contains('Outputs')
1029 .parents('[data-cy=process-io-card]').within(() => {
1030 cy.get('tbody tr').each((item) => {
1031 cy.wrap(item).contains('No value');