-
-
-
-
-
-
-
-
-
-
-
-
- {{ flat? $options.icons.mdiFormatAlignRight : $options.icons.mdiFormatAlignJustify }}
-
-
- {{ flat ? "Show Families" : "Hide Families" }}
-
-
-
- {{ $options.icons.mdiPlus }}
- Expand all
-
-
- {{ $options.icons.mdiMinus }}
- Collapse all
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/tests/component/specs/viewToolbar.cy.js b/tests/component/specs/viewToolbar.cy.js
index bc7ee88f6..87da7232c 100644
--- a/tests/component/specs/viewToolbar.cy.js
+++ b/tests/component/specs/viewToolbar.cy.js
@@ -27,7 +27,7 @@ describe('View Toolbar Component', () => {
cy.vmount(
ViewToolbar,
{
- props: { groups }
+ props: { groups },
}
).as('wrapper')
// add the classes Vuetify requires
@@ -224,4 +224,93 @@ describe('View Toolbar Component', () => {
// TODO: visual regression test
// https://github.com/cylc/cylc-ui/issues/178
})
+
+ it('filters task states', () => {
+ mountToolbar([
+ {
+ title: 'Group 1',
+ controls: [
+ {
+ title: 'Filter',
+ action: 'taskStateFilter',
+ value: [],
+ key: 'filter'
+ }
+ ]
+ },
+ ])
+ cy.get('.control > button').click()
+ cy.get('.v-list-item').as('menuItems')
+ .filter(':visible')
+ .should('have.length', 10)
+ .contains('.v-list-item', 'waiting').as('waitingItem')
+
+ // 1) select the waiting state and expand the waiting submenu
+ cy.get('@waitingItem')
+ .click()
+ .find('button')
+ .click({ force: true })
+
+ // the setOption event should be fired
+ .get('@wrapper').then(({ wrapper }) => {
+ expect(
+ wrapper.emitted().setOption.at(-1)[1]
+ ).to.deep.equal(['waiting'])
+ })
+
+ // the waiting state should be selected
+ .get('@waitingItem')
+ .should('have.class', 'v-list-item--active')
+
+ // the waiting submenu should be open
+ .get('.v-list-item').as('menuItems')
+ .filter(':visible')
+ .should('have.length', 15)
+
+ // 2) select the Retry state
+ cy.get('@menuItems')
+ .contains('Retry')
+ .click({ force: true })
+
+ // the setOption event should be fired
+ .get('@wrapper').then(({ wrapper }) => {
+ expect(
+ wrapper.emitted().setOption.at(-1)[1]
+ ).to.deep.equal(['waiting', 'isRetry'])
+ })
+
+ // 3) unselect the waiting state
+ cy.get('@waitingItem')
+ .click()
+
+ // implementation detail: the setOption event is fired again
+ // but the waiting state is not removed
+ .get('@wrapper').then(({ wrapper }) => {
+ expect(
+ wrapper.emitted().setOption.at(-1)[1]
+ ).to.deep.equal(['isRetry', 'waiting'])
+ })
+
+ // the waiting state should still be selected
+ .get('@waitingItem')
+ .should('have.class', 'v-list-item--active')
+
+ // 3) unselect the retry state THEN the waiting state
+ cy.get('@menuItems')
+ .contains('Retry')
+ .click({ force: true })
+ .get('@waitingItem')
+ .click()
+
+ // the waiting state should NOT be selected
+ .get('@waitingItem')
+ .should('not.have.class', 'v-list-item--active')
+
+ // the setOption event should be fired
+ .get('@wrapper').then(({ wrapper }) => {
+ expect(
+ wrapper.emitted().setOption.at(-1)[1]
+ ).to.deep.equal([])
+ })
+ })
})
diff --git a/tests/e2e/specs/analysis.cy.js b/tests/e2e/specs/analysis.cy.js
index 192842765..1d9899c77 100644
--- a/tests/e2e/specs/analysis.cy.js
+++ b/tests/e2e/specs/analysis.cy.js
@@ -420,19 +420,12 @@ describe('Analysis view', () => {
})
})
-function addView (view) {
- cy.get('[data-cy=add-view-btn]').click()
- cy.get(`#toolbar-add-${view}-view`).click()
- // wait for menu to close
- .should('not.be.exist')
-}
-
describe('Filters and Options save state', () => {
const numTasks = sortedTasks.length
describe('Options save state', () => {
beforeEach(() => {
+ localStorage.defaultView = 'Analysis'
cy.visit('/#/workspace/one')
- addView('Analysis')
})
it('remembers table and box & whiskers toggle option when switching between workflows', () => {
@@ -548,7 +541,12 @@ describe('Filters and Options save state', () => {
})
it('shows sorting controls in correct tab', () => {
- addView('Analysis') // second analysis view
+ // add second analysis view
+ cy.get('[data-cy=add-view-btn]').click()
+ cy.get('#toolbar-add-Analysis-view').click()
+ // wait for menu to close
+ .should('not.be.exist')
+
cy.get('.c-analysis [data-cy=box-plot-toggle]:last')
.click()
.get('[data-cy="box-plot-sort-select"]')
diff --git a/tests/e2e/specs/editRuntimeForm.cy.js b/tests/e2e/specs/editRuntimeForm.cy.js
index 3580df33e..fa4242df6 100644
--- a/tests/e2e/specs/editRuntimeForm.cy.js
+++ b/tests/e2e/specs/editRuntimeForm.cy.js
@@ -180,7 +180,7 @@ describe('Edit Runtime form', () => {
.get('.c-mutation-dialog .v-card-subtitle')
.contains('/root')
// but not jobs
- cy.get('[data-cy=tree-view] [data-c-interactive].c-job:first')
+ cy.get('.c-tree [data-c-interactive].c-job:first')
.click({ force: true })
.get('#less-more-button')
.should('not.exist') // if this does deliberately exist in future, change to .click()
diff --git a/tests/e2e/specs/gantt.cy.js b/tests/e2e/specs/gantt.cy.js
index 2ae9ad264..d4a3b1d9e 100644
--- a/tests/e2e/specs/gantt.cy.js
+++ b/tests/e2e/specs/gantt.cy.js
@@ -60,7 +60,7 @@ describe('Filter save state', () => {
// Set task name filter option to something other than default ('')
selectOption('#c-gantt-filter-job-name', 'c3')
// Set task times filter option to something other than default ('Total times')
- selectOption('#c-gantt-filter-job-timings', 'Queue')
+ selectOption('#c-gantt-filter-job-timings', 'Queue times')
// Set platform filter option to something other than default ('All')
selectOption('#c-gantt-filter-job-platforms', 'localhost')
// Set tasks per page filter option to something other than default (10)
@@ -75,7 +75,7 @@ describe('Filter save state', () => {
// Check name filter
checkOption('#c-gantt-filter-job-name', 'c3')
// Check task times filter
- checkOption('#c-gantt-filter-job-timings', 'Queue')
+ checkOption('#c-gantt-filter-job-timings', 'Queue times')
// Check platform filter
checkOption('#c-gantt-filter-job-platforms', 'localhost')
// Check tasks per page
diff --git a/tests/e2e/specs/mutation.cy.js b/tests/e2e/specs/mutation.cy.js
index 7cd4503d0..9988257e4 100644
--- a/tests/e2e/specs/mutation.cy.js
+++ b/tests/e2e/specs/mutation.cy.js
@@ -33,7 +33,7 @@ describe('Mutations component', () => {
* @param {string} nodeName - the tree node name, to search for and open the mutations form
*/
const openMutationsForm = (nodeName) => {
- cy.get('[data-cy=tree-view]').as('treeView')
+ cy.get('.c-tree').as('treeView')
.find('.c-treeitem')
.find('.c-task')
.should('be.visible')
diff --git a/tests/e2e/specs/table.cy.js b/tests/e2e/specs/table.cy.js
index 26df1dee7..20cd60ead 100644
--- a/tests/e2e/specs/table.cy.js
+++ b/tests/e2e/specs/table.cy.js
@@ -43,14 +43,12 @@ describe('Table view', () => {
it('Should filter by ID', () => {
cy.get('.c-table table > tbody > tr')
.should('have.length', initialNumRows)
- cy.get('[data-cy=filter-id] input')
+ cy.get('[data-cy=control-taskIDFilter] input')
.should('be.empty')
- cy.get('[data-cy="filter task state"] input')
- .should('have.value', '')
cy.get('td [data-cy-task-name=sleepy]')
.should('be.visible')
for (const id of ['eep', '/sle']) {
- cy.get('[data-cy=filter-id] input')
+ cy.get('[data-cy=control-taskIDFilter] input')
.clear()
.type(id)
cy.get('td [data-cy-task-name=sleepy]')
@@ -69,7 +67,7 @@ describe('Table view', () => {
.get('td [data-cy-task-name=failed]')
.should('be.visible')
cy
- .get('[data-cy="filter task state"]')
+ .get('[data-cy=control-taskStateFilter]')
.click()
cy
.get('.v-list-item')
@@ -89,7 +87,7 @@ describe('Table view', () => {
.get('.c-table table > tbody > tr')
.should('have.length', initialNumRows)
cy
- .get('[data-cy="filter task state"]')
+ .get('[data-cy=control-taskStateFilter]')
.click()
cy
.get('.v-list-item')
@@ -100,7 +98,7 @@ describe('Table view', () => {
.should('have.length', 2)
.should('be.visible')
cy
- .get('[data-cy=filter-id] input')
+ .get('[data-cy=control-taskIDFilter] input')
.type('eventually')
cy
.get('td [data-cy-task-name=eventually_succeeded]')
@@ -182,18 +180,19 @@ describe('State saving', () => {
.get('.c-table table > tbody > tr')
.should('have.length', initialNumRows)
cy
- .get('[data-cy="filter task state"]:last')
+ .get('[data-cy=control-taskStateFilter]:last')
.click()
cy
.get('.v-list-item')
- .contains(TaskState.SUCCEEDED.name)
+ .filter(':visible')
+ .contains('.v-list-item', 'succeeded')
.click({ force: true })
cy
.get('.c-table table > tbody > tr')
.should('have.length', 2)
.should('be.visible')
cy
- .get('[data-cy=filter-id] input:last')
+ .get('[data-cy=control-taskIDFilter] input:last')
.type('eventually')
cy
.get('td [data-cy-task-name=eventually_succeeded]')
diff --git a/tests/e2e/specs/tree.cy.js b/tests/e2e/specs/tree.cy.js
index 525cb733d..793af7fd9 100644
--- a/tests/e2e/specs/tree.cy.js
+++ b/tests/e2e/specs/tree.cy.js
@@ -174,7 +174,7 @@ describe('Tree view', () => {
.should('have.length', initialNumTasks)
.contains('waiting')
for (const id of ['eed', '/suc', 'GOOD', 'SUC']) {
- cy.get('[data-cy=filter-id] input')
+ cy.get('.c-view-toolbar input')
.clear()
.type(id)
cy.get('.node-data-task:visible')
@@ -184,12 +184,12 @@ describe('Tree view', () => {
.should('not.be.visible')
}
// It should stop filtering when input is cleared
- cy.get('[data-cy=filter-id] input')
+ cy.get('.c-view-toolbar input')
.clear()
.get('.node-data-task:visible')
.should('have.length', initialNumTasks)
// It should filter by cycle point
- cy.get('[data-cy=filter-id] input')
+ cy.get('.c-view-toolbar input')
.type('2000') // (matches all tasks)
.get('.node-data-task:visible')
.should('have.length', initialNumTasks)
@@ -202,7 +202,7 @@ describe('Tree view', () => {
.contains(name)
.should('be.visible')
}
- cy.get('[data-cy="filter task state"]')
+ cy.get('[data-cy="control-taskStateFilter"]')
.click()
.get('.v-list-item')
.contains(new RegExp(`^${TaskState.FAILED.name}$`))
@@ -226,10 +226,10 @@ describe('Tree view', () => {
.contains('failed')
.should('be.visible')
cy
- .get('[data-cy=filter-id]')
+ .get('[data-cy="control-taskIDFilter"]')
.type('i')
cy
- .get('[data-cy="filter task state"]')
+ .get('[data-cy="control-taskStateFilter"]')
.click()
.get('.v-list-item')
.contains(TaskState.WAITING.name)
@@ -247,10 +247,10 @@ describe('Tree view', () => {
.contains('failed')
.should('be.visible')
cy
- .get('[data-cy=filter-id]')
+ .get('[data-cy="control-taskIDFilter"]')
.type('i')
cy
- .get('[data-cy="filter task state"]')
+ .get('[data-cy="control-taskStateFilter"]')
.click()
.get('.v-list-item')
.contains(TaskState.WAITING.name)
@@ -265,18 +265,37 @@ describe('Tree view', () => {
.contains('retrying')
})
- it('Provides a select all functionality', () => {
+ it('Provides a reset functionality', () => {
cy.visit('/#/tree/one')
- cy.get('[data-cy="filter task state"]')
- .get('.v-list-item--active')
- .should('have.length', 0)
- cy.get('[data-cy="filter task state"]')
+ cy.get('[data-cy="control-taskStateFilter"]')
.click()
- .get('[data-cy=task-filter-select-all]')
+ .get('.v-list-item')
+ .as('filters')
+
+ // select some states
+ for (const state of [
+ TaskState.WAITING,
+ TaskState.PREPARING,
+ TaskState.SUBMITTED]
+ ) {
+ cy.get('@filters')
+ .contains(state.name)
+ .click()
+ }
+
+ // there should be three states selected
+ cy.get('@filters')
+ .get('.v-list-item--active')
+ .should('have.length', 3)
+
+ // press the reset button
+ cy.get('[data-cy="control-taskStateFilter-reset"]')
.click()
- cy.get('[data-cy="filter task state"]')
+
+ // there should be zero states selected
+ cy.get('@filters')
.get('.v-list-item--active')
- .should('have.length', 8)
+ .should('have.length', 0)
})
})
@@ -287,11 +306,11 @@ describe('Tree view', () => {
.contains('sleepy')
.as('sleepyTask')
.should('be.visible')
- cy.get('[data-cy=collapse-all]')
+ cy.get('[data-cy=control-CollapseAll]')
.click()
.get('@sleepyTask')
.should('not.be.visible')
- .get('[data-cy=expand-all]')
+ .get('[data-cy=control-ExpandAll]')
.click()
.get('@sleepyTask')
.should('be.visible')
@@ -299,7 +318,7 @@ describe('Tree view', () => {
it('Does not expand jobs but can collapse them', () => {
cy.visit('/#/tree/one')
- .get('[data-cy=expand-all]')
+ .get('[data-cy=control-ExpandAll]')
.click()
.get('.node-data-job:first')
.should('not.exist')
@@ -308,14 +327,14 @@ describe('Tree view', () => {
.click()
.get('.node-data-job:first')
.should('be.visible')
- cy.get('[data-cy=expand-all]')
+ cy.get('[data-cy=control-ExpandAll]')
.click()
// The job should remain expanded
.get('.node-data-job:first')
.should('be.visible')
- cy.get('[data-cy=collapse-all]')
+ cy.get('[data-cy=control-CollapseAll]')
.click()
- .get('[data-cy=expand-all]')
+ .get('[data-cy=control-ExpandAll]')
.click()
// The job should be collapsed now
.get('.node-data-job:first')
@@ -328,41 +347,24 @@ describe('Tree view', () => {
.contains('sleepy')
.as('sleepyTask')
.should('be.visible')
- cy.get('[data-cy=filter-id]')
+ cy.get('[data-cy="control-taskIDFilter"]')
.type('sleep')
- cy.get('[data-cy=collapse-all]')
+ cy.get('[data-cy=control-CollapseAll]')
.click()
.get('@sleepyTask')
.should('not.be.visible')
- .get('[data-cy=expand-all]')
+ .get('[data-cy=control-ExpandAll]')
.click()
.get('@sleepyTask')
.should('be.visible')
})
})
- it('should show a summary of tasks if the number of selected items is greater than the maximum limit', () => {
- cy.visit('/#/tree/one')
- cy.get('[data-cy="filter task state"]')
- .click()
- // eslint-disable-next-line no-lone-blocks
- TaskState.enumValues.forEach(state => {
- cy.get('.v-list-item')
- .contains(state.name)
- .click({ force: true })
- })
- // Click outside to close dropdown
- cy.get('noscript')
- .click({ force: true })
- cy.get('[data-cy="filter task state"]')
- .contains('.v-select__selection', '(+')
- })
-
describe('Toggle families', () => {
it('Toggles between flat and hierarchical modes', () => {
cy.visit('/#/tree/one')
cy.get('.node-data-family').should('have.length', 3)
- cy.get('[data-cy=toggle-families]').click()
+ cy.get('[data-cy=control-flat]').click()
cy.get('.node-data-family').should('have.length', 0)
})
})
diff --git a/tests/e2e/specs/workspace.cy.js b/tests/e2e/specs/workspace.cy.js
index 07c0c27fe..56b52cfb0 100644
--- a/tests/e2e/specs/workspace.cy.js
+++ b/tests/e2e/specs/workspace.cy.js
@@ -118,7 +118,7 @@ describe('Workspace view and component/widget', () => {
.should('have.length', 2)
cy.get('.c-tree')
.should('be.visible')
- .find('[data-cy=filter-id] input')
+ .find('[data-cy=control-taskIDFilter] input')
.should('have.value', 'GOOD')
cy.get('.c-table')
.should('be.visible')
@@ -141,7 +141,8 @@ describe('Workspace view and component/widget', () => {
// (It takes a moment for the split pane to render properly - should('be.visible') does not wait for this unfortunately)
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(100)
- cy.get('.c-tree [data-cy=filter-id] input')
+ cy.get('.c-tree')
+ .find('[data-cy=control-taskIDFilter] input')
.type('GOOD')
expectRememberedLayout()
diff --git a/tests/unit/components/cylc/common/filter.spec.js b/tests/unit/components/cylc/common/filter.spec.js
index cc965ad74..3d57f4f01 100644
--- a/tests/unit/components/cylc/common/filter.spec.js
+++ b/tests/unit/components/cylc/common/filter.spec.js
@@ -15,7 +15,12 @@
* along with this program. If not, see
.
*/
-import { matchID, matchNode, matchState } from '@/components/cylc/common/filter'
+import {
+ globToRegex,
+ matchID,
+ matchNode,
+ matchState,
+} from '@/components/cylc/common/filter'
const taskNode = {
id: '~user/one//20000102T0000Z/succeeded',
@@ -35,9 +40,12 @@ const taskNode = {
id: '~user/one//20000102T0000Z/succeeded',
name: 'succeeded',
state: 'succeeded',
- isHeld: false,
+ isHeld: true,
isQueued: false,
isRunahead: false,
+ isRetry: true,
+ isWallclock: false,
+ isXtriggered: false,
cyclePoint: '20000102T0000Z',
firstParent: {
id: '~user/one//20000102T0000Z/SUCCEEDED',
@@ -53,19 +61,21 @@ const taskNode = {
describe('task filtering', () => {
describe('matchID', () => {
it.each([
- { node: taskNode, id: '', expected: true },
- { node: taskNode, id: ' ', expected: true },
- { node: taskNode, id: '2000', expected: true },
- { node: taskNode, id: 'succeeded', expected: true },
- { node: taskNode, id: '20000102T0000Z/suc', expected: true },
- { node: taskNode, id: '2001', expected: false },
- { node: taskNode, id: 'darmok', expected: false },
+ { node: taskNode, regex: null, expected: true },
+ { node: taskNode, regex: /2000/, expected: true },
+ { node: taskNode, regex: /succeeded/, expected: true },
+ { node: taskNode, regex: /20000102T0000Z\/suc/, expected: true },
+ { node: taskNode, regex: /2001/, expected: false },
+ { node: taskNode, regex: globToRegex('*'), expected: true },
+ { node: taskNode, regex: globToRegex('suc*'), expected: true },
+ { node: taskNode, regex: /darmok/, expected: false },
+ { node: taskNode, regex: globToRegex('darmok*'), expected: false },
// Only matches relative ID:
- { node: taskNode, id: 'user/one', expected: false },
+ { node: taskNode, regex: /user\/one/, expected: false },
// Case sensitive:
- { node: taskNode, id: 'SUC', expected: false },
- ])('matchID(<$node.id>, $id)', ({ node, id, expected }) => {
- expect(matchID(node, id)).toBe(expected)
+ { node: taskNode, regex: /SUC/, expected: false },
+ ])('matchID(<$node.id>, $regex)', ({ node, regex, expected }) => {
+ expect(matchID(node, regex)).toBe(expected)
})
})
@@ -76,21 +86,61 @@ describe('task filtering', () => {
{ node: taskNode, states: ['succeeded'], expected: true },
{ node: taskNode, states: ['succeeded', 'failed'], expected: true },
{ node: taskNode, states: ['failed'], expected: false },
- ])('matchState(<$node.node.state>, $states)', ({ node, states, expected }) => {
- expect(matchState(node, states)).toBe(expected)
+ { node: taskNode, states: ['waiting'], waitingStateModifiers: ['isRetry'], expected: false },
+ { node: taskNode, genericModifiers: ['isHeld'], expected: true },
+ { node: taskNode, genericModifiers: ['isHeld', 'isRunahead'], expected: true },
+ { node: taskNode, genericModifiers: ['isRunahead'], expected: false },
+ { node: taskNode, states: ['succeeded'], genericModifiers: ['isHeld'], expected: true },
+ { node: taskNode, states: ['waiting'], genericModifiers: ['isHeld'], expected: false },
+ ])('matchState(<$node.node.state>, $states)', ({
+ node,
+ states,
+ waitingStateModifiers,
+ genericModifiers,
+ expected,
+ }) => {
+ expect(matchState(
+ node,
+ states,
+ waitingStateModifiers,
+ genericModifiers,
+ )).toBe(expected)
})
})
describe('matchNode', () => {
it.each([
- { node: taskNode, id: '', states: [], expected: true },
- { node: taskNode, id: '2000', states: [], expected: true },
- { node: taskNode, id: '', states: ['succeeded', 'failed'], expected: true },
- { node: taskNode, id: '2000', states: ['succeeded', 'failed'], expected: true },
- { node: taskNode, id: 'darmok', states: ['succeeded', 'failed'], expected: false },
- { node: taskNode, id: '2000', states: ['failed'], expected: false },
- ])('matchNode(<$node.id>, $id, $states)', ({ node, id, states, expected }) => {
- expect(matchNode(node, id, states)).toBe(expected)
+ { node: taskNode, regex: null, states: [], expected: true },
+ { node: taskNode, regex: /2000/, states: [], expected: true },
+ { node: taskNode, regex: /2000/, states: ['succeeded', 'failed'], expected: true },
+ { node: taskNode, regex: /darmok/, states: ['succeeded', 'failed'], expected: false },
+ { node: taskNode, regex: /2000/, states: ['failed'], expected: false },
+ ])('matchNode(<$node.id>, $regex, $states)', ({ node, regex, states, expected }) => {
+ expect(matchNode(node, regex, states)).toBe(expected)
+ })
+ })
+
+ describe('globToRegex', () => {
+ it.each([
+ // no pattern specified
+ { glob: '', regex: null },
+ { glob: ' ', regex: null },
+
+ // plain text
+ { glob: 'foo', regex: /foo/ },
+
+ // globs
+ { glob: 'f*o', regex: /f.*o/ },
+ { glob: 'f?o', regex: /f.o/ },
+ { glob: 'f[o]o', regex: /f[o]o/ },
+ { glob: 'f[!o]o', regex: /f[^o]o/ },
+
+ // regex escapes
+ { glob: '.*', regex: /\..*/ },
+ { glob: '(x)', regex: /\(x\)/ },
+ { glob: '\\w\\d\\s', regex: /\\w\\d\\s/ },
+ ])('globToRegex($glob) => $regex', ({ glob, regex }) => {
+ expect(String(globToRegex(glob))).toBe(String(regex))
})
})
})
diff --git a/tests/unit/views/table.vue.spec.js b/tests/unit/views/table.vue.spec.js
index 8314cc4ea..14022cae6 100644
--- a/tests/unit/views/table.vue.spec.js
+++ b/tests/unit/views/table.vue.spec.js
@@ -124,11 +124,19 @@ describe('Table view', () => {
})
it('should filter by ID', async () => {
+ // plain ID
wrapper.vm.tasksFilter = {
id: 'taskA'
}
await nextTick()
expect(wrapper.vm.filteredTasks.length).to.equal(1)
+
+ // glob ID
+ wrapper.vm.tasksFilter = {
+ id: 'task[A]'
+ }
+ await nextTick()
+ expect(wrapper.vm.filteredTasks.length).to.equal(1)
})
it('should filter by task state', async () => {
diff --git a/tests/unit/views/tree.vue.spec.js b/tests/unit/views/tree.vue.spec.js
index a8bd5a38f..421ec7abf 100644
--- a/tests/unit/views/tree.vue.spec.js
+++ b/tests/unit/views/tree.vue.spec.js
@@ -55,7 +55,7 @@ const workflowNode = {
{
...expandID('~user/workflow1//1/foo'),
type: 'task',
- node: { state: 'failed' },
+ node: { state: 'failed', isHeld: true },
children: [
{
...expandID('~user/workflow1//1/foo/1'),
@@ -114,19 +114,33 @@ describe('Tree view', () => {
})
it.each([
+ // the task should be displayed
{ tasksFilter: { id: 'foo' }, filteredOut: false },
{ tasksFilter: { states: ['failed'] }, filteredOut: false },
{ tasksFilter: { id: 'foo', states: ['failed'] }, filteredOut: false },
+ { tasksFilter: { id: 'foo', states: ['isHeld'] }, filteredOut: false },
+ { tasksFilter: { id: 'foo', states: ['failed', 'isHeld'] }, filteredOut: false },
+ { tasksFilter: { id: 'f*', states: ['failed', 'isHeld'] }, filteredOut: false },
+ { tasksFilter: { id: 'f?', states: ['failed', 'isHeld'] }, filteredOut: false },
+ { tasksFilter: { id: 'f[o]o', states: ['failed', 'isHeld'] }, filteredOut: false },
+ { tasksFilter: { id: 'f[!z]o', states: ['failed', 'isHeld'] }, filteredOut: false },
+ // the task should *not* be displayed
{ tasksFilter: { id: 'asdf' }, filteredOut: true },
{ tasksFilter: { states: ['running'] }, filteredOut: true },
{ tasksFilter: { id: 'foo', states: ['running'] }, filteredOut: true },
{ tasksFilter: { id: 'asdf', states: ['failed'] }, filteredOut: true },
+ { tasksFilter: { id: 'asdf', states: ['failed', 'isRunahead'] }, filteredOut: true },
+ { tasksFilter: { id: 'asdf*' }, filteredOut: true },
+ { tasksFilter: { id: 'asdf?' }, filteredOut: true },
+ { tasksFilter: { id: 'asd[f]' }, filteredOut: true },
+ { tasksFilter: { id: 'asd[!f]' }, filteredOut: true },
])('filters by $tasksFilter', async ({ tasksFilter, filteredOut }) => {
const wrapper = mountFunction()
wrapper.vm.tasksFilter = tasksFilter
await nextTick()
- expect(wrapper.vm.filterState).toMatchObject(tasksFilter)
+ expect(wrapper.vm.filterState[0]).toMatchObject(tasksFilter.id)
+ expect(wrapper.vm.filterState[1]).toMatchObject(tasksFilter.states)
const filteredOutNodesCache = new Map()
expect(wrapper.vm.filterNode(workflowNode, filteredOutNodesCache)).toEqual(!filteredOut)
expect(getIDMap(filteredOutNodesCache)).toEqual({
diff --git a/vite.config.js b/vite.config.js
index f7aec3560..b552c78e4 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -88,7 +88,8 @@ export default defineConfig(({ mode }) => {
},
watch: {
ignored: [
- path.resolve(__dirname, './coverage')
+ path.resolve(__dirname, './coverage'),
+ path.resolve(__dirname, '**/.nfs*'),
]
},
warmup: {
diff --git a/yarn.lock b/yarn.lock
index ffa582eaf..539d82138 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3957,9 +3957,9 @@ __metadata:
linkType: hard
"caniuse-lite@npm:^1.0.30001524, caniuse-lite@npm:^1.0.30001718":
- version: 1.0.30001723
- resolution: "caniuse-lite@npm:1.0.30001723"
- checksum: 10c0/e019503061759b96017c4d27ddd7ca1b48533eabcd0431b51d2e3156f99f6b031075e46c279c0db63424cdfc874bba992caec2db51b922a0f945e686246886f6
+ version: 1.0.30001757
+ resolution: "caniuse-lite@npm:1.0.30001757"
+ checksum: 10c0/3ccb71fa2bf1f8c96ff1bf9b918b08806fed33307e20a3ce3259155fda131eaf96cfcd88d3d309c8fd7f8285cc71d89a3b93648a1c04814da31c301f98508d42
languageName: node
linkType: hard