From 1b35148a286157fa63a77bde474bd59900e0c7b9 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 14 Jan 2021 09:51:21 -0800 Subject: [PATCH 01/42] fix SCT-2914 / PUBLIC-1493 - movement of unselected cells - fix movement of unselected cells - improve styling of toolbar controls in unselected cells - integration tests for the above --- RELEASE_NOTES.md | 1 + .../static/kbase/custom/custom.css | 20 +- kbase-extension/static/kbase/js/userMenu.js | 6 +- .../narrative_core/kbaseCellToolbarMenu.js | 25 +- .../specs/kbaseCellToolbarMenu_test.js | 317 ++++++++++++++++++ test/integration/wdioUtils.js | 13 +- 6 files changed, 358 insertions(+), 24 deletions(-) create mode 100644 test/integration/specs/kbaseCellToolbarMenu_test.js diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index d00aba80d4..c1407dd5c5 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -6,6 +6,7 @@ This is built on the Jupyter Notebook v6.0.2 (more notes will follow). ### Version NEXT - SCT-2778 - convert data slideout, public tab, refseq data source to use searchapi2/rpc api rather than searchapi2/legacy. - enhance integration testing support to add service, host, browser, screen size support +- SCT-2914 / PUBLIC-1493 - fix up/down cell movement behavior for unselected cells ### Version 4.3.1 - Fixed problem where code cells could forget their toggled state after saving. diff --git a/kbase-extension/static/kbase/custom/custom.css b/kbase-extension/static/kbase/custom/custom.css index 33a946f084..96c0613b29 100644 --- a/kbase-extension/static/kbase/custom/custom.css +++ b/kbase-extension/static/kbase/custom/custom.css @@ -315,14 +315,30 @@ div#notebook { color: #ccc; } +.cell.unselected .btn-default:hover { + color: #000; + } + .cell.unselected .kb-cell-toolbar .title-container { opacity: 0.5; } -.cell.unselected .kb-cell-toolbar .buttons-container { - opacity: 0.2; +.btn.btn-default.kb-btn-expander.-minimized { + color: rgba(255,137,0,1); +} + +.cell.unselected .kb-btn-expander.-minimized { + color: rgba(255,137,0, 0.5); } +.cell.unselected .kb-btn-expander.-minimized:hover { + color: rgba(255,137,0, 1); + } + +/* .cell.unselected .kb-cell-toolbar .buttons-container { + opacity: 0.2; +} */ + .kb-btn-icon { display: inline-block; padding: 4px; diff --git a/kbase-extension/static/kbase/js/userMenu.js b/kbase-extension/static/kbase/js/userMenu.js index cd10c1891c..1369f80922 100644 --- a/kbase-extension/static/kbase/js/userMenu.js +++ b/kbase-extension/static/kbase/js/userMenu.js @@ -82,10 +82,10 @@ define([ div({style: 'display:inline-block; width: 34px; vertical-align: top;'}, [ span({class: 'fa fa-user', style: 'font-size: 150%; margin-right: 10px;'}) ]), - div({style: 'display: inline-block', 'data-element': 'user-label'}, [ - displayName, + div({style: 'display: inline-block'}, [ + span({'data-element': 'realname'}, displayName), br(), - i({}, userName) + i({'data-element': 'username'}, userName) ]) ]) ]), diff --git a/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseCellToolbarMenu.js b/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseCellToolbarMenu.js index 97d559805c..853acff319 100644 --- a/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseCellToolbarMenu.js +++ b/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseCellToolbarMenu.js @@ -22,7 +22,7 @@ define([ ) { 'use strict'; - var t = html.tag, + const t = html.tag, div = t('div'), a = t('a'), button = t('button'), @@ -50,11 +50,13 @@ define([ readOnly = Jupyter.narrative.readonly; function doMoveCellUp() { - Jupyter.notebook.move_cell_up(); + const cellIndex = Jupyter.notebook.find_cell_index(cell); + Jupyter.notebook.move_cell_up(cellIndex); } function doMoveCellDown() { - Jupyter.notebook.move_cell_down(); + const cellIndex = Jupyter.notebook.find_cell_index(cell); + Jupyter.notebook.move_cell_down(cellIndex); } function doDeleteCell() { @@ -199,10 +201,8 @@ define([ } function renderOptions(cell, events) { - var toggleMinMax = utils.getCellMeta(cell, 'kbase.cellState.toggleMinMax', 'maximized'), - toggleIcon = (toggleMinMax === 'maximized' ? 'minus' : 'plus'), - dropdownId = html.genId(), - menuItems = []; + const dropdownId = html.genId(); + const menuItems = []; if (cell.cell_type === 'code') { menuItems.push({ @@ -403,12 +403,12 @@ define([ ])), (function () { - var toggleMinMax = utils.getCellMeta(cell, 'kbase.cellState.toggleMinMax', 'maximized'), + const toggleMinMax = utils.getCellMeta(cell, 'kbase.cellState.toggleMinMax', 'maximized'), toggleIcon = (toggleMinMax === 'maximized' ? 'minus' : 'plus'), - color = (toggleMinMax === 'maximized' ? '#000' : 'rgba(255,137,0,1)'); + classModifier = (toggleMinMax === 'maximized' ? '-maximized' : '-minimized'); return button({ type: 'button', - class: 'btn btn-default btn-xs', + class: `btn btn-default btn-xs kb-btn-expander ${classModifier}`, dataToggle: 'tooltip', dataPlacement: 'left', title: true, @@ -418,10 +418,7 @@ define([ id: events.addEvent({type: 'click', handler: doToggleMinMaxCell}) }, [ span({ - class: 'fa fa-' + toggleIcon + '-square-o fa-lg', - style: { - color: color - } + class: 'fa fa-' + toggleIcon + '-square-o fa-lg' }) ]); }()) diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js new file mode 100644 index 0000000000..5e656c2ed6 --- /dev/null +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -0,0 +1,317 @@ +/*global describe, it, browser, expect, $, afterEach, beforeEach*/ +/* eslint {strict: ['error', 'global']} */ +'use strict'; + +const {login, openNarrative, sendString, clickWhenReady} = require('../wdioUtils.js'); + +/* +Notes: + +The test narrative has 4 markdown cells, each collapsed. The initial collapsed +state makes some tests easier, because they all have a title. +*/ + +const testData = { + common: { + unselectedBorder: '1px 1px 1px 5px solid rgb(204, 204, 204)', + selectedBorder: '1px 1px 1px 5px solid rgb(75, 184, 86)', + }, + all: { + TEST_CASE1: { + cellIndex: 1, + title: "Narrative Cell Toolbar Testing" + }, + TEST_CASE2: { + cellIndex: 2, + title: "Cell 1" + }, + TEST_CASE3: { + cellIndex: 3, + title: "Cell 2" + }, + TEST_CASE4: { + cellIndex: 3, + title: "Cell 2" + }, + TEST_CASE5: { + cellIndex: 4, + body: "Cell 3" + } + }, + ci: { + TEST_CASE1: { + narrativeId: 58675, + }, + TEST_CASE2: { + narrativeId: 58675, + }, + TEST_CASE3: { + narrativeId: 58675, + }, + TEST_CASE4: { + narrativeId: 58675, + }, + TEST_CASE5: { + narrativeId: 58675, + } + }, + 'narrative-dev': { + TEST_CASE1: { + narrativeId: 80970, + }, + TEST_CASE2: { + narrativeId: 80970, + }, + TEST_CASE3: { + narrativeId: 80970, + }, + TEST_CASE4: { + narrativeId: 80970, + }, + TEST_CASE5: { + narrativeId: 80970, + } + } +}; + +const testCases = mergeObjects([testData[browser.config.testParams.ENV], testData.all]); + +function mergeObjects(listOfObjects) { + const simpleObjectPrototype = Object.getPrototypeOf({}); + + function isSimpleObject(obj) { + return Object.getPrototypeOf(obj) === simpleObjectPrototype; + } + + function merge(obj1, obj2, keyStack) { + Object.keys(obj2).forEach(function (key) { + const obj1Value = obj1[key]; + const obj2Value = obj2[key]; + const obj1Type = typeof obj1Value; + // var obj2Type = typeof obj2Value; + if (obj1Type === 'undefined') { + obj1[key] = obj2[key]; + } else if (isSimpleObject(obj1Value) && isSimpleObject(obj2Value)) { + keyStack.push(key); + merge(obj1Value, obj2Value, keyStack); + keyStack.pop(); + } else { + console.error('UNMERGABLE', obj1Type, obj1Value); + throw new Error('Unmergable at ' + keyStack.join('.') + ':' + key); + } + }); + } + + const base = JSON.parse(JSON.stringify(listOfObjects[0])); + for (let i = 1; i < listOfObjects.length; i += 1) { + merge(base, listOfObjects[i], []); + } + return base; +} + + + +async function waitForCell(notebookContainer, cellIndex){ + return await browser.waitUntil(async () => { + const cell = await notebookContainer.$(`.cell:nth-child(${cellIndex})`); + return cell; + }); + // return await panel.$$('[role="table"][data-test-id="result"] > div > [role="row"]'); +} + +async function waitForCellWithTitle(container, cellIndex, title) { + const cell = await waitForCell(container, cellIndex); + await browser.waitUntil(async () => { + const titleElement = await cell.$('[data-element="title"]'); + const text = await titleElement.getText(); + return text === title; + }); + return cell; +} + +async function waitForCellWithBody(container, cellIndex, bodyText) { + const cell = await waitForCell(container, cellIndex); + await browser.waitUntil(async () => { + const element = await cell.$('.text_cell_render.rendered_html'); + const text = await element.getText(); + return text === bodyText; + }); + return cell; +} + +async function selectCell(container, cellIndex, title) { + const cell = await waitForCellWithTitle(container, cellIndex, title); + + // Make sure not selected. + // We do this by inspecting the border. + const borderStyle = await cell.getCSSProperty('border'); + expect(borderStyle.value).toEqual(testData.common.unselectedBorder); + + // Click on title area to select cell. + const titleArea = await cell.$('.title-container'); + await clickWhenReady(titleArea); + + await browser.waitUntil(async () => { + const borderStyle = await cell.getCSSProperty('border'); + return borderStyle.value === testData.common.selectedBorder; + }); + + return cell; +} + +async function selectCellWithBody(container, cellIndex, body) { + const cell = await waitForCellWithBody(container, cellIndex, body); + + // Make sure not selected. + // We do this by inspecting the border. + const borderStyle = await cell.getCSSProperty('border'); + expect(borderStyle.value).toEqual(testData.common.unselectedBorder); + + // Click on title area to select cell. + const bodyArea = await cell.$('.text_cell_render.rendered_html'); + await clickWhenReady(bodyArea); + + await browser.waitUntil(async () => { + const borderStyle = await cell.getCSSProperty('border'); + return borderStyle.value === testData.common.selectedBorder; + }); + + return cell; +} + +describe('Test kbaseCellToolbarMenu', () => { + beforeEach(async () => { + await browser.setTimeout({ 'implicit': 30000 }); + await browser.reloadSession(); + }); + + afterEach(async () => { + await browser.deleteCookies(); + }); + + it('moves a minimized selected cell down', async () => { + const testCase = testCases.TEST_CASE1; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + + const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); + + // Find and click the move-down button + const downButton = await cell.$('[data-test="cell-move-down"]'); + await clickWhenReady(downButton); + await waitForCellWithTitle(narrativeContainer, testCase.cellIndex + 1, testCase.title); + }); + + it('moves a minimized unselected cell down', async () => { + const testCase = testCases.TEST_CASE2; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + + const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); + + // Find and click the move-down button + const downButton = await cell.$('[data-test="cell-move-down"]'); + await clickWhenReady(downButton); + await waitForCellWithTitle(narrativeContainer, testCase.cellIndex + 1, testCase.title); + }); + + it('moves a minimized unselected cell up', async () => { + const testCase = testCases.TEST_CASE3; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + + const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); + + // Find and click the move-ups button + const upButton = await cell.$('[data-test="cell-move-up"]'); + await clickWhenReady(upButton); + await waitForCellWithTitle(narrativeContainer, testCase.cellIndex - 1, testCase.title); + }); + + // select cell + it('selects a minimized cell', async () => { + const testCase = testCases.TEST_CASE4; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); + }); + + // select cell and move down + it('selects a minimized cell and moves it down', async () => { + const testCase = testCases.TEST_CASE4; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + const cell = await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); + const downButton = await cell.$('[data-test="cell-move-down"]'); + await clickWhenReady(downButton); + await waitForCellWithTitle(narrativeContainer, testCase.cellIndex + 1, testCase.title); + }); + + // select cell and move up + it('selects a minimized cell and moves it up', async () => { + const testCase = testCases.TEST_CASE4; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + const cell = await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); + const upButton = await cell.$('[data-test="cell-move-up"]'); + await clickWhenReady(upButton); + await waitForCellWithTitle(narrativeContainer, testCase.cellIndex - 1, testCase.title); + }); + + // Everything above, but cells are expanded. + + it('moves an expanded unselected cell down', async () => { + const testCase = testCases.TEST_CASE5; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + + const cell = await waitForCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + + // Find and click the move-down button + const downButton = await cell.$('[data-test="cell-move-down"]'); + await clickWhenReady(downButton); + await waitForCellWithBody(narrativeContainer, testCase.cellIndex + 1, testCase.body); + }); + + it('moves an expanded unselected cell up', async () => { + const testCase = testCases.TEST_CASE5; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + + const cell = await waitForCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + + // Find and click the move-down button + const button = await cell.$('[data-test="cell-move-up"]'); + await clickWhenReady(button); + await waitForCellWithBody(narrativeContainer, testCase.cellIndex - 1, testCase.body); + }); + + it('selects an expanded cell', async () => { + const testCase = testCases.TEST_CASE5; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + }); + + // select cell and move down + it('selects an expanded cell and moves it down', async () => { + const testCase = testCases.TEST_CASE5; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + const cell = await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + const downButton = await cell.$('[data-test="cell-move-down"]'); + await clickWhenReady(downButton); + await waitForCellWithBody(narrativeContainer, testCase.cellIndex + 1, testCase.body); + }); + + // select cell and move up + it('selects an expanded cell and moves it up', async () => { + const testCase = testCases.TEST_CASE5; + await login(); + const narrativeContainer = await openNarrative(testCase.narrativeId); + const cell = await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + const upButton = await cell.$('[data-test="cell-move-up"]'); + await clickWhenReady(upButton); + await waitForCellWithBody(narrativeContainer, testCase.cellIndex - 1, testCase.body); + }); +}); diff --git a/test/integration/wdioUtils.js b/test/integration/wdioUtils.js index 1fc8ff2f71..1c07157d55 100644 --- a/test/integration/wdioUtils.js +++ b/test/integration/wdioUtils.js @@ -93,13 +93,15 @@ async function openNarrative(workspaceId) { await clickWhenReady(loginButton); - const userLabelElement = await $('[data-element="user-label"]'); + const realnameElement = await $('[data-element="realname"]'); + const usernameElement = await $('[data-element="username"]'); await browser.waitUntil(async () => { - const userLabelText = await userLabelElement.getText(); - return (userLabelText && userLabelText.length > 0); + const text = await realnameElement.getText(); + return (text && text.length > 0); }); - const text = await userLabelElement.getText(); - console.warn(`Logged in as user ${text}`); + const realname = await realnameElement.getText(); + const username = await usernameElement.getText(); + console.warn(`Signed in as user "${realname}" (${username})`); await loginButton.click(); // Ensure narrative notebook has displayed @@ -110,6 +112,7 @@ async function openNarrative(workspaceId) { timeout, timeoutMsg: `Timeout after waiting ${timeout}ms for narrative to appear` }); + return container; } module.exports = { From 6aad8e9d72f9c03806284d3ba19b09450e2fccd3 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 14 Jan 2021 10:10:15 -0800 Subject: [PATCH 02/42] add more test doc --- .../specs/kbaseCellToolbarMenu_test.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index 5e656c2ed6..e2c23ff7a7 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -2,13 +2,21 @@ /* eslint {strict: ['error', 'global']} */ 'use strict'; -const {login, openNarrative, sendString, clickWhenReady} = require('../wdioUtils.js'); +const {login, openNarrative, clickWhenReady} = require('../wdioUtils.js'); /* Notes: -The test narrative has 4 markdown cells, each collapsed. The initial collapsed -state makes some tests easier, because they all have a title. +The test narrative has 5 markdown cells. The first cell has summary text, the remaining 4 contain the text "Cell #". +The first three cells are collapsed, the last two are expanded. + +Tests currently cover common cases of cell movement; additional cases can be added, e.g. try to move +past the end, or before the beginning, try moving the same cell multiple times, inspect the state +of all cells after a movement. + +This test suite could be expanded to cover all usage of the cell toolbar (kbaseCellToolbarMenu.js), or they +could be in separate files. + */ const testData = { @@ -109,8 +117,6 @@ function mergeObjects(listOfObjects) { return base; } - - async function waitForCell(notebookContainer, cellIndex){ return await browser.waitUntil(async () => { const cell = await notebookContainer.$(`.cell:nth-child(${cellIndex})`); From 632318dc5d0775584ef639bbb733a0e67059bb0a Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 14 Jan 2021 10:28:52 -0800 Subject: [PATCH 03/42] fix code quality issue --- test/integration/specs/kbaseCellToolbarMenu_test.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index e2c23ff7a7..493baf6035 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -150,8 +150,10 @@ async function selectCell(container, cellIndex, title) { // Make sure not selected. // We do this by inspecting the border. - const borderStyle = await cell.getCSSProperty('border'); - expect(borderStyle.value).toEqual(testData.common.unselectedBorder); + await browser.waitUntil(async () => { + const borderStyle = await cell.getCSSProperty('border'); + return borderStyle.value === testData.common.unselectedBorder; + }); // Click on title area to select cell. const titleArea = await cell.$('.title-container'); @@ -170,8 +172,11 @@ async function selectCellWithBody(container, cellIndex, body) { // Make sure not selected. // We do this by inspecting the border. - const borderStyle = await cell.getCSSProperty('border'); - expect(borderStyle.value).toEqual(testData.common.unselectedBorder); + await browser.waitUntil(async () => { + const borderStyle = await cell.getCSSProperty('border'); + return borderStyle.value === testData.common.unselectedBorder; + }); + // Click on title area to select cell. const bodyArea = await cell.$('.text_cell_render.rendered_html'); From a4a9a8338c1c04eb8d00634f90217ae874cddef7 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 14 Jan 2021 10:47:05 -0800 Subject: [PATCH 04/42] Address github code quality alerts --- .../static/kbase/custom/custom.css | 26 ++++++++----------- .../specs/kbaseCellToolbarMenu_test.js | 12 ++++----- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/kbase-extension/static/kbase/custom/custom.css b/kbase-extension/static/kbase/custom/custom.css index 96c0613b29..a28f6cc872 100644 --- a/kbase-extension/static/kbase/custom/custom.css +++ b/kbase-extension/static/kbase/custom/custom.css @@ -25,7 +25,7 @@ CSS should go in /kbase-extension/static/kbase/css/kbaseNarrative.css /* disable the standard notebook, bottom spacer */ -#notebook > .end_space { +#notebook>.end_space { min-height: 0; height: 0; } @@ -195,11 +195,11 @@ div#notebook { overflow: visible; } -.notebook_app .celltoolbar > .button_container { +.notebook_app .celltoolbar>.button_container { flex: 0 auto; } -.notebook_app .celltoolbar > .button_container:nth-child(1) { +.notebook_app .celltoolbar>.button_container:nth-child(1) { flex: auto; } @@ -303,7 +303,7 @@ div#notebook { color: #d84315; } -.cell > .inner_cell > .ctb_hideshow { +.cell>.inner_cell>.ctb_hideshow { display: block; } @@ -316,28 +316,24 @@ div#notebook { } .cell.unselected .btn-default:hover { - color: #000; - } + color: #000; +} .cell.unselected .kb-cell-toolbar .title-container { opacity: 0.5; } .btn.btn-default.kb-btn-expander.-minimized { - color: rgba(255,137,0,1); + color: rgba(255, 137, 0, 1); } .cell.unselected .kb-btn-expander.-minimized { - color: rgba(255,137,0, 0.5); + color: rgba(255, 137, 0, 0.5); } .cell.unselected .kb-btn-expander.-minimized:hover { - color: rgba(255,137,0, 1); - } - -/* .cell.unselected .kb-cell-toolbar .buttons-container { - opacity: 0.2; -} */ + color: rgba(255, 137, 0, 1); +} .kb-btn-icon { display: inline-block; @@ -385,4 +381,4 @@ div.code_cell div.input_prompt { .run_this_cell { padding: 0 !important; width: 0 !important; -} +} \ No newline at end of file diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index 493baf6035..01e8379629 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -27,23 +27,23 @@ const testData = { all: { TEST_CASE1: { cellIndex: 1, - title: "Narrative Cell Toolbar Testing" + title: 'Narrative Cell Toolbar Testing' }, TEST_CASE2: { cellIndex: 2, - title: "Cell 1" + title: 'Cell 1' }, TEST_CASE3: { cellIndex: 3, - title: "Cell 2" + title: 'Cell 2' }, TEST_CASE4: { cellIndex: 3, - title: "Cell 2" + title: 'Cell 2' }, TEST_CASE5: { cellIndex: 4, - body: "Cell 3" + body: 'Cell 3' } }, ci: { @@ -239,7 +239,7 @@ describe('Test kbaseCellToolbarMenu', () => { await waitForCellWithTitle(narrativeContainer, testCase.cellIndex - 1, testCase.title); }); - // select cell + // select cell it('selects a minimized cell', async () => { const testCase = testCases.TEST_CASE4; await login(); From 5ae04bc0c27f62291aa796d2836a3b4b531b09e3 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 14 Jan 2021 12:33:16 -0800 Subject: [PATCH 05/42] reformat to make codacy happy --- .../static/kbase/custom/custom.css | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/kbase-extension/static/kbase/custom/custom.css b/kbase-extension/static/kbase/custom/custom.css index a28f6cc872..97b7866d20 100644 --- a/kbase-extension/static/kbase/custom/custom.css +++ b/kbase-extension/static/kbase/custom/custom.css @@ -5,9 +5,15 @@ CSS should go in /kbase-extension/static/kbase/css/kbaseNarrative.css (or the specific css file if available) */ @font-face { - font-family: 'Glyphicons Halflings'; - src: url('../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot'); - src: url('../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff') format('woff'), url('../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); + font-family: "Glyphicons Halflings"; + src: url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot"); + src: url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot?#iefix") + format("embedded-opentype"), + url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2") format("woff2"), + url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff") format("woff"), + url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf") format("truetype"), + url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") + format("svg"); } .select2-container--default .select2-results__option--highlighted[aria-selected] { @@ -25,7 +31,7 @@ CSS should go in /kbase-extension/static/kbase/css/kbaseNarrative.css /* disable the standard notebook, bottom spacer */ -#notebook>.end_space { +#notebook > .end_space { min-height: 0; height: 0; } @@ -195,11 +201,11 @@ div#notebook { overflow: visible; } -.notebook_app .celltoolbar>.button_container { +.notebook_app .celltoolbar > .button_container { flex: 0 auto; } -.notebook_app .celltoolbar>.button_container:nth-child(1) { +.notebook_app .celltoolbar > .button_container:nth-child(1) { flex: auto; } @@ -303,7 +309,7 @@ div#notebook { color: #d84315; } -.cell>.inner_cell>.ctb_hideshow { +.cell > .inner_cell > .ctb_hideshow { display: block; } @@ -381,4 +387,4 @@ div.code_cell div.input_prompt { .run_this_cell { padding: 0 !important; width: 0 !important; -} \ No newline at end of file +} From f10799f6b88ee3a707fd4d01b5140eb665f7e20b Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 14 Jan 2021 13:33:01 -0800 Subject: [PATCH 06/42] more codacy / stylelint happiness --- kbase-extension/static/kbase/custom/custom.css | 7 ++++--- test/integration/specs/kbaseCellToolbarMenu_test.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/kbase-extension/static/kbase/custom/custom.css b/kbase-extension/static/kbase/custom/custom.css index 97b7866d20..de59079c5c 100644 --- a/kbase-extension/static/kbase/custom/custom.css +++ b/kbase-extension/static/kbase/custom/custom.css @@ -7,13 +7,14 @@ CSS should go in /kbase-extension/static/kbase/css/kbaseNarrative.css @font-face { font-family: "Glyphicons Halflings"; src: url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot"); - src: url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot?#iefix") - format("embedded-opentype"), + src: + url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot?#iefix") + format("embedded-opentype"), url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2") format("woff2"), url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff") format("woff"), url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf") format("truetype"), url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") - format("svg"); + format("svg"); } .select2-container--default .select2-results__option--highlighted[aria-selected] { diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index 01e8379629..a92d45008a 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -1,4 +1,4 @@ -/*global describe, it, browser, expect, $, afterEach, beforeEach*/ +/*global describe, it, browser, expect, afterEach, beforeEach*/ /* eslint {strict: ['error', 'global']} */ 'use strict'; From 9b6072551d60d75a02a5ec19ea9db0d526de8959 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 14 Jan 2021 13:38:26 -0800 Subject: [PATCH 07/42] more codacy spam --- kbase-extension/static/kbase/custom/custom.css | 2 +- test/integration/specs/kbaseCellToolbarMenu_test.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/kbase-extension/static/kbase/custom/custom.css b/kbase-extension/static/kbase/custom/custom.css index de59079c5c..c88f0b0b16 100644 --- a/kbase-extension/static/kbase/custom/custom.css +++ b/kbase-extension/static/kbase/custom/custom.css @@ -7,7 +7,7 @@ CSS should go in /kbase-extension/static/kbase/css/kbaseNarrative.css @font-face { font-family: "Glyphicons Halflings"; src: url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot"); - src: + src: url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"), url("../../ext_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2") format("woff2"), diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index a92d45008a..d15cdffb2a 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -1,4 +1,4 @@ -/*global describe, it, browser, expect, afterEach, beforeEach*/ +/*global describe, it, browser, afterEach, beforeEach*/ /* eslint {strict: ['error', 'global']} */ 'use strict'; @@ -122,7 +122,6 @@ async function waitForCell(notebookContainer, cellIndex){ const cell = await notebookContainer.$(`.cell:nth-child(${cellIndex})`); return cell; }); - // return await panel.$$('[role="table"][data-test-id="result"] > div > [role="row"]'); } async function waitForCellWithTitle(container, cellIndex, title) { From 2c7e7fab9f95869a384a4fdce5ca02ebe9d00339 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 21 Jan 2021 09:32:54 -0800 Subject: [PATCH 08/42] improve test case property naming (TEST_CASEX -> TEST_CASE_X); move login() into beforeEach() --- .../specs/kbaseCellToolbarMenu_test.js | 74 +++++++++---------- .../specs/kbaseNarrativeSidePublicTab_test.js | 39 +++++----- .../integration/specs/narrative_basic_test.js | 6 +- 3 files changed, 59 insertions(+), 60 deletions(-) diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index d15cdffb2a..cb2c9443d6 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -25,58 +25,58 @@ const testData = { selectedBorder: '1px 1px 1px 5px solid rgb(75, 184, 86)', }, all: { - TEST_CASE1: { + TEST_CASE_1: { cellIndex: 1, title: 'Narrative Cell Toolbar Testing' }, - TEST_CASE2: { + TEST_CASE_2: { cellIndex: 2, title: 'Cell 1' }, - TEST_CASE3: { + TEST_CASE_3: { cellIndex: 3, title: 'Cell 2' }, - TEST_CASE4: { + TEST_CASE_4: { cellIndex: 3, title: 'Cell 2' }, - TEST_CASE5: { + TEST_CASE_5: { cellIndex: 4, body: 'Cell 3' } }, ci: { - TEST_CASE1: { + TEST_CASE_1: { narrativeId: 58675, }, - TEST_CASE2: { + TEST_CASE_2: { narrativeId: 58675, }, - TEST_CASE3: { + TEST_CASE_3: { narrativeId: 58675, }, - TEST_CASE4: { + TEST_CASE_4: { narrativeId: 58675, }, - TEST_CASE5: { + TEST_CASE_5: { narrativeId: 58675, } }, 'narrative-dev': { - TEST_CASE1: { + TEST_CASE_1: { narrativeId: 80970, }, - TEST_CASE2: { + TEST_CASE_2: { narrativeId: 80970, }, - TEST_CASE3: { + TEST_CASE_3: { narrativeId: 80970, }, - TEST_CASE4: { + TEST_CASE_4: { narrativeId: 80970, }, - TEST_CASE5: { + TEST_CASE_5: { narrativeId: 80970, } } @@ -193,6 +193,7 @@ describe('Test kbaseCellToolbarMenu', () => { beforeEach(async () => { await browser.setTimeout({ 'implicit': 30000 }); await browser.reloadSession(); + await login(); }); afterEach(async () => { @@ -200,8 +201,7 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('moves a minimized selected cell down', async () => { - const testCase = testCases.TEST_CASE1; - await login(); + const testCase = testCases.TEST_CASE_1; const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); @@ -213,8 +213,8 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('moves a minimized unselected cell down', async () => { - const testCase = testCases.TEST_CASE2; - await login(); + const testCase = testCases.TEST_CASE_2; + const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); @@ -226,8 +226,8 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('moves a minimized unselected cell up', async () => { - const testCase = testCases.TEST_CASE3; - await login(); + const testCase = testCases.TEST_CASE_3; + const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); @@ -240,16 +240,16 @@ describe('Test kbaseCellToolbarMenu', () => { // select cell it('selects a minimized cell', async () => { - const testCase = testCases.TEST_CASE4; - await login(); + const testCase = testCases.TEST_CASE_4; + const narrativeContainer = await openNarrative(testCase.narrativeId); await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); }); // select cell and move down it('selects a minimized cell and moves it down', async () => { - const testCase = testCases.TEST_CASE4; - await login(); + const testCase = testCases.TEST_CASE_4; + const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); const downButton = await cell.$('[data-test="cell-move-down"]'); @@ -259,8 +259,8 @@ describe('Test kbaseCellToolbarMenu', () => { // select cell and move up it('selects a minimized cell and moves it up', async () => { - const testCase = testCases.TEST_CASE4; - await login(); + const testCase = testCases.TEST_CASE_4; + const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); const upButton = await cell.$('[data-test="cell-move-up"]'); @@ -271,8 +271,8 @@ describe('Test kbaseCellToolbarMenu', () => { // Everything above, but cells are expanded. it('moves an expanded unselected cell down', async () => { - const testCase = testCases.TEST_CASE5; - await login(); + const testCase = testCases.TEST_CASE_5; + const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await waitForCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); @@ -284,8 +284,8 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('moves an expanded unselected cell up', async () => { - const testCase = testCases.TEST_CASE5; - await login(); + const testCase = testCases.TEST_CASE_5; + const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await waitForCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); @@ -297,16 +297,16 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('selects an expanded cell', async () => { - const testCase = testCases.TEST_CASE5; - await login(); + const testCase = testCases.TEST_CASE_5; + const narrativeContainer = await openNarrative(testCase.narrativeId); await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); }); // select cell and move down it('selects an expanded cell and moves it down', async () => { - const testCase = testCases.TEST_CASE5; - await login(); + const testCase = testCases.TEST_CASE_5; + const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); const downButton = await cell.$('[data-test="cell-move-down"]'); @@ -316,8 +316,8 @@ describe('Test kbaseCellToolbarMenu', () => { // select cell and move up it('selects an expanded cell and moves it up', async () => { - const testCase = testCases.TEST_CASE5; - await login(); + const testCase = testCases.TEST_CASE_5; + const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); const upButton = await cell.$('[data-test="cell-move-up"]'); diff --git a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js index 85227c64f9..802f4dc44b 100644 --- a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js +++ b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js @@ -11,7 +11,7 @@ const {login, openNarrative, sendString, clickWhenReady} = require('../wdioUtils // Note that narrativetest is not yet set up in narrative-dev/prod. const allTestCases = { ci: { - TEST_CASE1: { + TEST_CASE_1: { narrativeId: 53983, row: 4, name: 'Acetobacter ascendens', @@ -43,7 +43,7 @@ const allTestCases = { } ] }, - TEST_CASE2: { + TEST_CASE_2: { narrativeId: 53983, row: 10, scrollTo: true, @@ -76,7 +76,7 @@ const allTestCases = { } ] }, - TEST_CASE3: { + TEST_CASE_3: { narrativeId: 53983, row: 1, scrollTo: false, @@ -111,12 +111,12 @@ const allTestCases = { } ] }, - TEST_CASE4: { + TEST_CASE_4: { narrativeId: 53983, searchFor: 'foobar', foundCount: 'None' }, - TEST_CASE5: { + TEST_CASE_5: { narrativeId: 53983, row: 30, scrollTo: true, @@ -154,7 +154,7 @@ const allTestCases = { } }, 'narrative-dev': { - TEST_CASE1: { + TEST_CASE_1: { narrativeId: 78050, row: 3, name: 'Absiella sp. AM09-45', @@ -186,7 +186,7 @@ const allTestCases = { } ] }, - TEST_CASE2: { + TEST_CASE_2: { narrativeId: 78050, row: 10, scrollTo: true, @@ -219,7 +219,7 @@ const allTestCases = { } ] }, - TEST_CASE3: { + TEST_CASE_3: { narrativeId: 78050, row: 1, scrollTo: false, @@ -254,12 +254,12 @@ const allTestCases = { } ] }, - TEST_CASE4: { + TEST_CASE_4: { narrativeId: 78050, searchFor: 'foobar', foundCount: 'None' }, - TEST_CASE5: { + TEST_CASE_5: { narrativeId: 78050, row: 30, scrollTo: true, @@ -352,6 +352,7 @@ describe('Test kbaseNarrativeSidePublicTab', () => { beforeEach(async () => { await browser.setTimeout({ 'implicit': 30000 }); await browser.reloadSession(); + await login(); }); afterEach(async () => { @@ -359,8 +360,8 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results', async () => { - const testCase = testCases.TEST_CASE1; - await login(); + const testCase = testCases.TEST_CASE_1; + await openNarrative(testCase.narrativeId); const publicPanel = await openPublicData(); @@ -385,8 +386,7 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { - const testCase = testCases.TEST_CASE2; - await login(); + const testCase = testCases.TEST_CASE_2; await openNarrative(testCase.narrativeId); const publicPanel = await openPublicData(); @@ -411,9 +411,8 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, searches for a term, should find an expected row', async () => { - const testCase = testCases.TEST_CASE3; + const testCase = testCases.TEST_CASE_3; - await login(); await openNarrative(testCase.narrativeId); const publicPanel = await openPublicData(); @@ -452,8 +451,8 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, searches for a term which should not be found', async () => { - await login(); - const testCase = testCases.TEST_CASE4; + const testCase = testCases.TEST_CASE_4; + await openNarrative(testCase.narrativeId); const publicPanel = await openPublicData(); @@ -480,8 +479,8 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { - const testCase = testCases.TEST_CASE5; - await login(); + const testCase = testCases.TEST_CASE_5; + await openNarrative(testCase.narrativeId); // Open the data slideout diff --git a/test/integration/specs/narrative_basic_test.js b/test/integration/specs/narrative_basic_test.js index cb3cf96c4e..0dc67bbaae 100644 --- a/test/integration/specs/narrative_basic_test.js +++ b/test/integration/specs/narrative_basic_test.js @@ -5,13 +5,13 @@ const env = process.env.ENV || 'ci'; const allTestCases = { ci: { - CASE1: { + CASE_1: { narrativeId: 31932 } }, 'narrative-dev': { - CASE1: { + CASE_1: { narrativeId: 78050 } } @@ -25,7 +25,7 @@ describe('Narrative tree page with login', () => { beforeEach(async () => await Utils.login()); it('opens a narrative', async () => { - await browser.url(Utils.makeURL(`narrative/${testCases.CASE1.narrativeId}`)); + await browser.url(Utils.makeURL(`narrative/${testCases.CASE_1.narrativeId}`)); const loadingBlocker = await $('#kb-loading-blocker'); const loadingText = await loadingBlocker.getText(); expect(loadingText).toContain('Connecting to KBase services...'); From f6e3d09d4a8d8d7234b746f33760b291d30c62cc Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 21 Jan 2021 13:35:28 -0800 Subject: [PATCH 09/42] refactor test data to support case and env defaults --- .../specs/kbaseCellToolbarMenu_test.js | 77 +++++-------------- .../specs/kbaseNarrativeSidePublicTab_test.js | 43 ++++++----- test/integration/wdioUtils.js | 69 ++++++++++++++++- 3 files changed, 112 insertions(+), 77 deletions(-) diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index cb2c9443d6..6dd23fe2d5 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -2,7 +2,7 @@ /* eslint {strict: ['error', 'global']} */ 'use strict'; -const {login, openNarrative, clickWhenReady} = require('../wdioUtils.js'); +const {login, openNarrative, clickWhenReady, getCaseData} = require('../wdioUtils.js'); /* Notes: @@ -24,7 +24,7 @@ const testData = { unselectedBorder: '1px 1px 1px 5px solid rgb(204, 204, 204)', selectedBorder: '1px 1px 1px 5px solid rgb(75, 184, 86)', }, - all: { + cases: { TEST_CASE_1: { cellIndex: 1, title: 'Narrative Cell Toolbar Testing' @@ -47,76 +47,37 @@ const testData = { } }, ci: { + defaults: { + narrativeId: 58675 + }, TEST_CASE_1: { - narrativeId: 58675, }, TEST_CASE_2: { - narrativeId: 58675, }, TEST_CASE_3: { - narrativeId: 58675, }, TEST_CASE_4: { - narrativeId: 58675, }, TEST_CASE_5: { - narrativeId: 58675, } }, 'narrative-dev': { + defaults: { + narrativeId: 80970 + }, TEST_CASE_1: { - narrativeId: 80970, }, TEST_CASE_2: { - narrativeId: 80970, }, TEST_CASE_3: { - narrativeId: 80970, }, TEST_CASE_4: { - narrativeId: 80970, }, TEST_CASE_5: { - narrativeId: 80970, } } }; -const testCases = mergeObjects([testData[browser.config.testParams.ENV], testData.all]); - -function mergeObjects(listOfObjects) { - const simpleObjectPrototype = Object.getPrototypeOf({}); - - function isSimpleObject(obj) { - return Object.getPrototypeOf(obj) === simpleObjectPrototype; - } - - function merge(obj1, obj2, keyStack) { - Object.keys(obj2).forEach(function (key) { - const obj1Value = obj1[key]; - const obj2Value = obj2[key]; - const obj1Type = typeof obj1Value; - // var obj2Type = typeof obj2Value; - if (obj1Type === 'undefined') { - obj1[key] = obj2[key]; - } else if (isSimpleObject(obj1Value) && isSimpleObject(obj2Value)) { - keyStack.push(key); - merge(obj1Value, obj2Value, keyStack); - keyStack.pop(); - } else { - console.error('UNMERGABLE', obj1Type, obj1Value); - throw new Error('Unmergable at ' + keyStack.join('.') + ':' + key); - } - }); - } - - const base = JSON.parse(JSON.stringify(listOfObjects[0])); - for (let i = 1; i < listOfObjects.length; i += 1) { - merge(base, listOfObjects[i], []); - } - return base; -} - async function waitForCell(notebookContainer, cellIndex){ return await browser.waitUntil(async () => { const cell = await notebookContainer.$(`.cell:nth-child(${cellIndex})`); @@ -201,7 +162,7 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('moves a minimized selected cell down', async () => { - const testCase = testCases.TEST_CASE_1; + const testCase = getCaseData(testData, 'TEST_CASE_1'); const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); @@ -213,7 +174,7 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('moves a minimized unselected cell down', async () => { - const testCase = testCases.TEST_CASE_2; + const testCase = getCaseData(testData, 'TEST_CASE_2'); const narrativeContainer = await openNarrative(testCase.narrativeId); @@ -226,7 +187,7 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('moves a minimized unselected cell up', async () => { - const testCase = testCases.TEST_CASE_3; + const testCase = getCaseData(testData, 'TEST_CASE_3'); const narrativeContainer = await openNarrative(testCase.narrativeId); @@ -240,7 +201,7 @@ describe('Test kbaseCellToolbarMenu', () => { // select cell it('selects a minimized cell', async () => { - const testCase = testCases.TEST_CASE_4; + const testCase = getCaseData(testData, 'TEST_CASE_4'); const narrativeContainer = await openNarrative(testCase.narrativeId); await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); @@ -248,7 +209,7 @@ describe('Test kbaseCellToolbarMenu', () => { // select cell and move down it('selects a minimized cell and moves it down', async () => { - const testCase = testCases.TEST_CASE_4; + const testCase = getCaseData(testData, 'TEST_CASE_4'); const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); @@ -259,7 +220,7 @@ describe('Test kbaseCellToolbarMenu', () => { // select cell and move up it('selects a minimized cell and moves it up', async () => { - const testCase = testCases.TEST_CASE_4; + const testCase = getCaseData(testData, 'TEST_CASE_4'); const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); @@ -271,7 +232,7 @@ describe('Test kbaseCellToolbarMenu', () => { // Everything above, but cells are expanded. it('moves an expanded unselected cell down', async () => { - const testCase = testCases.TEST_CASE_5; + const testCase = getCaseData(testData, 'TEST_CASE_5'); const narrativeContainer = await openNarrative(testCase.narrativeId); @@ -284,7 +245,7 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('moves an expanded unselected cell up', async () => { - const testCase = testCases.TEST_CASE_5; + const testCase = getCaseData(testData, 'TEST_CASE_5'); const narrativeContainer = await openNarrative(testCase.narrativeId); @@ -297,7 +258,7 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('selects an expanded cell', async () => { - const testCase = testCases.TEST_CASE_5; + const testCase = getCaseData(testData, 'TEST_CASE_5'); const narrativeContainer = await openNarrative(testCase.narrativeId); await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); @@ -305,7 +266,7 @@ describe('Test kbaseCellToolbarMenu', () => { // select cell and move down it('selects an expanded cell and moves it down', async () => { - const testCase = testCases.TEST_CASE_5; + const testCase = getCaseData(testData, 'TEST_CASE_5'); const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); @@ -316,7 +277,7 @@ describe('Test kbaseCellToolbarMenu', () => { // select cell and move up it('selects an expanded cell and moves it up', async () => { - const testCase = testCases.TEST_CASE_5; + const testCase = getCaseData(testData, 'TEST_CASE_5'); const narrativeContainer = await openNarrative(testCase.narrativeId); const cell = await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); diff --git a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js index 802f4dc44b..0172f168a1 100644 --- a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js +++ b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js @@ -2,17 +2,26 @@ /* eslint {strict: ['error', 'global']} */ 'use strict'; -const {login, openNarrative, sendString, clickWhenReady} = require('../wdioUtils.js'); +const {login, openNarrative, sendString, clickWhenReady, getCaseData} = require('../wdioUtils.js'); // Ideally the test data should be the same, except for narrative id, in each env. // But currently CI and prod are indexed differently. // Note that the narrativeIds used below must be owned or shared with full rights (at least edit) with the narrativetest user. // Note that narrativetest is not yet set up in narrative-dev/prod. -const allTestCases = { +const testData = { + cases: { + TEST_CASE_1: {}, + TEST_CASE_2: {}, + TEST_CASE_3: {}, + TEST_CASE_4: {}, + TEST_CASE_5: {} + }, ci: { - TEST_CASE_1: { + defaults: { narrativeId: 53983, + }, + TEST_CASE_1: { row: 4, name: 'Acetobacter ascendens', metadata: [ @@ -44,7 +53,6 @@ const allTestCases = { ] }, TEST_CASE_2: { - narrativeId: 53983, row: 10, scrollTo: true, name: 'Acidaminococcus fermentans', @@ -77,7 +85,6 @@ const allTestCases = { ] }, TEST_CASE_3: { - narrativeId: 53983, row: 1, scrollTo: false, searchFor: 'prochlorococcus', @@ -112,12 +119,10 @@ const allTestCases = { ] }, TEST_CASE_4: { - narrativeId: 53983, searchFor: 'foobar', foundCount: 'None' }, TEST_CASE_5: { - narrativeId: 53983, row: 30, scrollTo: true, scrolls: [ @@ -154,8 +159,10 @@ const allTestCases = { } }, 'narrative-dev': { + defaults: { + narrativeId: 78050 + }, TEST_CASE_1: { - narrativeId: 78050, row: 3, name: 'Absiella sp. AM09-45', metadata: [ @@ -187,7 +194,6 @@ const allTestCases = { ] }, TEST_CASE_2: { - narrativeId: 78050, row: 10, scrollTo: true, name: 'Abyssicoccus albus', @@ -220,7 +226,6 @@ const allTestCases = { ] }, TEST_CASE_3: { - narrativeId: 78050, row: 1, scrollTo: false, searchFor: 'prochlorococcus', @@ -255,12 +260,10 @@ const allTestCases = { ] }, TEST_CASE_4: { - narrativeId: 78050, searchFor: 'foobar', foundCount: 'None' }, TEST_CASE_5: { - narrativeId: 78050, row: 30, scrollTo: true, scrolls: [ @@ -298,7 +301,10 @@ const allTestCases = { } }; -const testCases = allTestCases[browser.config.testParams.ENV]; +// const testCases = allTestCases[browser.config.testParams.ENV]; + +// const testCases = getConfig(testData, browser.config.testParams.ENV); + async function testField({container, id, label, value}) { const lineageLabel = await container.$(`[role="row"][data-test-id="${id}"] [data-test-id="label"]`); @@ -360,7 +366,7 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results', async () => { - const testCase = testCases.TEST_CASE_1; + const testCase = getCaseData(testData, 'TEST_CASE_1'); await openNarrative(testCase.narrativeId); @@ -386,7 +392,8 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { - const testCase = testCases.TEST_CASE_2; + const testCase = getCaseData(testData, 'TEST_CASE_2'); + await openNarrative(testCase.narrativeId); const publicPanel = await openPublicData(); @@ -411,7 +418,7 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, searches for a term, should find an expected row', async () => { - const testCase = testCases.TEST_CASE_3; + const testCase = getCaseData(testData, 'TEST_CASE_3'); await openNarrative(testCase.narrativeId); @@ -451,7 +458,7 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, searches for a term which should not be found', async () => { - const testCase = testCases.TEST_CASE_4; + const testCase = getCaseData(testData, 'TEST_CASE_4'); await openNarrative(testCase.narrativeId); @@ -479,7 +486,7 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { - const testCase = testCases.TEST_CASE_5; + const testCase = getCaseData(testData, 'TEST_CASE_5'); await openNarrative(testCase.narrativeId); diff --git a/test/integration/wdioUtils.js b/test/integration/wdioUtils.js index 1c07157d55..ef86eeabd4 100644 --- a/test/integration/wdioUtils.js +++ b/test/integration/wdioUtils.js @@ -115,10 +115,77 @@ async function openNarrative(workspaceId) { return container; } +function mergeObjects(listOfObjects) { + const simpleObjectPrototype = Object.getPrototypeOf({}); + + function isSimpleObject(obj) { + if (typeof obj !== 'object') { + return false; + } + return Object.getPrototypeOf(obj) === simpleObjectPrototype; + } + + function merge(targetObj, sourceObj) { + if (!isSimpleObject(targetObj)) { + throw new Error(`Can only merge simple objects, target is a "${typeof targetObj}"`); + } + + // Copy target, so we don't stomp over original objects. + // Note that the source object is not copied, since we don't care if + // there is object sharing in the result, we just want to ensure that + // we don't overwrite properties of shared objects. + targetObj = JSON.parse(JSON.stringify(targetObj)); + + Object.keys(sourceObj).forEach(function (key) { + if (isSimpleObject(targetObj[key]) && isSimpleObject(sourceObj[key])) { + targetObj[key] = merge(targetObj[key], sourceObj[key]); + } else { + targetObj[key] = sourceObj[key]; + } + }); + + return targetObj; + } + + const objectsToMerge = listOfObjects.map((obj, index) => { + if (!isSimpleObject(obj)) { + throw new Error(`Can only merge simple objects, object #${index} is a "${typeof obj}"`); + } else { + return JSON.parse(JSON.stringify(obj)); + } + }); + let merged = objectsToMerge[0]; + for (let i = 1; i < objectsToMerge.length; i += 1) { + merged = merge(merged, objectsToMerge[i]); + } + return merged; +} + +function getCaseData(testData, caseLabel) { + const env = browser.config.testParams.ENV; + + // Note, order is least specific to most specific, so that the more + // specific can override the least. + + // Top level test cases provide defaults (non-env-specific) per-case + // test data. + const testCase = testData.cases[caseLabel]; + + // Each env can establish defaults (e.g. narrative id) + const envDefaults = testData[env].defaults; + + // Each test case is defined per environment as well, as the + // state of services will be different. + const envTestCase = testData[env][caseLabel]; + + return mergeObjects([testCase, envDefaults, envTestCase]); +} + module.exports = { login, makeURL, sendString, openNarrative, - clickWhenReady + clickWhenReady, + getCaseData }; \ No newline at end of file From b63e27c5c21c35214862b4ecb13441a84407060d Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 21 Jan 2021 13:36:16 -0800 Subject: [PATCH 10/42] don't expose service key - could be handy to obscure in CI, but expose locally. --- test/integration/wdio.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/wdio.conf.js b/test/integration/wdio.conf.js index 8f7728a9f1..e8d330e617 100644 --- a/test/integration/wdio.conf.js +++ b/test/integration/wdio.conf.js @@ -277,7 +277,7 @@ console.log('OS VERSION : ' + testParams.OS_VERSION); console.log('HEADLESS : ' + testParams.HEADLESS); console.log('TEST SERVICE : ' + testParams.SERVICE); console.log('SERVICE USER : ' + testParams.SERVICE_USER); -console.log('SERVICE KEY : ' + testParams.SERVICE_KEY); +console.log('SERVICE KEY : ' + (testParams.SERVICE_KEY ? 'set but hidden' : '')); console.log('-----------------'); const wdioConfig = { From 953964314d7f9064febfb6ab8bf997041ca1a40f Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 21 Jan 2021 14:45:21 -0800 Subject: [PATCH 11/42] use null, not empty string --- test/integration/wdio.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/wdio.conf.js b/test/integration/wdio.conf.js index e8d330e617..a7cc60ad4b 100644 --- a/test/integration/wdio.conf.js +++ b/test/integration/wdio.conf.js @@ -277,7 +277,7 @@ console.log('OS VERSION : ' + testParams.OS_VERSION); console.log('HEADLESS : ' + testParams.HEADLESS); console.log('TEST SERVICE : ' + testParams.SERVICE); console.log('SERVICE USER : ' + testParams.SERVICE_USER); -console.log('SERVICE KEY : ' + (testParams.SERVICE_KEY ? 'set but hidden' : '')); +console.log('SERVICE KEY : ' + (testParams.SERVICE_KEY ? 'set but hidden' : null)); console.log('-----------------'); const wdioConfig = { From da586464f8f4bd71345e388fc65a26190b7cb43e Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Thu, 21 Jan 2021 16:48:41 -0800 Subject: [PATCH 12/42] move some test utils into new NarrativeTesting class (and file), to compartmentalize usage of test data. --- test/integration/NarrativeTesting.js | 217 ++++++++++++++++++ .../specs/kbaseCellToolbarMenu_test.js | 165 ++++--------- .../specs/kbaseNarrativeSidePublicTab_test.js | 72 +++--- test/integration/wdioUtils.js | 69 +----- 4 files changed, 306 insertions(+), 217 deletions(-) create mode 100644 test/integration/NarrativeTesting.js diff --git a/test/integration/NarrativeTesting.js b/test/integration/NarrativeTesting.js new file mode 100644 index 0000000000..c8786292c8 --- /dev/null +++ b/test/integration/NarrativeTesting.js @@ -0,0 +1,217 @@ +/* eslint strict: ["error", "global"] */ +/*global browser, $*/ +'use strict'; + +const {makeURL, login, sendString, clickWhenReady} = require('./wdioUtils'); + +function mergeObjects(listOfObjects) { + const simpleObjectPrototype = Object.getPrototypeOf({}); + + function isSimpleObject(obj) { + if (typeof obj !== 'object') { + return false; + } + return Object.getPrototypeOf(obj) === simpleObjectPrototype; + } + + function merge(targetObj, sourceObj) { + if (!isSimpleObject(targetObj)) { + throw new Error(`Can only merge simple objects, target is a "${typeof targetObj}"`); + } + + // Copy target, so we don't stomp over original objects. + // Note that the source object is not copied, since we don't care if + // there is object sharing in the result, we just want to ensure that + // we don't overwrite properties of shared objects. + targetObj = JSON.parse(JSON.stringify(targetObj)); + + Object.keys(sourceObj).forEach(function (key) { + if (isSimpleObject(targetObj[key]) && isSimpleObject(sourceObj[key])) { + targetObj[key] = merge(targetObj[key], sourceObj[key]); + } else { + targetObj[key] = sourceObj[key]; + } + }); + + return targetObj; + } + + const objectsToMerge = listOfObjects.map((obj, index) => { + if (!isSimpleObject(obj)) { + throw new Error(`Can only merge simple objects, object #${index} is a "${typeof obj}"`); + } else { + return JSON.parse(JSON.stringify(obj)); + } + }); + let merged = objectsToMerge[0]; + for (let i = 1; i < objectsToMerge.length; i += 1) { + merged = merge(merged, objectsToMerge[i]); + } + return merged; +} + +class NarrativeTesting { + constructor({testData, caseLabel, timeout}) { + this.testData = testData; + this.caseLabel = caseLabel; + this.timeout = timeout; + this.testCase = this.getCaseData(); + } + + getCaseData() { + if (this.caseData) { + return this.caseData; + } + const env = browser.config.testParams.ENV; + + // Note, order is least specific to most specific, so that the more + // specific can override the least. + + // Top level test cases provide defaults (non-env-specific) per-case + // test data. + const testCase = this.testData.cases[this.caseLabel]; + + // Each env can establish defaults (e.g. narrative id) + const envDefaults = this.testData[env].defaults; + + // Each test case is defined per environment as well, as the + // state of services will be different. + const envTestCase = this.testData[env][this.caseLabel]; + + return mergeObjects([testCase, envDefaults, envTestCase]); + } + + /** + * Navigates the wdio browser to a workspace as given by its id, and waits until the + * narrative container is visible. + * @arg {number} The narrative's workspace id + * @returns {Promise} The Promise value is ignored. + */ + async openNarrative(workspaceId, timeoutOverride) { + + // Go to the narrative! + const timeout = timeoutOverride || this.timeout; + await browser.url(makeURL(`narrative/${workspaceId}`)); + + // should experience loading blocker for a few seconds. + const loadingBlocker = await $('#kb-loading-blocker'); + await loadingBlocker.waitForDisplayed({ + timeout, + timeoutMsg: `Timeout after waiting ${timeout}ms for loading blocker to appear` + }); + + // And then the loading blocker should disappear! + await loadingBlocker.waitForDisplayed({ + timeout, + timeoutMsg: `Timeout after waiting ${timeout}ms for loading blocker to disappear`, + reverse: true + }); + + // Ensure logged in + const loginButton = await $('#signin-button > div > button'); + await loginButton.waitForDisplayed({ + timeout, + timeoutMsg: `Timeout after waiting ${timeout}ms for login button to appear` + }); + + await clickWhenReady(loginButton); + + const realnameElement = await $('[data-element="realname"]'); + const usernameElement = await $('[data-element="username"]'); + await browser.waitUntil(async () => { + const text = await realnameElement.getText(); + return (text && text.length > 0); + }); + const realname = await realnameElement.getText(); + const username = await usernameElement.getText(); + console.warn(`Signed in as user "${realname}" (${username})`); + await loginButton.click(); + + // Ensure narrative notebook has displayed + // TODO: more interesting waitUntil loop to signal the + // failure reason (useful for debugging tests?) + const container = await $('#notebook-container'); + await container.waitForDisplayed({ + timeout, + timeoutMsg: `Timeout after waiting ${timeout}ms for narrative to appear` + }); + return container; + } + + async waitForCell(notebookContainer, cellIndex){ + return await browser.waitUntil(async () => { + const cell = await notebookContainer.$(`.cell:nth-child(${cellIndex})`); + return cell; + }); + } + + async selectCell(container, cellIndex, title) { + const cell = await this.waitForCellWithTitle(container, cellIndex, title); + + // Make sure not selected. + // We do this by inspecting the border. + await browser.waitUntil(async () => { + const borderStyle = await cell.getCSSProperty('border'); + return borderStyle.value === this.testData.common.unselectedBorder; + }); + + // Click on title area to select cell. + const titleArea = await cell.$('.title-container'); + await clickWhenReady(titleArea); + + await browser.waitUntil(async () => { + const borderStyle = await cell.getCSSProperty('border'); + return borderStyle.value === this.testData.common.selectedBorder; + }); + + return cell; + } + + async waitForCellWithText(container, cellIndex, selector, text) { + const cell = await this.waitForCell(container, cellIndex); + await browser.waitUntil(async () => { + const element = await cell.$(selector); + return text == await element.getText(); + }); + return cell; + } + + async waitForCellWithTitle(container, cellIndex, titleText) { + return await this.waitForCellWithText(container, cellIndex, '[data-element="title"]', titleText); + } + + async waitForCellWithBody(container, cellIndex, bodyText) { + return await this.waitForCellWithText(container, cellIndex, '.text_cell_render.rendered_html', bodyText); + } + + async selectCellWithText(container, cellIndex, selector, text) { + const cell = await this.waitForCellWithText(container, cellIndex, selector, text); + + await browser.waitUntil(async () => { + const borderStyle = await cell.getCSSProperty('border'); + return borderStyle.value === this.testData.common.unselectedBorder; + }); + + const bodyArea = await cell.$(selector); + await clickWhenReady(bodyArea); + + await browser.waitUntil(async () => { + const borderStyle = await cell.getCSSProperty('border'); + return borderStyle.value === this.testData.common.selectedBorder; + }); + + return cell; + } + + async selectCellWithBody(container, cellIndex, body) { + return await this.selectCellWithText(container, cellIndex, '.text_cell_render.rendered_html', body); + } +} + +module.exports = { + login, + makeURL, + sendString, + clickWhenReady, + NarrativeTesting +}; \ No newline at end of file diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index 6dd23fe2d5..d2eeb1011f 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -2,7 +2,14 @@ /* eslint {strict: ['error', 'global']} */ 'use strict'; -const {login, openNarrative, clickWhenReady, getCaseData} = require('../wdioUtils.js'); +// const { +// login, openNarrative, clickWhenReady, getCaseData, +// waitForCellWithTitle, selectCell, waitForCellWithBody, +// } = require('../wdioUtils.js'); + +const { NarrativeTesting } = require('../NarrativeTesting.js'); +const { login, clickWhenReady } = require('../wdioUtils.js'); + /* Notes: @@ -78,77 +85,7 @@ const testData = { } }; -async function waitForCell(notebookContainer, cellIndex){ - return await browser.waitUntil(async () => { - const cell = await notebookContainer.$(`.cell:nth-child(${cellIndex})`); - return cell; - }); -} - -async function waitForCellWithTitle(container, cellIndex, title) { - const cell = await waitForCell(container, cellIndex); - await browser.waitUntil(async () => { - const titleElement = await cell.$('[data-element="title"]'); - const text = await titleElement.getText(); - return text === title; - }); - return cell; -} - -async function waitForCellWithBody(container, cellIndex, bodyText) { - const cell = await waitForCell(container, cellIndex); - await browser.waitUntil(async () => { - const element = await cell.$('.text_cell_render.rendered_html'); - const text = await element.getText(); - return text === bodyText; - }); - return cell; -} - -async function selectCell(container, cellIndex, title) { - const cell = await waitForCellWithTitle(container, cellIndex, title); - - // Make sure not selected. - // We do this by inspecting the border. - await browser.waitUntil(async () => { - const borderStyle = await cell.getCSSProperty('border'); - return borderStyle.value === testData.common.unselectedBorder; - }); - - // Click on title area to select cell. - const titleArea = await cell.$('.title-container'); - await clickWhenReady(titleArea); - - await browser.waitUntil(async () => { - const borderStyle = await cell.getCSSProperty('border'); - return borderStyle.value === testData.common.selectedBorder; - }); - - return cell; -} - -async function selectCellWithBody(container, cellIndex, body) { - const cell = await waitForCellWithBody(container, cellIndex, body); - - // Make sure not selected. - // We do this by inspecting the border. - await browser.waitUntil(async () => { - const borderStyle = await cell.getCSSProperty('border'); - return borderStyle.value === testData.common.unselectedBorder; - }); - - - // Click on title area to select cell. - const bodyArea = await cell.$('.text_cell_render.rendered_html'); - await clickWhenReady(bodyArea); - - await browser.waitUntil(async () => { - const borderStyle = await cell.getCSSProperty('border'); - return borderStyle.value === testData.common.selectedBorder; - }); - - return cell; -} +const TIMEOUT = 60000; describe('Test kbaseCellToolbarMenu', () => { beforeEach(async () => { @@ -162,127 +99,127 @@ describe('Test kbaseCellToolbarMenu', () => { }); it('moves a minimized selected cell down', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_1'); - const narrativeContainer = await openNarrative(testCase.narrativeId); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_1'}); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); + const cell = await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex, t.testCase.title); // Find and click the move-down button const downButton = await cell.$('[data-test="cell-move-down"]'); await clickWhenReady(downButton); - await waitForCellWithTitle(narrativeContainer, testCase.cellIndex + 1, testCase.title); + await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.title); }); it('moves a minimized unselected cell down', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_2'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_2'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); + const cell = await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex, t.testCase.title); // Find and click the move-down button const downButton = await cell.$('[data-test="cell-move-down"]'); await clickWhenReady(downButton); - await waitForCellWithTitle(narrativeContainer, testCase.cellIndex + 1, testCase.title); + await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.title); }); it('moves a minimized unselected cell up', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_3'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_3'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - const cell = await waitForCellWithTitle(narrativeContainer, testCase.cellIndex, testCase.title); + const cell = await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex, t.testCase.title); // Find and click the move-ups button const upButton = await cell.$('[data-test="cell-move-up"]'); await clickWhenReady(upButton); - await waitForCellWithTitle(narrativeContainer, testCase.cellIndex - 1, testCase.title); + await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex - 1, t.testCase.title); }); // select cell it('selects a minimized cell', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_4'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_4'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); - await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + await t.selectCell(narrativeContainer, t.testCase.cellIndex, t.testCase.title); }); // select cell and move down it('selects a minimized cell and moves it down', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_4'); + const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel: 'TEST_CASE_4'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); - const cell = await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + const cell = await t.selectCell(narrativeContainer, t.testCase.cellIndex, t.testCase.title); const downButton = await cell.$('[data-test="cell-move-down"]'); await clickWhenReady(downButton); - await waitForCellWithTitle(narrativeContainer, testCase.cellIndex + 1, testCase.title); + await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.title); }); // select cell and move up it('selects a minimized cell and moves it up', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_4'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_4'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); - const cell = await selectCell(narrativeContainer, testCase.cellIndex, testCase.title); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + const cell = await t.selectCell(narrativeContainer, t.testCase.cellIndex, t.testCase.title); const upButton = await cell.$('[data-test="cell-move-up"]'); await clickWhenReady(upButton); - await waitForCellWithTitle(narrativeContainer, testCase.cellIndex - 1, testCase.title); + await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex - 1, t.testCase.title); }); // Everything above, but cells are expanded. it('moves an expanded unselected cell down', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_5'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - const cell = await waitForCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + const cell = await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); // Find and click the move-down button const downButton = await cell.$('[data-test="cell-move-down"]'); await clickWhenReady(downButton); - await waitForCellWithBody(narrativeContainer, testCase.cellIndex + 1, testCase.body); + await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.body); }); it('moves an expanded unselected cell up', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_5'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - const cell = await waitForCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + const cell = await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); // Find and click the move-down button const button = await cell.$('[data-test="cell-move-up"]'); await clickWhenReady(button); - await waitForCellWithBody(narrativeContainer, testCase.cellIndex - 1, testCase.body); + await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex - 1, t.testCase.body); }); it('selects an expanded cell', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_5'); + const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel: 'TEST_CASE_5'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); - await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + await t.selectCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); }); // select cell and move down it('selects an expanded cell and moves it down', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_5'); + const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel: 'TEST_CASE_5'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); - const cell = await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + const cell = await t.selectCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); const downButton = await cell.$('[data-test="cell-move-down"]'); await clickWhenReady(downButton); - await waitForCellWithBody(narrativeContainer, testCase.cellIndex + 1, testCase.body); + await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.body); }); // select cell and move up it('selects an expanded cell and moves it up', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_5'); + const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel: 'TEST_CASE_5'}); - const narrativeContainer = await openNarrative(testCase.narrativeId); - const cell = await selectCellWithBody(narrativeContainer, testCase.cellIndex, testCase.body); + const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + const cell = await t.selectCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); const upButton = await cell.$('[data-test="cell-move-up"]'); await clickWhenReady(upButton); - await waitForCellWithBody(narrativeContainer, testCase.cellIndex - 1, testCase.body); + await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex - 1, t.testCase.body); }); }); diff --git a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js index 0172f168a1..5fdd51943d 100644 --- a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js +++ b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js @@ -2,7 +2,9 @@ /* eslint {strict: ['error', 'global']} */ 'use strict'; -const {login, openNarrative, sendString, clickWhenReady, getCaseData} = require('../wdioUtils.js'); +const {login, openNarrative, sendString, clickWhenReady} = require('../wdioUtils.js'); +const { NarrativeTesting } = require('../NarrativeTesting.js'); + // Ideally the test data should be the same, except for narrative id, in each env. // But currently CI and prod are indexed differently. @@ -366,22 +368,22 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_1'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_1'}); - await openNarrative(testCase.narrativeId); + await openNarrative(t.testCase.narrativeId); const publicPanel = await openPublicData(); - const rows = await waitForRows(publicPanel, testCase.row); + const rows = await waitForRows(publicPanel, t.testCase.row); - expect(rows.length).toBeGreaterThanOrEqual(testCase.row); - const row = rows[testCase.row - 1]; + expect(rows.length).toBeGreaterThanOrEqual(t.testCase.row); + const row = rows[t.testCase.row - 1]; expect(row).toBeDefined(); const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(testCase.name); + expect(nameCell).toHaveText(t.testCase.name); // Confirm the metadata fields. - for (const {id, label, value} of testCase.metadata) { + for (const {id, label, value} of t.testCase.metadata) { await testField({ container: row, id, @@ -392,22 +394,22 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_2'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_2'}); - await openNarrative(testCase.narrativeId); + await openNarrative(t.testCase.narrativeId); const publicPanel = await openPublicData(); - const rows = await waitForRows(publicPanel, testCase.row); + const rows = await waitForRows(publicPanel, t.testCase.row); // Look at the row - it should already be in view. - const row = rows[testCase.row - 1]; + const row = rows[t.testCase.row - 1]; await row.scrollIntoView(); const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(testCase.name); + expect(nameCell).toHaveText(t.testCase.name); // Confirm the metadata fields. - for (const {id, label, value} of testCase.metadata) { + for (const {id, label, value} of t.testCase.metadata) { await testField({ container: row, id, @@ -418,36 +420,36 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, searches for a term, should find an expected row', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_3'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_3'}); - await openNarrative(testCase.narrativeId); + await openNarrative(t.testCase.narrativeId); const publicPanel = await openPublicData(); // Select search input and input a search term const searchInput = await publicPanel.$('[data-test-id="search-input"]'); await clickWhenReady(searchInput); - await sendString(testCase.searchFor); + await sendString(t.testCase.searchFor); await browser.keys('Enter'); const foundCount = await publicPanel.$('[data-test-id="found-count"]'); - expect(foundCount).toHaveText(testCase.foundCount); + expect(foundCount).toHaveText(t.testCase.foundCount); // get rows // When using roles, we sometimes need to be very specific in our queries. // Maybe roles are not suitable for integration tests, then. - const rows = await waitForRows(publicPanel, testCase.row); + const rows = await waitForRows(publicPanel, t.testCase.row); - expect(rows.length).toBeGreaterThanOrEqual(testCase.row); + expect(rows.length).toBeGreaterThanOrEqual(t.testCase.row); // Look at the row - it should already be in view. - const row = rows[testCase.row - 1]; + const row = rows[t.testCase.row - 1]; await row.scrollIntoView(); const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(testCase.name); + expect(nameCell).toHaveText(t.testCase.name); // Confirm the metadata fields. - for (const {id, label, value} of testCase.metadata) { + for (const {id, label, value} of t.testCase.metadata) { await testField({ container: row, id, @@ -458,16 +460,16 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, searches for a term which should not be found', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_4'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_4'}); - await openNarrative(testCase.narrativeId); + await openNarrative(t.testCase.narrativeId); const publicPanel = await openPublicData(); // Select search input and input a search term const searchInput = await publicPanel.$('[data-test-id="search-input"]'); await clickWhenReady(searchInput); - await sendString(testCase.searchFor); + await sendString(t.testCase.searchFor); await browser.keys('Enter'); await browser.waitUntil(async () => { @@ -475,20 +477,20 @@ describe('Test kbaseNarrativeSidePublicTab', () => { if (await foundCountElement.isDisplayed()) { const text = await foundCountElement.getText(); - return text === testCase.foundCount; + return text === t.testCase.foundCount; } else { return false; } }); const foundCount = await publicPanel.$('[data-test-id="found-count"]'); - expect(foundCount).toHaveText(testCase.foundCount); + expect(foundCount).toHaveText(t.testCase.foundCount); }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { - const testCase = getCaseData(testData, 'TEST_CASE_5'); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5'}); - await openNarrative(testCase.narrativeId); + await openNarrative(t.testCase.narrativeId); // Open the data slideout const publicPanel = await openPublicData(); @@ -496,21 +498,21 @@ describe('Test kbaseNarrativeSidePublicTab', () => { // get rows // When using roles, we sometimes need to be very specific in our queries. // Maybe roles are not suitable for integration tests, then. - for (const scrollRow of testCase.scrolls) { + for (const scrollRow of t.testCase.scrolls) { const rowElements = await waitForRows(publicPanel, scrollRow); const rowElement = rowElements[scrollRow - 1]; await rowElement.scrollIntoView(); } // ensure we have all of the rows. - const rows = await waitForRows(publicPanel, testCase.row); - const row = rows[testCase.row - 1]; + const rows = await waitForRows(publicPanel, t.testCase.row); + const row = rows[t.testCase.row - 1]; await row.scrollIntoView(); const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(testCase.name); + expect(nameCell).toHaveText(t.testCase.name); // Confirm the metadata fields. - for (const {id, label, value} of testCase.metadata) { + for (const {id, label, value} of t.testCase.metadata) { await testField({ container: row, id, diff --git a/test/integration/wdioUtils.js b/test/integration/wdioUtils.js index ef86eeabd4..1c07157d55 100644 --- a/test/integration/wdioUtils.js +++ b/test/integration/wdioUtils.js @@ -115,77 +115,10 @@ async function openNarrative(workspaceId) { return container; } -function mergeObjects(listOfObjects) { - const simpleObjectPrototype = Object.getPrototypeOf({}); - - function isSimpleObject(obj) { - if (typeof obj !== 'object') { - return false; - } - return Object.getPrototypeOf(obj) === simpleObjectPrototype; - } - - function merge(targetObj, sourceObj) { - if (!isSimpleObject(targetObj)) { - throw new Error(`Can only merge simple objects, target is a "${typeof targetObj}"`); - } - - // Copy target, so we don't stomp over original objects. - // Note that the source object is not copied, since we don't care if - // there is object sharing in the result, we just want to ensure that - // we don't overwrite properties of shared objects. - targetObj = JSON.parse(JSON.stringify(targetObj)); - - Object.keys(sourceObj).forEach(function (key) { - if (isSimpleObject(targetObj[key]) && isSimpleObject(sourceObj[key])) { - targetObj[key] = merge(targetObj[key], sourceObj[key]); - } else { - targetObj[key] = sourceObj[key]; - } - }); - - return targetObj; - } - - const objectsToMerge = listOfObjects.map((obj, index) => { - if (!isSimpleObject(obj)) { - throw new Error(`Can only merge simple objects, object #${index} is a "${typeof obj}"`); - } else { - return JSON.parse(JSON.stringify(obj)); - } - }); - let merged = objectsToMerge[0]; - for (let i = 1; i < objectsToMerge.length; i += 1) { - merged = merge(merged, objectsToMerge[i]); - } - return merged; -} - -function getCaseData(testData, caseLabel) { - const env = browser.config.testParams.ENV; - - // Note, order is least specific to most specific, so that the more - // specific can override the least. - - // Top level test cases provide defaults (non-env-specific) per-case - // test data. - const testCase = testData.cases[caseLabel]; - - // Each env can establish defaults (e.g. narrative id) - const envDefaults = testData[env].defaults; - - // Each test case is defined per environment as well, as the - // state of services will be different. - const envTestCase = testData[env][caseLabel]; - - return mergeObjects([testCase, envDefaults, envTestCase]); -} - module.exports = { login, makeURL, sendString, openNarrative, - clickWhenReady, - getCaseData + clickWhenReady }; \ No newline at end of file From 25ef6fe41bf4c2f2a47dc6da347c4c2b8d642db5 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Fri, 22 Jan 2021 10:01:44 -0800 Subject: [PATCH 13/42] refactor integration tests - improve NarrativeTesting tools - add range function to wdio utils - public tab adjust to NarrativeTesting chagnes - rarrange tests to run through single cell movement function, with rearranged test data. --- test/integration/NarrativeTesting.js | 51 +-- .../specs/kbaseCellToolbarMenu_test.js | 369 ++++++++++++------ .../specs/kbaseNarrativeSidePublicTab_test.js | 63 ++- test/integration/wdioUtils.js | 11 +- 4 files changed, 294 insertions(+), 200 deletions(-) diff --git a/test/integration/NarrativeTesting.js b/test/integration/NarrativeTesting.js index c8786292c8..16b620c077 100644 --- a/test/integration/NarrativeTesting.js +++ b/test/integration/NarrativeTesting.js @@ -15,10 +15,6 @@ function mergeObjects(listOfObjects) { } function merge(targetObj, sourceObj) { - if (!isSimpleObject(targetObj)) { - throw new Error(`Can only merge simple objects, target is a "${typeof targetObj}"`); - } - // Copy target, so we don't stomp over original objects. // Note that the source object is not copied, since we don't care if // there is object sharing in the result, we just want to ensure that @@ -37,6 +33,9 @@ function mergeObjects(listOfObjects) { } const objectsToMerge = listOfObjects.map((obj, index) => { + if (typeof obj === 'undefined') { + return {}; + } if (!isSimpleObject(obj)) { throw new Error(`Can only merge simple objects, object #${index} is a "${typeof obj}"`); } else { @@ -55,7 +54,7 @@ class NarrativeTesting { this.testData = testData; this.caseLabel = caseLabel; this.timeout = timeout; - this.testCase = this.getCaseData(); + this.caseData = this.getCaseData(); } getCaseData() { @@ -69,16 +68,16 @@ class NarrativeTesting { // Top level test cases provide defaults (non-env-specific) per-case // test data. - const testCase = this.testData.cases[this.caseLabel]; + const caseData = this.testData.cases[this.caseLabel]; // Each env can establish defaults (e.g. narrative id) const envDefaults = this.testData[env].defaults; // Each test case is defined per environment as well, as the // state of services will be different. - const envTestCase = this.testData[env][this.caseLabel]; + const envcaseData = this.testData[env][this.caseLabel]; - return mergeObjects([testCase, envDefaults, envTestCase]); + return mergeObjects([caseData, envDefaults, envcaseData]); } /** @@ -145,9 +144,7 @@ class NarrativeTesting { }); } - async selectCell(container, cellIndex, title) { - const cell = await this.waitForCellWithTitle(container, cellIndex, title); - + async selectCell(cell) { // Make sure not selected. // We do this by inspecting the border. await browser.waitUntil(async () => { @@ -168,12 +165,13 @@ class NarrativeTesting { } async waitForCellWithText(container, cellIndex, selector, text) { - const cell = await this.waitForCell(container, cellIndex); await browser.waitUntil(async () => { + const cell = await this.waitForCell(container, cellIndex); const element = await cell.$(selector); - return text == await element.getText(); + const cellText = await element.getText(); + return text === cellText; }); - return cell; + return await this.waitForCell(container, cellIndex); } async waitForCellWithTitle(container, cellIndex, titleText) { @@ -183,29 +181,6 @@ class NarrativeTesting { async waitForCellWithBody(container, cellIndex, bodyText) { return await this.waitForCellWithText(container, cellIndex, '.text_cell_render.rendered_html', bodyText); } - - async selectCellWithText(container, cellIndex, selector, text) { - const cell = await this.waitForCellWithText(container, cellIndex, selector, text); - - await browser.waitUntil(async () => { - const borderStyle = await cell.getCSSProperty('border'); - return borderStyle.value === this.testData.common.unselectedBorder; - }); - - const bodyArea = await cell.$(selector); - await clickWhenReady(bodyArea); - - await browser.waitUntil(async () => { - const borderStyle = await cell.getCSSProperty('border'); - return borderStyle.value === this.testData.common.selectedBorder; - }); - - return cell; - } - - async selectCellWithBody(container, cellIndex, body) { - return await this.selectCellWithText(container, cellIndex, '.text_cell_render.rendered_html', body); - } } module.exports = { @@ -214,4 +189,4 @@ module.exports = { sendString, clickWhenReady, NarrativeTesting -}; \ No newline at end of file +}; diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index d2eeb1011f..9c73314b93 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -2,27 +2,20 @@ /* eslint {strict: ['error', 'global']} */ 'use strict'; -// const { -// login, openNarrative, clickWhenReady, getCaseData, -// waitForCellWithTitle, selectCell, waitForCellWithBody, -// } = require('../wdioUtils.js'); - const { NarrativeTesting } = require('../NarrativeTesting.js'); const { login, clickWhenReady } = require('../wdioUtils.js'); - /* Notes: The test narrative has 5 markdown cells. The first cell has summary text, the remaining 4 contain the text "Cell #". The first three cells are collapsed, the last two are expanded. -Tests currently cover common cases of cell movement; additional cases can be added, e.g. try to move -past the end, or before the beginning, try moving the same cell multiple times, inspect the state -of all cells after a movement. +Tests currently cover moving cells up and down, in both selected and unselected state, and ensuring that the moved +cell is in the expected position. -This test suite could be expanded to cover all usage of the cell toolbar (kbaseCellToolbarMenu.js), or they -could be in separate files. +TODO: This test suite could be expanded to cover all usage of the cell toolbar (kbaseCellToolbarMenu.js), or such +test cases can be could be in separate files. */ @@ -30,64 +23,149 @@ const testData = { common: { unselectedBorder: '1px 1px 1px 5px solid rgb(204, 204, 204)', selectedBorder: '1px 1px 1px 5px solid rgb(75, 184, 86)', + cells: [ + {title: 'Narrative Cell Toolbar Testing'}, + {title: 'Cell 1'}, + {title: 'Cell 2'}, + {body: 'Cell 3'}, + {body: 'Cell 4'} + ] }, cases: { TEST_CASE_1: { cellIndex: 1, - title: 'Narrative Cell Toolbar Testing' + title: 'Narrative Cell Toolbar Testing', + expect: { + afterMove: { + up: { + cellOrder: [1, 2, 3, 4, 5] + }, + down: { + cellOrder: [2, 1, 3, 4, 5] + } + } + } }, TEST_CASE_2: { cellIndex: 2, - title: 'Cell 1' + title: 'Cell 1', + expect: { + afterMove: { + up: { + cellOrder: [2, 1, 3, 4, 5] + }, + down: { + cellOrder: [1, 3, 2, 4, 5] + } + } + } }, TEST_CASE_3: { cellIndex: 3, - title: 'Cell 2' + title: 'Cell 2', + expect: { + afterMove: { + up: { + cellOrder: [1, 3, 2, 4, 5] + }, + down: { + cellOrder: [1, 2, 4, 3, 5] + } + } + } }, TEST_CASE_4: { - cellIndex: 3, - title: 'Cell 2' + cellIndex: 4, + body: 'Cell 3', + expect: { + afterMove: { + up: { + cellOrder: [1, 2, 4, 3, 5] + }, + down: { + cellOrder: [1, 2, 3, 5, 4] + } + } + } }, TEST_CASE_5: { - cellIndex: 4, - body: 'Cell 3' + cellIndex: 5, + body: 'Cell 4', + expect: { + afterMove: { + up: { + cellOrder: [1, 2, 3, 5, 4] + }, + down: { + cellOrder: [1, 2, 3, 4, 5] + } + } + } } }, ci: { defaults: { narrativeId: 58675 - }, - TEST_CASE_1: { - }, - TEST_CASE_2: { - }, - TEST_CASE_3: { - }, - TEST_CASE_4: { - }, - TEST_CASE_5: { } }, 'narrative-dev': { defaults: { narrativeId: 80970 - }, - TEST_CASE_1: { - }, - TEST_CASE_2: { - }, - TEST_CASE_3: { - }, - TEST_CASE_4: { - }, - TEST_CASE_5: { } } }; const TIMEOUT = 60000; -describe('Test kbaseCellToolbarMenu', () => { +async function testCellMovement({caseLabel, selectCell, direction}) { + const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel}); + const cellIndex = t.caseData.cellIndex; + const cells = t.testData.common.cells; + const narrativeContainer = await t.openNarrative(t.caseData.narrativeId); + + function waitForExpectedCell(targetCellIndex, expectedCell) { + if (expectedCell.title) { + return t.waitForCellWithTitle(narrativeContainer, targetCellIndex, expectedCell.title); + } else if (expectedCell.body) { + return t.waitForCellWithBody(narrativeContainer, targetCellIndex, expectedCell.body); + } else { + throw new Error('Either title or body must be specified for a cell movement test'); + } + } + + // Select a cell by title or body text. + // Each test case targets a cell for movement, and this step ensures + // that we start with the right one. + const cell = await waitForExpectedCell(cellIndex, t.caseData); + + // Optionally select the cell. + // Since the bug which triggered this set of tests was for movement + // of unselected cells, we want to ensure that we can test for cell + // movement of both selected and unselected cells. + if (selectCell) { + await t.selectCell(cell); + } + + // Click the appropriate cell movement button. + const button = await cell.$(`[data-test="cell-move-${direction}"]`); + await clickWhenReady(button); + + // Loop through all of the cells in the test Narrative, ensuring that they + // are in the expected order. + // This relies on the "cellOrder" array, which contains expected ordering + // of cells, where each cell is identified by it's original cell position. + const cellOrder = t.caseData.expect.afterMove[direction].cellOrder; + await Promise.all(cellOrder.map((originalCellIndex, index) => { + const actualCellIndex = index + 1; + // Get the expected title or body for the cell at that position, based + // on the master list of starting cells. + const expected = cells[originalCellIndex - 1]; + + return waitForExpectedCell(actualCellIndex, expected); + })); +} + +describe('Test kbaseCellToolbarMenu movement buttons', () => { beforeEach(async () => { await browser.setTimeout({ 'implicit': 30000 }); await browser.reloadSession(); @@ -98,128 +176,165 @@ describe('Test kbaseCellToolbarMenu', () => { await browser.deleteCookies(); }); - it('moves a minimized selected cell down', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_1'}); - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - - const cell = await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex, t.testCase.title); + // Move first cell - // Find and click the move-down button - const downButton = await cell.$('[data-test="cell-move-down"]'); - await clickWhenReady(downButton); - await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.title); + it('moves a minimized selected first cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_1', + direction: 'up', + selectCell: false + }); }); - it('moves a minimized unselected cell down', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_2'}); - - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + it('moves a minimized selected first cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_1', + direction: 'down', + selectCell: false + }); + }); - const cell = await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex, t.testCase.title); + // Move second cell, a regular minimized cell. - // Find and click the move-down button - const downButton = await cell.$('[data-test="cell-move-down"]'); - await clickWhenReady(downButton); - await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.title); + it('moves a minimized selected second cell up', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_2', + direction: 'up', + selectCell: false + }); }); - it('moves a minimized unselected cell up', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_3'}); - - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + it('moves a minimized selected second cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_2', + direction: 'down', + selectCell: false + }); + }); - const cell = await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex, t.testCase.title); + // ... so select it and try again - // Find and click the move-ups button - const upButton = await cell.$('[data-test="cell-move-up"]'); - await clickWhenReady(upButton); - await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex - 1, t.testCase.title); + it('selects and moves a minimized selected second cell up', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_2', + direction: 'up', + selectCell: true + }); }); - // select cell - it('selects a minimized cell', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_4'}); - - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - await t.selectCell(narrativeContainer, t.testCase.cellIndex, t.testCase.title); + it('selects and moves a minimized selected second cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_2', + direction: 'down', + selectCell: true + }); }); - // select cell and move down - it('selects a minimized cell and moves it down', async () => { - const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel: 'TEST_CASE_4'}); + // Third cell is minimized. - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - const cell = await t.selectCell(narrativeContainer, t.testCase.cellIndex, t.testCase.title); - const downButton = await cell.$('[data-test="cell-move-down"]'); - await clickWhenReady(downButton); - await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.title); + it('moves a minimized selected second cell up', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_3', + direction: 'up', + selectCell: false + }); }); - // select cell and move up - it('selects a minimized cell and moves it up', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_4'}); - - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - const cell = await t.selectCell(narrativeContainer, t.testCase.cellIndex, t.testCase.title); - const upButton = await cell.$('[data-test="cell-move-up"]'); - await clickWhenReady(upButton); - await t.waitForCellWithTitle(narrativeContainer, t.testCase.cellIndex - 1, t.testCase.title); + it('moves a minimized selected second cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_3', + direction: 'down', + selectCell: false + }); }); - // Everything above, but cells are expanded. + // ... so select it and try again. - it('moves an expanded unselected cell down', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5'}); + it('moves a minimized selected second cell up', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_3', + direction: 'up', + selectCell: true + }); + }); - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + it('moves a minimized selected second cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_3', + direction: 'down', + selectCell: true + }); + }); - const cell = await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); + // Fourth cell is expanded - // Find and click the move-down button - const downButton = await cell.$('[data-test="cell-move-down"]'); - await clickWhenReady(downButton); - await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.body); + it('moves an expanded selected fourth cell up', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_4', + direction: 'up', + selectCell: false + }); }); - it('moves an expanded unselected cell up', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5'}); + it('moves an expanded unselected fourth cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_4', + direction: 'down', + selectCell: false + }); + }); - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); + // ... so select it and try again. - const cell = await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); + it('selects and moves an expanded unselected second cell up', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_4', + direction: 'up', + selectCell: true + }); + }); - // Find and click the move-down button - const button = await cell.$('[data-test="cell-move-up"]'); - await clickWhenReady(button); - await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex - 1, t.testCase.body); + it('selects and moves an expanded selected second cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_4', + direction: 'down', + selectCell: true + }); }); - it('selects an expanded cell', async () => { - const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel: 'TEST_CASE_5'}); + // Fifth cell is expanded - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - await t.selectCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); + it('moves an expanded selected fourth cell up', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_5', + direction: 'up', + selectCell: false + }); }); - // select cell and move down - it('selects an expanded cell and moves it down', async () => { - const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel: 'TEST_CASE_5'}); - - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - const cell = await t.selectCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); - const downButton = await cell.$('[data-test="cell-move-down"]'); - await clickWhenReady(downButton); - await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex + 1, t.testCase.body); + it('moves an expanded selected fourth cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_5', + direction: 'down', + selectCell: false + }); }); - // select cell and move up - it('selects an expanded cell and moves it up', async () => { - const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel: 'TEST_CASE_5'}); + // ... so select it and try again. + + it('selects and moves an expanded last cell up', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_5', + direction: 'up', + selectCell: true + }); + }); - const narrativeContainer = await t.openNarrative(t.testCase.narrativeId); - const cell = await t.selectCellWithBody(narrativeContainer, t.testCase.cellIndex, t.testCase.body); - const upButton = await cell.$('[data-test="cell-move-up"]'); - await clickWhenReady(upButton); - await t.waitForCellWithBody(narrativeContainer, t.testCase.cellIndex - 1, t.testCase.body); + it('selects and moves an expanded last cell down', async () => { + await testCellMovement({ + caseLabel: 'TEST_CASE_5', + direction: 'down', + selectCell: true + }); }); }); diff --git a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js index 5fdd51943d..86f60fee8d 100644 --- a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js +++ b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js @@ -303,11 +303,6 @@ const testData = { } }; -// const testCases = allTestCases[browser.config.testParams.ENV]; - -// const testCases = getConfig(testData, browser.config.testParams.ENV); - - async function testField({container, id, label, value}) { const lineageLabel = await container.$(`[role="row"][data-test-id="${id}"] [data-test-id="label"]`); expect(lineageLabel).toHaveText(label); @@ -370,20 +365,20 @@ describe('Test kbaseNarrativeSidePublicTab', () => { it('opens the public data search tab, should show default results', async () => { const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_1'}); - await openNarrative(t.testCase.narrativeId); + await openNarrative(t.caseData.narrativeId); const publicPanel = await openPublicData(); - const rows = await waitForRows(publicPanel, t.testCase.row); + const rows = await waitForRows(publicPanel, t.caseData.row); - expect(rows.length).toBeGreaterThanOrEqual(t.testCase.row); - const row = rows[t.testCase.row - 1]; + expect(rows.length).toBeGreaterThanOrEqual(t.caseData.row); + const row = rows[t.caseData.row - 1]; expect(row).toBeDefined(); const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(t.testCase.name); + expect(nameCell).toHaveText(t.caseData.name); // Confirm the metadata fields. - for (const {id, label, value} of t.testCase.metadata) { + for (const {id, label, value} of t.caseData.metadata) { await testField({ container: row, id, @@ -396,20 +391,20 @@ describe('Test kbaseNarrativeSidePublicTab', () => { it('opens the public data search tab, should show default results, scroll to desired row', async () => { const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_2'}); - await openNarrative(t.testCase.narrativeId); + await openNarrative(t.caseData.narrativeId); const publicPanel = await openPublicData(); - const rows = await waitForRows(publicPanel, t.testCase.row); + const rows = await waitForRows(publicPanel, t.caseData.row); // Look at the row - it should already be in view. - const row = rows[t.testCase.row - 1]; + const row = rows[t.caseData.row - 1]; await row.scrollIntoView(); const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(t.testCase.name); + expect(nameCell).toHaveText(t.caseData.name); // Confirm the metadata fields. - for (const {id, label, value} of t.testCase.metadata) { + for (const {id, label, value} of t.caseData.metadata) { await testField({ container: row, id, @@ -422,34 +417,34 @@ describe('Test kbaseNarrativeSidePublicTab', () => { it('opens the public data search tab, searches for a term, should find an expected row', async () => { const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_3'}); - await openNarrative(t.testCase.narrativeId); + await openNarrative(t.caseData.narrativeId); const publicPanel = await openPublicData(); // Select search input and input a search term const searchInput = await publicPanel.$('[data-test-id="search-input"]'); await clickWhenReady(searchInput); - await sendString(t.testCase.searchFor); + await sendString(t.caseData.searchFor); await browser.keys('Enter'); const foundCount = await publicPanel.$('[data-test-id="found-count"]'); - expect(foundCount).toHaveText(t.testCase.foundCount); + expect(foundCount).toHaveText(t.caseData.foundCount); // get rows // When using roles, we sometimes need to be very specific in our queries. // Maybe roles are not suitable for integration tests, then. - const rows = await waitForRows(publicPanel, t.testCase.row); + const rows = await waitForRows(publicPanel, t.caseData.row); - expect(rows.length).toBeGreaterThanOrEqual(t.testCase.row); + expect(rows.length).toBeGreaterThanOrEqual(t.caseData.row); // Look at the row - it should already be in view. - const row = rows[t.testCase.row - 1]; + const row = rows[t.caseData.row - 1]; await row.scrollIntoView(); const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(t.testCase.name); + expect(nameCell).toHaveText(t.caseData.name); // Confirm the metadata fields. - for (const {id, label, value} of t.testCase.metadata) { + for (const {id, label, value} of t.caseData.metadata) { await testField({ container: row, id, @@ -462,14 +457,14 @@ describe('Test kbaseNarrativeSidePublicTab', () => { it('opens the public data search tab, searches for a term which should not be found', async () => { const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_4'}); - await openNarrative(t.testCase.narrativeId); + await openNarrative(t.caseData.narrativeId); const publicPanel = await openPublicData(); // Select search input and input a search term const searchInput = await publicPanel.$('[data-test-id="search-input"]'); await clickWhenReady(searchInput); - await sendString(t.testCase.searchFor); + await sendString(t.caseData.searchFor); await browser.keys('Enter'); await browser.waitUntil(async () => { @@ -477,20 +472,20 @@ describe('Test kbaseNarrativeSidePublicTab', () => { if (await foundCountElement.isDisplayed()) { const text = await foundCountElement.getText(); - return text === t.testCase.foundCount; + return text === t.caseData.foundCount; } else { return false; } }); const foundCount = await publicPanel.$('[data-test-id="found-count"]'); - expect(foundCount).toHaveText(t.testCase.foundCount); + expect(foundCount).toHaveText(t.caseData.foundCount); }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5'}); - await openNarrative(t.testCase.narrativeId); + await openNarrative(t.caseData.narrativeId); // Open the data slideout const publicPanel = await openPublicData(); @@ -498,21 +493,21 @@ describe('Test kbaseNarrativeSidePublicTab', () => { // get rows // When using roles, we sometimes need to be very specific in our queries. // Maybe roles are not suitable for integration tests, then. - for (const scrollRow of t.testCase.scrolls) { + for (const scrollRow of t.caseData.scrolls) { const rowElements = await waitForRows(publicPanel, scrollRow); const rowElement = rowElements[scrollRow - 1]; await rowElement.scrollIntoView(); } // ensure we have all of the rows. - const rows = await waitForRows(publicPanel, t.testCase.row); - const row = rows[t.testCase.row - 1]; + const rows = await waitForRows(publicPanel, t.caseData.row); + const row = rows[t.caseData.row - 1]; await row.scrollIntoView(); const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(t.testCase.name); + expect(nameCell).toHaveText(t.caseData.name); // Confirm the metadata fields. - for (const {id, label, value} of t.testCase.metadata) { + for (const {id, label, value} of t.caseData.metadata) { await testField({ container: row, id, diff --git a/test/integration/wdioUtils.js b/test/integration/wdioUtils.js index 1c07157d55..554cc000ff 100644 --- a/test/integration/wdioUtils.js +++ b/test/integration/wdioUtils.js @@ -115,10 +115,19 @@ async function openNarrative(workspaceId) { return container; } +function* range(start, end) { + yield start; + if (start === end) { + return; + } + yield* range(start + 1, end); +} + module.exports = { login, makeURL, sendString, openNarrative, - clickWhenReady + clickWhenReady, + range }; \ No newline at end of file From 2ce09eae33da77425d317211a631d8744c19e75d Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Fri, 22 Jan 2021 12:26:34 -0800 Subject: [PATCH 14/42] remove inadvertently re-exported functions --- test/integration/NarrativeTesting.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/integration/NarrativeTesting.js b/test/integration/NarrativeTesting.js index 16b620c077..eb48464c80 100644 --- a/test/integration/NarrativeTesting.js +++ b/test/integration/NarrativeTesting.js @@ -2,7 +2,7 @@ /*global browser, $*/ 'use strict'; -const {makeURL, login, sendString, clickWhenReady} = require('./wdioUtils'); +const {makeURL, clickWhenReady} = require('./wdioUtils'); function mergeObjects(listOfObjects) { const simpleObjectPrototype = Object.getPrototypeOf({}); @@ -184,9 +184,6 @@ class NarrativeTesting { } module.exports = { - login, - makeURL, - sendString, - clickWhenReady, - NarrativeTesting + NarrativeTesting, + mergeObjects }; From 09e0a6549f95295ba7b02c9dbd94880af22d5e8c Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Fri, 22 Jan 2021 14:54:50 -0800 Subject: [PATCH 15/42] remove duplicate code, part 1 --- .../specs/kbaseCellToolbarMenu_test.js | 4 +- .../specs/kbaseNarrativeSidePublicTab_test.js | 25 ++++---- test/integration/wdioUtils.js | 60 +------------------ 3 files changed, 16 insertions(+), 73 deletions(-) diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index 9c73314b93..0c29464cc0 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -5,6 +5,8 @@ const { NarrativeTesting } = require('../NarrativeTesting.js'); const { login, clickWhenReady } = require('../wdioUtils.js'); +const TIMEOUT = 30000; + /* Notes: @@ -115,8 +117,6 @@ const testData = { } }; -const TIMEOUT = 60000; - async function testCellMovement({caseLabel, selectCell, direction}) { const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel}); const cellIndex = t.caseData.cellIndex; diff --git a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js index 86f60fee8d..52e5ab85f4 100644 --- a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js +++ b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js @@ -2,9 +2,10 @@ /* eslint {strict: ['error', 'global']} */ 'use strict'; -const {login, openNarrative, sendString, clickWhenReady} = require('../wdioUtils.js'); +const {login, sendString, clickWhenReady} = require('../wdioUtils.js'); const { NarrativeTesting } = require('../NarrativeTesting.js'); +const TIMEOUT = 30000; // Ideally the test data should be the same, except for narrative id, in each env. // But currently CI and prod are indexed differently. @@ -353,7 +354,7 @@ async function openPublicData() { describe('Test kbaseNarrativeSidePublicTab', () => { beforeEach(async () => { - await browser.setTimeout({ 'implicit': 30000 }); + await browser.setTimeout({ 'implicit': TIMEOUT }); await browser.reloadSession(); await login(); }); @@ -363,9 +364,9 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_1'}); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_1', timeout: TIMEOUT}); - await openNarrative(t.caseData.narrativeId); + await t.openNarrative(t.caseData.narrativeId); const publicPanel = await openPublicData(); const rows = await waitForRows(publicPanel, t.caseData.row); @@ -389,9 +390,9 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_2'}); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_2', timeout: TIMEOUT}); - await openNarrative(t.caseData.narrativeId); + await t.openNarrative(t.caseData.narrativeId); const publicPanel = await openPublicData(); const rows = await waitForRows(publicPanel, t.caseData.row); @@ -415,9 +416,9 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, searches for a term, should find an expected row', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_3'}); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_3', timeout: TIMEOUT}); - await openNarrative(t.caseData.narrativeId); + await t.openNarrative(t.caseData.narrativeId); const publicPanel = await openPublicData(); @@ -455,9 +456,9 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, searches for a term which should not be found', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_4'}); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_4', timeout: TIMEOUT}); - await openNarrative(t.caseData.narrativeId); + await t.openNarrative(t.caseData.narrativeId); const publicPanel = await openPublicData(); @@ -483,9 +484,9 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5'}); + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5', timeout: TIMEOUT}); - await openNarrative(t.caseData.narrativeId); + await t.openNarrative(t.caseData.narrativeId); // Open the data slideout const publicPanel = await openPublicData(); diff --git a/test/integration/wdioUtils.js b/test/integration/wdioUtils.js index 554cc000ff..f0c9e6d589 100644 --- a/test/integration/wdioUtils.js +++ b/test/integration/wdioUtils.js @@ -1,5 +1,5 @@ /* eslint strict: ["error", "global"] */ -/*global browser, $*/ +/*global browser */ 'use strict'; @@ -58,63 +58,6 @@ async function clickWhenReady(el) { await el.click(); } -/** -* Navigates the wdio browser to a workspace as given by its id, and waits until the -* narrative container is visible. -* @arg {number} The narrative's workspace id -* @returns {Promise} The Promise value is ignored. -*/ -async function openNarrative(workspaceId) { - const timeout = 60000; - - // Go to the narrative! - await browser.url(makeURL(`narrative/${workspaceId}`)); - - // should experience loading blocker for a few seconds. - const loadingBlocker = await $('#kb-loading-blocker'); - await loadingBlocker.waitForDisplayed({ - timeout, - timeoutMsg: `Timeout after waiting ${timeout}ms for loading blocker to appear` - }); - - // And then the loading blocker should disappear! - await loadingBlocker.waitForDisplayed({ - timeout, - timeoutMsg: `Timeout after waiting ${timeout}ms for loading blocker to disappear`, - reverse: true - }); - - // Ensure logged in - const loginButton = await $('#signin-button > div > button'); - await loginButton.waitForDisplayed({ - timeout, - timeoutMsg: `Timeout after waiting ${timeout}ms for login button to appear` - }); - - await clickWhenReady(loginButton); - - const realnameElement = await $('[data-element="realname"]'); - const usernameElement = await $('[data-element="username"]'); - await browser.waitUntil(async () => { - const text = await realnameElement.getText(); - return (text && text.length > 0); - }); - const realname = await realnameElement.getText(); - const username = await usernameElement.getText(); - console.warn(`Signed in as user "${realname}" (${username})`); - await loginButton.click(); - - // Ensure narrative notebook has displayed - // TODO: more interesting waitUntil loop to signal the - // failure reason (useful for debugging tests?) - const container = await $('#notebook-container'); - await container.waitForDisplayed({ - timeout, - timeoutMsg: `Timeout after waiting ${timeout}ms for narrative to appear` - }); - return container; -} - function* range(start, end) { yield start; if (start === end) { @@ -127,7 +70,6 @@ module.exports = { login, makeURL, sendString, - openNarrative, clickWhenReady, range }; \ No newline at end of file From 234228e09896c7aa5899c07743a38348be3489a7 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Fri, 22 Jan 2021 15:13:09 -0800 Subject: [PATCH 16/42] move test data to separate json file --- .../specs/kbaseCellToolbarMenu_data.json | 165 ++++++++++ .../specs/kbaseCellToolbarMenu_test.js | 97 +----- .../kbaseNarrativeSidePublicTab_data.json | 291 +++++++++++++++++ .../specs/kbaseNarrativeSidePublicTab_test.js | 298 +----------------- 4 files changed, 458 insertions(+), 393 deletions(-) create mode 100644 test/integration/specs/kbaseCellToolbarMenu_data.json create mode 100644 test/integration/specs/kbaseNarrativeSidePublicTab_data.json diff --git a/test/integration/specs/kbaseCellToolbarMenu_data.json b/test/integration/specs/kbaseCellToolbarMenu_data.json new file mode 100644 index 0000000000..fa4c67f11e --- /dev/null +++ b/test/integration/specs/kbaseCellToolbarMenu_data.json @@ -0,0 +1,165 @@ +{ + "common": { + "unselectedBorder": "1px 1px 1px 5px solid rgb(204, 204, 204)", + "selectedBorder": "1px 1px 1px 5px solid rgb(75, 184, 86)", + "cells": [ + { + "title": "Narrative Cell Toolbar Testing" + }, + { + "title": "Cell 1" + }, + { + "title": "Cell 2" + }, + { + "body": "Cell 3" + }, + { + "body": "Cell 4" + } + ] + }, + "cases": { + "TEST_CASE_1": { + "cellIndex": 1, + "title": "Narrative Cell Toolbar Testing", + "expect": { + "afterMove": { + "up": { + "cellOrder": [ + 1, + 2, + 3, + 4, + 5 + ] + }, + "down": { + "cellOrder": [ + 2, + 1, + 3, + 4, + 5 + ] + } + } + } + }, + "TEST_CASE_2": { + "cellIndex": 2, + "title": "Cell 1", + "expect": { + "afterMove": { + "up": { + "cellOrder": [ + 2, + 1, + 3, + 4, + 5 + ] + }, + "down": { + "cellOrder": [ + 1, + 3, + 2, + 4, + 5 + ] + } + } + } + }, + "TEST_CASE_3": { + "cellIndex": 3, + "title": "Cell 2", + "expect": { + "afterMove": { + "up": { + "cellOrder": [ + 1, + 3, + 2, + 4, + 5 + ] + }, + "down": { + "cellOrder": [ + 1, + 2, + 4, + 3, + 5 + ] + } + } + } + }, + "TEST_CASE_4": { + "cellIndex": 4, + "body": "Cell 3", + "expect": { + "afterMove": { + "up": { + "cellOrder": [ + 1, + 2, + 4, + 3, + 5 + ] + }, + "down": { + "cellOrder": [ + 1, + 2, + 3, + 5, + 4 + ] + } + } + } + }, + "TEST_CASE_5": { + "cellIndex": 5, + "body": "Cell 4", + "expect": { + "afterMove": { + "up": { + "cellOrder": [ + 1, + 2, + 3, + 5, + 4 + ] + }, + "down": { + "cellOrder": [ + 1, + 2, + 3, + 4, + 5 + ] + } + } + } + } + }, + "ci": { + "defaults": { + "narrativeId": 58675 + } + }, + "narrative-dev": { + "defaults": { + "narrativeId": 80970 + } + } +} \ No newline at end of file diff --git a/test/integration/specs/kbaseCellToolbarMenu_test.js b/test/integration/specs/kbaseCellToolbarMenu_test.js index 0c29464cc0..d446f27f77 100644 --- a/test/integration/specs/kbaseCellToolbarMenu_test.js +++ b/test/integration/specs/kbaseCellToolbarMenu_test.js @@ -4,6 +4,7 @@ const { NarrativeTesting } = require('../NarrativeTesting.js'); const { login, clickWhenReady } = require('../wdioUtils.js'); +const testData = require('./kbaseCellToolbarMenu_data.json'); const TIMEOUT = 30000; @@ -21,102 +22,6 @@ test cases can be could be in separate files. */ -const testData = { - common: { - unselectedBorder: '1px 1px 1px 5px solid rgb(204, 204, 204)', - selectedBorder: '1px 1px 1px 5px solid rgb(75, 184, 86)', - cells: [ - {title: 'Narrative Cell Toolbar Testing'}, - {title: 'Cell 1'}, - {title: 'Cell 2'}, - {body: 'Cell 3'}, - {body: 'Cell 4'} - ] - }, - cases: { - TEST_CASE_1: { - cellIndex: 1, - title: 'Narrative Cell Toolbar Testing', - expect: { - afterMove: { - up: { - cellOrder: [1, 2, 3, 4, 5] - }, - down: { - cellOrder: [2, 1, 3, 4, 5] - } - } - } - }, - TEST_CASE_2: { - cellIndex: 2, - title: 'Cell 1', - expect: { - afterMove: { - up: { - cellOrder: [2, 1, 3, 4, 5] - }, - down: { - cellOrder: [1, 3, 2, 4, 5] - } - } - } - }, - TEST_CASE_3: { - cellIndex: 3, - title: 'Cell 2', - expect: { - afterMove: { - up: { - cellOrder: [1, 3, 2, 4, 5] - }, - down: { - cellOrder: [1, 2, 4, 3, 5] - } - } - } - }, - TEST_CASE_4: { - cellIndex: 4, - body: 'Cell 3', - expect: { - afterMove: { - up: { - cellOrder: [1, 2, 4, 3, 5] - }, - down: { - cellOrder: [1, 2, 3, 5, 4] - } - } - } - }, - TEST_CASE_5: { - cellIndex: 5, - body: 'Cell 4', - expect: { - afterMove: { - up: { - cellOrder: [1, 2, 3, 5, 4] - }, - down: { - cellOrder: [1, 2, 3, 4, 5] - } - } - } - } - }, - ci: { - defaults: { - narrativeId: 58675 - } - }, - 'narrative-dev': { - defaults: { - narrativeId: 80970 - } - } -}; - async function testCellMovement({caseLabel, selectCell, direction}) { const t = new NarrativeTesting({testData, timeout: TIMEOUT, caseLabel}); const cellIndex = t.caseData.cellIndex; diff --git a/test/integration/specs/kbaseNarrativeSidePublicTab_data.json b/test/integration/specs/kbaseNarrativeSidePublicTab_data.json new file mode 100644 index 0000000000..8ecc11dafa --- /dev/null +++ b/test/integration/specs/kbaseNarrativeSidePublicTab_data.json @@ -0,0 +1,291 @@ +{ + "cases": { + "TEST_CASE_1": {}, + "TEST_CASE_2": {}, + "TEST_CASE_3": {}, + "TEST_CASE_4": {}, + "TEST_CASE_5": {} + }, + "ci": { + "defaults": { + "narrativeId": 53983 + }, + "TEST_CASE_1": { + "row": 4, + "name": "Acetobacter ascendens", + "metadata": [ + { + "id": "lineage", + "label": "Lineage", + "value": "Bacteria > Proteobacteria > Alphaproteobacteria > Rhodospirillales > Acetobacteraceae > Acetobacter" + }, + { + "id": "kbase_id", + "label": "KBase ID", + "value": "GCF_001766255.1" + }, + { + "id": "refseq_id", + "label": "RefSeq ID", + "value": "NZ_CP015168" + }, + { + "id": "contigs", + "label": "Contigs", + "value": "4" + }, + { + "id": "features", + "label": "Features", + "value": "3,032" + } + ] + }, + "TEST_CASE_2": { + "row": 10, + "scrollTo": true, + "name": "Acidaminococcus fermentans", + "metadata": [ + { + "id": "lineage", + "label": "Lineage", + "value": "Bacteria > Terrabacteria group > Firmicutes > Negativicutes > Acidaminococcales > Acidaminococcaceae > Acidaminococcus" + }, + { + "id": "kbase_id", + "label": "KBase ID", + "value": "GCF_900107075.1" + }, + { + "id": "refseq_id", + "label": "RefSeq ID", + "value": "NZ_FNOP01000039" + }, + { + "id": "contigs", + "label": "Contigs", + "value": "40" + }, + { + "id": "features", + "label": "Features", + "value": "2,067" + } + ] + }, + "TEST_CASE_3": { + "row": 1, + "scrollTo": false, + "searchFor": "prochlorococcus", + "foundCount": "14", + "name": "Prochlorococcus marinus str. GP2", + "metadata": [ + { + "id": "lineage", + "label": "Lineage", + "value": "Bacteria > Terrabacteria group > Cyanobacteria/Melainabacteria group > Cyanobacteria > Synechococcales > Prochloraceae > Prochlorococcus > Prochlorococcus marinus" + }, + { + "id": "kbase_id", + "label": "KBase ID", + "value": "GCF_000759885.1" + }, + { + "id": "refseq_id", + "label": "RefSeq ID", + "value": "NZ_JNAH01000001" + }, + { + "id": "contigs", + "label": "Contigs", + "value": "11" + }, + { + "id": "features", + "label": "Features", + "value": "1,760" + } + ] + }, + "TEST_CASE_4": { + "searchFor": "foobar", + "foundCount": "None" + }, + "TEST_CASE_5": { + "row": 30, + "scrollTo": true, + "scrolls": [ + 20 + ], + "name": "Acinetobacter baumannii", + "metadata": [ + { + "id": "lineage", + "label": "Lineage", + "value": "Bacteria > Proteobacteria > Gammaproteobacteria > Pseudomonadales > Moraxellaceae > Acinetobacter > Acinetobacter calcoaceticus/baumannii complex" + }, + { + "id": "kbase_id", + "label": "KBase ID", + "value": "GCF_000804875.1" + }, + { + "id": "refseq_id", + "label": "RefSeq ID", + "value": "NZ_JSCS01000001" + }, + { + "id": "contigs", + "label": "Contigs", + "value": "74" + }, + { + "id": "features", + "label": "Features", + "value": "3,862" + } + ] + } + }, + "narrative-dev": { + "defaults": { + "narrativeId": 78050 + }, + "TEST_CASE_1": { + "row": 3, + "name": "Absiella sp. AM09-45", + "metadata": [ + { + "id": "lineage", + "label": "Lineage", + "value": "Bacteria > Terrabacteria group > Firmicutes > Erysipelotrichia > Erysipelotrichales > Erysipelotrichaceae > Absiella > unclassified Absiella" + }, + { + "id": "kbase_id", + "label": "KBase ID", + "value": "GCF_003433745.1" + }, + { + "id": "refseq_id", + "label": "RefSeq ID", + "value": "NZ_QVFJ01000001" + }, + { + "id": "contigs", + "label": "Contigs", + "value": "96" + }, + { + "id": "features", + "label": "Features", + "value": "4,170" + } + ] + }, + "TEST_CASE_2": { + "row": 10, + "scrollTo": true, + "name": "Abyssicoccus albus", + "metadata": [ + { + "id": "lineage", + "label": "Lineage", + "value": "Bacteria > Terrabacteria group > Firmicutes > Bacilli > Bacillales > Staphylococcaceae > Abyssicoccus" + }, + { + "id": "kbase_id", + "label": "KBase ID", + "value": "GCF_003815035.1" + }, + { + "id": "refseq_id", + "label": "RefSeq ID", + "value": "NZ_RKRK01000002" + }, + { + "id": "contigs", + "label": "Contigs", + "value": "10" + }, + { + "id": "features", + "label": "Features", + "value": "1,777" + } + ] + }, + "TEST_CASE_3": { + "row": 1, + "scrollTo": false, + "searchFor": "prochlorococcus", + "foundCount": "28", + "name": "Prochlorococcus marinus", + "metadata": [ + { + "id": "lineage", + "label": "Lineage", + "value": "Bacteria > Terrabacteria group > Cyanobacteria/Melainabacteria group > Cyanobacteria > Synechococcales > Prochloraceae > Prochlorococcus" + }, + { + "id": "kbase_id", + "label": "KBase ID", + "value": "GCF_001180245.1" + }, + { + "id": "refseq_id", + "label": "RefSeq ID", + "value": "NZ_CVSV01000001" + }, + { + "id": "contigs", + "label": "Contigs", + "value": "136" + }, + { + "id": "features", + "label": "Features", + "value": "1,648" + } + ] + }, + "TEST_CASE_4": { + "searchFor": "foobar", + "foundCount": "None" + }, + "TEST_CASE_5": { + "row": 30, + "scrollTo": true, + "scrolls": [ + 20 + ], + "name": "Acetobacter orientalis", + "metadata": [ + { + "id": "lineage", + "label": "Lineage", + "value": "Bacteria > Proteobacteria > Alphaproteobacteria > Rhodospirillales > Acetobacteraceae > Acetobacter" + }, + { + "id": "kbase_id", + "label": "KBase ID", + "value": "GCF_002153475.1" + }, + { + "id": "refseq_id", + "label": "RefSeq ID", + "value": "NZ_JOMO01000001" + }, + { + "id": "contigs", + "label": "Contigs", + "value": "106" + }, + { + "id": "features", + "label": "Features", + "value": "2,539" + } + ] + } + } +} \ No newline at end of file diff --git a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js index 52e5ab85f4..0f99b31b5d 100644 --- a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js +++ b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js @@ -4,306 +4,10 @@ const {login, sendString, clickWhenReady} = require('../wdioUtils.js'); const { NarrativeTesting } = require('../NarrativeTesting.js'); +const testData = require('./kbaseNarrativeSidePublicTab_data.json'); const TIMEOUT = 30000; -// Ideally the test data should be the same, except for narrative id, in each env. -// But currently CI and prod are indexed differently. - -// Note that the narrativeIds used below must be owned or shared with full rights (at least edit) with the narrativetest user. -// Note that narrativetest is not yet set up in narrative-dev/prod. -const testData = { - cases: { - TEST_CASE_1: {}, - TEST_CASE_2: {}, - TEST_CASE_3: {}, - TEST_CASE_4: {}, - TEST_CASE_5: {} - }, - ci: { - defaults: { - narrativeId: 53983, - }, - TEST_CASE_1: { - row: 4, - name: 'Acetobacter ascendens', - metadata: [ - { - id: 'lineage', - label: 'Lineage', - value: 'Bacteria > Proteobacteria > Alphaproteobacteria > Rhodospirillales > Acetobacteraceae > Acetobacter' - }, - { - id: 'kbase_id', - label: 'KBase ID', - value: 'GCF_001766255.1' - }, - { - id: 'refseq_id', - label: 'RefSeq ID', - value: 'NZ_CP015168' - }, - { - id: 'contigs', - label: 'Contigs', - value: '4' - }, - { - id: 'features', - label: 'Features', - value: '3,032' - } - ] - }, - TEST_CASE_2: { - row: 10, - scrollTo: true, - name: 'Acidaminococcus fermentans', - metadata: [ - { - id: 'lineage', - label: 'Lineage', - value: 'Bacteria > Terrabacteria group > Firmicutes > Negativicutes > Acidaminococcales > Acidaminococcaceae > Acidaminococcus' - }, - { - id: 'kbase_id', - label: 'KBase ID', - value: 'GCF_900107075.1' - }, - { - id: 'refseq_id', - label: 'RefSeq ID', - value: 'NZ_FNOP01000039' - }, - { - id: 'contigs', - label: 'Contigs', - value: '40' - }, - { - id: 'features', - label: 'Features', - value: '2,067' - } - ] - }, - TEST_CASE_3: { - row: 1, - scrollTo: false, - searchFor: 'prochlorococcus', - foundCount: '14', - name: 'Prochlorococcus marinus str. GP2', - metadata: [ - { - id: 'lineage', - label: 'Lineage', - value: 'Bacteria > Terrabacteria group > Cyanobacteria/Melainabacteria group > Cyanobacteria > Synechococcales > Prochloraceae > Prochlorococcus > Prochlorococcus marinus' - }, - { - id: 'kbase_id', - label: 'KBase ID', - value: 'GCF_000759885.1' - }, - { - id: 'refseq_id', - label: 'RefSeq ID', - value: 'NZ_JNAH01000001' - }, - { - id: 'contigs', - label: 'Contigs', - value: '11' - }, - { - id: 'features', - label: 'Features', - value: '1,760' - } - ] - }, - TEST_CASE_4: { - searchFor: 'foobar', - foundCount: 'None' - }, - TEST_CASE_5: { - row: 30, - scrollTo: true, - scrolls: [ - 20 - ], - name: 'Acinetobacter baumannii', - metadata: [ - { - id: 'lineage', - label: 'Lineage', - value: 'Bacteria > Proteobacteria > Gammaproteobacteria > Pseudomonadales > Moraxellaceae > Acinetobacter > Acinetobacter calcoaceticus/baumannii complex' - }, - { - id: 'kbase_id', - label: 'KBase ID', - value: 'GCF_000804875.1' - }, - { - id: 'refseq_id', - label: 'RefSeq ID', - value: 'NZ_JSCS01000001' - }, - { - id: 'contigs', - label: 'Contigs', - value: '74' - }, - { - id: 'features', - label: 'Features', - value: '3,862' - } - ] - } - }, - 'narrative-dev': { - defaults: { - narrativeId: 78050 - }, - TEST_CASE_1: { - row: 3, - name: 'Absiella sp. AM09-45', - metadata: [ - { - id: 'lineage', - label: 'Lineage', - value: 'Bacteria > Terrabacteria group > Firmicutes > Erysipelotrichia > Erysipelotrichales > Erysipelotrichaceae > Absiella > unclassified Absiella' - }, - { - id: 'kbase_id', - label: 'KBase ID', - value: 'GCF_003433745.1' - }, - { - id: 'refseq_id', - label: 'RefSeq ID', - value: 'NZ_QVFJ01000001' - }, - { - id: 'contigs', - label: 'Contigs', - value: '96' - }, - { - id: 'features', - label: 'Features', - value: '4,170' - } - ] - }, - TEST_CASE_2: { - row: 10, - scrollTo: true, - name: 'Abyssicoccus albus', - metadata: [ - { - id: 'lineage', - label: 'Lineage', - value: 'Bacteria > Terrabacteria group > Firmicutes > Bacilli > Bacillales > Staphylococcaceae > Abyssicoccus' - }, - { - id: 'kbase_id', - label: 'KBase ID', - value: 'GCF_003815035.1' - }, - { - id: 'refseq_id', - label: 'RefSeq ID', - value: 'NZ_RKRK01000002' - }, - { - id: 'contigs', - label: 'Contigs', - value: '10' - }, - { - id: 'features', - label: 'Features', - value: '1,777' - } - ] - }, - TEST_CASE_3: { - row: 1, - scrollTo: false, - searchFor: 'prochlorococcus', - foundCount: '28', - name: 'Prochlorococcus marinus', - metadata: [ - { - id: 'lineage', - label: 'Lineage', - value: 'Bacteria > Terrabacteria group > Cyanobacteria/Melainabacteria group > Cyanobacteria > Synechococcales > Prochloraceae > Prochlorococcus' - }, - { - id: 'kbase_id', - label: 'KBase ID', - value: 'GCF_001180245.1' - }, - { - id: 'refseq_id', - label: 'RefSeq ID', - value: 'NZ_CVSV01000001' - }, - { - id: 'contigs', - label: 'Contigs', - value: '136' - }, - { - id: 'features', - label: 'Features', - value: '1,648' - } - ] - }, - TEST_CASE_4: { - searchFor: 'foobar', - foundCount: 'None' - }, - TEST_CASE_5: { - row: 30, - scrollTo: true, - scrolls: [ - 20 - ], - name: 'Acetobacter orientalis', - metadata: [ - { - id: 'lineage', - label: 'Lineage', - value: 'Bacteria > Proteobacteria > Alphaproteobacteria > Rhodospirillales > Acetobacteraceae > Acetobacter' - }, - { - id: 'kbase_id', - label: 'KBase ID', - value: 'GCF_002153475.1' - }, - { - id: 'refseq_id', - label: 'RefSeq ID', - value: 'NZ_JOMO01000001' - }, - { - id: 'contigs', - label: 'Contigs', - value: '106' - }, - { - id: 'features', - label: 'Features', - value: '2,539' - } - ] - } - } -}; - async function testField({container, id, label, value}) { const lineageLabel = await container.$(`[role="row"][data-test-id="${id}"] [data-test-id="label"]`); expect(lineageLabel).toHaveText(label); From 417067665d4fa6b4ebcbe01f7056472fecf2da87 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Sat, 23 Jan 2021 08:52:36 -0800 Subject: [PATCH 17/42] change test data to match ci changes --- .../specs/kbaseNarrativeSidePublicTab_data.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/integration/specs/kbaseNarrativeSidePublicTab_data.json b/test/integration/specs/kbaseNarrativeSidePublicTab_data.json index 8ecc11dafa..ee54667279 100644 --- a/test/integration/specs/kbaseNarrativeSidePublicTab_data.json +++ b/test/integration/specs/kbaseNarrativeSidePublicTab_data.json @@ -127,22 +127,22 @@ { "id": "kbase_id", "label": "KBase ID", - "value": "GCF_000804875.1" + "value": "GCF_000695855.3" }, { "id": "refseq_id", "label": "RefSeq ID", - "value": "NZ_JSCS01000001" + "value": "NZ_CP007535" }, { "id": "contigs", "label": "Contigs", - "value": "74" + "value": "3" }, { "id": "features", "label": "Features", - "value": "3,862" + "value": "3,739" } ] } From 22454ca5e7ad41830022751b6ea8907d8c0fd003 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Sat, 23 Jan 2021 08:53:39 -0800 Subject: [PATCH 18/42] refactor some common code into functions; fix usage of async expect --- .../specs/kbaseNarrativeSidePublicTab_test.js | 191 ++++++++---------- 1 file changed, 82 insertions(+), 109 deletions(-) diff --git a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js index 0f99b31b5d..f3d091182e 100644 --- a/test/integration/specs/kbaseNarrativeSidePublicTab_test.js +++ b/test/integration/specs/kbaseNarrativeSidePublicTab_test.js @@ -9,10 +9,10 @@ const testData = require('./kbaseNarrativeSidePublicTab_data.json'); const TIMEOUT = 30000; async function testField({container, id, label, value}) { - const lineageLabel = await container.$(`[role="row"][data-test-id="${id}"] [data-test-id="label"]`); - expect(lineageLabel).toHaveText(label); - const lineageValue = await container.$(`[role="row"][data-test-id="${id}"] [data-test-id="value"]`); - expect(lineageValue).toHaveText(value); + const labelElement = await container.$(`[role="row"][data-test-id="${id}"] [data-test-id="label"]`); + await expect(labelElement).toHaveText(label); + const valueElement = await container.$(`[role="row"][data-test-id="${id}"] [data-test-id="value"]`); + await expect(valueElement).toHaveText(value); } async function waitForRows(panel, count){ @@ -23,7 +23,9 @@ async function waitForRows(panel, count){ return await panel.$$('[role="table"][data-test-id="result"] > div > [role="row"]'); } -async function openPublicData() { +async function openPublicDataPanel(t) { + await t.openNarrative(t.caseData.narrativeId); + // Open the data slideout const button = await $('[data-test-id="data-slideout-button"]'); await button.waitForExist(); @@ -52,10 +54,58 @@ async function openPublicData() { // Maybe roles are not suitable for integration tests, then. const rows = await waitForRows(publicPanel, 20); - expect(rows.length).toEqual(20); + await expect(rows.length).toEqual(20); return publicPanel; } +/** + * Tests the a row to ensure that columns have the values specified + * in the test data. + * @param {} row + * @param {*} t + */ +async function testRow(row, t) { + const nameCell = await row.$('[role="cell"][data-test-id="name"]'); + await expect(nameCell).toHaveText(t.caseData.name); + + // Confirm the metadata fields. + for (const {id, label, value} of t.caseData.metadata) { + await testField({ + container: row, + id, + label, + value + }); + } +} + +async function getPublicDataRows(t) { + const publicPanel = await openPublicDataPanel(t); + const rows = await waitForRows(publicPanel, t.caseData.row); + await expect(rows.length).toBeGreaterThanOrEqual(t.caseData.row); + return rows; +} + +async function waitForRow(publicPanel, rowNumber) { + const rows = await waitForRows(publicPanel, rowNumber); + const row = rows[rowNumber - 1]; + await row.scrollIntoView(); + return row; +} + +async function testPublicDataRow(t, scrollIntoView) { + const rows = await getPublicDataRows(t); + + // get row + const row = rows[t.caseData.row - 1]; + if (scrollIntoView) { + await row.scrollIntoView(); + } + await expect(row).toBeDefined(); + + await testRow(row, t); +} + describe('Test kbaseNarrativeSidePublicTab', () => { beforeEach(async () => { await browser.setTimeout({ 'implicit': TIMEOUT }); @@ -69,62 +119,40 @@ describe('Test kbaseNarrativeSidePublicTab', () => { it('opens the public data search tab, should show default results', async () => { const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_1', timeout: TIMEOUT}); - - await t.openNarrative(t.caseData.narrativeId); - - const publicPanel = await openPublicData(); - const rows = await waitForRows(publicPanel, t.caseData.row); - - expect(rows.length).toBeGreaterThanOrEqual(t.caseData.row); - const row = rows[t.caseData.row - 1]; - expect(row).toBeDefined(); - - const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(t.caseData.name); - - // Confirm the metadata fields. - for (const {id, label, value} of t.caseData.metadata) { - await testField({ - container: row, - id, - label, - value - }); - } + await testPublicDataRow(t, false); }); it('opens the public data search tab, should show default results, scroll to desired row', async () => { const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_2', timeout: TIMEOUT}); + await testPublicDataRow(t, true); + }); + + it('opens the public data search tab, should show default results, scroll to desired row', async () => { + const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5', timeout: TIMEOUT}); - await t.openNarrative(t.caseData.narrativeId); + const publicPanel = await openPublicDataPanel(t); - const publicPanel = await openPublicData(); - const rows = await waitForRows(publicPanel, t.caseData.row); + for (const scrollRow of t.caseData.scrolls) { + const rowElements = await waitForRows(publicPanel, scrollRow); + const rowElement = rowElements[scrollRow - 1]; + await rowElement.scrollIntoView(); + } - // Look at the row - it should already be in view. + const rows = await waitForRows(publicPanel, t.caseData.row); const row = rows[t.caseData.row - 1]; await row.scrollIntoView(); + await expect(row).toBeVisible(); + await testRow(row, t); + }); - const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(t.caseData.name); - - // Confirm the metadata fields. - for (const {id, label, value} of t.caseData.metadata) { - await testField({ - container: row, - id, - label, - value - }); - } + it('does nothing', async () => { + await expect(1).toEqual(1); }); it('opens the public data search tab, searches for a term, should find an expected row', async () => { const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_3', timeout: TIMEOUT}); - await t.openNarrative(t.caseData.narrativeId); - - const publicPanel = await openPublicData(); + const publicPanel = await openPublicDataPanel(t); // Select search input and input a search term const searchInput = await publicPanel.$('[data-test-id="search-input"]'); @@ -132,39 +160,18 @@ describe('Test kbaseNarrativeSidePublicTab', () => { await sendString(t.caseData.searchFor); await browser.keys('Enter'); + // Ensure the correct number of items was found. const foundCount = await publicPanel.$('[data-test-id="found-count"]'); - expect(foundCount).toHaveText(t.caseData.foundCount); - - // get rows - // When using roles, we sometimes need to be very specific in our queries. - // Maybe roles are not suitable for integration tests, then. - const rows = await waitForRows(publicPanel, t.caseData.row); - - expect(rows.length).toBeGreaterThanOrEqual(t.caseData.row); + await expect(foundCount).toHaveText(t.caseData.foundCount); - // Look at the row - it should already be in view. - const row = rows[t.caseData.row - 1]; - await row.scrollIntoView(); - const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(t.caseData.name); - - // Confirm the metadata fields. - for (const {id, label, value} of t.caseData.metadata) { - await testField({ - container: row, - id, - label, - value - }); - } + const row = await waitForRow(publicPanel, t.caseData.row); + await testRow(row, t); }); it('opens the public data search tab, searches for a term which should not be found', async () => { const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_4', timeout: TIMEOUT}); - await t.openNarrative(t.caseData.narrativeId); - - const publicPanel = await openPublicData(); + const publicPanel = await openPublicDataPanel(t); // Select search input and input a search term const searchInput = await publicPanel.$('[data-test-id="search-input"]'); @@ -172,6 +179,7 @@ describe('Test kbaseNarrativeSidePublicTab', () => { await sendString(t.caseData.searchFor); await browser.keys('Enter'); + // Ensure that the reported found count matches expectations. await browser.waitUntil(async () => { const foundCountElement = await publicPanel.$('[data-test-id="found-count"]'); @@ -184,41 +192,6 @@ describe('Test kbaseNarrativeSidePublicTab', () => { }); const foundCount = await publicPanel.$('[data-test-id="found-count"]'); - expect(foundCount).toHaveText(t.caseData.foundCount); - }); - - it('opens the public data search tab, should show default results, scroll to desired row', async () => { - const t = new NarrativeTesting({testData, caseLabel: 'TEST_CASE_5', timeout: TIMEOUT}); - - await t.openNarrative(t.caseData.narrativeId); - - // Open the data slideout - const publicPanel = await openPublicData(); - - // get rows - // When using roles, we sometimes need to be very specific in our queries. - // Maybe roles are not suitable for integration tests, then. - for (const scrollRow of t.caseData.scrolls) { - const rowElements = await waitForRows(publicPanel, scrollRow); - const rowElement = rowElements[scrollRow - 1]; - await rowElement.scrollIntoView(); - } - - // ensure we have all of the rows. - const rows = await waitForRows(publicPanel, t.caseData.row); - const row = rows[t.caseData.row - 1]; - await row.scrollIntoView(); - const nameCell = await row.$('[role="cell"][data-test-id="name"]'); - expect(nameCell).toHaveText(t.caseData.name); - - // Confirm the metadata fields. - for (const {id, label, value} of t.caseData.metadata) { - await testField({ - container: row, - id, - label, - value - }); - } + await expect(foundCount).toHaveText(t.caseData.foundCount); }); }); From 574ef346b81df372d23bee711a5633245f6da3a5 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Mon, 25 Jan 2021 18:33:13 -0800 Subject: [PATCH 19/42] test config should use narrativetest as the test user --- test/testConfig.json | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/test/testConfig.json b/test/testConfig.json index 387ccc3eda..b856b37c4b 100644 --- a/test/testConfig.json +++ b/test/testConfig.json @@ -1,12 +1,14 @@ { "token": { - "user": "wjriehl", - "file": "test/wjriehl.tok" + "user": "narrativetest", + "file": "test/narrativetest.tok" }, "currentNarrative": "bar", - "data": [{ - "file": "/test/data/blah.xyz", - "type": "Module.type-1.0", - "name": "obj_name" - }] -} + "data": [ + { + "file": "/test/data/blah.xyz", + "type": "Module.type-1.0", + "name": "obj_name" + } + ] +} \ No newline at end of file From c26d813b7fd11f28074e078c6bb80c766e96c726 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Tue, 26 Jan 2021 09:59:18 -0800 Subject: [PATCH 20/42] use chrome binary in pupeteer - github's ubuntu should be fixed to support it now --- package-lock.json | 151 +++++++++++++++++----------------- package.json | 4 +- test/integration/wdio.conf.js | 6 +- 3 files changed, 83 insertions(+), 78 deletions(-) diff --git a/package-lock.json b/package-lock.json index 43cb486a4f..3b3dc6c14a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -377,28 +377,28 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" } }, @@ -1193,12 +1193,20 @@ "dev": true }, "axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", "dev": true, "requires": { - "follow-redirects": "1.5.10" + "follow-redirects": "^1.10.0" + }, + "dependencies": { + "follow-redirects": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz", + "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==", + "dev": true + } } }, "backo2": { @@ -1626,17 +1634,18 @@ } }, "chromedriver": { - "version": "87.0.0", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-87.0.0.tgz", - "integrity": "sha512-PY7FnHOQKfH0oPfSdhpLx5nEy5g4dGYySf2C/WZGkAaCaldYH8/3lPPucZ8MlOCi4bCSGoKoCUTeG6+wYWavvw==", + "version": "88.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-88.0.0.tgz", + "integrity": "sha512-EE8rXh7mikxk3VWKjUsz0KCUX8d3HkQ4HgMNJhWrWjzju12dKPPVHO9MY+YaAI5ryXrXGNf0Y4HcNKgW36P/CA==", "dev": true, "requires": { "@testim/chrome-version": "^1.0.7", - "axios": "^0.19.2", - "del": "^5.1.0", + "axios": "^0.21.1", + "del": "^6.0.0", "extract-zip": "^2.0.1", "https-proxy-agent": "^5.0.0", "mkdirp": "^1.0.4", + "proxy-from-env": "^1.1.0", "tcp-port-used": "^1.0.1" }, "dependencies": { @@ -2117,18 +2126,18 @@ } }, "del": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", - "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", + "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", "dev": true, "requires": { - "globby": "^10.0.1", - "graceful-fs": "^4.2.2", + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", "is-glob": "^4.0.1", "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.1", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", "slash": "^3.0.0" } }, @@ -2976,9 +2985,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -3002,9 +3011,9 @@ "dev": true }, "fastq": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", - "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.0.tgz", + "integrity": "sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -3386,18 +3395,16 @@ "dev": true }, "globby": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", - "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", + "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", "dev": true, "requires": { - "@types/glob": "^7.1.1", "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", "slash": "^3.0.0" } }, @@ -4125,9 +4132,9 @@ "dev": true }, "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", "dev": true }, "is-absolute": { @@ -4395,14 +4402,14 @@ } }, "is2": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.1.tgz", - "integrity": "sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.6.tgz", + "integrity": "sha512-+Z62OHOjA6k2sUDOKXoZI3EXv7Fb1K52jpTBLbkfx62bcUeSsrTBLhEquCRDKTx0XE5XbHcG/S2vrtE3lnEDsQ==", "dev": true, "requires": { "deep-is": "^0.1.3", - "ip-regex": "^2.1.0", - "is-url": "^1.2.2" + "ip-regex": "^4.1.0", + "is-url": "^1.2.4" } }, "isarray": { @@ -6369,9 +6376,9 @@ } }, "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "requires": { "aggregate-error": "^3.0.0" @@ -6672,13 +6679,13 @@ "dev": true }, "puppeteer": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-5.4.0.tgz", - "integrity": "sha512-LgTqVW2ClEP4XGAT64FLQ0QWVhdNSRwJp9HfMFVfoJlZHGQu3HUbuBhR1hBow3DXZH1K3b/WfHxt1n8hr2uayw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-5.5.0.tgz", + "integrity": "sha512-OM8ZvTXAhfgFA7wBIIGlPQzvyEETzDjeRa4mZRCRHxYL+GNH5WAuYUQdja3rpWZvkX/JKqmuVgbsxDNsDFjMEg==", "dev": true, "requires": { "debug": "^4.1.0", - "devtools-protocol": "0.0.809251", + "devtools-protocol": "0.0.818844", "extract-zip": "^2.0.0", "https-proxy-agent": "^4.0.0", "node-fetch": "^2.6.1", @@ -6692,20 +6699,14 @@ }, "dependencies": { "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { "ms": "2.1.2" } }, - "devtools-protocol": { - "version": "0.0.809251", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.809251.tgz", - "integrity": "sha512-pf+2OY6ghMDPjKkzSWxHMq+McD+9Ojmq5XVRYpv/kPd9sTMQxzEt21592a31API8qRjro0iYYOc3ag46qF/1FA==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -8076,22 +8077,22 @@ } }, "tcp-port-used": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.1.tgz", - "integrity": "sha512-rwi5xJeU6utXoEIiMvVBMc9eJ2/ofzB+7nLOdnZuFTmNCLqRiQh2sMG9MqCxHU/69VC/Fwp5dV9306Qd54ll1Q==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz", + "integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==", "dev": true, "requires": { - "debug": "4.1.0", - "is2": "2.0.1" + "debug": "4.3.1", + "is2": "^2.0.6" }, "dependencies": { "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { diff --git a/package.json b/package.json index cc77e8360e..db03ae0674 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "@wdio/browserstack-service": "^6.10.4", "bower": "^1.8.8", "chrome-launcher": "^0.13.4", - "chromedriver": "^87.0.0", + "chromedriver": "^88.0.0", "eslint": "7.17.0", "grunt": "1.3.0", "grunt-cli": "1.3.2", @@ -38,7 +38,7 @@ "karma-mocha-reporter": "2.2.5", "karma-requirejs": "1.1.0", "karma-safari-launcher": "1.0.0", - "puppeteer": "5.4.0", + "puppeteer": "5.5.0", "requirejs": "2.3.6", "selenium-standalone": "6.23.0", "selenium-webdriver": "3.6.0", diff --git a/test/integration/wdio.conf.js b/test/integration/wdio.conf.js index a7cc60ad4b..ebd5b0d670 100644 --- a/test/integration/wdio.conf.js +++ b/test/integration/wdio.conf.js @@ -6,6 +6,9 @@ const testConfig = require('../testConfig'); const fs = require('fs'); +const CHROME_BINARY = require('puppeteer').executablePath(); +// process.env. + // Import environment variables used to control the tests. // Note that most have defaults, and many are only applicable // to testing services @@ -211,7 +214,8 @@ function makeCapabilities(config) { acceptInsecureCerts: true, maxInstances: 1, 'goog:chromeOptions': { - args + args, + binary: CHROME_BINARY } }; })(); From efbd2bdce2b4e3cc64e4ad0b5083655e6e093cf8 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Tue, 25 May 2021 10:18:27 -0700 Subject: [PATCH 21/42] add unreleased section to release notes --- RELEASE_NOTES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9cc2274821..39fdfe4ac5 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -4,6 +4,9 @@ The Narrative Interface allows users to craft KBase Narratives using a combinati This is built on the Jupyter Notebook v6.0.2 (more notes will follow). +### Unreleased +- SCT-2914 / PUBLIC-1493 - fix up/down cell movement behavior for unselected cells + ### Version 4.4.0 - No ticket: boatloads of code cleanup and fixes to the unit and internal testing - PTV-1635: fix bug in data slideout tab selection From 7ec78de51338936cec44971ea01d0ce0c9c7bc51 Mon Sep 17 00:00:00 2001 From: Erik Pearson Date: Wed, 26 May 2021 10:34:12 -0700 Subject: [PATCH 22/42] prettier and linting fixes --- kbase-extension/static/kbase/js/userMenu.js | 12 +- .../appWidgets2/input/select2ObjectInput.js | 18 +- .../narrative_core/kbaseCellToolbarMenu.js | 130 +----- .../narrative_core/kbaseNarrativeDataList.js | 7 +- .../kbaseNarrativeSidePublicTab.js | 399 ++++++++++-------- .../kbaseNarrativeStagingDataTab.js | 12 +- .../publicDataSources/search2DataSource.js | 390 +++++++++-------- .../upload/stagingAreaViewer.js | 7 +- test/integration/NarrativeTesting.js | 58 +-- .../specs/kbaseCellToolbarMenu_test.js | 63 +-- .../specs/kbaseNarrativeSidePublicTab_test.js | 48 ++- 11 files changed, 561 insertions(+), 583 deletions(-) diff --git a/kbase-extension/static/kbase/js/userMenu.js b/kbase-extension/static/kbase/js/userMenu.js index 41c444b59d..61ef0c353a 100644 --- a/kbase-extension/static/kbase/js/userMenu.js +++ b/kbase-extension/static/kbase/js/userMenu.js @@ -88,13 +88,11 @@ define([ }), ] ), - div( - { - style: 'display: inline-block', - 'data-element': 'user-label', - }, - [displayName, br(), i({}, userName)] - ), + div({ style: 'display: inline-block' }, [ + span({ 'data-element': 'realname' }, displayName), + br(), + i({ 'data-element': 'username' }, userName), + ]), ] ), ]), diff --git a/kbase-extension/static/kbase/js/widgets/appWidgets2/input/select2ObjectInput.js b/kbase-extension/static/kbase/js/widgets/appWidgets2/input/select2ObjectInput.js index 9d10c7fe52..a471951e92 100644 --- a/kbase-extension/static/kbase/js/widgets/appWidgets2/input/select2ObjectInput.js +++ b/kbase-extension/static/kbase/js/widgets/appWidgets2/input/select2ObjectInput.js @@ -14,19 +14,7 @@ define([ 'select2', 'bootstrap', 'css!font-awesome', -], ( - Promise, - $, - html, - utils, - Data, - Events, - Runtime, - UI, - Validation, - TimeFormat, - WidgetCommon, -) => { +], (Promise, $, html, utils, Data, Events, Runtime, UI, Validation, TimeFormat, WidgetCommon) => { 'use strict'; // Constants @@ -50,9 +38,7 @@ define([ availableValuesMap: {}, value: undefined, }; - let parent, - container, - ui; + let parent, container, ui; // TODO: getting rid of blacklist temporarily until we work out how to state-ify everything by reference. model.blacklistValues = []; //config.blacklist || []; diff --git a/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseCellToolbarMenu.js b/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseCellToolbarMenu.js index d098c7d863..e244844f5a 100644 --- a/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseCellToolbarMenu.js +++ b/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseCellToolbarMenu.js @@ -15,7 +15,6 @@ define([ div = t('div'), a = t('a'), button = t('button'), - p = t('p'), span = t('span'), ul = t('ul'), li = t('li'); @@ -33,10 +32,9 @@ define([ return cell.metadata.kbase[group][name]; } - function factory(config) { - let container, - cell, - readOnly = Jupyter.narrative.readonly; + function factory() { + let container, cell; + const readOnly = Jupyter.narrative.readonly; function doMoveCellUp() { const cellIndex = Jupyter.notebook.find_cell_index(cell); @@ -63,9 +61,8 @@ define([ } function getCellSubtitle(cell) { - const subTitle = getMeta(cell, 'attributes', 'subtitle'), - showTitle = utils.getCellMeta(cell, 'kbase.cellState.showTitle', true), - showSubtitle = utils.getCellMeta(cell, 'kbase.cellState.showSubtitle', true); + const subTitle = getMeta(cell, 'attributes', 'subtitle'); + const showTitle = utils.getCellMeta(cell, 'kbase.cellState.showTitle', true); if (showTitle) { return subTitle; @@ -73,31 +70,11 @@ define([ return ''; } - function getCellInfoLink(cell, events) { - const url = utils.getCellMeta(cell, 'kbase.attributes.info.url'), - label = utils.getCellMeta(cell, 'kbase.attributes.info.label'); - - if (url) { - return a( - { - href: url, - target: '_blank', - id: events.addEvent({ - type: 'click', - handler: doShowInfoModal, - }), - }, - label || 'ref' - ); - } - return ''; - } - function doToggleMinMaxCell(e) { if (e.getModifierState) { const modifier = e.getModifierState('Alt'); if (modifier) { - console.log('I want to toggle all cells!'); + console.warn('I want to toggle all cells!'); } } cell.toggleMinMax(); @@ -114,70 +91,6 @@ define([ return null; } - function doShowInfoModal(e) { - e.preventDefault(); - const version = utils.getCellMeta(cell, 'kbase.appCell.app.version'), - authors = utils.getCellMeta(cell, 'kbase.appCell.app.spec.info.authors'), - title = getMeta(cell, 'attributes', 'title') + ' v' + version, - appStoreUrl = utils.getCellMeta(cell, 'kbase.attributes.info.url'), - tag = utils.getCellMeta(cell, 'kbase.appCell.app.tag'), - module = utils.getCellMeta(cell, 'kbase.appCell.app.spec.info.module_name'); - var dialog = new BootstrapDialog({ - title: title, - body: $('
'), - buttons: [ - $( - 'View on App Store' - ), - $('').click(() => { - dialog.hide(); - }), - ], - enterToTrigger: true, - closeButton: true, - }); - - const infoPanel = AppInfoPanel.make({ - appId: utils.getCellMeta(cell, 'kbase.appCell.app.id'), - appVersion: version, - appAuthors: authors, - appModule: module, - tag: tag, - }); - infoPanel.start({ node: dialog.getBody() }); - - dialog.getElement().on('hidden.bs.modal', () => { - dialog.destroy(); - }); - dialog.show(); - } - - function doToggleCellSettings() { - cell.element.trigger('toggleCellSettings.cell'); - } - - function renderToggleCellSettings(events) { - // Only kbase cells have cell settings. - if (!cell.metadata || !cell.metadata.kbase || !cell.metadata.kbase.type) { - return; - } - - return button( - { - type: 'button', - class: 'btn btn-default btn-xs', - dataToggle: 'tooltip', - dataPlacement: 'left', - title: true, - dataOriginalTitle: 'Cell Settings', - id: events.addEvent({ type: 'click', handler: doToggleCellSettings }), - }, - [span({ class: 'fa fa-cog', style: 'font-size: 14pt' })] - ); - } - function renderIcon(icon) { return span({ class: 'fa fa-' + icon.type + ' fa-sm', @@ -185,24 +98,7 @@ define([ }); } - function isKBaseCell(cell) { - if (!cell.metadata || !cell.metadata.kbase || !cell.metadata.kbase.type) { - return false; - } - return true; - } - - function doHelp() { - alert('help here...'); - } - function renderOptions(cell, events) { - const toggleMinMax = utils.getCellMeta( - cell, - 'kbase.cellState.toggleMinMax', - 'maximized' - ); - const toggleIcon = toggleMinMax === 'maximized' ? 'minus' : 'plus'; const dropdownId = html.genId(); const menuItems = []; @@ -429,13 +325,15 @@ define([ ), (function () { const toggleMinMax = utils.getCellMeta( - cell, - 'kbase.cellState.toggleMinMax', - 'maximized' - ); + cell, + 'kbase.cellState.toggleMinMax', + 'maximized' + ); const toggleIcon = toggleMinMax === 'maximized' ? 'minus' : 'plus'; - const color = toggleMinMax === 'maximized' ? '#000' : 'rgba(255,137,0,1)'; - const classModifier = (toggleMinMax === 'maximized' ? '-maximized' : '-minimized'); + const color = + toggleMinMax === 'maximized' ? '#000' : 'rgba(255,137,0,1)'; + const classModifier = + toggleMinMax === 'maximized' ? '-maximized' : '-minimized'; return button( { type: 'button', diff --git a/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseNarrativeDataList.js b/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseNarrativeDataList.js index d8c86e2e9f..576fb6ad5e 100644 --- a/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseNarrativeDataList.js +++ b/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseNarrativeDataList.js @@ -277,7 +277,10 @@ define([ height: this.mainListPanelHeight, }) .on('scroll', (event) => { - if ($(event.target).scrollTop() + $(event.target).innerHeight() >= event.target.scrollHeight) { + if ( + $(event.target).scrollTop() + $(event.target).innerHeight() >= + event.target.scrollHeight + ) { this.renderMore(); } }); @@ -411,7 +414,7 @@ define([ } }) .catch((error) => { - console.trace('dumping stacktrace!') + console.trace('dumping stacktrace!'); console.error('DataList: when checking for updates:', error); if (showError) { this.showBlockingError( diff --git a/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseNarrativeSidePublicTab.js b/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseNarrativeSidePublicTab.js index e5e7cd3cb9..2b999eb90f 100644 --- a/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseNarrativeSidePublicTab.js +++ b/kbase-extension/static/kbase/js/widgets/narrative_core/kbaseNarrativeSidePublicTab.js @@ -32,13 +32,12 @@ define([ Icon, WorkspaceDataSource, SearchDataSource, - DataSourceConfig, + DataSourceConfig ) => { 'use strict'; function formatValue(value) { - if (typeof value === 'undefined' || - (typeof value === 'string' && value.length === 0)) { + if (typeof value === 'undefined' || (typeof value === 'string' && value.length === 0)) { return 'n/a'; } else { return String(value); @@ -48,7 +47,9 @@ define([ function formatItem(item) { return ` - ${item.label}: + ${ + item.label + }:   ${formatValue(item.value)} @@ -60,35 +61,40 @@ define([ // an array of the same. // function metadataToTable(metadata) { - const $table = $('') - .css('font-size', '80%'); + const $table = $('
').css('font-size', '80%'); metadata.forEach((item) => { let value; if (item.value instanceof Array) { - value = item.value.map((item) => { - return formatItem(item); - }).join('   '); + value = item.value + .map((item) => { + return formatItem(item); + }) + .join('   '); } else { value = formatValue(item.value); } const $row = $(``) .css('margin-bottom', '2px') - .append($('
') - .css('width', '7em') - .css('font-weight', 'normal') - .css('font-style', 'italic') - .css('padding-right', '4px') - .css('color', '#AAA') - .css('vertical-align', 'top') - .css('padding-bottom', '2px') - .text(item.label)) - .append($('') - // .css('font-weight', 'bold') - .css('vertical-align', 'top') - .css('padding-bottom', '2px') - .html(value)); + .append( + $('') + .css('width', '7em') + .css('font-weight', 'normal') + .css('font-style', 'italic') + .css('padding-right', '4px') + .css('color', '#AAA') + .css('vertical-align', 'top') + .css('padding-bottom', '2px') + .text(item.label) + ) + .append( + $('') + // .css('font-weight', 'bold') + .css('vertical-align', 'top') + .css('padding-bottom', '2px') + .html(value) + ); $table.append($row); }); @@ -98,21 +104,25 @@ define([ function renderTotals(found, total) { const $totals = $('').addClass('kb-data-list-type'); if (total === 0) { - $totals - .append($('None available')); + $totals.append($('None available')); } else if (found === 0) { $totals - .append($('').css('font-weight', 'bold').text('None')) + .append( + $('').css('font-weight', 'bold').text('None') + ) .append($('').text(' found out of ')) .append($('').css('font-weight', 'bold').text(numeral(total).format('0,0'))) .append($('').text(' available')); } else if (total > found) { $totals - .append($('').css('font-weight', 'bold').text(numeral(found).format('0,0'))) + .append( + $('') + .css('font-weight', 'bold') + .text(numeral(found).format('0,0')) + ) .append($('').text(' found out of ')) .append($('').css('font-weight', 'bold').text(numeral(total).format('0,0'))) .append($('').text(' available')); - } else { $totals .append($('').text(numeral(total).format('0,0'))) @@ -218,7 +228,7 @@ define([ narrativeObjects: {}, narrativeObjectsClean: null, - init: function(options) { + init: function (options) { this._super(options); this.data_icons = Config.get('icons').data; @@ -232,16 +242,20 @@ define([ return this; }, - loadObjects: function() { + loadObjects: function () { this.narrativeObjectsClean = false; - $(document).trigger('dataLoadedQuery.Narrative', [null, this.IGNORE_VERSION, function(objects) { - this.narrativeObjects = objects; - this.narrativeObjectsClean = true; - }.bind(this)]); + $(document).trigger('dataLoadedQuery.Narrative', [ + null, + this.IGNORE_VERSION, + function (objects) { + this.narrativeObjects = objects; + this.narrativeObjectsClean = true; + }.bind(this), + ]); }, - render: function() { - if ((!this.token) || (!this.wsName)) { + render: function () { + if (!this.token || !this.wsName) { return; } @@ -250,18 +264,20 @@ define([ this.loadObjects(); this.loaded = true; $(document).on('dataUpdated.Narrative', () => { - $(document).trigger('dataLoadedQuery.Narrative', [null, this.IGNORE_VERSION, function(objects) { - this.narrativeObjects = objects; - this.narrativeObjectsClean = true; - }.bind(this)]); + $(document).trigger('dataLoadedQuery.Narrative', [ + null, + this.IGNORE_VERSION, + function (objects) { + this.narrativeObjects = objects; + this.narrativeObjectsClean = true; + }.bind(this), + ]); }); } this.infoPanel = $('
'); this.dataPolicyPanel = $('
'); - this.$elem.empty() - .append(this.infoPanel) - .append(this.dataPolicyPanel); + this.$elem.empty().append(this.infoPanel).append(this.dataPolicyPanel); this.narrativeService = new DynamicServiceClient({ module: 'NarrativeService', @@ -275,11 +291,12 @@ define([ }); const margin = { margin: '10px 0px 10px 0px' }; - const $typeInput = $('').css(margin); this.dataSourceConfigs.forEach((config, index) => { - $typeInput.append(''); + $typeInput.append( + '' + ); }); const $dataSourceLogo = $('') @@ -292,33 +309,36 @@ define([ .css('background-color', 'transparent'); this.$dataSourceLogo = $dataSourceLogo; - const $inputGroup = $('
') - .addClass('input-group') - .css('width', '100%'); + const $inputGroup = $('
').addClass('input-group').css('width', '100%'); - const typeFilter = $('
') - .append($inputGroup - .append($typeInput) - .append($dataSourceLogo)); + const typeFilter = $('
').append( + $inputGroup.append($typeInput).append($dataSourceLogo) + ); - const $filterInput = $(''); + const $filterInput = $( + '' + ); const $filterInputField = $('
') .css(margin) .append($filterInput) - .append($('
') - .append($('')) - .css('padding', '4px 8px') - .click(() => { - $filterInput.change(); - })) - .append($('
') - .append($('')) - .css('padding', '4px 8px') - .click(() => { - $filterInput.val(''); - inputFieldLastValue = ''; - $filterInput.change(); - })); + .append( + $('
') + .append($('')) + .css('padding', '4px 8px') + .click(() => { + $filterInput.change(); + }) + ) + .append( + $('
') + .append($('')) + .css('padding', '4px 8px') + .click(() => { + $filterInput.val(''); + inputFieldLastValue = ''; + $filterInput.change(); + }) + ); /* search and render when the type dropdown changes. @@ -329,8 +349,7 @@ define([ this.$dataSourceLogo.empty(); if (dataSource) { if (dataSource.logoUrl) { - this.$dataSourceLogo.append($('') - .attr('src', dataSource.logoUrl)); + this.$dataSourceLogo.append($('').attr('src', dataSource.logoUrl)); } } this.searchAndRender(newDataSourceID, $filterInput.val()); @@ -365,11 +384,12 @@ define([ const searchFilter = $('
').append($filterInputField); - const header = $('
').css({ 'margin': '0px 10px 0px 10px' }) + const header = $('
') + .css({ margin: '0px 10px 0px 10px' }) .append(typeFilter) .append(searchFilter); this.$elem.append(header); - this.totalPanel = $('
').css({ 'margin': '0px 0px 0px 10px' }); + this.totalPanel = $('
').css({ margin: '0px 0px 0px 10px' }); this.$elem.append(this.totalPanel); this.resultPanel = $('
'); @@ -405,15 +425,15 @@ define([ return this; }, - hideResultFooter: function() { + hideResultFooter: function () { this.resultFooter.addClass('hide'); }, - showResultFooter: function() { + showResultFooter: function () { this.resultFooter.removeClass('hide'); }, - searchAndRender: function(category, query) { + searchAndRender: function (category, query) { if (query) { query = query.trim(); if (query.length == 0) { @@ -432,7 +452,11 @@ define([ } // Duplicate queries are suppressed. - if (this.currentQuery && this.currentQuery === query && category === this.currentCategory) { + if ( + this.currentQuery && + this.currentQuery === query && + category === this.currentCategory + ) { return; } @@ -447,22 +471,23 @@ define([ return this.renderInitial(); }, - renderTotalsPanel: function() { + renderTotalsPanel: function () { const $totals = renderTotals(this.currentFilteredResults, this.totalAvailable); this.totalPanel.html($totals); }, - renderInitial: function() { + renderInitial: function () { // Get and render the first batch of data. // Note that the loading ui is only displayed on the initial load. // Reset the ui. this.totalPanel.empty(); this.resultPanel.empty(); this.resultsFooterMessage.empty(); - this.totalPanel - .append($('') + this.totalPanel.append( + $('') .addClass('kb-data-list-type') - .append(' searching...')); + .append(' searching...') + ); this.hideError(); this.showResultFooter(); @@ -471,14 +496,16 @@ define([ return this.renderFromDataSource(this.currentCategory, true); }, - renderError: function() { + renderError: function () { this.totalPanel.empty(); this.hideResultFooter(); this.resultsFooterMessage.empty(); - this.totalPanel.html('
An error occurred executing this search!
'); + this.totalPanel.html( + '
An error occurred executing this search!
' + ); }, - renderMore: function() { + renderMore: function () { this.hideError(); // suss out whether we really need more... @@ -499,13 +526,12 @@ define([ this.currentPage += 1; - return this.renderFromDataSource(this.currentCategory, false) - .finally(() => { - this.renderingMore = false; - }); + return this.renderFromDataSource(this.currentCategory, false).finally(() => { + this.renderingMore = false; + }); }, - fetchFromDataSource: function(dataSource) { + fetchFromDataSource: function (dataSource) { const query = { input: this.currentQuery, page: this.currentPage, @@ -514,7 +540,7 @@ define([ return dataSource.search(query); }, - getDataSource: function(dataSourceID) { + getDataSource: function (dataSourceID) { let dataSource; const dataSourceConfig = this.dataSourceConfigs[dataSourceID]; if (this.currentDataSource && this.currentDataSource.config === dataSourceConfig) { @@ -522,25 +548,26 @@ define([ } else { const dataSourceType = dataSourceTypes[dataSourceConfig.sourceType]; - const urls = Object.keys(dataSourceType.serviceDependencies) - .reduce((accumUrls, key) => { + const urls = Object.keys(dataSourceType.serviceDependencies).reduce( + (accumUrls, key) => { const configKey = dataSourceType.serviceDependencies[key]; accumUrls[key] = Config.url(configKey); return accumUrls; - }, {}); - dataSource = Object.create(dataSourceType.baseObject) - .init({ - config: dataSourceConfig, - urls, - token: this.token, - pageSize: this.itemsPerPage, - }); + }, + {} + ); + dataSource = Object.create(dataSourceType.baseObject).init({ + config: dataSourceConfig, + urls, + token: this.token, + pageSize: this.itemsPerPage, + }); this.currentDataSource = dataSource; } return dataSource; }, - renderFromDataSource: function(dataSourceID, initial) { + renderFromDataSource: function (dataSourceID, initial) { const dataSource = this.getDataSource(dataSourceID); this.resultsFooterMessage.html(` fetching another ${this.itemsPerPage} items @@ -570,7 +597,11 @@ define([ if (dataSource.fetchedDataCount === dataSource.filteredDataCount) { message = 'all ' + this.currentFilteredResults + ' fetched'; } else { - message = 'fetched ' + dataSource.fetchedDataCount + ' of ' + this.currentFilteredResults; + message = + 'fetched ' + + dataSource.fetchedDataCount + + ' of ' + + this.currentFilteredResults; } this.showResultFooter(); } else { @@ -591,23 +622,23 @@ define([ }); }, - clearRows: function() { + clearRows: function () { this.resultPanel.empty(); }, - addRow: function(dataSource, row) { + addRow: function (dataSource, row) { const $row = this.renderObjectRow(dataSource, row); this.resultPanel.append($row); }, - escapeSearchQuery: function(str) { + escapeSearchQuery: function (str) { return str.replace(/[%]/g, '').replace(/[:"\\]/g, '\\$&'); }, /* renderObjectRow */ - renderObjectRow: function(dataSource, object) { + renderObjectRow: function (dataSource, object) { const self = this; const type = object.type.split('.')[1].split('-')[0]; const copyText = ' Add'; @@ -646,7 +677,7 @@ define([ .attr('role', 'toolbar') .hide(); const btnClasses = 'btn btn-xs btn-default'; - const css = { 'color': '#888' }; + const css = { color: '#888' }; const $openLandingPage = $('') // tooltips showing behind pullout, need to fix! //.tooltip({title:'Explore data', 'container':'#'+this.mainListId}) @@ -658,46 +689,45 @@ define([ }); const $openProvenance = $('') - .addClass(btnClasses).css(css) + .addClass(btnClasses) + .css(css) //.tooltip({title:'View data provenance and relationships', 'container':'body'}) .append($('').addClass('fa fa-sitemap fa-rotate-90').css(css)) .click((e) => { e.stopPropagation(); window.open(provenanceLink); }); - $btnToolbar - .append($openLandingPage) - .append($openProvenance); + $btnToolbar.append($openLandingPage).append($openProvenance); // Action Column - const $addDiv = - $('
').append( - $('