From 3a9057a89c57223f9bf7b427c2c26e3702ffefb8 Mon Sep 17 00:00:00 2001 From: Jai Bhagat Date: Tue, 28 Dec 2021 11:08:12 -0500 Subject: [PATCH] ui: prettify js files --- ui/.storybook/babel.config.js | 11 +- ui/app/abilities/abstract.js | 46 ++- ui/app/abilities/agent.js | 6 +- ui/app/abilities/client.js | 15 +- ui/app/abilities/job.js | 6 +- ui/app/abilities/recommendation.js | 6 +- ui/app/adapters/allocation.js | 13 +- ui/app/adapters/application.js | 4 +- ui/app/adapters/deployment.js | 5 +- ui/app/adapters/job-version.js | 5 +- ui/app/adapters/job.js | 15 +- ui/app/adapters/node.js | 5 +- ui/app/adapters/recommendation-summary.js | 17 +- ui/app/adapters/token.js | 5 +- ui/app/adapters/watchable-namespace-ids.js | 3 +- ui/app/adapters/watchable.js | 54 ++- ui/app/components/allocation-row.js | 4 +- ui/app/components/allocation-stat.js | 6 +- ui/app/components/chart-primitives/area.js | 4 +- ui/app/components/children-status-bar.js | 18 +- ui/app/components/client-node-row.js | 4 +- ui/app/components/das/dismissed.js | 3 +- .../das/recommendation-accordion.js | 4 +- ui/app/components/das/recommendation-card.js | 77 ++-- ui/app/components/das/recommendation-chart.js | 48 ++- ui/app/components/distribution-bar.js | 30 +- ui/app/components/exec/task-group-parent.js | 18 +- ui/app/components/flex-masonry.js | 10 +- ui/app/components/fs/browser.js | 11 +- ui/app/components/fs/file.js | 14 +- ui/app/components/global-search/control.js | 53 ++- ui/app/components/gutter-menu.js | 4 +- ui/app/components/job-client-status-bar.js | 12 +- ui/app/components/job-diff.js | 6 +- ui/app/components/job-dispatch.js | 10 +- ui/app/components/job-editor.js | 5 +- ui/app/components/job-version.js | 10 +- ui/app/components/job-versions-stream.js | 4 +- ui/app/components/line-chart.js | 26 +- ui/app/components/multi-select-dropdown.js | 8 +- ui/app/components/popover-menu.js | 4 +- ui/app/components/primary-metric/node.js | 5 +- ui/app/components/primary-metric/task.js | 4 +- ui/app/components/scale-events-chart.js | 5 +- ui/app/components/server-agent-row.js | 9 +- ui/app/components/stats-time-series.js | 8 +- ui/app/components/stepper-input.js | 11 +- ui/app/components/streaming-file.js | 9 +- ui/app/components/task-group-row.js | 3 +- ui/app/components/task-log.js | 4 +- ui/app/components/toggle.js | 6 +- ui/app/components/tooltip.js | 4 +- ui/app/components/topo-viz.js | 67 +++- ui/app/components/topo-viz/datacenter.js | 3 +- ui/app/components/topo-viz/node.js | 19 +- ui/app/components/two-step-button.js | 5 +- ui/app/controllers/clients/client/index.js | 41 +- ui/app/controllers/clients/index.js | 46 ++- ui/app/controllers/csi/plugins/index.js | 5 +- .../csi/plugins/plugin/allocations.js | 13 +- ui/app/controllers/exec.js | 28 +- ui/app/controllers/jobs/index.js | 29 +- ui/app/controllers/jobs/job/allocations.js | 45 ++- ui/app/controllers/jobs/job/clients.js | 36 +- ui/app/controllers/jobs/job/definition.js | 4 +- ui/app/controllers/jobs/job/deployments.js | 4 +- ui/app/controllers/jobs/job/index.js | 10 +- ui/app/controllers/jobs/job/task-group.js | 38 +- ui/app/controllers/jobs/job/versions.js | 8 +- ui/app/controllers/optimize.js | 40 +- ui/app/controllers/topology.js | 34 +- ui/app/helpers/bind.js | 5 +- ui/app/helpers/is-object.js | 3 +- ui/app/helpers/x-icon.js | 4 +- ui/app/mixins/searchable.js | 14 +- ui/app/mixins/sortable-factory.js | 11 +- ui/app/mixins/window-resizable.js | 5 +- ui/app/mixins/with-watchers.js | 5 +- ui/app/models/allocation.js | 12 +- ui/app/models/deployment.js | 15 +- ui/app/models/evaluation.js | 3 +- ui/app/models/job-plan.js | 3 +- ui/app/models/job.js | 23 +- ui/app/models/node.js | 4 +- ui/app/models/recommendation-summary.js | 15 +- ui/app/models/recommendation.js | 6 +- ui/app/models/task-group-scale.js | 5 +- ui/app/models/task-group.js | 24 +- ui/app/models/task-state.js | 6 +- ui/app/models/task.js | 6 +- ui/app/models/volume.js | 5 +- ui/app/routes/allocations/allocation/fs.js | 17 +- ui/app/routes/allocations/allocation/index.js | 3 +- ui/app/routes/allocations/allocation/task.js | 4 +- .../routes/allocations/allocation/task/fs.js | 22 +- ui/app/routes/application.js | 8 +- ui/app/routes/clients/client/index.js | 5 +- ui/app/routes/csi/plugins.js | 4 +- ui/app/routes/csi/plugins/plugin.js | 4 +- ui/app/routes/csi/volumes/index.js | 10 +- ui/app/routes/csi/volumes/volume.js | 4 +- ui/app/routes/exec.js | 5 +- ui/app/routes/jobs/index.js | 14 +- ui/app/routes/jobs/job/clients.js | 6 +- ui/app/routes/jobs/job/deployments.js | 5 +- ui/app/routes/jobs/job/index.js | 18 +- ui/app/routes/jobs/job/task-group.js | 28 +- ui/app/routes/jobs/job/versions.js | 5 +- ui/app/routes/jobs/run.js | 6 +- ui/app/routes/optimize/summary.js | 7 +- ui/app/serializers/agent.js | 18 +- ui/app/serializers/allocation.js | 28 +- ui/app/serializers/application.js | 4 +- ui/app/serializers/deployment.js | 12 +- ui/app/serializers/job-plan.js | 4 +- ui/app/serializers/job-summary.js | 3 +- ui/app/serializers/job.js | 13 +- ui/app/serializers/node.js | 7 +- ui/app/serializers/recommendation-summary.js | 16 +- ui/app/serializers/recommendation.js | 5 +- ui/app/serializers/volume.js | 7 +- ui/app/services/sockets.js | 6 +- ui/app/services/stats-trackers-registry.js | 10 +- ui/app/services/system.js | 27 +- ui/app/services/user-settings.js | 3 +- ui/app/utils/classes/abstract-logger.js | 22 +- .../utils/classes/abstract-stats-tracker.js | 4 +- .../utils/classes/allocation-stats-tracker.js | 15 +- .../classes/exec-socket-xterm-adapter.js | 12 +- ui/app/utils/classes/log.js | 20 +- ui/app/utils/classes/promise-array.js | 4 +- ui/app/utils/classes/promise-object.js | 4 +- ui/app/utils/format-duration.js | 33 +- ui/app/utils/generate-exec-url.js | 30 +- .../utils/properties/glimmer-style-string.js | 4 +- ui/app/utils/properties/style-string.js | 4 +- ui/app/utils/resources-diffs.js | 18 +- ui/app/utils/stream-frames.js | 4 +- ui/config/deprecation-workflow.js | 5 +- ui/config/targets.js | 6 +- ui/ember-cli-build.js | 5 +- ui/server/index.js | 4 +- ui/server/proxies/api.js | 5 +- ui/stories/charts/progress-bar.stories.js | 11 +- .../charts/stats-time-series.stories.js | 8 +- ui/stories/components/copy-button.stories.js | 5 +- ui/stories/components/diff-viewer.stories.js | 314 +++++++++++++-- ui/stories/components/json-viewer.stories.js | 9 +- ui/stories/components/table.stories.js | 378 +++++++++++++++--- ui/testem.js | 6 +- ui/tests/acceptance/allocation-detail-test.js | 211 +++++++--- ui/tests/acceptance/allocation-fs-test.js | 23 +- .../acceptance/application-errors-test.js | 5 +- ui/tests/acceptance/behaviors/fs.js | 91 ++++- .../acceptance/behaviors/page-size-select.js | 7 +- ui/tests/acceptance/client-detail-test.js | 216 ++++++++-- ui/tests/acceptance/client-monitor-test.js | 21 +- ui/tests/acceptance/clients-list-test.js | 86 +++- ui/tests/acceptance/exec-test.js | 68 +++- ui/tests/acceptance/job-allocations-test.js | 56 ++- ui/tests/acceptance/job-clients-test.js | 17 +- ui/tests/acceptance/job-definition-test.js | 40 +- ui/tests/acceptance/job-deployments-test.js | 98 ++++- ui/tests/acceptance/job-detail-test.js | 165 +++++--- ui/tests/acceptance/job-dispatch-test.js | 35 +- ui/tests/acceptance/job-evaluations-test.js | 23 +- ui/tests/acceptance/job-versions-test.js | 31 +- ui/tests/acceptance/jobs-list-test.js | 131 ++++-- ui/tests/acceptance/optimize-test.js | 113 ++++-- .../acceptance/plugin-allocations-test.js | 25 +- ui/tests/acceptance/plugin-detail-test.js | 98 +++-- ui/tests/acceptance/plugins-list-test.js | 17 +- ui/tests/acceptance/proxy-test.js | 6 +- ui/tests/acceptance/regions-test.js | 32 +- ui/tests/acceptance/search-test.js | 15 +- ui/tests/acceptance/server-detail-test.js | 16 +- ui/tests/acceptance/servers-list-test.js | 18 +- ui/tests/acceptance/task-detail-test.js | 198 ++++++--- ui/tests/acceptance/task-fs-test.js | 41 +- ui/tests/acceptance/task-group-detail-test.js | 299 +++++++++----- ui/tests/acceptance/task-logs-test.js | 19 +- ui/tests/acceptance/token-test.js | 56 ++- ui/tests/acceptance/topology-test.js | 103 +++-- ui/tests/acceptance/volume-detail-test.js | 55 ++- ui/tests/acceptance/volumes-list-test.js | 31 +- ui/tests/helpers/glimmer-factory.js | 5 +- ui/tests/helpers/module-for-job.js | 81 +++- .../components/agent-monitor-test.js | 33 +- .../components/allocation-row-test.js | 15 +- .../components/attributes-table-test.js | 21 +- .../components/copy-button-test.js | 5 +- .../components/das/dismissed-test.js | 5 +- .../das/recommendation-card-test.js | 79 ++-- .../components/flex-masonry-test.js | 9 +- .../integration/components/fs/file-test.js | 28 +- .../integration/components/image-file-test.js | 10 +- .../components/job-client-status-bar-test.js | 6 +- .../integration/components/job-diff-test.js | 36 +- .../integration/components/job-editor-test.js | 85 +++- .../components/job-page/helpers.js | 10 +- .../components/job-page/parts/body-test.js | 8 +- .../job-page/parts/children-test.js | 15 +- .../job-page/parts/latest-deployment-test.js | 282 +++++++------ .../job-page/parts/placement-failures-test.js | 143 ++++--- .../components/job-page/parts/summary-test.js | 35 +- .../job-page/parts/task-groups-test.js | 233 ++++++----- .../components/job-page/periodic-test.js | 21 +- .../components/job-page/service-test.js | 34 +- .../components/lifecycle-chart-test.js | 8 +- .../integration/components/line-chart-test.js | 31 +- .../components/list-pagination-test.js | 56 ++- .../integration/components/list-table-test.js | 42 +- .../components/multi-select-dropdown-test.js | 108 ++++- .../components/page-layout-test.js | 15 +- .../components/placement-failure-test.js | 14 +- .../components/plugin-allocation-row-test.js | 38 +- .../primary-metric/allocation-test.js | 9 +- .../primary-metric/primary-metric.js | 27 +- .../components/primary-metric/task-test.js | 3 +- .../reschedule-event-timeline-test.js | 17 +- .../components/scale-events-accordion-test.js | 46 ++- .../components/single-select-dropdown-test.js | 9 +- .../components/stepper-input-test.js | 21 +- .../components/streaming-file-test.js | 8 +- .../components/task-group-row-test.js | 4 +- .../integration/components/task-log-test.js | 134 +++++-- .../integration/components/topo-viz-test.js | 19 +- .../components/topo-viz/datacenter-test.js | 24 +- .../components/topo-viz/node-test.js | 31 +- .../components/two-step-button-test.js | 38 +- .../exec-command-editor-xterm-adapter-test.js | 166 ++++---- .../util/exec-socket-xterm-adapter-test.js | 19 +- ui/tests/pages/allocations/detail.js | 5 +- ui/tests/pages/clients/detail.js | 62 ++- ui/tests/pages/clients/monitor.js | 13 +- ui/tests/pages/components/allocations.js | 22 +- ui/tests/pages/components/facet.js | 5 +- ui/tests/pages/components/page-size-select.js | 12 +- ui/tests/pages/components/popover-menu.js | 8 +- .../pages/components/recommendation-card.js | 8 +- ui/tests/pages/components/toggle.js | 9 +- ui/tests/pages/components/topo-viz.js | 9 +- ui/tests/pages/components/two-step-button.js | 8 +- ui/tests/pages/exec.js | 4 +- ui/tests/pages/jobs/detail.js | 37 +- ui/tests/pages/jobs/job/evaluations.js | 9 +- ui/tests/pages/jobs/job/task-group.js | 41 +- ui/tests/pages/jobs/job/versions.js | 8 +- ui/tests/pages/optimize.js | 27 +- ui/tests/pages/servers/detail.js | 9 +- ui/tests/pages/servers/list.js | 8 +- ui/tests/pages/servers/monitor.js | 13 +- ui/tests/pages/storage/plugins/detail.js | 20 +- .../storage/plugins/plugin/allocations.js | 8 +- ui/tests/unit/abilities/allocation-test.js | 32 +- ui/tests/unit/abilities/job-test.js | 36 +- .../unit/abilities/recommendation-test.js | 122 +++--- ui/tests/unit/adapters/allocation-test.js | 41 +- ui/tests/unit/adapters/deployment-test.js | 19 +- ui/tests/unit/adapters/job-test.js | 20 +- ui/tests/unit/adapters/node-test.js | 25 +- ui/tests/unit/adapters/volume-test.js | 69 +++- ui/tests/unit/components/line-chart-test.js | 12 +- .../unit/components/stats-time-series-test.js | 19 +- ui/tests/unit/components/tooltip-test.js | 4 +- ui/tests/unit/components/topo-viz-test.js | 61 ++- ui/tests/unit/mixins/searchable-test.js | 69 +++- ui/tests/unit/models/task-group-test.js | 4 +- ui/tests/unit/serializers/allocation-test.js | 10 +- ui/tests/unit/serializers/application-test.js | 10 +- ui/tests/unit/serializers/deployment-test.js | 5 +- ui/tests/unit/serializers/evaluation-test.js | 5 +- ui/tests/unit/serializers/job-plan-test.js | 5 +- ui/tests/unit/serializers/job-summary-test.js | 5 +- ui/tests/unit/serializers/job-test.js | 5 +- ui/tests/unit/serializers/node-test.js | 16 +- .../recommendation-summary-test.js | 6 +- ui/tests/unit/serializers/scale-event-test.js | 5 +- ui/tests/unit/serializers/volume-test.js | 5 +- .../services/stats-trackers-registry-test.js | 45 ++- .../utils/allocation-stats-tracker-test.js | 69 +++- .../behaviors/stats-tracker-frame-missing.js | 34 +- ui/tests/unit/utils/format-duration-test.js | 15 +- ui/tests/unit/utils/generate-exec-url-test.js | 45 ++- ui/tests/unit/utils/log-test.js | 29 +- .../utils/message-from-adapter-error-test.js | 5 +- .../unit/utils/node-stats-tracker-test.js | 41 +- ui/tests/unit/utils/rolling-array-test.js | 8 +- ui/tests/unit/utils/stream-logger-test.js | 4 +- ui/tests/unit/utils/units-test.js | 84 +++- .../utils/ember-power-select-extensions.js | 27 +- 291 files changed, 6362 insertions(+), 2145 deletions(-) diff --git a/ui/.storybook/babel.config.js b/ui/.storybook/babel.config.js index 5dd544f2a..b69a0355e 100644 --- a/ui/.storybook/babel.config.js +++ b/ui/.storybook/babel.config.js @@ -14,7 +14,11 @@ module.exports = { shippedProposals: true, useBuiltIns: 'usage', corejs: '3', - targets: ['last 1 Chrome versions', 'last 1 Firefox versions', 'last 1 Safari versions'], + targets: [ + 'last 1 Chrome versions', + 'last 1 Firefox versions', + 'last 1 Safari versions', + ], }, ], ], @@ -27,7 +31,10 @@ module.exports = { ], ['@babel/plugin-proposal-class-properties', { loose: true }], '@babel/plugin-syntax-dynamic-import', - ['@babel/plugin-proposal-object-rest-spread', { loose: true, useBuiltIns: true }], + [ + '@babel/plugin-proposal-object-rest-spread', + { loose: true, useBuiltIns: true }, + ], 'babel-plugin-macros', ['emotion', { sourceMap: true, autoLabel: true }], [ diff --git a/ui/app/abilities/abstract.js b/ui/app/abilities/abstract.js index dba7f7a8f..d1bccf543 100644 --- a/ui/app/abilities/abstract.js +++ b/ui/app/abilities/abstract.js @@ -26,17 +26,26 @@ export default class Abstract extends Ability { get rulesForNamespace() { let namespace = this._namespace; - return (this.get('token.selfTokenPolicies') || []).toArray().reduce((rules, policy) => { - let policyNamespaces = get(policy, 'rulesJSON.Namespaces') || []; + return (this.get('token.selfTokenPolicies') || []) + .toArray() + .reduce((rules, policy) => { + let policyNamespaces = get(policy, 'rulesJSON.Namespaces') || []; - let matchingNamespace = this._findMatchingNamespace(policyNamespaces, namespace); + let matchingNamespace = this._findMatchingNamespace( + policyNamespaces, + namespace + ); - if (matchingNamespace) { - rules.push(policyNamespaces.find((namespace) => namespace.Name === matchingNamespace)); - } + if (matchingNamespace) { + rules.push( + policyNamespaces.find( + (namespace) => namespace.Name === matchingNamespace + ) + ); + } - return rules; - }, []); + return rules; + }, []); } @computed('token.selfTokenPolicies.[]') @@ -44,9 +53,11 @@ export default class Abstract extends Ability { return (this.get('token.selfTokenPolicies') || []) .toArray() .reduce((allCapabilities, policy) => { - (get(policy, 'rulesJSON.Namespaces') || []).forEach(({ Capabilities }) => { - allCapabilities = allCapabilities.concat(Capabilities); - }); + (get(policy, 'rulesJSON.Namespaces') || []).forEach( + ({ Capabilities }) => { + allCapabilities = allCapabilities.concat(Capabilities); + } + ); return allCapabilities; }, []); } @@ -76,12 +87,16 @@ export default class Abstract extends Ability { return namespace; } - let globNamespaceNames = namespaceNames.filter((namespaceName) => namespaceName.includes('*')); + let globNamespaceNames = namespaceNames.filter((namespaceName) => + namespaceName.includes('*') + ); let matchingNamespaceName = globNamespaceNames.reduce( (mostMatching, namespaceName) => { // Convert * wildcards to .* for regex matching - let namespaceNameRegExp = new RegExp(namespaceName.replace(/\*/g, '.*')); + let namespaceNameRegExp = new RegExp( + namespaceName.replace(/\*/g, '.*') + ); let characterDifference = namespace.length - namespaceName.length; if ( @@ -96,7 +111,10 @@ export default class Abstract extends Ability { return mostMatching; } }, - { mostMatchingNamespaceName: null, mostMatchingCharacterDifference: Number.MAX_SAFE_INTEGER } + { + mostMatchingNamespaceName: null, + mostMatchingCharacterDifference: Number.MAX_SAFE_INTEGER, + } ).mostMatchingNamespaceName; if (matchingNamespaceName) { diff --git a/ui/app/abilities/agent.js b/ui/app/abilities/agent.js index 7535b5c01..21e65fce3 100644 --- a/ui/app/abilities/agent.js +++ b/ui/app/abilities/agent.js @@ -3,7 +3,11 @@ import { computed, get } from '@ember/object'; import { or } from '@ember/object/computed'; export default class Client extends AbstractAbility { - @or('bypassAuthorization', 'selfTokenIsManagement', 'policiesIncludeAgentReadOrWrite') + @or( + 'bypassAuthorization', + 'selfTokenIsManagement', + 'policiesIncludeAgentReadOrWrite' + ) canRead; @computed('token.selfTokenPolicies.[]') diff --git a/ui/app/abilities/client.js b/ui/app/abilities/client.js index f48eeb93e..e54dd159a 100644 --- a/ui/app/abilities/client.js +++ b/ui/app/abilities/client.js @@ -10,17 +10,26 @@ export default class Client extends AbstractAbility { @or('bypassAuthorization', 'selfTokenIsManagement', 'policiesIncludeNodeRead') canRead; - @or('bypassAuthorization', 'selfTokenIsManagement', 'policiesIncludeNodeWrite') + @or( + 'bypassAuthorization', + 'selfTokenIsManagement', + 'policiesIncludeNodeWrite' + ) canWrite; @computed('token.selfTokenPolicies.[]') get policiesIncludeNodeRead() { - return policiesIncludePermissions(this.get('token.selfTokenPolicies'), ['read', 'write']); + return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [ + 'read', + 'write' + ]); } @computed('token.selfTokenPolicies.[]') get policiesIncludeNodeWrite() { - return policiesIncludePermissions(this.get('token.selfTokenPolicies'), ['write']); + return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [ + 'write' + ]); } } diff --git a/ui/app/abilities/job.js b/ui/app/abilities/job.js index 02e175cb4..fbc8d982c 100644 --- a/ui/app/abilities/job.js +++ b/ui/app/abilities/job.js @@ -20,7 +20,11 @@ export default class Job extends AbstractAbility { @or('bypassAuthorization', 'selfTokenIsManagement') canListAll; - @or('bypassAuthorization', 'selfTokenIsManagement', 'policiesSupportDispatching') + @or( + 'bypassAuthorization', + 'selfTokenIsManagement', + 'policiesSupportDispatching' + ) canDispatch; @computed('rulesForNamespace.@each.capabilities') diff --git a/ui/app/abilities/recommendation.js b/ui/app/abilities/recommendation.js index 11decdb43..ce6f03f1d 100644 --- a/ui/app/abilities/recommendation.js +++ b/ui/app/abilities/recommendation.js @@ -6,7 +6,11 @@ export default class Recommendation extends AbstractAbility { @and('dynamicApplicationSizingIsPresent', 'hasPermissions') canAccept; - @or('bypassAuthorization', 'selfTokenIsManagement', 'policiesSupportAcceptingOnAnyNamespace') + @or( + 'bypassAuthorization', + 'selfTokenIsManagement', + 'policiesSupportAcceptingOnAnyNamespace' + ) hasPermissions; @computed('capabilitiesForAllNamespaces.[]') diff --git a/ui/app/adapters/allocation.js b/ui/app/adapters/allocation.js index 7714ffa64..64c1ef7da 100644 --- a/ui/app/adapters/allocation.js +++ b/ui/app/adapters/allocation.js @@ -14,13 +14,17 @@ export default class AllocationAdapter extends Watchable { ls(model, path) { return this.token - .authorizedRequest(`/v1/client/fs/ls/${model.id}?path=${encodeURIComponent(path)}`) + .authorizedRequest( + `/v1/client/fs/ls/${model.id}?path=${encodeURIComponent(path)}` + ) .then(handleFSResponse); } stat(model, path) { return this.token - .authorizedRequest(`/v1/client/fs/stat/${model.id}?path=${encodeURIComponent(path)}`) + .authorizedRequest( + `/v1/client/fs/stat/${model.id}?path=${encodeURIComponent(path)}` + ) .then(handleFSResponse); } } @@ -40,7 +44,10 @@ async function handleFSResponse(response) { function adapterAction(path, verb = 'POST') { return function (allocation) { - const url = addToPath(this.urlForFindRecord(allocation.id, 'allocation'), path); + const url = addToPath( + this.urlForFindRecord(allocation.id, 'allocation'), + path + ); return this.ajax(url, verb); }; } diff --git a/ui/app/adapters/application.js b/ui/app/adapters/application.js index 6ece9bc93..efe4efb0b 100644 --- a/ui/app/adapters/application.js +++ b/ui/app/adapters/application.js @@ -125,5 +125,7 @@ export default class ApplicationAdapter extends RESTAdapter { } function associateRegion(url, region) { - return url.indexOf('?') !== -1 ? `${url}®ion=${region}` : `${url}?region=${region}`; + return url.indexOf('?') !== -1 + ? `${url}®ion=${region}` + : `${url}?region=${region}`; } diff --git a/ui/app/adapters/deployment.js b/ui/app/adapters/deployment.js index d24628c36..8904038d0 100644 --- a/ui/app/adapters/deployment.js +++ b/ui/app/adapters/deployment.js @@ -13,7 +13,10 @@ export default class DeploymentAdapter extends Watchable { promote(deployment) { const id = deployment.get('id'); - const url = urlForAction(this.urlForFindRecord(id, 'deployment'), '/promote'); + const url = urlForAction( + this.urlForFindRecord(id, 'deployment'), + '/promote' + ); return this.ajax(url, 'POST', { data: { DeploymentId: id, diff --git a/ui/app/adapters/job-version.js b/ui/app/adapters/job-version.js index eb2393a94..fb9eba821 100644 --- a/ui/app/adapters/job-version.js +++ b/ui/app/adapters/job-version.js @@ -5,7 +5,10 @@ export default class JobVersionAdapter extends ApplicationAdapter { revertTo(jobVersion) { const jobAdapter = this.store.adapterFor('job'); - const url = addToPath(jobAdapter.urlForFindRecord(jobVersion.get('job.id'), 'job'), '/revert'); + const url = addToPath( + jobAdapter.urlForFindRecord(jobVersion.get('job.id'), 'job'), + '/revert' + ); const [jobName] = JSON.parse(jobVersion.get('job.id')); return this.ajax(url, 'POST', { diff --git a/ui/app/adapters/job.js b/ui/app/adapters/job.js index da3d1475d..94995fd8e 100644 --- a/ui/app/adapters/job.js +++ b/ui/app/adapters/job.js @@ -14,7 +14,10 @@ export default class JobAdapter extends WatchableNamespaceIDs { forcePeriodic(job) { if (job.get('periodic')) { - const url = addToPath(this.urlForFindRecord(job.get('id'), 'job'), '/periodic/force'); + const url = addToPath( + this.urlForFindRecord(job.get('id'), 'job'), + '/periodic/force' + ); return this.ajax(url, 'POST'); } } @@ -71,7 +74,10 @@ export default class JobAdapter extends WatchableNamespaceIDs { } scale(job, group, count, message) { - const url = addToPath(this.urlForFindRecord(job.get('id'), 'job'), '/scale'); + const url = addToPath( + this.urlForFindRecord(job.get('id'), 'job'), + '/scale' + ); return this.ajax(url, 'POST', { data: { Count: count, @@ -87,7 +93,10 @@ export default class JobAdapter extends WatchableNamespaceIDs { } dispatch(job, meta, payload) { - const url = addToPath(this.urlForFindRecord(job.get('id'), 'job'), '/dispatch'); + const url = addToPath( + this.urlForFindRecord(job.get('id'), 'job'), + '/dispatch' + ); return this.ajax(url, 'POST', { data: { Payload: base64EncodeString(payload), diff --git a/ui/app/adapters/node.js b/ui/app/adapters/node.js index 746f51f6e..fdb085a2c 100644 --- a/ui/app/adapters/node.js +++ b/ui/app/adapters/node.js @@ -11,7 +11,10 @@ export default class NodeAdapter extends Watchable { } setEligibility(node, isEligible) { - const url = addToPath(this.urlForFindRecord(node.id, 'node'), '/eligibility'); + const url = addToPath( + this.urlForFindRecord(node.id, 'node'), + '/eligibility' + ); return this.ajax(url, 'POST', { data: { NodeID: node.id, diff --git a/ui/app/adapters/recommendation-summary.js b/ui/app/adapters/recommendation-summary.js index 42754d80b..71b807749 100644 --- a/ui/app/adapters/recommendation-summary.js +++ b/ui/app/adapters/recommendation-summary.js @@ -9,13 +9,20 @@ export default class RecommendationSummaryAdapter extends ApplicationAdapter { } updateRecord(store, type, snapshot) { - const url = `${super.urlForCreateRecord('recommendations', snapshot)}/apply`; + const url = `${super.urlForCreateRecord( + 'recommendations', + snapshot + )}/apply`; - const allRecommendationIds = snapshot.hasMany('recommendations').mapBy('id'); - const excludedRecommendationIds = (snapshot.hasMany('excludedRecommendations') || []).mapBy( - 'id' + const allRecommendationIds = snapshot + .hasMany('recommendations') + .mapBy('id'); + const excludedRecommendationIds = ( + snapshot.hasMany('excludedRecommendations') || [] + ).mapBy('id'); + const includedRecommendationIds = allRecommendationIds.removeObjects( + excludedRecommendationIds ); - const includedRecommendationIds = allRecommendationIds.removeObjects(excludedRecommendationIds); const data = { Apply: includedRecommendationIds, diff --git a/ui/app/adapters/token.js b/ui/app/adapters/token.js index 44f0d6469..253673534 100644 --- a/ui/app/adapters/token.js +++ b/ui/app/adapters/token.js @@ -30,7 +30,10 @@ export default class TokenAdapter extends ApplicationAdapter { tokens: [token], }); - return store.peekRecord('token', store.normalize('token', token).data.id); + return store.peekRecord( + 'token', + store.normalize('token', token).data.id + ); }) .catch(() => { throw new OTTExchangeError(); diff --git a/ui/app/adapters/watchable-namespace-ids.js b/ui/app/adapters/watchable-namespace-ids.js index 004097351..ffee65fcc 100644 --- a/ui/app/adapters/watchable-namespace-ids.js +++ b/ui/app/adapters/watchable-namespace-ids.js @@ -26,7 +26,8 @@ export default class WatchableNamespaceIDs extends Watchable { findRecord(store, type, id, snapshot) { const [, namespace] = JSON.parse(id); - const namespaceQuery = namespace && namespace !== 'default' ? { namespace } : {}; + const namespaceQuery = + namespace && namespace !== 'default' ? { namespace } : {}; return super.findRecord(store, type, id, snapshot, namespaceQuery); } diff --git a/ui/app/adapters/watchable.js b/ui/app/adapters/watchable.js index 2068ee1ec..b8eff658e 100644 --- a/ui/app/adapters/watchable.js +++ b/ui/app/adapters/watchable.js @@ -40,7 +40,10 @@ export default class Watchable extends ApplicationAdapter { params.index = this.watchList.getIndexFor(url); } - const signal = get(snapshotRecordArray || {}, 'adapterOptions.abortController.signal'); + const signal = get( + snapshotRecordArray || {}, + 'adapterOptions.abortController.signal' + ); return this.ajax(url, 'GET', { signal, data: params, @@ -48,9 +51,18 @@ export default class Watchable extends ApplicationAdapter { } findRecord(store, type, id, snapshot, additionalParams = {}) { - const originalUrl = this.buildURL(type.modelName, id, snapshot, 'findRecord'); + const originalUrl = this.buildURL( + type.modelName, + id, + snapshot, + 'findRecord' + ); let [url, params] = originalUrl.split('?'); - params = assign(queryString.parse(params) || {}, this.buildQuery(), additionalParams); + params = assign( + queryString.parse(params) || {}, + this.buildQuery(), + additionalParams + ); if (get(snapshot || {}, 'adapterOptions.watch')) { params.index = this.watchList.getIndexFor(originalUrl); @@ -68,15 +80,29 @@ export default class Watchable extends ApplicationAdapter { }); } - query(store, type, query, snapshotRecordArray, options, additionalParams = {}) { + query( + store, + type, + query, + snapshotRecordArray, + options, + additionalParams = {} + ) { const url = this.buildURL(type.modelName, null, null, 'query', query); let [urlPath, params] = url.split('?'); - params = assign(queryString.parse(params) || {}, this.buildQuery(), additionalParams, query); + params = assign( + queryString.parse(params) || {}, + this.buildQuery(), + additionalParams, + query + ); if (get(options, 'adapterOptions.watch')) { // The intended query without additional blocking query params is used // to track the appropriate query index. - params.index = this.watchList.getIndexFor(`${urlPath}?${queryString.stringify(query)}`); + params.index = this.watchList.getIndexFor( + `${urlPath}?${queryString.stringify(query)}` + ); } const signal = get(options, 'adapterOptions.abortController.signal'); @@ -88,7 +114,9 @@ export default class Watchable extends ApplicationAdapter { // Query params may not necessarily map one-to-one to attribute names. // Adapters are responsible for declaring param mappings. - const queryParamsToAttrs = Object.keys(adapter.queryParamsToAttrs || {}).map((key) => ({ + const queryParamsToAttrs = Object.keys( + adapter.queryParamsToAttrs || {} + ).map((key) => ({ queryParam: key, attr: adapter.queryParamsToAttrs[key], })); @@ -110,7 +138,11 @@ export default class Watchable extends ApplicationAdapter { }); } - reloadRelationship(model, relationshipName, options = { watch: false, abortController: null }) { + reloadRelationship( + model, + relationshipName, + options = { watch: false, abortController: null } + ) { const { watch, abortController } = options; const relationship = model.relationshipFor(relationshipName); if (relationship.kind !== 'belongsTo' && relationship.kind !== 'hasMany') { @@ -146,7 +178,11 @@ export default class Watchable extends ApplicationAdapter { : 'normalizeFindHasManyResponse'; const serializer = store.serializerFor(relationship.type); const modelClass = store.modelFor(relationship.type); - const normalizedData = serializer[normalizeMethod](store, modelClass, json); + const normalizedData = serializer[normalizeMethod]( + store, + modelClass, + json + ); store.push(normalizedData); }, (error) => { diff --git a/ui/app/components/allocation-row.js b/ui/app/components/allocation-row.js index 1d193141f..4eaddb3fd 100644 --- a/ui/app/components/allocation-row.js +++ b/ui/app/components/allocation-row.js @@ -85,7 +85,9 @@ async function qualifyAllocation() { // Make sure the allocation is a complete record and not a partial so we // can show information such as preemptions and rescheduled allocation. if (allocation.isPartial) { - await this.store.findRecord('allocation', allocation.id, { backgroundReload: false }); + await this.store.findRecord('allocation', allocation.id, { + backgroundReload: false, + }); } if (allocation.get('job.isPending')) { diff --git a/ui/app/components/allocation-stat.js b/ui/app/components/allocation-stat.js index b53531070..efac3ad62 100644 --- a/ui/app/components/allocation-stat.js +++ b/ui/app/components/allocation-stat.js @@ -42,8 +42,10 @@ export default class AllocationStat extends Component { @computed('metric', 'statsTracker.{reservedMemory,reservedCPU}') get formattedReserved() { - if (this.metric === 'memory') return formatBytes(this.statsTracker.reservedMemory, 'MiB'); - if (this.metric === 'cpu') return formatHertz(this.statsTracker.reservedCPU, 'MHz'); + if (this.metric === 'memory') + return formatBytes(this.statsTracker.reservedMemory, 'MiB'); + if (this.metric === 'cpu') + return formatHertz(this.statsTracker.reservedCPU, 'MHz'); return undefined; } } diff --git a/ui/app/components/chart-primitives/area.js b/ui/app/components/chart-primitives/area.js index b0f996936..ec4e21945 100644 --- a/ui/app/components/chart-primitives/area.js +++ b/ui/app/components/chart-primitives/area.js @@ -7,7 +7,9 @@ export default class ChartPrimitiveArea extends Component { get colorClass() { if (this.args.colorClass) return this.args.colorClass; if (this.args.colorScale && this.args.index != null) - return `${this.args.colorScale} ${this.args.colorScale}-${this.args.index + 1}`; + return `${this.args.colorScale} ${this.args.colorScale}-${ + this.args.index + 1 + }`; return 'is-primary'; } diff --git a/ui/app/components/children-status-bar.js b/ui/app/components/children-status-bar.js index 5ea7d6eb7..b64cbb351 100644 --- a/ui/app/components/children-status-bar.js +++ b/ui/app/components/children-status-bar.js @@ -16,10 +16,22 @@ export default class ChildrenStatusBar extends DistributionBar { return []; } - const children = this.job.getProperties('pendingChildren', 'runningChildren', 'deadChildren'); + const children = this.job.getProperties( + 'pendingChildren', + 'runningChildren', + 'deadChildren' + ); return [ - { label: 'Pending', value: children.pendingChildren, className: 'queued' }, - { label: 'Running', value: children.runningChildren, className: 'running' }, + { + label: 'Pending', + value: children.pendingChildren, + className: 'queued', + }, + { + label: 'Running', + value: children.runningChildren, + className: 'running', + }, { label: 'Dead', value: children.deadChildren, className: 'complete' }, ]; } diff --git a/ui/app/components/client-node-row.js b/ui/app/components/client-node-row.js index 5a6e4a648..013ffb4be 100644 --- a/ui/app/components/client-node-row.js +++ b/ui/app/components/client-node-row.js @@ -10,7 +10,9 @@ import classic from 'ember-classic-decorator'; @classic @tagName('tr') @classNames('client-node-row', 'is-interactive') -export default class ClientNodeRow extends Component.extend(WithVisibilityDetection) { +export default class ClientNodeRow extends Component.extend( + WithVisibilityDetection +) { @service store; node = null; diff --git a/ui/app/components/das/dismissed.js b/ui/app/components/das/dismissed.js index 85fa8e9f1..3fdefa6ec 100644 --- a/ui/app/components/das/dismissed.js +++ b/ui/app/components/das/dismissed.js @@ -4,7 +4,8 @@ import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; export default class DasDismissedComponent extends Component { - @localStorageProperty('nomadRecommendationDismssalUnderstood', false) explanationUnderstood; + @localStorageProperty('nomadRecommendationDismssalUnderstood', false) + explanationUnderstood; @tracked dismissInTheFuture = false; diff --git a/ui/app/components/das/recommendation-accordion.js b/ui/app/components/das/recommendation-accordion.js index 83fcdd121..75c0e1f13 100644 --- a/ui/app/components/das/recommendation-accordion.js +++ b/ui/app/components/das/recommendation-accordion.js @@ -13,7 +13,9 @@ export default class DasRecommendationAccordionComponent extends Component { @(task(function* () { this.closing = true; - this.animationContainerStyle = htmlSafe(`height: ${this.accordionElement.clientHeight}px`); + this.animationContainerStyle = htmlSafe( + `height: ${this.accordionElement.clientHeight}px` + ); yield timeout(10); diff --git a/ui/app/components/das/recommendation-card.js b/ui/app/components/das/recommendation-card.js index 908932890..7ab471631 100644 --- a/ui/app/components/das/recommendation-card.js +++ b/ui/app/components/das/recommendation-card.js @@ -93,35 +93,39 @@ export default class DasRecommendationCardComponent extends Component { get taskToggleRows() { const taskNameToTaskToggles = {}; - return this.args.summary.recommendations.reduce((taskToggleRows, recommendation) => { - let taskToggleRow = taskNameToTaskToggles[recommendation.task.name]; + return this.args.summary.recommendations.reduce( + (taskToggleRows, recommendation) => { + let taskToggleRow = taskNameToTaskToggles[recommendation.task.name]; - if (!taskToggleRow) { - taskToggleRow = { - recommendations: [], - task: recommendation.task, + if (!taskToggleRow) { + taskToggleRow = { + recommendations: [], + task: recommendation.task, + }; + + taskNameToTaskToggles[recommendation.task.name] = taskToggleRow; + taskToggleRows.push(taskToggleRow); + } + + const isCpu = recommendation.resource === 'CPU'; + const rowResourceProperty = isCpu ? 'cpu' : 'memory'; + + taskToggleRow[rowResourceProperty] = { + recommendation, + isActive: + !this.args.summary.excludedRecommendations.includes(recommendation), }; - taskNameToTaskToggles[recommendation.task.name] = taskToggleRow; - taskToggleRows.push(taskToggleRow); - } + if (isCpu) { + taskToggleRow.recommendations.unshift(recommendation); + } else { + taskToggleRow.recommendations.push(recommendation); + } - const isCpu = recommendation.resource === 'CPU'; - const rowResourceProperty = isCpu ? 'cpu' : 'memory'; - - taskToggleRow[rowResourceProperty] = { - recommendation, - isActive: !this.args.summary.excludedRecommendations.includes(recommendation), - }; - - if (isCpu) { - taskToggleRow.recommendations.unshift(recommendation); - } else { - taskToggleRow.recommendations.push(recommendation); - } - - return taskToggleRows; - }, []); + return taskToggleRows; + }, + [] + ); } get showToggleAllToggles() { @@ -129,23 +133,30 @@ export default class DasRecommendationCardComponent extends Component { } get allCpuToggleDisabled() { - return !this.args.summary.recommendations.filterBy('resource', 'CPU').length; + return !this.args.summary.recommendations.filterBy('resource', 'CPU') + .length; } get allMemoryToggleDisabled() { - return !this.args.summary.recommendations.filterBy('resource', 'MemoryMB').length; + return !this.args.summary.recommendations.filterBy('resource', 'MemoryMB') + .length; } get cannotAccept() { return ( - this.args.summary.excludedRecommendations.length == this.args.summary.recommendations.length + this.args.summary.excludedRecommendations.length == + this.args.summary.recommendations.length ); } get copyButtonLink() { - const path = this.router.urlFor('optimize.summary', this.args.summary.slug, { - queryParams: { namespace: this.args.summary.jobNamespace }, - }); + const path = this.router.urlFor( + 'optimize.summary', + this.args.summary.slug, + { + queryParams: { namespace: this.args.summary.jobNamespace }, + } + ); const { origin } = window.location; return `${origin}${path}`; @@ -185,7 +196,9 @@ export default class DasRecommendationCardComponent extends Component { @action dismiss() { this.storeCardHeight(); - this.args.summary.excludedRecommendations.pushObjects(this.args.summary.recommendations); + this.args.summary.excludedRecommendations.pushObjects( + this.args.summary.recommendations + ); this.args.summary .save() .then( diff --git a/ui/app/components/das/recommendation-chart.js b/ui/app/components/das/recommendation-chart.js index 6a22cfbbb..9fb82c8a1 100644 --- a/ui/app/components/das/recommendation-chart.js +++ b/ui/app/components/das/recommendation-chart.js @@ -64,10 +64,12 @@ export default class RecommendationChartComponent extends Component { edgeTickHeight = 23; centerTickOffset = 6; - centerY = this.tickTextHeight + this.centerTickOffset + this.edgeTickHeight / 2; + centerY = + this.tickTextHeight + this.centerTickOffset + this.edgeTickHeight / 2; edgeTickY1 = this.tickTextHeight + this.centerTickOffset; - edgeTickY2 = this.tickTextHeight + this.edgeTickHeight + this.centerTickOffset; + edgeTickY2 = + this.tickTextHeight + this.edgeTickHeight + this.centerTickOffset; deltaTextY = this.edgeTickY2; @@ -129,7 +131,10 @@ export default class RecommendationChartComponent extends Component { }, rect: { x: this.gutterWidthLeft, - y: (this.edgeTickHeight - rectHeight) / 2 + this.centerTickOffset + this.tickTextHeight, + y: + (this.edgeTickHeight - rectHeight) / 2 + + this.centerTickOffset + + this.tickTextHeight, width: rectWidth, height: rectHeight, }, @@ -145,7 +150,10 @@ export default class RecommendationChartComponent extends Component { } get maximumX() { - return Math.max(this.higherValue, get(this.args.stats, 'max') || Number.MIN_SAFE_INTEGER); + return Math.max( + this.higherValue, + get(this.args.stats, 'max') || Number.MIN_SAFE_INTEGER + ); } get lowerValue() { @@ -153,7 +161,9 @@ export default class RecommendationChartComponent extends Component { } get xScale() { - return scaleLinear().domain([0, this.maximumX]).rangeRound([0, this.barWidth]); + return scaleLinear() + .domain([0, this.maximumX]) + .rangeRound([0, this.barWidth]); } get lowerValueWidth() { @@ -210,9 +220,13 @@ export default class RecommendationChartComponent extends Component { let translateX; if (this.shown) { - translateX = this.isIncrease ? this.higherValueWidth : this.lowerValueWidth; + translateX = this.isIncrease + ? this.higherValueWidth + : this.lowerValueWidth; } else { - translateX = this.isIncrease ? this.lowerValueWidth : this.higherValueWidth; + translateX = this.isIncrease + ? this.lowerValueWidth + : this.higherValueWidth; } return { @@ -220,7 +234,9 @@ export default class RecommendationChartComponent extends Component { points: ` 0,${this.center.y1} 0,${this.center.y1 - this.deltaTriangleHeight / 2} - ${(directionXMultiplier * this.deltaTriangleHeight) / 2},${this.center.y1} + ${(directionXMultiplier * this.deltaTriangleHeight) / 2},${ + this.center.y1 + } 0,${this.center.y1 + this.deltaTriangleHeight / 2} `, }; @@ -234,7 +250,9 @@ export default class RecommendationChartComponent extends Component { }, delta: { style: htmlSafe( - `transform: translateX(${this.shown ? this.higherValueWidth : this.lowerValueWidth}px)` + `transform: translateX(${ + this.shown ? this.higherValueWidth : this.lowerValueWidth + }px)` ), }, }; @@ -245,7 +263,9 @@ export default class RecommendationChartComponent extends Component { }, delta: { style: htmlSafe( - `transform: translateX(${this.shown ? this.lowerValueWidth : this.higherValueWidth}px)` + `transform: translateX(${ + this.shown ? this.lowerValueWidth : this.higherValueWidth + }px)` ), }, }; @@ -269,7 +289,8 @@ export default class RecommendationChartComponent extends Component { }; const percentText = formatPercent( - (this.args.recommendedValue - this.args.currentValue) / this.args.currentValue + (this.args.recommendedValue - this.args.currentValue) / + this.args.currentValue ); const percent = { @@ -314,7 +335,10 @@ export default class RecommendationChartComponent extends Component { }; return Object.keys(statsWithCurrentAndRecommended) - .map((key) => ({ label: statsKeyToLabel[key], value: statsWithCurrentAndRecommended[key] })) + .map((key) => ({ + label: statsKeyToLabel[key], + value: statsWithCurrentAndRecommended[key], + })) .sortBy('value'); } else { return []; diff --git a/ui/app/components/distribution-bar.js b/ui/app/components/distribution-bar.js index ef36ff6e2..a33c48f3e 100644 --- a/ui/app/components/distribution-bar.js +++ b/ui/app/components/distribution-bar.js @@ -34,17 +34,20 @@ export default class DistributionBar extends Component.extend(WindowResizable) { const data = copy(this.data, true); const sum = data.mapBy('value').reduce(sumAggregate, 0); - return data.map(({ label, value, className, layers, legendLink, help }, index) => ({ - label, - value, - className, - layers, - legendLink, - help, - index, - percent: value / sum, - offset: data.slice(0, index).mapBy('value').reduce(sumAggregate, 0) / sum, - })); + return data.map( + ({ label, value, className, layers, legendLink, help }, index) => ({ + label, + value, + className, + layers, + legendLink, + help, + index, + percent: value / sum, + offset: + data.slice(0, index).mapBy('value').reduce(sumAggregate, 0) / sum, + }) + ); } didInsertElement() { @@ -60,7 +63,10 @@ export default class DistributionBar extends Component.extend(WindowResizable) { run(() => { this.set('isActive', false); this.set('activeDatum', null); - chart.selectAll('g').classed('active', false).classed('inactive', false); + chart + .selectAll('g') + .classed('active', false) + .classed('inactive', false); }); }); diff --git a/ui/app/components/exec/task-group-parent.js b/ui/app/components/exec/task-group-parent.js index 76cb2af0a..762616be5 100644 --- a/ui/app/components/exec/task-group-parent.js +++ b/ui/app/components/exec/task-group-parent.js @@ -31,7 +31,9 @@ export default class TaskGroupParent extends Component { @computed('taskGroup.allocations.@each.clientStatus') get hasPendingAllocations() { - return this.taskGroup.allocations.any((allocation) => allocation.clientStatus === 'pending'); + return this.taskGroup.allocations.any( + (allocation) => allocation.clientStatus === 'pending' + ); } @mapBy('taskGroup.allocations', 'states') allocationTaskStatesRecordArrays; @@ -39,7 +41,10 @@ export default class TaskGroupParent extends Component { get allocationTaskStates() { const flattenRecordArrays = (accumulator, recordArray) => accumulator.concat(recordArray.toArray()); - return this.allocationTaskStatesRecordArrays.reduce(flattenRecordArrays, []); + return this.allocationTaskStatesRecordArrays.reduce( + flattenRecordArrays, + [] + ); } @filterBy('allocationTaskStates', 'isActive') activeTaskStates; @@ -56,11 +61,16 @@ export default class TaskGroupParent extends Component { get tasksWithRunningStates() { const activeTaskStateNames = this.activeTaskStates .filter((taskState) => { - return taskState.task && taskState.task.taskGroup.name === this.taskGroup.name; + return ( + taskState.task && + taskState.task.taskGroup.name === this.taskGroup.name + ); }) .mapBy('name'); - return this.taskGroup.tasks.filter((task) => activeTaskStateNames.includes(task.name)); + return this.taskGroup.tasks.filter((task) => + activeTaskStateNames.includes(task.name) + ); } taskSorting = ['name']; diff --git a/ui/app/components/flex-masonry.js b/ui/app/components/flex-masonry.js index 329a99062..29b32501a 100644 --- a/ui/app/components/flex-masonry.js +++ b/ui/app/components/flex-masonry.js @@ -18,7 +18,9 @@ export default class FlexMasonry extends Component { // There's nothing to do if there is no element if (!this.element) return; - const items = this.element.querySelectorAll(':scope > .flex-masonry-item'); + const items = this.element.querySelectorAll( + ':scope > .flex-masonry-item' + ); // Clear out specified order and flex-basis values in case this was once a multi-column layout if (this.args.columns === 1 || !this.args.columns) { @@ -62,10 +64,12 @@ export default class FlexMasonry extends Component { // beteen the height of the column and the previous column, then flexbox will naturally place the first // item at the end of the previous column). columns.forEach((column, index) => { - const nextHeight = index < columns.length - 1 ? columns[index + 1].height : 0; + const nextHeight = + index < columns.length - 1 ? columns[index + 1].height : 0; const item = column.elements.lastObject; if (item) { - item.style.flexBasis = item.clientHeight + Math.max(0, nextHeight - column.height) + 'px'; + item.style.flexBasis = + item.clientHeight + Math.max(0, nextHeight - column.height) + 'px'; } }); diff --git a/ui/app/components/fs/browser.js b/ui/app/components/fs/browser.js index 751f60f65..a57365667 100644 --- a/ui/app/components/fs/browser.js +++ b/ui/app/components/fs/browser.js @@ -39,11 +39,18 @@ export default class Browser extends Component { @filterBy('directoryEntries', 'IsDir') directories; @filterBy('directoryEntries', 'IsDir', false) files; - @computed('directories', 'directoryEntries.[]', 'files', 'sortDescending', 'sortProperty') + @computed( + 'directories', + 'directoryEntries.[]', + 'files', + 'sortDescending', + 'sortProperty' + ) get sortedDirectoryEntries() { const sortProperty = this.sortProperty; - const directorySortProperty = sortProperty === 'Size' ? 'Name' : sortProperty; + const directorySortProperty = + sortProperty === 'Size' ? 'Name' : sortProperty; const sortedDirectories = this.directories.sortBy(directorySortProperty); const sortedFiles = this.files.sortBy(sortProperty); diff --git a/ui/app/components/fs/file.js b/ui/app/components/fs/file.js index 6535aa4ed..1af183478 100644 --- a/ui/app/components/fs/file.js +++ b/ui/app/components/fs/file.js @@ -39,7 +39,10 @@ export default class File extends Component { if (contentType.startsWith('image/')) { return 'image'; - } else if (contentType.startsWith('text/') || contentType.startsWith('application/json')) { + } else if ( + contentType.startsWith('text/') || + contentType.startsWith('application/json') + ) { return 'stream'; } else { return 'unknown'; @@ -108,7 +111,14 @@ export default class File extends Component { } } - @computed('clientTimeout', 'fileParams', 'fileUrl', 'mode', 'serverTimeout', 'useServer') + @computed( + 'clientTimeout', + 'fileParams', + 'fileUrl', + 'mode', + 'serverTimeout', + 'useServer' + ) get logger() { // The cat and readat APIs are in plainText while the stream API is always encoded. const plainText = this.mode === 'head' || this.mode === 'tail'; diff --git a/ui/app/components/global-search/control.js b/ui/app/components/global-search/control.js index 6dece158a..e68e5c7be 100644 --- a/ui/app/components/global-search/control.js +++ b/ui/app/components/global-search/control.js @@ -43,14 +43,17 @@ export default class GlobalSearchControl extends Component { } @task(function* (string) { - const searchResponse = yield this.token.authorizedRequest('/v1/search/fuzzy', { - method: 'POST', - body: JSON.stringify({ - Text: string, - Context: 'all', - Namespace: '*', - }), - }); + const searchResponse = yield this.token.authorizedRequest( + '/v1/search/fuzzy', + { + method: 'POST', + body: JSON.stringify({ + Text: string, + Context: 'all', + Namespace: '*', + }), + } + ); const results = yield searchResponse.json(); @@ -95,11 +98,13 @@ export default class GlobalSearchControl extends Component { label: `${namespace} > ${jobId} > ${id}`, })); - const csiPluginResults = allCSIPluginResults.slice(0, MAXIMUM_RESULTS).map(({ ID: id }) => ({ - type: 'plugin', - id, - label: id, - })); + const csiPluginResults = allCSIPluginResults + .slice(0, MAXIMUM_RESULTS) + .map(({ ID: id }) => ({ + type: 'plugin', + id, + label: id, + })); const { jobs: jobsTruncated, @@ -111,11 +116,21 @@ export default class GlobalSearchControl extends Component { return [ { - groupName: resultsGroupLabel('Jobs', jobResults, allJobResults, jobsTruncated), + groupName: resultsGroupLabel( + 'Jobs', + jobResults, + allJobResults, + jobsTruncated + ), options: jobResults, }, { - groupName: resultsGroupLabel('Clients', nodeResults, allNodeResults, nodesTruncated), + groupName: resultsGroupLabel( + 'Clients', + nodeResults, + allNodeResults, + nodesTruncated + ), options: nodeResults, }, { @@ -191,10 +206,14 @@ export default class GlobalSearchControl extends Component { openOnClickOrTab(select, { target }) { // Bypass having to press enter to access search after clicking/tabbing const targetClassList = target.classList; - const targetIsTrigger = targetClassList.contains('ember-power-select-trigger'); + const targetIsTrigger = targetClassList.contains( + 'ember-power-select-trigger' + ); // Allow tabbing out of search - const triggerIsNotActive = !targetClassList.contains('ember-power-select-trigger--active'); + const triggerIsNotActive = !targetClassList.contains( + 'ember-power-select-trigger--active' + ); if (targetIsTrigger && triggerIsNotActive) { debounce(this, this.open, 150); diff --git a/ui/app/components/gutter-menu.js b/ui/app/components/gutter-menu.js index 469ac039b..e73f58da3 100644 --- a/ui/app/components/gutter-menu.js +++ b/ui/app/components/gutter-menu.js @@ -44,7 +44,9 @@ export default class GutterMenu extends Component { // an intent to reset context, but where to reset to depends on where the namespace // is being switched from. Jobs take precedence, but if the namespace is switched from // a storage-related page, context should be reset to volumes. - const destination = this.router.currentRouteName.startsWith('csi.') ? 'csi.volumes' : 'jobs'; + const destination = this.router.currentRouteName.startsWith('csi.') + ? 'csi.volumes' + : 'jobs'; this.router.transitionTo(destination, { queryParams: { namespace: namespace.get('id') }, diff --git a/ui/app/components/job-client-status-bar.js b/ui/app/components/job-client-status-bar.js index 98b848a41..9f3690b01 100644 --- a/ui/app/components/job-client-status-bar.js +++ b/ui/app/components/job-client-status-bar.js @@ -12,8 +12,16 @@ export default class JobClientStatusBar extends DistributionBar { @computed('job.namespace', 'jobClientStatus.byStatus') get data() { - const { queued, starting, running, complete, degraded, failed, lost, notScheduled } = - this.jobClientStatus.byStatus; + const { + queued, + starting, + running, + complete, + degraded, + failed, + lost, + notScheduled, + } = this.jobClientStatus.byStatus; return [ { diff --git a/ui/app/components/job-diff.js b/ui/app/components/job-diff.js index 2f7a6921c..505350877 100644 --- a/ui/app/components/job-diff.js +++ b/ui/app/components/job-diff.js @@ -5,7 +5,11 @@ import classic from 'ember-classic-decorator'; @classic @classNames('job-diff') -@classNameBindings('isEdited:is-edited', 'isAdded:is-added', 'isDeleted:is-deleted') +@classNameBindings( + 'isEdited:is-edited', + 'isAdded:is-added', + 'isDeleted:is-deleted' +) export default class JobDiff extends Component { diff = null; diff --git a/ui/app/components/job-dispatch.js b/ui/app/components/job-dispatch.js index 4c84942fc..d0a5af2d2 100644 --- a/ui/app/components/job-dispatch.js +++ b/ui/app/components/job-dispatch.js @@ -59,8 +59,14 @@ export default class JobDispatch extends Component { ); // Fetch the different types of parameters. - const required = mapper(this.args.job.parameterizedDetails.MetaRequired || [], true); - const optional = mapper(this.args.job.parameterizedDetails.MetaOptional || [], false); + const required = mapper( + this.args.job.parameterizedDetails.MetaRequired || [], + true + ); + const optional = mapper( + this.args.job.parameterizedDetails.MetaOptional || [], + false + ); // Merge them, required before optional. this.metaFields = required.concat(optional); diff --git a/ui/app/components/job-editor.js b/ui/app/components/job-editor.js index 093c5cb12..0e9426851 100644 --- a/ui/app/components/job-editor.js +++ b/ui/app/components/job-editor.js @@ -25,7 +25,10 @@ export default class JobEditor extends Component { set context(value) { const allowedValues = ['new', 'edit']; - assert(`context must be one of: ${allowedValues.join(', ')}`, allowedValues.includes(value)); + assert( + `context must be one of: ${allowedValues.join(', ')}`, + allowedValues.includes(value) + ); this.set('_context', value); } diff --git a/ui/app/components/job-version.js b/ui/app/components/job-version.js index 28f45a9e8..3e5ad74af 100644 --- a/ui/app/components/job-version.js +++ b/ui/app/components/job-version.js @@ -31,7 +31,9 @@ export default class JobVersion extends Component { return ( fieldChanges(diff) + taskGroups.reduce(arrayOfFieldChanges, 0) + - (taskGroups.mapBy('Tasks') || []).reduce(flatten, []).reduce(arrayOfFieldChanges, 0) + (taskGroups.mapBy('Tasks') || []) + .reduce(flatten, []) + .reduce(arrayOfFieldChanges, 0) ); } @@ -58,7 +60,8 @@ export default class JobVersion extends Component { this.handleError({ level: 'warn', title: 'Reversion Had No Effect', - description: 'Reverting to an identical older version doesn’t produce a new version', + description: + 'Reverting to an identical older version doesn’t produce a new version', }); } else { const job = this.get('version.job'); @@ -79,7 +82,8 @@ export default class JobVersion extends Component { } const flatten = (accumulator, array) => accumulator.concat(array); -const countChanges = (total, field) => (changeTypes.includes(field.Type) ? total + 1 : total); +const countChanges = (total, field) => + changeTypes.includes(field.Type) ? total + 1 : total; function fieldChanges(diff) { return ( diff --git a/ui/app/components/job-versions-stream.js b/ui/app/components/job-versions-stream.js index 5497565e5..88f7e9668 100644 --- a/ui/app/components/job-versions-stream.js +++ b/ui/app/components/job-versions-stream.js @@ -24,7 +24,9 @@ export default class JobVersionsStream extends Component { meta.showDate = true; } else { const previousVersion = versions.objectAt(index - 1); - const previousStart = moment(previousVersion.get('submitTime')).startOf('day'); + const previousStart = moment(previousVersion.get('submitTime')).startOf( + 'day' + ); const currentStart = moment(version.get('submitTime')).startOf('day'); if (previousStart.diff(currentStart, 'days') > 0) { meta.showDate = true; diff --git a/ui/app/components/line-chart.js b/ui/app/components/line-chart.js index d5e7ad05d..8f7bb19f1 100644 --- a/ui/app/components/line-chart.js +++ b/ui/app/components/line-chart.js @@ -92,7 +92,9 @@ export default class LineChart extends Component { @action xFormat(timeseries) { if (this.args.xFormat) return this.args.xFormat; - return timeseries ? d3TimeFormat.timeFormat('%b %d, %H:%M') : d3Format.format(','); + return timeseries + ? d3TimeFormat.timeFormat('%b %d, %H:%M') + : d3Format.format(','); } @action @@ -153,7 +155,11 @@ export default class LineChart extends Component { get xAxis() { const formatter = this.xFormat(this.args.timeseries); - return d3Axis.axisBottom().scale(this.xScale).ticks(5).tickFormat(formatter); + return d3Axis + .axisBottom() + .scale(this.xScale) + .ticks(5) + .tickFormat(formatter); } get yTicks() { @@ -167,7 +173,11 @@ export default class LineChart extends Component { get yAxis() { const formatter = this.yFormat(); - return d3Axis.axisRight().scale(this.yScale).tickValues(this.yTicks).tickFormat(formatter); + return d3Axis + .axisRight() + .scale(this.yScale) + .tickValues(this.yTicks) + .tickFormat(formatter); } get yGridlines() { @@ -297,7 +307,11 @@ export default class LineChart extends Component { // Of the selected data, determine which is closest const closestDatum = activeData .slice() - .sort((a, b) => Math.abs(a.datum.datum[xProp] - x) - Math.abs(b.datum.datum[xProp] - x))[0]; + .sort( + (a, b) => + Math.abs(a.datum.datum[xProp] - x) - + Math.abs(b.datum.datum[xProp] - x) + )[0]; // If any other selected data are beyond a distance threshold, drop them from the list // xScale is used here to measure distance in screen-space rather than data-space. @@ -340,7 +354,9 @@ export default class LineChart extends Component { if (!this.isDestroyed && !this.isDestroying) { d3.select(this.element.querySelector('.x-axis')).call(this.xAxis); d3.select(this.element.querySelector('.y-axis')).call(this.yAxis); - d3.select(this.element.querySelector('.y-gridlines')).call(this.yGridlines); + d3.select(this.element.querySelector('.y-gridlines')).call( + this.yGridlines + ); } } diff --git a/ui/app/components/multi-select-dropdown.js b/ui/app/components/multi-select-dropdown.js index dc53b708c..692ea7c9f 100644 --- a/ui/app/components/multi-select-dropdown.js +++ b/ui/app/components/multi-select-dropdown.js @@ -60,8 +60,12 @@ export default class MultiSelectDropdown extends Component { dropdown.actions.open(e); e.preventDefault(); } else if (this.isOpen && (e.keyCode === TAB || e.keyCode === ARROW_DOWN)) { - const optionsId = this.element.querySelector('.dropdown-trigger').getAttribute('aria-owns'); - const firstElement = document.querySelector(`#${optionsId} .dropdown-option`); + const optionsId = this.element + .querySelector('.dropdown-trigger') + .getAttribute('aria-owns'); + const firstElement = document.querySelector( + `#${optionsId} .dropdown-option` + ); if (firstElement) { firstElement.focus(); diff --git a/ui/app/components/popover-menu.js b/ui/app/components/popover-menu.js index d37ca65a3..a6498a9aa 100644 --- a/ui/app/components/popover-menu.js +++ b/ui/app/components/popover-menu.js @@ -49,7 +49,9 @@ export default class PopoverMenu extends Component { dropdown.actions.open(e); e.preventDefault(); } else if (this.isOpen && (e.keyCode === TAB || e.keyCode === ARROW_DOWN)) { - const optionsId = this.element.querySelector('.popover-trigger').getAttribute('aria-owns'); + const optionsId = this.element + .querySelector('.popover-trigger') + .getAttribute('aria-owns'); const popoverContentEl = document.querySelector(`#${optionsId}`); const firstFocusableElement = popoverContentEl.querySelector(FOCUSABLE); diff --git a/ui/app/components/primary-metric/node.js b/ui/app/components/primary-metric/node.js index 52b873163..a4a7102b9 100644 --- a/ui/app/components/primary-metric/node.js +++ b/ui/app/components/primary-metric/node.js @@ -4,7 +4,10 @@ import { task, timeout } from 'ember-concurrency'; import { assert } from '@ember/debug'; import { inject as service } from '@ember/service'; import { action, get } from '@ember/object'; -import { formatScheduledBytes, formatScheduledHertz } from 'nomad-ui/utils/units'; +import { + formatScheduledBytes, + formatScheduledHertz, +} from 'nomad-ui/utils/units'; export default class NodePrimaryMetric extends Component { @service('stats-trackers-registry') statsTrackersRegistry; diff --git a/ui/app/components/primary-metric/task.js b/ui/app/components/primary-metric/task.js index 8748f360b..20d987caf 100644 --- a/ui/app/components/primary-metric/task.js +++ b/ui/app/components/primary-metric/task.js @@ -53,7 +53,9 @@ export default class TaskPrimaryMetric extends Component { @action start() { this.taskState = this.args.taskState; - this.tracker = this.statsTrackersRegistry.getTracker(this.args.taskState.allocation); + this.tracker = this.statsTrackersRegistry.getTracker( + this.args.taskState.allocation + ); this.poller.perform(); } diff --git a/ui/app/components/scale-events-chart.js b/ui/app/components/scale-events-chart.js index ae9b73015..8a687f139 100644 --- a/ui/app/components/scale-events-chart.js +++ b/ui/app/components/scale-events-chart.js @@ -40,7 +40,10 @@ export default class ScaleEventsChart extends Component { } toggleEvent(ev) { - if (this.activeEvent && get(this.activeEvent, 'event.uid') === get(ev, 'event.uid')) { + if ( + this.activeEvent && + get(this.activeEvent, 'event.uid') === get(ev, 'event.uid') + ) { this.closeEventDetails(); } else { this.activeEvent = ev; diff --git a/ui/app/components/server-agent-row.js b/ui/app/components/server-agent-row.js index 3c5ee4632..e0cc0ede2 100644 --- a/ui/app/components/server-agent-row.js +++ b/ui/app/components/server-agent-row.js @@ -3,7 +3,11 @@ import { alias } from '@ember/object/computed'; import Component from '@ember/component'; import { computed } from '@ember/object'; import { lazyClick } from '../helpers/lazy-click'; -import { classNames, classNameBindings, tagName } from '@ember-decorators/component'; +import { + classNames, + classNameBindings, + tagName, +} from '@ember-decorators/component'; import classic from 'ember-classic-decorator'; @classic @@ -38,7 +42,8 @@ export default class ServerAgentRow extends Component { } click() { - const transition = () => this.router.transitionTo('servers.server', this.agent); + const transition = () => + this.router.transitionTo('servers.server', this.agent); lazyClick([transition, event]); } } diff --git a/ui/app/components/stats-time-series.js b/ui/app/components/stats-time-series.js index 0caf938b2..f530fb7af 100644 --- a/ui/app/components/stats-time-series.js +++ b/ui/app/components/stats-time-series.js @@ -39,14 +39,18 @@ export default class StatsTimeSeries extends Component { const [low, high] = d3Array.extent(data, (d) => d.timestamp); const minLow = moment(high).subtract(5, 'minutes').toDate(); - const extent = data.length ? [Math.min(low, minLow), high] : [minLow, new Date()]; + const extent = data.length + ? [Math.min(low, minLow), high] + : [minLow, new Date()]; scale.rangeRound([10, yAxisOffset]).domain(extent); return scale; } yScale(data, xAxisOffset) { - const yValues = (data || []).mapBy(this.args.dataProp ? 'percentStack' : 'percent'); + const yValues = (data || []).mapBy( + this.args.dataProp ? 'percentStack' : 'percent' + ); let [low, high] = [0, 1]; if (yValues.compact().length) { diff --git a/ui/app/components/stepper-input.js b/ui/app/components/stepper-input.js index 8509c3534..f1993144c 100644 --- a/ui/app/components/stepper-input.js +++ b/ui/app/components/stepper-input.js @@ -9,7 +9,12 @@ const ESC = 27; @classic @classNames('stepper-input') -@classNameBindings('class', 'disabled:is-disabled', 'disabled:tooltip', 'disabled:multiline') +@classNameBindings( + 'class', + 'disabled:is-disabled', + 'disabled:tooltip', + 'disabled:multiline' +) export default class StepperInput extends Component { min = 0; max = 10; @@ -41,7 +46,9 @@ export default class StepperInput extends Component { @action setValue(e) { if (e.target.value !== '') { - const newValue = Math.floor(Math.min(this.max, Math.max(this.min, e.target.value))); + const newValue = Math.floor( + Math.min(this.max, Math.max(this.min, e.target.value)) + ); this.set('internalValue', newValue); this.update(this.internalValue); } else { diff --git a/ui/app/components/streaming-file.js b/ui/app/components/streaming-file.js index 40963288c..b19dea125 100644 --- a/ui/app/components/streaming-file.js +++ b/ui/app/components/streaming-file.js @@ -59,7 +59,10 @@ export default class StreamingFile extends Component.extend(WindowResizable) { if (this.requestFrame) { window.requestAnimationFrame(() => { // If the scroll position is close enough to the bottom, autoscroll to the bottom - this.set('follow', cli.scrollHeight - cli.scrollTop - cli.clientHeight < 20); + this.set( + 'follow', + cli.scrollHeight - cli.scrollTop - cli.clientHeight < 20 + ); this.requestFrame = true; }); } @@ -105,7 +108,9 @@ export default class StreamingFile extends Component.extend(WindowResizable) { // of having the log window fill available height is worth the hack. const margins = 30; // Account for padding and margin on either side of the CLI const cliWindow = this.element; - cliWindow.style.height = `${window.innerHeight - cliWindow.offsetTop - margins}px`; + cliWindow.style.height = `${ + window.innerHeight - cliWindow.offsetTop - margins + }px`; } @task(function* () { diff --git a/ui/app/components/task-group-row.js b/ui/app/components/task-group-row.js index 57d9e9336..3346fe8be 100644 --- a/ui/app/components/task-group-row.js +++ b/ui/app/components/task-group-row.js @@ -27,7 +27,8 @@ export default class TaskGroupRow extends Component { get tooltipText() { if (this.can.cannot('scale job', null, { namespace: this.namespace })) return "You aren't allowed to scale task groups"; - if (this.runningDeployment) return 'You cannot scale task groups during a deployment'; + if (this.runningDeployment) + return 'You cannot scale task groups during a deployment'; return undefined; } diff --git a/ui/app/components/task-log.js b/ui/app/components/task-log.js index ec098e5fb..2ed7325d0 100644 --- a/ui/app/components/task-log.js +++ b/ui/app/components/task-log.js @@ -58,7 +58,9 @@ export default class TaskLog extends Component { // If the log request can't settle in one second, the client // must be unavailable and the server should be used instead - const aborter = window.AbortController ? new AbortController() : new MockAbortController(); + const aborter = window.AbortController + ? new AbortController() + : new MockAbortController(); const timing = this.useServer ? this.serverTimeout : this.clientTimeout; // Capture the state of useServer at logger create time to avoid a race diff --git a/ui/app/components/toggle.js b/ui/app/components/toggle.js index 6701f64f9..efa1ed87d 100644 --- a/ui/app/components/toggle.js +++ b/ui/app/components/toggle.js @@ -1,5 +1,9 @@ import Component from '@ember/component'; -import { classNames, classNameBindings, tagName } from '@ember-decorators/component'; +import { + classNames, + classNameBindings, + tagName, +} from '@ember-decorators/component'; import classic from 'ember-classic-decorator'; @classic diff --git a/ui/app/components/tooltip.js b/ui/app/components/tooltip.js index fa1420c62..a9fb3120c 100644 --- a/ui/app/components/tooltip.js +++ b/ui/app/components/tooltip.js @@ -8,7 +8,9 @@ export default class Tooltip extends Component { } const prefix = inputText.substr(0, 15).trim(); - const suffix = inputText.substr(inputText.length - 10, inputText.length).trim(); + const suffix = inputText + .substr(inputText.length - 10, inputText.length) + .trim(); return `${prefix}...${suffix}`; } } diff --git a/ui/app/components/topo-viz.js b/ui/app/components/topo-viz.js index e3d2bbac2..48faa6b7f 100644 --- a/ui/app/components/topo-viz.js +++ b/ui/app/components/topo-viz.js @@ -26,11 +26,14 @@ export default class TopoViz extends Component { @styleStringProperty('tooltipProps') tooltipStyle; get isSingleColumn() { - if (this.topology.datacenters.length <= 1 || this.viewportColumns === 1) return true; + if (this.topology.datacenters.length <= 1 || this.viewportColumns === 1) + return true; // Compute the coefficient of variance to determine if it would be // better to stack datacenters or place them in columns - const nodeCounts = this.topology.datacenters.map((datacenter) => datacenter.nodes.length); + const nodeCounts = this.topology.datacenters.map( + (datacenter) => datacenter.nodes.length + ); const variationCoefficient = deviation(nodeCounts) / mean(nodeCounts); // The point at which the varation is too extreme for a two column layout @@ -43,7 +46,10 @@ export default class TopoViz extends Component { // If there are enough nodes, use two columns of nodes within // a single column layout of datacenters to increase density. if (this.viewportColumns === 1) return true; - return !this.isSingleColumn || (this.isSingleColumn && this.args.nodes.length <= 20); + return ( + !this.isSingleColumn || + (this.isSingleColumn && this.args.nodes.length <= 20) + ); } // Once a cluster is large enough, the exact details of a node are @@ -110,7 +116,10 @@ export default class TopoViz extends Component { // Ignore orphaned allocations and allocations on nodes with an old Nomad agent version. if (!nodeContainer) return; - const allocationContainer = this.dataForAllocation(allocation, nodeContainer); + const allocationContainer = this.dataForAllocation( + allocation, + nodeContainer + ); nodeContainer.allocations.push(allocationContainer); const key = allocationContainer.groupKey; @@ -119,11 +128,15 @@ export default class TopoViz extends Component { }); // Group nodes into datacenters - const datacentersMap = nodeContainers.reduce((datacenters, nodeContainer) => { - if (!datacenters[nodeContainer.datacenter]) datacenters[nodeContainer.datacenter] = []; - datacenters[nodeContainer.datacenter].push(nodeContainer); - return datacenters; - }, {}); + const datacentersMap = nodeContainers.reduce( + (datacenters, nodeContainer) => { + if (!datacenters[nodeContainer.datacenter]) + datacenters[nodeContainer.datacenter] = []; + datacenters[nodeContainer.datacenter].push(nodeContainer); + return datacenters; + }, + {} + ); // Turn hash of datacenters into a sorted array const datacenters = Object.keys(datacentersMap) @@ -191,7 +204,8 @@ export default class TopoViz extends Component { this.activeEdges = []; if (this.topology.selectedKey) { - const selectedAllocations = this.topology.allocationIndex[this.topology.selectedKey]; + const selectedAllocations = + this.topology.allocationIndex[this.topology.selectedKey]; if (selectedAllocations) { selectedAllocations.forEach((allocation) => { set(allocation, 'isSelected', false); @@ -205,7 +219,8 @@ export default class TopoViz extends Component { } this.activeNode = null; this.activeAllocation = allocation; - const selectedAllocations = this.topology.allocationIndex[this.topology.selectedKey]; + const selectedAllocations = + this.topology.allocationIndex[this.topology.selectedKey]; if (selectedAllocations) { selectedAllocations.forEach((allocation) => { set(allocation, 'isSelected', false); @@ -213,7 +228,8 @@ export default class TopoViz extends Component { } set(this.topology, 'selectedKey', allocation.groupKey); - const newAllocations = this.topology.allocationIndex[this.topology.selectedKey]; + const newAllocations = + this.topology.allocationIndex[this.topology.selectedKey]; if (newAllocations) { newAllocations.forEach((allocation) => { set(allocation, 'isSelected', true); @@ -221,14 +237,19 @@ export default class TopoViz extends Component { } // Only show the lines if the selected allocations are sparse (low count relative to the client count or low count generally). - if (newAllocations.length < 10 || newAllocations.length < this.args.nodes.length * 0.75) { + if ( + newAllocations.length < 10 || + newAllocations.length < this.args.nodes.length * 0.75 + ) { this.computedActiveEdges(); } else { this.activeEdges = []; } } if (this.args.onAllocationSelect) - this.args.onAllocationSelect(this.activeAllocation && this.activeAllocation.allocation); + this.args.onAllocationSelect( + this.activeAllocation && this.activeAllocation.allocation + ); if (this.args.onNodeSelect) this.args.onNodeSelect(this.activeNode); } @@ -251,11 +272,15 @@ export default class TopoViz extends Component { const path = line().curve(curveBasis); // 1. Get the active element const allocation = this.activeAllocation.allocation; - const activeEl = this.element.querySelector(`[data-allocation-id="${allocation.id}"]`); + const activeEl = this.element.querySelector( + `[data-allocation-id="${allocation.id}"]` + ); const activePoint = centerOfBBox(activeEl.getBoundingClientRect()); // 2. Collect the mem and cpu pairs for all selected allocs - const selectedMem = Array.from(this.element.querySelectorAll('.memory .bar.is-selected')); + const selectedMem = Array.from( + this.element.querySelectorAll('.memory .bar.is-selected') + ); const selectedPairs = selectedMem.map((mem) => { const id = mem.closest('[data-allocation-id]').dataset.allocationId; const cpu = mem @@ -283,8 +308,14 @@ export default class TopoViz extends Component { const stepsSecondary = [0.8, 1.0]; selectedPoints.forEach((points) => { curves.push( - curveFromPoints(...pointsAlongPath(activePoint, points[2], stepsMain), points[0]), - curveFromPoints(...pointsAlongPath(activePoint, points[2], stepsSecondary), points[1]) + curveFromPoints( + ...pointsAlongPath(activePoint, points[2], stepsMain), + points[0] + ), + curveFromPoints( + ...pointsAlongPath(activePoint, points[2], stepsSecondary), + points[1] + ) ); }); diff --git a/ui/app/components/topo-viz/datacenter.js b/ui/app/components/topo-viz/datacenter.js index 0750fc1eb..965af2f77 100644 --- a/ui/app/components/topo-viz/datacenter.js +++ b/ui/app/components/topo-viz/datacenter.js @@ -3,7 +3,8 @@ import Component from '@glimmer/component'; export default class TopoVizDatacenter extends Component { get scheduledAllocations() { return this.args.datacenter.nodes.reduce( - (all, node) => all.concat(node.allocations.filterBy('allocation.isScheduled')), + (all, node) => + all.concat(node.allocations.filterBy('allocation.isScheduled')), [] ); } diff --git a/ui/app/components/topo-viz/node.js b/ui/app/components/topo-viz/node.js index 3f581dafa..400b69c0b 100644 --- a/ui/app/components/topo-viz/node.js +++ b/ui/app/components/topo-viz/node.js @@ -10,7 +10,9 @@ export default class TopoVizNode extends Component { @tracked activeAllocation = null; get height() { - return this.args.heightScale ? this.args.heightScale(this.args.node.memory) : 15; + return this.args.heightScale + ? this.args.heightScale(this.args.node.memory) + : 15; } get labelHeight() { @@ -57,11 +59,13 @@ export default class TopoVizNode extends Component { get allocations() { // Sort by the delta between memory and cpu percent. This creates the least amount of // drift between the positional alignment of an alloc's cpu and memory representations. - return this.args.node.allocations.filterBy('allocation.isScheduled').sort((a, b) => { - const deltaA = Math.abs(a.memoryPercent - a.cpuPercent); - const deltaB = Math.abs(b.memoryPercent - b.cpuPercent); - return deltaA - deltaB; - }); + return this.args.node.allocations + .filterBy('allocation.isScheduled') + .sort((a, b) => { + const deltaA = Math.abs(a.memoryPercent - a.cpuPercent); + const deltaB = Math.abs(b.memoryPercent - b.cpuPercent); + return deltaA - deltaB; + }); } @action @@ -91,7 +95,8 @@ export default class TopoVizNode extends Component { @action highlightAllocation(allocation, { target }) { this.activeAllocation = allocation; - this.args.onAllocationFocus && this.args.onAllocationFocus(allocation, target); + this.args.onAllocationFocus && + this.args.onAllocationFocus(allocation, target); } @action diff --git a/ui/app/components/two-step-button.js b/ui/app/components/two-step-button.js index e66603e07..cd29dd8aa 100644 --- a/ui/app/components/two-step-button.js +++ b/ui/app/components/two-step-button.js @@ -9,7 +9,10 @@ import classic from 'ember-classic-decorator'; @classic @classNames('two-step-button') -@classNameBindings('inlineText:has-inline-text', 'fadingBackground:has-fading-background') +@classNameBindings( + 'inlineText:has-inline-text', + 'fadingBackground:has-fading-background' +) export default class TwoStepButton extends Component { idleText = ''; cancelText = ''; diff --git a/ui/app/controllers/clients/client/index.js b/ui/app/controllers/clients/client/index.js index a251d1bd7..6a9b2475c 100644 --- a/ui/app/controllers/clients/client/index.js +++ b/ui/app/controllers/clients/client/index.js @@ -10,11 +10,17 @@ import intersection from 'lodash.intersection'; import Sortable from 'nomad-ui/mixins/sortable'; import Searchable from 'nomad-ui/mixins/searchable'; import messageFromAdapterError from 'nomad-ui/utils/message-from-adapter-error'; -import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize'; +import { + serialize, + deserializedQueryParam as selection, +} from 'nomad-ui/utils/qp-serialize'; import classic from 'ember-classic-decorator'; @classic -export default class ClientController extends Controller.extend(Sortable, Searchable) { +export default class ClientController extends Controller.extend( + Sortable, + Searchable +) { queryParams = [ { currentPage: 'page', @@ -66,18 +72,32 @@ export default class ClientController extends Controller.extend(Sortable, Search return this.onlyPreemptions ? this.preemptions : this.model.allocations; } - @computed('visibleAllocations.[]', 'selectionNamespace', 'selectionJob', 'selectionStatus') + @computed( + 'visibleAllocations.[]', + 'selectionNamespace', + 'selectionJob', + 'selectionStatus' + ) get filteredAllocations() { const { selectionNamespace, selectionJob, selectionStatus } = this; return this.visibleAllocations.filter((alloc) => { - if (selectionNamespace.length && !selectionNamespace.includes(alloc.get('namespace'))) { + if ( + selectionNamespace.length && + !selectionNamespace.includes(alloc.get('namespace')) + ) { return false; } - if (selectionJob.length && !selectionJob.includes(alloc.get('plainJobId'))) { + if ( + selectionJob.length && + !selectionJob.includes(alloc.get('plainJobId')) + ) { return false; } - if (selectionStatus.length && !selectionStatus.includes(alloc.clientStatus)) { + if ( + selectionStatus.length && + !selectionStatus.includes(alloc.clientStatus) + ) { return false; } return true; @@ -217,12 +237,17 @@ export default class ClientController extends Controller.extend(Sortable, Search @computed('model.allocations.[]', 'selectionNamespace') get optionsNamespace() { - const ns = Array.from(new Set(this.model.allocations.mapBy('namespace'))).compact(); + const ns = Array.from( + new Set(this.model.allocations.mapBy('namespace')) + ).compact(); // Update query param when the list of namespaces changes. scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpNamespace', serialize(intersection(ns, this.selectionNamespace))); + this.set( + 'qpNamespace', + serialize(intersection(ns, this.selectionNamespace)) + ); }); return ns.sort().map((n) => ({ key: n, label: n })); diff --git a/ui/app/controllers/clients/index.js b/ui/app/controllers/clients/index.js index 66e5d3ce0..3ed795c69 100644 --- a/ui/app/controllers/clients/index.js +++ b/ui/app/controllers/clients/index.js @@ -7,7 +7,10 @@ import { scheduleOnce } from '@ember/runloop'; import intersection from 'lodash.intersection'; import SortableFactory from 'nomad-ui/mixins/sortable-factory'; import Searchable from 'nomad-ui/mixins/searchable'; -import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize'; +import { + serialize, + deserializedQueryParam as selection, +} from 'nomad-ui/utils/qp-serialize'; import classic from 'ember-classic-decorator'; @classic @@ -83,7 +86,10 @@ export default class IndexController extends Controller.extend( // Remove any invalid node classes from the query param/selection scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpClass', serialize(intersection(classes, this.selectionClass))); + this.set( + 'qpClass', + serialize(intersection(classes, this.selectionClass)) + ); }); return classes.sort().map((dc) => ({ key: dc, label: dc })); @@ -102,12 +108,17 @@ export default class IndexController extends Controller.extend( @computed('nodes.[]', 'selectionDatacenter') get optionsDatacenter() { - const datacenters = Array.from(new Set(this.nodes.mapBy('datacenter'))).compact(); + const datacenters = Array.from( + new Set(this.nodes.mapBy('datacenter')) + ).compact(); // Remove any invalid datacenters from the query param/selection scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpDatacenter', serialize(intersection(datacenters, this.selectionDatacenter))); + this.set( + 'qpDatacenter', + serialize(intersection(datacenters, this.selectionDatacenter)) + ); }); return datacenters.sort().map((dc) => ({ key: dc, label: dc })); @@ -120,7 +131,10 @@ export default class IndexController extends Controller.extend( // Remove any invalid versions from the query param/selection scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpVersion', serialize(intersection(versions, this.selectionVersion))); + this.set( + 'qpVersion', + serialize(intersection(versions, this.selectionVersion)) + ); }); return versions.sort().map((v) => ({ key: v, label: v })); @@ -135,7 +149,10 @@ export default class IndexController extends Controller.extend( scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpVolume', serialize(intersection(volumes, this.selectionVolume))); + this.set( + 'qpVolume', + serialize(intersection(volumes, this.selectionVolume)) + ); }); return volumes.sort().map((volume) => ({ key: volume, label: volume })); @@ -165,11 +182,18 @@ export default class IndexController extends Controller.extend( const statuses = states.without('ineligible').without('draining'); return this.nodes.filter((node) => { - if (classes.length && !classes.includes(node.get('nodeClass'))) return false; - if (statuses.length && !statuses.includes(node.get('status'))) return false; - if (datacenters.length && !datacenters.includes(node.get('datacenter'))) return false; - if (versions.length && !versions.includes(node.get('version'))) return false; - if (volumes.length && !node.hostVolumes.find((volume) => volumes.includes(volume.name))) + if (classes.length && !classes.includes(node.get('nodeClass'))) + return false; + if (statuses.length && !statuses.includes(node.get('status'))) + return false; + if (datacenters.length && !datacenters.includes(node.get('datacenter'))) + return false; + if (versions.length && !versions.includes(node.get('version'))) + return false; + if ( + volumes.length && + !node.hostVolumes.find((volume) => volumes.includes(volume.name)) + ) return false; if (onlyIneligible && node.get('isEligible')) return false; diff --git a/ui/app/controllers/csi/plugins/index.js b/ui/app/controllers/csi/plugins/index.js index 42668ba1e..b4c88ad9c 100644 --- a/ui/app/controllers/csi/plugins/index.js +++ b/ui/app/controllers/csi/plugins/index.js @@ -59,6 +59,9 @@ export default class IndexController extends Controller.extend( @action gotoPlugin(plugin, event) { - lazyClick([() => this.transitionToRoute('csi.plugins.plugin', plugin.plainId), event]); + lazyClick([ + () => this.transitionToRoute('csi.plugins.plugin', plugin.plainId), + event, + ]); } } diff --git a/ui/app/controllers/csi/plugins/plugin/allocations.js b/ui/app/controllers/csi/plugins/plugin/allocations.js index 8630a32ac..32c5ba669 100644 --- a/ui/app/controllers/csi/plugins/plugin/allocations.js +++ b/ui/app/controllers/csi/plugins/plugin/allocations.js @@ -4,7 +4,10 @@ import { action, computed } from '@ember/object'; import { alias, readOnly } from '@ember/object/computed'; import SortableFactory from 'nomad-ui/mixins/sortable-factory'; import { lazyClick } from 'nomad-ui/helpers/lazy-click'; -import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize'; +import { + serialize, + deserializedQueryParam as selection, +} from 'nomad-ui/utils/qp-serialize'; import classic from 'ember-classic-decorator'; @classic @@ -82,7 +85,8 @@ export default class AllocationsController extends Controller.extend( listToFilter = this.model.nodes; } - if (healths.length === 1 && healths[0] === 'true') return listToFilter.filterBy('healthy'); + if (healths.length === 1 && healths[0] === 'true') + return listToFilter.filterBy('healthy'); if (healths.length === 1 && healths[0] === 'false') return listToFilter.filterBy('healthy', false); return listToFilter; @@ -103,6 +107,9 @@ export default class AllocationsController extends Controller.extend( @action gotoAllocation(allocation, event) { - lazyClick([() => this.transitionToRoute('allocations.allocation', allocation), event]); + lazyClick([ + () => this.transitionToRoute('allocations.allocation', allocation), + event, + ]); } } diff --git a/ui/app/controllers/exec.js b/ui/app/controllers/exec.js index db7da454b..1738300d8 100644 --- a/ui/app/controllers/exec.js +++ b/ui/app/controllers/exec.js @@ -25,18 +25,25 @@ export default class ExecController extends Controller { @computed('model.allocations.@each.clientStatus') get pendingAndRunningAllocations() { return this.model.allocations.filter( - (allocation) => allocation.clientStatus === 'pending' || allocation.clientStatus === 'running' + (allocation) => + allocation.clientStatus === 'pending' || + allocation.clientStatus === 'running' ); } - @mapBy('pendingAndRunningAllocations', 'taskGroup') pendingAndRunningTaskGroups; + @mapBy('pendingAndRunningAllocations', 'taskGroup') + pendingAndRunningTaskGroups; @uniq('pendingAndRunningTaskGroups') uniquePendingAndRunningTaskGroups; taskGroupSorting = ['name']; - @sort('uniquePendingAndRunningTaskGroups', 'taskGroupSorting') sortedTaskGroups; + @sort('uniquePendingAndRunningTaskGroups', 'taskGroupSorting') + sortedTaskGroups; setUpTerminal(Terminal) { - this.terminal = new Terminal({ fontFamily: 'monospace', fontWeight: '400' }); + this.terminal = new Terminal({ + fontFamily: 'monospace', + fontWeight: '400', + }); window.execTerminal = this.terminal; // Issue to improve: https://github.com/hashicorp/nomad/issues/7457 this.terminal.write(ANSI_UI_GRAY_400); @@ -64,7 +71,10 @@ export default class ExecController extends Controller { allocation = this.allocations.findBy('shortId', this.allocationShortId); } else { allocation = this.allocations.find((allocation) => - allocation.states.filterBy('isActive').mapBy('name').includes(this.taskName) + allocation.states + .filterBy('isActive') + .mapBy('name') + .includes(this.taskName) ); } @@ -94,7 +104,9 @@ export default class ExecController extends Controller { this.terminal.writeln(''); } - this.terminal.writeln('Customize your command, then hit ‘return’ to run.'); + this.terminal.writeln( + 'Customize your command, then hit ‘return’ to run.' + ); this.terminal.writeln(''); this.terminal.write( `$ nomad alloc exec -i -t -task ${escapeTaskName(taskName)} ${ @@ -126,7 +138,9 @@ export default class ExecController extends Controller { new ExecSocketXtermAdapter(this.terminal, this.socket, this.token.secret); } else { - this.terminal.writeln(`Failed to open a socket because task ${this.taskName} is not active.`); + this.terminal.writeln( + `Failed to open a socket because task ${this.taskName} is not active.` + ); } } } diff --git a/ui/app/controllers/jobs/index.js b/ui/app/controllers/jobs/index.js index c2b633fe4..ff38e023b 100644 --- a/ui/app/controllers/jobs/index.js +++ b/ui/app/controllers/jobs/index.js @@ -8,11 +8,17 @@ import { scheduleOnce } from '@ember/runloop'; import intersection from 'lodash.intersection'; import Sortable from 'nomad-ui/mixins/sortable'; import Searchable from 'nomad-ui/mixins/searchable'; -import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize'; +import { + serialize, + deserializedQueryParam as selection, +} from 'nomad-ui/utils/qp-serialize'; import classic from 'ember-classic-decorator'; @classic -export default class IndexController extends Controller.extend(Sortable, Searchable) { +export default class IndexController extends Controller.extend( + Sortable, + Searchable +) { @service system; @service userSettings; @@ -100,7 +106,9 @@ export default class IndexController extends Controller.extend(Sortable, Searcha @computed('selectionDatacenter', 'visibleJobs.[]') get optionsDatacenter() { const flatten = (acc, val) => acc.concat(val); - const allDatacenters = new Set(this.visibleJobs.mapBy('datacenters').reduce(flatten, [])); + const allDatacenters = new Set( + this.visibleJobs.mapBy('datacenters').reduce(flatten, []) + ); // Remove any invalid datacenters from the query param/selection const availableDatacenters = Array.from(allDatacenters).compact(); @@ -144,7 +152,10 @@ export default class IndexController extends Controller.extend(Sortable, Searcha const availablePrefixes = prefixes.mapBy('prefix'); scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpPrefix', serialize(intersection(availablePrefixes, this.selectionPrefix))); + this.set( + 'qpPrefix', + serialize(intersection(availablePrefixes, this.selectionPrefix)) + ); }); // Sort, format, and include the count in the label @@ -216,12 +227,18 @@ export default class IndexController extends Controller.extend(Sortable, Searcha return false; } - if (datacenters.length && !job.get('datacenters').find((dc) => datacenters.includes(dc))) { + if ( + datacenters.length && + !job.get('datacenters').find((dc) => datacenters.includes(dc)) + ) { return false; } const name = job.get('name'); - if (prefixes.length && !prefixes.find((prefix) => name.startsWith(prefix))) { + if ( + prefixes.length && + !prefixes.find((prefix) => name.startsWith(prefix)) + ) { return false; } diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js index 0ca2f5747..466b7567d 100644 --- a/ui/app/controllers/jobs/job/allocations.js +++ b/ui/app/controllers/jobs/job/allocations.js @@ -7,7 +7,10 @@ import intersection from 'lodash.intersection'; import Sortable from 'nomad-ui/mixins/sortable'; import Searchable from 'nomad-ui/mixins/searchable'; import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting'; -import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize'; +import { + serialize, + deserializedQueryParam as selection, +} from 'nomad-ui/utils/qp-serialize'; import classic from 'ember-classic-decorator'; @classic @@ -61,18 +64,32 @@ export default class AllocationsController extends Controller.extend( return this.get('model.allocations') || []; } - @computed('allocations.[]', 'selectionStatus', 'selectionClient', 'selectionTaskGroup') + @computed( + 'allocations.[]', + 'selectionStatus', + 'selectionClient', + 'selectionTaskGroup' + ) get filteredAllocations() { const { selectionStatus, selectionClient, selectionTaskGroup } = this; return this.allocations.filter((alloc) => { - if (selectionStatus.length && !selectionStatus.includes(alloc.clientStatus)) { + if ( + selectionStatus.length && + !selectionStatus.includes(alloc.clientStatus) + ) { return false; } - if (selectionClient.length && !selectionClient.includes(alloc.get('node.shortId'))) { + if ( + selectionClient.length && + !selectionClient.includes(alloc.get('node.shortId')) + ) { return false; } - if (selectionTaskGroup.length && !selectionTaskGroup.includes(alloc.taskGroupName)) { + if ( + selectionTaskGroup.length && + !selectionTaskGroup.includes(alloc.taskGroupName) + ) { return false; } return true; @@ -104,12 +121,17 @@ export default class AllocationsController extends Controller.extend( @computed('model.allocations.[]', 'selectionClient') get optionsClients() { - const clients = Array.from(new Set(this.model.allocations.mapBy('node.shortId'))).compact(); + const clients = Array.from( + new Set(this.model.allocations.mapBy('node.shortId')) + ).compact(); // Update query param when the list of clients changes. scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpClient', serialize(intersection(clients, this.selectionClient))); + this.set( + 'qpClient', + serialize(intersection(clients, this.selectionClient)) + ); }); return clients.sort().map((c) => ({ key: c, label: c })); @@ -117,12 +139,17 @@ export default class AllocationsController extends Controller.extend( @computed('model.allocations.[]', 'selectionTaskGroup') get optionsTaskGroups() { - const taskGroups = Array.from(new Set(this.model.allocations.mapBy('taskGroupName'))).compact(); + const taskGroups = Array.from( + new Set(this.model.allocations.mapBy('taskGroupName')) + ).compact(); // Update query param when the list of task groups changes. scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpTaskGroup', serialize(intersection(taskGroups, this.selectionTaskGroup))); + this.set( + 'qpTaskGroup', + serialize(intersection(taskGroups, this.selectionTaskGroup)) + ); }); return taskGroups.sort().map((tg) => ({ key: tg, label: tg })); diff --git a/ui/app/controllers/jobs/job/clients.js b/ui/app/controllers/jobs/job/clients.js index d3a00379c..a4b7f05df 100644 --- a/ui/app/controllers/jobs/job/clients.js +++ b/ui/app/controllers/jobs/job/clients.js @@ -8,7 +8,10 @@ import SortableFactory from 'nomad-ui/mixins/sortable-factory'; import Searchable from 'nomad-ui/mixins/searchable'; import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting'; import jobClientStatus from 'nomad-ui/utils/properties/job-client-status'; -import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize'; +import { + serialize, + deserializedQueryParam as selection, +} from 'nomad-ui/utils/qp-serialize'; import classic from 'ember-classic-decorator'; @classic @@ -96,7 +99,10 @@ export default class ClientsController extends Controller.extend( return this.nodes .filter((node) => { - if (statuses.length && !statuses.includes(this.jobClientStatus.byNode[node.id])) { + if ( + statuses.length && + !statuses.includes(this.jobClientStatus.byNode[node.id]) + ) { return false; } if (datacenters.length && !datacenters.includes(node.datacenter)) { @@ -109,7 +115,9 @@ export default class ClientsController extends Controller.extend( return true; }) .map((node) => { - const allocations = this.job.allocations.filter((alloc) => alloc.get('node.id') == node.id); + const allocations = this.job.allocations.filter( + (alloc) => alloc.get('node.id') == node.id + ); return { node, @@ -137,12 +145,17 @@ export default class ClientsController extends Controller.extend( @computed('selectionDatacenter', 'nodes') get optionsDatacenter() { - const datacenters = Array.from(new Set(this.nodes.mapBy('datacenter'))).compact(); + const datacenters = Array.from( + new Set(this.nodes.mapBy('datacenter')) + ).compact(); // Update query param when the list of datacenters changes. scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpDatacenter', serialize(intersection(datacenters, this.selectionDatacenter))); + this.set( + 'qpDatacenter', + serialize(intersection(datacenters, this.selectionDatacenter)) + ); }); return datacenters.sort().map((dc) => ({ key: dc, label: dc })); @@ -150,15 +163,22 @@ export default class ClientsController extends Controller.extend( @computed('selectionClientClass', 'nodes') get optionsClientClass() { - const clientClasses = Array.from(new Set(this.nodes.mapBy('nodeClass'))).compact(); + const clientClasses = Array.from( + new Set(this.nodes.mapBy('nodeClass')) + ).compact(); // Update query param when the list of datacenters changes. scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpClientClass', serialize(intersection(clientClasses, this.selectionClientClass))); + this.set( + 'qpClientClass', + serialize(intersection(clientClasses, this.selectionClientClass)) + ); }); - return clientClasses.sort().map((clientClass) => ({ key: clientClass, label: clientClass })); + return clientClasses + .sort() + .map((clientClass) => ({ key: clientClass, label: clientClass })); } @action diff --git a/ui/app/controllers/jobs/job/definition.js b/ui/app/controllers/jobs/job/definition.js index faa94d92f..a428f941b 100644 --- a/ui/app/controllers/jobs/job/definition.js +++ b/ui/app/controllers/jobs/job/definition.js @@ -4,7 +4,9 @@ import { alias } from '@ember/object/computed'; import classic from 'ember-classic-decorator'; @classic -export default class DefinitionController extends Controller.extend(WithNamespaceResetting) { +export default class DefinitionController extends Controller.extend( + WithNamespaceResetting +) { @alias('model.job') job; @alias('model.definition') definition; diff --git a/ui/app/controllers/jobs/job/deployments.js b/ui/app/controllers/jobs/job/deployments.js index cbce847e2..f6b71c167 100644 --- a/ui/app/controllers/jobs/job/deployments.js +++ b/ui/app/controllers/jobs/job/deployments.js @@ -4,6 +4,8 @@ import { alias } from '@ember/object/computed'; import classic from 'ember-classic-decorator'; @classic -export default class DeploymentsController extends Controller.extend(WithNamespaceResetting) { +export default class DeploymentsController extends Controller.extend( + WithNamespaceResetting +) { @alias('model') job; } diff --git a/ui/app/controllers/jobs/job/index.js b/ui/app/controllers/jobs/job/index.js index b57a44343..9feccefa5 100644 --- a/ui/app/controllers/jobs/job/index.js +++ b/ui/app/controllers/jobs/job/index.js @@ -6,7 +6,9 @@ import { action } from '@ember/object'; import classic from 'ember-classic-decorator'; @classic -export default class IndexController extends Controller.extend(WithNamespaceResetting) { +export default class IndexController extends Controller.extend( + WithNamespaceResetting +) { @service system; queryParams = [ @@ -38,7 +40,11 @@ export default class IndexController extends Controller.extend(WithNamespaceRese @action gotoTaskGroup(taskGroup) { - this.transitionToRoute('jobs.job.task-group', taskGroup.get('job'), taskGroup); + this.transitionToRoute( + 'jobs.job.task-group', + taskGroup.get('job'), + taskGroup + ); } @action diff --git a/ui/app/controllers/jobs/job/task-group.js b/ui/app/controllers/jobs/job/task-group.js index 2ee4c3632..592f1508e 100644 --- a/ui/app/controllers/jobs/job/task-group.js +++ b/ui/app/controllers/jobs/job/task-group.js @@ -9,7 +9,10 @@ import { qpBuilder } from 'nomad-ui/utils/classes/query-params'; import Sortable from 'nomad-ui/mixins/sortable'; import Searchable from 'nomad-ui/mixins/searchable'; import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting'; -import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize'; +import { + serialize, + deserializedQueryParam as selection, +} from 'nomad-ui/utils/qp-serialize'; import classic from 'ember-classic-decorator'; @classic @@ -65,10 +68,16 @@ export default class TaskGroupController extends Controller.extend( const { selectionStatus, selectionClient } = this; return this.allocations.filter((alloc) => { - if (selectionStatus.length && !selectionStatus.includes(alloc.clientStatus)) { + if ( + selectionStatus.length && + !selectionStatus.includes(alloc.clientStatus) + ) { return false; } - if (selectionClient.length && !selectionClient.includes(alloc.get('node.shortId'))) { + if ( + selectionClient.length && + !selectionClient.includes(alloc.get('node.shortId')) + ) { return false; } @@ -94,15 +103,23 @@ export default class TaskGroupController extends Controller.extend( @computed('sortedScaleEvents.@each.hasCount', function () { const countEventsCount = this.sortedScaleEvents.filterBy('hasCount').length; - return countEventsCount > 1 && countEventsCount >= this.sortedScaleEvents.length / 2; + return ( + countEventsCount > 1 && + countEventsCount >= this.sortedScaleEvents.length / 2 + ); }) shouldShowScaleEventTimeline; @computed('model.job.{namespace,runningDeployment}') get tooltipText() { - if (this.can.cannot('scale job', null, { namespace: this.model.job.namespace.get('name') })) + if ( + this.can.cannot('scale job', null, { + namespace: this.model.job.namespace.get('name'), + }) + ) return "You aren't allowed to scale task groups"; - if (this.model.job.runningDeployment) return 'You cannot scale task groups during a deployment'; + if (this.model.job.runningDeployment) + return 'You cannot scale task groups during a deployment'; return undefined; } @@ -128,12 +145,17 @@ export default class TaskGroupController extends Controller.extend( @computed('model.allocations.[]', 'selectionClient') get optionsClients() { - const clients = Array.from(new Set(this.model.allocations.mapBy('node.shortId'))).compact(); + const clients = Array.from( + new Set(this.model.allocations.mapBy('node.shortId')) + ).compact(); // Update query param when the list of clients changes. scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.set('qpClient', serialize(intersection(clients, this.selectionClient))); + this.set( + 'qpClient', + serialize(intersection(clients, this.selectionClient)) + ); }); return clients.sort().map((dc) => ({ key: dc, label: dc })); diff --git a/ui/app/controllers/jobs/job/versions.js b/ui/app/controllers/jobs/job/versions.js index 087100ea0..195f73619 100644 --- a/ui/app/controllers/jobs/job/versions.js +++ b/ui/app/controllers/jobs/job/versions.js @@ -12,14 +12,18 @@ const errorLevelToAlertClass = { }; @classic -export default class VersionsController extends Controller.extend(WithNamespaceResetting) { +export default class VersionsController extends Controller.extend( + WithNamespaceResetting +) { error = null; @alias('model') job; @computed('error.level') get errorLevelClass() { - return errorLevelToAlertClass[this.get('error.level')] || alertClassFallback; + return ( + errorLevelToAlertClass[this.get('error.level')] || alertClassFallback + ); } onDismiss() { diff --git a/ui/app/controllers/optimize.js b/ui/app/controllers/optimize.js index 7dd087141..53331cc8f 100644 --- a/ui/app/controllers/optimize.js +++ b/ui/app/controllers/optimize.js @@ -7,7 +7,10 @@ import { inject as service } from '@ember/service'; import { scheduleOnce } from '@ember/runloop'; import { task } from 'ember-concurrency'; import intersection from 'lodash.intersection'; -import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize'; +import { + serialize, + deserializedQueryParam as selection, +} from 'nomad-ui/utils/qp-serialize'; import EmberObject, { computed } from '@ember/object'; import { alias } from '@ember/object/computed'; @@ -104,13 +107,17 @@ export default class OptimizeController extends Controller { get optionsDatacenter() { const flatten = (acc, val) => acc.concat(val); - const allDatacenters = new Set(this.summaries.mapBy('job.datacenters').reduce(flatten, [])); + const allDatacenters = new Set( + this.summaries.mapBy('job.datacenters').reduce(flatten, []) + ); // Remove any invalid datacenters from the query param/selection const availableDatacenters = Array.from(allDatacenters).compact(); scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.qpDatacenter = serialize(intersection(availableDatacenters, this.selectionDatacenter)); + this.qpDatacenter = serialize( + intersection(availableDatacenters, this.selectionDatacenter) + ); }); return availableDatacenters.sort().map((dc) => ({ key: dc, label: dc })); @@ -144,7 +151,9 @@ export default class OptimizeController extends Controller { const availablePrefixes = prefixes.mapBy('prefix'); scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects - this.qpPrefix = serialize(intersection(availablePrefixes, this.selectionPrefix)); + this.qpPrefix = serialize( + intersection(availablePrefixes, this.selectionPrefix) + ); }); // Sort, format, and include the count in the label @@ -171,7 +180,10 @@ export default class OptimizeController extends Controller { return false; } - if (this.qpNamespace !== '*' && job.get('namespace.name') !== this.qpNamespace) { + if ( + this.qpNamespace !== '*' && + job.get('namespace.name') !== this.qpNamespace + ) { return false; } @@ -183,12 +195,18 @@ export default class OptimizeController extends Controller { return false; } - if (datacenters.length && !job.get('datacenters').find((dc) => datacenters.includes(dc))) { + if ( + datacenters.length && + !job.get('datacenters').find((dc) => datacenters.includes(dc)) + ) { return false; } const name = job.get('name'); - if (prefixes.length && !prefixes.find((prefix) => name.startsWith(prefix))) { + if ( + prefixes.length && + !prefixes.find((prefix) => name.startsWith(prefix)) + ) { return false; } @@ -207,8 +225,12 @@ export default class OptimizeController extends Controller { // This is a task because the accordion uses timeouts for animation // eslint-disable-next-line require-yield @(task(function* () { - const currentSummaryIndex = this.filteredSummaries.indexOf(this.activeRecommendationSummary); - const nextSummary = this.filteredSummaries.objectAt(currentSummaryIndex + 1); + const currentSummaryIndex = this.filteredSummaries.indexOf( + this.activeRecommendationSummary + ); + const nextSummary = this.filteredSummaries.objectAt( + currentSummaryIndex + 1 + ); if (nextSummary) { this.transitionToSummary(nextSummary); diff --git a/ui/app/controllers/topology.js b/ui/app/controllers/topology.js index d5bfbf4a4..c3866eb5e 100644 --- a/ui/app/controllers/topology.js +++ b/ui/app/controllers/topology.js @@ -31,13 +31,17 @@ export default class TopologyControllers extends Controller { @computed('model.nodes.@each.resources') get totalMemory() { - const mibs = this.model.nodes.mapBy('resources.memory').reduce(sumAggregator, 0); + const mibs = this.model.nodes + .mapBy('resources.memory') + .reduce(sumAggregator, 0); return mibs * 1024 * 1024; } @computed('model.nodes.@each.resources') get totalCPU() { - return this.model.nodes.mapBy('resources.cpu').reduce((sum, cpu) => sum + (cpu || 0), 0); + return this.model.nodes + .mapBy('resources.cpu') + .reduce((sum, cpu) => sum + (cpu || 0), 0); } @computed('totalMemory') @@ -70,7 +74,9 @@ export default class TopologyControllers extends Controller { @computed('scheduledAllocations.@each.allocatedResources') get totalReservedCPU() { - return this.scheduledAllocations.mapBy('allocatedResources.cpu').reduce(sumAggregator, 0); + return this.scheduledAllocations + .mapBy('allocatedResources.cpu') + .reduce(sumAggregator, 0); } @computed('totalMemory', 'totalReservedMemory') @@ -85,23 +91,35 @@ export default class TopologyControllers extends Controller { return this.totalReservedCPU / this.totalCPU; } - @computed('activeAllocation.taskGroupName', 'scheduledAllocations.@each.{job,taskGroupName}') + @computed( + 'activeAllocation.taskGroupName', + 'scheduledAllocations.@each.{job,taskGroupName}' + ) get siblingAllocations() { if (!this.activeAllocation) return []; const taskGroup = this.activeAllocation.taskGroupName; const jobId = this.activeAllocation.belongsTo('job').id(); return this.scheduledAllocations.filter((allocation) => { - return allocation.taskGroupName === taskGroup && allocation.belongsTo('job').id() === jobId; + return ( + allocation.taskGroupName === taskGroup && + allocation.belongsTo('job').id() === jobId + ); }); } @computed('activeNode') get nodeUtilization() { const node = this.activeNode; - const [formattedMemory, memoryUnits] = reduceBytes(node.memory * 1024 * 1024); - const totalReservedMemory = node.allocations.mapBy('memory').reduce(sumAggregator, 0); - const totalReservedCPU = node.allocations.mapBy('cpu').reduce(sumAggregator, 0); + const [formattedMemory, memoryUnits] = reduceBytes( + node.memory * 1024 * 1024 + ); + const totalReservedMemory = node.allocations + .mapBy('memory') + .reduce(sumAggregator, 0); + const totalReservedCPU = node.allocations + .mapBy('cpu') + .reduce(sumAggregator, 0); return { totalMemoryFormatted: formattedMemory.toFixed(2), diff --git a/ui/app/helpers/bind.js b/ui/app/helpers/bind.js index 36e3bf4e2..d48dab528 100644 --- a/ui/app/helpers/bind.js +++ b/ui/app/helpers/bind.js @@ -9,7 +9,10 @@ import { assert } from '@ember/debug'; * Returns a version of a function bound to the template target (e.g., component or controller) */ export function bind([func, target]) { - assert('A function is required as the first argument', typeof func === 'function'); + assert( + 'A function is required as the first argument', + typeof func === 'function' + ); assert('A context is required as the second argument', target); return func.bind(target); } diff --git a/ui/app/helpers/is-object.js b/ui/app/helpers/is-object.js index 97dd42e65..53804c904 100644 --- a/ui/app/helpers/is-object.js +++ b/ui/app/helpers/is-object.js @@ -1,7 +1,8 @@ import Helper from '@ember/component/helper'; export function isObject([value]) { - const isObject = !Array.isArray(value) && value !== null && typeof value === 'object'; + const isObject = + !Array.isArray(value) && value !== null && typeof value === 'object'; return isObject; } diff --git a/ui/app/helpers/x-icon.js b/ui/app/helpers/x-icon.js index f53a50543..770428299 100644 --- a/ui/app/helpers/x-icon.js +++ b/ui/app/helpers/x-icon.js @@ -13,7 +13,9 @@ import SVGs from '../svgs'; */ export function xIcon(params, options) { const name = params[0]; - const classes = [options.class, 'icon', `icon-is-${name}`].compact().join(' '); + const classes = [options.class, 'icon', `icon-is-${name}`] + .compact() + .join(' '); return inlineSvg(SVGs, name, { class: classes }); } diff --git a/ui/app/mixins/searchable.js b/ui/app/mixins/searchable.js index faf05fc8a..04cc7ef3a 100644 --- a/ui/app/mixins/searchable.js +++ b/ui/app/mixins/searchable.js @@ -95,7 +95,11 @@ export default Mixin.create({ if (this.exactMatchEnabled) { results.push( - ...exactMatchSearch(searchTerm, this.listToSearch, this.exactMatchSearchProps) + ...exactMatchSearch( + searchTerm, + this.listToSearch, + this.exactMatchSearchProps + ) ); } @@ -114,7 +118,9 @@ export default Mixin.create({ } if (this.regexEnabled) { - results.push(...regexSearch(searchTerm, this.listToSearch, this.regexSearchProps)); + results.push( + ...regexSearch(searchTerm, this.listToSearch, this.regexSearchProps) + ); } return results.uniq(); @@ -134,7 +140,9 @@ function regexSearch(term, list, keys) { const regex = new RegExp(term, 'i'); // Test the value of each key for each object against the regex // All that match are returned. - return list.filter((item) => keys.some((key) => regex.test(get(item, key)))); + return list.filter((item) => + keys.some((key) => regex.test(get(item, key))) + ); } catch (e) { // Swallow the error; most likely due to an eager search of an incomplete regex } diff --git a/ui/app/mixins/sortable-factory.js b/ui/app/mixins/sortable-factory.js index cbd76805a..38510b9fb 100644 --- a/ui/app/mixins/sortable-factory.js +++ b/ui/app/mixins/sortable-factory.js @@ -19,7 +19,9 @@ import { warn } from '@ember/debug'; - listSorted: a copy of listToSort that has been sorted */ export default function sortableFactory(properties, fromSortableMixin) { - const eachProperties = properties.map((property) => `listToSort.@each.${property}`); + const eachProperties = properties.map( + (property) => `listToSort.@each.${property}` + ); // eslint-disable-next-line ember/no-new-mixins return Mixin.create({ @@ -44,10 +46,13 @@ export default function sortableFactory(properties, fromSortableMixin) { 'Using SortableFactory without property keys means the list will only sort when the members change, not when any of their properties change.'; if (fromSortableMixin) { - message += ' The Sortable mixin is deprecated in favor of SortableFactory.'; + message += + ' The Sortable mixin is deprecated in favor of SortableFactory.'; } - warn(message, properties.length > 0, { id: 'nomad.no-sortable-properties' }); + warn(message, properties.length > 0, { + id: 'nomad.no-sortable-properties', + }); // eslint-disable-next-line ember/no-side-effects this.set('_sortableFactoryWarningPrinted', true); } diff --git a/ui/app/mixins/window-resizable.js b/ui/app/mixins/window-resizable.js index 6ac4aee9b..164cb4c66 100644 --- a/ui/app/mixins/window-resizable.js +++ b/ui/app/mixins/window-resizable.js @@ -6,7 +6,10 @@ import { on } from '@ember/object/evented'; // eslint-disable-next-line ember/no-new-mixins export default Mixin.create({ windowResizeHandler() { - assert('windowResizeHandler needs to be overridden in the Component', false); + assert( + 'windowResizeHandler needs to be overridden in the Component', + false + ); }, setupWindowResize: on('didInsertElement', function () { diff --git a/ui/app/mixins/with-watchers.js b/ui/app/mixins/with-watchers.js index 2f131a85c..b74a2b031 100644 --- a/ui/app/mixins/with-watchers.js +++ b/ui/app/mixins/with-watchers.js @@ -36,7 +36,10 @@ export default Mixin.create(WithVisibilityDetection, { actions: { willTransition(transition) { // Don't cancel watchers if transitioning into a sub-route - if (!transition.intent.name || !transition.intent.name.startsWith(this.routeName)) { + if ( + !transition.intent.name || + !transition.intent.name.startsWith(this.routeName) + ) { this.cancelAllWatchers(); } diff --git a/ui/app/models/allocation.js b/ui/app/models/allocation.js index 79db30dd1..dd2aad6a0 100644 --- a/ui/app/models/allocation.js +++ b/ui/app/models/allocation.js @@ -77,8 +77,10 @@ export default class Allocation extends Model { @belongsTo('allocation', { inverse: 'nextAllocation' }) previousAllocation; @belongsTo('allocation', { inverse: 'previousAllocation' }) nextAllocation; - @hasMany('allocation', { inverse: 'preemptedByAllocation' }) preemptedAllocations; - @belongsTo('allocation', { inverse: 'preemptedAllocations' }) preemptedByAllocation; + @hasMany('allocation', { inverse: 'preemptedByAllocation' }) + preemptedAllocations; + @belongsTo('allocation', { inverse: 'preemptedAllocations' }) + preemptedByAllocation; @attr('boolean') wasPreempted; @belongsTo('evaluation') followUpEvaluation; @@ -135,7 +137,11 @@ export default class Allocation extends Model { return this.get('rescheduleEvents.length') > 0 || this.nextAllocation; } - @computed('clientStatus', 'followUpEvaluation.content', 'nextAllocation.content') + @computed( + 'clientStatus', + 'followUpEvaluation.content', + 'nextAllocation.content' + ) get hasStoppedRescheduling() { return ( !this.get('nextAllocation.content') && diff --git a/ui/app/models/deployment.js b/ui/app/models/deployment.js index 0d500dc3a..0136f6380 100644 --- a/ui/app/models/deployment.js +++ b/ui/app/models/deployment.js @@ -24,7 +24,10 @@ export default class Deployment extends Model { this.status === 'running' && this.taskGroupSummaries .toArray() - .some((summary) => summary.get('requiresPromotion') && !summary.get('promoted')) + .some( + (summary) => + summary.get('requiresPromotion') && !summary.get('promoted') + ) ); } @@ -38,7 +41,10 @@ export default class Deployment extends Model { @computed('versionNumber', 'job.versions.content.@each.number') get version() { - return (this.get('job.versions') || []).findBy('number', this.versionNumber); + return (this.get('job.versions') || []).findBy( + 'number', + this.versionNumber + ); } // Dependent keys can only go one level past an @each so an alias is needed @@ -65,7 +71,10 @@ export default class Deployment extends Model { } promote() { - assert('A deployment needs to requirePromotion to be promoted', this.requiresPromotion); + assert( + 'A deployment needs to requirePromotion to be promoted', + this.requiresPromotion + ); return this.store.adapterFor('deployment').promote(this); } diff --git a/ui/app/models/evaluation.js b/ui/app/models/evaluation.js index 8cd50ba2a..944d03e10 100644 --- a/ui/app/models/evaluation.js +++ b/ui/app/models/evaluation.js @@ -11,7 +11,8 @@ export default class Evaluation extends Model { @attr('string') triggeredBy; @attr('string') status; @attr('string') statusDescription; - @fragmentArray('placement-failure', { defaultValue: () => [] }) failedTGAllocs; + @fragmentArray('placement-failure', { defaultValue: () => [] }) + failedTGAllocs; @bool('failedTGAllocs.length') hasPlacementFailures; @equal('status', 'blocked') isBlocked; diff --git a/ui/app/models/job-plan.js b/ui/app/models/job-plan.js index b7a06db06..7cebc1cc0 100644 --- a/ui/app/models/job-plan.js +++ b/ui/app/models/job-plan.js @@ -5,6 +5,7 @@ import { hasMany } from '@ember-data/model'; export default class JobPlan extends Model { @attr() diff; - @fragmentArray('placement-failure', { defaultValue: () => [] }) failedTGAllocs; + @fragmentArray('placement-failure', { defaultValue: () => [] }) + failedTGAllocs; @hasMany('allocation') preemptions; } diff --git a/ui/app/models/job.js b/ui/app/models/job.js index e9ccbf1ee..b157592ef 100644 --- a/ui/app/models/job.js +++ b/ui/app/models/job.js @@ -51,7 +51,9 @@ export default class Job extends Model { // The parent job name is prepended to child launch job names @computed('name', 'parent.content') get trimmedName() { - return this.get('parent.content') ? this.name.replace(/.+?\//, '') : this.name; + return this.get('parent.content') + ? this.name.replace(/.+?\//, '') + : this.name; } // A composite of type and other job attributes to determine @@ -69,7 +71,12 @@ export default class Job extends Model { // A composite of type and other job attributes to determine // type for templating rather than scheduling - @computed('type', 'periodic', 'parameterized', 'parent.{periodic,parameterized}') + @computed( + 'type', + 'periodic', + 'parameterized', + 'parent.{periodic,parameterized}' + ) get templateType() { const type = this.type; @@ -158,7 +165,9 @@ export default class Job extends Model { @computed('evaluations.@each.isBlocked') get hasBlockedEvaluation() { - return this.evaluations.toArray().some((evaluation) => evaluation.get('isBlocked')); + return this.evaluations + .toArray() + .some((evaluation) => evaluation.get('isBlocked')); } @and('latestFailureEvaluation', 'hasBlockedEvaluation') hasPlacementFailures; @@ -256,7 +265,8 @@ export default class Job extends Model { } scale(group, count, message) { - if (message == null) message = `Manually scaled to ${count} from the Nomad UI`; + if (message == null) + message = `Manually scaled to ${count} from the Nomad UI`; return this.store.adapterFor('job').scale(this, group, count, message); } @@ -278,7 +288,10 @@ export default class Job extends Model { } resetId() { - this.set('id', JSON.stringify([this.plainId, this.get('namespace.name') || 'default'])); + this.set( + 'id', + JSON.stringify([this.plainId, this.get('namespace.name') || 'default']) + ); } @computed('status') diff --git a/ui/app/models/node.js b/ui/app/models/node.js index e4a496312..3e985bd4d 100644 --- a/ui/app/models/node.js +++ b/ui/app/models/node.js @@ -63,7 +63,9 @@ export default class Node extends Model { @computed('allocations.@each.{isMigrating,isRunning}') get migratingAllocations() { - return this.allocations.filter((alloc) => alloc.isRunning && alloc.isMigrating); + return this.allocations.filter( + (alloc) => alloc.isRunning && alloc.isMigrating + ); } @computed('allocations.@each.{isMigrating,isRunning,modifyTime}') diff --git a/ui/app/models/recommendation-summary.js b/ui/app/models/recommendation-summary.js index 459b780e5..e3ca79226 100644 --- a/ui/app/models/recommendation-summary.js +++ b/ui/app/models/recommendation-summary.js @@ -5,7 +5,8 @@ import { action } from '@ember/object'; export default class RecommendationSummary extends Model { @hasMany('recommendation') recommendations; - @hasMany('recommendation', { defaultValue: () => [] }) excludedRecommendations; + @hasMany('recommendation', { defaultValue: () => [] }) + excludedRecommendations; @belongsTo('job') job; @attr('string') jobId; @@ -30,7 +31,8 @@ export default class RecommendationSummary extends Model { @action toggleRecommendation(recommendation) { if (this.excludedRecommendations.includes(recommendation)) { - this.excludedRecommendations = this.excludedRecommendations.removeObject(recommendation); + this.excludedRecommendations = + this.excludedRecommendations.removeObject(recommendation); } else { this.excludedRecommendations.pushObject(recommendation); } @@ -39,9 +41,14 @@ export default class RecommendationSummary extends Model { @action toggleAllRecommendationsForResource(resource, enabled) { if (enabled) { - this.excludedRecommendations = this.excludedRecommendations.rejectBy('resource', resource); + this.excludedRecommendations = this.excludedRecommendations.rejectBy( + 'resource', + resource + ); } else { - this.excludedRecommendations.pushObjects(this.recommendations.filterBy('resource', resource)); + this.excludedRecommendations.pushObjects( + this.recommendations.filterBy('resource', resource) + ); } } diff --git a/ui/app/models/recommendation.js b/ui/app/models/recommendation.js index cb36e2504..36e2ed341 100644 --- a/ui/app/models/recommendation.js +++ b/ui/app/models/recommendation.js @@ -4,7 +4,8 @@ import { get } from '@ember/object'; export default class Recommendation extends Model { @belongsTo('job') job; - @belongsTo('recommendation-summary', { inverse: 'recommendations' }) recommendationSummary; + @belongsTo('recommendation-summary', { inverse: 'recommendations' }) + recommendationSummary; @attr('date') submitTime; @@ -22,7 +23,8 @@ export default class Recommendation extends Model { @attr('number') value; get currentValue() { - const resourceProperty = this.resource === 'CPU' ? 'reservedCPU' : 'reservedMemory'; + const resourceProperty = + this.resource === 'CPU' ? 'reservedCPU' : 'reservedMemory'; return get(this, `task.${resourceProperty}`); } diff --git a/ui/app/models/task-group-scale.js b/ui/app/models/task-group-scale.js index 5429a2837..9eb5238d4 100644 --- a/ui/app/models/task-group-scale.js +++ b/ui/app/models/task-group-scale.js @@ -1,7 +1,10 @@ import { computed } from '@ember/object'; import Fragment from 'ember-data-model-fragments/fragment'; import { attr } from '@ember-data/model'; -import { fragmentOwner, fragmentArray } from 'ember-data-model-fragments/attributes'; +import { + fragmentOwner, + fragmentArray, +} from 'ember-data-model-fragments/attributes'; export default class TaskGroupScale extends Fragment { @fragmentOwner() jobScale; diff --git a/ui/app/models/task-group.js b/ui/app/models/task-group.js index a1579a2e1..afeafe69c 100644 --- a/ui/app/models/task-group.js +++ b/ui/app/models/task-group.js @@ -1,7 +1,11 @@ import { computed } from '@ember/object'; import Fragment from 'ember-data-model-fragments/fragment'; import { attr } from '@ember-data/model'; -import { fragmentOwner, fragmentArray, fragment } from 'ember-data-model-fragments/attributes'; +import { + fragmentOwner, + fragmentArray, + fragment, +} from 'ember-data-model-fragments/attributes'; import sumAggregation from '../utils/properties/sum-aggregation'; import classic from 'ember-classic-decorator'; @@ -39,7 +43,10 @@ export default class TaskGroup extends Fragment { @computed('job.allocations.@each.taskGroup', 'name') get allocations() { - return maybe(this.get('job.allocations')).filterBy('taskGroupName', this.name); + return maybe(this.get('job.allocations')).filterBy( + 'taskGroupName', + this.name + ); } @sumAggregation('tasks', 'reservedCPU') reservedCPU; @@ -57,13 +64,17 @@ export default class TaskGroup extends Fragment { @computed('job.latestFailureEvaluation.failedTGAllocs.[]', 'name') get placementFailures() { - const placementFailures = this.get('job.latestFailureEvaluation.failedTGAllocs'); + const placementFailures = this.get( + 'job.latestFailureEvaluation.failedTGAllocs' + ); return placementFailures && placementFailures.findBy('name', this.name); } @computed('summary.{queuedAllocs,startingAllocs}') get queuedOrStartingAllocs() { - return this.get('summary.queuedAllocs') + this.get('summary.startingAllocs'); + return ( + this.get('summary.queuedAllocs') + this.get('summary.startingAllocs') + ); } @computed('job.taskGroupSummaries.[]', 'name') @@ -73,7 +84,10 @@ export default class TaskGroup extends Fragment { @computed('job.scaleState.taskGroupScales.[]', 'name') get scaleState() { - return maybe(this.get('job.scaleState.taskGroupScales')).findBy('name', this.name); + return maybe(this.get('job.scaleState.taskGroupScales')).findBy( + 'name', + this.name + ); } scale(count, message) { diff --git a/ui/app/models/task-state.js b/ui/app/models/task-state.js index 416a89c8e..0f80cdc30 100644 --- a/ui/app/models/task-state.js +++ b/ui/app/models/task-state.js @@ -2,7 +2,11 @@ import { computed } from '@ember/object'; import { alias, none, and } from '@ember/object/computed'; import Fragment from 'ember-data-model-fragments/fragment'; import { attr } from '@ember-data/model'; -import { fragment, fragmentOwner, fragmentArray } from 'ember-data-model-fragments/attributes'; +import { + fragment, + fragmentOwner, + fragmentArray, +} from 'ember-data-model-fragments/attributes'; import classic from 'ember-classic-decorator'; @classic diff --git a/ui/app/models/task.js b/ui/app/models/task.js index bf9a0a3eb..83c22f64e 100644 --- a/ui/app/models/task.js +++ b/ui/app/models/task.js @@ -1,6 +1,10 @@ import { attr } from '@ember-data/model'; import Fragment from 'ember-data-model-fragments/fragment'; -import { fragment, fragmentArray, fragmentOwner } from 'ember-data-model-fragments/attributes'; +import { + fragment, + fragmentArray, + fragmentOwner, +} from 'ember-data-model-fragments/attributes'; import { computed } from '@ember/object'; export default class Task extends Fragment { diff --git a/ui/app/models/volume.js b/ui/app/models/volume.js index 6e290af5f..f7de4b1f0 100644 --- a/ui/app/models/volume.js +++ b/ui/app/models/volume.js @@ -14,7 +14,10 @@ export default class Volume extends Model { @computed('writeAllocations.[]', 'readAllocations.[]') get allocations() { - return [...this.writeAllocations.toArray(), ...this.readAllocations.toArray()]; + return [ + ...this.writeAllocations.toArray(), + ...this.readAllocations.toArray(), + ]; } @attr('number') currentWriters; diff --git a/ui/app/routes/allocations/allocation/fs.js b/ui/app/routes/allocations/allocation/fs.js index c988b7e05..1f01725df 100644 --- a/ui/app/routes/allocations/allocation/fs.js +++ b/ui/app/routes/allocations/allocation/fs.js @@ -15,7 +15,9 @@ export default class FsRoute extends Route { return RSVP.hash({ path: decodedPath, allocation, - directoryEntries: allocation.ls(decodedPath).catch(notifyError(this)), + directoryEntries: allocation + .ls(decodedPath) + .catch(notifyError(this)), isFile: false, }); } else { @@ -30,8 +32,17 @@ export default class FsRoute extends Route { .catch(notifyError(this)); } - setupController(controller, { path, allocation, directoryEntries, isFile, stat } = {}) { + setupController( + controller, + { path, allocation, directoryEntries, isFile, stat } = {} + ) { super.setupController(...arguments); - controller.setProperties({ path, allocation, directoryEntries, isFile, stat }); + controller.setProperties({ + path, + allocation, + directoryEntries, + isFile, + stat, + }); } } diff --git a/ui/app/routes/allocations/allocation/index.js b/ui/app/routes/allocations/allocation/index.js index e4de01cdb..672ce3330 100644 --- a/ui/app/routes/allocations/allocation/index.js +++ b/ui/app/routes/allocations/allocation/index.js @@ -4,7 +4,8 @@ export default class IndexRoute extends Route { setupController(controller, model) { // Suppress the preemptedByAllocation fetch error in the event it's a 404 if (model) { - const setPreempter = () => controller.set('preempter', model.preemptedByAllocation); + const setPreempter = () => + controller.set('preempter', model.preemptedByAllocation); model.preemptedByAllocation.then(setPreempter, setPreempter); } diff --git a/ui/app/routes/allocations/allocation/task.js b/ui/app/routes/allocations/allocation/task.js index c17a4b8bb..8513aecbc 100644 --- a/ui/app/routes/allocations/allocation/task.js +++ b/ui/app/routes/allocations/allocation/task.js @@ -16,7 +16,9 @@ export default class TaskRoute extends Route { const task = allocation.get('states').findBy('name', name); if (!task) { - const err = new EmberError(`Task ${name} not found for allocation ${allocation.get('id')}`); + const err = new EmberError( + `Task ${name} not found for allocation ${allocation.get('id')}` + ); err.code = '404'; this.controllerFor('application').set('error', err); } diff --git a/ui/app/routes/allocations/allocation/task/fs.js b/ui/app/routes/allocations/allocation/task/fs.js index 8ba69555c..3143c9017 100644 --- a/ui/app/routes/allocations/allocation/task/fs.js +++ b/ui/app/routes/allocations/allocation/task/fs.js @@ -14,13 +14,18 @@ export default class FsRoute extends Route { decodedPath.startsWith('/') ? '' : '/' }${decodedPath}`; - return RSVP.all([allocation.stat(pathWithTaskName), taskState.get('allocation.node')]) + return RSVP.all([ + allocation.stat(pathWithTaskName), + taskState.get('allocation.node'), + ]) .then(([statJson]) => { if (statJson.IsDir) { return RSVP.hash({ path: decodedPath, taskState, - directoryEntries: allocation.ls(pathWithTaskName).catch(notifyError(this)), + directoryEntries: allocation + .ls(pathWithTaskName) + .catch(notifyError(this)), isFile: false, }); } else { @@ -35,8 +40,17 @@ export default class FsRoute extends Route { .catch(notifyError(this)); } - setupController(controller, { path, taskState, directoryEntries, isFile, stat } = {}) { + setupController( + controller, + { path, taskState, directoryEntries, isFile, stat } = {} + ) { super.setupController(...arguments); - controller.setProperties({ path, taskState, directoryEntries, isFile, stat }); + controller.setProperties({ + path, + taskState, + directoryEntries, + isFile, + stat, + }); } } diff --git a/ui/app/routes/application.js b/ui/app/routes/application.js index f4fb78e76..be815bd44 100644 --- a/ui/app/routes/application.js +++ b/ui/app/routes/application.js @@ -50,13 +50,17 @@ export default class ApplicationRoute extends Route { this.controllerFor('application').set('error', e); } - const fetchSelfTokenAndPolicies = this.get('token.fetchSelfTokenAndPolicies') + const fetchSelfTokenAndPolicies = this.get( + 'token.fetchSelfTokenAndPolicies' + ) .perform() .catch(); const fetchLicense = this.get('system.fetchLicense').perform().catch(); - const checkFuzzySearchPresence = this.get('system.checkFuzzySearchPresence') + const checkFuzzySearchPresence = this.get( + 'system.checkFuzzySearchPresence' + ) .perform() .catch(); diff --git a/ui/app/routes/clients/client/index.js b/ui/app/routes/clients/client/index.js index 04f66faa6..b1383ca47 100644 --- a/ui/app/routes/clients/client/index.js +++ b/ui/app/routes/clients/client/index.js @@ -1,7 +1,10 @@ import { inject as service } from '@ember/service'; import Route from '@ember/routing/route'; import { collect } from '@ember/object/computed'; -import { watchRecord, watchRelationship } from 'nomad-ui/utils/properties/watch'; +import { + watchRecord, + watchRelationship, +} from 'nomad-ui/utils/properties/watch'; import WithWatchers from 'nomad-ui/mixins/with-watchers'; export default class ClientRoute extends Route.extend(WithWatchers) { diff --git a/ui/app/routes/csi/plugins.js b/ui/app/routes/csi/plugins.js index 25728b2d2..9d24bc239 100644 --- a/ui/app/routes/csi/plugins.js +++ b/ui/app/routes/csi/plugins.js @@ -7,6 +7,8 @@ export default class PluginsRoute extends Route.extend(WithForbiddenState) { @service store; model() { - return this.store.query('plugin', { type: 'csi' }).catch(notifyForbidden(this)); + return this.store + .query('plugin', { type: 'csi' }) + .catch(notifyForbidden(this)); } } diff --git a/ui/app/routes/csi/plugins/plugin.js b/ui/app/routes/csi/plugins/plugin.js index 9728e5be1..41cbfb381 100644 --- a/ui/app/routes/csi/plugins/plugin.js +++ b/ui/app/routes/csi/plugins/plugin.js @@ -11,6 +11,8 @@ export default class PluginRoute extends Route { } model(params) { - return this.store.findRecord('plugin', `csi/${params.plugin_name}`).catch(notifyError(this)); + return this.store + .findRecord('plugin', `csi/${params.plugin_name}`) + .catch(notifyError(this)); } } diff --git a/ui/app/routes/csi/volumes/index.js b/ui/app/routes/csi/volumes/index.js index f2db7cfa0..62d3db557 100644 --- a/ui/app/routes/csi/volumes/index.js +++ b/ui/app/routes/csi/volumes/index.js @@ -7,7 +7,10 @@ import WithWatchers from 'nomad-ui/mixins/with-watchers'; import notifyForbidden from 'nomad-ui/utils/notify-forbidden'; import WithForbiddenState from 'nomad-ui/mixins/with-forbidden-state'; -export default class IndexRoute extends Route.extend(WithWatchers, WithForbiddenState) { +export default class IndexRoute extends Route.extend( + WithWatchers, + WithForbiddenState +) { @service store; queryParams = { @@ -29,7 +32,10 @@ export default class IndexRoute extends Route.extend(WithWatchers, WithForbidden controller.set('namespacesWatch', this.watchNamespaces.perform()); controller.set( 'modelWatch', - this.watchVolumes.perform({ type: 'csi', namespace: controller.qpNamespace }) + this.watchVolumes.perform({ + type: 'csi', + namespace: controller.qpNamespace, + }) ); } diff --git a/ui/app/routes/csi/volumes/volume.js b/ui/app/routes/csi/volumes/volume.js index 01afa4b4c..8c5041fc4 100644 --- a/ui/app/routes/csi/volumes/volume.js +++ b/ui/app/routes/csi/volumes/volume.js @@ -16,7 +16,7 @@ export default class VolumeRoute extends Route.extend(WithWatchers) { if (!model) return; controller.set('watchers', { - model: this.watch.perform(model), + model: this.watch.perform(model) }); } @@ -30,7 +30,7 @@ export default class VolumeRoute extends Route.extend(WithWatchers) { const fullId = JSON.stringify([`csi/${name}`, namespace || 'default']); return RSVP.hash({ volume: this.store.findRecord('volume', fullId, { reload: true }), - namespaces: this.store.findAll('namespace'), + namespaces: this.store.findAll('namespace') }) .then(hash => hash.volume) .catch(notifyError(this)); diff --git a/ui/app/routes/exec.js b/ui/app/routes/exec.js index 89b2613cb..33493e7a4 100644 --- a/ui/app/routes/exec.js +++ b/ui/app/routes/exec.js @@ -3,7 +3,10 @@ import Route from '@ember/routing/route'; import notifyError from 'nomad-ui/utils/notify-error'; import { collect } from '@ember/object/computed'; import WithWatchers from 'nomad-ui/mixins/with-watchers'; -import { watchRecord, watchRelationship } from 'nomad-ui/utils/properties/watch'; +import { + watchRecord, + watchRelationship, +} from 'nomad-ui/utils/properties/watch'; import classic from 'ember-classic-decorator'; @classic diff --git a/ui/app/routes/jobs/index.js b/ui/app/routes/jobs/index.js index a9d4edf39..93bc9d39e 100644 --- a/ui/app/routes/jobs/index.js +++ b/ui/app/routes/jobs/index.js @@ -7,7 +7,10 @@ import WithWatchers from 'nomad-ui/mixins/with-watchers'; import notifyForbidden from 'nomad-ui/utils/notify-forbidden'; import WithForbiddenState from 'nomad-ui/mixins/with-forbidden-state'; -export default class IndexRoute extends Route.extend(WithWatchers, WithForbiddenState) { +export default class IndexRoute extends Route.extend( + WithWatchers, + WithForbiddenState +) { @service store; queryParams = { @@ -18,14 +21,19 @@ export default class IndexRoute extends Route.extend(WithWatchers, WithForbidden model(params) { return RSVP.hash({ - jobs: this.store.query('job', { namespace: params.qpNamespace }).catch(notifyForbidden(this)), + jobs: this.store + .query('job', { namespace: params.qpNamespace }) + .catch(notifyForbidden(this)), namespaces: this.store.findAll('namespace'), }); } startWatchers(controller) { controller.set('namespacesWatch', this.watchNamespaces.perform()); - controller.set('modelWatch', this.watchJobs.perform({ namespace: controller.qpNamesapce })); + controller.set( + 'modelWatch', + this.watchJobs.perform({ namespace: controller.qpNamesapce }) + ); } @watchQuery('job') watchJobs; diff --git a/ui/app/routes/jobs/job/clients.js b/ui/app/routes/jobs/job/clients.js index 71b9d23e8..bcd3a5af3 100644 --- a/ui/app/routes/jobs/job/clients.js +++ b/ui/app/routes/jobs/job/clients.js @@ -1,6 +1,10 @@ import Route from '@ember/routing/route'; import WithWatchers from 'nomad-ui/mixins/with-watchers'; -import { watchRecord, watchRelationship, watchAll } from 'nomad-ui/utils/properties/watch'; +import { + watchRecord, + watchRelationship, + watchAll, +} from 'nomad-ui/utils/properties/watch'; import { collect } from '@ember/object/computed'; export default class ClientsRoute extends Route.extend(WithWatchers) { diff --git a/ui/app/routes/jobs/job/deployments.js b/ui/app/routes/jobs/job/deployments.js index e1e9d6b49..94aa0c1da 100644 --- a/ui/app/routes/jobs/job/deployments.js +++ b/ui/app/routes/jobs/job/deployments.js @@ -7,7 +7,10 @@ import WithWatchers from 'nomad-ui/mixins/with-watchers'; export default class DeploymentsRoute extends Route.extend(WithWatchers) { model() { const job = this.modelFor('jobs.job'); - return job && RSVP.all([job.get('deployments'), job.get('versions')]).then(() => job); + return ( + job && + RSVP.all([job.get('deployments'), job.get('versions')]).then(() => job) + ); } startWatchers(controller, model) { diff --git a/ui/app/routes/jobs/job/index.js b/ui/app/routes/jobs/job/index.js index b085ca744..0f36a70c0 100644 --- a/ui/app/routes/jobs/job/index.js +++ b/ui/app/routes/jobs/job/index.js @@ -5,7 +5,7 @@ import { watchRecord, watchRelationship, watchAll, - watchQuery, + watchQuery } from 'nomad-ui/utils/properties/watch'; import WithWatchers from 'nomad-ui/mixins/with-watchers'; @@ -38,24 +38,30 @@ export default class IndexRoute extends Route.extend(WithWatchers) { allocations: this.watchAllocations.perform(model.job), evaluations: this.watchEvaluations.perform(model.job), latestDeployment: - model.job.get('supportsDeployments') && this.watchLatestDeployment.perform(model.job), + model.job.get('supportsDeployments') && + this.watchLatestDeployment.perform(model.job), list: model.job.get('hasChildren') && - this.watchAllJobs.perform({ namespace: model.job.namespace.get('name') }), + this.watchAllJobs.perform({ + namespace: model.job.namespace.get('name') + }), nodes: this.can.can('read client') && model.job.get('hasClientStatus') && - this.watchNodes.perform(), + this.watchNodes.perform() }); } setupController(controller, model) { // Parameterized and periodic detail pages, which list children jobs, // should sort by submit time. - if (model.job && ['periodic', 'parameterized'].includes(model.job.templateType)) { + if ( + model.job && + ['periodic', 'parameterized'].includes(model.job.templateType) + ) { controller.setProperties({ sortProperty: 'submitTime', - sortDescending: true, + sortDescending: true }); } return super.setupController(...arguments); diff --git a/ui/app/routes/jobs/job/task-group.js b/ui/app/routes/jobs/job/task-group.js index 17ea124f4..7f5a8f49c 100644 --- a/ui/app/routes/jobs/job/task-group.js +++ b/ui/app/routes/jobs/job/task-group.js @@ -2,7 +2,10 @@ import Route from '@ember/routing/route'; import { collect } from '@ember/object/computed'; import EmberError from '@ember/error'; import { resolve, all } from 'rsvp'; -import { watchRecord, watchRelationship } from 'nomad-ui/utils/properties/watch'; +import { + watchRecord, + watchRelationship +} from 'nomad-ui/utils/properties/watch'; import WithWatchers from 'nomad-ui/mixins/with-watchers'; import notifyError from 'nomad-ui/utils/notify-error'; @@ -21,15 +24,18 @@ export default class TaskGroupRoute extends Route.extend(WithWatchers) { .then(() => { const taskGroup = job.get('taskGroups').findBy('name', name); if (!taskGroup) { - const err = new EmberError(`Task group ${name} for job ${job.get('name')} not found`); + const err = new EmberError( + `Task group ${name} for job ${job.get('name')} not found` + ); err.code = '404'; throw err; } // Refresh job allocations before-hand (so page sort works on load) - return all([job.hasMany('allocations').reload(), job.get('scaleState')]).then( - () => taskGroup - ); + return all([ + job.hasMany('allocations').reload(), + job.get('scaleState') + ]).then(() => taskGroup); }) .catch(notifyError(this)); } @@ -42,7 +48,9 @@ export default class TaskGroupRoute extends Route.extend(WithWatchers) { summary: this.watchSummary.perform(job.get('summary')), scale: this.watchScale.perform(job.get('scaleState')), allocations: this.watchAllocations.perform(job), - latestDeployment: job.get('supportsDeployments') && this.watchLatestDeployment.perform(job), + latestDeployment: + job.get('supportsDeployments') && + this.watchLatestDeployment.perform(job) }); } } @@ -53,6 +61,12 @@ export default class TaskGroupRoute extends Route.extend(WithWatchers) { @watchRelationship('allocations') watchAllocations; @watchRelationship('latestDeployment') watchLatestDeployment; - @collect('watchJob', 'watchSummary', 'watchScale', 'watchAllocations', 'watchLatestDeployment') + @collect( + 'watchJob', + 'watchSummary', + 'watchScale', + 'watchAllocations', + 'watchLatestDeployment' + ) watchers; } diff --git a/ui/app/routes/jobs/job/versions.js b/ui/app/routes/jobs/job/versions.js index 2923c321c..dc924197f 100644 --- a/ui/app/routes/jobs/job/versions.js +++ b/ui/app/routes/jobs/job/versions.js @@ -1,6 +1,9 @@ import Route from '@ember/routing/route'; import { collect } from '@ember/object/computed'; -import { watchRecord, watchRelationship } from 'nomad-ui/utils/properties/watch'; +import { + watchRecord, + watchRelationship, +} from 'nomad-ui/utils/properties/watch'; import WithWatchers from 'nomad-ui/mixins/with-watchers'; export default class VersionsRoute extends Route.extend(WithWatchers) { diff --git a/ui/app/routes/jobs/run.js b/ui/app/routes/jobs/run.js index 6d456ead9..915854ebf 100644 --- a/ui/app/routes/jobs/run.js +++ b/ui/app/routes/jobs/run.js @@ -9,7 +9,11 @@ export default class RunRoute extends Route { @service system; beforeModel(transition) { - if (this.can.cannot('run job', null, { namespace: transition.to.queryParams.namespace })) { + if ( + this.can.cannot('run job', null, { + namespace: transition.to.queryParams.namespace, + }) + ) { this.transitionTo('jobs'); } } diff --git a/ui/app/routes/optimize/summary.js b/ui/app/routes/optimize/summary.js index 15044ae72..13e6f30cd 100644 --- a/ui/app/routes/optimize/summary.js +++ b/ui/app/routes/optimize/summary.js @@ -4,11 +4,14 @@ import notifyError from 'nomad-ui/utils/notify-error'; export default class OptimizeSummaryRoute extends Route { async model({ jobNamespace, slug }) { const model = this.modelFor('optimize').summaries.find( - (summary) => summary.slug === slug && summary.jobNamespace === jobNamespace + (summary) => + summary.slug === slug && summary.jobNamespace === jobNamespace ); if (!model) { - const error = new Error(`Unable to find summary for ${slug} in namespace ${jobNamespace}`); + const error = new Error( + `Unable to find summary for ${slug} in namespace ${jobNamespace}` + ); error.code = 404; notifyError(this)(error); } else { diff --git a/ui/app/serializers/agent.js b/ui/app/serializers/agent.js index 75b4ce111..ec6b393c9 100644 --- a/ui/app/serializers/agent.js +++ b/ui/app/serializers/agent.js @@ -15,7 +15,8 @@ export default class AgentSerializer extends ApplicationSerializer { // acts like the API in this case. const error = new AdapterError([{ status: '404' }]); - error.message = 'Requested Agent was not found in set of available Agents'; + error.message = + 'Requested Agent was not found in set of available Agents'; throw error; } @@ -28,10 +29,21 @@ export default class AgentSerializer extends ApplicationSerializer { } normalizeResponse(store, typeClass, hash, ...args) { - return super.normalizeResponse(store, typeClass, hash.Members || [], ...args); + return super.normalizeResponse( + store, + typeClass, + hash.Members || [], + ...args + ); } normalizeSingleResponse(store, typeClass, hash, id, ...args) { - return super.normalizeSingleResponse(store, typeClass, hash.findBy('Name', id), id, ...args); + return super.normalizeSingleResponse( + store, + typeClass, + hash.findBy('Name', id), + id, + ...args + ); } } diff --git a/ui/app/serializers/allocation.js b/ui/app/serializers/allocation.js index 275c92fa1..6e471cb75 100644 --- a/ui/app/serializers/allocation.js +++ b/ui/app/serializers/allocation.js @@ -5,7 +5,8 @@ import classic from 'ember-classic-decorator'; const taskGroupFromJob = (job, taskGroupName) => { const taskGroups = job && job.TaskGroups; - const taskGroup = taskGroups && taskGroups.find((group) => group.Name === taskGroupName); + const taskGroup = + taskGroups && taskGroups.find((group) => group.Name === taskGroupName); return taskGroup ? taskGroup : null; }; @@ -44,12 +45,16 @@ export default class AllocationSerializer extends ApplicationSerializer { .map((key) => { const state = states[key] || {}; const summary = { Name: key }; - Object.keys(state).forEach((stateKey) => (summary[stateKey] = state[stateKey])); - summary.Resources = hash.AllocatedResources && hash.AllocatedResources.Tasks[key]; + Object.keys(state).forEach( + (stateKey) => (summary[stateKey] = state[stateKey]) + ); + summary.Resources = + hash.AllocatedResources && hash.AllocatedResources.Tasks[key]; return summary; }); - hash.JobVersion = hash.JobVersion != null ? hash.JobVersion : get(hash, 'Job.Version'); + hash.JobVersion = + hash.JobVersion != null ? hash.JobVersion : get(hash, 'Job.Version'); hash.PlainJobId = hash.JobID; hash.Namespace = hash.Namespace || get(hash, 'Job.Namespace') || 'default'; @@ -60,9 +65,13 @@ export default class AllocationSerializer extends ApplicationSerializer { hash.IsMigrating = (hash.DesiredTransition || {}).Migrate; // API returns empty strings instead of null - hash.PreviousAllocationID = hash.PreviousAllocation ? hash.PreviousAllocation : null; + hash.PreviousAllocationID = hash.PreviousAllocation + ? hash.PreviousAllocation + : null; hash.NextAllocationID = hash.NextAllocation ? hash.NextAllocation : null; - hash.FollowUpEvaluationID = hash.FollowupEvalID ? hash.FollowupEvalID : null; + hash.FollowUpEvaluationID = hash.FollowupEvalID + ? hash.FollowupEvalID + : null; hash.PreemptedAllocationIDs = hash.PreemptedAllocations || []; hash.PreemptedByAllocationID = hash.PreemptedByAllocation || null; @@ -70,14 +79,17 @@ export default class AllocationSerializer extends ApplicationSerializer { const shared = hash.AllocatedResources && hash.AllocatedResources.Shared; hash.AllocatedResources = - hash.AllocatedResources && merge(Object.values(hash.AllocatedResources.Tasks)); + hash.AllocatedResources && + merge(Object.values(hash.AllocatedResources.Tasks)); if (shared) { hash.AllocatedResources.Ports = shared.Ports; hash.AllocatedResources.Networks = shared.Networks; } // The Job definition for an allocation is only included in findRecord responses. - hash.AllocationTaskGroup = !hash.Job ? null : taskGroupFromJob(hash.Job, hash.TaskGroup); + hash.AllocationTaskGroup = !hash.Job + ? null + : taskGroupFromJob(hash.Job, hash.TaskGroup); return super.normalize(typeHash, hash); } diff --git a/ui/app/serializers/application.js b/ui/app/serializers/application.js index b69971176..c37983af6 100644 --- a/ui/app/serializers/application.js +++ b/ui/app/serializers/application.js @@ -162,7 +162,9 @@ export default class Application extends JSONSerializer { .filter((record) => get(record, 'id')) .filter(storeFilter) .forEach((old) => { - const newRecord = newRecords.find((record) => get(record, 'id') === get(old, 'id')); + const newRecord = newRecords.find( + (record) => get(record, 'id') === get(old, 'id') + ); if (!newRecord) { removeRecord(store, old); } else { diff --git a/ui/app/serializers/deployment.js b/ui/app/serializers/deployment.js index 49e8ddcdb..d947a4ad1 100644 --- a/ui/app/serializers/deployment.js +++ b/ui/app/serializers/deployment.js @@ -14,20 +14,26 @@ export default class DeploymentSerializer extends ApplicationSerializer { normalize(typeHash, hash) { if (hash) { hash.PlainJobId = hash.JobID; - hash.Namespace = hash.Namespace || get(hash, 'Job.Namespace') || 'default'; + hash.Namespace = + hash.Namespace || get(hash, 'Job.Namespace') || 'default'; // Ember Data doesn't support multiple inverses. This means that since jobs have // two relationships to a deployment (hasMany deployments, and belongsTo latestDeployment), // the deployment must in turn have two relationships to the job, despite it being the // same job. - hash.JobID = hash.JobForLatestID = JSON.stringify([hash.JobID, hash.Namespace]); + hash.JobID = hash.JobForLatestID = JSON.stringify([ + hash.JobID, + hash.Namespace, + ]); } return super.normalize(typeHash, hash); } extractRelationships(modelClass, hash) { - const namespace = this.store.adapterFor(modelClass.modelName).get('namespace'); + const namespace = this.store + .adapterFor(modelClass.modelName) + .get('namespace'); const id = this.extractId(modelClass, hash); return assign( diff --git a/ui/app/serializers/job-plan.js b/ui/app/serializers/job-plan.js index 1893f8c9d..ea8971451 100644 --- a/ui/app/serializers/job-plan.js +++ b/ui/app/serializers/job-plan.js @@ -5,7 +5,9 @@ export default class JobPlan extends ApplicationSerializer { mapToArray = ['FailedTGAllocs']; normalize(typeHash, hash) { - hash.PreemptionIDs = (get(hash, 'Annotations.PreemptedAllocs') || []).mapBy('ID'); + hash.PreemptionIDs = (get(hash, 'Annotations.PreemptedAllocs') || []).mapBy( + 'ID' + ); return super.normalize(...arguments); } } diff --git a/ui/app/serializers/job-summary.js b/ui/app/serializers/job-summary.js index 9bb4583ca..23af75c7c 100644 --- a/ui/app/serializers/job-summary.js +++ b/ui/app/serializers/job-summary.js @@ -28,7 +28,8 @@ export default class JobSummary extends ApplicationSerializer { const childrenStats = get(hash, 'Children'); if (childrenStats) { Object.keys(childrenStats).forEach( - (childrenKey) => (hash[`${childrenKey}Children`] = childrenStats[childrenKey]) + (childrenKey) => + (hash[`${childrenKey}Children`] = childrenStats[childrenKey]) ); } diff --git a/ui/app/serializers/job.js b/ui/app/serializers/job.js index 8c24bea0a..65a2001bb 100644 --- a/ui/app/serializers/job.js +++ b/ui/app/serializers/job.js @@ -20,7 +20,10 @@ export default class JobSerializer extends ApplicationSerializer { if (!hash.ParentID) { hash.ParentID = null; } else { - hash.ParentID = JSON.stringify([hash.ParentID, hash.NamespaceID || 'default']); + hash.ParentID = JSON.stringify([ + hash.ParentID, + hash.NamespaceID || 'default', + ]); } // Job Summary is always at /:job-id/summary, but since it can also come from @@ -52,10 +55,14 @@ export default class JobSerializer extends ApplicationSerializer { extractRelationships(modelClass, hash) { const namespace = - !hash.NamespaceID || hash.NamespaceID === 'default' ? undefined : hash.NamespaceID; + !hash.NamespaceID || hash.NamespaceID === 'default' + ? undefined + : hash.NamespaceID; const { modelName } = modelClass; - const apiNamespace = this.store.adapterFor(modelClass.modelName).get('namespace'); + const apiNamespace = this.store + .adapterFor(modelClass.modelName) + .get('namespace'); const [jobURL] = this.store .adapterFor(modelName) diff --git a/ui/app/serializers/node.js b/ui/app/serializers/node.js index a689c40b2..69cce417a 100644 --- a/ui/app/serializers/node.js +++ b/ui/app/serializers/node.js @@ -17,7 +17,12 @@ export default class NodeSerializer extends ApplicationSerializer { const { modelName } = modelClass; const nodeURL = this.store .adapterFor(modelName) - .buildURL(modelName, this.extractId(modelClass, hash), hash, 'findRecord'); + .buildURL( + modelName, + this.extractId(modelClass, hash), + hash, + 'findRecord' + ); return { allocations: { diff --git a/ui/app/serializers/recommendation-summary.js b/ui/app/serializers/recommendation-summary.js index 3a96223d6..c04bb6458 100644 --- a/ui/app/serializers/recommendation-summary.js +++ b/ui/app/serializers/recommendation-summary.js @@ -17,9 +17,10 @@ export default class RecommendationSummarySerializer extends ApplicationSerializ const allRecommendations = []; payload.forEach((recommendationHash) => { - const slug = `${JSON.stringify([recommendationHash.JobID, recommendationHash.Namespace])}/${ - recommendationHash.Group - }`; + const slug = `${JSON.stringify([ + recommendationHash.JobID, + recommendationHash.Namespace, + ])}/${recommendationHash.Group}`; if (!slugToSummaryObject[slug]) { slugToSummaryObject[slug] = { @@ -38,7 +39,9 @@ export default class RecommendationSummarySerializer extends ApplicationSerializ return { data: Object.values(slugToSummaryObject).map((summaryObject) => { - const latest = Math.max(...summaryObject.recommendations.mapBy('SubmitTime')); + const latest = Math.max( + ...summaryObject.recommendations.mapBy('SubmitTime') + ); return { type: 'recommendation-summary', @@ -70,7 +73,10 @@ export default class RecommendationSummarySerializer extends ApplicationSerializ }), included: allRecommendations.map( (recommendationHash) => - recommendationSerializer.normalize(RecommendationModel, recommendationHash).data + recommendationSerializer.normalize( + RecommendationModel, + recommendationHash + ).data ), }; } diff --git a/ui/app/serializers/recommendation.js b/ui/app/serializers/recommendation.js index bb9bd785a..32b062052 100644 --- a/ui/app/serializers/recommendation.js +++ b/ui/app/serializers/recommendation.js @@ -12,7 +12,10 @@ export default class RecommendationSerializer extends ApplicationSerializer { separateNanos = ['SubmitTime']; extractRelationships(modelClass, hash) { - const namespace = !hash.Namespace || hash.Namespace === 'default' ? undefined : hash.Namespace; + const namespace = + !hash.Namespace || hash.Namespace === 'default' + ? undefined + : hash.Namespace; const [jobURL] = this.store .adapterFor('job') diff --git a/ui/app/serializers/volume.js b/ui/app/serializers/volume.js index 3eb57c7f5..faf2b398d 100644 --- a/ui/app/serializers/volume.js +++ b/ui/app/serializers/volume.js @@ -44,7 +44,12 @@ export default class VolumeSerializer extends ApplicationSerializer { } const normalizedHash = super.normalize(typeHash, hash); - return this.extractEmbeddedRecords(this, this.store, typeHash, normalizedHash); + return this.extractEmbeddedRecords( + this, + this.store, + typeHash, + normalizedHash + ); } keyForRelationship(attr, relationshipType) { diff --git a/ui/app/services/sockets.js b/ui/app/services/sockets.js index eb22c0792..236d77630 100644 --- a/ui/app/services/sockets.js +++ b/ui/app/services/sockets.js @@ -19,7 +19,11 @@ export default class SocketsService extends Service { send(e) { if (!this.messageDisplayed) { this.messageDisplayed = true; - this.onmessage({ data: `{"stdout":{"data":"${btoa('unsupported in Mirage\n\r')}"}}` }); + this.onmessage({ + data: `{"stdout":{"data":"${btoa( + 'unsupported in Mirage\n\r' + )}"}}`, + }); } else { this.onmessage({ data: e.replace('stdin', 'stdout') }); } diff --git a/ui/app/services/stats-trackers-registry.js b/ui/app/services/stats-trackers-registry.js index bc47d144e..6d222dc08 100644 --- a/ui/app/services/stats-trackers-registry.js +++ b/ui/app/services/stats-trackers-registry.js @@ -12,7 +12,9 @@ const MAX_STAT_TRACKERS = 10; let registry; const exists = (tracker, prop) => - tracker.get(prop) && !tracker.get(prop).isDestroyed && !tracker.get(prop).isDestroying; + tracker.get(prop) && + !tracker.get(prop).isDestroyed && + !tracker.get(prop).isDestroying; export default class StatsTrackersRegistryService extends Service { @service token; @@ -38,14 +40,16 @@ export default class StatsTrackersRegistryService extends Service { const type = resource && resource.constructor.modelName; const key = `${type}:${resource.get('id')}`; - const Constructor = type === 'node' ? NodeStatsTracker : AllocationStatsTracker; + const Constructor = + type === 'node' ? NodeStatsTracker : AllocationStatsTracker; const resourceProp = type === 'node' ? 'node' : 'allocation'; const cachedTracker = registry.get(key); if (cachedTracker) { // It's possible for the resource on a cachedTracker to have been // deleted. Rebind it if that's the case. - if (!exists(cachedTracker, resourceProp)) cachedTracker.set(resourceProp, resource); + if (!exists(cachedTracker, resourceProp)) + cachedTracker.set(resourceProp, resource); return cachedTracker; } diff --git a/ui/app/services/system.js b/ui/app/services/system.js index c9d878729..1859c701e 100644 --- a/ui/app/services/system.js +++ b/ui/app/services/system.js @@ -40,10 +40,13 @@ export default class SystemService extends Service { .then(jsonWithDefault({})) .then((agent) => { if (agent?.config?.Version) { - const { Version, VersionPrerelease, VersionMetadata } = agent.config.Version; + const { Version, VersionPrerelease, VersionMetadata } = + agent.config.Version; agent.version = Version; - if (VersionPrerelease) agent.version = `${agent.version}-${VersionPrerelease}`; - if (VersionMetadata) agent.version = `${agent.version}+${VersionMetadata}`; + if (VersionPrerelease) + agent.version = `${agent.version}-${VersionPrerelease}`; + if (VersionMetadata) + agent.version = `${agent.version}+${VersionMetadata}`; } return agent; }), @@ -68,7 +71,9 @@ export default class SystemService extends Service { const token = this.token; return PromiseArray.create({ - promise: token.authorizedRawRequest(`/${namespace}/regions`).then(jsonWithDefault([])), + promise: token + .authorizedRawRequest(`/${namespace}/regions`) + .then(jsonWithDefault([])), }); } @@ -103,20 +108,28 @@ export default class SystemService extends Service { @computed('activeRegion', 'defaultRegion.region', 'shouldShowRegions') get shouldIncludeRegion() { - return this.shouldShowRegions && this.activeRegion !== this.get('defaultRegion.region'); + return ( + this.shouldShowRegions && + this.activeRegion !== this.get('defaultRegion.region') + ); } @computed('activeRegion') get namespaces() { return PromiseArray.create({ - promise: this.store.findAll('namespace').then((namespaces) => namespaces.compact()), + promise: this.store + .findAll('namespace') + .then((namespaces) => namespaces.compact()), }); } @computed('namespaces.[]') get shouldShowNamespaces() { const namespaces = this.namespaces.toArray(); - return namespaces.length && namespaces.some((namespace) => namespace.get('id') !== 'default'); + return ( + namespaces.length && + namespaces.some((namespace) => namespace.get('id') !== 'default') + ); } // The cachedNamespace is set on pages that have a namespaces filter. diff --git a/ui/app/services/user-settings.js b/ui/app/services/user-settings.js index dbe650ed1..3c8362dfa 100644 --- a/ui/app/services/user-settings.js +++ b/ui/app/services/user-settings.js @@ -4,5 +4,6 @@ import localStorageProperty from 'nomad-ui/utils/properties/local-storage'; export default class UserSettingsService extends Service { @localStorageProperty('nomadPageSize', 25) pageSize; @localStorageProperty('nomadLogMode', 'stdout') logMode; - @localStorageProperty('nomadTopoVizPollingNotice', true) showTopoVizPollingNotice; + @localStorageProperty('nomadTopoVizPollingNotice', true) + showTopoVizPollingNotice; } diff --git a/ui/app/utils/classes/abstract-logger.js b/ui/app/utils/classes/abstract-logger.js index 99d3a4de5..e8b404958 100644 --- a/ui/app/utils/classes/abstract-logger.js +++ b/ui/app/utils/classes/abstract-logger.js @@ -12,7 +12,9 @@ export default Mixin.create({ url: '', params: overridable(() => ({})), logFetch() { - assert('Loggers need a logFetch method, which should have an interface like window.fetch'); + assert( + 'Loggers need a logFetch method, which should have an interface like window.fetch' + ); }, endOffset: null, @@ -26,10 +28,16 @@ export default Mixin.create({ additionalParams: overridable(() => ({})), - fullUrl: computed('url', 'params', 'offsetParams', 'additionalParams', function () { - const queryParams = queryString.stringify( - assign({}, this.params, this.offsetParams, this.additionalParams) - ); - return `${this.url}?${queryParams}`; - }), + fullUrl: computed( + 'url', + 'params', + 'offsetParams', + 'additionalParams', + function () { + const queryParams = queryString.stringify( + assign({}, this.params, this.offsetParams, this.additionalParams) + ); + return `${this.url}?${queryParams}`; + } + ), }); diff --git a/ui/app/utils/classes/abstract-stats-tracker.js b/ui/app/utils/classes/abstract-stats-tracker.js index c1546847c..2c45f2f49 100644 --- a/ui/app/utils/classes/abstract-stats-tracker.js +++ b/ui/app/utils/classes/abstract-stats-tracker.js @@ -18,7 +18,9 @@ export default Mixin.create({ maxFrameMisses: 5, fetch() { - assert('StatsTrackers need a fetch method, which should have an interface like window.fetch'); + assert( + 'StatsTrackers need a fetch method, which should have an interface like window.fetch' + ); }, append(/* frame */) { diff --git a/ui/app/utils/classes/allocation-stats-tracker.js b/ui/app/utils/classes/allocation-stats-tracker.js index 20edc9c00..092357d18 100644 --- a/ui/app/utils/classes/allocation-stats-tracker.js +++ b/ui/app/utils/classes/allocation-stats-tracker.js @@ -26,7 +26,8 @@ const sortMap = [ return map; }, {}); -const taskPrioritySort = (a, b) => sortMap[a.lifecycleName] - sortMap[b.lifecycleName]; +const taskPrioritySort = (a, b) => + sortMap[a.lifecycleName] - sortMap[b.lifecycleName]; @classic class AllocationStatsTracker extends EmberObject.extend(AbstractStatsTracker) { @@ -64,9 +65,12 @@ class AllocationStatsTracker extends EmberObject.extend(AbstractStatsTracker) { // it has already stopped), just keep going. if (!taskFrame) continue; - const frameTimestamp = new Date(Math.floor(taskFrame.Timestamp / 1000000)); + const frameTimestamp = new Date( + Math.floor(taskFrame.Timestamp / 1000000) + ); - const taskCpuUsed = Math.floor(taskFrame.ResourceUsage.CpuStats.TotalTicks) || 0; + const taskCpuUsed = + Math.floor(taskFrame.ResourceUsage.CpuStats.TotalTicks) || 0; const percentCpuTotal = percent(taskCpuUsed, this.reservedCPU); stats.cpu.pushObject({ timestamp: frameTimestamp, @@ -77,7 +81,10 @@ class AllocationStatsTracker extends EmberObject.extend(AbstractStatsTracker) { }); const taskMemoryUsed = taskFrame.ResourceUsage.MemoryStats.RSS; - const percentMemoryTotal = percent(taskMemoryUsed / 1024 / 1024, this.reservedMemory); + const percentMemoryTotal = percent( + taskMemoryUsed / 1024 / 1024, + this.reservedMemory + ); stats.memory.pushObject({ timestamp: frameTimestamp, used: taskMemoryUsed, diff --git a/ui/app/utils/classes/exec-socket-xterm-adapter.js b/ui/app/utils/classes/exec-socket-xterm-adapter.js index 96229c94a..3eef4c726 100644 --- a/ui/app/utils/classes/exec-socket-xterm-adapter.js +++ b/ui/app/utils/classes/exec-socket-xterm-adapter.js @@ -44,12 +44,16 @@ export default class ExecSocketXtermAdapter { sendTtySize() { this.socket.send( - JSON.stringify({ tty_size: { width: this.terminal.cols, height: this.terminal.rows } }) + JSON.stringify({ + tty_size: { width: this.terminal.cols, height: this.terminal.rows }, + }) ); } sendWsHandshake() { - this.socket.send(JSON.stringify({ version: 1, auth_token: this.token || '' })); + this.socket.send( + JSON.stringify({ version: 1, auth_token: this.token || '' }) + ); } startHeartbeat() { @@ -63,6 +67,8 @@ export default class ExecSocketXtermAdapter { } handleData(data) { - this.socket.send(JSON.stringify({ stdin: { data: base64EncodeString(data) } })); + this.socket.send( + JSON.stringify({ stdin: { data: base64EncodeString(data) } }) + ); } } diff --git a/ui/app/utils/classes/log.js b/ui/app/utils/classes/log.js index 3441c5ee9..5ea91dc85 100644 --- a/ui/app/utils/classes/log.js +++ b/ui/app/utils/classes/log.js @@ -16,7 +16,8 @@ import classic from 'ember-classic-decorator'; const MAX_OUTPUT_LENGTH = 50000; // eslint-disable-next-line -export const fetchFailure = (url) => () => console.warn(`LOG FETCH: Couldn't connect to ${url}`); +export const fetchFailure = (url) => () => + console.warn(`LOG FETCH: Couldn't connect to ${url}`); @classic class Log extends EmberObject.extend(Evented) { @@ -30,7 +31,9 @@ class Log extends EmberObject.extend(Evented) { plainText = false; logFetch() { - assert('Log objects need a logFetch method, which should have an interface like window.fetch'); + assert( + 'Log objects need a logFetch method, which should have an interface like window.fetch' + ); } // Read-only state @@ -96,12 +99,16 @@ class Log extends EmberObject.extend(Evented) { const url = `${this.url}?${queryParams}`; this.stop(); - const response = yield logFetch(url).then((res) => res.text(), fetchFailure(url)); + const response = yield logFetch(url).then( + (res) => res.text(), + fetchFailure(url) + ); let text = this.plainText ? response : decode(response).message; if (text && text.length > MAX_OUTPUT_LENGTH) { text = text.substr(0, MAX_OUTPUT_LENGTH); - text += '\n\n---------- TRUNCATED: Click "tail" to view the bottom of the log ----------'; + text += + '\n\n---------- TRUNCATED: Click "tail" to view the bottom of the log ----------'; } this.set('head', text); this.set('logPointer', 'head'); @@ -122,7 +129,10 @@ class Log extends EmberObject.extend(Evented) { const url = `${this.url}?${queryParams}`; this.stop(); - const response = yield logFetch(url).then((res) => res.text(), fetchFailure(url)); + const response = yield logFetch(url).then( + (res) => res.text(), + fetchFailure(url) + ); let text = this.plainText ? response : decode(response).message; this.set('tail', text); diff --git a/ui/app/utils/classes/promise-array.js b/ui/app/utils/classes/promise-array.js index 1bf2efb1a..49615cfb2 100644 --- a/ui/app/utils/classes/promise-array.js +++ b/ui/app/utils/classes/promise-array.js @@ -3,4 +3,6 @@ import PromiseProxyMixin from '@ember/object/promise-proxy-mixin'; import classic from 'ember-classic-decorator'; @classic -export default class PromiseArray extends ArrayProxy.extend(PromiseProxyMixin) {} +export default class PromiseArray extends ArrayProxy.extend( + PromiseProxyMixin +) {} diff --git a/ui/app/utils/classes/promise-object.js b/ui/app/utils/classes/promise-object.js index dbab8f7ec..bd8940b4a 100644 --- a/ui/app/utils/classes/promise-object.js +++ b/ui/app/utils/classes/promise-object.js @@ -3,4 +3,6 @@ import PromiseProxyMixin from '@ember/object/promise-proxy-mixin'; import classic from 'ember-classic-decorator'; @classic -export default class PromiseObject extends ObjectProxy.extend(PromiseProxyMixin) {} +export default class PromiseObject extends ObjectProxy.extend( + PromiseProxyMixin +) {} diff --git a/ui/app/utils/format-duration.js b/ui/app/utils/format-duration.js index 75e518339..768e0b43e 100644 --- a/ui/app/utils/format-duration.js +++ b/ui/app/utils/format-duration.js @@ -13,9 +13,27 @@ const allUnits = [ { name: 'years', suffix: 'year', inMoment: true, pluralizable: true }, { name: 'months', suffix: 'month', inMoment: true, pluralizable: true }, { name: 'days', suffix: 'day', inMoment: true, pluralizable: true }, - { name: 'hours', suffix: 'h', longSuffix: 'hour', inMoment: true, pluralizable: false }, - { name: 'minutes', suffix: 'm', longSuffix: 'minute', inMoment: true, pluralizable: false }, - { name: 'seconds', suffix: 's', longSuffix: 'second', inMoment: true, pluralizable: false }, + { + name: 'hours', + suffix: 'h', + longSuffix: 'hour', + inMoment: true, + pluralizable: false, + }, + { + name: 'minutes', + suffix: 'm', + longSuffix: 'minute', + inMoment: true, + pluralizable: false, + }, + { + name: 'seconds', + suffix: 's', + longSuffix: 'second', + inMoment: true, + pluralizable: false, + }, { name: 'milliseconds', suffix: 'ms', inMoment: true, pluralizable: false }, { name: 'microseconds', suffix: 'µs', inMoment: false, pluralizable: false }, { name: 'nanoseconds', suffix: 'ns', inMoment: false, pluralizable: false }, @@ -30,7 +48,8 @@ const pluralizeUnits = (amount, unit, longForm) => { suffix = amount === 1 ? unit.longSuffix : pluralize(unit.longSuffix); } else { // In the normal case, only pluralize based on the pluralizable flag - suffix = amount === 1 || !unit.pluralizable ? unit.suffix : pluralize(unit.suffix); + suffix = + amount === 1 || !unit.pluralizable ? unit.suffix : pluralize(unit.suffix); } // A space should go between the value and the unit when the unit is a full word @@ -47,7 +66,11 @@ const pluralizeUnits = (amount, unit, longForm) => { * @param {Boolean} longForm Whether or not to expand single character suffixes, * used to ensure screen readers correctly read units. */ -export default function formatDuration(duration = 0, units = 'ns', longForm = false) { +export default function formatDuration( + duration = 0, + units = 'ns', + longForm = false +) { const durationParts = {}; // Moment only handles up to millisecond precision. diff --git a/ui/app/utils/generate-exec-url.js b/ui/app/utils/generate-exec-url.js index a5b5d0fb7..ed619460f 100644 --- a/ui/app/utils/generate-exec-url.js +++ b/ui/app/utils/generate-exec-url.js @@ -1,6 +1,9 @@ import { get } from '@ember/object'; -export default function generateExecUrl(router, { job, taskGroup, task, allocation }) { +export default function generateExecUrl( + router, + { job, taskGroup, task, allocation } +) { const queryParams = {}; const namespace = get(job, 'namespace.name'); @@ -33,9 +36,14 @@ export default function generateExecUrl(router, { job, taskGroup, task, allocati } ); } else if (taskGroup) { - return router.urlFor('exec.task-group', get(job, 'plainId'), get(taskGroup, 'name'), { - queryParams, - }); + return router.urlFor( + 'exec.task-group', + get(job, 'plainId'), + get(taskGroup, 'name'), + { + queryParams, + } + ); } else if (allocation) { if (get(allocation, 'taskGroup.tasks.length') === 1) { return router.urlFor( @@ -43,14 +51,24 @@ export default function generateExecUrl(router, { job, taskGroup, task, allocati get(job, 'plainId'), get(allocation, 'taskGroup.name'), get(allocation, 'taskGroup.tasks.firstObject.name'), - { queryParams: { allocation: get(allocation, 'shortId'), ...queryParams } } + { + queryParams: { + allocation: get(allocation, 'shortId'), + ...queryParams, + }, + } ); } else { return router.urlFor( 'exec.task-group', get(job, 'plainId'), get(allocation, 'taskGroup.name'), - { queryParams: { allocation: get(allocation, 'shortId'), ...queryParams } } + { + queryParams: { + allocation: get(allocation, 'shortId'), + ...queryParams, + }, + } ); } } else { diff --git a/ui/app/utils/properties/glimmer-style-string.js b/ui/app/utils/properties/glimmer-style-string.js index 44936c11b..d2d05d704 100644 --- a/ui/app/utils/properties/glimmer-style-string.js +++ b/ui/app/utils/properties/glimmer-style-string.js @@ -19,7 +19,9 @@ export default function styleString(target, name, descriptor) { str = Object.keys(styles) .reduce(function (arr, key) { const val = styles[key]; - arr.push(key + ':' + (typeof val === 'number' ? val.toFixed(2) + 'px' : val)); + arr.push( + key + ':' + (typeof val === 'number' ? val.toFixed(2) + 'px' : val) + ); return arr; }, []) .join(';'); diff --git a/ui/app/utils/properties/style-string.js b/ui/app/utils/properties/style-string.js index 245f0fdb4..804fd5218 100644 --- a/ui/app/utils/properties/style-string.js +++ b/ui/app/utils/properties/style-string.js @@ -15,7 +15,9 @@ export default function styleStringProperty(prop) { str = Object.keys(styles) .reduce(function (arr, key) { const val = styles[key]; - arr.push(key + ':' + (typeof val === 'number' ? val.toFixed(2) + 'px' : val)); + arr.push( + key + ':' + (typeof val === 'number' ? val.toFixed(2) + 'px' : val) + ); return arr; }, []) .join(';'); diff --git a/ui/app/utils/resources-diffs.js b/ui/app/utils/resources-diffs.js index 85f695b8b..7a301f11d 100644 --- a/ui/app/utils/resources-diffs.js +++ b/ui/app/utils/resources-diffs.js @@ -30,8 +30,14 @@ export default class ResourcesDiffs { } get memory() { - const included = this.includedRecommendations.filterBy('resource', 'MemoryMB'); - const excluded = this.excludedRecommendations.filterBy('resource', 'MemoryMB'); + const included = this.includedRecommendations.filterBy( + 'resource', + 'MemoryMB' + ); + const excluded = this.excludedRecommendations.filterBy( + 'resource', + 'MemoryMB' + ); return new ResourceDiffs( this.model.reservedMemory, @@ -44,7 +50,9 @@ export default class ResourcesDiffs { } get includedRecommendations() { - return this.recommendations.reject((r) => this.excludedRecommendations.includes(r)); + return this.recommendations.reject((r) => + this.excludedRecommendations.includes(r) + ); } } @@ -69,7 +77,9 @@ class ResourceDiffs { if (this.included.length) { return ( this.included.mapBy('value').reduce(sumAggregate, 0) + - this.excluded.mapBy(`task.${this.baseTaskPropertyName}`).reduce(sumAggregate, 0) + this.excluded + .mapBy(`task.${this.baseTaskPropertyName}`) + .reduce(sumAggregate, 0) ); } else { return this.base; diff --git a/ui/app/utils/stream-frames.js b/ui/app/utils/stream-frames.js index 753b2780c..7a861fb8b 100644 --- a/ui/app/utils/stream-frames.js +++ b/ui/app/utils/stream-frames.js @@ -14,7 +14,9 @@ const decoder = new TextDecoderLite('utf-8'); */ export function decode(chunk) { const lines = chunk.replace(/\}\{/g, '}\n{').split('\n').without(''); - const frames = lines.map((line) => JSON.parse(line)).filter((frame) => frame.Data); + const frames = lines + .map((line) => JSON.parse(line)) + .filter((frame) => frame.Data); if (frames.length) { frames.forEach((frame) => (frame.Data = b64decode(frame.Data))); diff --git a/ui/config/deprecation-workflow.js b/ui/config/deprecation-workflow.js index e7c8c41fe..abb58e926 100644 --- a/ui/config/deprecation-workflow.js +++ b/ui/config/deprecation-workflow.js @@ -5,7 +5,10 @@ self.deprecationWorkflow.config = { { handler: 'throw', matchId: 'ember-inflector.globals' }, { handler: 'throw', matchId: 'ember-runtime.deprecate-copy-copyable' }, { handler: 'throw', matchId: 'ember-console.deprecate-logger' }, - { handler: 'throw', matchId: 'ember-test-helpers.rendering-context.jquery-element' }, + { + handler: 'throw', + matchId: 'ember-test-helpers.rendering-context.jquery-element', + }, { handler: 'throw', matchId: 'ember-cli-page-object.is-property' }, { handler: 'throw', matchId: 'ember-views.partial' }, ], diff --git a/ui/config/targets.js b/ui/config/targets.js index 9f6cc6396..1e48e0599 100644 --- a/ui/config/targets.js +++ b/ui/config/targets.js @@ -1,6 +1,10 @@ 'use strict'; -const browsers = ['last 1 Chrome versions', 'last 1 Firefox versions', 'last 1 Safari versions']; +const browsers = [ + 'last 1 Chrome versions', + 'last 1 Firefox versions', + 'last 1 Safari versions', +]; module.exports = { browsers, diff --git a/ui/ember-cli-build.js b/ui/ember-cli-build.js index a79605aa2..bbeaf43f4 100644 --- a/ui/ember-cli-build.js +++ b/ui/ember-cli-build.js @@ -8,7 +8,10 @@ const isTest = environment === 'test'; module.exports = function (defaults) { var app = new EmberApp(defaults, { svg: { - paths: ['node_modules/@hashicorp/structure-icons/dist', 'public/images/icons'], + paths: [ + 'node_modules/@hashicorp/structure-icons/dist', + 'public/images/icons', + ], optimize: { plugins: [{ removeViewBox: false }], }, diff --git a/ui/server/index.js b/ui/server/index.js index 0d6db58af..d0eb3d395 100644 --- a/ui/server/index.js +++ b/ui/server/index.js @@ -3,7 +3,9 @@ module.exports = function (app, options) { const globSync = require('glob').sync; const mocks = globSync('./mocks/**/*.js', { cwd: __dirname }).map(require); - const proxies = globSync('./proxies/**/*.js', { cwd: __dirname }).map(require); + const proxies = globSync('./proxies/**/*.js', { cwd: __dirname }).map( + require + ); // Log proxy requests const morgan = require('morgan'); diff --git a/ui/server/proxies/api.js b/ui/server/proxies/api.js index 2c0b2fd5a..3e6ab01e1 100644 --- a/ui/server/proxies/api.js +++ b/ui/server/proxies/api.js @@ -41,7 +41,10 @@ module.exports = function (app, options) { }); server.on('upgrade', function (req, socket, head) { - if (req.url.startsWith('/v1/client/allocation') && req.url.includes('exec?')) { + if ( + req.url.startsWith('/v1/client/allocation') && + req.url.includes('exec?') + ) { req.headers.origin = proxyAddress; proxy.ws(req, socket, head, { target: proxyAddress }); } diff --git a/ui/stories/charts/progress-bar.stories.js b/ui/stories/charts/progress-bar.stories.js index b9a92c129..617fbd20e 100644 --- a/ui/stories/charts/progress-bar.stories.js +++ b/ui/stories/charts/progress-bar.stories.js @@ -126,9 +126,14 @@ export let LiveUpdates = () => { return Math.round(this.denominator * this.percentage * 100) / 100; }), - liveDetails: computed('denominator', 'numerator', 'percentage', function () { - return this.getProperties('denominator', 'numerator', 'percentage'); - }), + liveDetails: computed( + 'denominator', + 'numerator', + 'percentage', + function () { + return this.getProperties('denominator', 'numerator', 'percentage'); + } + ), }).create(), }, }; diff --git a/ui/stories/charts/stats-time-series.stories.js b/ui/stories/charts/stats-time-series.stories.js index 1c6f50bf3..959dda4b9 100644 --- a/ui/stories/charts/stats-time-series.stories.js +++ b/ui/stories/charts/stats-time-series.stories.js @@ -68,14 +68,18 @@ export let HighLowComparison = () => { 'timer', setInterval(() => { let metricsHigh = this.metricsHigh; - let prev = metricsHigh.length ? metricsHigh[metricsHigh.length - 1].percent : 0.9; + let prev = metricsHigh.length + ? metricsHigh[metricsHigh.length - 1].percent + : 0.9; this.appendTSValue( metricsHigh, Math.min(Math.max(prev + Math.random() * 0.05 - 0.025, 0.5), 1) ); let metricsLow = this.metricsLow; - let prev2 = metricsLow.length ? metricsLow[metricsLow.length - 1].percent : 0.1; + let prev2 = metricsLow.length + ? metricsLow[metricsLow.length - 1].percent + : 0.1; this.appendTSValue( metricsLow, Math.min(Math.max(prev2 + Math.random() * 0.05 - 0.025, 0), 0.5) diff --git a/ui/stories/components/copy-button.stories.js b/ui/stories/components/copy-button.stories.js index 3ebbd7082..f67b0369e 100644 --- a/ui/stories/components/copy-button.stories.js +++ b/ui/stories/components/copy-button.stories.js @@ -20,7 +20,10 @@ export let CopyButton = () => { `, context: { - clipboardText: text('Clipboard Text', 'e8c898a0-794b-9063-7a7f-bf0c4a405f83'), + clipboardText: text( + 'Clipboard Text', + 'e8c898a0-794b-9063-7a7f-bf0c4a405f83' + ), }, }; }; diff --git a/ui/stories/components/diff-viewer.stories.js b/ui/stories/components/diff-viewer.stories.js index cbadcb0b7..4a13e5eeb 100644 --- a/ui/stories/components/diff-viewer.stories.js +++ b/ui/stories/components/diff-viewer.stories.js @@ -16,10 +16,34 @@ export let DiffViewerWithInsertions = () => { `, context: { insertionsOnly: generateDiff([ - { Annotations: null, Name: 'Attempts', New: '15', Old: '15', Type: 'None' }, - { Annotations: null, Name: 'Delay', New: '25000000000', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'Interval', New: '900000000000', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'Mode', New: 'delay', Old: 'delay', Type: 'None' }, + { + Annotations: null, + Name: 'Attempts', + New: '15', + Old: '15', + Type: 'None', + }, + { + Annotations: null, + Name: 'Delay', + New: '25000000000', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'Interval', + New: '900000000000', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'Mode', + New: 'delay', + Old: 'delay', + Type: 'None', + }, ]), }, }; @@ -37,7 +61,13 @@ export let DiffViewerWithDeletions = () => { `, context: { deletionsOnly: generateDiff([ - { Annotations: null, Name: 'Attempts', New: '15', Old: '15', Type: 'None' }, + { + Annotations: null, + Name: 'Attempts', + New: '15', + Old: '15', + Type: 'None', + }, { Annotations: null, Name: 'Delay', @@ -52,7 +82,13 @@ export let DiffViewerWithDeletions = () => { Old: '900000000000', Type: 'None', }, - { Annotations: null, Name: 'Mode', New: '', Old: 'delay', Type: 'Deleted' }, + { + Annotations: null, + Name: 'Mode', + New: '', + Old: 'delay', + Type: 'Deleted', + }, ]), }, }; @@ -71,7 +107,13 @@ export let DiffViewerWithEdits = () => { `, context: { editsOnly: generateDiff([ - { Annotations: null, Name: 'Attempts', New: '15', Old: '15', Type: 'None' }, + { + Annotations: null, + Name: 'Attempts', + New: '15', + Old: '15', + Type: 'None', + }, { Annotations: null, Name: 'Delay', @@ -86,7 +128,13 @@ export let DiffViewerWithEdits = () => { Old: '250000000000', Type: 'Edited', }, - { Annotations: null, Name: 'Mode', New: 'delay', Old: 'delay', Type: 'None' }, + { + Annotations: null, + Name: 'Mode', + New: 'delay', + Old: 'delay', + Type: 'None', + }, ]), }, }; @@ -156,9 +204,27 @@ export let DiffViewerWithManyChanges = () => { }, { Fields: [ - { Annotations: null, Name: 'CPU', New: '1000', Old: '500', Type: 'Edited' }, - { Annotations: null, Name: 'DiskMB', New: '0', Old: '0', Type: 'None' }, - { Annotations: null, Name: 'IOPS', New: '0', Old: '0', Type: 'None' }, + { + Annotations: null, + Name: 'CPU', + New: '1000', + Old: '500', + Type: 'Edited', + }, + { + Annotations: null, + Name: 'DiskMB', + New: '0', + Old: '0', + Type: 'None', + }, + { + Annotations: null, + Name: 'IOPS', + New: '0', + Old: '0', + Type: 'None', + }, { Annotations: null, Name: 'MemoryMB', @@ -171,7 +237,13 @@ export let DiffViewerWithManyChanges = () => { Objects: [ { Fields: [ - { Annotations: null, Name: 'MBits', New: '100', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'MBits', + New: '100', + Old: '', + Type: 'Added', + }, ], Name: 'Network', Objects: [ @@ -194,7 +266,13 @@ export let DiffViewerWithManyChanges = () => { }, { Fields: [ - { Annotations: null, Name: 'MBits', New: '', Old: '10', Type: 'Deleted' }, + { + Annotations: null, + Name: 'MBits', + New: '', + Old: '10', + Type: 'Deleted', + }, ], Name: 'Network', Objects: [ @@ -234,13 +312,25 @@ export let DiffViewerWithManyChanges = () => { Old: 'redis-cache', Type: 'None', }, - { Annotations: null, Name: 'PortLabel', New: 'db', Old: 'db', Type: 'None' }, + { + Annotations: null, + Name: 'PortLabel', + New: 'db', + Old: 'db', + Type: 'None', + }, ], Name: 'Service', Objects: [ { Fields: [ - { Annotations: null, Name: 'Tags', New: 'redis', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'Tags', + New: 'redis', + Old: '', + Type: 'Added', + }, { Annotations: null, Name: 'Tags', @@ -269,7 +359,13 @@ export let DiffViewerWithManyChanges = () => { Old: '', Type: 'None', }, - { Annotations: null, Name: 'Command', New: '', Old: '', Type: 'None' }, + { + Annotations: null, + Name: 'Command', + New: '', + Old: '', + Type: 'None', + }, { Annotations: null, Name: 'GRPCService', @@ -298,7 +394,13 @@ export let DiffViewerWithManyChanges = () => { Old: '10000000000', Type: 'Edited', }, - { Annotations: null, Name: 'Method', New: '', Old: '', Type: 'None' }, + { + Annotations: null, + Name: 'Method', + New: '', + Old: '', + Type: 'None', + }, { Annotations: null, Name: 'Name', @@ -306,9 +408,27 @@ export let DiffViewerWithManyChanges = () => { Old: 'alive', Type: 'None', }, - { Annotations: null, Name: 'Path', New: '', Old: '', Type: 'None' }, - { Annotations: null, Name: 'PortLabel', New: '', Old: '', Type: 'None' }, - { Annotations: null, Name: 'Protocol', New: '', Old: '', Type: 'None' }, + { + Annotations: null, + Name: 'Path', + New: '', + Old: '', + Type: 'None', + }, + { + Annotations: null, + Name: 'PortLabel', + New: '', + Old: '', + Type: 'None', + }, + { + Annotations: null, + Name: 'Protocol', + New: '', + Old: '', + Type: 'None', + }, { Annotations: null, Name: 'TLSSkipVerify', @@ -323,7 +443,13 @@ export let DiffViewerWithManyChanges = () => { Old: '2000000000', Type: 'Edited', }, - { Annotations: null, Name: 'Type', New: 'tcp', Old: 'tcp', Type: 'None' }, + { + Annotations: null, + Name: 'Type', + New: 'tcp', + Old: 'tcp', + Type: 'None', + }, ], Name: 'Check', Objects: null, @@ -341,16 +467,46 @@ export let DiffViewerWithManyChanges = () => { }, { Fields: [ - { Annotations: null, Name: 'Count', New: '1', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'Meta[key]', New: 'value', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'Meta[red]', New: 'fish', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'Count', + New: '1', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'Meta[key]', + New: 'value', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'Meta[red]', + New: 'fish', + Old: '', + Type: 'Added', + }, ], Name: 'cache2', Objects: [ { Fields: [ - { Annotations: null, Name: 'Attempts', New: '2', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'Delay', New: '15000000000', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'Attempts', + New: '2', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'Delay', + New: '15000000000', + Old: '', + Type: 'Added', + }, { Annotations: null, Name: 'Interval', @@ -358,7 +514,13 @@ export let DiffViewerWithManyChanges = () => { Old: '', Type: 'Added', }, - { Annotations: null, Name: 'Mode', New: 'fail', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'Mode', + New: 'fail', + Old: '', + Type: 'Added', + }, ], Name: 'RestartPolicy', Objects: null, @@ -366,9 +528,27 @@ export let DiffViewerWithManyChanges = () => { }, { Fields: [ - { Annotations: null, Name: 'Migrate', New: 'false', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'SizeMB', New: '300', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'Sticky', New: 'false', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'Migrate', + New: 'false', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'SizeMB', + New: '300', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'Sticky', + New: 'false', + Old: '', + Type: 'Added', + }, ], Name: 'EphemeralDisk', Objects: null, @@ -379,7 +559,13 @@ export let DiffViewerWithManyChanges = () => { { Annotations: null, Fields: [ - { Annotations: null, Name: 'Driver', New: 'docker', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'Driver', + New: 'docker', + Old: '', + Type: 'Added', + }, { Annotations: null, Name: 'KillTimeout', @@ -387,8 +573,20 @@ export let DiffViewerWithManyChanges = () => { Old: '', Type: 'Added', }, - { Annotations: null, Name: 'Leader', New: 'false', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'ShutdownDelay', New: '0', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'Leader', + New: 'false', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'ShutdownDelay', + New: '0', + Old: '', + Type: 'Added', + }, ], Name: 'redis', Objects: [ @@ -415,16 +613,46 @@ export let DiffViewerWithManyChanges = () => { }, { Fields: [ - { Annotations: null, Name: 'CPU', New: '500', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'DiskMB', New: '0', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'IOPS', New: '0', Old: '', Type: 'Added' }, - { Annotations: null, Name: 'MemoryMB', New: '256', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'CPU', + New: '500', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'DiskMB', + New: '0', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'IOPS', + New: '0', + Old: '', + Type: 'Added', + }, + { + Annotations: null, + Name: 'MemoryMB', + New: '256', + Old: '', + Type: 'Added', + }, ], Name: 'Resources', Objects: [ { Fields: [ - { Annotations: null, Name: 'MBits', New: '10', Old: '', Type: 'Added' }, + { + Annotations: null, + Name: 'MBits', + New: '10', + Old: '', + Type: 'Added', + }, ], Name: 'Network', Objects: [ @@ -469,7 +697,15 @@ function generateDiff(changeset) { Objects: null, TaskGroups: [ { - Fields: [{ Annotations: null, Name: 'Count', New: '2', Old: '2', Type: 'None' }], + Fields: [ + { + Annotations: null, + Name: 'Count', + New: '2', + Old: '2', + Type: 'None', + }, + ], Name: 'cache', Objects: [ { diff --git a/ui/stories/components/json-viewer.stories.js b/ui/stories/components/json-viewer.stories.js index 236bd1da8..5c313a557 100644 --- a/ui/stories/components/json-viewer.stories.js +++ b/ui/stories/components/json-viewer.stories.js @@ -21,7 +21,14 @@ export let Standard = () => { data: { foo: 'bar', number: 123456789, - products: ['Consul', 'Nomad', 'Packer', 'Terraform', 'Vagrant', 'Vault'], + products: [ + 'Consul', + 'Nomad', + 'Packer', + 'Terraform', + 'Vagrant', + 'Vault', + ], currentTime: '2019-10-16T14:24:12.378Z', nested: { obj: 'ject', diff --git a/ui/stories/components/table.stories.js b/ui/stories/components/table.stories.js index d0e772532..0cce0359c 100644 --- a/ui/stories/components/table.stories.js +++ b/ui/stories/components/table.stories.js @@ -39,10 +39,34 @@ function injectRoutedController(controllerClass) { } let longList = [ - { city: 'New York', growth: 0.048, population: '8405837', rank: '1', state: 'New York' }, - { city: 'Los Angeles', growth: 0.048, population: '3884307', rank: '2', state: 'California' }, - { city: 'Chicago', growth: -0.061, population: '2718782', rank: '3', state: 'Illinois' }, - { city: 'Houston', growth: 0.11, population: '2195914', rank: '4', state: 'Texas' }, + { + city: 'New York', + growth: 0.048, + population: '8405837', + rank: '1', + state: 'New York', + }, + { + city: 'Los Angeles', + growth: 0.048, + population: '3884307', + rank: '2', + state: 'California', + }, + { + city: 'Chicago', + growth: -0.061, + population: '2718782', + rank: '3', + state: 'Illinois', + }, + { + city: 'Houston', + growth: 0.11, + population: '2195914', + rank: '4', + state: 'Texas', + }, { city: 'Philadelphia', growth: 0.026, @@ -50,14 +74,62 @@ let longList = [ rank: '5', state: 'Pennsylvania', }, - { city: 'Phoenix', growth: 0.14, population: '1513367', rank: '6', state: 'Arizona' }, - { city: 'San Antonio', growth: 0.21, population: '1409019', rank: '7', state: 'Texas' }, - { city: 'San Diego', growth: 0.105, population: '1355896', rank: '8', state: 'California' }, - { city: 'Dallas', growth: 0.056, population: '1257676', rank: '9', state: 'Texas' }, - { city: 'San Jose', growth: 0.105, population: '998537', rank: '10', state: 'California' }, - { city: 'Austin', growth: 0.317, population: '885400', rank: '11', state: 'Texas' }, - { city: 'Indianapolis', growth: 0.078, population: '843393', rank: '12', state: 'Indiana' }, - { city: 'Jacksonville', growth: 0.143, population: '842583', rank: '13', state: 'Florida' }, + { + city: 'Phoenix', + growth: 0.14, + population: '1513367', + rank: '6', + state: 'Arizona', + }, + { + city: 'San Antonio', + growth: 0.21, + population: '1409019', + rank: '7', + state: 'Texas', + }, + { + city: 'San Diego', + growth: 0.105, + population: '1355896', + rank: '8', + state: 'California', + }, + { + city: 'Dallas', + growth: 0.056, + population: '1257676', + rank: '9', + state: 'Texas', + }, + { + city: 'San Jose', + growth: 0.105, + population: '998537', + rank: '10', + state: 'California', + }, + { + city: 'Austin', + growth: 0.317, + population: '885400', + rank: '11', + state: 'Texas', + }, + { + city: 'Indianapolis', + growth: 0.078, + population: '843393', + rank: '12', + state: 'Indiana', + }, + { + city: 'Jacksonville', + growth: 0.143, + population: '842583', + rank: '13', + state: 'Florida', + }, { city: 'San Francisco', growth: 0.077, @@ -65,7 +137,13 @@ let longList = [ rank: '14', state: 'California', }, - { city: 'Columbus', growth: 0.148, population: '822553', rank: '15', state: 'Ohio' }, + { + city: 'Columbus', + growth: 0.148, + population: '822553', + rank: '15', + state: 'Ohio', + }, { city: 'Charlotte', growth: 0.391, @@ -73,12 +151,48 @@ let longList = [ rank: '16', state: 'North Carolina', }, - { city: 'Fort Worth', growth: 0.451, population: '792727', rank: '17', state: 'Texas' }, - { city: 'Detroit', growth: -0.271, population: '688701', rank: '18', state: 'Michigan' }, - { city: 'El Paso', growth: 0.194, population: '674433', rank: '19', state: 'Texas' }, - { city: 'Memphis', growth: -0.053, population: '653450', rank: '20', state: 'Tennessee' }, - { city: 'Seattle', growth: 0.156, population: '652405', rank: '21', state: 'Washington' }, - { city: 'Denver', growth: 0.167, population: '649495', rank: '22', state: 'Colorado' }, + { + city: 'Fort Worth', + growth: 0.451, + population: '792727', + rank: '17', + state: 'Texas', + }, + { + city: 'Detroit', + growth: -0.271, + population: '688701', + rank: '18', + state: 'Michigan', + }, + { + city: 'El Paso', + growth: 0.194, + population: '674433', + rank: '19', + state: 'Texas', + }, + { + city: 'Memphis', + growth: -0.053, + population: '653450', + rank: '20', + state: 'Tennessee', + }, + { + city: 'Seattle', + growth: 0.156, + population: '652405', + rank: '21', + state: 'Washington', + }, + { + city: 'Denver', + growth: 0.167, + population: '649495', + rank: '22', + state: 'Colorado', + }, { city: 'Washington', growth: 0.13, @@ -86,7 +200,13 @@ let longList = [ rank: '23', state: 'District of Columbia', }, - { city: 'Boston', growth: 0.094, population: '645966', rank: '24', state: 'Massachusetts' }, + { + city: 'Boston', + growth: 0.094, + population: '645966', + rank: '24', + state: 'Massachusetts', + }, { city: 'Nashville-Davidson', growth: 0.162, @@ -94,8 +214,20 @@ let longList = [ rank: '25', state: 'Tennessee', }, - { city: 'Baltimore', growth: -0.04, population: '622104', rank: '26', state: 'Maryland' }, - { city: 'Oklahoma City', growth: 0.202, population: '610613', rank: '27', state: 'Oklahoma' }, + { + city: 'Baltimore', + growth: -0.04, + population: '622104', + rank: '26', + state: 'Maryland', + }, + { + city: 'Oklahoma City', + growth: 0.202, + population: '610613', + rank: '27', + state: 'Oklahoma', + }, { city: 'Louisville/Jefferson County', growth: 0.1, @@ -103,18 +235,90 @@ let longList = [ rank: '28', state: 'Kentucky', }, - { city: 'Portland', growth: 0.15, population: '609456', rank: '29', state: 'Oregon' }, - { city: 'Las Vegas', growth: 0.245, population: '603488', rank: '30', state: 'Nevada' }, - { city: 'Milwaukee', growth: 0.003, population: '599164', rank: '31', state: 'Wisconsin' }, - { city: 'Albuquerque', growth: 0.235, population: '556495', rank: '32', state: 'New Mexico' }, - { city: 'Tucson', growth: 0.075, population: '526116', rank: '33', state: 'Arizona' }, - { city: 'Fresno', growth: 0.183, population: '509924', rank: '34', state: 'California' }, - { city: 'Sacramento', growth: 0.172, population: '479686', rank: '35', state: 'California' }, - { city: 'Long Beach', growth: 0.015, population: '469428', rank: '36', state: 'California' }, - { city: 'Kansas City', growth: 0.055, population: '467007', rank: '37', state: 'Missouri' }, - { city: 'Mesa', growth: 0.135, population: '457587', rank: '38', state: 'Arizona' }, - { city: 'Virginia Beach', growth: 0.051, population: '448479', rank: '39', state: 'Virginia' }, - { city: 'Atlanta', growth: 0.062, population: '447841', rank: '40', state: 'Georgia' }, + { + city: 'Portland', + growth: 0.15, + population: '609456', + rank: '29', + state: 'Oregon', + }, + { + city: 'Las Vegas', + growth: 0.245, + population: '603488', + rank: '30', + state: 'Nevada', + }, + { + city: 'Milwaukee', + growth: 0.003, + population: '599164', + rank: '31', + state: 'Wisconsin', + }, + { + city: 'Albuquerque', + growth: 0.235, + population: '556495', + rank: '32', + state: 'New Mexico', + }, + { + city: 'Tucson', + growth: 0.075, + population: '526116', + rank: '33', + state: 'Arizona', + }, + { + city: 'Fresno', + growth: 0.183, + population: '509924', + rank: '34', + state: 'California', + }, + { + city: 'Sacramento', + growth: 0.172, + population: '479686', + rank: '35', + state: 'California', + }, + { + city: 'Long Beach', + growth: 0.015, + population: '469428', + rank: '36', + state: 'California', + }, + { + city: 'Kansas City', + growth: 0.055, + population: '467007', + rank: '37', + state: 'Missouri', + }, + { + city: 'Mesa', + growth: 0.135, + population: '457587', + rank: '38', + state: 'Arizona', + }, + { + city: 'Virginia Beach', + growth: 0.051, + population: '448479', + rank: '39', + state: 'Virginia', + }, + { + city: 'Atlanta', + growth: 0.062, + population: '447841', + rank: '40', + state: 'Georgia', + }, { city: 'Colorado Springs', growth: 0.214, @@ -122,15 +326,69 @@ let longList = [ rank: '41', state: 'Colorado', }, - { city: 'Omaha', growth: 0.059, population: '434353', rank: '42', state: 'Nebraska' }, - { city: 'Raleigh', growth: 0.487, population: '431746', rank: '43', state: 'North Carolina' }, - { city: 'Miami', growth: 0.149, population: '417650', rank: '44', state: 'Florida' }, - { city: 'Oakland', growth: 0.013, population: '406253', rank: '45', state: 'California' }, - { city: 'Minneapolis', growth: 0.045, population: '400070', rank: '46', state: 'Minnesota' }, - { city: 'Tulsa', growth: 0.013, population: '398121', rank: '47', state: 'Oklahoma' }, - { city: 'Cleveland', growth: -0.181, population: '390113', rank: '48', state: 'Ohio' }, - { city: 'Wichita', growth: 0.097, population: '386552', rank: '49', state: 'Kansas' }, - { city: 'Arlington', growth: 0.133, population: '379577', rank: '50', state: 'Texas' }, + { + city: 'Omaha', + growth: 0.059, + population: '434353', + rank: '42', + state: 'Nebraska', + }, + { + city: 'Raleigh', + growth: 0.487, + population: '431746', + rank: '43', + state: 'North Carolina', + }, + { + city: 'Miami', + growth: 0.149, + population: '417650', + rank: '44', + state: 'Florida', + }, + { + city: 'Oakland', + growth: 0.013, + population: '406253', + rank: '45', + state: 'California', + }, + { + city: 'Minneapolis', + growth: 0.045, + population: '400070', + rank: '46', + state: 'Minnesota', + }, + { + city: 'Tulsa', + growth: 0.013, + population: '398121', + rank: '47', + state: 'Oklahoma', + }, + { + city: 'Cleveland', + growth: -0.181, + population: '390113', + rank: '48', + state: 'Ohio', + }, + { + city: 'Wichita', + growth: 0.097, + population: '386552', + rank: '49', + state: 'Kansas', + }, + { + city: 'Arlington', + growth: 0.133, + population: '379577', + rank: '50', + state: 'Texas', + }, ]; export let Standard = () => { @@ -204,7 +462,9 @@ export let Search = () => { filteredShortList: computed('searchTerm', function () { let term = this.searchTerm.toLowerCase(); - return productMetadata.filter((product) => product.name.toLowerCase().includes(term)); + return productMetadata.filter((product) => + product.name.toLowerCase().includes(term) + ); }), }).create(), }, @@ -241,10 +501,17 @@ export let SortableColumns = () => { }) ), - sortedShortList: computed('controller.{sortProperty,sortDescending}', function () { - let sorted = productMetadata.sortBy(this.get('controller.sortProperty') || 'name'); - return this.get('controller.sortDescending') ? sorted.reverse() : sorted; - }), + sortedShortList: computed( + 'controller.{sortProperty,sortDescending}', + function () { + let sorted = productMetadata.sortBy( + this.get('controller.sortProperty') || 'name' + ); + return this.get('controller.sortDescending') + ? sorted.reverse() + : sorted; + } + ), }, }; }; @@ -279,10 +546,17 @@ export let MultiRow = () => { }) ), - sortedShortList: computed('controller.{sortProperty,sortDescending}', function () { - let sorted = productMetadata.sortBy(this.get('controller.sortProperty') || 'name'); - return this.get('controller.sortDescending') ? sorted.reverse() : sorted; - }), + sortedShortList: computed( + 'controller.{sortProperty,sortDescending}', + function () { + let sorted = productMetadata.sortBy( + this.get('controller.sortProperty') || 'name' + ); + return this.get('controller.sortDescending') + ? sorted.reverse() + : sorted; + } + ), }, }; }; diff --git a/ui/testem.js b/ui/testem.js index c048c20b1..f0d81dfdf 100644 --- a/ui/testem.js +++ b/ui/testem.js @@ -39,7 +39,11 @@ if (process.env.CI) { }, { ReporterClass: XunitReporter, - args: [false, fs.createWriteStream('/tmp/test-reports/ui.xml'), { get: () => false }], + args: [ + false, + fs.createWriteStream('/tmp/test-reports/ui.xml'), + { get: () => false }, + ], }, ]; diff --git a/ui/tests/acceptance/allocation-detail-test.js b/ui/tests/acceptance/allocation-detail-test.js index d1fd9defe..4a6809bf9 100644 --- a/ui/tests/acceptance/allocation-detail-test.js +++ b/ui/tests/acceptance/allocation-detail-test.js @@ -25,10 +25,10 @@ module('Acceptance | allocation detail', function(hooks) { job = server.create('job', { groupsCount: 1, withGroupServices: true, - createAllocations: false, + createAllocations: false }); allocation = server.create('allocation', 'withTaskWithPorts', { - clientStatus: 'running', + clientStatus: 'running' }); // Make sure the node has an unhealthy driver @@ -36,14 +36,14 @@ module('Acceptance | allocation detail', function(hooks) { driver: assign(node.drivers, { docker: { detected: true, - healthy: false, - }, - }), + healthy: false + } + }) }); // Make sure a task for the allocation depends on the unhealthy driver server.schema.tasks.first().update({ - driver: 'docker', + driver: 'docker' }); window.localStorage.clear(); @@ -56,8 +56,15 @@ module('Acceptance | allocation detail', function(hooks) { }); test('/allocation/:id should name the allocation and link to the corresponding job and node', async function(assert) { - assert.ok(Allocation.title.includes(allocation.name), 'Allocation name is in the heading'); - assert.equal(Allocation.details.job, job.name, 'Job name is in the subheading'); + assert.ok( + Allocation.title.includes(allocation.name), + 'Allocation name is in the heading' + ); + assert.equal( + Allocation.details.job, + job.name, + 'Job name is in the subheading' + ); assert.equal( Allocation.details.client, node.id.split('-')[0], @@ -68,18 +75,38 @@ module('Acceptance | allocation detail', function(hooks) { assert.equal(document.title, `Allocation ${allocation.name} - Nomad`); await Allocation.details.visitJob(); - assert.equal(currentURL(), `/jobs/${job.id}`, 'Job link navigates to the job'); + assert.equal( + currentURL(), + `/jobs/${job.id}`, + 'Job link navigates to the job' + ); await Allocation.visit({ id: allocation.id }); await Allocation.details.visitClient(); - assert.equal(currentURL(), `/clients/${node.id}`, 'Client link navigates to the client'); + assert.equal( + currentURL(), + `/clients/${node.id}`, + 'Client link navigates to the client' + ); }); test('/allocation/:id should include resource utilization graphs', async function(assert) { - assert.equal(Allocation.resourceCharts.length, 2, 'Two resource utilization graphs'); - assert.equal(Allocation.resourceCharts.objectAt(0).name, 'CPU', 'First chart is CPU'); - assert.equal(Allocation.resourceCharts.objectAt(1).name, 'Memory', 'Second chart is Memory'); + assert.equal( + Allocation.resourceCharts.length, + 2, + 'Two resource utilization graphs' + ); + assert.equal( + Allocation.resourceCharts.objectAt(0).name, + 'CPU', + 'First chart is CPU' + ); + assert.equal( + Allocation.resourceCharts.objectAt(1).name, + 'Memory', + 'Second chart is Memory' + ); }); test('/allocation/:id should present task lifecycles', async function(assert) { @@ -87,12 +114,12 @@ module('Acceptance | allocation detail', function(hooks) { groupsCount: 1, groupTaskCount: 6, withGroupServices: true, - createAllocations: false, + createAllocations: false }); const allocation = server.create('allocation', 'withTaskWithPorts', { clientStatus: 'running', - jobId: job.id, + jobId: job.id }); await Allocation.visit({ id: allocation.id }); @@ -109,10 +136,17 @@ module('Acceptance | allocation detail', function(hooks) { .sortBy('name') .find(taskState => { const task = server.db.tasks.findBy({ name: taskState.name }); - return task.Lifecycle && task.Lifecycle.Hook === 'prestart' && !task.Lifecycle.Sidecar; + return ( + task.Lifecycle && + task.Lifecycle.Hook === 'prestart' && + !task.Lifecycle.Sidecar + ); }); - assert.equal(currentURL(), `/allocations/${allocation.id}/${prestartEphemeralTask.name}`); + assert.equal( + currentURL(), + `/allocations/${allocation.id}/${prestartEphemeralTask.name}` + ); }); test('/allocation/:id should list all tasks for the allocation', async function(assert) { @@ -125,19 +159,21 @@ module('Acceptance | allocation detail', function(hooks) { }); test('each task row should list high-level information for the task', async function(assert) { - const task = server.db.taskStates.where({ allocationId: allocation.id }).sortBy('name')[0]; + const task = server.db.taskStates + .where({ allocationId: allocation.id }) + .sortBy('name')[0]; const events = server.db.taskEvents.where({ taskStateId: task.id }); const event = events[events.length - 1]; const taskGroup = server.schema.taskGroups.where({ jobId: allocation.jobId, - name: allocation.taskGroup, + name: allocation.taskGroup }).models[0]; const jobTask = taskGroup.tasks.models.find(m => m.name === task.name); const volumes = jobTask.volumeMounts.map(volume => ({ name: volume.Volume, - source: taskGroup.volumes[volume.Volume].Source, + source: taskGroup.volumes[volume.Volume].Source })); Allocation.tasks[0].as(taskRow => { @@ -152,14 +188,22 @@ module('Acceptance | allocation detail', function(hooks) { const volumesText = taskRow.volumes; volumes.forEach(volume => { - assert.ok(volumesText.includes(volume.name), `Found label ${volume.name}`); - assert.ok(volumesText.includes(volume.source), `Found value ${volume.source}`); + assert.ok( + volumesText.includes(volume.name), + `Found label ${volume.name}` + ); + assert.ok( + volumesText.includes(volume.source), + `Found value ${volume.source}` + ); }); }); }); test('each task row should link to the task detail page', async function(assert) { - const task = server.db.taskStates.where({ allocationId: allocation.id }).sortBy('name')[0]; + const task = server.db.taskStates + .where({ allocationId: allocation.id }) + .sortBy('name')[0]; await Allocation.tasks.objectAt(0).clickLink(); @@ -186,9 +230,9 @@ module('Acceptance | allocation detail', function(hooks) { name: 'node-read', rulesJSON: { Node: { - Policy: 'read', - }, - }, + Policy: 'read' + } + } }); const clientToken = server.create('token', { type: 'client' }); clientToken.policyIds = [policy.id]; @@ -200,7 +244,10 @@ module('Acceptance | allocation detail', function(hooks) { await Tokens.secret(clientToken.secretId).submit(); await Allocation.visit({ id: allocation.id }); - assert.ok(Allocation.firstUnhealthyTask().hasUnhealthyDriver, 'Warning is shown'); + assert.ok( + Allocation.firstUnhealthyTask().hasUnhealthyDriver, + 'Warning is shown' + ); }); test('proxy task has a proxy tag', async function(assert) { @@ -208,12 +255,12 @@ module('Acceptance | allocation detail', function(hooks) { job = server.create('job', { groupsCount: 1, withGroupServices: true, - createAllocations: false, + createAllocations: false }); allocation = server.create('allocation', 'withTaskWithPorts', { clientStatus: 'running', - jobId: job.id, + jobId: job.id }); const taskState = allocation.taskStates.models.sortBy('name')[0]; @@ -228,14 +275,19 @@ module('Acceptance | allocation detail', function(hooks) { test('when there are no tasks, an empty state is shown', async function(assert) { // Make sure the allocation is pending in order to ensure there are no tasks - allocation = server.create('allocation', 'withTaskWithPorts', { clientStatus: 'pending' }); + allocation = server.create('allocation', 'withTaskWithPorts', { + clientStatus: 'pending' + }); await Allocation.visit({ id: allocation.id }); assert.ok(Allocation.isEmpty, 'Task table empty state is shown'); }); test('when the allocation has not been rescheduled, the reschedule events section is not rendered', async function(assert) { - assert.notOk(Allocation.hasRescheduleEvents, 'Reschedule Events section exists'); + assert.notOk( + Allocation.hasRescheduleEvents, + 'Reschedule Events section exists' + ); }); test('ports are listed', async function(assert) { @@ -246,12 +298,17 @@ module('Acceptance | allocation detail', function(hooks) { assert.equal(renderedPort.name, serverPort.Label); assert.equal(renderedPort.to, serverPort.To); - assert.equal(renderedPort.address, formatHost(serverPort.HostIP, serverPort.Value)); + assert.equal( + renderedPort.address, + formatHost(serverPort.HostIP, serverPort.Value) + ); }); }); test('services are listed', async function(assert) { - const taskGroup = server.schema.taskGroups.findBy({ name: allocation.taskGroup }); + const taskGroup = server.schema.taskGroups.findBy({ + name: allocation.taskGroup + }); assert.equal(Allocation.services.length, taskGroup.services.length); @@ -263,11 +320,16 @@ module('Acceptance | allocation detail', function(hooks) { assert.equal(renderedService.onUpdate, serverService.onUpdate); assert.equal(renderedService.tags, (serverService.tags || []).join(', ')); - assert.equal(renderedService.connect, serverService.Connect ? 'Yes' : 'No'); + assert.equal( + renderedService.connect, + serverService.Connect ? 'Yes' : 'No' + ); const upstreams = serverService.Connect.SidecarService.Proxy.Upstreams; const serverUpstreamsString = upstreams - .map(upstream => `${upstream.DestinationName}:${upstream.LocalBindPort}`) + .map( + upstream => `${upstream.DestinationName}:${upstream.LocalBindPort}` + ) .join(' '); assert.equal(renderedService.upstreams, serverUpstreamsString); @@ -284,9 +346,17 @@ module('Acceptance | allocation detail', function(hooks) { '/v1/allocation/not-a-real-allocation', 'A request to the nonexistent allocation is made' ); - assert.equal(currentURL(), '/allocations/not-a-real-allocation', 'The URL persists'); + assert.equal( + currentURL(), + '/allocations/not-a-real-allocation', + 'The URL persists' + ); assert.ok(Allocation.error.isShown, 'Error message is shown'); - assert.equal(Allocation.error.title, 'Not Found', 'Error message is for 404'); + assert.equal( + Allocation.error.title, + 'Not Found', + 'Error message is for 404' + ); }); test('allocation can be stopped', async function(assert) { @@ -345,7 +415,10 @@ module('Acceptance | allocation detail', function(hooks) { await Allocation.inlineError.dismiss(); - assert.notOk(Allocation.inlineError.isShown, 'Inline error is no longer shown'); + assert.notOk( + Allocation.inlineError.isShown, + 'Inline error is no longer shown' + ); }); }); @@ -364,7 +437,10 @@ module('Acceptance | allocation detail (rescheduled)', function(hooks) { }); test('when the allocation has been rescheduled, the reschedule events section is rendered', async function(assert) { - assert.ok(Allocation.hasRescheduleEvents, 'Reschedule Events section exists'); + assert.ok( + Allocation.hasRescheduleEvents, + 'Reschedule Events section exists' + ); }); }); @@ -411,14 +487,25 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) { test('shows a dedicated section to the allocation that preempted this allocation', async function(assert) { allocation = server.create('allocation', 'preempted'); - const preempter = server.schema.find('allocation', allocation.preemptedByAllocation); + const preempter = server.schema.find( + 'allocation', + allocation.preemptedByAllocation + ); const preempterJob = server.schema.find('job', preempter.jobId); const preempterClient = server.schema.find('node', preempter.nodeId); await Allocation.visit({ id: allocation.id }); assert.ok(Allocation.wasPreempted, 'Preempted allocation section is shown'); - assert.equal(Allocation.preempter.status, preempter.clientStatus, 'Preempter status matches'); - assert.equal(Allocation.preempter.name, preempter.name, 'Preempter name matches'); + assert.equal( + Allocation.preempter.status, + preempter.clientStatus, + 'Preempter status matches' + ); + assert.equal( + Allocation.preempter.name, + preempter.name, + 'Preempter name matches' + ); assert.equal( Allocation.preempter.priority, preempterJob.priority, @@ -452,7 +539,10 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) { test('shows a dedicated section to the allocations this allocation preempted', async function(assert) { allocation = server.create('allocation', 'preempter'); await Allocation.visit({ id: allocation.id }); - assert.ok(Allocation.preempted, 'The allocations this allocation preempted are shown'); + assert.ok( + Allocation.preempted, + 'The allocations this allocation preempted are shown' + ); }); test('each preempted allocation in the table lists basic allocation information', async function(assert) { @@ -471,7 +561,11 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) { 'The preemptions table has a row for each preempted allocation' ); - assert.equal(preemptionRow.shortId, preemption.id.split('-')[0], 'Preemption short id'); + assert.equal( + preemptionRow.shortId, + preemption.id.split('-')[0], + 'Preemption short id' + ); assert.equal( preemptionRow.createTime, moment(preemption.createTime / 1000000).format('MMM DD HH:mm:ss ZZ'), @@ -482,8 +576,16 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) { moment(preemption.modifyTime / 1000000).fromNow(), 'Preemption modify time' ); - assert.equal(preemptionRow.status, preemption.clientStatus, 'Client status'); - assert.equal(preemptionRow.jobVersion, preemption.jobVersion, 'Job Version'); + assert.equal( + preemptionRow.status, + preemption.clientStatus, + 'Client status' + ); + assert.equal( + preemptionRow.jobVersion, + preemption.jobVersion, + 'Job Version' + ); assert.equal( preemptionRow.client, server.db.nodes.find(preemption.nodeId).id.split('-')[0], @@ -498,9 +600,9 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) { name: 'node-read', rulesJSON: { Node: { - Policy: 'read', - }, - }, + Policy: 'read' + } + } }); const clientToken = server.create('token', { type: 'client' }); clientToken.policyIds = [policy.id]; @@ -517,13 +619,20 @@ module('Acceptance | allocation detail (preemptions)', function(hooks) { const preemptionRow = Allocation.preemptions.objectAt(0); await preemptionRow.visitClient(); - assert.equal(currentURL(), `/clients/${preemption.nodeId}`, 'Node links to node page'); + assert.equal( + currentURL(), + `/clients/${preemption.nodeId}`, + 'Node links to node page' + ); }); test('when an allocation both preempted allocations and was preempted itself, both preemptions sections are shown', async function(assert) { allocation = server.create('allocation', 'preempter', 'preempted'); await Allocation.visit({ id: allocation.id }); - assert.ok(Allocation.preempted, 'The allocations this allocation preempted are shown'); + assert.ok( + Allocation.preempted, + 'The allocations this allocation preempted are shown' + ); assert.ok(Allocation.wasPreempted, 'Preempted allocation section is shown'); }); }); diff --git a/ui/tests/acceptance/allocation-fs-test.js b/ui/tests/acceptance/allocation-fs-test.js index 80638e64d..5f88d72ab 100644 --- a/ui/tests/acceptance/allocation-fs-test.js +++ b/ui/tests/acceptance/allocation-fs-test.js @@ -18,7 +18,10 @@ module('Acceptance | allocation fs', function (hooks) { server.create('node', 'forceIPv4'); const job = server.create('job', { createAllocations: false }); - allocation = server.create('allocation', { jobId: job.id, clientStatus: 'running' }); + allocation = server.create('allocation', { + jobId: job.id, + clientStatus: 'running', + }); this.allocation = allocation; @@ -27,7 +30,13 @@ module('Acceptance | allocation fs', function (hooks) { // Nested files files.push(server.create('allocFile', { isDir: true, name: 'directory' })); - files.push(server.create('allocFile', { isDir: true, name: 'another', parent: files[0] })); + files.push( + server.create('allocFile', { + isDir: true, + name: 'another', + parent: files[0], + }) + ); files.push( server.create('allocFile', 'file', { name: 'something.txt', @@ -36,7 +45,9 @@ module('Acceptance | allocation fs', function (hooks) { }) ); - files.push(server.create('allocFile', { isDir: true, name: 'empty-directory' })); + files.push( + server.create('allocFile', { isDir: true, name: 'empty-directory' }) + ); files.push(server.create('allocFile', 'file', { fileType: 'txt' })); files.push(server.create('allocFile', 'file', { fileType: 'txt' })); @@ -47,8 +58,10 @@ module('Acceptance | allocation fs', function (hooks) { browseFilesystem({ visitSegments: ({ allocation }) => ({ id: allocation.id }), - getExpectedPathBase: ({ allocation }) => `/allocations/${allocation.id}/fs/`, - getTitleComponent: ({ allocation }) => `Allocation ${allocation.id.split('-')[0]} filesystem`, + getExpectedPathBase: ({ allocation }) => + `/allocations/${allocation.id}/fs/`, + getTitleComponent: ({ allocation }) => + `Allocation ${allocation.id.split('-')[0]} filesystem`, getBreadcrumbComponent: ({ allocation }) => allocation.id.split('-')[0], getFilesystemRoot: () => '', pageObjectVisitFunctionName: 'visitAllocation', diff --git a/ui/tests/acceptance/application-errors-test.js b/ui/tests/acceptance/application-errors-test.js index cbd725bc9..114e970bd 100644 --- a/ui/tests/acceptance/application-errors-test.js +++ b/ui/tests/acceptance/application-errors-test.js @@ -30,7 +30,10 @@ module('Acceptance | application errors ', function (hooks) { assert.ok(ClientsList.error.isPresent, 'Application has errored'); await JobsList.visit(); - assert.notOk(JobsList.error.isPresent, 'Application is no longer in an error state'); + assert.notOk( + JobsList.error.isPresent, + 'Application is no longer in an error state' + ); }); test('the 403 error page links to the ACL tokens page', async function (assert) { diff --git a/ui/tests/acceptance/behaviors/fs.js b/ui/tests/acceptance/behaviors/fs.js index 0520d5f7b..f99183d9c 100644 --- a/ui/tests/acceptance/behaviors/fs.js +++ b/ui/tests/acceptance/behaviors/fs.js @@ -55,7 +55,12 @@ export default function browseFilesystem({ }); test('visiting filesystem paths', async function (assert) { - const paths = ['some-file.log', 'a/deep/path/to/a/file.log', '/', 'Unicode™®']; + const paths = [ + 'some-file.log', + 'a/deep/path/to/a/file.log', + '/', + 'Unicode™®', + ]; const testPath = async (filePath) => { let pathWithLeadingSlash = filePath; @@ -100,11 +105,15 @@ export default function browseFilesystem({ test('navigating allocation filesystem', async function (assert) { const objects = { allocation: this.allocation, task: this.task }; - await FS[pageObjectVisitPathFunctionName]({ ...visitSegments(objects), path: '/' }); + await FS[pageObjectVisitPathFunctionName]({ + ...visitSegments(objects), + path: '/', + }); const sortedFiles = fileSort( 'name', - filesForPath(this.server.schema.allocFiles, getFilesystemRoot(objects)).models + filesForPath(this.server.schema.allocFiles, getFilesystemRoot(objects)) + .models ); assert.ok(FS.fileViewer.isHidden); @@ -119,11 +128,21 @@ export default function browseFilesystem({ FS.directoryEntries[0].as((directory) => { const fileRecord = sortedFiles[0]; - assert.equal(directory.name, fileRecord.name, 'directories should come first'); + assert.equal( + directory.name, + fileRecord.name, + 'directories should come first' + ); assert.ok(directory.isDirectory); assert.equal(directory.size, '', 'directory sizes are hidden'); - assert.equal(directory.lastModified, moment(fileRecord.modTime).fromNow()); - assert.notOk(directory.path.includes('//'), 'paths shouldn’t have redundant separators'); + assert.equal( + directory.lastModified, + moment(fileRecord.modTime).fromNow() + ); + assert.notOk( + directory.path.includes('//'), + 'paths shouldn’t have redundant separators' + ); }); FS.directoryEntries[2].as((file) => { @@ -139,7 +158,10 @@ export default function browseFilesystem({ assert.equal(FS.directoryEntries.length, 1); assert.equal(FS.breadcrumbs.length, 2); - assert.equal(FS.breadcrumbsText, `${getBreadcrumbComponent(objects)} ${this.directory.name}`); + assert.equal( + FS.breadcrumbsText, + `${getBreadcrumbComponent(objects)} ${this.directory.name}` + ); assert.notOk(FS.breadcrumbs[0].isActive); @@ -157,7 +179,9 @@ export default function browseFilesystem({ assert.equal(FS.breadcrumbs.length, 3); assert.equal( FS.breadcrumbsText, - `${getBreadcrumbComponent(objects)} ${this.directory.name} ${this.nestedDirectory.name}` + `${getBreadcrumbComponent(objects)} ${this.directory.name} ${ + this.nestedDirectory.name + }` ); assert.equal(FS.breadcrumbs[2].text, this.nestedDirectory.name); @@ -171,7 +195,10 @@ export default function browseFilesystem({ ); await FS.breadcrumbs[1].visit(); - assert.equal(FS.breadcrumbsText, `${getBreadcrumbComponent(objects)} ${this.directory.name}`); + assert.equal( + FS.breadcrumbsText, + `${getBreadcrumbComponent(objects)} ${this.directory.name}` + ); assert.equal(FS.breadcrumbs.length, 2); }); @@ -299,22 +326,32 @@ export default function browseFilesystem({ const objects = { allocation: this.allocation, task: this.task }; const node = server.db.nodes.find(this.allocation.nodeId); - server.get(`http://${node.httpAddr}/v1/client/fs/readat/:allocation_id`, function () { - return new Response(500); - }); + server.get( + `http://${node.httpAddr}/v1/client/fs/readat/:allocation_id`, + function () { + return new Response(500); + } + ); - await FS[pageObjectVisitPathFunctionName]({ ...visitSegments(objects), path: '/' }); + await FS[pageObjectVisitPathFunctionName]({ + ...visitSegments(objects), + path: '/', + }); const sortedFiles = fileSort( 'name', - filesForPath(this.server.schema.allocFiles, getFilesystemRoot(objects)).models + filesForPath(this.server.schema.allocFiles, getFilesystemRoot(objects)) + .models ); const fileRecord = sortedFiles.find((f) => !f.isDir); const fileIndex = sortedFiles.indexOf(fileRecord); await FS.directoryEntries[fileIndex].visit(); - assert.equal(FS.breadcrumbsText, `${getBreadcrumbComponent(objects)} ${fileRecord.name}`); + assert.equal( + FS.breadcrumbsText, + `${getBreadcrumbComponent(objects)} ${fileRecord.name}` + ); assert.ok(FS.fileViewer.isPresent); @@ -353,8 +390,16 @@ export default function browseFilesystem({ ...visitSegments({ allocation: this.allocation, task: this.task }), path: '/what-is-this', }); - assert.notEqual(FS.error.title, 'Not Found', '500 is not interpreted as 404'); - assert.equal(FS.error.title, 'Server Error', '500 is not interpreted as 500'); + assert.notEqual( + FS.error.title, + 'Not Found', + '500 is not interpreted as 404' + ); + assert.equal( + FS.error.title, + 'Server Error', + '500 is not interpreted as 500' + ); await visit('/'); @@ -378,8 +423,16 @@ export default function browseFilesystem({ ...visitSegments({ allocation: this.allocation, task: this.task }), path: this.directory.name, }); - assert.notEqual(FS.error.title, 'Not Found', '500 is not interpreted as 404'); - assert.equal(FS.error.title, 'Server Error', '500 is not interpreted as 404'); + assert.notEqual( + FS.error.title, + 'Not Found', + '500 is not interpreted as 404' + ); + assert.equal( + FS.error.title, + 'Server Error', + '500 is not interpreted as 404' + ); await visit('/'); diff --git a/ui/tests/acceptance/behaviors/page-size-select.js b/ui/tests/acceptance/behaviors/page-size-select.js index a9d14e42a..f20204372 100644 --- a/ui/tests/acceptance/behaviors/page-size-select.js +++ b/ui/tests/acceptance/behaviors/page-size-select.js @@ -2,7 +2,12 @@ import { pluralize } from 'ember-inflector'; import { test } from 'qunit'; import { selectChoose } from 'ember-power-select/test-support'; -export default function pageSizeSelect({ resourceName, pageObject, pageObjectList, setup }) { +export default function pageSizeSelect({ + resourceName, + pageObject, + pageObjectList, + setup, +}) { test(`the number of ${pluralize( resourceName )} is equal to the localStorage user setting for page size`, async function (assert) { diff --git a/ui/tests/acceptance/client-detail-test.js b/ui/tests/acceptance/client-detail-test.js index 56e7a959f..94a319bc0 100644 --- a/ui/tests/acceptance/client-detail-test.js +++ b/ui/tests/acceptance/client-detail-test.js @@ -72,11 +72,18 @@ module('Acceptance | client detail', function (hooks) { 'Second breadcrumb is a titled breadcrumb saying the node short id' ); await Layout.breadcrumbFor('clients.index').visit(); - assert.equal(currentURL(), '/clients', 'First breadcrumb links back to clients'); + assert.equal( + currentURL(), + '/clients', + 'First breadcrumb links back to clients' + ); }); test('/clients/:id should list immediate details for the node in the title', async function (assert) { - node = server.create('node', 'forceIPv4', { schedulingEligibility: 'eligible', drain: false }); + node = server.create('node', 'forceIPv4', { + schedulingEligibility: 'eligible', + drain: false, + }); await ClientDetail.visit({ id: node.id }); @@ -113,13 +120,27 @@ module('Acceptance | client detail', function (hooks) { test('/clients/:id should include resource utilization graphs', async function (assert) { await ClientDetail.visit({ id: node.id }); - assert.equal(ClientDetail.resourceCharts.length, 2, 'Two resource utilization graphs'); - assert.equal(ClientDetail.resourceCharts.objectAt(0).name, 'CPU', 'First chart is CPU'); - assert.equal(ClientDetail.resourceCharts.objectAt(1).name, 'Memory', 'Second chart is Memory'); + assert.equal( + ClientDetail.resourceCharts.length, + 2, + 'Two resource utilization graphs' + ); + assert.equal( + ClientDetail.resourceCharts.objectAt(0).name, + 'CPU', + 'First chart is CPU' + ); + assert.equal( + ClientDetail.resourceCharts.objectAt(1).name, + 'Memory', + 'Second chart is Memory' + ); }); test('/clients/:id should list all allocations on the node', async function (assert) { - const allocationsCount = server.db.allocations.where({ nodeId: node.id }).length; + const allocationsCount = server.db.allocations.where({ + nodeId: node.id, + }).length; await ClientDetail.visit({ id: node.id }); @@ -135,7 +156,10 @@ module('Acceptance | client detail', function (hooks) { await ClientDetail.visit({ id: emptyNode.id }); - assert.true(ClientDetail.emptyAllocations.isVisible, 'Empty message is visible'); + assert.true( + ClientDetail.emptyAllocations.isVisible, + 'Empty message is visible' + ); assert.equal(ClientDetail.emptyAllocations.headline, 'No Allocations'); }); @@ -153,13 +177,20 @@ module('Acceptance | client detail', function (hooks) { const tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id)); const cpuUsed = tasks.reduce((sum, task) => sum + task.resources.CPU, 0); - const memoryUsed = tasks.reduce((sum, task) => sum + task.resources.MemoryMB, 0); + const memoryUsed = tasks.reduce( + (sum, task) => sum + task.resources.MemoryMB, + 0 + ); await ClientDetail.visit({ id: node.id }); const allocationRow = ClientDetail.allocations.objectAt(0); - assert.equal(allocationRow.shortId, allocation.id.split('-')[0], 'Allocation short ID'); + assert.equal( + allocationRow.shortId, + allocation.id.split('-')[0], + 'Allocation short ID' + ); assert.equal( allocationRow.createTime, moment(allocation.createTime / 1000000).format('MMM DD HH:mm:ss ZZ'), @@ -170,8 +201,16 @@ module('Acceptance | client detail', function (hooks) { moment(allocation.modifyTime / 1000000).fromNow(), 'Allocation modify time' ); - assert.equal(allocationRow.status, allocation.clientStatus, 'Client status'); - assert.equal(allocationRow.job, server.db.jobs.find(allocation.jobId).name, 'Job name'); + assert.equal( + allocationRow.status, + allocation.clientStatus, + 'Client status' + ); + assert.equal( + allocationRow.job, + server.db.jobs.find(allocation.jobId).name, + 'Job name' + ); assert.ok(allocationRow.taskGroup, 'Task group name'); assert.ok(allocationRow.jobVersion, 'Job Version'); assert.equal(allocationRow.volume, 'Yes', 'Volume'); @@ -180,7 +219,9 @@ module('Acceptance | client detail', function (hooks) { Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks) / cpuUsed, 'CPU %' ); - const roundedTicks = Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks); + const roundedTicks = Math.floor( + allocStats.resourceUsage.CpuStats.TotalTicks + ); assert.equal( allocationRow.cpuTooltip, `${formatHertz(roundedTicks, 'MHz')} / ${formatHertz(cpuUsed, 'MHz')}`, @@ -224,8 +265,15 @@ module('Acceptance | client detail', function (hooks) { .sortBy('modifyIndex') .reverse()[0]; - assert.equal(allocationRow.job, server.db.jobs.find(allocation.jobId).name, 'Job name'); - assert.ok(allocationRow.taskGroup.includes(allocation.taskGroup), 'Task group name'); + assert.equal( + allocationRow.job, + server.db.jobs.find(allocation.jobId).name, + 'Job name' + ); + assert.ok( + allocationRow.taskGroup.includes(allocation.taskGroup), + 'Task group name' + ); }); test('each allocation should link to the allocation detail page', async function (assert) { @@ -302,8 +350,16 @@ module('Acceptance | client detail', function (hooks) { await ClientDetail.allocationFilter.preemptions(); await ClientDetail.allocationFilter.all(); - assert.equal(ClientDetail.allocations.length, allocations.length, 'All allocations are shown'); - assert.equal(currentURL(), `/clients/${node.id}`, 'Filter is persisted in the URL'); + assert.equal( + ClientDetail.allocations.length, + allocations.length, + 'All allocations are shown' + ); + assert.equal( + currentURL(), + `/clients/${node.id}`, + 'Filter is persisted in the URL' + ); }); test('navigating directly to the client detail page with the preemption query param set will filter the allocations table', async function (assert) { @@ -349,7 +405,10 @@ module('Acceptance | client detail', function (hooks) { test('/clients/:id shows an empty message when there is no meta data', async function (assert) { await ClientDetail.visit({ id: node.id }); - assert.notOk(ClientDetail.metaTable, 'Meta attributes table is not on the page'); + assert.notOk( + ClientDetail.metaTable, + 'Meta attributes table is not on the page' + ); assert.ok(ClientDetail.emptyMetaMessage, 'Meta attributes is empty'); }); @@ -365,7 +424,11 @@ module('Acceptance | client detail', function (hooks) { ); assert.equal(currentURL(), '/clients/not-a-real-node', 'The URL persists'); assert.ok(ClientDetail.error.isShown, 'Error message is shown'); - assert.equal(ClientDetail.error.title, 'Not Found', 'Error message is for 404'); + assert.equal( + ClientDetail.error.title, + 'Not Found', + 'Error message is for 404' + ); }); test('/clients/:id shows the recent events list', async function (assert) { @@ -375,7 +438,10 @@ module('Acceptance | client detail', function (hooks) { }); test('each node event shows basic node event information', async function (assert) { - const event = server.db.nodeEvents.where({ nodeId: node.id }).sortBy('time').reverse()[0]; + const event = server.db.nodeEvents + .where({ nodeId: node.id }) + .sortBy('time') + .reverse()[0]; await ClientDetail.visit({ id: node.id }); @@ -402,7 +468,9 @@ module('Acceptance | client detail', function (hooks) { node.drivers = nodeDrivers; const drivers = Object.keys(node.drivers) - .map((driverName) => assign({ Name: driverName }, node.drivers[driverName])) + .map((driverName) => + assign({ Name: driverName }, node.drivers[driverName]) + ) .sortBy('Name'); assert.ok(drivers.length > 0, 'Node has drivers'); @@ -412,7 +480,11 @@ module('Acceptance | client detail', function (hooks) { drivers.forEach((driver, index) => { const driverHead = ClientDetail.driverHeads.objectAt(index); - assert.equal(driverHead.name, driver.Name, `${driver.Name}: Name is correct`); + assert.equal( + driverHead.name, + driver.Name, + `${driver.Name}: Name is correct` + ); assert.equal( driverHead.detected, driver.Detected ? 'Yes' : 'No', @@ -436,7 +508,9 @@ module('Acceptance | client detail', function (hooks) { `${driver.Name}: Health is correct` ); assert.ok( - driverHead.healthClass.includes(driver.Healthy ? 'running' : 'failed'), + driverHead.healthClass.includes( + driver.Healthy ? 'running' : 'failed' + ), `${driver.Name}: Swatch with correct class is shown` ); } @@ -452,15 +526,23 @@ module('Acceptance | client detail', function (hooks) { node.drivers = nodeDrivers; const driver = Object.keys(node.drivers) - .map((driverName) => assign({ Name: driverName }, node.drivers[driverName])) + .map((driverName) => + assign({ Name: driverName }, node.drivers[driverName]) + ) .sortBy('Name')[0]; await ClientDetail.visit({ id: node.id }); const driverHead = ClientDetail.driverHeads.objectAt(0); const driverBody = ClientDetail.driverBodies.objectAt(0); - assert.notOk(driverBody.descriptionIsShown, 'Driver health description is not shown'); - assert.notOk(driverBody.attributesAreShown, 'Driver attributes section is not shown'); + assert.notOk( + driverBody.descriptionIsShown, + 'Driver health description is not shown' + ); + assert.notOk( + driverBody.attributesAreShown, + 'Driver attributes section is not shown' + ); await driverHead.toggle(); assert.equal( @@ -468,7 +550,10 @@ module('Acceptance | client detail', function (hooks) { driver.HealthDescription, 'Driver health description is now shown' ); - assert.ok(driverBody.attributesAreShown, 'Driver attributes section is now shown'); + assert.ok( + driverBody.attributesAreShown, + 'Driver attributes section is now shown' + ); }); test('the status light indicates when the node is ineligible for scheduling', async function (assert) { @@ -535,7 +620,10 @@ module('Acceptance | client detail', function (hooks) { await ClientDetail.visit({ id: node.id }); - assert.notOk(ClientDetail.drainDetails.durationIsShown, 'Duration is omitted'); + assert.notOk( + ClientDetail.drainDetails.durationIsShown, + 'Duration is omitted' + ); assert.ok( ClientDetail.drainDetails.deadline.includes('No deadline'), @@ -568,9 +656,15 @@ module('Acceptance | client detail', function (hooks) { 'Forced Drain is described' ); - assert.ok(ClientDetail.drainDetails.duration.includes('--'), 'Duration is shown but unset'); + assert.ok( + ClientDetail.drainDetails.duration.includes('--'), + 'Duration is shown but unset' + ); - assert.ok(ClientDetail.drainDetails.deadline.includes('--'), 'Deadline is shown but unset'); + assert.ok( + ClientDetail.drainDetails.deadline.includes('--'), + 'Deadline is shown but unset' + ); assert.ok( ClientDetail.drainDetails.drainSystemJobsText.endsWith('Yes'), @@ -584,7 +678,11 @@ module('Acceptance | client detail', function (hooks) { schedulingEligibility: 'eligible', }); - server.pretender.post('/v1/node/:id/eligibility', () => [200, {}, ''], true); + server.pretender.post( + '/v1/node/:id/eligibility', + () => [200, {}, ''], + true + ); await ClientDetail.visit({ id: node.id }); assert.ok(ClientDetail.eligibilityToggle.isActive); @@ -687,8 +785,11 @@ module('Acceptance | client detail', function (hooks) { await ClientDetail.drainPopover.toggle(); await ClientDetail.drainPopover.deadlineOptions.open(); - const optionsCount = ClientDetail.drainPopover.deadlineOptions.options.length; - await ClientDetail.drainPopover.deadlineOptions.options.objectAt(optionsCount - 1).choose(); + const optionsCount = + ClientDetail.drainPopover.deadlineOptions.options.length; + await ClientDetail.drainPopover.deadlineOptions.options + .objectAt(optionsCount - 1) + .choose(); await ClientDetail.drainPopover.setCustomDeadline('1h40m20s'); await ClientDetail.drainPopover.submit(); @@ -756,8 +857,11 @@ module('Acceptance | client detail', function (hooks) { // Change all options to non-default values. await ClientDetail.drainPopover.deadlineToggle.toggle(); await ClientDetail.drainPopover.deadlineOptions.open(); - const optionsCount = ClientDetail.drainPopover.deadlineOptions.options.length; - await ClientDetail.drainPopover.deadlineOptions.options.objectAt(optionsCount - 1).choose(); + const optionsCount = + ClientDetail.drainPopover.deadlineOptions.options.length; + await ClientDetail.drainPopover.deadlineOptions.options + .objectAt(optionsCount - 1) + .choose(); await ClientDetail.drainPopover.setCustomDeadline('1h40m20s'); await ClientDetail.drainPopover.forceDrainToggle.toggle(); await ClientDetail.drainPopover.systemJobsToggle.toggle(); @@ -934,7 +1038,9 @@ module('Acceptance | client detail', function (hooks) { await ClientDetail.eligibilityToggle.toggle(); assert.ok(ClientDetail.eligibilityError.isPresent); - assert.ok(ClientDetail.eligibilityError.title.includes('Eligibility Error')); + assert.ok( + ClientDetail.eligibilityError.title.includes('Eligibility Error') + ); await ClientDetail.eligibilityError.dismiss(); assert.notOk(ClientDetail.eligibilityError.isPresent); @@ -954,7 +1060,9 @@ module('Acceptance | client detail', function (hooks) { await ClientDetail.eligibilityToggle.toggle(); assert.ok(ClientDetail.eligibilityError.isPresent); - assert.ok(ClientDetail.eligibilityError.title.includes('Eligibility Error')); + assert.ok( + ClientDetail.eligibilityError.title.includes('Eligibility Error') + ); await ClientDetail.visit({ id: node2.id }); @@ -977,7 +1085,10 @@ module('Acceptance | client detail', function (hooks) { .sortBy('Name'); assert.ok(ClientDetail.hasHostVolumes); - assert.equal(ClientDetail.hostVolumes.length, Object.keys(node.hostVolumes).length); + assert.equal( + ClientDetail.hostVolumes.length, + Object.keys(node.hostVolumes).length + ); ClientDetail.hostVolumes.forEach((volume, index) => { assert.equal(volume.name, sortedHostVolumes[index].Name); @@ -995,7 +1106,10 @@ module('Acceptance | client detail', function (hooks) { const volumeRow = sortedHostVolumes[0]; assert.equal(volume.name, volumeRow.Name); assert.equal(volume.path, volumeRow.Path); - assert.equal(volume.permissions, volumeRow.ReadOnly ? 'Read' : 'Read/Write'); + assert.equal( + volume.permissions, + volumeRow.ReadOnly ? 'Read' : 'Read/Write' + ); }); }); @@ -1064,14 +1178,22 @@ module('Acceptance | client detail (multi-namespace)', function (hooks) { server.create('agent'); // Make a job for each namespace, but have both scheduled on the same node - server.create('job', { id: 'job-1', namespaceId: 'default', createAllocations: false }); + server.create('job', { + id: 'job-1', + namespaceId: 'default', + createAllocations: false, + }); server.createList('allocation', 3, { nodeId: node.id, jobId: 'job-1', clientStatus: 'running', }); - server.create('job', { id: 'job-2', namespaceId: 'other-namespace', createAllocations: false }); + server.create('job', { + id: 'job-2', + namespaceId: 'other-namespace', + createAllocations: false, + }); server.createList('allocation', 3, { nodeId: node.id, jobId: 'job-2', @@ -1094,7 +1216,10 @@ module('Acceptance | client detail (multi-namespace)', function (hooks) { 'Job One fetched correctly' ); assert.ok( - server.pretender.handledRequests.findBy('url', '/v1/job/job-2?namespace=other-namespace'), + server.pretender.handledRequests.findBy( + 'url', + '/v1/job/job-2?namespace=other-namespace' + ), 'Job Two fetched correctly' ); }); @@ -1140,7 +1265,10 @@ module('Acceptance | client detail (multi-namespace)', function (hooks) { }); }); -function testFacet(label, { facet, paramName, beforeEach, filter, expectedOptions }) { +function testFacet( + label, + { facet, paramName, beforeEach, filter, expectedOptions } +) { test(`facet ${label} | the ${label} facet has the correct options`, async function (assert) { await beforeEach(); await facet.toggle(); @@ -1225,7 +1353,9 @@ function testFacet(label, { facet, paramName, beforeEach, filter, expectedOption assert.equal( currentURL(), - `/clients/${node.id}?${paramName}=${encodeURIComponent(JSON.stringify(selection))}`, + `/clients/${node.id}?${paramName}=${encodeURIComponent( + JSON.stringify(selection) + )}`, 'URL has the correct query param key and value' ); }); diff --git a/ui/tests/acceptance/client-monitor-test.js b/ui/tests/acceptance/client-monitor-test.js index 32adc3ca4..900885b97 100644 --- a/ui/tests/acceptance/client-monitor-test.js +++ b/ui/tests/acceptance/client-monitor-test.js @@ -11,11 +11,11 @@ let node; let managementToken; let clientToken; -module('Acceptance | client monitor', function (hooks) { +module('Acceptance | client monitor', function(hooks) { setupApplicationTest(hooks); setupMirage(hooks); - hooks.beforeEach(function () { + hooks.beforeEach(function() { node = server.create('node'); managementToken = server.create('token'); @@ -27,25 +27,28 @@ module('Acceptance | client monitor', function (hooks) { run.later(run, run.cancelTimers, 500); }); - test('it passes an accessibility audit', async function (assert) { + test('it passes an accessibility audit', async function(assert) { await ClientMonitor.visit({ id: node.id }); await a11yAudit(assert); }); - test('/clients/:id/monitor should have a breadcrumb trail linking back to clients', async function (assert) { + test('/clients/:id/monitor should have a breadcrumb trail linking back to clients', async function(assert) { await ClientMonitor.visit({ id: node.id }); assert.equal(Layout.breadcrumbFor('clients.index').text, 'Clients'); - assert.equal(Layout.breadcrumbFor('clients.client').text, `Client ${node.id.split('-')[0]}`); + assert.equal( + Layout.breadcrumbFor('clients.client').text, + `Client ${node.id.split('-')[0]}` + ); await Layout.breadcrumbFor('clients.index').visit(); assert.equal(currentURL(), '/clients'); }); - test('the monitor page immediately streams agent monitor output at the info level', async function (assert) { + test('the monitor page immediately streams agent monitor output at the info level', async function(assert) { await ClientMonitor.visit({ id: node.id }); - const logRequest = server.pretender.handledRequests.find((req) => + const logRequest = server.pretender.handledRequests.find(req => req.url.startsWith('/v1/agent/monitor') ); assert.ok(ClientMonitor.logsArePresent); @@ -53,13 +56,13 @@ module('Acceptance | client monitor', function (hooks) { assert.ok(logRequest.url.includes('log_level=info')); }); - test('switching the log level persists the new log level as a query param', async function (assert) { + test('switching the log level persists the new log level as a query param', async function(assert) { await ClientMonitor.visit({ id: node.id }); await ClientMonitor.selectLogLevel('Debug'); assert.equal(currentURL(), `/clients/${node.id}/monitor?level=debug`); }); - test('when the current access token does not include the agent:read rule, a descriptive error message is shown', async function (assert) { + test('when the current access token does not include the agent:read rule, a descriptive error message is shown', async function(assert) { window.localStorage.nomadTokenSecret = clientToken.secretId; await ClientMonitor.visit({ id: node.id }); diff --git a/ui/tests/acceptance/clients-list-test.js b/ui/tests/acceptance/clients-list-test.js index b5275e934..538810ac5 100644 --- a/ui/tests/acceptance/clients-list-test.js +++ b/ui/tests/acceptance/clients-list-test.js @@ -39,7 +39,11 @@ module('Acceptance | clients list', function (hooks) { const sortedNodes = server.db.nodes.sortBy('modifyIndex').reverse(); ClientsList.nodes.forEach((node, index) => { - assert.equal(node.id, sortedNodes[index].id.split('-')[0], 'Clients are ordered'); + assert.equal( + node.id, + sortedNodes[index].id.split('-')[0], + 'Clients are ordered' + ); }); assert.equal(document.title, 'Clients - Nomad'); @@ -82,7 +86,9 @@ module('Acceptance | clients list', function (hooks) { server.create('job', { createAllocations: false }); - const running = server.createList('allocation', 2, { clientStatus: 'running' }); + const running = server.createList('allocation', 2, { + clientStatus: 'running', + }); server.createList('allocation', 3, { clientStatus: 'pending' }); server.createList('allocation', 10, { clientStatus: 'complete' }); @@ -154,10 +160,16 @@ module('Acceptance | clients list', function (hooks) { ); assert.equal(ClientsList.nodes[4].compositeStatus.text, 'ineligible'); - assert.ok(ClientsList.nodes[4].compositeStatus.isWarning, 'expected warning class'); + assert.ok( + ClientsList.nodes[4].compositeStatus.isWarning, + 'expected warning class' + ); assert.equal(ClientsList.nodes[5].compositeStatus.text, 'draining'); - assert.ok(ClientsList.nodes[5].compositeStatus.isInfo, 'expected info class'); + assert.ok( + ClientsList.nodes[5].compositeStatus.isInfo, + 'expected info class' + ); await ClientsList.sortBy('compositeStatus'); @@ -171,7 +183,10 @@ module('Acceptance | clients list', function (hooks) { ]); // Simulate a client state change arriving through polling - let readyClient = this.owner.lookup('service:store').peekAll('node').findBy('modifyIndex', 5); + let readyClient = this.owner + .lookup('service:store') + .peekAll('node') + .findBy('modifyIndex', 5); readyClient.set('schedulingEligibility', 'ineligible'); await settled(); @@ -262,7 +277,13 @@ module('Acceptance | clients list', function (hooks) { testFacet('State', { facet: ClientsList.facets.state, paramName: 'state', - expectedOptions: ['Initializing', 'Ready', 'Down', 'Ineligible', 'Draining'], + expectedOptions: [ + 'Initializing', + 'Ready', + 'Down', + 'Ineligible', + 'Draining', + ], async beforeEach() { server.create('agent'); @@ -270,15 +291,27 @@ module('Acceptance | clients list', function (hooks) { server.createList('node', 2, { status: 'ready' }); server.createList('node', 2, { status: 'down' }); - server.createList('node', 2, { schedulingEligibility: 'eligible', drain: false }); - server.createList('node', 2, { schedulingEligibility: 'ineligible', drain: false }); - server.createList('node', 2, { schedulingEligibility: 'ineligible', drain: true }); + server.createList('node', 2, { + schedulingEligibility: 'eligible', + drain: false, + }); + server.createList('node', 2, { + schedulingEligibility: 'ineligible', + drain: false, + }); + server.createList('node', 2, { + schedulingEligibility: 'ineligible', + drain: true, + }); await ClientsList.visit(); }, filter: (node, selection) => { if (selection.includes('draining') && !node.drain) return false; - if (selection.includes('ineligible') && node.schedulingEligibility === 'eligible') + if ( + selection.includes('ineligible') && + node.schedulingEligibility === 'eligible' + ) return false; return selection.includes(node.status); @@ -322,17 +355,23 @@ module('Acceptance | clients list', function (hooks) { paramName: 'volume', expectedOptions(nodes) { const flatten = (acc, val) => acc.concat(Object.keys(val)); - return Array.from(new Set(nodes.mapBy('hostVolumes').reduce(flatten, []))); + return Array.from( + new Set(nodes.mapBy('hostVolumes').reduce(flatten, [])) + ); }, async beforeEach() { server.create('agent'); server.createList('node', 2, { hostVolumes: { One: { Name: 'One' } } }); - server.createList('node', 2, { hostVolumes: { One: { Name: 'One' }, Two: { Name: 'Two' } } }); + server.createList('node', 2, { + hostVolumes: { One: { Name: 'One' }, Two: { Name: 'Two' } }, + }); server.createList('node', 2, { hostVolumes: { Two: { Name: 'Two' } } }); await ClientsList.visit(); }, filter: (node, selection) => - Object.keys(node.hostVolumes).find((volume) => selection.includes(volume)), + Object.keys(node.hostVolumes).find((volume) => + selection.includes(volume) + ), }); test('when the facet selections result in no matches, the empty state states why', async function (assert) { @@ -344,7 +383,11 @@ module('Acceptance | clients list', function (hooks) { await ClientsList.facets.state.toggle(); await ClientsList.facets.state.options.objectAt(0).toggle(); assert.ok(ClientsList.isEmpty, 'There is an empty message'); - assert.equal(ClientsList.empty.headline, 'No Matches', 'The message is appropriate'); + assert.equal( + ClientsList.empty.headline, + 'No Matches', + 'The message is appropriate' + ); }); test('the clients list is immediately filtered based on query params', async function (assert) { @@ -354,10 +397,17 @@ module('Acceptance | clients list', function (hooks) { await ClientsList.visit({ class: JSON.stringify(['wtf-tiny']) }); - assert.equal(ClientsList.nodes.length, 1, 'Only one client shown due to query param'); + assert.equal( + ClientsList.nodes.length, + 1, + 'Only one client shown due to query param' + ); }); - function testFacet(label, { facet, paramName, beforeEach, filter, expectedOptions }) { + function testFacet( + label, + { facet, paramName, beforeEach, filter, expectedOptions } + ) { test(`the ${label} facet has the correct options`, async function (assert) { await beforeEach(); await facet.toggle(); @@ -442,7 +492,9 @@ module('Acceptance | clients list', function (hooks) { assert.equal( currentURL(), - `/clients?${paramName}=${encodeURIComponent(JSON.stringify(selection))}`, + `/clients?${paramName}=${encodeURIComponent( + JSON.stringify(selection) + )}`, 'URL has the correct query param key and value' ); }); diff --git a/ui/tests/acceptance/exec-test.js b/ui/tests/acceptance/exec-test.js index dcedea4f3..21b549575 100644 --- a/ui/tests/acceptance/exec-test.js +++ b/ui/tests/acceptance/exec-test.js @@ -52,7 +52,11 @@ module('Acceptance | exec', function (hooks) { status: 'running', }); - await Exec.visitJob({ job: this.job.id, namespace: namespace.id, region: 'region-2' }); + await Exec.visitJob({ + job: this.job.id, + namespace: namespace.id, + region: 'region-2', + }); assert.equal(document.title, 'Exec - region-2 - Nomad'); @@ -101,7 +105,10 @@ module('Acceptance | exec', function (hooks) { test('a task group with a pending allocation shows a loading spinner', async function (assert) { let taskGroup = this.job.taskGroups.models.sortBy('name')[0]; - this.server.db.allocations.update({ taskGroup: taskGroup.name }, { clientStatus: 'pending' }); + this.server.db.allocations.update( + { taskGroup: taskGroup.name }, + { clientStatus: 'pending' } + ); await Exec.visitJob({ job: this.job.id }); assert.ok(Exec.taskGroups[0].isLoading); @@ -109,7 +116,10 @@ module('Acceptance | exec', function (hooks) { test('a task group with no running task states or pending allocations should not be shown', async function (assert) { let taskGroup = this.job.taskGroups.models.sortBy('name')[0]; - this.server.db.allocations.update({ taskGroup: taskGroup.name }, { clientStatus: 'failed' }); + this.server.db.allocations.update( + { taskGroup: taskGroup.name }, + { clientStatus: 'failed' } + ); await Exec.visitJob({ job: this.job.id }); assert.notEqual(Exec.taskGroups[0].name, taskGroup.name); @@ -125,7 +135,10 @@ module('Acceptance | exec', function (hooks) { let runningTaskGroup = this.job.taskGroups.models.sortBy('name')[1]; runningTaskGroup.tasks.models.forEach((task, index) => { if (index > 0) { - this.server.db.taskStates.update({ name: task.name }, { finishedAt: new Date() }); + this.server.db.taskStates.update( + { name: task.name }, + { finishedAt: new Date() } + ); } }); @@ -146,7 +159,10 @@ module('Acceptance | exec', function (hooks) { let changingTaskStateName; runningTaskGroup.tasks.models.sortBy('name').forEach((task, index) => { if (index > 0) { - this.server.db.taskStates.update({ name: task.name }, { finishedAt: new Date() }); + this.server.db.taskStates.update( + { name: task.name }, + { finishedAt: new Date() } + ); } if (index === 1) { @@ -164,7 +180,10 @@ module('Acceptance | exec', function (hooks) { .lookup('service:store') .peekAll('allocation') .forEach((allocation) => { - const changingTaskState = allocation.states.findBy('name', changingTaskStateName); + const changingTaskState = allocation.states.findBy( + 'name', + changingTaskStateName + ); if (changingTaskState) { changingTaskState.set('finishedAt', undefined); @@ -221,7 +240,11 @@ module('Acceptance | exec', function (hooks) { assert.ok(Exec.taskGroups[0].chevron.isDown); let task = taskGroup.tasks.models.sortBy('name')[0]; - await Exec.visitTask({ job: this.job.id, task_group: taskGroup.name, task_name: task.name }); + await Exec.visitTask({ + job: this.job.id, + task_group: taskGroup.name, + task_name: task.name, + }); assert.equal(Exec.taskGroups[0].tasks.length, taskGroup.tasks.length); assert.ok(Exec.taskGroups[0].chevron.isDown); @@ -242,7 +265,10 @@ module('Acceptance | exec', function (hooks) { await settled(); - assert.equal(currentURL(), `/exec/${this.job.id}/${taskGroup.name}/${task.name}`); + assert.equal( + currentURL(), + `/exec/${this.job.id}/${taskGroup.name}/${task.name}` + ); assert.ok(Exec.taskGroups[0].tasks[0].isActive); assert.equal( @@ -257,7 +283,9 @@ module('Acceptance | exec', function (hooks) { assert.equal( window.execTerminal.buffer.active.getLine(6).translateToString().trim(), - `$ nomad alloc exec -i -t -task ${task.name} ${allocationId.split('-')[0]} /bin/bash` + `$ nomad alloc exec -i -t -task ${task.name} ${ + allocationId.split('-')[0] + } /bin/bash` ); }); @@ -270,7 +298,10 @@ module('Acceptance | exec', function (hooks) { }); let allocation = allocations[allocations.length - 1]; - this.server.db.taskStates.update({ name: task.name }, { name: 'spaced name!' }); + this.server.db.taskStates.update( + { name: task.name }, + { name: 'spaced name!' } + ); task.name = 'spaced name!'; task.save(); @@ -286,7 +317,9 @@ module('Acceptance | exec', function (hooks) { assert.equal( window.execTerminal.buffer.active.getLine(4).translateToString().trim(), - `$ nomad alloc exec -i -t -task spaced\\ name\\! ${allocation.id.split('-')[0]} /bin/bash` + `$ nomad alloc exec -i -t -task spaced\\ name\\! ${ + allocation.id.split('-')[0] + } /bin/bash` ); }); @@ -394,7 +427,10 @@ module('Acceptance | exec', function (hooks) { await Exec.terminal.pressEnter(); await settled(); - assert.equal(mockSocket.sent[0], `{"version":1,"auth_token":"${secretId}"}`); + assert.equal( + mockSocket.sent[0], + `{"version":1,"auth_token":"${secretId}"}` + ); }); test('only one socket is opened after switching between tasks', async function (assert) { @@ -471,7 +507,9 @@ module('Acceptance | exec', function (hooks) { assert.equal( window.execTerminal.buffer.active.getLine(6).translateToString().trim(), - `$ nomad alloc exec -i -t -task ${task.name} ${allocation.id.split('-')[0]}` + `$ nomad alloc exec -i -t -task ${task.name} ${ + allocation.id.split('-')[0] + }` ); await window.execTerminal.simulateCommandDataEvent('/sh'); @@ -504,7 +542,9 @@ module('Acceptance | exec', function (hooks) { assert.equal( window.execTerminal.buffer.active.getLine(4).translateToString().trim(), - `$ nomad alloc exec -i -t -task ${task.name} ${allocation.id.split('-')[0]} /bin/sh` + `$ nomad alloc exec -i -t -task ${task.name} ${ + allocation.id.split('-')[0] + } /bin/sh` ); }); diff --git a/ui/tests/acceptance/job-allocations-test.js b/ui/tests/acceptance/job-allocations-test.js index 954d62980..2cfec901a 100644 --- a/ui/tests/acceptance/job-allocations-test.js +++ b/ui/tests/acceptance/job-allocations-test.js @@ -26,11 +26,16 @@ module('Acceptance | job allocations', function (hooks) { hooks.beforeEach(function () { server.create('node'); - job = server.create('job', { noFailedPlacements: true, createAllocations: false }); + job = server.create('job', { + noFailedPlacements: true, + createAllocations: false, + }); }); test('it passes an accessibility audit', async function (assert) { - server.createList('allocation', Allocations.pageSize - 1, { shallow: true }); + server.createList('allocation', Allocations.pageSize - 1, { + shallow: true, + }); allocations = server.schema.allocations.where({ jobId: job.id }).models; await Allocations.visit({ id: job.id }); @@ -38,7 +43,9 @@ module('Acceptance | job allocations', function (hooks) { }); test('lists all allocations for the job', async function (assert) { - server.createList('allocation', Allocations.pageSize - 1, { shallow: true }); + server.createList('allocation', Allocations.pageSize - 1, { + shallow: true, + }); allocations = server.schema.allocations.where({ jobId: job.id }).models; await Allocations.visit({ id: job.id }); @@ -53,7 +60,11 @@ module('Acceptance | job allocations', function (hooks) { Allocations.allocations.forEach((allocation, index) => { const shortId = sortedAllocations[index].id.split('-')[0]; - assert.equal(allocation.shortId, shortId, `Allocation ${index} is ${shortId}`); + assert.equal( + allocation.shortId, + shortId, + `Allocation ${index} is ${shortId}` + ); }); assert.equal(document.title, `Job ${job.name} allocations - Nomad`); @@ -90,7 +101,11 @@ module('Acceptance | job allocations', function (hooks) { await Allocations.visit({ id: job.id }); await Allocations.search('ffffff'); - assert.equal(Allocations.allocations.length, 5, 'List is filtered by search term'); + assert.equal( + Allocations.allocations.length, + 5, + 'List is filtered by search term' + ); }); test('when a search yields no results, the search box remains', async function (assert) { @@ -120,9 +135,17 @@ module('Acceptance | job allocations', function (hooks) { '/v1/job/not-a-real-job', 'A request to the nonexistent job is made' ); - assert.equal(currentURL(), '/jobs/not-a-real-job/allocations', 'The URL persists'); + assert.equal( + currentURL(), + '/jobs/not-a-real-job/allocations', + 'The URL persists' + ); assert.ok(Allocations.error.isPresent, 'Error message is shown'); - assert.equal(Allocations.error.title, 'Not Found', 'Error message is for 404'); + assert.equal( + Allocations.error.title, + 'Not Found', + 'Error message is for 404' + ); }); testFacet('Status', { @@ -135,7 +158,8 @@ module('Acceptance | job allocations', function (hooks) { }); await Allocations.visit({ id: job.id }); }, - filter: (alloc, selection) => alloc.jobId == job.id && selection.includes(alloc.clientStatus), + filter: (alloc, selection) => + alloc.jobId == job.id && selection.includes(alloc.clientStatus), }); testFacet('Client', { @@ -166,7 +190,9 @@ module('Acceptance | job allocations', function (hooks) { paramName: 'taskGroup', expectedOptions(allocs) { return Array.from( - new Set(allocs.filter((alloc) => alloc.jobId == job.id).mapBy('taskGroup')) + new Set( + allocs.filter((alloc) => alloc.jobId == job.id).mapBy('taskGroup') + ) ).sort(); }, async beforeEach() { @@ -178,11 +204,15 @@ module('Acceptance | job allocations', function (hooks) { await Allocations.visit({ id: job.id }); }, - filter: (alloc, selection) => alloc.jobId == job.id && selection.includes(alloc.taskGroup), + filter: (alloc, selection) => + alloc.jobId == job.id && selection.includes(alloc.taskGroup), }); }); -function testFacet(label, { facet, paramName, beforeEach, filter, expectedOptions }) { +function testFacet( + label, + { facet, paramName, beforeEach, filter, expectedOptions } +) { test(`facet ${label} | the ${label} facet has the correct options`, async function (assert) { await beforeEach(); await facet.toggle(); @@ -267,7 +297,9 @@ function testFacet(label, { facet, paramName, beforeEach, filter, expectedOption assert.equal( currentURL(), - `/jobs/${job.id}/allocations?${paramName}=${encodeURIComponent(JSON.stringify(selection))}`, + `/jobs/${job.id}/allocations?${paramName}=${encodeURIComponent( + JSON.stringify(selection) + )}`, 'URL has the correct query param key and value' ); }); diff --git a/ui/tests/acceptance/job-clients-test.js b/ui/tests/acceptance/job-clients-test.js index a4813d7e4..c4d9f7b20 100644 --- a/ui/tests/acceptance/job-clients-test.js +++ b/ui/tests/acceptance/job-clients-test.js @@ -75,14 +75,21 @@ module('Acceptance | job clients', function (hooks) { ['createTime', 'modifyTime'].forEach((col) => { if (jobStatus === 'not scheduled') { - assert.equal(clientRow[col].text, '-', `row ${index} doesn't have ${col} tooltip`); + assert.equal( + clientRow[col].text, + '-', + `row ${index} doesn't have ${col} tooltip` + ); return; } const hasTooltip = clientRow[col].tooltip.isPresent; const tooltipText = clientRow[col].tooltip.text; assert.true(hasTooltip, `row ${index} has ${col} tooltip`); - assert.ok(tooltipText, `row ${index} has ${col} tooltip content ${tooltipText}`); + assert.ok( + tooltipText, + `row ${index} has ${col} tooltip content ${tooltipText}` + ); }); }); }); @@ -142,7 +149,11 @@ module('Acceptance | job clients', function (hooks) { '/v1/job/not-a-real-job', 'A request to the nonexistent job is made' ); - assert.equal(currentURL(), '/jobs/not-a-real-job/clients', 'The URL persists'); + assert.equal( + currentURL(), + '/jobs/not-a-real-job/clients', + 'The URL persists' + ); assert.ok(Clients.error.isPresent, 'Error message is shown'); assert.equal(Clients.error.title, 'Not Found', 'Error message is for 404'); }); diff --git a/ui/tests/acceptance/job-definition-test.js b/ui/tests/acceptance/job-definition-test.js index 142f3d698..08eb59e7d 100644 --- a/ui/tests/acceptance/job-definition-test.js +++ b/ui/tests/acceptance/job-definition-test.js @@ -38,7 +38,11 @@ module('Acceptance | job definition', function (hooks) { const jobRequests = server.pretender.handledRequests .map((req) => req.url.split('?')[0]) .filter((url) => url === jobURL); - assert.ok(jobRequests.length === 2, 'Two requests for the job were made'); + assert.strictEqual( + jobRequests.length, + 2, + 'Two requests for the job were made' + ); }); test('the job definition can be edited', async function (assert) { @@ -46,7 +50,10 @@ module('Acceptance | job definition', function (hooks) { await Definition.edit(); - assert.ok(Definition.editor.isPresent, 'Editor is shown after clicking edit'); + assert.ok( + Definition.editor.isPresent, + 'Editor is shown after clicking edit' + ); assert.notOk(Definition.jsonViewer, 'Editor replaces the JSON viewer'); }); @@ -60,8 +67,15 @@ module('Acceptance | job definition', function (hooks) { test('when in editing mode, the editor is prepopulated with the job definition', async function (assert) { const requests = server.pretender.handledRequests; - const jobDefinition = requests.findBy('url', `/v1/job/${job.id}`).responseText; - const formattedJobDefinition = JSON.stringify(JSON.parse(jobDefinition), null, 2); + const jobDefinition = requests.findBy( + 'url', + `/v1/job/${job.id}` + ).responseText; + const formattedJobDefinition = JSON.stringify( + JSON.parse(jobDefinition), + null, + 2 + ); await Definition.edit(); @@ -77,7 +91,11 @@ module('Acceptance | job definition', function (hooks) { await Definition.editor.plan(); await Definition.editor.run(); - assert.equal(currentURL(), `/jobs/${job.id}`, 'Now on the job overview page'); + assert.equal( + currentURL(), + `/jobs/${job.id}`, + 'Now on the job overview page' + ); }); test('when the job for the definition is not found, an error message is shown, but the URL persists', async function (assert) { @@ -90,8 +108,16 @@ module('Acceptance | job definition', function (hooks) { '/v1/job/not-a-real-job', 'A request to the nonexistent job is made' ); - assert.equal(currentURL(), '/jobs/not-a-real-job/definition', 'The URL persists'); + assert.equal( + currentURL(), + '/jobs/not-a-real-job/definition', + 'The URL persists' + ); assert.ok(Definition.error.isPresent, 'Error message is shown'); - assert.equal(Definition.error.title, 'Not Found', 'Error message is for 404'); + assert.equal( + Definition.error.title, + 'Not Found', + 'Error message is for 404' + ); }); }); diff --git a/ui/tests/acceptance/job-deployments-test.js b/ui/tests/acceptance/job-deployments-test.js index 7d77ccd51..68c621b8d 100644 --- a/ui/tests/acceptance/job-deployments-test.js +++ b/ui/tests/acceptance/job-deployments-test.js @@ -23,8 +23,14 @@ module('Acceptance | job deployments', function (hooks) { job = server.create('job'); deployments = server.schema.deployments.where({ jobId: job.id }); sortedDeployments = deployments.sort((a, b) => { - const aVersion = server.db.jobVersions.findBy({ jobId: a.jobId, version: a.versionNumber }); - const bVersion = server.db.jobVersions.findBy({ jobId: b.jobId, version: b.versionNumber }); + const aVersion = server.db.jobVersions.findBy({ + jobId: a.jobId, + version: a.versionNumber, + }); + const bVersion = server.db.jobVersions.findBy({ + jobId: b.jobId, + version: b.versionNumber, + }); if (aVersion.submitTime < bVersion.submitTime) { return 1; } else if (aVersion.submitTime > bVersion.submitTime) { @@ -60,15 +66,23 @@ module('Acceptance | job deployments', function (hooks) { }); const deploymentRow = Deployments.deployments.objectAt(0); - assert.ok(deploymentRow.text.includes(deployment.id.split('-')[0]), 'Short ID'); + assert.ok( + deploymentRow.text.includes(deployment.id.split('-')[0]), + 'Short ID' + ); assert.equal(deploymentRow.status, deployment.status, 'Status'); assert.ok( deploymentRow.statusClass.includes(classForStatus(deployment.status)), 'Status Class' ); - assert.ok(deploymentRow.version.includes(deployment.versionNumber), 'Version #'); assert.ok( - deploymentRow.submitTime.includes(moment(version.submitTime / 1000000).fromNow()), + deploymentRow.version.includes(deployment.versionNumber), + 'Version #' + ); + assert.ok( + deploymentRow.submitTime.includes( + moment(version.submitTime / 1000000).fromNow() + ), 'Submit time ago' ); }); @@ -76,8 +90,8 @@ module('Acceptance | job deployments', function (hooks) { test('when the deployment is running and needs promotion, the deployment item says so', async function (assert) { // Ensure the deployment needs deployment const deployment = sortedDeployments.models[0]; - const taskGroupSummary = deployment.deploymentTaskGroupSummaryIds.map((id) => - server.schema.deploymentTaskGroupSummaries.find(id) + const taskGroupSummary = deployment.deploymentTaskGroupSummaryIds.map( + (id) => server.schema.deploymentTaskGroupSummaries.find(id) )[0]; deployment.update('status', 'running'); @@ -94,7 +108,10 @@ module('Acceptance | job deployments', function (hooks) { await Deployments.visit({ id: job.id }); const deploymentRow = Deployments.deployments.objectAt(0); - assert.ok(deploymentRow.promotionIsRequired, 'Requires Promotion badge found'); + assert.ok( + deploymentRow.promotionIsRequired, + 'Requires Promotion badge found' + ); }); test('each deployment item can be opened to show details', async function (assert) { @@ -112,8 +129,8 @@ module('Acceptance | job deployments', function (hooks) { const deployment = sortedDeployments.models[0]; const deploymentRow = Deployments.deployments.objectAt(0); - const taskGroupSummaries = deployment.deploymentTaskGroupSummaryIds.map((id) => - server.db.deploymentTaskGroupSummaries.find(id) + const taskGroupSummaries = deployment.deploymentTaskGroupSummaryIds.map( + (id) => server.db.deploymentTaskGroupSummaries.find(id) ); await deploymentRow.toggle(); @@ -163,8 +180,8 @@ module('Acceptance | job deployments', function (hooks) { const deployment = sortedDeployments.models[0]; const deploymentRow = Deployments.deployments.objectAt(0); - const taskGroupSummaries = deployment.deploymentTaskGroupSummaryIds.map((id) => - server.db.deploymentTaskGroupSummaries.find(id) + const taskGroupSummaries = deployment.deploymentTaskGroupSummaryIds.map( + (id) => server.db.deploymentTaskGroupSummaries.find(id) ); await deploymentRow.toggle(); @@ -178,11 +195,22 @@ module('Acceptance | job deployments', function (hooks) { ); const taskGroup = taskGroupSummaries[0]; - const taskGroupRow = deploymentRow.taskGroups.findOneBy('name', taskGroup.name); + const taskGroupRow = deploymentRow.taskGroups.findOneBy( + 'name', + taskGroup.name + ); assert.equal(taskGroupRow.name, taskGroup.name, 'Name'); - assert.equal(taskGroupRow.promotion, promotionTestForTaskGroup(taskGroup), 'Needs Promotion'); - assert.equal(taskGroupRow.autoRevert, taskGroup.autoRevert ? 'Yes' : 'No', 'Auto Revert'); + assert.equal( + taskGroupRow.promotion, + promotionTestForTaskGroup(taskGroup), + 'Needs Promotion' + ); + assert.equal( + taskGroupRow.autoRevert, + taskGroup.autoRevert ? 'Yes' : 'No', + 'Auto Revert' + ); assert.equal( taskGroupRow.canaries, `${taskGroup.placedCanaries.length} / ${taskGroup.desiredCanaries}`, @@ -193,8 +221,16 @@ module('Acceptance | job deployments', function (hooks) { `${taskGroup.placedAllocs} / ${taskGroup.desiredTotal}`, 'Allocs' ); - assert.equal(taskGroupRow.healthy, taskGroup.healthyAllocs, 'Healthy Allocs'); - assert.equal(taskGroupRow.unhealthy, taskGroup.unhealthyAllocs, 'Unhealthy Allocs'); + assert.equal( + taskGroupRow.healthy, + taskGroup.healthyAllocs, + 'Healthy Allocs' + ); + assert.equal( + taskGroupRow.unhealthy, + taskGroup.unhealthyAllocs, + 'Unhealthy Allocs' + ); assert.equal( taskGroupRow.progress, moment(taskGroup.requireProgressBy).format("MMM DD, 'YY HH:mm:ss ZZ"), @@ -210,16 +246,26 @@ module('Acceptance | job deployments', function (hooks) { // TODO: Make this less brittle. This logic is copied from the mirage config, // since there is no reference to allocations on the deployment model. - const allocations = server.db.allocations.where({ jobId: deployment.jobId }).slice(0, 3); + const allocations = server.db.allocations + .where({ jobId: deployment.jobId }) + .slice(0, 3); await deploymentRow.toggle(); assert.ok(deploymentRow.hasAllocations, 'Allocations found'); - assert.equal(deploymentRow.allocations.length, allocations.length, 'One row per allocation'); + assert.equal( + deploymentRow.allocations.length, + allocations.length, + 'One row per allocation' + ); const allocation = allocations[0]; const allocationRow = deploymentRow.allocations.objectAt(0); - assert.equal(allocationRow.shortId, allocation.id.split('-')[0], 'Allocation is as expected'); + assert.equal( + allocationRow.shortId, + allocation.id.split('-')[0], + 'Allocation is as expected' + ); }); test('when the job for the deployments is not found, an error message is shown, but the URL persists', async function (assert) { @@ -232,9 +278,17 @@ module('Acceptance | job deployments', function (hooks) { '/v1/job/not-a-real-job', 'A request to the nonexistent job is made' ); - assert.equal(currentURL(), '/jobs/not-a-real-job/deployments', 'The URL persists'); + assert.equal( + currentURL(), + '/jobs/not-a-real-job/deployments', + 'The URL persists' + ); assert.ok(Deployments.error.isPresent, 'Error message is shown'); - assert.equal(Deployments.error.title, 'Not Found', 'Error message is for 404'); + assert.equal( + Deployments.error.title, + 'Not Found', + 'Error message is for 404' + ); }); function classForStatus(status) { diff --git a/ui/tests/acceptance/job-detail-test.js b/ui/tests/acceptance/job-detail-test.js index 3d0e9b853..68147cdc6 100644 --- a/ui/tests/acceptance/job-detail-test.js +++ b/ui/tests/acceptance/job-detail-test.js @@ -5,7 +5,9 @@ import { setupApplicationTest } from 'ember-qunit'; import { setupMirage } from 'ember-cli-mirage/test-support'; import moment from 'moment'; import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit'; -import moduleForJob, { moduleForJobWithClientStatus } from 'nomad-ui/tests/helpers/module-for-job'; +import moduleForJob, { + moduleForJobWithClientStatus, +} from 'nomad-ui/tests/helpers/module-for-job'; import JobDetail from 'nomad-ui/tests/pages/jobs/detail'; moduleForJob('Acceptance | job detail (batch)', 'allocations', () => @@ -16,26 +18,30 @@ moduleForJob('Acceptance | job detail (system)', 'allocations', () => server.create('job', { type: 'system', shallow: true }) ); -moduleForJobWithClientStatus('Acceptance | job detail with client status (system)', () => - server.create('job', { - status: 'running', - datacenters: ['dc1'], - type: 'system', - createAllocations: false, - }) +moduleForJobWithClientStatus( + 'Acceptance | job detail with client status (system)', + () => + server.create('job', { + status: 'running', + datacenters: ['dc1'], + type: 'system', + createAllocations: false, + }) ); moduleForJob('Acceptance | job detail (sysbatch)', 'allocations', () => server.create('job', { type: 'sysbatch', shallow: true }) ); -moduleForJobWithClientStatus('Acceptance | job detail with client status (sysbatch)', () => - server.create('job', { - status: 'running', - datacenters: ['dc1'], - type: 'sysbatch', - createAllocations: false, - }) +moduleForJobWithClientStatus( + 'Acceptance | job detail with client status (sysbatch)', + () => + server.create('job', { + status: 'running', + datacenters: ['dc1'], + type: 'sysbatch', + createAllocations: false, + }) ); moduleForJobWithClientStatus( @@ -61,14 +67,17 @@ moduleForJob('Acceptance | job detail (sysbatch child)', 'allocations', () => { return server.db.jobs.where({ parentId: parent.id })[0]; }); -moduleForJobWithClientStatus('Acceptance | job detail with client status (sysbatch child)', () => { - const parent = server.create('job', 'periodicSysbatch', { - childrenCount: 1, - shallow: true, - datacenters: ['dc1'], - }); - return server.db.jobs.where({ parentId: parent.id })[0]; -}); +moduleForJobWithClientStatus( + 'Acceptance | job detail with client status (sysbatch child)', + () => { + const parent = server.create('job', 'periodicSysbatch', { + childrenCount: 1, + shallow: true, + datacenters: ['dc1'], + }); + return server.db.jobs.where({ parentId: parent.id })[0]; + } +); moduleForJobWithClientStatus( 'Acceptance | job detail with client status (sysbatch child with namespace)', @@ -98,7 +107,9 @@ moduleForJob( assert.ok(JobDetail.jobsHeader.hasSubmitTime); assert.equal( JobDetail.jobs[0].submitTime, - moment(mostRecentLaunch.submitTime / 1000000).format('MMM DD HH:mm:ss ZZ') + moment(mostRecentLaunch.submitTime / 1000000).format( + 'MMM DD HH:mm:ss ZZ' + ) ); }, } @@ -137,7 +148,9 @@ moduleForJob( assert.ok(JobDetail.jobsHeader.hasSubmitTime); assert.equal( JobDetail.jobs[0].submitTime, - moment(mostRecentLaunch.submitTime / 1000000).format('MMM DD HH:mm:ss ZZ') + moment(mostRecentLaunch.submitTime / 1000000).format( + 'MMM DD HH:mm:ss ZZ' + ) ); }, } @@ -163,14 +176,24 @@ moduleForJob( ); moduleForJob('Acceptance | job detail (periodic child)', 'allocations', () => { - const parent = server.create('job', 'periodic', { childrenCount: 1, shallow: true }); + const parent = server.create('job', 'periodic', { + childrenCount: 1, + shallow: true, + }); return server.db.jobs.where({ parentId: parent.id })[0]; }); -moduleForJob('Acceptance | job detail (parameterized child)', 'allocations', () => { - const parent = server.create('job', 'parameterized', { childrenCount: 1, shallow: true }); - return server.db.jobs.where({ parentId: parent.id })[0]; -}); +moduleForJob( + 'Acceptance | job detail (parameterized child)', + 'allocations', + () => { + const parent = server.create('job', 'parameterized', { + childrenCount: 1, + shallow: true, + }); + return server.db.jobs.where({ parentId: parent.id })[0]; + } +); moduleForJob( 'Acceptance | job detail (service)', @@ -181,23 +204,25 @@ moduleForJob( await JobDetail.tabFor('deployments').visit(); assert.equal(currentURL(), `/jobs/${job.id}/deployments`); }, - 'when the job is not found, an error message is shown, but the URL persists': async ( - job, - assert - ) => { - await JobDetail.visit({ id: 'not-a-real-job' }); + 'when the job is not found, an error message is shown, but the URL persists': + async (job, assert) => { + await JobDetail.visit({ id: 'not-a-real-job' }); - assert.equal( - server.pretender.handledRequests - .filter((request) => !request.url.includes('policy')) - .findBy('status', 404).url, - '/v1/job/not-a-real-job', - 'A request to the nonexistent job is made' - ); - assert.equal(currentURL(), '/jobs/not-a-real-job', 'The URL persists'); - assert.ok(JobDetail.error.isPresent, 'Error message is shown'); - assert.equal(JobDetail.error.title, 'Not Found', 'Error message is for 404'); - }, + assert.equal( + server.pretender.handledRequests + .filter((request) => !request.url.includes('policy')) + .findBy('status', 404).url, + '/v1/job/not-a-real-job', + 'A request to the nonexistent job is made' + ); + assert.equal(currentURL(), '/jobs/not-a-real-job', 'The URL persists'); + assert.ok(JobDetail.error.isPresent, 'Error message is shown'); + assert.equal( + JobDetail.error.title, + 'Not Found', + 'Error message is for 404' + ); + }, } ); @@ -233,7 +258,10 @@ module('Acceptance | job detail (with namespaces)', function (hooks) { const namespace = server.db.namespaces.find(job.namespaceId); await JobDetail.visit({ id: job.id, namespace: namespace.name }); - assert.ok(JobDetail.statFor('namespace').text, 'Namespace included in stats'); + assert.ok( + JobDetail.statFor('namespace').text, + 'Namespace included in stats' + ); }); test('the exec button state can change between namespaces', async function (assert) { @@ -292,7 +320,10 @@ module('Acceptance | job detail (with namespaces)', function (hooks) { }, }); - await JobDetail.visit({ id: job.id, namespace: server.db.namespaces[1].name }); + await JobDetail.visit({ + id: job.id, + namespace: server.db.namespaces[1].name, + }); assert.notOk(JobDetail.execButton.isDisabled); }); @@ -305,10 +336,16 @@ module('Acceptance | job detail (with namespaces)', function (hooks) { }, }); - await JobDetail.visit({ id: job.id, namespace: server.db.namespaces[1].name }); + await JobDetail.visit({ + id: job.id, + namespace: server.db.namespaces[1].name, + }); assert.notOk(JobDetail.metaTable, 'Meta table not present'); - await JobDetail.visit({ id: jobWithMeta.id, namespace: server.db.namespaces[1].name }); + await JobDetail.visit({ + id: jobWithMeta.id, + namespace: server.db.namespaces[1].name, + }); assert.ok(JobDetail.metaTable, 'Meta table is present'); }); @@ -349,7 +386,10 @@ module('Acceptance | job detail (with namespaces)', function (hooks) { }); window.localStorage.nomadTokenSecret = managementToken.secretId; - await JobDetail.visit({ id: job.id, namespace: server.db.namespaces[1].name }); + await JobDetail.visit({ + id: job.id, + namespace: server.db.namespaces[1].name, + }); const groupsWithRecommendations = job.taskGroups.filter((group) => group.tasks.models.any((task) => task.recommendations.models.length) @@ -380,7 +420,10 @@ module('Acceptance | job detail (with namespaces)', function (hooks) { await toggle.click(); - assert.equal(recommendation.card.slug.groupName, firstRecommendationGroup.name); + assert.equal( + recommendation.card.slug.groupName, + firstRecommendationGroup.name + ); await recommendation.card.acceptButton.click(); @@ -394,13 +437,17 @@ module('Acceptance | job detail (with namespaces)', function (hooks) { test('resource recommendations are not fetched when the feature doesn’t exist', async function (assert) { window.localStorage.nomadTokenSecret = managementToken.secretId; - await JobDetail.visit({ id: job.id, namespace: server.db.namespaces[1].name }); + await JobDetail.visit({ + id: job.id, + namespace: server.db.namespaces[1].name, + }); assert.equal(JobDetail.recommendations.length, 0); assert.equal( - server.pretender.handledRequests.filter((request) => request.url.includes('recommendations')) - .length, + server.pretender.handledRequests.filter((request) => + request.url.includes('recommendations') + ).length, 0 ); }); @@ -410,8 +457,12 @@ module('Acceptance | job detail (with namespaces)', function (hooks) { const READ_ONLY_NAMESPACE = 'read-only-namespace'; const clientToken = server.create('token'); - const namespace = server.create('namespace', { id: SCALE_AND_WRITE_NAMESPACE }); - const secondNamespace = server.create('namespace', { id: READ_ONLY_NAMESPACE }); + const namespace = server.create('namespace', { + id: SCALE_AND_WRITE_NAMESPACE, + }); + const secondNamespace = server.create('namespace', { + id: READ_ONLY_NAMESPACE, + }); job = server.create('job', { groupCount: 0, diff --git a/ui/tests/acceptance/job-dispatch-test.js b/ui/tests/acceptance/job-dispatch-test.js index 7c6fb1393..ffae782a4 100644 --- a/ui/tests/acceptance/job-dispatch-test.js +++ b/ui/tests/acceptance/job-dispatch-test.js @@ -99,7 +99,8 @@ function moduleForJobDispatch(title, jobFactory) { await JobDispatch.visit({ id: job.id, namespace: namespace.name }); assert.equal( JobDispatch.metaFields.length, - job.parameterizedJob.MetaOptional.length + job.parameterizedJob.MetaRequired.length + job.parameterizedJob.MetaOptional.length + + job.parameterizedJob.MetaRequired.length ); }); @@ -108,12 +109,17 @@ function moduleForJobDispatch(title, jobFactory) { JobDispatch.metaFields.forEach((f) => { const hasIndicator = f.label.includes(REQUIRED_INDICATOR); - const isRequired = job.parameterizedJob.MetaRequired.includes(f.field.id); + const isRequired = job.parameterizedJob.MetaRequired.includes( + f.field.id + ); if (isRequired) { assert.ok(hasIndicator, `${f.label} contains required indicator.`); } else { - assert.notOk(hasIndicator, `${f.label} doesn't contain required indicator.`); + assert.notOk( + hasIndicator, + `${f.label} doesn't contain required indicator.` + ); } }); }); @@ -128,7 +134,10 @@ function moduleForJobDispatch(title, jobFactory) { }, }); - await JobDispatch.visit({ id: jobWithoutMeta.id, namespace: namespace.name }); + await JobDispatch.visit({ + id: jobWithoutMeta.id, + namespace: namespace.name, + }); assert.ok(JobDispatch.dispatchButton.isPresent); }); @@ -158,7 +167,10 @@ function moduleForJobDispatch(title, jobFactory) { }, }); - await JobDispatch.visit({ id: jobPayloadRequired.id, namespace: namespace.name }); + await JobDispatch.visit({ + id: jobPayloadRequired.id, + namespace: namespace.name, + }); let payloadTitle = JobDispatch.payload.title; assert.ok( @@ -166,7 +178,10 @@ function moduleForJobDispatch(title, jobFactory) { `${payloadTitle} contains required indicator.` ); - await JobDispatch.visit({ id: jobPayloadOptional.id, namespace: namespace.name }); + await JobDispatch.visit({ + id: jobPayloadOptional.id, + namespace: namespace.name, + }); payloadTitle = JobDispatch.payload.title; assert.notOk( @@ -177,7 +192,9 @@ function moduleForJobDispatch(title, jobFactory) { test('dispatch a job', async function (assert) { function countDispatchChildren() { - return server.db.jobs.where((j) => j.id.startsWith(`${job.id}/`)).length; + return server.db.jobs.where((j) => + j.id.startsWith(`${job.id}/`) + ).length; } await JobDispatch.visit({ id: job.id, namespace: namespace.name }); @@ -191,7 +208,9 @@ function moduleForJobDispatch(title, jobFactory) { const childrenCountAfter = countDispatchChildren(); assert.equal(childrenCountAfter, childrenCountBefore + 1); - assert.ok(currentURL().startsWith(`/jobs/${encodeURIComponent(`${job.id}/`)}`)); + assert.ok( + currentURL().startsWith(`/jobs/${encodeURIComponent(`${job.id}/`)}`) + ); assert.ok(JobDetail.jobName); }); diff --git a/ui/tests/acceptance/job-evaluations-test.js b/ui/tests/acceptance/job-evaluations-test.js index 71fb862f8..b0bb474e9 100644 --- a/ui/tests/acceptance/job-evaluations-test.js +++ b/ui/tests/acceptance/job-evaluations-test.js @@ -13,7 +13,10 @@ module('Acceptance | job evaluations', function (hooks) { setupMirage(hooks); hooks.beforeEach(async function () { - job = server.create('job', { noFailedPlacements: true, createAllocations: false }); + job = server.create('job', { + noFailedPlacements: true, + createAllocations: false, + }); evaluations = server.db.evaluations.where({ jobId: job.id }); await Evaluations.visit({ id: job.id }); @@ -24,7 +27,11 @@ module('Acceptance | job evaluations', function (hooks) { }); test('lists all evaluations for the job', async function (assert) { - assert.equal(Evaluations.evaluations.length, evaluations.length, 'All evaluations are listed'); + assert.equal( + Evaluations.evaluations.length, + evaluations.length, + 'All evaluations are listed' + ); const sortedEvaluations = evaluations.sortBy('modifyIndex').reverse(); @@ -65,8 +72,16 @@ module('Acceptance | job evaluations', function (hooks) { '/v1/job/not-a-real-job', 'A request to the nonexistent job is made' ); - assert.equal(currentURL(), '/jobs/not-a-real-job/evaluations', 'The URL persists'); + assert.equal( + currentURL(), + '/jobs/not-a-real-job/evaluations', + 'The URL persists' + ); assert.ok(Evaluations.error.isPresent, 'Error message is shown'); - assert.equal(Evaluations.error.title, 'Not Found', 'Error message is for 404'); + assert.equal( + Evaluations.error.title, + 'Not Found', + 'Error message is for 404' + ); }); }); diff --git a/ui/tests/acceptance/job-versions-test.js b/ui/tests/acceptance/job-versions-test.js index 8c6119027..a1eb313ad 100644 --- a/ui/tests/acceptance/job-versions-test.js +++ b/ui/tests/acceptance/job-versions-test.js @@ -19,7 +19,10 @@ module('Acceptance | job versions', function (hooks) { server.create('namespace'); namespace = server.create('namespace'); - job = server.create('job', { namespaceId: namespace.id, createAllocations: false }); + job = server.create('job', { + namespaceId: namespace.id, + createAllocations: false, + }); versions = server.db.jobVersions.where({ jobId: job.id }); const managementToken = server.create('token'); @@ -33,7 +36,11 @@ module('Acceptance | job versions', function (hooks) { }); test('/jobs/:id/versions should list all job versions', async function (assert) { - assert.ok(Versions.versions.length, versions.length, 'Each version gets a row in the timeline'); + assert.ok( + Versions.versions.length, + versions.length, + 'Each version gets a row in the timeline' + ); assert.equal(document.title, `Job ${job.name} versions - Nomad`); }); @@ -44,7 +51,10 @@ module('Acceptance | job versions', function (hooks) { ); const versionRow = Versions.versions.objectAt(0); - assert.ok(versionRow.text.includes(`Version #${version.version}`), 'Version #'); + assert.ok( + versionRow.text.includes(`Version #${version.version}`), + 'Version #' + ); assert.equal(versionRow.stability, version.stable.toString(), 'Stability'); assert.equal(versionRow.submitTime, formattedSubmitTime, 'Submit time'); }); @@ -67,11 +77,14 @@ module('Acceptance | job versions', function (hooks) { await versionRowToRevertTo.revertToButton.idle(); await versionRowToRevertTo.revertToButton.confirm(); - const revertRequest = this.server.pretender.handledRequests.find((request) => - request.url.includes('revert') + const revertRequest = this.server.pretender.handledRequests.find( + (request) => request.url.includes('revert') ); - assert.equal(revertRequest.url, `/v1/job/${job.id}/revert?namespace=${namespace.id}`); + assert.equal( + revertRequest.url, + `/v1/job/${job.id}/revert?namespace=${namespace.id}` + ); assert.deepEqual(JSON.parse(revertRequest.requestBody), { JobID: job.id, @@ -141,7 +154,11 @@ module('Acceptance | job versions', function (hooks) { '/v1/job/not-a-real-job', 'A request to the nonexistent job is made' ); - assert.equal(currentURL(), '/jobs/not-a-real-job/versions', 'The URL persists'); + assert.equal( + currentURL(), + '/jobs/not-a-real-job/versions', + 'The URL persists' + ); assert.ok(Versions.error.isPresent, 'Error message is shown'); assert.equal(Versions.error.title, 'Not Found', 'Error message is for 404'); }); diff --git a/ui/tests/acceptance/jobs-list-test.js b/ui/tests/acceptance/jobs-list-test.js index 235c9a021..c3e3222ed 100644 --- a/ui/tests/acceptance/jobs-list-test.js +++ b/ui/tests/acceptance/jobs-list-test.js @@ -118,7 +118,11 @@ module('Acceptance | jobs list', function (hooks) { await JobsList.visit(); assert.ok(JobsList.isEmpty, 'There is an empty message'); - assert.equal(JobsList.emptyState.headline, 'No Jobs', 'The message is appropriate'); + assert.equal( + JobsList.emptyState.headline, + 'No Jobs', + 'The message is appropriate' + ); }); test('when there are jobs, but no matches for a search result, there is an empty message', async function (assert) { @@ -129,16 +133,26 @@ module('Acceptance | jobs list', function (hooks) { await JobsList.search.fillIn('dog'); assert.ok(JobsList.isEmpty, 'The empty message is shown'); - assert.equal(JobsList.emptyState.headline, 'No Matches', 'The message is appropriate'); + assert.equal( + JobsList.emptyState.headline, + 'No Matches', + 'The message is appropriate' + ); }); test('searching resets the current page', async function (assert) { - server.createList('job', JobsList.pageSize + 1, { createAllocations: false }); + server.createList('job', JobsList.pageSize + 1, { + createAllocations: false, + }); await JobsList.visit(); await JobsList.nextPage(); - assert.equal(currentURL(), '/jobs?page=2', 'Page query param captures page=2'); + assert.equal( + currentURL(), + '/jobs?page=2', + 'Page query param captures page=2' + ); await JobsList.search.fillIn('foobar'); @@ -158,8 +172,12 @@ module('Acceptance | jobs list', function (hooks) { test('when the namespace query param is set, only matching jobs are shown', async function (assert) { server.createList('namespace', 2); - const job1 = server.create('job', { namespaceId: server.db.namespaces[0].id }); - const job2 = server.create('job', { namespaceId: server.db.namespaces[1].id }); + const job1 = server.create('job', { + namespaceId: server.db.namespaces[0].id, + }); + const job2 = server.create('job', { + namespaceId: server.db.namespaces[1].id, + }); await JobsList.visit(); assert.equal(JobsList.jobs.length, 2, 'All jobs by default'); @@ -167,13 +185,25 @@ module('Acceptance | jobs list', function (hooks) { const firstNamespace = server.db.namespaces[0]; await JobsList.visit({ namespace: firstNamespace.id }); assert.equal(JobsList.jobs.length, 1, 'One job in the default namespace'); - assert.equal(JobsList.jobs.objectAt(0).name, job1.name, 'The correct job is shown'); + assert.equal( + JobsList.jobs.objectAt(0).name, + job1.name, + 'The correct job is shown' + ); const secondNamespace = server.db.namespaces[1]; await JobsList.visit({ namespace: secondNamespace.id }); - assert.equal(JobsList.jobs.length, 1, `One job in the ${secondNamespace.name} namespace`); - assert.equal(JobsList.jobs.objectAt(0).name, job2.name, 'The correct job is shown'); + assert.equal( + JobsList.jobs.length, + 1, + `One job in the ${secondNamespace.name} namespace` + ); + assert.equal( + JobsList.jobs.objectAt(0).name, + job2.name, + 'The correct job is shown' + ); }); test('when accessing jobs is forbidden, show a message with a link to the tokens page', async function (assert) { @@ -187,13 +217,20 @@ module('Acceptance | jobs list', function (hooks) { }); function typeForJob(job) { - return job.periodic ? 'periodic' : job.parameterized ? 'parameterized' : job.type; + return job.periodic + ? 'periodic' + : job.parameterized + ? 'parameterized' + : job.type; } test('the jobs list page has appropriate faceted search options', async function (assert) { await JobsList.visit(); - assert.ok(JobsList.facets.namespace.isHidden, 'Namespace facet not found (no namespaces)'); + assert.ok( + JobsList.facets.namespace.isHidden, + 'Namespace facet not found (no namespaces)' + ); assert.ok(JobsList.facets.type.isPresent, 'Type facet found'); assert.ok(JobsList.facets.status.isPresent, 'Status facet found'); assert.ok(JobsList.facets.datacenter.isPresent, 'Datacenter facet found'); @@ -220,7 +257,14 @@ module('Acceptance | jobs list', function (hooks) { testFacet('Type', { facet: JobsList.facets.type, paramName: 'type', - expectedOptions: ['Batch', 'Parameterized', 'Periodic', 'Service', 'System', 'System Batch'], + expectedOptions: [ + 'Batch', + 'Parameterized', + 'Periodic', + 'Service', + 'System', + 'System Batch', + ], async beforeEach() { server.createList('job', 2, { createAllocations: false, type: 'batch' }); server.createList('job', 2, { @@ -235,7 +279,10 @@ module('Acceptance | jobs list', function (hooks) { parameterized: true, childrenCount: 0, }); - server.createList('job', 2, { createAllocations: false, type: 'service' }); + server.createList('job', 2, { + createAllocations: false, + type: 'service', + }); await JobsList.visit(); }, filter(job, selection) { @@ -261,7 +308,11 @@ module('Acceptance | jobs list', function (hooks) { createAllocations: false, childrenCount: 0, }); - server.createList('job', 2, { status: 'dead', createAllocations: false, childrenCount: 0 }); + server.createList('job', 2, { + status: 'dead', + createAllocations: false, + childrenCount: 0, + }); await JobsList.visit(); }, filter: (job, selection) => selection.includes(job.status), @@ -297,10 +348,15 @@ module('Acceptance | jobs list', function (hooks) { createAllocations: false, childrenCount: 0, }); - server.create('job', { datacenters: ['pdx'], createAllocations: false, childrenCount: 0 }); + server.create('job', { + datacenters: ['pdx'], + createAllocations: false, + childrenCount: 0, + }); await JobsList.visit(); }, - filter: (job, selection) => job.datacenters.find((dc) => selection.includes(dc)), + filter: (job, selection) => + job.datacenters.find((dc) => selection.includes(dc)), }); testFacet('Prefix', { @@ -319,22 +375,35 @@ module('Acceptance | jobs list', function (hooks) { 'nmd_two', 'noprefix', ].forEach((name) => { - server.create('job', { name, createAllocations: false, childrenCount: 0 }); + server.create('job', { + name, + createAllocations: false, + childrenCount: 0, + }); }); await JobsList.visit(); }, - filter: (job, selection) => selection.find((prefix) => job.name.startsWith(prefix)), + filter: (job, selection) => + selection.find((prefix) => job.name.startsWith(prefix)), }); test('when the facet selections result in no matches, the empty state states why', async function (assert) { - server.createList('job', 2, { status: 'pending', createAllocations: false, childrenCount: 0 }); + server.createList('job', 2, { + status: 'pending', + createAllocations: false, + childrenCount: 0, + }); await JobsList.visit(); await JobsList.facets.status.toggle(); await JobsList.facets.status.options.objectAt(1).toggle(); assert.ok(JobsList.isEmpty, 'There is an empty message'); - assert.equal(JobsList.emptyState.headline, 'No Matches', 'The message is appropriate'); + assert.equal( + JobsList.emptyState.headline, + 'No Matches', + 'The message is appropriate' + ); }); test('the jobs list is immediately filtered based on query params', async function (assert) { @@ -343,7 +412,11 @@ module('Acceptance | jobs list', function (hooks) { await JobsList.visit({ type: JSON.stringify(['batch']) }); - assert.equal(JobsList.jobs.length, 1, 'Only one job shown due to query param'); + assert.equal( + JobsList.jobs.length, + 1, + 'Only one job shown due to query param' + ); }); test('the active namespace is carried over to the storage pages', async function (assert) { @@ -400,7 +473,10 @@ module('Acceptance | jobs list', function (hooks) { pageObject: JobsList, pageObjectList: JobsList.jobs, async setup() { - server.createList('job', JobsList.pageSize, { shallow: true, createAllocations: false }); + server.createList('job', JobsList.pageSize, { + shallow: true, + createAllocations: false, + }); await JobsList.visit(); }, }); @@ -468,7 +544,10 @@ module('Acceptance | jobs list', function (hooks) { }); } - function testFacet(label, { facet, paramName, beforeEach, filter, expectedOptions }) { + function testFacet( + label, + { facet, paramName, beforeEach, filter, expectedOptions } + ) { test(`the ${label} facet has the correct options`, async function (assert) { await facetOptions(assert, beforeEach, facet, expectedOptions); }); @@ -545,7 +624,11 @@ module('Acceptance | jobs list', function (hooks) { test('the run job button works when filters are set', async function (assert) { ['pre-one', 'pre-two', 'pre-three'].forEach((name) => { - server.create('job', { name, createAllocations: false, childrenCount: 0 }); + server.create('job', { + name, + createAllocations: false, + childrenCount: 0, + }); }); await JobsList.visit(); diff --git a/ui/tests/acceptance/optimize-test.js b/ui/tests/acceptance/optimize-test.js index 19eb6241d..676f42989 100644 --- a/ui/tests/acceptance/optimize-test.js +++ b/ui/tests/acceptance/optimize-test.js @@ -18,7 +18,8 @@ function getLatestRecommendationSubmitTimeForJob(job) { .mapBy('tasks.models') .reduce((tasks, taskModels) => tasks.concat(taskModels), []); const recommendations = tasks.reduce( - (recommendations, task) => recommendations.concat(task.recommendations.models), + (recommendations, task) => + recommendations.concat(task.recommendations.models), [] ); return Math.max(...recommendations.mapBy('submitTime')); @@ -96,7 +97,10 @@ module('Acceptance | optimize', function (hooks) { `${this.job1.name} / ${currentTaskGroup.name}` ); - assert.equal(Optimize.recommendationSummaries[0].namespace, this.job1.namespace); + assert.equal( + Optimize.recommendationSummaries[0].namespace, + this.job1.namespace + ); assert.equal( Optimize.recommendationSummaries[1].slug, @@ -104,15 +108,20 @@ module('Acceptance | optimize', function (hooks) { ); const currentRecommendations = currentTaskGroup.tasks.models.reduce( - (recommendations, task) => recommendations.concat(task.recommendations.models), + (recommendations, task) => + recommendations.concat(task.recommendations.models), [] ); - const latestSubmitTime = Math.max(...currentRecommendations.mapBy('submitTime')); + const latestSubmitTime = Math.max( + ...currentRecommendations.mapBy('submitTime') + ); Optimize.recommendationSummaries[0].as((summary) => { assert.equal( summary.date, - moment(new Date(latestSubmitTime / 1000000)).format('MMM DD HH:mm:ss ZZ') + moment(new Date(latestSubmitTime / 1000000)).format( + 'MMM DD HH:mm:ss ZZ' + ) ); const currentTaskGroupAllocations = server.schema.allocations.where({ @@ -154,23 +163,39 @@ module('Acceptance | optimize', function (hooks) { assert.equal( replaceMinus(summary.cpu), - cpuDiff ? `${cpuSign}${formatHertz(cpuDiff, 'MHz')} ${cpuSign}${cpuDiffPercent}%` : '' + cpuDiff + ? `${cpuSign}${formatHertz( + cpuDiff, + 'MHz' + )} ${cpuSign}${cpuDiffPercent}%` + : '' ); assert.equal( replaceMinus(summary.memory), - memDiff ? `${memSign}${formattedMemDiff(memDiff)} ${memSign}${memDiffPercent}%` : '' + memDiff + ? `${memSign}${formattedMemDiff( + memDiff + )} ${memSign}${memDiffPercent}%` + : '' ); assert.equal( replaceMinus(summary.aggregateCpu), cpuDiff - ? `${cpuSign}${formatHertz(cpuDiff * currentTaskGroupAllocations.length, 'MHz')}` + ? `${cpuSign}${formatHertz( + cpuDiff * currentTaskGroupAllocations.length, + 'MHz' + )}` : '' ); assert.equal( replaceMinus(summary.aggregateMemory), - memDiff ? `${memSign}${formattedMemDiff(memDiff * currentTaskGroupAllocations.length)}` : '' + memDiff + ? `${memSign}${formattedMemDiff( + memDiff * currentTaskGroupAllocations.length + )}` + : '' ); }); @@ -215,12 +240,16 @@ module('Acceptance | optimize', function (hooks) { .models.filter(taskIdFilter) .mapBy('id'); - const appliedIds = toggledAnything ? cpuRecommendationIds : memoryRecommendationIds; + const appliedIds = toggledAnything + ? cpuRecommendationIds + : memoryRecommendationIds; const dismissedIds = toggledAnything ? memoryRecommendationIds : []; await Optimize.card.acceptButton.click(); - const request = server.pretender.handledRequests.filterBy('method', 'POST').pop(); + const request = server.pretender.handledRequests + .filterBy('method', 'POST') + .pop(); const { Apply, Dismiss } = JSON.parse(request.requestBody); assert.equal(request.url, '/v1/recommendations/apply'); @@ -263,24 +292,34 @@ module('Acceptance | optimize', function (hooks) { await Optimize.visit(); const lastSummary = - Optimize.recommendationSummaries[Optimize.recommendationSummaries.length - 1]; + Optimize.recommendationSummaries[ + Optimize.recommendationSummaries.length - 1 + ]; const collapsedSlug = lastSummary.slug.replace(' / ', '/'); // preferable to use page object’s visitable but it encodes the slash - await visit(`/optimize/${collapsedSlug}?namespace=${lastSummary.namespace}`); + await visit( + `/optimize/${collapsedSlug}?namespace=${lastSummary.namespace}` + ); assert.equal( `${Optimize.card.slug.jobName} / ${Optimize.card.slug.groupName}`, lastSummary.slug ); assert.ok(lastSummary.isActive); - assert.equal(currentURL(), `/optimize/${collapsedSlug}?namespace=${lastSummary.namespace}`); + assert.equal( + currentURL(), + `/optimize/${collapsedSlug}?namespace=${lastSummary.namespace}` + ); }); test('when a summary is not found, an error message is shown, but the URL persists', async function (assert) { await visit('/optimize/nonexistent/summary?namespace=anamespace'); - assert.equal(currentURL(), '/optimize/nonexistent/summary?namespace=anamespace'); + assert.equal( + currentURL(), + '/optimize/nonexistent/summary?namespace=anamespace' + ); assert.ok(Optimize.applicationError.isPresent); assert.equal(Optimize.applicationError.title, 'Not Found'); }); @@ -310,7 +349,9 @@ module('Acceptance | optimize', function (hooks) { await Optimize.card.dismissButton.click(); - const request = server.pretender.handledRequests.filterBy('method', 'POST').pop(); + const request = server.pretender.handledRequests + .filterBy('method', 'POST') + .pop(); const { Apply, Dismiss } = JSON.parse(request.requestBody); assert.equal(request.url, '/v1/recommendations/apply'); @@ -493,7 +534,8 @@ module('Acceptance | optimize search and facets', function (hooks) { server.schema.recommendations.all().models.forEach((recommendation) => { const parentJob = recommendation.task.taskGroup.job; - const submitTimeForJob = jobNameToRecommendationSubmitTime[parentJob.name]; + const submitTimeForJob = + jobNameToRecommendationSubmitTime[parentJob.name]; recommendation.submitTime = submitTimeForJob; recommendation.save(); }); @@ -527,8 +569,14 @@ module('Acceptance | optimize search and facets', function (hooks) { expectedOptions: ['All (*)', 'default', 'namespace-1'], optionToSelect: 'namespace-1', async beforeEach() { - server.createList('job', 2, { namespaceId: 'default', createRecommendations: true }); - server.createList('job', 2, { namespaceId: 'namespace-1', createRecommendations: true }); + server.createList('job', 2, { + namespaceId: 'default', + createRecommendations: true, + }); + server.createList('job', 2, { + namespaceId: 'namespace-1', + createRecommendations: true, + }); await Optimize.visit(); }, filter(taskGroup, selection) { @@ -629,7 +677,11 @@ module('Acceptance | optimize search and facets', function (hooks) { groupTaskCount: 2, childrenCount: 0, }); - server.create('job', { datacenters: ['pdx'], createRecommendations: true, childrenCount: 0 }); + server.create('job', { + datacenters: ['pdx'], + createRecommendations: true, + childrenCount: 0, + }); await Optimize.visit(); }, filter: (taskGroup, selection) => @@ -701,7 +753,9 @@ module('Acceptance | optimize search and facets', function (hooks) { const selection = option.key; await option.select(); - const sortedRecommendations = server.db.recommendations.sortBy('submitTime').reverse(); + const sortedRecommendations = server.db.recommendations + .sortBy('submitTime') + .reverse(); const recommendationTaskGroups = server.schema.tasks .find(sortedRecommendations.mapBy('taskId').uniq()) @@ -730,7 +784,10 @@ module('Acceptance | optimize search and facets', function (hooks) { }); } - function testFacet(label, { facet, paramName, beforeEach, filter, expectedOptions }) { + function testFacet( + label, + { facet, paramName, beforeEach, filter, expectedOptions } + ) { test(`the ${label} facet has the correct options`, async function (assert) { await facetOptions.call(this, assert, beforeEach, facet, expectedOptions); }); @@ -746,7 +803,9 @@ module('Acceptance | optimize search and facets', function (hooks) { const selection = [option.key]; - const sortedRecommendations = server.db.recommendations.sortBy('submitTime').reverse(); + const sortedRecommendations = server.db.recommendations + .sortBy('submitTime') + .reverse(); const recommendationTaskGroups = server.schema.tasks .find(sortedRecommendations.mapBy('taskId').uniq()) @@ -773,7 +832,9 @@ module('Acceptance | optimize search and facets', function (hooks) { await option2.toggle(); selection.push(option2.key); - const sortedRecommendations = server.db.recommendations.sortBy('submitTime').reverse(); + const sortedRecommendations = server.db.recommendations + .sortBy('submitTime') + .reverse(); const recommendationTaskGroups = server.schema.tasks .find(sortedRecommendations.mapBy('taskId').uniq()) @@ -800,7 +861,9 @@ module('Acceptance | optimize search and facets', function (hooks) { await option2.toggle(); selection.push(option2.key); - assert.ok(currentURL().includes(encodeURIComponent(JSON.stringify(selection)))); + assert.ok( + currentURL().includes(encodeURIComponent(JSON.stringify(selection))) + ); }); } }); diff --git a/ui/tests/acceptance/plugin-allocations-test.js b/ui/tests/acceptance/plugin-allocations-test.js index 9df943961..e841c80e8 100644 --- a/ui/tests/acceptance/plugin-allocations-test.js +++ b/ui/tests/acceptance/plugin-allocations-test.js @@ -71,7 +71,8 @@ module('Acceptance | plugin allocations', function (hooks) { await PluginAllocations.visit({ id: plugin.id }); }, - filter: (allocation, selection) => selection.includes(allocation.healthy.toString()), + filter: (allocation, selection) => + selection.includes(allocation.healthy.toString()), }); testFacet('Type', { @@ -89,7 +90,8 @@ module('Acceptance | plugin allocations', function (hooks) { }, filter: (allocation, selection) => { if (selection.length === 0 || selection.length === 2) return true; - if (selection[0] === 'controller') return plugin.controllers.models.includes(allocation); + if (selection[0] === 'controller') + return plugin.controllers.models.includes(allocation); return plugin.nodes.models.includes(allocation); }, }); @@ -105,7 +107,10 @@ module('Acceptance | plugin allocations', function (hooks) { await option.toggle(); const selection = [option.key]; - const allAllocations = [...plugin.controllers.models, ...plugin.nodes.models]; + const allAllocations = [ + ...plugin.controllers.models, + ...plugin.nodes.models, + ]; const expectedAllocations = allAllocations .filter((allocation) => filter(allocation, selection)) .sortBy('updateTime'); @@ -128,7 +133,10 @@ module('Acceptance | plugin allocations', function (hooks) { await option2.toggle(); selection.push(option2.key); - const allAllocations = [...plugin.controllers.models, ...plugin.nodes.models]; + const allAllocations = [ + ...plugin.controllers.models, + ...plugin.nodes.models, + ]; const expectedAllocations = allAllocations .filter((allocation) => filter(allocation, selection)) .sortBy('updateTime'); @@ -151,9 +159,14 @@ module('Acceptance | plugin allocations', function (hooks) { await option2.toggle(); selection.push(option2.key); - const queryString = `${paramName}=${window.encodeURIComponent(JSON.stringify(selection))}`; + const queryString = `${paramName}=${window.encodeURIComponent( + JSON.stringify(selection) + )}`; - assert.equal(currentURL(), `/csi/plugins/${plugin.id}/allocations?${queryString}`); + assert.equal( + currentURL(), + `/csi/plugins/${plugin.id}/allocations?${queryString}` + ); }); } }); diff --git a/ui/tests/acceptance/plugin-detail-test.js b/ui/tests/acceptance/plugin-detail-test.js index 95e891b7e..0ccc77325 100644 --- a/ui/tests/acceptance/plugin-detail-test.js +++ b/ui/tests/acceptance/plugin-detail-test.js @@ -44,7 +44,9 @@ module('Acceptance | plugin detail', function (hooks) { assert.ok( PluginDetail.controllerHealth.includes( - `${Math.round((plugin.controllersHealthy / plugin.controllersExpected) * 100)}%` + `${Math.round( + (plugin.controllersHealthy / plugin.controllersExpected) * 100 + )}%` ) ); assert.ok( @@ -57,19 +59,29 @@ module('Acceptance | plugin detail', function (hooks) { `${Math.round((plugin.nodesHealthy / plugin.nodesExpected) * 100)}%` ) ); - assert.ok(PluginDetail.nodeHealth.includes(`${plugin.nodesHealthy}/${plugin.nodesExpected}`)); + assert.ok( + PluginDetail.nodeHealth.includes( + `${plugin.nodesHealthy}/${plugin.nodesExpected}` + ) + ); assert.ok(PluginDetail.provider.includes(plugin.provider)); }); test('/csi/plugins/:id should list all the controller plugin allocations for the plugin', async function (assert) { await PluginDetail.visit({ id: plugin.id }); - assert.equal(PluginDetail.controllerAllocations.length, plugin.controllers.length); + assert.equal( + PluginDetail.controllerAllocations.length, + plugin.controllers.length + ); plugin.controllers.models .sortBy('updateTime') .reverse() .forEach((allocation, idx) => { - assert.equal(PluginDetail.controllerAllocations.objectAt(idx).id, allocation.allocID); + assert.equal( + PluginDetail.controllerAllocations.objectAt(idx).id, + allocation.allocID + ); }); }); @@ -81,12 +93,17 @@ module('Acceptance | plugin detail', function (hooks) { .sortBy('updateTime') .reverse() .forEach((allocation, idx) => { - assert.equal(PluginDetail.nodeAllocations.objectAt(idx).id, allocation.allocID); + assert.equal( + PluginDetail.nodeAllocations.objectAt(idx).id, + allocation.allocID + ); }); }); test('each allocation should have high-level details for the allocation', async function (assert) { - const controller = plugin.controllers.models.sortBy('updateTime').reverse()[0]; + const controller = plugin.controllers.models + .sortBy('updateTime') + .reverse()[0]; const allocation = server.db.allocations.find(controller.allocID); const allocStats = server.db.clientAllocationStats.find(allocation.id); const taskGroup = server.db.taskGroups.findBy({ @@ -96,12 +113,19 @@ module('Acceptance | plugin detail', function (hooks) { const tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id)); const cpuUsed = tasks.reduce((sum, task) => sum + task.resources.CPU, 0); - const memoryUsed = tasks.reduce((sum, task) => sum + task.resources.MemoryMB, 0); + const memoryUsed = tasks.reduce( + (sum, task) => sum + task.resources.MemoryMB, + 0 + ); await PluginDetail.visit({ id: plugin.id }); PluginDetail.controllerAllocations.objectAt(0).as((allocationRow) => { - assert.equal(allocationRow.shortId, allocation.id.split('-')[0], 'Allocation short ID'); + assert.equal( + allocationRow.shortId, + allocation.id.split('-')[0], + 'Allocation short ID' + ); assert.equal( allocationRow.createTime, moment(allocation.createTime / 1000000).format('MMM D') @@ -110,8 +134,14 @@ module('Acceptance | plugin detail', function (hooks) { allocationRow.createTooltip, moment(allocation.createTime / 1000000).format('MMM DD HH:mm:ss ZZ') ); - assert.equal(allocationRow.modifyTime, moment(allocation.modifyTime / 1000000).fromNow()); - assert.equal(allocationRow.health, controller.healthy ? 'Healthy' : 'Unhealthy'); + assert.equal( + allocationRow.modifyTime, + moment(allocation.modifyTime / 1000000).fromNow() + ); + assert.equal( + allocationRow.health, + controller.healthy ? 'Healthy' : 'Unhealthy' + ); assert.equal( allocationRow.client, server.db.nodes.find(allocation.nodeId).id.split('-')[0], @@ -122,7 +152,11 @@ module('Acceptance | plugin detail', function (hooks) { server.db.nodes.find(allocation.nodeId).name.substr(0, 15), 'Node Name' ); - assert.equal(allocationRow.job, server.db.jobs.find(allocation.jobId).name, 'Job name'); + assert.equal( + allocationRow.job, + server.db.jobs.find(allocation.jobId).name, + 'Job name' + ); assert.ok(allocationRow.taskGroup, 'Task group name'); assert.ok(allocationRow.jobVersion, 'Job Version'); assert.equal( @@ -130,7 +164,9 @@ module('Acceptance | plugin detail', function (hooks) { Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks) / cpuUsed, 'CPU %' ); - const roundedTicks = Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks); + const roundedTicks = Math.floor( + allocStats.resourceUsage.CpuStats.TotalTicks + ); assert.equal( allocationRow.cpuTooltip, `${formatHertz(roundedTicks, 'MHz')} / ${formatHertz(cpuUsed, 'MHz')}`, @@ -143,17 +179,18 @@ module('Acceptance | plugin detail', function (hooks) { ); assert.equal( allocationRow.memTooltip, - `${formatBytes(allocStats.resourceUsage.MemoryStats.RSS)} / ${formatBytes( - memoryUsed, - 'MiB' - )}`, + `${formatBytes( + allocStats.resourceUsage.MemoryStats.RSS + )} / ${formatBytes(memoryUsed, 'MiB')}`, 'Detailed memory information is in a tooltip' ); }); }); test('each allocation should link to the allocation detail page', async function (assert) { - const controller = plugin.controllers.models.sortBy('updateTime').reverse()[0]; + const controller = plugin.controllers.models + .sortBy('updateTime') + .reverse()[0]; await PluginDetail.visit({ id: plugin.id }); await PluginDetail.controllerAllocations.objectAt(0).visit(); @@ -173,14 +210,22 @@ module('Acceptance | plugin detail', function (hooks) { await PluginDetail.visit({ id: emptyPlugin.id }); assert.ok(PluginDetail.controllerTableIsEmpty); - assert.equal(PluginDetail.controllerEmptyState.headline, 'No Controller Plugin Allocations'); + assert.equal( + PluginDetail.controllerEmptyState.headline, + 'No Controller Plugin Allocations' + ); assert.ok(PluginDetail.nodeTableIsEmpty); - assert.equal(PluginDetail.nodeEmptyState.headline, 'No Node Plugin Allocations'); + assert.equal( + PluginDetail.nodeEmptyState.headline, + 'No Node Plugin Allocations' + ); }); test('when the plugin is node-only, the controller information is omitted', async function (assert) { - const nodeOnlyPlugin = server.create('csi-plugin', { controllerRequired: false }); + const nodeOnlyPlugin = server.create('csi-plugin', { + controllerRequired: false, + }); await PluginDetail.visit({ id: nodeOnlyPlugin.id }); @@ -208,7 +253,9 @@ module('Acceptance | plugin detail', function (hooks) { await PluginDetail.visit({ id: plugin.id }); assert.ok( - PluginDetail.goToControllerAllocationsText.includes(plugin.controllers.models.length) + PluginDetail.goToControllerAllocationsText.includes( + plugin.controllers.models.length + ) ); await PluginDetail.goToControllerAllocations(); assert.equal( @@ -217,8 +264,13 @@ module('Acceptance | plugin detail', function (hooks) { ); await PluginDetail.visit({ id: plugin.id }); - assert.ok(PluginDetail.goToNodeAllocationsText.includes(plugin.nodes.models.length)); + assert.ok( + PluginDetail.goToNodeAllocationsText.includes(plugin.nodes.models.length) + ); await PluginDetail.goToNodeAllocations(); - assert.equal(currentURL(), `/csi/plugins/${plugin.id}/allocations?type=${serialize(['node'])}`); + assert.equal( + currentURL(), + `/csi/plugins/${plugin.id}/allocations?type=${serialize(['node'])}` + ); }); }); diff --git a/ui/tests/acceptance/plugins-list-test.js b/ui/tests/acceptance/plugins-list-test.js index 6cb4b952c..4abbf3bc5 100644 --- a/ui/tests/acceptance/plugins-list-test.js +++ b/ui/tests/acceptance/plugins-list-test.js @@ -41,12 +41,16 @@ module('Acceptance | plugins list', function (hooks) { }); test('each plugin row should contain information about the plugin', async function (assert) { - const plugin = server.create('csi-plugin', { shallow: true, controllerRequired: true }); + const plugin = server.create('csi-plugin', { + shallow: true, + controllerRequired: true, + }); await PluginsList.visit(); const pluginRow = PluginsList.plugins.objectAt(0); - const controllerHealthStr = plugin.controllersHealthy > 0 ? 'Healthy' : 'Unhealthy'; + const controllerHealthStr = + plugin.controllersHealthy > 0 ? 'Healthy' : 'Unhealthy'; const nodeHealthStr = plugin.nodesHealthy > 0 ? 'Healthy' : 'Unhealthy'; assert.equal(pluginRow.id, plugin.id); @@ -62,7 +66,10 @@ module('Acceptance | plugins list', function (hooks) { }); test('node only plugins explain that there is no controller health for this plugin type', async function (assert) { - const plugin = server.create('csi-plugin', { shallow: true, controllerRequired: false }); + const plugin = server.create('csi-plugin', { + shallow: true, + controllerRequired: false, + }); await PluginsList.visit(); @@ -112,7 +119,9 @@ module('Acceptance | plugins list', function (hooks) { }); test('search resets the current page', async function (assert) { - server.createList('csi-plugin', PluginsList.pageSize + 1, { shallow: true }); + server.createList('csi-plugin', PluginsList.pageSize + 1, { + shallow: true, + }); await PluginsList.visit(); await PluginsList.nextPage(); diff --git a/ui/tests/acceptance/proxy-test.js b/ui/tests/acceptance/proxy-test.js index fbe8d9a19..7d7a4643e 100644 --- a/ui/tests/acceptance/proxy-test.js +++ b/ui/tests/acceptance/proxy-test.js @@ -36,7 +36,11 @@ module('Acceptance | reverse proxy', function (hooks) { const { secretId } = managementToken; await Jobs.visit(); - assert.ok(window.localStorage.nomadTokenSecret == null, 'No token secret set'); + assert.equal( + window.localStorage.nomadTokenSecret, + null, + 'No token secret set' + ); // Make sure that server received the header assert.ok( diff --git a/ui/tests/acceptance/regions-test.js b/ui/tests/acceptance/regions-test.js index 691a58616..3700ab0ae 100644 --- a/ui/tests/acceptance/regions-test.js +++ b/ui/tests/acceptance/regions-test.js @@ -16,7 +16,10 @@ module('Acceptance | regions (only one)', function (hooks) { hooks.beforeEach(function () { server.create('agent'); server.create('node'); - server.createList('job', 2, { createAllocations: false, noDeployments: true }); + server.createList('job', 2, { + createAllocations: false, + noDeployments: true, + }); }); test('it passes an accessibility audit', async function (assert) { @@ -75,7 +78,10 @@ module('Acceptance | regions (many)', function (hooks) { hooks.beforeEach(function () { server.create('agent'); server.create('node'); - server.createList('job', 2, { createAllocations: false, noDeployments: true }); + server.createList('job', 2, { + createAllocations: false, + noDeployments: true, + }); server.create('allocation'); server.create('region', { id: 'global' }); server.create('region', { id: 'region-2' }); @@ -84,7 +90,10 @@ module('Acceptance | regions (many)', function (hooks) { test('the region switcher is rendered in the nav bar and the region is in the page title', async function (assert) { await JobsList.visit(); - assert.ok(Layout.navbar.regionSwitcher.isPresent, 'Region switcher is shown'); + assert.ok( + Layout.navbar.regionSwitcher.isPresent, + 'Region switcher is shown' + ); assert.equal(document.title, 'Jobs - global - Nomad'); }); @@ -92,7 +101,11 @@ module('Acceptance | regions (many)', function (hooks) { await JobsList.visit(); assert.equal(currentURL(), '/jobs', 'No region query param'); - assert.equal(window.localStorage.nomadActiveRegion, 'global', 'Region in localStorage'); + assert.equal( + window.localStorage.nomadActiveRegion, + 'global', + 'Region in localStorage' + ); }); test('switching regions sets localStorage and the region query param', async function (assert) { @@ -106,7 +119,11 @@ module('Acceptance | regions (many)', function (hooks) { currentURL().includes(`region=${newRegion}`), 'New region is the region query param value' ); - assert.equal(window.localStorage.nomadActiveRegion, newRegion, 'New region in localStorage'); + assert.equal( + window.localStorage.nomadActiveRegion, + newRegion, + 'New region in localStorage' + ); }); test('switching regions to the default region, unsets the region query param', async function (assert) { @@ -117,7 +134,10 @@ module('Acceptance | regions (many)', function (hooks) { await selectChoose('[data-test-region-switcher-parent]', defaultRegion); - assert.notOk(currentURL().includes('region='), 'No region query param for the default region'); + assert.notOk( + currentURL().includes('region='), + 'No region query param for the default region' + ); assert.equal( window.localStorage.nomadActiveRegion, defaultRegion, diff --git a/ui/tests/acceptance/search-test.js b/ui/tests/acceptance/search-test.js index fd533f6b4..a9f66efbc 100644 --- a/ui/tests/acceptance/search-test.js +++ b/ui/tests/acceptance/search-test.js @@ -29,7 +29,12 @@ module('Acceptance | search', function (hooks) { groupsCount: 1, groupTaskCount: 1, }); - server.create('job', { id: 'abc', namespaceId: 'default', groupsCount: 1, groupTaskCount: 1 }); + server.create('job', { + id: 'abc', + namespaceId: 'default', + groupsCount: 1, + groupTaskCount: 1, + }); const firstAllocation = server.schema.allocations.all().models[0]; const firstTaskGroup = server.schema.taskGroups.all().models[0]; @@ -100,7 +105,10 @@ module('Acceptance | search', function (hooks) { await Layout.navbar.search.groups[4].options[0].click(); assert.equal(currentURL(), '/csi/plugins/xyz-plugin'); - const fuzzySearchQueries = server.pretender.handledRequests.filterBy('url', '/v1/search/fuzzy'); + const fuzzySearchQueries = server.pretender.handledRequests.filterBy( + 'url', + '/v1/search/fuzzy' + ); const featureDetectionQueries = fuzzySearchQueries.filter((request) => request.requestBody.includes('feature-detection-query') @@ -128,7 +136,8 @@ module('Acceptance | search', function (hooks) { assert.ok(Layout.navbar.search.noOptionsShown); assert.equal( - server.pretender.handledRequests.filterBy('url', '/v1/search/fuzzy').length, + server.pretender.handledRequests.filterBy('url', '/v1/search/fuzzy') + .length, 1, 'expect the feature detection query' ); diff --git a/ui/tests/acceptance/server-detail-test.js b/ui/tests/acceptance/server-detail-test.js index 0dbe34511..058dd2b7d 100644 --- a/ui/tests/acceptance/server-detail-test.js +++ b/ui/tests/acceptance/server-detail-test.js @@ -35,7 +35,9 @@ module('Acceptance | server detail', function (hooks) { test('the details ribbon displays basic information about the server', async function (assert) { assert.ok(ServerDetail.serverStatus.includes(agent.member.Status)); assert.ok( - ServerDetail.address.includes(formatHost(agent.member.Address, agent.member.Tags.port)) + ServerDetail.address.includes( + formatHost(agent.member.Address, agent.member.Tags.port) + ) ); assert.ok(ServerDetail.datacenter.includes(agent.member.Tags.dc)); }); @@ -61,7 +63,15 @@ module('Acceptance | server detail', function (hooks) { test('when the server is not found, an error message is shown, but the URL persists', async function (assert) { await ServerDetail.visit({ name: 'not-a-real-server' }); - assert.equal(currentURL(), '/servers/not-a-real-server', 'The URL persists'); - assert.equal(ServerDetail.error.title, 'Not Found', 'Error message is for 404'); + assert.equal( + currentURL(), + '/servers/not-a-real-server', + 'The URL persists' + ); + assert.equal( + ServerDetail.error.title, + 'Not Found', + 'Error message is for 404' + ); }); }); diff --git a/ui/tests/acceptance/servers-list-test.js b/ui/tests/acceptance/servers-list-test.js index 0da89c271..163b292d1 100644 --- a/ui/tests/acceptance/servers-list-test.js +++ b/ui/tests/acceptance/servers-list-test.js @@ -40,10 +40,18 @@ module('Acceptance | servers list', function (hooks) { await ServersList.visit(); - assert.equal(ServersList.servers.length, ServersList.pageSize, 'List is stopped at pageSize'); + assert.equal( + ServersList.servers.length, + ServersList.pageSize, + 'List is stopped at pageSize' + ); ServersList.servers.forEach((server, index) => { - assert.equal(server.name, sortedAgents[index].name, 'Servers are ordered'); + assert.equal( + server.name, + sortedAgents[index].name, + 'Servers are ordered' + ); }); assert.equal(document.title, 'Servers - Nomad'); @@ -73,7 +81,11 @@ module('Acceptance | servers list', function (hooks) { await ServersList.visit(); await ServersList.servers.objectAt(0).clickRow(); - assert.equal(currentURL(), `/servers/${agent.name}`, 'Now at the server detail page'); + assert.equal( + currentURL(), + `/servers/${agent.name}`, + 'Now at the server detail page' + ); }); test('when accessing servers is forbidden, show a message with a link to the tokens page', async function (assert) { diff --git a/ui/tests/acceptance/task-detail-test.js b/ui/tests/acceptance/task-detail-test.js index 6f87d0fe4..625b09821 100644 --- a/ui/tests/acceptance/task-detail-test.js +++ b/ui/tests/acceptance/task-detail-test.js @@ -10,38 +10,47 @@ import moment from 'moment'; let allocation; let task; -module('Acceptance | task detail', function (hooks) { +module('Acceptance | task detail', function(hooks) { setupApplicationTest(hooks); setupMirage(hooks); - hooks.beforeEach(async function () { + hooks.beforeEach(async function() { server.create('agent'); server.create('node'); server.create('job', { createAllocations: false }); - allocation = server.create('allocation', 'withTaskWithPorts', { clientStatus: 'running' }); + allocation = server.create('allocation', 'withTaskWithPorts', { + clientStatus: 'running' + }); task = server.db.taskStates.where({ allocationId: allocation.id })[0]; await Task.visit({ id: allocation.id, name: task.name }); }); - test('it passes an accessibility audit', async function (assert) { + test('it passes an accessibility audit', async function(assert) { await a11yAudit(assert); }); - test('/allocation/:id/:task_name should name the task and list high-level task information', async function (assert) { + test('/allocation/:id/:task_name should name the task and list high-level task information', async function(assert) { assert.ok(Task.title.text.includes(task.name), 'Task name'); assert.ok(Task.state.includes(task.state), 'Task state'); assert.ok( - Task.startedAt.includes(moment(task.startedAt).format("MMM DD, 'YY HH:mm:ss ZZ")), + Task.startedAt.includes( + moment(task.startedAt).format("MMM DD, 'YY HH:mm:ss ZZ") + ), 'Task started at' ); const lifecycle = server.db.tasks.where({ name: task.name })[0].Lifecycle; let lifecycleName = 'main'; - if (lifecycle && (lifecycle.Hook === 'prestart' || lifecycle.Hook === 'poststart')) { - lifecycleName = `${lifecycle.Hook}-${lifecycle.Sidecar ? 'sidecar' : 'ephemeral'}`; + if ( + lifecycle && + (lifecycle.Hook === 'prestart' || lifecycle.Hook === 'poststart') + ) { + lifecycleName = `${lifecycle.Hook}-${ + lifecycle.Sidecar ? 'sidecar' : 'ephemeral' + }`; } if (lifecycle && lifecycle.Hook === 'poststop') { lifecycleName = 'poststop'; @@ -52,12 +61,16 @@ module('Acceptance | task detail', function (hooks) { assert.equal(document.title, `Task ${task.name} - Nomad`); }); - test('breadcrumbs match jobs / job / task group / allocation / task', async function (assert) { + test('breadcrumbs match jobs / job / task group / allocation / task', async function(assert) { const { jobId, taskGroup } = allocation; const job = server.db.jobs.find(jobId); const shortId = allocation.id.split('-')[0]; - assert.equal(Layout.breadcrumbFor('jobs.index').text, 'Jobs', 'Jobs is the first breadcrumb'); + assert.equal( + Layout.breadcrumbFor('jobs.index').text, + 'Jobs', + 'Jobs is the first breadcrumb' + ); await waitFor('[data-test-job-breadcrumb]'); assert.equal( @@ -86,7 +99,11 @@ module('Acceptance | task detail', function (hooks) { await Task.visit({ id: allocation.id, name: task.name }); await Layout.breadcrumbFor('jobs.job.index').visit(); - assert.equal(currentURL(), `/jobs/${job.id}`, 'Job breadcrumb links correctly'); + assert.equal( + currentURL(), + `/jobs/${job.id}`, + 'Job breadcrumb links correctly' + ); await Task.visit({ id: allocation.id, name: task.name }); await Layout.breadcrumbFor('jobs.job.task-group').visit(); @@ -105,57 +122,85 @@ module('Acceptance | task detail', function (hooks) { ); }); - test('/allocation/:id/:task_name should include resource utilization graphs', async function (assert) { - assert.equal(Task.resourceCharts.length, 2, 'Two resource utilization graphs'); - assert.equal(Task.resourceCharts.objectAt(0).name, 'CPU', 'First chart is CPU'); - assert.equal(Task.resourceCharts.objectAt(1).name, 'Memory', 'Second chart is Memory'); + test('/allocation/:id/:task_name should include resource utilization graphs', async function(assert) { + assert.equal( + Task.resourceCharts.length, + 2, + 'Two resource utilization graphs' + ); + assert.equal( + Task.resourceCharts.objectAt(0).name, + 'CPU', + 'First chart is CPU' + ); + assert.equal( + Task.resourceCharts.objectAt(1).name, + 'Memory', + 'Second chart is Memory' + ); }); - test('the events table lists all recent events', async function (assert) { + test('the events table lists all recent events', async function(assert) { const events = server.db.taskEvents.where({ taskStateId: task.id }); - assert.equal(Task.events.length, events.length, `Lists ${events.length} events`); + assert.equal( + Task.events.length, + events.length, + `Lists ${events.length} events` + ); }); - test('when a task has volumes, the volumes table is shown', async function (assert) { + test('when a task has volumes, the volumes table is shown', async function(assert) { const taskGroup = server.schema.taskGroups.where({ jobId: allocation.jobId, - name: allocation.taskGroup, + name: allocation.taskGroup }).models[0]; - const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name); + const jobTask = taskGroup.tasks.models.find(m => m.name === task.name); assert.ok(Task.hasVolumes); assert.equal(Task.volumes.length, jobTask.volumeMounts.length); }); - test('when a task does not have volumes, the volumes table is not shown', async function (assert) { - const job = server.create('job', { createAllocations: false, noHostVolumes: true }); - allocation = server.create('allocation', { jobId: job.id, clientStatus: 'running' }); + test('when a task does not have volumes, the volumes table is not shown', async function(assert) { + const job = server.create('job', { + createAllocations: false, + noHostVolumes: true + }); + allocation = server.create('allocation', { + jobId: job.id, + clientStatus: 'running' + }); task = server.db.taskStates.where({ allocationId: allocation.id })[0]; await Task.visit({ id: allocation.id, name: task.name }); assert.notOk(Task.hasVolumes); }); - test('each volume in the volumes table shows information about the volume', async function (assert) { + test('each volume in the volumes table shows information about the volume', async function(assert) { const taskGroup = server.schema.taskGroups.where({ jobId: allocation.jobId, - name: allocation.taskGroup, + name: allocation.taskGroup }).models[0]; - const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name); + const jobTask = taskGroup.tasks.models.find(m => m.name === task.name); const volume = jobTask.volumeMounts[0]; - Task.volumes[0].as((volumeRow) => { + Task.volumes[0].as(volumeRow => { assert.equal(volumeRow.name, volume.Volume); assert.equal(volumeRow.destination, volume.Destination); - assert.equal(volumeRow.permissions, volume.ReadOnly ? 'Read' : 'Read/Write'); - assert.equal(volumeRow.clientSource, taskGroup.volumes[volume.Volume].Source); + assert.equal( + volumeRow.permissions, + volume.ReadOnly ? 'Read' : 'Read/Write' + ); + assert.equal( + volumeRow.clientSource, + taskGroup.volumes[volume.Volume].Source + ); }); }); - test('each recent event should list the time, type, and description of the event', async function (assert) { + test('each recent event should list the time, type, and description of the event', async function(assert) { const event = server.db.taskEvents.where({ taskStateId: task.id })[0]; const recentEvent = Task.events.objectAt(Task.events.length - 1); @@ -168,12 +213,12 @@ module('Acceptance | task detail', function (hooks) { assert.equal(recentEvent.message, event.displayMessage, 'Event message'); }); - test('when the allocation is not found, the application errors', async function (assert) { + test('when the allocation is not found, the application errors', async function(assert) { await Task.visit({ id: 'not-a-real-allocation', name: task.name }); assert.equal( server.pretender.handledRequests - .filter((request) => !request.url.includes('policy')) + .filter(request => !request.url.includes('policy')) .findBy('status', 404).url, '/v1/allocation/not-a-real-allocation', 'A request to the nonexistent allocation is made' @@ -187,7 +232,7 @@ module('Acceptance | task detail', function (hooks) { assert.equal(Task.error.title, 'Not Found', 'Error message is for 404'); }); - test('when the allocation is found but the task is not, the application errors', async function (assert) { + test('when the allocation is found but the task is not, the application errors', async function(assert) { await Task.visit({ id: allocation.id, name: 'not-a-real-task-name' }); assert.ok( @@ -206,7 +251,7 @@ module('Acceptance | task detail', function (hooks) { assert.equal(Task.error.title, 'Not Found', 'Error message is for 404'); }); - test('task can be restarted', async function (assert) { + test('task can be restarted', async function(assert) { await Task.restart.idle(); await Task.restart.confirm(); @@ -224,14 +269,21 @@ module('Acceptance | task detail', function (hooks) { ); }); - test('when task restart fails (403), an ACL permissions error message is shown', async function (assert) { - server.pretender.put('/v1/client/allocation/:id/restart', () => [403, {}, '']); + test('when task restart fails (403), an ACL permissions error message is shown', async function(assert) { + server.pretender.put('/v1/client/allocation/:id/restart', () => [ + 403, + {}, + '' + ]); await Task.restart.idle(); await Task.restart.confirm(); assert.ok(Task.inlineError.isShown, 'Inline error is shown'); - assert.ok(Task.inlineError.title.includes('Could Not Restart Task'), 'Title is descriptive'); + assert.ok( + Task.inlineError.title.includes('Could Not Restart Task'), + 'Title is descriptive' + ); assert.ok( /ACL token.+?allocation lifecycle/.test(Task.inlineError.message), 'Message mentions ACLs and the appropriate permission' @@ -242,9 +294,13 @@ module('Acceptance | task detail', function (hooks) { assert.notOk(Task.inlineError.isShown, 'Inline error is no longer shown'); }); - test('when task restart fails (500), the error message from the API is piped through to the alert', async function (assert) { + test('when task restart fails (500), the error message from the API is piped through to the alert', async function(assert) { const message = 'A plaintext error message'; - server.pretender.put('/v1/client/allocation/:id/restart', () => [500, {}, message]); + server.pretender.put('/v1/client/allocation/:id/restart', () => [ + 500, + {}, + message + ]); await Task.restart.idle(); await Task.restart.confirm(); @@ -258,48 +314,59 @@ module('Acceptance | task detail', function (hooks) { assert.notOk(Task.inlineError.isShown); }); - test('exec button is present', async function (assert) { + test('exec button is present', async function(assert) { assert.ok(Task.execButton.isPresent); }); }); -module('Acceptance | task detail (no addresses)', function (hooks) { +module('Acceptance | task detail (no addresses)', function(hooks) { setupApplicationTest(hooks); setupMirage(hooks); - hooks.beforeEach(async function () { + hooks.beforeEach(async function() { server.create('agent'); server.create('node'); server.create('job'); - allocation = server.create('allocation', 'withoutTaskWithPorts', { clientStatus: 'running' }); + allocation = server.create('allocation', 'withoutTaskWithPorts', { + clientStatus: 'running' + }); task = server.db.taskStates.where({ allocationId: allocation.id })[0]; await Task.visit({ id: allocation.id, name: task.name }); }); }); -module('Acceptance | task detail (different namespace)', function (hooks) { +module('Acceptance | task detail (different namespace)', function(hooks) { setupApplicationTest(hooks); setupMirage(hooks); - hooks.beforeEach(async function () { + hooks.beforeEach(async function() { server.create('agent'); server.create('node'); server.create('namespace'); server.create('namespace', { id: 'other-namespace' }); - server.create('job', { createAllocations: false, namespaceId: 'other-namespace' }); - allocation = server.create('allocation', 'withTaskWithPorts', { clientStatus: 'running' }); + server.create('job', { + createAllocations: false, + namespaceId: 'other-namespace' + }); + allocation = server.create('allocation', 'withTaskWithPorts', { + clientStatus: 'running' + }); task = server.db.taskStates.where({ allocationId: allocation.id })[0]; await Task.visit({ id: allocation.id, name: task.name }); }); - test('breadcrumbs match jobs / job / task group / allocation / task', async function (assert) { + test('breadcrumbs match jobs / job / task group / allocation / task', async function(assert) { const { jobId, taskGroup } = allocation; const job = server.db.jobs.find(jobId); await Layout.breadcrumbFor('jobs.index').visit(); - assert.equal(currentURL(), '/jobs?namespace=*', 'Jobs breadcrumb links correctly'); + assert.equal( + currentURL(), + '/jobs?namespace=*', + 'Jobs breadcrumb links correctly' + ); await Task.visit({ id: allocation.id, name: task.name }); await Layout.breadcrumbFor('jobs.job.index').visit(); @@ -327,41 +394,52 @@ module('Acceptance | task detail (different namespace)', function (hooks) { }); }); -module('Acceptance | task detail (not running)', function (hooks) { +module('Acceptance | task detail (not running)', function(hooks) { setupApplicationTest(hooks); setupMirage(hooks); - hooks.beforeEach(async function () { + hooks.beforeEach(async function() { server.create('agent'); server.create('node'); server.create('namespace'); server.create('namespace', { id: 'other-namespace' }); - server.create('job', { createAllocations: false, namespaceId: 'other-namespace' }); - allocation = server.create('allocation', 'withTaskWithPorts', { clientStatus: 'complete' }); + server.create('job', { + createAllocations: false, + namespaceId: 'other-namespace' + }); + allocation = server.create('allocation', 'withTaskWithPorts', { + clientStatus: 'complete' + }); task = server.db.taskStates.where({ allocationId: allocation.id })[0]; await Task.visit({ id: allocation.id, name: task.name }); }); - test('when the allocation for a task is not running, the resource utilization graphs are replaced by an empty message', async function (assert) { + test('when the allocation for a task is not running, the resource utilization graphs are replaced by an empty message', async function(assert) { assert.equal(Task.resourceCharts.length, 0, 'No resource charts'); - assert.equal(Task.resourceEmptyMessage, "Task isn't running", 'Empty message is appropriate'); + assert.equal( + Task.resourceEmptyMessage, + "Task isn't running", + 'Empty message is appropriate' + ); }); - test('exec button is absent', async function (assert) { + test('exec button is absent', async function(assert) { assert.notOk(Task.execButton.isPresent); }); }); -module('Acceptance | proxy task detail', function (hooks) { +module('Acceptance | proxy task detail', function(hooks) { setupApplicationTest(hooks); setupMirage(hooks); - hooks.beforeEach(async function () { + hooks.beforeEach(async function() { server.create('agent'); server.create('node'); server.create('job', { createAllocations: false }); - allocation = server.create('allocation', 'withTaskWithPorts', { clientStatus: 'running' }); + allocation = server.create('allocation', 'withTaskWithPorts', { + clientStatus: 'running' + }); const taskState = allocation.taskStates.models[0]; const task = server.schema.tasks.findBy({ name: taskState.name }); @@ -371,7 +449,7 @@ module('Acceptance | proxy task detail', function (hooks) { await Task.visit({ id: allocation.id, name: taskState.name }); }); - test('a proxy tag is shown', async function (assert) { + test('a proxy tag is shown', async function(assert) { assert.ok(Task.title.proxyTag.isPresent); }); }); diff --git a/ui/tests/acceptance/task-fs-test.js b/ui/tests/acceptance/task-fs-test.js index ce59f0563..4af319090 100644 --- a/ui/tests/acceptance/task-fs-test.js +++ b/ui/tests/acceptance/task-fs-test.js @@ -19,8 +19,12 @@ module('Acceptance | task fs', function (hooks) { server.create('node', 'forceIPv4'); const job = server.create('job', { createAllocations: false }); - allocation = server.create('allocation', { jobId: job.id, clientStatus: 'running' }); - task = server.schema.taskStates.where({ allocationId: allocation.id }).models[0]; + allocation = server.create('allocation', { + jobId: job.id, + clientStatus: 'running', + }); + task = server.schema.taskStates.where({ allocationId: allocation.id }) + .models[0]; task.name = 'task-name'; task.save(); @@ -30,7 +34,10 @@ module('Acceptance | task fs', function (hooks) { // Reset files files = []; - taskDirectory = server.create('allocFile', { isDir: true, name: task.name }); + taskDirectory = server.create('allocFile', { + isDir: true, + name: task.name, + }); files.push(taskDirectory); // Nested files @@ -57,10 +64,24 @@ module('Acceptance | task fs', function (hooks) { ); files.push( - server.create('allocFile', { isDir: true, name: 'empty-directory', parent: taskDirectory }) + server.create('allocFile', { + isDir: true, + name: 'empty-directory', + parent: taskDirectory, + }) + ); + files.push( + server.create('allocFile', 'file', { + fileType: 'txt', + parent: taskDirectory, + }) + ); + files.push( + server.create('allocFile', 'file', { + fileType: 'txt', + parent: taskDirectory, + }) ); - files.push(server.create('allocFile', 'file', { fileType: 'txt', parent: taskDirectory })); - files.push(server.create('allocFile', 'file', { fileType: 'txt', parent: taskDirectory })); this.files = files; this.directory = directory; @@ -68,8 +89,12 @@ module('Acceptance | task fs', function (hooks) { }); browseFilesystem({ - visitSegments: ({ allocation, task }) => ({ id: allocation.id, name: task.name }), - getExpectedPathBase: ({ allocation, task }) => `/allocations/${allocation.id}/${task.name}/fs/`, + visitSegments: ({ allocation, task }) => ({ + id: allocation.id, + name: task.name, + }), + getExpectedPathBase: ({ allocation, task }) => + `/allocations/${allocation.id}/${task.name}/fs/`, getTitleComponent: ({ task }) => `Task ${task.name} filesystem`, getBreadcrumbComponent: ({ task }) => task.name, getFilesystemRoot: ({ task }) => task.name, diff --git a/ui/tests/acceptance/task-group-detail-test.js b/ui/tests/acceptance/task-group-detail-test.js index 8d4ea096e..5ab558b9e 100644 --- a/ui/tests/acceptance/task-group-detail-test.js +++ b/ui/tests/acceptance/task-group-detail-test.js @@ -7,7 +7,7 @@ import { formatBytes, formatHertz, formatScheduledBytes, - formatScheduledHertz, + formatScheduledHertz } from 'nomad-ui/utils/units'; import TaskGroup from 'nomad-ui/tests/pages/jobs/job/task-group'; import Layout from 'nomad-ui/tests/pages/layout'; @@ -22,30 +22,30 @@ let managementToken; const sum = (total, n) => total + n; -module('Acceptance | task group detail', function (hooks) { +module('Acceptance | task group detail', function(hooks) { setupApplicationTest(hooks); setupMirage(hooks); - hooks.beforeEach(async function () { + hooks.beforeEach(async function() { server.create('agent'); server.create('node', 'forceIPv4'); job = server.create('job', { groupsCount: 2, - createAllocations: false, + createAllocations: false }); const taskGroups = server.db.taskGroups.where({ jobId: job.id }); taskGroup = taskGroups[0]; - tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id)); + tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id)); server.create('node', 'forceIPv4'); allocations = server.createList('allocation', 2, { jobId: job.id, taskGroup: taskGroup.name, - clientStatus: 'running', + clientStatus: 'running' }); // Allocations associated to a different task group on the job to @@ -53,20 +53,20 @@ module('Acceptance | task group detail', function (hooks) { server.createList('allocation', 3, { jobId: job.id, taskGroup: taskGroups[1].name, - clientStatus: 'running', + clientStatus: 'running' }); // Set a static name to make the search test deterministic - server.db.allocations.forEach((alloc) => { + server.db.allocations.forEach(alloc => { alloc.name = 'aaaaa'; }); // Mark the first alloc as rescheduled allocations[0].update({ - nextAllocation: allocations[1].id, + nextAllocation: allocations[1].id }); allocations[1].update({ - previousAllocation: allocations[0].id, + previousAllocation: allocations[0].id }); managementToken = server.create('token'); @@ -74,16 +74,16 @@ module('Acceptance | task group detail', function (hooks) { window.localStorage.clear(); }); - test('it passes an accessibility audit', async function (assert) { + test('it passes an accessibility audit', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); await a11yAudit(assert); }); - test('/jobs/:id/:task-group should list high-level metrics for the allocation', async function (assert) { + test('/jobs/:id/:task-group should list high-level metrics for the allocation', async function(assert) { const totalCPU = tasks.mapBy('resources.CPU').reduce(sum, 0); const totalMemory = tasks.mapBy('resources.MemoryMB').reduce(sum, 0); const totalMemoryMax = tasks - .map((t) => t.resources.MemoryMaxMB || t.resources.MemoryMB) + .map(t => t.resources.MemoryMaxMB || t.resources.MemoryMB) .reduce(sum, 0); const totalDisk = taskGroup.ephemeralDisk.SizeMB; @@ -99,12 +99,18 @@ module('Acceptance | task group detail', function (hooks) { let totalMemoryMaxAddendum = ''; if (totalMemoryMax > totalMemory) { - totalMemoryMaxAddendum = ` (${formatScheduledBytes(totalMemoryMax, 'MiB')} Max)`; + totalMemoryMaxAddendum = ` (${formatScheduledBytes( + totalMemoryMax, + 'MiB' + )} Max)`; } assert.equal( TaskGroup.mem, - `Reserved Memory ${formatScheduledBytes(totalMemory, 'MiB')}${totalMemoryMaxAddendum}`, + `Reserved Memory ${formatScheduledBytes( + totalMemory, + 'MiB' + )}${totalMemoryMaxAddendum}`, 'Aggregated Memory reservation for all tasks' ); assert.equal( @@ -113,13 +119,20 @@ module('Acceptance | task group detail', function (hooks) { 'Aggregated Disk reservation for all tasks' ); - assert.equal(document.title, `Task group ${taskGroup.name} - Job ${job.name} - Nomad`); + assert.equal( + document.title, + `Task group ${taskGroup.name} - Job ${job.name} - Nomad` + ); }); - test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', async function (assert) { + test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); - assert.equal(Layout.breadcrumbFor('jobs.index').text, 'Jobs', 'First breadcrumb says jobs'); + assert.equal( + Layout.breadcrumbFor('jobs.index').text, + 'Jobs', + 'First breadcrumb says jobs' + ); assert.equal( Layout.breadcrumbFor('jobs.job.index').text, `Job ${job.name}`, @@ -132,14 +145,14 @@ module('Acceptance | task group detail', function (hooks) { ); }); - test('/jobs/:id/:task-group first breadcrumb should link to jobs', async function (assert) { + test('/jobs/:id/:task-group first breadcrumb should link to jobs', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); await Layout.breadcrumbFor('jobs.index').visit(); assert.equal(currentURL(), '/jobs', 'First breadcrumb links back to jobs'); }); - test('/jobs/:id/:task-group second breadcrumb should link to the job for the task group', async function (assert) { + test('/jobs/:id/:task-group second breadcrumb should link to the job for the task group', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); await Layout.breadcrumbFor('jobs.job.index').visit(); @@ -150,7 +163,7 @@ module('Acceptance | task group detail', function (hooks) { ); }); - test('when the user has a client token that has a namespace with a policy to run and scale a job the autoscaler options should be available', async function (assert) { + test('when the user has a client token that has a namespace with a policy to run and scale a job the autoscaler options should be available', async function(assert) { window.localStorage.clear(); const SCALE_AND_WRITE_NAMESPACE = 'scale-and-write-namespace'; @@ -158,21 +171,23 @@ module('Acceptance | task group detail', function (hooks) { const clientToken = server.create('token'); server.create('namespace', { id: SCALE_AND_WRITE_NAMESPACE }); - const secondNamespace = server.create('namespace', { id: READ_ONLY_NAMESPACE }); + const secondNamespace = server.create('namespace', { + id: READ_ONLY_NAMESPACE + }); job = server.create('job', { groupCount: 0, createAllocations: false, shallow: true, noActiveDeployment: true, - namespaceId: SCALE_AND_WRITE_NAMESPACE, + namespaceId: SCALE_AND_WRITE_NAMESPACE }); const scalingGroup = server.create('task-group', { job, name: 'scaling', count: 1, shallow: true, - withScaling: true, + withScaling: true }); job.update({ taskGroupIds: [scalingGroup.id] }); @@ -181,14 +196,14 @@ module('Acceptance | task group detail', function (hooks) { createAllocations: false, shallow: true, noActiveDeployment: true, - namespaceId: READ_ONLY_NAMESPACE, + namespaceId: READ_ONLY_NAMESPACE }); const scalingGroup2 = server.create('task-group', { job: job2, name: 'scaling', count: 1, shallow: true, - withScaling: true, + withScaling: true }); job2.update({ taskGroupIds: [scalingGroup2.id] }); @@ -199,14 +214,14 @@ module('Acceptance | task group detail', function (hooks) { Namespaces: [ { Name: SCALE_AND_WRITE_NAMESPACE, - Capabilities: ['scale-job', 'submit-job', 'read-job', 'list-jobs'], + Capabilities: ['scale-job', 'submit-job', 'read-job', 'list-jobs'] }, { Name: READ_ONLY_NAMESPACE, - Capabilities: ['list-jobs', 'read-job'], - }, - ], - }, + Capabilities: ['list-jobs', 'read-job'] + } + ] + } }); clientToken.policyIds = [policy.id]; @@ -217,32 +232,39 @@ module('Acceptance | task group detail', function (hooks) { await TaskGroup.visit({ id: job.id, name: scalingGroup.name, - namespace: SCALE_AND_WRITE_NAMESPACE, + namespace: SCALE_AND_WRITE_NAMESPACE }); - assert.equal(currentURL(), `/jobs/${job.id}/scaling?namespace=${SCALE_AND_WRITE_NAMESPACE}`); + assert.equal( + currentURL(), + `/jobs/${job.id}/scaling?namespace=${SCALE_AND_WRITE_NAMESPACE}` + ); assert.notOk(TaskGroup.countStepper.increment.isDisabled); await TaskGroup.visit({ id: job2.id, name: scalingGroup2.name, - namespace: secondNamespace.name, + namespace: secondNamespace.name }); - assert.equal(currentURL(), `/jobs/${job2.id}/scaling?namespace=${READ_ONLY_NAMESPACE}`); + assert.equal( + currentURL(), + `/jobs/${job2.id}/scaling?namespace=${READ_ONLY_NAMESPACE}` + ); assert.ok(TaskGroup.countStepper.increment.isDisabled); }); - test('/jobs/:id/:task-group should list one page of allocations for the task group', async function (assert) { + test('/jobs/:id/:task-group should list one page of allocations for the task group', async function(assert) { server.createList('allocation', TaskGroup.pageSize, { jobId: job.id, taskGroup: taskGroup.name, - clientStatus: 'running', + clientStatus: 'running' }); await TaskGroup.visit({ id: job.id, name: taskGroup.name }); assert.ok( - server.db.allocations.where({ jobId: job.id }).length > TaskGroup.pageSize, + server.db.allocations.where({ jobId: job.id }).length > + TaskGroup.pageSize, 'There are enough allocations to invoke pagination' ); @@ -253,13 +275,17 @@ module('Acceptance | task group detail', function (hooks) { ); }); - test('each allocation should show basic information about the allocation', async function (assert) { + test('each allocation should show basic information about the allocation', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); const allocation = allocations.sortBy('modifyIndex').reverse()[0]; const allocationRow = TaskGroup.allocations.objectAt(0); - assert.equal(allocationRow.shortId, allocation.id.split('-')[0], 'Allocation short id'); + assert.equal( + allocationRow.shortId, + allocation.id.split('-')[0], + 'Allocation short id' + ); assert.equal( allocationRow.createTime, moment(allocation.createTime / 1000000).format('MMM DD HH:mm:ss ZZ'), @@ -270,8 +296,16 @@ module('Acceptance | task group detail', function (hooks) { moment(allocation.modifyTime / 1000000).fromNow(), 'Allocation modify time' ); - assert.equal(allocationRow.status, allocation.clientStatus, 'Client status'); - assert.equal(allocationRow.jobVersion, allocation.jobVersion, 'Job Version'); + assert.equal( + allocationRow.status, + allocation.clientStatus, + 'Client status' + ); + assert.equal( + allocationRow.jobVersion, + allocation.jobVersion, + 'Job Version' + ); assert.equal( allocationRow.client, server.db.nodes.find(allocation.nodeId).id.split('-')[0], @@ -291,9 +325,9 @@ module('Acceptance | task group detail', function (hooks) { name: 'node-read', rulesJSON: { Node: { - Policy: 'read', - }, - }, + Policy: 'read' + } + } }); const clientToken = server.create('token', { type: 'client' }); clientToken.policyIds = [policy.id]; @@ -306,20 +340,27 @@ module('Acceptance | task group detail', function (hooks) { const allocationRow = TaskGroup.allocations.objectAt(0); await allocationRow.visitClient(); - assert.equal(currentURL(), `/clients/${allocation.nodeId}`, 'Node links to node page'); + assert.equal( + currentURL(), + `/clients/${allocation.nodeId}`, + 'Node links to node page' + ); }); - test('each allocation should show stats about the allocation', async function (assert) { + test('each allocation should show stats about the allocation', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); const allocation = allocations.sortBy('name')[0]; const allocationRow = TaskGroup.allocations.objectAt(0); const allocStats = server.db.clientAllocationStats.find(allocation.id); - const tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id)); + const tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id)); const cpuUsed = tasks.reduce((sum, task) => sum + task.resources.CPU, 0); - const memoryUsed = tasks.reduce((sum, task) => sum + task.resources.MemoryMB, 0); + const memoryUsed = tasks.reduce( + (sum, task) => sum + task.resources.MemoryMB, + 0 + ); assert.equal( allocationRow.cpu, @@ -327,7 +368,9 @@ module('Acceptance | task group detail', function (hooks) { 'CPU %' ); - const roundedTicks = Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks); + const roundedTicks = Math.floor( + allocStats.resourceUsage.CpuStats.TotalTicks + ); assert.equal( allocationRow.cpuTooltip, `${formatHertz(roundedTicks, 'MHz')} / ${formatHertz(cpuUsed, 'MHz')}`, @@ -350,7 +393,7 @@ module('Acceptance | task group detail', function (hooks) { ); }); - test('when the allocation search has no matches, there is an empty message', async function (assert) { + test('when the allocation search has no matches, there is an empty message', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); await TaskGroup.search('zzzzzz'); @@ -363,20 +406,23 @@ module('Acceptance | task group detail', function (hooks) { ); }); - test('when the allocation has reschedule events, the allocation row is denoted with an icon', async function (assert) { + test('when the allocation has reschedule events, the allocation row is denoted with an icon', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); const rescheduleRow = TaskGroup.allocationFor(allocations[0].id); const normalRow = TaskGroup.allocationFor(allocations[1].id); - assert.ok(rescheduleRow.rescheduled, 'Reschedule row has a reschedule icon'); + assert.ok( + rescheduleRow.rescheduled, + 'Reschedule row has a reschedule icon' + ); assert.notOk(normalRow.rescheduled, 'Normal row has no reschedule icon'); }); - test('/jobs/:id/:task-group should present task lifecycles', async function (assert) { + test('/jobs/:id/:task-group should present task lifecycles', async function(assert) { job = server.create('job', { groupsCount: 2, - groupTaskCount: 3, + groupTaskCount: 3 }); const taskGroups = server.db.taskGroups.where({ jobId: job.id }); @@ -385,30 +431,36 @@ module('Acceptance | task group detail', function (hooks) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); assert.ok(TaskGroup.lifecycleChart.isPresent); - assert.equal(TaskGroup.lifecycleChart.title, 'Task Lifecycle Configuration'); + assert.equal( + TaskGroup.lifecycleChart.title, + 'Task Lifecycle Configuration' + ); - tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id)); + tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id)); const taskNames = tasks.mapBy('name'); // This is thoroughly tested in allocation detail tests, so this mostly checks what’s different assert.equal(TaskGroup.lifecycleChart.tasks.length, 3); - TaskGroup.lifecycleChart.tasks.forEach((Task) => { + TaskGroup.lifecycleChart.tasks.forEach(Task => { assert.ok(taskNames.includes(Task.name)); assert.notOk(Task.isActive); assert.notOk(Task.isFinished); }); }); - test('when the task group depends on volumes, the volumes table is shown', async function (assert) { + test('when the task group depends on volumes, the volumes table is shown', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); assert.ok(TaskGroup.hasVolumes); - assert.equal(TaskGroup.volumes.length, Object.keys(taskGroup.volumes).length); + assert.equal( + TaskGroup.volumes.length, + Object.keys(taskGroup.volumes).length + ); }); - test('when the task group does not depend on volumes, the volumes table is not shown', async function (assert) { + test('when the task group does not depend on volumes, the volumes table is not shown', async function(assert) { job = server.create('job', { noHostVolumes: true, shallow: true }); taskGroup = server.db.taskGroups.where({ jobId: job.id })[0]; @@ -417,33 +469,36 @@ module('Acceptance | task group detail', function (hooks) { assert.notOk(TaskGroup.hasVolumes); }); - test('each row in the volumes table lists information about the volume', async function (assert) { + test('each row in the volumes table lists information about the volume', async function(assert) { await TaskGroup.visit({ id: job.id, name: taskGroup.name }); - TaskGroup.volumes[0].as((volumeRow) => { + TaskGroup.volumes[0].as(volumeRow => { const volume = taskGroup.volumes[volumeRow.name]; assert.equal(volumeRow.name, volume.Name); assert.equal(volumeRow.type, volume.Type); assert.equal(volumeRow.source, volume.Source); - assert.equal(volumeRow.permissions, volume.ReadOnly ? 'Read' : 'Read/Write'); + assert.equal( + volumeRow.permissions, + volume.ReadOnly ? 'Read' : 'Read/Write' + ); }); }); - test('the count stepper sends the appropriate POST request', async function (assert) { + test('the count stepper sends the appropriate POST request', async function(assert) { window.localStorage.nomadTokenSecret = managementToken.secretId; job = server.create('job', { groupCount: 0, createAllocations: false, shallow: true, - noActiveDeployment: true, + noActiveDeployment: true }); const scalingGroup = server.create('task-group', { job, name: 'scaling', count: 1, shallow: true, - withScaling: true, + withScaling: true }); job.update({ taskGroupIds: [scalingGroup.id] }); @@ -452,28 +507,28 @@ module('Acceptance | task group detail', function (hooks) { await settled(); const scaleRequest = server.pretender.handledRequests.find( - (req) => req.method === 'POST' && req.url.endsWith('/scale') + req => req.method === 'POST' && req.url.endsWith('/scale') ); const requestBody = JSON.parse(scaleRequest.requestBody); assert.equal(requestBody.Target.Group, scalingGroup.name); assert.equal(requestBody.Count, scalingGroup.count + 1); }); - test('the count stepper is disabled when a deployment is running', async function (assert) { + test('the count stepper is disabled when a deployment is running', async function(assert) { window.localStorage.nomadTokenSecret = managementToken.secretId; job = server.create('job', { groupCount: 0, createAllocations: false, shallow: true, - activeDeployment: true, + activeDeployment: true }); const scalingGroup = server.create('task-group', { job, name: 'scaling', count: 1, shallow: true, - withScaling: true, + withScaling: true }); job.update({ taskGroupIds: [scalingGroup.id] }); @@ -484,22 +539,33 @@ module('Acceptance | task group detail', function (hooks) { assert.ok(TaskGroup.countStepper.decrement.isDisabled); }); - test('when the job for the task group is not found, an error message is shown, but the URL persists', async function (assert) { - await TaskGroup.visit({ id: 'not-a-real-job', name: 'not-a-real-task-group' }); + test('when the job for the task group is not found, an error message is shown, but the URL persists', async function(assert) { + await TaskGroup.visit({ + id: 'not-a-real-job', + name: 'not-a-real-task-group' + }); assert.equal( server.pretender.handledRequests - .filter((request) => !request.url.includes('policy')) + .filter(request => !request.url.includes('policy')) .findBy('status', 404).url, '/v1/job/not-a-real-job', 'A request to the nonexistent job is made' ); - assert.equal(currentURL(), '/jobs/not-a-real-job/not-a-real-task-group', 'The URL persists'); + assert.equal( + currentURL(), + '/jobs/not-a-real-job/not-a-real-task-group', + 'The URL persists' + ); assert.ok(TaskGroup.error.isPresent, 'Error message is shown'); - assert.equal(TaskGroup.error.title, 'Not Found', 'Error message is for 404'); + assert.equal( + TaskGroup.error.title, + 'Not Found', + 'Error message is for 404' + ); }); - test('when the task group is not found on the job, an error message is shown, but the URL persists', async function (assert) { + test('when the task group is not found on the job, an error message is shown, but the URL persists', async function(assert) { await TaskGroup.visit({ id: job.id, name: 'not-a-real-task-group' }); assert.ok( @@ -509,9 +575,17 @@ module('Acceptance | task group detail', function (hooks) { .includes(`/v1/job/${job.id}`), 'A request to the job is made and succeeds' ); - assert.equal(currentURL(), `/jobs/${job.id}/not-a-real-task-group`, 'The URL persists'); + assert.equal( + currentURL(), + `/jobs/${job.id}/not-a-real-task-group`, + 'The URL persists' + ); assert.ok(TaskGroup.error.isPresent, 'Error message is shown'); - assert.equal(TaskGroup.error.title, 'Not Found', 'Error message is for 404'); + assert.equal( + TaskGroup.error.title, + 'Not Found', + 'Error message is for 404' + ); }); pageSizeSelect({ @@ -522,16 +596,16 @@ module('Acceptance | task group detail', function (hooks) { server.createList('allocation', TaskGroup.pageSize, { jobId: job.id, taskGroup: taskGroup.name, - clientStatus: 'running', + clientStatus: 'running' }); await TaskGroup.visit({ id: job.id, name: taskGroup.name }); - }, + } }); - test('when a task group has no scaling events, there is no recent scaling events section', async function (assert) { + test('when a task group has no scaling events, there is no recent scaling events section', async function(assert) { const taskGroupScale = job.jobScale.taskGroupScales.models.find( - (m) => m.name === taskGroup.name + m => m.name === taskGroup.name ); taskGroupScale.update({ events: [] }); @@ -540,9 +614,9 @@ module('Acceptance | task group detail', function (hooks) { assert.notOk(TaskGroup.hasScaleEvents); }); - test('the recent scaling events section shows all recent scaling events in reverse chronological order', async function (assert) { + test('the recent scaling events section shows all recent scaling events in reverse chronological order', async function(assert) { const taskGroupScale = job.jobScale.taskGroupScales.models.find( - (m) => m.name === taskGroup.name + m => m.name === taskGroup.name ); taskGroupScale.update({ events: [ @@ -551,8 +625,8 @@ module('Acceptance | task group detail', function (hooks) { server.create('scale-event', { error: true }), server.create('scale-event', { error: true }), server.create('scale-event', { count: 3, error: false }), - server.create('scale-event', { count: 1, error: false }), - ], + server.create('scale-event', { count: 1, error: false }) + ] }); const scaleEvents = taskGroupScale.events.models.sortBy('time').reverse(); await TaskGroup.visit({ id: job.id, name: taskGroup.name }); @@ -562,7 +636,10 @@ module('Acceptance | task group detail', function (hooks) { scaleEvents.forEach((scaleEvent, idx) => { const ScaleEvent = TaskGroup.scaleEvents[idx]; - assert.equal(ScaleEvent.time, moment(scaleEvent.time / 1000000).format('MMM DD HH:mm:ss ZZ')); + assert.equal( + ScaleEvent.time, + moment(scaleEvent.time / 1000000).format('MMM DD HH:mm:ss ZZ') + ); assert.equal(ScaleEvent.message, scaleEvent.message); if (scaleEvent.count != null) { @@ -581,9 +658,9 @@ module('Acceptance | task group detail', function (hooks) { }); }); - test('when a task group has at least two count scaling events and the count scaling events outnumber the non-count scaling events, a timeline is shown in addition to the accordion', async function (assert) { + test('when a task group has at least two count scaling events and the count scaling events outnumber the non-count scaling events, a timeline is shown in addition to the accordion', async function(assert) { const taskGroupScale = job.jobScale.taskGroupScales.models.find( - (m) => m.name === taskGroup.name + m => m.name === taskGroup.name ); taskGroupScale.update({ events: [ @@ -595,8 +672,8 @@ module('Acceptance | task group detail', function (hooks) { server.create('scale-event', { count: 3, error: false }), server.create('scale-event', { count: 2, error: false }), server.create('scale-event', { count: 9, error: false }), - server.create('scale-event', { count: 1, error: false }), - ], + server.create('scale-event', { count: 1, error: false }) + ] }); const scaleEvents = taskGroupScale.events.models.sortBy('time').reverse(); await TaskGroup.visit({ id: job.id, name: taskGroup.name }); @@ -606,7 +683,7 @@ module('Acceptance | task group detail', function (hooks) { assert.equal( TaskGroup.scalingAnnotations.length, - scaleEvents.filter((ev) => ev.count == null).length + scaleEvents.filter(ev => ev.count == null).length ); }); @@ -615,7 +692,7 @@ module('Acceptance | task group detail', function (hooks) { paramName: 'status', expectedOptions: ['Pending', 'Running', 'Complete', 'Failed', 'Lost'], async beforeEach() { - ['pending', 'running', 'complete', 'failed', 'lost'].forEach((s) => { + ['pending', 'running', 'complete', 'failed', 'lost'].forEach(s => { server.createList('allocation', 5, { clientStatus: s }); }); await TaskGroup.visit({ id: job.id, name: taskGroup.name }); @@ -623,7 +700,7 @@ module('Acceptance | task group detail', function (hooks) { filter: (alloc, selection) => alloc.jobId == job.id && alloc.taskGroup == taskGroup.name && - selection.includes(alloc.clientStatus), + selection.includes(alloc.clientStatus) }); testFacet('Client', { @@ -633,19 +710,22 @@ module('Acceptance | task group detail', function (hooks) { return Array.from( new Set( allocs - .filter((alloc) => alloc.jobId == job.id && alloc.taskGroup == taskGroup.name) + .filter( + alloc => + alloc.jobId == job.id && alloc.taskGroup == taskGroup.name + ) .mapBy('nodeId') - .map((id) => id.split('-')[0]) + .map(id => id.split('-')[0]) ) ).sort(); }, async beforeEach() { const nodes = server.createList('node', 3, 'forceIPv4'); - nodes.forEach((node) => + nodes.forEach(node => server.createList('allocation', 5, { nodeId: node.id, jobId: job.id, - taskGroup: taskGroup.name, + taskGroup: taskGroup.name }) ); await TaskGroup.visit({ id: job.id, name: taskGroup.name }); @@ -653,12 +733,15 @@ module('Acceptance | task group detail', function (hooks) { filter: (alloc, selection) => alloc.jobId == job.id && alloc.taskGroup == taskGroup.name && - selection.includes(alloc.nodeId.split('-')[0]), + selection.includes(alloc.nodeId.split('-')[0]) }); }); -function testFacet(label, { facet, paramName, beforeEach, filter, expectedOptions }) { - test(`facet ${label} | the ${label} facet has the correct options`, async function (assert) { +function testFacet( + label, + { facet, paramName, beforeEach, filter, expectedOptions } +) { + test(`facet ${label} | the ${label} facet has the correct options`, async function(assert) { await beforeEach(); await facet.toggle(); @@ -670,13 +753,13 @@ function testFacet(label, { facet, paramName, beforeEach, filter, expectedOption } assert.deepEqual( - facet.options.map((option) => option.label.trim()), + facet.options.map(option => option.label.trim()), expectation, 'Options for facet are as expected' ); }); - test(`facet ${label} | the ${label} facet filters the allocations list by ${label}`, async function (assert) { + test(`facet ${label} | the ${label} facet filters the allocations list by ${label}`, async function(assert) { let option; await beforeEach(); @@ -687,7 +770,7 @@ function testFacet(label, { facet, paramName, beforeEach, filter, expectedOption const selection = [option.key]; const expectedAllocs = server.db.allocations - .filter((alloc) => filter(alloc, selection)) + .filter(alloc => filter(alloc, selection)) .sortBy('modifyIndex') .reverse(); @@ -700,7 +783,7 @@ function testFacet(label, { facet, paramName, beforeEach, filter, expectedOption }); }); - test(`facet ${label} | selecting multiple options in the ${label} facet results in a broader search`, async function (assert) { + test(`facet ${label} | selecting multiple options in the ${label} facet results in a broader search`, async function(assert) { const selection = []; await beforeEach(); @@ -714,7 +797,7 @@ function testFacet(label, { facet, paramName, beforeEach, filter, expectedOption selection.push(option2.key); const expectedAllocs = server.db.allocations - .filter((alloc) => filter(alloc, selection)) + .filter(alloc => filter(alloc, selection)) .sortBy('modifyIndex') .reverse(); @@ -727,7 +810,7 @@ function testFacet(label, { facet, paramName, beforeEach, filter, expectedOption }); }); - test(`facet ${label} | selecting options in the ${label} facet updates the ${paramName} query param`, async function (assert) { + test(`facet ${label} | selecting options in the ${label} facet updates the ${paramName} query param`, async function(assert) { const selection = []; await beforeEach(); diff --git a/ui/tests/acceptance/task-logs-test.js b/ui/tests/acceptance/task-logs-test.js index 236f530b5..51f95355b 100644 --- a/ui/tests/acceptance/task-logs-test.js +++ b/ui/tests/acceptance/task-logs-test.js @@ -18,7 +18,10 @@ module('Acceptance | task logs', function (hooks) { server.create('node', 'forceIPv4'); const job = server.create('job', { createAllocations: false }); - allocation = server.create('allocation', { jobId: job.id, clientStatus: 'running' }); + allocation = server.create('allocation', { + jobId: job.id, + clientStatus: 'running', + }); task = server.db.taskStates.where({ allocationId: allocation.id })[0]; run.later(run, run.cancelTimers, 1000); @@ -30,16 +33,24 @@ module('Acceptance | task logs', function (hooks) { }); test('/allocation/:id/:task_name/logs should have a log component', async function (assert) { - assert.equal(currentURL(), `/allocations/${allocation.id}/${task.name}/logs`, 'No redirect'); + assert.equal( + currentURL(), + `/allocations/${allocation.id}/${task.name}/logs`, + 'No redirect' + ); assert.ok(TaskLogs.hasTaskLog, 'Task log component found'); assert.equal(document.title, `Task ${task.name} logs - Nomad`); }); test('the stdout log immediately starts streaming', async function (assert) { const node = server.db.nodes.find(allocation.nodeId); - const logUrlRegex = new RegExp(`${node.httpAddr}/v1/client/fs/logs/${allocation.id}`); + const logUrlRegex = new RegExp( + `${node.httpAddr}/v1/client/fs/logs/${allocation.id}` + ); assert.ok( - server.pretender.handledRequests.filter((req) => logUrlRegex.test(req.url)).length, + server.pretender.handledRequests.filter((req) => + logUrlRegex.test(req.url) + ).length, 'Log requests were made' ); }); diff --git a/ui/tests/acceptance/token-test.js b/ui/tests/acceptance/token-test.js index c9a47f13b..3e20d441c 100644 --- a/ui/tests/acceptance/token-test.js +++ b/ui/tests/acceptance/token-test.js @@ -38,11 +38,19 @@ module('Acceptance | tokens', function (hooks) { const { secretId } = managementToken; await Tokens.visit(); - assert.ok(window.localStorage.nomadTokenSecret == null, 'No token secret set'); + assert.equal( + window.localStorage.nomadTokenSecret, + null, + 'No token secret set' + ); assert.equal(document.title, 'Tokens - Nomad'); await Tokens.secret(secretId).submit(); - assert.equal(window.localStorage.nomadTokenSecret, secretId, 'Token secret was set'); + assert.equal( + window.localStorage.nomadTokenSecret, + secretId, + 'Token secret was set' + ); }); // TODO: unskip once store.unloadAll reliably waits for in-flight requests to settle @@ -52,7 +60,10 @@ module('Acceptance | tokens', function (hooks) { await JobDetail.visit({ id: job.id }); await ClientDetail.visit({ id: node.id }); - assert.ok(server.pretender.handledRequests.length > 1, 'Requests have been made'); + assert.ok( + server.pretender.handledRequests.length > 1, + 'Requests have been made' + ); server.pretender.handledRequests.forEach((req) => { assert.notOk(getHeader(req, 'x-nomad-token'), `No token for ${req.url}`); @@ -71,7 +82,11 @@ module('Acceptance | tokens', function (hooks) { // Cross-origin requests can't have a token newRequests.forEach((req) => { - assert.equal(getHeader(req, 'x-nomad-token'), secretId, `Token set for ${req.url}`); + assert.equal( + getHeader(req, 'x-nomad-token'), + secretId, + `Token set for ${req.url}` + ); }); }); @@ -87,7 +102,11 @@ module('Acceptance | tokens', function (hooks) { await Tokens.visit(); await Tokens.secret(bogusSecret).submit(); - assert.ok(window.localStorage.nomadTokenSecret == null, 'Token secret is discarded on failure'); + assert.equal( + window.localStorage.nomadTokenSecret, + null, + 'Token secret is discarded on failure' + ); assert.ok(Tokens.errorMessage, 'Token error message is shown'); assert.notOk(Tokens.successMessage, 'Token success message is not shown'); assert.equal(Tokens.policies.length, 0, 'No token policies are shown'); @@ -115,7 +134,10 @@ module('Acceptance | tokens', function (hooks) { assert.ok(Tokens.successMessage, 'Token success message is shown'); assert.notOk(Tokens.errorMessage, 'Token error message is not shown'); - assert.notOk(Tokens.managementMessage, 'Token management message is not shown'); + assert.notOk( + Tokens.managementMessage, + 'Token management message is not shown' + ); assert.equal( Tokens.policies.length, clientToken.policies.length, @@ -125,7 +147,11 @@ module('Acceptance | tokens', function (hooks) { const policyElement = Tokens.policies.objectAt(0); assert.equal(policyElement.name, policy.name, 'Policy Name'); - assert.equal(policyElement.description, policy.description, 'Policy Description'); + assert.equal( + policyElement.description, + policy.description, + 'Policy Description' + ); assert.equal(policyElement.rules, policy.rules, 'Policy Rules'); }); @@ -153,11 +179,18 @@ module('Acceptance | tokens', function (hooks) { await JobDetail.visit({ id: job.id, ott: oneTimeSecret }); - assert.notOk(currentURL().includes(oneTimeSecret), 'OTT is cleared from the URL after loading'); + assert.notOk( + currentURL().includes(oneTimeSecret), + 'OTT is cleared from the URL after loading' + ); await Tokens.visit(); - assert.equal(window.localStorage.nomadTokenSecret, secretId, 'Token secret was set'); + assert.equal( + window.localStorage.nomadTokenSecret, + secretId, + 'Token secret was set' + ); }); test('when the ott exchange fails an error is shown', async function (assert) { @@ -165,7 +198,10 @@ module('Acceptance | tokens', function (hooks) { assert.ok(Layout.error.isPresent); assert.equal(Layout.error.title, 'Token Exchange Error'); - assert.equal(Layout.error.message, 'Failed to exchange the one-time token.'); + assert.equal( + Layout.error.message, + 'Failed to exchange the one-time token.' + ); }); function getHeader({ requestHeaders }, name) { diff --git a/ui/tests/acceptance/topology-test.js b/ui/tests/acceptance/topology-test.js index 26ec9184c..7920f2484 100644 --- a/ui/tests/acceptance/topology-test.js +++ b/ui/tests/acceptance/topology-test.js @@ -49,27 +49,46 @@ module('Acceptance | topology', function (hooks) { const scheduledAllocs = allocs.filter((alloc) => ['pending', 'running'].includes(alloc.clientStatus) ); - assert.equal(Topology.clusterInfoPanel.allocCount, `${scheduledAllocs.length} Allocations`); + assert.equal( + Topology.clusterInfoPanel.allocCount, + `${scheduledAllocs.length} Allocations` + ); - const nodeResources = server.schema.nodes.all().models.mapBy('nodeResources'); - const taskResources = scheduledAllocs.mapBy('taskResources.models').flat().mapBy('resources'); + const nodeResources = server.schema.nodes + .all() + .models.mapBy('nodeResources'); + const taskResources = scheduledAllocs + .mapBy('taskResources.models') + .flat() + .mapBy('resources'); const totalMem = sumResources(nodeResources, 'Memory.MemoryMB'); const totalCPU = sumResources(nodeResources, 'Cpu.CpuShares'); const reservedMem = sumResources(taskResources, 'Memory.MemoryMB'); const reservedCPU = sumResources(taskResources, 'Cpu.CpuShares'); - assert.equal(Topology.clusterInfoPanel.memoryProgressValue, reservedMem / totalMem); - assert.equal(Topology.clusterInfoPanel.cpuProgressValue, reservedCPU / totalCPU); + assert.equal( + Topology.clusterInfoPanel.memoryProgressValue, + reservedMem / totalMem + ); + assert.equal( + Topology.clusterInfoPanel.cpuProgressValue, + reservedCPU / totalCPU + ); assert.equal( Topology.clusterInfoPanel.memoryAbsoluteValue, - `${formatBytes(reservedMem * 1024 * 1024)} / ${formatBytes(totalMem * 1024 * 1024)} reserved` + `${formatBytes(reservedMem * 1024 * 1024)} / ${formatBytes( + totalMem * 1024 * 1024 + )} reserved` ); assert.equal( Topology.clusterInfoPanel.cpuAbsoluteValue, - `${formatHertz(reservedCPU, 'MHz')} / ${formatHertz(totalCPU, 'MHz')} reserved` + `${formatHertz(reservedCPU, 'MHz')} / ${formatHertz( + totalCPU, + 'MHz' + )} reserved` ); }); @@ -81,10 +100,14 @@ module('Acceptance | topology', function (hooks) { const requests = this.server.pretender.handledRequests; assert.ok(requests.findBy('url', '/v1/nodes?resources=true')); - const allocationsRequest = requests.find((req) => req.url.startsWith('/v1/allocations')); + const allocationsRequest = requests.find((req) => + req.url.startsWith('/v1/allocations') + ); assert.ok(allocationsRequest); - const allocationRequestParams = queryString.parse(allocationsRequest.url.split('?')[1]); + const allocationRequestParams = queryString.parse( + allocationsRequest.url.split('?')[1] + ); assert.deepEqual(allocationRequestParams, { namespace: '*', task_states: 'false', @@ -113,12 +136,20 @@ module('Acceptance | topology', function (hooks) { } } - const dcIndex = nodes.mapBy('datacenter').uniq().sort().indexOf(node.datacenter); - const nodeIndex = nodes.filterBy('datacenter', node.datacenter).indexOf(node); + const dcIndex = nodes + .mapBy('datacenter') + .uniq() + .sort() + .indexOf(node.datacenter); + const nodeIndex = nodes + .filterBy('datacenter', node.datacenter) + .indexOf(node); const reset = async () => { await Topology.visit(); - await Topology.viz.datacenters[dcIndex].nodes[nodeIndex].memoryRects[0].select(); + await Topology.viz.datacenters[dcIndex].nodes[ + nodeIndex + ].memoryRects[0].select(); }; await reset(); @@ -127,7 +158,10 @@ module('Acceptance | topology', function (hooks) { assert.equal(Topology.allocInfoPanel.id, alloc.id.split('-')[0]); const uniqueClients = allocs.mapBy('nodeId').uniq(); - assert.equal(Topology.allocInfoPanel.siblingAllocs, `Sibling Allocations: ${allocs.length}`); + assert.equal( + Topology.allocInfoPanel.siblingAllocs, + `Sibling Allocations: ${allocs.length}` + ); assert.equal( Topology.allocInfoPanel.uniquePlacements, `Unique Client Placements: ${uniqueClients.length}` @@ -154,7 +188,10 @@ module('Acceptance | topology', function (hooks) { test('changing which allocation is selected changes the metric charts', async function (assert) { server.create('node'); const job1 = server.create('job', { createAllocations: false }); - const taskGroup1 = server.schema.find('taskGroup', job1.taskGroupIds[0]).name; + const taskGroup1 = server.schema.find( + 'taskGroup', + job1.taskGroupIds[0] + ).name; server.create('allocation', { forceRunningClientStatus: true, jobId: job1.id, @@ -162,7 +199,10 @@ module('Acceptance | topology', function (hooks) { }); const job2 = server.create('job', { createAllocations: false }); - const taskGroup2 = server.schema.find('taskGroup', job2.taskGroupIds[0]).name; + const taskGroup2 = server.schema.find( + 'taskGroup', + job2.taskGroupIds[0] + ).name; server.create('allocation', { forceRunningClientStatus: true, jobId: job2.id, @@ -171,10 +211,12 @@ module('Acceptance | topology', function (hooks) { await Topology.visit(); await Topology.viz.datacenters[0].nodes[0].memoryRects[0].select(); - const firstAllocationTaskNames = Topology.allocInfoPanel.charts[0].areas.mapBy('taskName'); + const firstAllocationTaskNames = + Topology.allocInfoPanel.charts[0].areas.mapBy('taskName'); await Topology.viz.datacenters[0].nodes[0].memoryRects[1].select(); - const secondAllocationTaskNames = Topology.allocInfoPanel.charts[0].areas.mapBy('taskName'); + const secondAllocationTaskNames = + Topology.allocInfoPanel.charts[0].areas.mapBy('taskName'); assert.notDeepEqual(firstAllocationTaskNames, secondAllocationTaskNames); }); @@ -197,7 +239,10 @@ module('Acceptance | topology', function (hooks) { assert.equal(Topology.nodeInfoPanel.address, `Address: ${node.httpAddr}`); assert.equal(Topology.nodeInfoPanel.status, `Status: ${node.status}`); - assert.equal(Topology.nodeInfoPanel.drainingLabel, node.drain ? 'Yes' : 'No'); + assert.equal( + Topology.nodeInfoPanel.drainingLabel, + node.drain ? 'Yes' : 'No' + ); assert.equal( Topology.nodeInfoPanel.eligibleLabel, node.schedulingEligibility === 'eligible' ? 'Yes' : 'No' @@ -209,22 +254,30 @@ module('Acceptance | topology', function (hooks) { node.schedulingEligibility !== 'eligible' ); - const taskResources = allocs.mapBy('taskResources.models').flat().mapBy('resources'); + const taskResources = allocs + .mapBy('taskResources.models') + .flat() + .mapBy('resources'); const reservedMem = sumResources(taskResources, 'Memory.MemoryMB'); const reservedCPU = sumResources(taskResources, 'Cpu.CpuShares'); const totalMem = node.nodeResources.Memory.MemoryMB; const totalCPU = node.nodeResources.Cpu.CpuShares; - assert.equal(Topology.nodeInfoPanel.memoryProgressValue, reservedMem / totalMem); - assert.equal(Topology.nodeInfoPanel.cpuProgressValue, reservedCPU / totalCPU); + assert.equal( + Topology.nodeInfoPanel.memoryProgressValue, + reservedMem / totalMem + ); + assert.equal( + Topology.nodeInfoPanel.cpuProgressValue, + reservedCPU / totalCPU + ); assert.equal( Topology.nodeInfoPanel.memoryAbsoluteValue, - `${formatScheduledBytes(reservedMem * 1024 * 1024)} / ${formatScheduledBytes( - totalMem, - 'MiB' - )} reserved` + `${formatScheduledBytes( + reservedMem * 1024 * 1024 + )} / ${formatScheduledBytes(totalMem, 'MiB')} reserved` ); assert.equal( diff --git a/ui/tests/acceptance/volume-detail-test.js b/ui/tests/acceptance/volume-detail-test.js index 822f3cf3c..e34b1c60b 100644 --- a/ui/tests/acceptance/volume-detail-test.js +++ b/ui/tests/acceptance/volume-detail-test.js @@ -55,7 +55,11 @@ module('Acceptance | volume detail', function (hooks) { test('/csi/volumes/:id should list additional details for the volume below the title', async function (assert) { await VolumeDetail.visit({ id: volume.id }); - assert.ok(VolumeDetail.health.includes(volume.schedulable ? 'Schedulable' : 'Unschedulable')); + assert.ok( + VolumeDetail.health.includes( + volume.schedulable ? 'Schedulable' : 'Unschedulable' + ) + ); assert.ok(VolumeDetail.provider.includes(volume.provider)); assert.ok(VolumeDetail.externalId.includes(volume.externalId)); assert.notOk( @@ -77,7 +81,10 @@ module('Acceptance | volume detail', function (hooks) { .sortBy('modifyIndex') .reverse() .forEach((allocation, idx) => { - assert.equal(allocation.id, VolumeDetail.writeAllocations.objectAt(idx).id); + assert.equal( + allocation.id, + VolumeDetail.writeAllocations.objectAt(idx).id + ); }); }); @@ -94,7 +101,10 @@ module('Acceptance | volume detail', function (hooks) { .sortBy('modifyIndex') .reverse() .forEach((allocation, idx) => { - assert.equal(allocation.id, VolumeDetail.readAllocations.objectAt(idx).id); + assert.equal( + allocation.id, + VolumeDetail.readAllocations.objectAt(idx).id + ); }); }); @@ -110,12 +120,19 @@ module('Acceptance | volume detail', function (hooks) { const tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id)); const cpuUsed = tasks.reduce((sum, task) => sum + task.resources.CPU, 0); - const memoryUsed = tasks.reduce((sum, task) => sum + task.resources.MemoryMB, 0); + const memoryUsed = tasks.reduce( + (sum, task) => sum + task.resources.MemoryMB, + 0 + ); await VolumeDetail.visit({ id: volume.id }); VolumeDetail.writeAllocations.objectAt(0).as((allocationRow) => { - assert.equal(allocationRow.shortId, allocation.id.split('-')[0], 'Allocation short ID'); + assert.equal( + allocationRow.shortId, + allocation.id.split('-')[0], + 'Allocation short ID' + ); assert.equal( allocationRow.createTime, moment(allocation.createTime / 1000000).format('MMM DD HH:mm:ss ZZ'), @@ -126,8 +143,16 @@ module('Acceptance | volume detail', function (hooks) { moment(allocation.modifyTime / 1000000).fromNow(), 'Allocation modify time' ); - assert.equal(allocationRow.status, allocation.clientStatus, 'Client status'); - assert.equal(allocationRow.job, server.db.jobs.find(allocation.jobId).name, 'Job name'); + assert.equal( + allocationRow.status, + allocation.clientStatus, + 'Client status' + ); + assert.equal( + allocationRow.job, + server.db.jobs.find(allocation.jobId).name, + 'Job name' + ); assert.ok(allocationRow.taskGroup, 'Task group name'); assert.ok(allocationRow.jobVersion, 'Job Version'); assert.equal( @@ -145,7 +170,9 @@ module('Acceptance | volume detail', function (hooks) { Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks) / cpuUsed, 'CPU %' ); - const roundedTicks = Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks); + const roundedTicks = Math.floor( + allocStats.resourceUsage.CpuStats.TotalTicks + ); assert.equal( allocationRow.cpuTooltip, `${formatHertz(roundedTicks, 'MHz')} / ${formatHertz(cpuUsed, 'MHz')}`, @@ -158,10 +185,9 @@ module('Acceptance | volume detail', function (hooks) { ); assert.equal( allocationRow.memTooltip, - `${formatBytes(allocStats.resourceUsage.MemoryStats.RSS)} / ${formatBytes( - memoryUsed, - 'MiB' - )}`, + `${formatBytes( + allocStats.resourceUsage.MemoryStats.RSS + )} / ${formatBytes(memoryUsed, 'MiB')}`, 'Detailed memory information is in a tooltip' ); }); @@ -195,7 +221,10 @@ module('Acceptance | volume detail', function (hooks) { await VolumeDetail.visit({ id: volume.id }); assert.equal(VolumeDetail.constraints.accessMode, volume.accessMode); - assert.equal(VolumeDetail.constraints.attachmentMode, volume.attachmentMode); + assert.equal( + VolumeDetail.constraints.attachmentMode, + volume.attachmentMode + ); }); }); diff --git a/ui/tests/acceptance/volumes-list-test.js b/ui/tests/acceptance/volumes-list-test.js index 8adf0bb49..1d028b200 100644 --- a/ui/tests/acceptance/volumes-list-test.js +++ b/ui/tests/acceptance/volumes-list-test.js @@ -76,14 +76,19 @@ module('Acceptance | volumes list', function (hooks) { const healthy = volume.controllersHealthy; const expected = volume.controllersExpected; const isHealthy = healthy > 0; - controllerHealthStr = `${isHealthy ? 'Healthy' : 'Unhealthy'} (${healthy}/${expected})`; + controllerHealthStr = `${ + isHealthy ? 'Healthy' : 'Unhealthy' + } (${healthy}/${expected})`; } const nodeHealthStr = volume.nodesHealthy > 0 ? 'Healthy' : 'Unhealthy'; assert.equal(volumeRow.name, volume.id); assert.notOk(volumeRow.hasNamespace); - assert.equal(volumeRow.schedulable, volume.schedulable ? 'Schedulable' : 'Unschedulable'); + assert.equal( + volumeRow.schedulable, + volume.schedulable ? 'Schedulable' : 'Unschedulable' + ); assert.equal(volumeRow.controllerHealth, controllerHealthStr); assert.equal( volumeRow.nodeHealth, @@ -95,18 +100,26 @@ module('Acceptance | volumes list', function (hooks) { test('each volume row should link to the corresponding volume', async function (assert) { const [, secondNamespace] = server.createList('namespace', 2); - const volume = server.create('csi-volume', { namespaceId: secondNamespace.id }); + const volume = server.create('csi-volume', { + namespaceId: secondNamespace.id, + }); await VolumesList.visit({ namespace: '*' }); await VolumesList.volumes.objectAt(0).clickName(); - assert.equal(currentURL(), `/csi/volumes/${volume.id}?namespace=${secondNamespace.id}`); + assert.equal( + currentURL(), + `/csi/volumes/${volume.id}?namespace=${secondNamespace.id}` + ); await VolumesList.visit({ namespace: '*' }); assert.equal(currentURL(), '/csi/volumes?namespace=*'); await VolumesList.volumes.objectAt(0).clickRow(); - assert.equal(currentURL(), `/csi/volumes/${volume.id}?namespace=${secondNamespace.id}`); + assert.equal( + currentURL(), + `/csi/volumes/${volume.id}?namespace=${secondNamespace.id}` + ); }); test('when there are no volumes, there is an empty message', async function (assert) { @@ -152,8 +165,12 @@ module('Acceptance | volumes list', function (hooks) { test('when the namespace query param is set, only matching volumes are shown and the namespace value is forwarded to app state', async function (assert) { server.createList('namespace', 2); - const volume1 = server.create('csi-volume', { namespaceId: server.db.namespaces[0].id }); - const volume2 = server.create('csi-volume', { namespaceId: server.db.namespaces[1].id }); + const volume1 = server.create('csi-volume', { + namespaceId: server.db.namespaces[0].id, + }); + const volume2 = server.create('csi-volume', { + namespaceId: server.db.namespaces[1].id, + }); await VolumesList.visit(); assert.equal(VolumesList.volumes.length, 2); diff --git a/ui/tests/helpers/glimmer-factory.js b/ui/tests/helpers/glimmer-factory.js index c460753dc..6625a7f2a 100644 --- a/ui/tests/helpers/glimmer-factory.js +++ b/ui/tests/helpers/glimmer-factory.js @@ -13,7 +13,10 @@ // }); export default function setupGlimmerComponentFactory(hooks, componentKey) { hooks.beforeEach(function () { - this.createComponent = glimmerComponentInstantiator(this.owner, componentKey); + this.createComponent = glimmerComponentInstantiator( + this.owner, + componentKey + ); }); hooks.afterEach(function () { diff --git a/ui/tests/helpers/module-for-job.js b/ui/tests/helpers/module-for-job.js index 87462b063..b293f8bdc 100644 --- a/ui/tests/helpers/module-for-job.js +++ b/ui/tests/helpers/module-for-job.js @@ -6,7 +6,12 @@ import JobDetail from 'nomad-ui/tests/pages/jobs/detail'; import Tokens from 'nomad-ui/tests/pages/settings/tokens'; // eslint-disable-next-line ember/no-test-module-for -export default function moduleForJob(title, context, jobFactory, additionalTests) { +export default function moduleForJob( + title, + context, + jobFactory, + additionalTests +) { let job; module(title, function(hooks) { @@ -59,7 +64,10 @@ export default function moduleForJob(title, context, jobFactory, additionalTests await JobDetail.tabFor('definition').visit(); assert.equal( currentURL(), - urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}/definition`, job.namespace) + urlWithNamespace( + `/jobs/${encodeURIComponent(job.id)}/definition`, + job.namespace + ) ); }); @@ -67,7 +75,10 @@ export default function moduleForJob(title, context, jobFactory, additionalTests await JobDetail.tabFor('versions').visit(); assert.equal( currentURL(), - urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}/versions`, job.namespace) + urlWithNamespace( + `/jobs/${encodeURIComponent(job.id)}/versions`, + job.namespace + ) ); }); @@ -75,7 +86,10 @@ export default function moduleForJob(title, context, jobFactory, additionalTests await JobDetail.tabFor('evaluations').visit(); assert.equal( currentURL(), - urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}/evaluations`, job.namespace) + urlWithNamespace( + `/jobs/${encodeURIComponent(job.id)}/evaluations`, + job.namespace + ) ); }); @@ -117,13 +131,17 @@ export default function moduleForJob(title, context, jobFactory, additionalTests }); test('clicking legend item navigates to a pre-filtered allocations table', async function(assert) { - const legendItem = JobDetail.allocationsSummary.legend.clickableItems[1]; + const legendItem = + JobDetail.allocationsSummary.legend.clickableItems[1]; const status = legendItem.label; await legendItem.click(); const encodedStatus = encodeURIComponent(JSON.stringify([status])); const expectedURL = new URL( - urlWithNamespace(`/jobs/${job.name}/clients?status=${encodedStatus}`, job.namespace), + urlWithNamespace( + `/jobs/${job.name}/clients?status=${encodedStatus}`, + job.namespace + ), window.location ); const gotURL = new URL(currentURL(), window.location); @@ -139,7 +157,9 @@ export default function moduleForJob(title, context, jobFactory, additionalTests const encodedStatus = encodeURIComponent(JSON.stringify([status])); const expectedURL = new URL( urlWithNamespace( - `/jobs/${encodeURIComponent(job.name)}/allocations?status=${encodedStatus}`, + `/jobs/${encodeURIComponent( + job.name + )}/allocations?status=${encodedStatus}`, job.namespace ), window.location @@ -150,13 +170,19 @@ export default function moduleForJob(title, context, jobFactory, additionalTests // Sort and compare URL query params. gotURL.searchParams.sort(); expectedURL.searchParams.sort(); - assert.equal(gotURL.searchParams.toString(), expectedURL.searchParams.toString()); + assert.equal( + gotURL.searchParams.toString(), + expectedURL.searchParams.toString() + ); }); } if (context === 'children') { test('children for the job are shown in the overview', async function(assert) { - assert.ok(JobDetail.childrenSummary.isPresent, 'Children are shown in the summary section'); + assert.ok( + JobDetail.childrenSummary.isPresent, + 'Children are shown in the summary section' + ); assert.ok( JobDetail.allocationsSummary.isHidden, 'Allocations are not shown in the summary section' @@ -173,7 +199,11 @@ export default function moduleForJob(title, context, jobFactory, additionalTests } // eslint-disable-next-line ember/no-test-module-for -export function moduleForJobWithClientStatus(title, jobFactory, additionalTests) { +export function moduleForJobWithClientStatus( + title, + jobFactory, + additionalTests +) { let job; module(title, function(hooks) { @@ -187,9 +217,9 @@ export function moduleForJobWithClientStatus(title, jobFactory, additionalTests) name: 'node-read', rulesJSON: { Node: { - Policy: 'read', - }, - }, + Policy: 'read' + } + } }); const clientToken = server.create('token', { type: 'client' }); clientToken.policyIds = [policy.id]; @@ -200,7 +230,7 @@ export function moduleForJobWithClientStatus(title, jobFactory, additionalTests) const clients = server.createList('node', 3, { datacenter: 'dc1', - status: 'ready', + status: 'ready' }); job = jobFactory(); clients.forEach(c => { @@ -234,7 +264,10 @@ export function moduleForJobWithClientStatus(title, jobFactory, additionalTests) await JobDetail.tabFor('clients').visit(); assert.equal( currentURL(), - urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}/clients`, job.namespace) + urlWithNamespace( + `/jobs/${encodeURIComponent(job.id)}/clients`, + job.namespace + ) ); }); @@ -246,13 +279,17 @@ export function moduleForJobWithClientStatus(title, jobFactory, additionalTests) }); test('clicking legend item navigates to a pre-filtered clients table', async function(assert) { - const legendItem = JobDetail.jobClientStatusSummary.statusBar.legend.clickableItems[0]; + const legendItem = + JobDetail.jobClientStatusSummary.statusBar.legend.clickableItems[0]; const status = legendItem.label; await legendItem.click(); const encodedStatus = encodeURIComponent(JSON.stringify([status])); const expectedURL = new URL( - urlWithNamespace(`/jobs/${job.name}/clients?status=${encodedStatus}`, job.namespace), + urlWithNamespace( + `/jobs/${job.name}/clients?status=${encodedStatus}`, + job.namespace + ), window.location ); const gotURL = new URL(currentURL(), window.location); @@ -267,7 +304,10 @@ export function moduleForJobWithClientStatus(title, jobFactory, additionalTests) const encodedStatus = encodeURIComponent(JSON.stringify([status])); const expectedURL = new URL( - urlWithNamespace(`/jobs/${job.name}/clients?status=${encodedStatus}`, job.namespace), + urlWithNamespace( + `/jobs/${job.name}/clients?status=${encodedStatus}`, + job.namespace + ), window.location ); const gotURL = new URL(currentURL(), window.location); @@ -276,7 +316,10 @@ export function moduleForJobWithClientStatus(title, jobFactory, additionalTests) // Sort and compare URL query params. gotURL.searchParams.sort(); expectedURL.searchParams.sort(); - assert.equal(gotURL.searchParams.toString(), expectedURL.searchParams.toString()); + assert.equal( + gotURL.searchParams.toString(), + expectedURL.searchParams.toString() + ); }); for (var testName in additionalTests) { diff --git a/ui/tests/integration/components/agent-monitor-test.js b/ui/tests/integration/components/agent-monitor-test.js index 15ef4fe55..d4e08caf3 100644 --- a/ui/tests/integration/components/agent-monitor-test.js +++ b/ui/tests/integration/components/agent-monitor-test.js @@ -7,7 +7,10 @@ import hbs from 'htmlbars-inline-precompile'; import Pretender from 'pretender'; import sinon from 'sinon'; import { logEncode } from '../../../mirage/data/logs'; -import { selectOpen, selectOpenChoose } from '../../utils/ember-power-select-extensions'; +import { + selectOpen, + selectOpenChoose, +} from '../../utils/ember-power-select-extensions'; import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; module('Integration | Component | agent-monitor', function (hooks) { @@ -22,7 +25,14 @@ module('Integration | Component | agent-monitor', function (hooks) { this.get('/v1/agent/monitor', ({ queryParams }) => [ 200, {}, - logEncode([`[${(queryParams.log_level || 'info').toUpperCase()}] ${LOG_MESSAGE}\n`], 0), + logEncode( + [ + `[${( + queryParams.log_level || 'info' + ).toUpperCase()}] ${LOG_MESSAGE}\n`, + ], + 0 + ), ]); }); }); @@ -135,7 +145,10 @@ module('Integration | Component | agent-monitor', function (hooks) { await render(commonTemplate); - assert.equal(find('[data-test-log-cli]').textContent, `[INFO] ${LOG_MESSAGE}\n`); + assert.equal( + find('[data-test-log-cli]').textContent, + `[INFO] ${LOG_MESSAGE}\n` + ); const contentId = await selectOpen('[data-test-level-switcher-parent]'); run.later(run, run.cancelTimers, INTERVAL); @@ -158,7 +171,14 @@ module('Integration | Component | agent-monitor', function (hooks) { {}, queryParams.log_level === 'info' ? logEncode([''], 0) - : logEncode([`[${(queryParams.log_level || 'info').toUpperCase()}] ${LOG_MESSAGE}\n`], 0), + : logEncode( + [ + `[${( + queryParams.log_level || 'info' + ).toUpperCase()}] ${LOG_MESSAGE}\n`, + ], + 0 + ), ]); this.setProperties({ @@ -178,6 +198,9 @@ module('Integration | Component | agent-monitor', function (hooks) { await selectOpenChoose(contentId, newLevel.capitalize()); await settled(); - assert.equal(find('[data-test-log-cli]').textContent, `[TRACE] ${LOG_MESSAGE}\n`); + assert.equal( + find('[data-test-log-cli]').textContent, + `[TRACE] ${LOG_MESSAGE}\n` + ); }); }); diff --git a/ui/tests/integration/components/allocation-row-test.js b/ui/tests/integration/components/allocation-row-test.js index 5d3cb8b8f..b985665d4 100644 --- a/ui/tests/integration/components/allocation-row-test.js +++ b/ui/tests/integration/components/allocation-row-test.js @@ -125,7 +125,10 @@ module('Integration | Component | allocation row', function(hooks) { @context={{context}} /> `); - assert.ok(find('[data-test-icon="unhealthy-driver"]'), 'Unhealthy driver icon is shown'); + assert.ok( + find('[data-test-icon="unhealthy-driver"]'), + 'Unhealthy driver icon is shown' + ); await componentA11yAudit(this.element, assert); }); @@ -169,8 +172,14 @@ module('Integration | Component | allocation row', function(hooks) { `); const status = allocation.get('clientStatus'); - assert.notOk(find('[data-test-cpu] .inline-chart'), `No CPU chart for ${status}`); - assert.notOk(find('[data-test-mem] .inline-chart'), `No Mem chart for ${status}`); + assert.notOk( + find('[data-test-cpu] .inline-chart'), + `No CPU chart for ${status}` + ); + assert.notOk( + find('[data-test-mem] .inline-chart'), + `No Mem chart for ${status}` + ); } }); }); diff --git a/ui/tests/integration/components/attributes-table-test.js b/ui/tests/integration/components/attributes-table-test.js index 44de440b4..0e4e03b67 100644 --- a/ui/tests/integration/components/attributes-table-test.js +++ b/ui/tests/integration/components/attributes-table-test.js @@ -33,7 +33,9 @@ module('Integration | Component | attributes table', function (hooks) { const rowsCount = Object.keys(flatten(commonAttributes)).length; assert.equal( - this.element.querySelectorAll('[data-test-attributes-section] [data-test-value]').length, + this.element.querySelectorAll( + '[data-test-attributes-section] [data-test-value]' + ).length, rowsCount, `Table has ${rowsCount} rows with values` ); @@ -45,8 +47,16 @@ module('Integration | Component | attributes table', function (hooks) { this.set('attributes', commonAttributes); await render(hbs``); - assert.equal(find('[data-test-key]').textContent.trim(), 'key', 'Row renders the key'); - assert.equal(find('[data-test-value]').textContent.trim(), 'value', 'Row renders the value'); + assert.equal( + find('[data-test-key]').textContent.trim(), + 'key', + 'Row renders the key' + ); + assert.equal( + find('[data-test-value]').textContent.trim(), + 'value', + 'Row renders the value' + ); const deepRow = findAll('[data-test-attributes-section]')[8]; assert.equal( @@ -59,7 +69,10 @@ module('Integration | Component | attributes table', function (hooks) { 'so.are.deeply.', 'The prefix is faded to put emphasis on the attribute' ); - assert.equal(deepRow.querySelector('[data-test-value]').textContent.trim(), 'properties'); + assert.equal( + deepRow.querySelector('[data-test-value]').textContent.trim(), + 'properties' + ); }); test('should render a row for key/value pairs even when the value is another object', async function (assert) { diff --git a/ui/tests/integration/components/copy-button-test.js b/ui/tests/integration/components/copy-button-test.js index 2b31d0a98..99fc8d1b3 100644 --- a/ui/tests/integration/components/copy-button-test.js +++ b/ui/tests/integration/components/copy-button-test.js @@ -6,7 +6,10 @@ import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; import sinon from 'sinon'; -import { triggerCopyError, triggerCopySuccess } from 'ember-cli-clipboard/test-support'; +import { + triggerCopyError, + triggerCopySuccess, +} from 'ember-cli-clipboard/test-support'; module('Integration | Component | copy-button', function (hooks) { setupRenderingTest(hooks); diff --git a/ui/tests/integration/components/das/dismissed-test.js b/ui/tests/integration/components/das/dismissed-test.js index 9a1549782..6f8bf773e 100644 --- a/ui/tests/integration/components/das/dismissed-test.js +++ b/ui/tests/integration/components/das/dismissed-test.js @@ -24,7 +24,10 @@ module('Integration | Component | das/dismissed', function (hooks) { await click('[data-test-understood]'); assert.ok(proceedSpy.calledWith({ manuallyDismissed: true })); - assert.equal(window.localStorage.getItem('nomadRecommendationDismssalUnderstood'), 'true'); + assert.equal( + window.localStorage.getItem('nomadRecommendationDismssalUnderstood'), + 'true' + ); }); test('it renders the dismissal interstitial with no button when the option to never show again has been chosen and proceeds automatically', async function (assert) { diff --git a/ui/tests/integration/components/das/recommendation-card-test.js b/ui/tests/integration/components/das/recommendation-card-test.js index 30d8c4c0f..301c8a1e8 100644 --- a/ui/tests/integration/components/das/recommendation-card-test.js +++ b/ui/tests/integration/components/das/recommendation-card-test.js @@ -108,10 +108,12 @@ module('Integration | Component | das/recommendation-card', function (hooks) { assert.ok(RecommendedCpu.isDecrease); }); - RecommendationCard.totalsTable.recommended.memory.as((RecommendedMemory) => { - assert.equal(RecommendedMemory.text, '512 MiB'); - assert.ok(RecommendedMemory.isIncrease); - }); + RecommendationCard.totalsTable.recommended.memory.as( + (RecommendedMemory) => { + assert.equal(RecommendedMemory.text, '512 MiB'); + assert.ok(RecommendedMemory.isIncrease); + } + ); assert.equal(RecommendationCard.totalsTable.unitDiff.cpu, '-75 MHz'); assert.equal(RecommendationCard.totalsTable.unitDiff.memory, '+128 MiB'); @@ -127,18 +129,28 @@ module('Integration | Component | das/recommendation-card', function (hooks) { ) ); - assert.equal(RecommendationCard.activeTask.totalsTable.current.cpu.text, '150 MHz'); - assert.equal(RecommendationCard.activeTask.totalsTable.current.memory.text, '128 MiB'); + assert.equal( + RecommendationCard.activeTask.totalsTable.current.cpu.text, + '150 MHz' + ); + assert.equal( + RecommendationCard.activeTask.totalsTable.current.memory.text, + '128 MiB' + ); - RecommendationCard.activeTask.totalsTable.recommended.cpu.as((RecommendedCpu) => { - assert.equal(RecommendedCpu.text, '50 MHz'); - assert.ok(RecommendedCpu.isDecrease); - }); + RecommendationCard.activeTask.totalsTable.recommended.cpu.as( + (RecommendedCpu) => { + assert.equal(RecommendedCpu.text, '50 MHz'); + assert.ok(RecommendedCpu.isDecrease); + } + ); - RecommendationCard.activeTask.totalsTable.recommended.memory.as((RecommendedMemory) => { - assert.equal(RecommendedMemory.text, '192 MiB'); - assert.ok(RecommendedMemory.isIncrease); - }); + RecommendationCard.activeTask.totalsTable.recommended.memory.as( + (RecommendedMemory) => { + assert.equal(RecommendedMemory.text, '192 MiB'); + assert.ok(RecommendedMemory.isIncrease); + } + ); assert.equal(RecommendationCard.activeTask.charts.length, 2); assert.equal( @@ -177,20 +189,24 @@ module('Integration | Component | das/recommendation-card', function (hooks) { assert.ok(RecommendedCpu.isIncrease); }); - RecommendationCard.activeTask.totalsTable.recommended.cpu.as((RecommendedCpu) => { - assert.equal(RecommendedCpu.text, '150 MHz'); - assert.ok(RecommendedCpu.isNeutral); - }); + RecommendationCard.activeTask.totalsTable.recommended.cpu.as( + (RecommendedCpu) => { + assert.equal(RecommendedCpu.text, '150 MHz'); + assert.ok(RecommendedCpu.isNeutral); + } + ); await RecommendationCard.togglesTable.toggleAllMemory.toggle(); assert.notOk(RecommendationCard.togglesTable.tasks[0].memory.isActive); assert.notOk(RecommendationCard.togglesTable.tasks[1].memory.isActive); - RecommendationCard.totalsTable.recommended.memory.as((RecommendedMemory) => { - assert.equal(RecommendedMemory.text, '384 MiB'); - assert.ok(RecommendedMemory.isNeutral); - }); + RecommendationCard.totalsTable.recommended.memory.as( + (RecommendedMemory) => { + assert.equal(RecommendedMemory.text, '384 MiB'); + assert.ok(RecommendedMemory.isNeutral); + } + ); await RecommendationCard.togglesTable.tasks[1].click(); @@ -198,7 +214,10 @@ module('Integration | Component | das/recommendation-card', function (hooks) { assert.ok(RecommendationCard.togglesTable.tasks[1].isActive); assert.equal(RecommendationCard.activeTask.name, 'tortle task'); - assert.equal(RecommendationCard.activeTask.totalsTable.current.cpu.text, '125 MHz'); + assert.equal( + RecommendationCard.activeTask.totalsTable.current.cpu.text, + '125 MHz' + ); await componentA11yAudit(this.element, assert); }); @@ -317,7 +336,10 @@ module('Integration | Component | das/recommendation-card', function (hooks) { await render(hbs``); - assert.equal(RecommendationCard.totalsTable.recommended.memory.text, '128 MiB'); + assert.equal( + RecommendationCard.totalsTable.recommended.memory.text, + '128 MiB' + ); assert.equal(RecommendationCard.totalsTable.unitDiff.memory, '0 MiB'); assert.equal(RecommendationCard.totalsTable.percentDiff.memory, '+0%'); @@ -601,9 +623,14 @@ class MockRecommendationSummary { @action toggleAllRecommendationsForResource(resource, enabled) { if (enabled) { - this.excludedRecommendations = this.excludedRecommendations.rejectBy('resource', resource); + this.excludedRecommendations = this.excludedRecommendations.rejectBy( + 'resource', + resource + ); } else { - this.excludedRecommendations.pushObjects(this.recommendations.filterBy('resource', resource)); + this.excludedRecommendations.pushObjects( + this.recommendations.filterBy('resource', resource) + ); } } } diff --git a/ui/tests/integration/components/flex-masonry-test.js b/ui/tests/integration/components/flex-masonry-test.js index 8b88ee7dd..4380920d9 100644 --- a/ui/tests/integration/components/flex-masonry-test.js +++ b/ui/tests/integration/components/flex-masonry-test.js @@ -45,7 +45,10 @@ module('Integration | Component | FlexMasonry', function (hooks) { `); - assert.equal(findAll('[data-test-flex-masonry-item]').length, this.items.length); + assert.equal( + findAll('[data-test-flex-masonry-item]').length, + this.items.length + ); }); test('the @withSpacing arg adds the with-spacing class', async function (assert) { @@ -57,7 +60,9 @@ module('Integration | Component | FlexMasonry', function (hooks) { `); - assert.ok(find('[data-test-flex-masonry]').classList.contains('with-spacing')); + assert.ok( + find('[data-test-flex-masonry]').classList.contains('with-spacing') + ); }); test('individual items along with the reflow action are yielded', async function (assert) { diff --git a/ui/tests/integration/components/fs/file-test.js b/ui/tests/integration/components/fs/file-test.js index 992a6deb1..7ba969351 100644 --- a/ui/tests/integration/components/fs/file-test.js +++ b/ui/tests/integration/components/fs/file-test.js @@ -19,10 +19,22 @@ module('Integration | Component | fs/file', function (hooks) { {}, JSON.stringify({ ServerRegion: 'default', Members: [] }), ]); - this.get('/v1/regions', () => [200, {}, JSON.stringify(['default', 'region-2'])]); - this.get('/v1/client/fs/stream/:alloc_id', () => [200, {}, logEncode(['Hello World'], 0)]); + this.get('/v1/regions', () => [ + 200, + {}, + JSON.stringify(['default', 'region-2']), + ]); + this.get('/v1/client/fs/stream/:alloc_id', () => [ + 200, + {}, + logEncode(['Hello World'], 0), + ]); this.get('/v1/client/fs/cat/:alloc_id', () => [200, {}, 'Hello World']); - this.get('/v1/client/fs/readat/:alloc_id', () => [200, {}, 'Hello World']); + this.get('/v1/client/fs/readat/:alloc_id', () => [ + 200, + {}, + 'Hello World', + ]); }); this.system = this.owner.lookup('service:system'); }); @@ -114,7 +126,10 @@ module('Integration | Component | fs/file', function (hooks) { find('[data-test-file-box] [data-test-log-cli]'), 'The streaming file component was not rendered' ); - assert.ok(find('[data-test-unsupported-type]'), 'Unsupported file type message is shown'); + assert.ok( + find('[data-test-unsupported-type]'), + 'Unsupported file type message is shown' + ); await componentA11yAudit(this.element, assert); }); @@ -257,6 +272,9 @@ module('Integration | Component | fs/file', function (hooks) { classes = Array.from(find('[data-test-file-box]').classList); assert.notOk(classes.includes('is-dark'), 'Body is still not dark'); - assert.notOk(classes.includes('is-full-bleed'), 'Body is still not full-bleed'); + assert.notOk( + classes.includes('is-full-bleed'), + 'Body is still not full-bleed' + ); }); }); diff --git a/ui/tests/integration/components/image-file-test.js b/ui/tests/integration/components/image-file-test.js index 6d2354b71..369747ae2 100644 --- a/ui/tests/integration/components/image-file-test.js +++ b/ui/tests/integration/components/image-file-test.js @@ -47,7 +47,11 @@ module('Integration | Component | image file', function (hooks) { commonProperties.src, `href is ${commonProperties.src}` ); - assert.equal(find('a').getAttribute('target'), '_blank', 'Anchor opens to a new tab'); + assert.equal( + find('a').getAttribute('target'), + '_blank', + 'Anchor opens to a new tab' + ); assert.equal( find('a').getAttribute('rel'), 'noopener noreferrer', @@ -80,7 +84,9 @@ module('Integration | Component | image file', function (hooks) { 'Width and height are formatted correctly' ); assert.ok( - statsEl.textContent.trim().endsWith(formatBytes(commonProperties.size) + ')'), + statsEl.textContent + .trim() + .endsWith(formatBytes(commonProperties.size) + ')'), 'Human-formatted size is included' ); }); diff --git a/ui/tests/integration/components/job-client-status-bar-test.js b/ui/tests/integration/components/job-client-status-bar-test.js index 94b76a538..47e1dff52 100644 --- a/ui/tests/integration/components/job-client-status-bar-test.js +++ b/ui/tests/integration/components/job-client-status-bar-test.js @@ -67,7 +67,11 @@ module('Integration | Component | job-client-status-bar', function (hooks) { ...props, jobClientStatus: { ...props.jobClientStatus, - byStatus: { ...props.jobClientStatus.byStatus, starting: [], running: ['someNodeId'] }, + byStatus: { + ...props.jobClientStatus.byStatus, + starting: [], + running: ['someNodeId'], + }, }, }; this.setProperties(newProps); diff --git a/ui/tests/integration/components/job-diff-test.js b/ui/tests/integration/components/job-diff-test.js index 766b6cb3d..2b9b6f7dd 100644 --- a/ui/tests/integration/components/job-diff-test.js +++ b/ui/tests/integration/components/job-diff-test.js @@ -37,21 +37,27 @@ module('Integration | Component | job diff', function (hooks) { ); assert.equal( cleanWhitespace( - find('[data-test-diff-section-label="field"][data-test-diff-field="added"]').textContent + find( + '[data-test-diff-section-label="field"][data-test-diff-field="added"]' + ).textContent ), '+ Added Field: "Foobar"', 'Added field is rendered correctly' ); assert.equal( cleanWhitespace( - find('[data-test-diff-section-label="field"][data-test-diff-field="edited"]').textContent + find( + '[data-test-diff-section-label="field"][data-test-diff-field="edited"]' + ).textContent ), '+/- Edited Field: "256" => "512"', 'Edited field is rendered correctly' ); assert.equal( cleanWhitespace( - find('[data-test-diff-section-label="field"][data-test-diff-field="deleted"]').textContent + find( + '[data-test-diff-section-label="field"][data-test-diff-field="deleted"]' + ).textContent ), '- Removed Field: "12"', 'Removed field is rendered correctly' @@ -108,38 +114,50 @@ module('Integration | Component | job diff', function (hooks) { assert.ok( cleanWhitespace( - find('[data-test-diff-section-label="object"][data-test-diff-field="added"]').textContent + find( + '[data-test-diff-section-label="object"][data-test-diff-field="added"]' + ).textContent ).startsWith('+ DeepConfiguration {'), 'Added object starts with a JSON block' ); assert.ok( cleanWhitespace( - find('[data-test-diff-section-label="object"][data-test-diff-field="edited"]').textContent + find( + '[data-test-diff-section-label="object"][data-test-diff-field="edited"]' + ).textContent ).startsWith('+/- ComplexProperty {'), 'Edited object starts with a JSON block' ); assert.ok( cleanWhitespace( - find('[data-test-diff-section-label="object"][data-test-diff-field="deleted"]').textContent + find( + '[data-test-diff-section-label="object"][data-test-diff-field="deleted"]' + ).textContent ).startsWith('- DatedStuff {'), 'Removed object starts with a JSON block' ); assert.ok( cleanWhitespace( - find('[data-test-diff-section-label="object"][data-test-diff-field="added"]').textContent + find( + '[data-test-diff-section-label="object"][data-test-diff-field="added"]' + ).textContent ).endsWith('}'), 'Added object ends the JSON block' ); assert.ok( cleanWhitespace( - find('[data-test-diff-section-label="object"][data-test-diff-field="edited"]').textContent + find( + '[data-test-diff-section-label="object"][data-test-diff-field="edited"]' + ).textContent ).endsWith('}'), 'Edited object starts with a JSON block' ); assert.ok( cleanWhitespace( - find('[data-test-diff-section-label="object"][data-test-diff-field="deleted"]').textContent + find( + '[data-test-diff-section-label="object"][data-test-diff-field="deleted"]' + ).textContent ).endsWith('}'), 'Removed object ends the JSON block' ); diff --git a/ui/tests/integration/components/job-editor-test.js b/ui/tests/integration/components/job-editor-test.js index a6e8ba6d8..23bc9ef95 100644 --- a/ui/tests/integration/components/job-editor-test.js +++ b/ui/tests/integration/components/job-editor-test.js @@ -95,7 +95,12 @@ module('Integration | Component | job-editor', function (hooks) { }; const renderEditJob = async (component, job) => { - component.setProperties({ job, onSubmit: sinon.spy(), onCancel: sinon.spy(), context: 'edit' }); + component.setProperties({ + job, + onSubmit: sinon.spy(), + onCancel: sinon.spy(), + context: 'edit', + }); await component.render(cancelableTemplate); }; @@ -108,7 +113,10 @@ module('Integration | Component | job-editor', function (hooks) { const job = await this.store.createRecord('job'); await renderNewJob(this, job); - assert.ok(Editor.editorHelp.isPresent, 'Editor explanation popup is present'); + assert.ok( + Editor.editorHelp.isPresent, + 'Editor explanation popup is present' + ); assert.ok(Editor.editor.isPresent, 'Editor is present'); await componentA11yAudit(this.element, assert); @@ -119,7 +127,10 @@ module('Integration | Component | job-editor', function (hooks) { await renderNewJob(this, job); await Editor.editorHelp.dismiss(); - assert.notOk(Editor.editorHelp.isPresent, 'Editor explanation popup is gone'); + assert.notOk( + Editor.editorHelp.isPresent, + 'Editor explanation popup is gone' + ); assert.equal( window.localStorage.nomadMessageJobEditor, 'false', @@ -133,7 +144,10 @@ module('Integration | Component | job-editor', function (hooks) { const job = await this.store.createRecord('job'); await renderNewJob(this, job); - assert.notOk(Editor.editorHelp.isPresent, 'Editor explanation popup is gone'); + assert.notOk( + Editor.editorHelp.isPresent, + 'Editor explanation popup is gone' + ); }); test('submitting a json job skips the parse endpoint', async function (assert) { @@ -143,8 +157,14 @@ module('Integration | Component | job-editor', function (hooks) { await renderNewJob(this, job); await planJob(spec); const requests = this.server.pretender.handledRequests.mapBy('url'); - assert.notOk(requests.includes('/v1/jobs/parse'), 'JSON job spec is not parsed'); - assert.ok(requests.includes(`/v1/job/${newJobName}/plan`), 'JSON job spec is still planned'); + assert.notOk( + requests.includes('/v1/jobs/parse'), + 'JSON job spec is not parsed' + ); + assert.ok( + requests.includes(`/v1/job/${newJobName}/plan`), + 'JSON job spec is still planned' + ); }); test('submitting an hcl job requires the parse endpoint', async function (assert) { @@ -154,10 +174,17 @@ module('Integration | Component | job-editor', function (hooks) { await renderNewJob(this, job); await planJob(spec); const requests = this.server.pretender.handledRequests.mapBy('url'); - assert.ok(requests.includes('/v1/jobs/parse'), 'HCL job spec is parsed first'); - assert.ok(requests.includes(`/v1/job/${newJobName}/plan`), 'HCL job spec is planned'); assert.ok( - requests.indexOf('/v1/jobs/parse') < requests.indexOf(`/v1/job/${newJobName}/plan`), + requests.includes('/v1/jobs/parse'), + 'HCL job spec is parsed first' + ); + assert.ok( + requests.includes(`/v1/job/${newJobName}/plan`), + 'HCL job spec is planned' + ); + assert.ok( + requests.indexOf('/v1/jobs/parse') < + requests.indexOf(`/v1/job/${newJobName}/plan`), 'Parse comes before Plan' ); }); @@ -169,7 +196,10 @@ module('Integration | Component | job-editor', function (hooks) { await renderNewJob(this, job); await planJob(spec); assert.ok(Editor.planOutput, 'The plan is outputted'); - assert.notOk(Editor.editor.isPresent, 'The editor is replaced with the plan output'); + assert.notOk( + Editor.editor.isPresent, + 'The editor is replaced with the plan output' + ); assert.ok(Editor.planHelp.isPresent, 'The plan explanation popup is shown'); await componentA11yAudit(this.element, assert); @@ -183,7 +213,11 @@ module('Integration | Component | job-editor', function (hooks) { await planJob(spec); await Editor.cancel(); assert.ok(Editor.editor.isPresent, 'The editor is shown again'); - assert.equal(Editor.editor.contents, spec, 'The spec that was planned is still in the editor'); + assert.equal( + Editor.editor.contents, + spec, + 'The spec that was planned is still in the editor' + ); }); test('when parse fails, the parse error message is shown', async function (assert) { @@ -213,7 +247,11 @@ module('Integration | Component | job-editor', function (hooks) { const errorMessage = 'Plan Failed!! :o'; const job = await this.store.createRecord('job'); - this.server.pretender.post(`/v1/job/${newJobName}/plan`, () => [400, {}, errorMessage]); + this.server.pretender.post(`/v1/job/${newJobName}/plan`, () => [ + 400, + {}, + errorMessage, + ]); await renderNewJob(this, job); await planJob(spec); @@ -300,9 +338,17 @@ module('Integration | Component | job-editor', function (hooks) { await renderEditJob(this, job); await planJob(spec); await Editor.run(); - const requests = this.server.pretender.handledRequests.filterBy('method', 'POST').mapBy('url'); - assert.ok(requests.includes(`/v1/job/${newJobName}`), 'A request was made to job update'); - assert.notOk(requests.includes('/v1/jobs'), 'A request was not made to job create'); + const requests = this.server.pretender.handledRequests + .filterBy('method', 'POST') + .mapBy('url'); + assert.ok( + requests.includes(`/v1/job/${newJobName}`), + 'A request was made to job update' + ); + assert.notOk( + requests.includes('/v1/jobs'), + 'A request was not made to job create' + ); }); test('when a job is submitted in the new context, a POST request is made to the create job endpoint', async function (assert) { @@ -312,8 +358,13 @@ module('Integration | Component | job-editor', function (hooks) { await renderNewJob(this, job); await planJob(spec); await Editor.run(); - const requests = this.server.pretender.handledRequests.filterBy('method', 'POST').mapBy('url'); - assert.ok(requests.includes('/v1/jobs'), 'A request was made to job create'); + const requests = this.server.pretender.handledRequests + .filterBy('method', 'POST') + .mapBy('url'); + assert.ok( + requests.includes('/v1/jobs'), + 'A request was made to job create' + ); assert.notOk( requests.includes(`/v1/job/${newJobName}`), 'A request was not made to job update' diff --git a/ui/tests/integration/components/job-page/helpers.js b/ui/tests/integration/components/job-page/helpers.js index 6f41db06c..7b986816d 100644 --- a/ui/tests/integration/components/job-page/helpers.js +++ b/ui/tests/integration/components/job-page/helpers.js @@ -29,7 +29,10 @@ export function expectStartRequest(assert, server, job) { const requestPayload = JSON.parse(request.requestBody).Job; assert.ok(request, 'POST URL was made correctly'); - assert.ok(requestPayload.Stop == null, 'The Stop signal is not sent in the POST request'); + assert.ok( + requestPayload.Stop == null, + 'The Stop signal is not sent in the POST request' + ); } export async function expectError(assert, title) { @@ -44,7 +47,10 @@ export async function expectError(assert, title) { ); await click('[data-test-job-error-close]'); - assert.notOk(find('[data-test-job-error-title]'), 'Error message is dismissable'); + assert.notOk( + find('[data-test-job-error-title]'), + 'Error message is dismissable' + ); } export function expectDeleteRequest(assert, server, job) { diff --git a/ui/tests/integration/components/job-page/parts/body-test.js b/ui/tests/integration/components/job-page/parts/body-test.js index ad5a61421..3c03d74e6 100644 --- a/ui/tests/integration/components/job-page/parts/body-test.js +++ b/ui/tests/integration/components/job-page/parts/body-test.js @@ -46,7 +46,9 @@ module('Integration | Component | job-page/parts/body', function (hooks) { `); - const subnavLabels = findAll('[data-test-tab]').map((anchor) => anchor.textContent); + const subnavLabels = findAll('[data-test-tab]').map( + (anchor) => anchor.textContent + ); assert.ok( subnavLabels.some((label) => label === 'Definition'), 'Definition link' @@ -78,7 +80,9 @@ module('Integration | Component | job-page/parts/body', function (hooks) { `); - const subnavLabels = findAll('[data-test-tab]').map((anchor) => anchor.textContent); + const subnavLabels = findAll('[data-test-tab]').map( + (anchor) => anchor.textContent + ); assert.ok( subnavLabels.some((label) => label === 'Definition'), 'Definition link' diff --git a/ui/tests/integration/components/job-page/parts/children-test.js b/ui/tests/integration/components/job-page/parts/children-test.js index ffdb793e8..c70b409ff 100644 --- a/ui/tests/integration/components/job-page/parts/children-test.js +++ b/ui/tests/integration/components/job-page/parts/children-test.js @@ -89,12 +89,21 @@ module('Integration | Component | job-page/parts/children', function (hooks) { `); const childrenCount = parent.get('children.length'); - assert.ok(childrenCount > pageSize, 'Parent has more children than one page size'); - assert.equal(findAll('[data-test-job-name]').length, pageSize, 'Table length maxes out at 10'); + assert.ok( + childrenCount > pageSize, + 'Parent has more children than one page size' + ); + assert.equal( + findAll('[data-test-job-name]').length, + pageSize, + 'Table length maxes out at 10' + ); assert.ok(find('.pagination-next'), 'Next button is rendered'); assert.ok( - new RegExp(`1.10.+?${childrenCount}`).test(find('.pagination-numbers').textContent.trim()) + new RegExp(`1.10.+?${childrenCount}`).test( + find('.pagination-numbers').textContent.trim() + ) ); await componentA11yAudit(this.element, assert); diff --git a/ui/tests/integration/components/job-page/parts/latest-deployment-test.js b/ui/tests/integration/components/job-page/parts/latest-deployment-test.js index 7388934cf..06a99f594 100644 --- a/ui/tests/integration/components/job-page/parts/latest-deployment-test.js +++ b/ui/tests/integration/components/job-page/parts/latest-deployment-test.js @@ -7,176 +7,202 @@ import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage'; import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer'; import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; -module('Integration | Component | job-page/parts/latest-deployment', function (hooks) { - setupRenderingTest(hooks); +module( + 'Integration | Component | job-page/parts/latest-deployment', + function (hooks) { + setupRenderingTest(hooks); - hooks.beforeEach(function () { - fragmentSerializerInitializer(this.owner); - window.localStorage.clear(); - this.store = this.owner.lookup('service:store'); - this.server = startMirage(); - this.server.create('namespace'); - }); - - hooks.afterEach(function () { - this.server.shutdown(); - window.localStorage.clear(); - }); - - test('there is no latest deployment section when the job has no deployments', async function (assert) { - this.server.create('job', { - type: 'service', - noDeployments: true, - createAllocations: false, + hooks.beforeEach(function () { + fragmentSerializerInitializer(this.owner); + window.localStorage.clear(); + this.store = this.owner.lookup('service:store'); + this.server = startMirage(); + this.server.create('namespace'); }); - await this.store.findAll('job'); + hooks.afterEach(function () { + this.server.shutdown(); + window.localStorage.clear(); + }); - this.set('job', this.store.peekAll('job').get('firstObject')); - await render(hbs` + test('there is no latest deployment section when the job has no deployments', async function (assert) { + this.server.create('job', { + type: 'service', + noDeployments: true, + createAllocations: false, + }); + + await this.store.findAll('job'); + + this.set('job', this.store.peekAll('job').get('firstObject')); + await render(hbs` ) `); - assert.notOk(find('[data-test-active-deployment]'), 'No active deployment'); - }); - - test('the latest deployment section shows up for the currently running deployment', async function (assert) { - this.server.create('job', { - type: 'service', - createAllocations: false, - activeDeployment: true, + assert.notOk( + find('[data-test-active-deployment]'), + 'No active deployment' + ); }); - await this.store.findAll('job'); + test('the latest deployment section shows up for the currently running deployment', async function (assert) { + this.server.create('job', { + type: 'service', + createAllocations: false, + activeDeployment: true, + }); - this.set('job', this.store.peekAll('job').get('firstObject')); - await render(hbs` + await this.store.findAll('job'); + + this.set('job', this.store.peekAll('job').get('firstObject')); + await render(hbs` `); - const deployment = await this.get('job.latestDeployment'); - const version = await deployment.get('version'); + const deployment = await this.get('job.latestDeployment'); + const version = await deployment.get('version'); - assert.ok(find('[data-test-active-deployment]'), 'Active deployment'); - assert.ok( - find('[data-test-active-deployment]').classList.contains('is-info'), - 'Running deployment gets the is-info class' - ); - assert.equal( - find('[data-test-active-deployment-stat="id"]').textContent.trim(), - deployment.get('shortId'), - 'The active deployment is the most recent running deployment' - ); + assert.ok(find('[data-test-active-deployment]'), 'Active deployment'); + assert.ok( + find('[data-test-active-deployment]').classList.contains('is-info'), + 'Running deployment gets the is-info class' + ); + assert.equal( + find('[data-test-active-deployment-stat="id"]').textContent.trim(), + deployment.get('shortId'), + 'The active deployment is the most recent running deployment' + ); - assert.equal( - find('[data-test-active-deployment-stat="submit-time"]').textContent.trim(), - moment(version.get('submitTime')).fromNow(), - 'Time since the job was submitted is in the active deployment header' - ); + assert.equal( + find( + '[data-test-active-deployment-stat="submit-time"]' + ).textContent.trim(), + moment(version.get('submitTime')).fromNow(), + 'Time since the job was submitted is in the active deployment header' + ); - assert.equal( - find('[data-test-deployment-metric="canaries"]').textContent.trim(), - `${deployment.get('placedCanaries')} / ${deployment.get('desiredCanaries')}`, - 'Canaries, both places and desired, are in the metrics' - ); + assert.equal( + find('[data-test-deployment-metric="canaries"]').textContent.trim(), + `${deployment.get('placedCanaries')} / ${deployment.get( + 'desiredCanaries' + )}`, + 'Canaries, both places and desired, are in the metrics' + ); - assert.equal( - find('[data-test-deployment-metric="placed"]').textContent.trim(), - deployment.get('placedAllocs'), - 'Placed allocs aggregates across task groups' - ); + assert.equal( + find('[data-test-deployment-metric="placed"]').textContent.trim(), + deployment.get('placedAllocs'), + 'Placed allocs aggregates across task groups' + ); - assert.equal( - find('[data-test-deployment-metric="desired"]').textContent.trim(), - deployment.get('desiredTotal'), - 'Desired allocs aggregates across task groups' - ); + assert.equal( + find('[data-test-deployment-metric="desired"]').textContent.trim(), + deployment.get('desiredTotal'), + 'Desired allocs aggregates across task groups' + ); - assert.equal( - find('[data-test-deployment-metric="healthy"]').textContent.trim(), - deployment.get('healthyAllocs'), - 'Healthy allocs aggregates across task groups' - ); + assert.equal( + find('[data-test-deployment-metric="healthy"]').textContent.trim(), + deployment.get('healthyAllocs'), + 'Healthy allocs aggregates across task groups' + ); - assert.equal( - find('[data-test-deployment-metric="unhealthy"]').textContent.trim(), - deployment.get('unhealthyAllocs'), - 'Unhealthy allocs aggregates across task groups' - ); + assert.equal( + find('[data-test-deployment-metric="unhealthy"]').textContent.trim(), + deployment.get('unhealthyAllocs'), + 'Unhealthy allocs aggregates across task groups' + ); - assert.equal( - find('[data-test-deployment-notification]').textContent.trim(), - deployment.get('statusDescription'), - 'Status description is in the metrics block' - ); + assert.equal( + find('[data-test-deployment-notification]').textContent.trim(), + deployment.get('statusDescription'), + 'Status description is in the metrics block' + ); - await componentA11yAudit(this.element, assert); - }); - - test('when there is no running deployment, the latest deployment section shows up for the last deployment', async function (assert) { - this.server.create('job', { - type: 'service', - createAllocations: false, - noActiveDeployment: true, + await componentA11yAudit(this.element, assert); }); - await this.store.findAll('job'); + test('when there is no running deployment, the latest deployment section shows up for the last deployment', async function (assert) { + this.server.create('job', { + type: 'service', + createAllocations: false, + noActiveDeployment: true, + }); - this.set('job', this.store.peekAll('job').get('firstObject')); - await render(hbs` + await this.store.findAll('job'); + + this.set('job', this.store.peekAll('job').get('firstObject')); + await render(hbs` `); - assert.ok(find('[data-test-active-deployment]'), 'Active deployment'); - assert.notOk( - find('[data-test-active-deployment]').classList.contains('is-info'), - 'Non-running deployment does not get the is-info class' - ); - }); + assert.ok(find('[data-test-active-deployment]'), 'Active deployment'); + assert.notOk( + find('[data-test-active-deployment]').classList.contains('is-info'), + 'Non-running deployment does not get the is-info class' + ); + }); - test('the latest deployment section can be expanded to show task groups and allocations', async function (assert) { - this.server.create('node'); - this.server.create('job', { type: 'service', activeDeployment: true }); + test('the latest deployment section can be expanded to show task groups and allocations', async function (assert) { + this.server.create('node'); + this.server.create('job', { type: 'service', activeDeployment: true }); - await this.store.findAll('job'); + await this.store.findAll('job'); - this.set('job', this.store.peekAll('job').get('firstObject')); - await render(hbs` + this.set('job', this.store.peekAll('job').get('firstObject')); + await render(hbs` `); - assert.notOk(find('[data-test-deployment-task-groups]'), 'Task groups not found'); - assert.notOk(find('[data-test-deployment-allocations]'), 'Allocations not found'); + assert.notOk( + find('[data-test-deployment-task-groups]'), + 'Task groups not found' + ); + assert.notOk( + find('[data-test-deployment-allocations]'), + 'Allocations not found' + ); - await click('[data-test-deployment-toggle-details]'); + await click('[data-test-deployment-toggle-details]'); - assert.ok(find('[data-test-deployment-task-groups]'), 'Task groups found'); - assert.ok(find('[data-test-deployment-allocations]'), 'Allocations found'); + assert.ok( + find('[data-test-deployment-task-groups]'), + 'Task groups found' + ); + assert.ok( + find('[data-test-deployment-allocations]'), + 'Allocations found' + ); - await componentA11yAudit(this.element, assert); - }); + await componentA11yAudit(this.element, assert); + }); - test('each task group in the expanded task group section shows task group details', async function (assert) { - this.server.create('node'); - this.server.create('job', { type: 'service', activeDeployment: true }); + test('each task group in the expanded task group section shows task group details', async function (assert) { + this.server.create('node'); + this.server.create('job', { type: 'service', activeDeployment: true }); - await this.store.findAll('job'); + await this.store.findAll('job'); - const job = this.store.peekAll('job').get('firstObject'); + const job = this.store.peekAll('job').get('firstObject'); - this.set('job', job); - await render(hbs` + this.set('job', job); + await render(hbs` `); - await click('[data-test-deployment-toggle-details]'); + await click('[data-test-deployment-toggle-details]'); - const task = job.get('runningDeployment.taskGroupSummaries.firstObject'); - const findForTaskGroup = (selector) => find(`[data-test-deployment-task-group-${selector}]`); - assert.equal(findForTaskGroup('name').textContent.trim(), task.get('name')); - assert.equal( - findForTaskGroup('progress-deadline').textContent.trim(), - moment(task.get('requireProgressBy')).format("MMM DD, 'YY HH:mm:ss ZZ") - ); - }); -}); + const task = job.get('runningDeployment.taskGroupSummaries.firstObject'); + const findForTaskGroup = (selector) => + find(`[data-test-deployment-task-group-${selector}]`); + assert.equal( + findForTaskGroup('name').textContent.trim(), + task.get('name') + ); + assert.equal( + findForTaskGroup('progress-deadline').textContent.trim(), + moment(task.get('requireProgressBy')).format("MMM DD, 'YY HH:mm:ss ZZ") + ); + }); + } +); diff --git a/ui/tests/integration/components/job-page/parts/placement-failures-test.js b/ui/tests/integration/components/job-page/parts/placement-failures-test.js index 0789783b7..be83e7f4c 100644 --- a/ui/tests/integration/components/job-page/parts/placement-failures-test.js +++ b/ui/tests/integration/components/job-page/parts/placement-failures-test.js @@ -6,76 +6,93 @@ import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage'; import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer'; import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; -module('Integration | Component | job-page/parts/placement-failures', function (hooks) { - setupRenderingTest(hooks); +module( + 'Integration | Component | job-page/parts/placement-failures', + function (hooks) { + setupRenderingTest(hooks); - hooks.beforeEach(function () { - fragmentSerializerInitializer(this.owner); - window.localStorage.clear(); - this.store = this.owner.lookup('service:store'); - this.server = startMirage(); - this.server.create('namespace'); - }); - - hooks.afterEach(function () { - this.server.shutdown(); - window.localStorage.clear(); - }); - - test('when the job has placement failures, they are called out', async function (assert) { - this.server.create('job', { failedPlacements: true, createAllocations: false }); - await this.store.findAll('job'); - - const job = this.store.peekAll('job').get('firstObject'); - await job.reload(); - - this.set('job', job); - - await render(hbs` - ) - `); - - const failedEvaluation = this.get('job.evaluations') - .filterBy('hasPlacementFailures') - .sortBy('modifyIndex') - .reverse() - .get('firstObject'); - const failedTGAllocs = failedEvaluation.get('failedTGAllocs'); - - assert.ok(find('[data-test-placement-failures]'), 'Placement failures section found'); - - const taskGroupLabels = findAll('[data-test-placement-failure-task-group]').map((title) => - title.textContent.trim() - ); - - failedTGAllocs.forEach((alloc) => { - const name = alloc.get('name'); - assert.ok( - taskGroupLabels.find((label) => label.includes(name)), - `${name} included in placement failures list` - ); - assert.ok( - taskGroupLabels.find((label) => label.includes(alloc.get('coalescedFailures') + 1)), - 'The number of unplaced allocs = CoalescedFailures + 1' - ); + hooks.beforeEach(function () { + fragmentSerializerInitializer(this.owner); + window.localStorage.clear(); + this.store = this.owner.lookup('service:store'); + this.server = startMirage(); + this.server.create('namespace'); }); - await componentA11yAudit(this.element, assert); - }); + hooks.afterEach(function () { + this.server.shutdown(); + window.localStorage.clear(); + }); - test('when the job has no placement failures, the placement failures section is gone', async function (assert) { - this.server.create('job', { noFailedPlacements: true, createAllocations: false }); - await this.store.findAll('job'); + test('when the job has placement failures, they are called out', async function (assert) { + this.server.create('job', { + failedPlacements: true, + createAllocations: false, + }); + await this.store.findAll('job'); - const job = this.store.peekAll('job').get('firstObject'); - await job.reload(); + const job = this.store.peekAll('job').get('firstObject'); + await job.reload(); - this.set('job', job); + this.set('job', job); - await render(hbs` + await render(hbs` ) `); - assert.notOk(find('[data-test-placement-failures]'), 'Placement failures section not found'); - }); -}); + const failedEvaluation = this.get('job.evaluations') + .filterBy('hasPlacementFailures') + .sortBy('modifyIndex') + .reverse() + .get('firstObject'); + const failedTGAllocs = failedEvaluation.get('failedTGAllocs'); + + assert.ok( + find('[data-test-placement-failures]'), + 'Placement failures section found' + ); + + const taskGroupLabels = findAll( + '[data-test-placement-failure-task-group]' + ).map((title) => title.textContent.trim()); + + failedTGAllocs.forEach((alloc) => { + const name = alloc.get('name'); + assert.ok( + taskGroupLabels.find((label) => label.includes(name)), + `${name} included in placement failures list` + ); + assert.ok( + taskGroupLabels.find((label) => + label.includes(alloc.get('coalescedFailures') + 1) + ), + 'The number of unplaced allocs = CoalescedFailures + 1' + ); + }); + + await componentA11yAudit(this.element, assert); + }); + + test('when the job has no placement failures, the placement failures section is gone', async function (assert) { + this.server.create('job', { + noFailedPlacements: true, + createAllocations: false, + }); + await this.store.findAll('job'); + + const job = this.store.peekAll('job').get('firstObject'); + await job.reload(); + + this.set('job', job); + + await render(hbs` + ) + `); + + assert.notOk( + find('[data-test-placement-failures]'), + 'Placement failures section not found' + ); + }); + } +); diff --git a/ui/tests/integration/components/job-page/parts/summary-test.js b/ui/tests/integration/components/job-page/parts/summary-test.js index cde24e3ae..e9373650b 100644 --- a/ui/tests/integration/components/job-page/parts/summary-test.js +++ b/ui/tests/integration/components/job-page/parts/summary-test.js @@ -35,8 +35,14 @@ module('Integration | Component | job-page/parts/summary', function (hooks) { `); - assert.ok(find('[data-test-children-status-bar]'), 'Children status bar found'); - assert.notOk(find('[data-test-allocation-status-bar]'), 'Allocation status bar not found'); + assert.ok( + find('[data-test-children-status-bar]'), + 'Children status bar found' + ); + assert.notOk( + find('[data-test-allocation-status-bar]'), + 'Allocation status bar not found' + ); await componentA11yAudit(this.element, assert); }); @@ -54,8 +60,14 @@ module('Integration | Component | job-page/parts/summary', function (hooks) { `); - assert.ok(find('[data-test-allocation-status-bar]'), 'Allocation status bar found'); - assert.notOk(find('[data-test-children-status-bar]'), 'Children status bar not found'); + assert.ok( + find('[data-test-allocation-status-bar]'), + 'Allocation status bar found' + ); + assert.notOk( + find('[data-test-children-status-bar]'), + 'Children status bar not found' + ); await componentA11yAudit(this.element, assert); }); @@ -176,7 +188,10 @@ module('Integration | Component | job-page/parts/summary', function (hooks) { await click('[data-test-accordion-toggle]'); - assert.ok(find('[data-test-allocation-status-bar]'), 'Allocation bar still existed'); + assert.ok( + find('[data-test-allocation-status-bar]'), + 'Allocation bar still existed' + ); assert.ok( find('.inline-chart [data-test-allocation-status-bar]'), 'Allocation bar is rendered in an inline-chart container' @@ -198,7 +213,10 @@ module('Integration | Component | job-page/parts/summary', function (hooks) { `); - assert.notOk(window.localStorage.nomadExpandJobSummary, 'No value in localStorage yet'); + assert.notOk( + window.localStorage.nomadExpandJobSummary, + 'No value in localStorage yet' + ); await click('[data-test-accordion-toggle]'); assert.equal( @@ -223,7 +241,10 @@ module('Integration | Component | job-page/parts/summary', function (hooks) { `); - assert.ok(find('[data-test-allocation-status-bar]'), 'Allocation bar still existed'); + assert.ok( + find('[data-test-allocation-status-bar]'), + 'Allocation bar still existed' + ); assert.ok( find('.inline-chart [data-test-allocation-status-bar]'), 'Allocation bar is rendered in an inline-chart container' diff --git a/ui/tests/integration/components/job-page/parts/task-groups-test.js b/ui/tests/integration/components/job-page/parts/task-groups-test.js index 0e8130b20..b143b95a7 100644 --- a/ui/tests/integration/components/job-page/parts/task-groups-test.js +++ b/ui/tests/integration/components/job-page/parts/task-groups-test.js @@ -6,46 +6,51 @@ import sinon from 'sinon'; import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage'; import { setupRenderingTest } from 'ember-qunit'; import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; -import { formatScheduledHertz, formatScheduledBytes } from 'nomad-ui/utils/units'; +import { + formatScheduledHertz, + formatScheduledBytes, +} from 'nomad-ui/utils/units'; -module('Integration | Component | job-page/parts/task-groups', function (hooks) { - setupRenderingTest(hooks); +module( + 'Integration | Component | job-page/parts/task-groups', + function (hooks) { + setupRenderingTest(hooks); - hooks.beforeEach(function () { - window.localStorage.clear(); - this.store = this.owner.lookup('service:store'); - this.server = startMirage(); - this.server.create('namespace'); - }); - - hooks.afterEach(function () { - this.server.shutdown(); - }); - - const props = (job, options = {}) => - assign( - { - job, - sortProperty: 'name', - sortDescending: true, - gotoTaskGroup: () => {}, - }, - options - ); - - test('the job detail page should list all task groups', async function (assert) { - this.server.create('job', { - createAllocations: false, + hooks.beforeEach(function () { + window.localStorage.clear(); + this.store = this.owner.lookup('service:store'); + this.server = startMirage(); + this.server.create('namespace'); }); - await this.store.findAll('job').then((jobs) => { - jobs.forEach((job) => job.reload()); + hooks.afterEach(function () { + this.server.shutdown(); }); - const job = this.store.peekAll('job').get('firstObject'); - this.setProperties(props(job)); + const props = (job, options = {}) => + assign( + { + job, + sortProperty: 'name', + sortDescending: true, + gotoTaskGroup: () => {}, + }, + options + ); - await render(hbs` + test('the job detail page should list all task groups', async function (assert) { + this.server.create('job', { + createAllocations: false, + }); + + await this.store.findAll('job').then((jobs) => { + jobs.forEach((job) => job.reload()); + }); + + const job = this.store.peekAll('job').get('firstObject'); + this.setProperties(props(job)); + + await render(hbs` `); - assert.equal( - findAll('[data-test-task-group]').length, - job.get('taskGroups.length'), - 'One row per task group' - ); + assert.equal( + findAll('[data-test-task-group]').length, + job.get('taskGroups.length'), + 'One row per task group' + ); - await componentA11yAudit(this.element, assert); - }); - - test('each row in the task group table should show basic information about the task group', async function (assert) { - this.server.create('job', { - createAllocations: false, + await componentA11yAudit(this.element, assert); }); - const job = await this.store.findAll('job').then(async (jobs) => { - return await jobs.get('firstObject').reload(); - }); + test('each row in the task group table should show basic information about the task group', async function (assert) { + this.server.create('job', { + createAllocations: false, + }); - const taskGroups = await job.get('taskGroups'); - const taskGroup = taskGroups.sortBy('name').reverse().get('firstObject'); + const job = await this.store.findAll('job').then(async (jobs) => { + return await jobs.get('firstObject').reload(); + }); - this.setProperties(props(job)); + const taskGroups = await job.get('taskGroups'); + const taskGroup = taskGroups.sortBy('name').reverse().get('firstObject'); - await render(hbs` + this.setProperties(props(job)); + + await render(hbs` `); - const taskGroupRow = find('[data-test-task-group]'); + const taskGroupRow = find('[data-test-task-group]'); - assert.equal( - taskGroupRow.querySelector('[data-test-task-group-name]').textContent.trim(), - taskGroup.get('name'), - 'Name' - ); - assert.equal( - taskGroupRow.querySelector('[data-test-task-group-count]').textContent.trim(), - taskGroup.get('count'), - 'Count' - ); - assert.equal( - taskGroupRow.querySelector('[data-test-task-group-volume]').textContent.trim(), - taskGroup.get('volumes.length') ? 'Yes' : '', - 'Volumes' - ); - assert.equal( - taskGroupRow.querySelector('[data-test-task-group-cpu]').textContent.trim(), - `${formatScheduledHertz(taskGroup.get('reservedCPU'), 'MHz')}`, - 'Reserved CPU' - ); - assert.equal( - taskGroupRow.querySelector('[data-test-task-group-mem]').textContent.trim(), - `${formatScheduledBytes(taskGroup.get('reservedMemory'), 'MiB')}`, - 'Reserved Memory' - ); - assert.equal( - taskGroupRow.querySelector('[data-test-task-group-disk]').textContent.trim(), - `${formatScheduledBytes(taskGroup.get('reservedEphemeralDisk'), 'MiB')}`, - 'Reserved Disk' - ); - }); - - test('gotoTaskGroup is called when task group rows are clicked', async function (assert) { - this.server.create('job', { - createAllocations: false, + assert.equal( + taskGroupRow + .querySelector('[data-test-task-group-name]') + .textContent.trim(), + taskGroup.get('name'), + 'Name' + ); + assert.equal( + taskGroupRow + .querySelector('[data-test-task-group-count]') + .textContent.trim(), + taskGroup.get('count'), + 'Count' + ); + assert.equal( + taskGroupRow + .querySelector('[data-test-task-group-volume]') + .textContent.trim(), + taskGroup.get('volumes.length') ? 'Yes' : '', + 'Volumes' + ); + assert.equal( + taskGroupRow + .querySelector('[data-test-task-group-cpu]') + .textContent.trim(), + `${formatScheduledHertz(taskGroup.get('reservedCPU'), 'MHz')}`, + 'Reserved CPU' + ); + assert.equal( + taskGroupRow + .querySelector('[data-test-task-group-mem]') + .textContent.trim(), + `${formatScheduledBytes(taskGroup.get('reservedMemory'), 'MiB')}`, + 'Reserved Memory' + ); + assert.equal( + taskGroupRow + .querySelector('[data-test-task-group-disk]') + .textContent.trim(), + `${formatScheduledBytes( + taskGroup.get('reservedEphemeralDisk'), + 'MiB' + )}`, + 'Reserved Disk' + ); }); - const job = await this.store.findAll('job').then(async (jobs) => { - return await jobs.get('firstObject').reload(); - }); + test('gotoTaskGroup is called when task group rows are clicked', async function (assert) { + this.server.create('job', { + createAllocations: false, + }); - const taskGroupSpy = sinon.spy(); + const job = await this.store.findAll('job').then(async (jobs) => { + return await jobs.get('firstObject').reload(); + }); - const taskGroups = await job.get('taskGroups'); - const taskGroup = taskGroups.sortBy('name').reverse().get('firstObject'); + const taskGroupSpy = sinon.spy(); - this.setProperties( - props(job, { - gotoTaskGroup: taskGroupSpy, - }) - ); + const taskGroups = await job.get('taskGroups'); + const taskGroup = taskGroups.sortBy('name').reverse().get('firstObject'); - await render(hbs` + this.setProperties( + props(job, { + gotoTaskGroup: taskGroupSpy, + }) + ); + + await render(hbs` `); - await click('[data-test-task-group]'); + await click('[data-test-task-group]'); - assert.ok( - taskGroupSpy.withArgs(taskGroup).calledOnce, - 'Clicking the task group row calls the gotoTaskGroup action' - ); - }); -}); + assert.ok( + taskGroupSpy.withArgs(taskGroup).calledOnce, + 'Clicking the task group row calls the gotoTaskGroup action' + ); + }); + } +); diff --git a/ui/tests/integration/components/job-page/periodic-test.js b/ui/tests/integration/components/job-page/periodic-test.js index 8d13c8f42..98473239a 100644 --- a/ui/tests/integration/components/job-page/periodic-test.js +++ b/ui/tests/integration/components/job-page/periodic-test.js @@ -91,11 +91,19 @@ module('Integration | Component | job-page/periodic', function (hooks) { 'POST URL was correct' ); - assert.equal(server.db.jobs.length, currentJobCount + 1, 'POST request was made'); + assert.equal( + server.db.jobs.length, + currentJobCount + 1, + 'POST request was made' + ); }); test('Clicking force launch without proper permissions shows an error message', async function (assert) { - this.server.pretender.post('/v1/job/:id/periodic/force', () => [403, {}, '']); + this.server.pretender.post('/v1/job/:id/periodic/force', () => [ + 403, + {}, + '', + ]); this.server.create('job', 'periodic', { id: 'parent', @@ -127,7 +135,10 @@ module('Integration | Component | job-page/periodic', function (hooks) { await click('[data-test-job-error-close]'); - assert.notOk(find('[data-test-job-error-title]'), 'Error message is dismissable'); + assert.notOk( + find('[data-test-job-error-title]'), + 'Error message is dismissable' + ); }); test('Stopping a job sends a delete request for the job', async function (assert) { @@ -223,7 +234,9 @@ module('Integration | Component | job-page/periodic', function (hooks) { assert.equal( find('[data-test-job-submit-time]').textContent, - moment(job.get('children.firstObject.submitTime')).format('MMM DD HH:mm:ss ZZ'), + moment(job.get('children.firstObject.submitTime')).format( + 'MMM DD HH:mm:ss ZZ' + ), 'The new periodic job launch is in the children list' ); }); diff --git a/ui/tests/integration/components/job-page/service-test.js b/ui/tests/integration/components/job-page/service-test.js index e423a2dcf..efc9fe904 100644 --- a/ui/tests/integration/components/job-page/service-test.js +++ b/ui/tests/integration/components/job-page/service-test.js @@ -4,7 +4,13 @@ import { setupRenderingTest } from 'ember-qunit'; import { click, find, render } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage'; -import { startJob, stopJob, expectError, expectDeleteRequest, expectStartRequest } from './helpers'; +import { + startJob, + stopJob, + expectError, + expectDeleteRequest, + expectStartRequest, +} from './helpers'; import Job from 'nomad-ui/tests/pages/jobs/detail'; import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer'; import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; @@ -124,11 +130,17 @@ module('Integration | Component | job-page/service', function (hooks) { this.setProperties(commonProperties(job)); await render(commonTemplate); - const allocation = this.server.db.allocations.sortBy('modifyIndex').reverse()[0]; + const allocation = this.server.db.allocations + .sortBy('modifyIndex') + .reverse()[0]; const allocationRow = Job.allocations.objectAt(0); assert.equal(allocationRow.shortId, allocation.id.split('-')[0], 'ID'); - assert.equal(allocationRow.taskGroup, allocation.taskGroup, 'Task Group name'); + assert.equal( + allocationRow.taskGroup, + allocation.taskGroup, + 'Task Group name' + ); await componentA11yAudit(this.element, assert); }); @@ -196,7 +208,11 @@ module('Integration | Component | job-page/service', function (hooks) { }); test('When promoting the active deployment fails, an error is shown', async function (assert) { - this.server.pretender.post('/v1/deployment/promote/:id', () => [403, {}, '']); + this.server.pretender.post('/v1/deployment/promote/:id', () => [ + 403, + {}, + '', + ]); this.server.create('node'); const mirageJob = makeMirageJob(this.server, { activeDeployment: true }); @@ -224,7 +240,10 @@ module('Integration | Component | job-page/service', function (hooks) { await click('[data-test-job-error-close]'); - assert.notOk(find('[data-test-job-error-title]'), 'Error message is dismissable'); + assert.notOk( + find('[data-test-job-error-title]'), + 'Error message is dismissable' + ); }); test('Active deployment can be failed', async function (assert) { @@ -282,6 +301,9 @@ module('Integration | Component | job-page/service', function (hooks) { await click('[data-test-job-error-close]'); - assert.notOk(find('[data-test-job-error-title]'), 'Error message is dismissable'); + assert.notOk( + find('[data-test-job-error-title]'), + 'Error message is dismissable' + ); }); }); diff --git a/ui/tests/integration/components/lifecycle-chart-test.js b/ui/tests/integration/components/lifecycle-chart-test.js index 9e892ce6d..22355d595 100644 --- a/ui/tests/integration/components/lifecycle-chart-test.js +++ b/ui/tests/integration/components/lifecycle-chart-test.js @@ -158,7 +158,8 @@ module('Integration | Component | lifecycle-chart', function (hooks) { activePhaseNames: [], }, { - testName: 'poststart ephemeral task states affect main phase active state', + testName: + 'poststart ephemeral task states affect main phase active state', runningTaskNames: ['poststart ephemeral'], activePhaseNames: ['Main'], }, @@ -184,7 +185,10 @@ module('Integration | Component | lifecycle-chart', function (hooks) { if (activePhaseNames.includes(Phase.name)) { assert.ok(Phase.isActive, `expected ${Phase.name} not to be active`); } else { - assert.notOk(Phase.isActive, `expected ${Phase.name} phase not to be active`); + assert.notOk( + Phase.isActive, + `expected ${Phase.name} phase not to be active` + ); } }); }); diff --git a/ui/tests/integration/components/line-chart-test.js b/ui/tests/integration/components/line-chart-test.js index 73516c1a4..3fc239b02 100644 --- a/ui/tests/integration/components/line-chart-test.js +++ b/ui/tests/integration/components/line-chart-test.js @@ -1,4 +1,10 @@ -import { find, findAll, click, render, triggerEvent } from '@ember/test-helpers'; +import { + find, + findAll, + click, + render, + triggerEvent, +} from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; @@ -245,9 +251,14 @@ module('Integration | Component | line-chart', function (hooks) { // MouseEnter triggers the tooltip visibility await triggerEvent(hoverTarget, 'mouseenter'); // MouseMove positions the tooltip and updates the active datum - await triggerEvent(hoverTarget, 'mousemove', { clientX: xOffset + interval * 1 + 5 }); + await triggerEvent(hoverTarget, 'mousemove', { + clientX: xOffset + interval * 1 + 5, + }); assert.equal(findAll('[data-test-chart-tooltip] li').length, 1); - assert.equal(find('[data-test-chart-tooltip] .label').textContent.trim(), this.data[1].series); + assert.equal( + find('[data-test-chart-tooltip] .label').textContent.trim(), + this.data[1].series + ); assert.equal( find('[data-test-chart-tooltip] .value').textContent.trim(), series2.find((d) => d.x === 2).y @@ -261,11 +272,19 @@ module('Integration | Component | line-chart', function (hooks) { { label: this.data[0].series, value: series1.find((d) => d.x === 3).y }, { label: this.data[1].series, value: series2.find((d) => d.x === 2).y }, ]; - await triggerEvent(hoverTarget, 'mousemove', { clientX: xOffset + interval * 1.5 + 5 }); + await triggerEvent(hoverTarget, 'mousemove', { + clientX: xOffset + interval * 1.5 + 5, + }); assert.equal(findAll('[data-test-chart-tooltip] li').length, 2); findAll('[data-test-chart-tooltip] li').forEach((tooltipEntry, index) => { - assert.equal(tooltipEntry.querySelector('.label').textContent.trim(), expected[index].label); - assert.equal(tooltipEntry.querySelector('.value').textContent.trim(), expected[index].value); + assert.equal( + tooltipEntry.querySelector('.label').textContent.trim(), + expected[index].label + ); + assert.equal( + tooltipEntry.querySelector('.value').textContent.trim(), + expected[index].value + ); }); }); }); diff --git a/ui/tests/integration/components/list-pagination-test.js b/ui/tests/integration/components/list-pagination-test.js index 294606db3..14015af1e 100644 --- a/ui/tests/integration/components/list-pagination-test.js +++ b/ui/tests/integration/components/list-pagination-test.js @@ -37,8 +37,14 @@ module('Integration | Component | list pagination', function (hooks) { `); - assert.ok(!findAll('.first').length, 'On the first page, there is no first link'); - assert.ok(!findAll('.prev').length, 'On the first page, there is no prev link'); + assert.notOk( + findAll('.first').length, + 'On the first page, there is no first link' + ); + assert.notOk( + findAll('.prev').length, + 'On the first page, there is no prev link' + ); await componentA11yAudit(this.element, assert); assert.equal( @@ -48,11 +54,20 @@ module('Integration | Component | list pagination', function (hooks) { ); for (var pageNumber = 1; pageNumber <= defaults.spread + 1; pageNumber++) { - assert.ok(findAll(`.link.page-${pageNumber}`).length, `Page link includes ${pageNumber}`); + assert.ok( + findAll(`.link.page-${pageNumber}`).length, + `Page link includes ${pageNumber}` + ); } - assert.ok(findAll('.next').length, 'While not on the last page, there is a next link'); - assert.ok(findAll('.last').length, 'While not on the last page, there is a last link'); + assert.ok( + findAll('.next').length, + 'While not on the last page, there is a next link' + ); + assert.ok( + findAll('.last').length, + 'While not on the last page, there is a last link' + ); await componentA11yAudit(this.element, assert); assert.ok( @@ -82,7 +97,11 @@ module('Integration | Component | list pagination', function (hooks) { `); const totalPages = Math.ceil(this.source.length / this.size); - assert.equal(find('.page-info').textContent, `1 of ${totalPages}`, `${totalPages} total pages`); + assert.equal( + find('.page-info').textContent, + `1 of ${totalPages}`, + `${totalPages} total pages` + ); }); test('the spread property', async function (assert) { @@ -150,10 +169,10 @@ module('Integration | Component | list pagination', function (hooks) { `); - assert.ok(!findAll('.first').length, 'No first link'); - assert.ok(!findAll('.prev').length, 'No prev link'); - assert.ok(!findAll('.next').length, 'No next link'); - assert.ok(!findAll('.last').length, 'No last link'); + assert.notOk(findAll('.first').length, 'No first link'); + assert.notOk(findAll('.prev').length, 'No prev link'); + assert.notOk(findAll('.next').length, 'No next link'); + assert.notOk(findAll('.last').length, 'No last link'); assert.equal(find('.page-info').textContent, '1 of 1', 'Only one page'); assert.equal( @@ -191,15 +210,26 @@ module('Integration | Component | list pagination', function (hooks) { assert.ok(findAll('.prev').length, 'Prev page still exists'); assert.ok(findAll('.next').length, 'Next page still exists'); assert.ok(findAll('.last').length, 'Last page still exists'); - assert.equal(findAll('.link').length, totalPages, 'Every page gets a page link'); + assert.equal( + findAll('.link').length, + totalPages, + 'Every page gets a page link' + ); for (var pageNumber = 1; pageNumber < totalPages; pageNumber++) { - assert.ok(findAll(`.link.page-${pageNumber}`).length, `Page link for ${pageNumber} exists`); + assert.ok( + findAll(`.link.page-${pageNumber}`).length, + `Page link for ${pageNumber} exists` + ); } }); function testSpread(assert) { const { spread, currentPage } = this.getProperties('spread', 'currentPage'); - for (var pageNumber = currentPage - spread; pageNumber <= currentPage + spread; pageNumber++) { + for ( + var pageNumber = currentPage - spread; + pageNumber <= currentPage + spread; + pageNumber++ + ) { assert.ok( findAll(`.link.page-${pageNumber}`).length, `Page links for currentPage (${currentPage}) +/- spread of ${spread} (${pageNumber})` diff --git a/ui/tests/integration/components/list-table-test.js b/ui/tests/integration/components/list-table-test.js index 858caccb1..96711bd71 100644 --- a/ui/tests/integration/components/list-table-test.js +++ b/ui/tests/integration/components/list-table-test.js @@ -30,7 +30,11 @@ module('Integration | Component | list table', function (hooks) { `); assert.ok(findAll('.head').length, 'Table head is rendered'); - assert.equal(find('.head').tagName.toLowerCase(), 'thead', 'Table head is a thead element'); + assert.equal( + find('.head').tagName.toLowerCase(), + 'thead', + 'Table head is a thead element' + ); }); // tbody @@ -54,18 +58,42 @@ module('Integration | Component | list table', function (hooks) { `); assert.ok(findAll('.body').length, 'Table body is rendered'); - assert.equal(find('.body').tagName.toLowerCase(), 'tbody', 'Table body is a tbody element'); + assert.equal( + find('.body').tagName.toLowerCase(), + 'tbody', + 'Table body is a tbody element' + ); - assert.equal(findAll('.item').length, this.get('source.length'), 'Each item gets its own row'); + assert.equal( + findAll('.item').length, + this.get('source.length'), + 'Each item gets its own row' + ); // list-table is not responsible for sorting, only dispatching sort events. The table is still // rendered in index-order. this.source.forEach((item, index) => { const $item = this.element.querySelectorAll('.item')[index]; - assert.equal($item.querySelectorAll('td')[0].innerHTML.trim(), item.firstName, 'First name'); - assert.equal($item.querySelectorAll('td')[1].innerHTML.trim(), item.lastName, 'Last name'); - assert.equal($item.querySelectorAll('td')[2].innerHTML.trim(), item.age, 'Age'); - assert.equal($item.querySelectorAll('td')[3].innerHTML.trim(), index, 'Index'); + assert.equal( + $item.querySelectorAll('td')[0].innerHTML.trim(), + item.firstName, + 'First name' + ); + assert.equal( + $item.querySelectorAll('td')[1].innerHTML.trim(), + item.lastName, + 'Last name' + ); + assert.equal( + $item.querySelectorAll('td')[2].innerHTML.trim(), + item.age, + 'Age' + ); + assert.equal( + $item.querySelectorAll('td')[3].innerHTML.trim(), + index, + 'Index' + ); }); await componentA11yAudit(this.element, assert); diff --git a/ui/tests/integration/components/multi-select-dropdown-test.js b/ui/tests/integration/components/multi-select-dropdown-test.js index f53182afc..303630c7b 100644 --- a/ui/tests/integration/components/multi-select-dropdown-test.js +++ b/ui/tests/integration/components/multi-select-dropdown-test.js @@ -1,4 +1,11 @@ -import { findAll, find, click, focus, render, triggerKeyEvent } from '@ember/test-helpers'; +import { + findAll, + find, + click, + focus, + render, + triggerKeyEvent, +} from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import sinon from 'sinon'; @@ -47,7 +54,10 @@ module('Integration | Component | multi-select dropdown', function (hooks) { props.label, 'Trigger is appropriately labeled' ); - assert.notOk(find('[data-test-dropdown-options]'), 'Options are not rendered'); + assert.notOk( + find('[data-test-dropdown-options]'), + 'Options are not rendered' + ); await componentA11yAudit(this.element, assert); }); @@ -59,12 +69,18 @@ module('Integration | Component | multi-select dropdown', function (hooks) { await click('[data-test-dropdown-trigger]'); - await assert.ok(find('[data-test-dropdown-options]'), 'Options are shown now'); + await assert.ok( + find('[data-test-dropdown-options]'), + 'Options are shown now' + ); await componentA11yAudit(this.element, assert); await click('[data-test-dropdown-trigger]'); - assert.notOk(find('[data-test-dropdown-options]'), 'Options are hidden after clicking again'); + assert.notOk( + find('[data-test-dropdown-options]'), + 'Options are hidden after clicking again' + ); }); test('all options are shown in the options dropdown, each with a checkbox input', async function (assert) { @@ -81,8 +97,15 @@ module('Integration | Component | multi-select dropdown', function (hooks) { ); findAll('[data-test-dropdown-option]').forEach((optionEl, index) => { const label = props.options[index].label; - assert.equal(optionEl.textContent.trim(), label, `Correct label for ${label}`); - assert.ok(optionEl.querySelector('input[type="checkbox"]'), 'Option contains a checkbox'); + assert.equal( + optionEl.textContent.trim(), + label, + `Correct label for ${label}` + ); + assert.ok( + optionEl.querySelector('input[type="checkbox"]'), + 'Option contains a checkbox' + ); }); }); @@ -114,7 +137,8 @@ module('Integration | Component | multi-select dropdown', function (hooks) { 'The count is shown' ); assert.equal( - find('[data-test-dropdown-trigger] [data-test-dropdown-count]').textContent, + find('[data-test-dropdown-trigger] [data-test-dropdown-count]') + .textContent, props.selection.length, 'The count is accurate' ); @@ -135,8 +159,15 @@ module('Integration | Component | multi-select dropdown', function (hooks) { await render(commonTemplate); await focus('[data-test-dropdown-trigger]'); - assert.notOk(find('[data-test-dropdown-options]'), 'Options are not shown on focus'); - await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN); + assert.notOk( + find('[data-test-dropdown-options]'), + 'Options are not shown on focus' + ); + await triggerKeyEvent( + '[data-test-dropdown-trigger]', + 'keydown', + ARROW_DOWN + ); assert.ok(find('[data-test-dropdown-options]'), 'Options are now shown'); assert.equal( document.activeElement, @@ -151,8 +182,16 @@ module('Integration | Component | multi-select dropdown', function (hooks) { await render(commonTemplate); await focus('[data-test-dropdown-trigger]'); - await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN); - await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN); + await triggerKeyEvent( + '[data-test-dropdown-trigger]', + 'keydown', + ARROW_DOWN + ); + await triggerKeyEvent( + '[data-test-dropdown-trigger]', + 'keydown', + ARROW_DOWN + ); assert.equal( document.activeElement, find('[data-test-dropdown-option]'), @@ -166,7 +205,11 @@ module('Integration | Component | multi-select dropdown', function (hooks) { await render(commonTemplate); await focus('[data-test-dropdown-trigger]'); - await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN); + await triggerKeyEvent( + '[data-test-dropdown-trigger]', + 'keydown', + ARROW_DOWN + ); await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', TAB); assert.equal( document.activeElement, @@ -222,7 +265,11 @@ module('Integration | Component | multi-select dropdown', function (hooks) { await triggerKeyEvent(option, 'keydown', ARROW_DOWN); if (index < lastIndex) { - assert.equal(document.activeElement, optionEls[index + 1], `Option ${index + 1} has focus`); + assert.equal( + document.activeElement, + optionEls[index + 1], + `Option ${index + 1} has focus` + ); } } @@ -261,7 +308,11 @@ module('Integration | Component | multi-select dropdown', function (hooks) { await click('[data-test-dropdown-trigger]'); findAll('[data-test-dropdown-option]').forEach((option) => { - assert.equal(parseInt(option.getAttribute('tabindex'), 10), 0, 'tabindex is zero'); + assert.equal( + parseInt(option.getAttribute('tabindex'), 10), + 0, + 'tabindex is zero' + ); }); }); @@ -274,7 +325,12 @@ module('Integration | Component | multi-select dropdown', function (hooks) { findAll('[data-test-dropdown-option]').forEach((option) => { assert.ok( - parseInt(option.querySelector('input[type="checkbox"]').getAttribute('tabindex'), 10) < 0, + parseInt( + option + .querySelector('input[type="checkbox"]') + .getAttribute('tabindex'), + 10 + ) < 0, 'tabindex is a negative value' ); }); @@ -286,11 +342,22 @@ module('Integration | Component | multi-select dropdown', function (hooks) { await render(commonTemplate); await focus('[data-test-dropdown-trigger]'); - await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN); - await triggerKeyEvent('[data-test-dropdown-trigger]', 'keydown', ARROW_DOWN); + await triggerKeyEvent( + '[data-test-dropdown-trigger]', + 'keydown', + ARROW_DOWN + ); + await triggerKeyEvent( + '[data-test-dropdown-trigger]', + 'keydown', + ARROW_DOWN + ); await triggerKeyEvent('[data-test-dropdown-option]', 'keydown', ESC); - assert.notOk(find('[data-test-dropdown-options]'), 'The options list is hidden once more'); + assert.notOk( + find('[data-test-dropdown-options]'), + 'The options list is hidden once more' + ); assert.equal( document.activeElement, find('[data-test-dropdown-trigger]'), @@ -305,7 +372,10 @@ module('Integration | Component | multi-select dropdown', function (hooks) { await render(commonTemplate); await click('[data-test-dropdown-trigger]'); - assert.ok(find('[data-test-dropdown-options]'), 'The dropdown is still shown'); + assert.ok( + find('[data-test-dropdown-options]'), + 'The dropdown is still shown' + ); assert.ok(find('[data-test-dropdown-empty]'), 'The empty state is shown'); assert.notOk(find('[data-test-dropdown-option]'), 'No options are shown'); await componentA11yAudit(this.element, assert); diff --git a/ui/tests/integration/components/page-layout-test.js b/ui/tests/integration/components/page-layout-test.js index 99b317183..d96df7043 100644 --- a/ui/tests/integration/components/page-layout-test.js +++ b/ui/tests/integration/components/page-layout-test.js @@ -25,7 +25,10 @@ module('Integration | Component | page layout', function (hooks) { ); await click('[data-test-header-gutter-toggle]'); - assert.ok(find('[data-test-gutter-menu]').classList.contains('is-open'), 'Gutter menu is open'); + assert.ok( + find('[data-test-gutter-menu]').classList.contains('is-open'), + 'Gutter menu is open' + ); await componentA11yAudit(this.element, assert); }); @@ -34,7 +37,10 @@ module('Integration | Component | page layout', function (hooks) { await click('[data-test-header-gutter-toggle]'); - assert.ok(find('[data-test-gutter-menu]').classList.contains('is-open'), 'Gutter menu is open'); + assert.ok( + find('[data-test-gutter-menu]').classList.contains('is-open'), + 'Gutter menu is open' + ); await click('[data-test-gutter-gutter-toggle]'); assert.notOk( @@ -48,7 +54,10 @@ module('Integration | Component | page layout', function (hooks) { await click('[data-test-header-gutter-toggle]'); - assert.ok(find('[data-test-gutter-menu]').classList.contains('is-open'), 'Gutter menu is open'); + assert.ok( + find('[data-test-gutter-menu]').classList.contains('is-open'), + 'Gutter menu is open' + ); await click('[data-test-gutter-backdrop]'); assert.notOk( diff --git a/ui/tests/integration/components/placement-failure-test.js b/ui/tests/integration/components/placement-failure-test.js index 322f51ea6..6bb12b3ad 100644 --- a/ui/tests/integration/components/placement-failure-test.js +++ b/ui/tests/integration/components/placement-failure-test.js @@ -29,12 +29,16 @@ module('Integration | Component | placement failures', function (hooks) { await render(commonTemplate); assert.equal( - cleanWhitespace(find('[data-test-placement-failure-task-group]').firstChild.wholeText), + cleanWhitespace( + find('[data-test-placement-failure-task-group]').firstChild.wholeText + ), name, 'Title is rendered with the name of the placement failure' ); assert.equal( - parseInt(find('[data-test-placement-failure-coalesced-failures]').textContent), + parseInt( + find('[data-test-placement-failure-coalesced-failures]').textContent + ), failures, 'Title is rendered correctly with a count of unplaced' ); @@ -78,7 +82,11 @@ module('Integration | Component | placement failures', function (hooks) { 1, 'Quota exhausted message shown' ); - assert.equal(findAll('[data-test-placement-failure-scores]').length, 1, 'Scores message shown'); + assert.equal( + findAll('[data-test-placement-failure-scores]').length, + 1, + 'Scores message shown' + ); await componentA11yAudit(this.element, assert); }); diff --git a/ui/tests/integration/components/plugin-allocation-row-test.js b/ui/tests/integration/components/plugin-allocation-row-test.js index c65efc87f..e8df8b327 100644 --- a/ui/tests/integration/components/plugin-allocation-row-test.js +++ b/ui/tests/integration/components/plugin-allocation-row-test.js @@ -21,7 +21,10 @@ module('Integration | Component | plugin allocation row', function (hooks) { }); test('Plugin allocation row immediately fetches the plugin allocation', async function (assert) { - const plugin = this.server.create('csi-plugin', { id: 'plugin', controllerRequired: true }); + const plugin = this.server.create('csi-plugin', { + id: 'plugin', + controllerRequired: true, + }); const storageController = plugin.controllers.models[0]; const pluginRecord = await this.store.find('plugin', 'csi/plugin'); @@ -34,15 +37,21 @@ module('Integration | Component | plugin allocation row', function (hooks) { `); - const allocationRequest = this.server.pretender.handledRequests.find((req) => - req.url.startsWith('/v1/allocation') + const allocationRequest = this.server.pretender.handledRequests.find( + (req) => req.url.startsWith('/v1/allocation') + ); + assert.equal( + allocationRequest.url, + `/v1/allocation/${storageController.allocID}` ); - assert.equal(allocationRequest.url, `/v1/allocation/${storageController.allocID}`); await componentA11yAudit(this.element, assert); }); test('After the plugin allocation row fetches the plugin allocation, allocation stats are fetched', async function (assert) { - const plugin = this.server.create('csi-plugin', { id: 'plugin', controllerRequired: true }); + const plugin = this.server.create('csi-plugin', { + id: 'plugin', + controllerRequired: true, + }); const storageController = plugin.controllers.models[0]; const pluginRecord = await this.store.find('plugin', 'csi/plugin'); @@ -57,7 +66,10 @@ module('Integration | Component | plugin allocation row', function (hooks) { const [statsRequest] = this.server.pretender.handledRequests.slice(-1); - assert.equal(statsRequest.url, `/v1/client/allocation/${storageController.allocID}/stats`); + assert.equal( + statsRequest.url, + `/v1/client/allocation/${storageController.allocID}/stats` + ); }); test('Setting a new plugin fetches the new plugin allocation', async function (assert) { @@ -80,11 +92,14 @@ module('Integration | Component | plugin allocation row', function (hooks) { `); - const allocationRequest = this.server.pretender.handledRequests.find((req) => - req.url.startsWith('/v1/allocation') + const allocationRequest = this.server.pretender.handledRequests.find( + (req) => req.url.startsWith('/v1/allocation') ); - assert.equal(allocationRequest.url, `/v1/allocation/${storageController.allocID}`); + assert.equal( + allocationRequest.url, + `/v1/allocation/${storageController.allocID}` + ); this.set('plugin', pluginRecord.get('controllers').toArray()[1]); await settled(); @@ -93,6 +108,9 @@ module('Integration | Component | plugin allocation row', function (hooks) { .filter((req) => req.url.startsWith('/v1/allocation')) .reverse()[0]; - assert.equal(latestAllocationRequest.url, `/v1/allocation/${storageController2.allocID}`); + assert.equal( + latestAllocationRequest.url, + `/v1/allocation/${storageController2.allocID}` + ); }); }); diff --git a/ui/tests/integration/components/primary-metric/allocation-test.js b/ui/tests/integration/components/primary-metric/allocation-test.js index 59fb23b12..1f3b122e3 100644 --- a/ui/tests/integration/components/primary-metric/allocation-test.js +++ b/ui/tests/integration/components/primary-metric/allocation-test.js @@ -23,7 +23,11 @@ module('Integration | Component | PrimaryMetric::Allocation', function (hooks) { this.server = startMirage(); this.server.create('namespace'); this.server.create('node'); - this.server.create('job', { groupsCount: 1, groupTaskCount: 3, createAllocations: false }); + this.server.create('job', { + groupsCount: 1, + groupTaskCount: 3, + createAllocations: false, + }); this.server.create('allocation'); }); @@ -41,7 +45,8 @@ module('Integration | Component | PrimaryMetric::Allocation', function (hooks) { await store.findAll('allocation'); }; - const findResource = (store) => store.peekAll('allocation').get('firstObject'); + const findResource = (store) => + store.peekAll('allocation').get('firstObject'); test('Must pass an accessibility audit', async function (assert) { await preload(this.store); diff --git a/ui/tests/integration/components/primary-metric/primary-metric.js b/ui/tests/integration/components/primary-metric/primary-metric.js index a20b5577a..ee1182381 100644 --- a/ui/tests/integration/components/primary-metric/primary-metric.js +++ b/ui/tests/integration/components/primary-metric/primary-metric.js @@ -35,8 +35,13 @@ export function setupPrimaryMetricMocks(hooks, tasks = []) { }, }); - this.owner.register('service:stats-trackers-registry', mockStatsTrackersRegistry); - this.statsTrackersRegistry = this.owner.lookup('service:stats-trackers-registry'); + this.owner.register( + 'service:stats-trackers-registry', + mockStatsTrackersRegistry + ); + this.statsTrackersRegistry = this.owner.lookup( + 'service:stats-trackers-registry' + ); }); } @@ -100,7 +105,8 @@ export function primaryMetric({ template, findResource, preload }) { await render(template); assert.ok( - this.getTrackerSpy.calledWith(resource) || this.getTrackerSpy.calledWith(resource.allocation), + this.getTrackerSpy.calledWith(resource) || + this.getTrackerSpy.calledWith(resource.allocation), 'Uses the tracker registry to get the tracker for the provided resource' ); }); @@ -115,7 +121,10 @@ export function primaryMetric({ template, findResource, preload }) { await render(template); - assert.ok(this.trackerPollSpy.calledOnce, 'The tracker is polled immediately'); + assert.ok( + this.trackerPollSpy.calledOnce, + 'The tracker is polled immediately' + ); }); test('A pause signal is sent to the tracker when the component is destroyed', async function (assert) { @@ -130,9 +139,15 @@ export function primaryMetric({ template, findResource, preload }) { this.setProperties({ resource, metric }); await render(template); - assert.notOk(trackerSignalPauseSpy.called, 'No pause signal has been sent yet'); + assert.notOk( + trackerSignalPauseSpy.called, + 'No pause signal has been sent yet' + ); await clearRender(); - assert.ok(trackerSignalPauseSpy.calledOnce, 'A pause signal is sent to the tracker'); + assert.ok( + trackerSignalPauseSpy.calledOnce, + 'A pause signal is sent to the tracker' + ); }); } diff --git a/ui/tests/integration/components/primary-metric/task-test.js b/ui/tests/integration/components/primary-metric/task-test.js index 957fd75ca..b388ebb65 100644 --- a/ui/tests/integration/components/primary-metric/task-test.js +++ b/ui/tests/integration/components/primary-metric/task-test.js @@ -51,7 +51,8 @@ module('Integration | Component | PrimaryMetric::Task', function (hooks) { await store.findAll('allocation'); }; - const findResource = (store) => store.peekAll('allocation').get('firstObject.states.firstObject'); + const findResource = (store) => + store.peekAll('allocation').get('firstObject.states.firstObject'); test('Must pass an accessibility audit', async function (assert) { await preload(this.store); diff --git a/ui/tests/integration/components/reschedule-event-timeline-test.js b/ui/tests/integration/components/reschedule-event-timeline-test.js index 5d8a76759..436a1437b 100644 --- a/ui/tests/integration/components/reschedule-event-timeline-test.js +++ b/ui/tests/integration/components/reschedule-event-timeline-test.js @@ -95,7 +95,10 @@ module('Integration | Component | reschedule event timeline', function (hooks) { find('[data-test-stop-warning]'), 'Stop warning is shown since the last allocation failed' ); - assert.notOk(find('[data-test-attempt-notice]'), 'Reschdule attempt notice is not shown'); + assert.notOk( + find('[data-test-attempt-notice]'), + 'Reschdule attempt notice is not shown' + ); await componentA11yAudit(this.element, assert); }); @@ -108,7 +111,9 @@ module('Integration | Component | reschedule event timeline', function (hooks) { rescheduleSuccess: false, }); - const lastAllocation = server.schema.allocations.findBy({ nextAllocation: undefined }); + const lastAllocation = server.schema.allocations.findBy({ + nextAllocation: undefined, + }); lastAllocation.update({ followupEvalId: server.create('evaluation', { waitUntil: moment().add(2, 'hours').toDate(), @@ -143,7 +148,9 @@ module('Integration | Component | reschedule event timeline', function (hooks) { await this.store.findAll('allocation'); - const allocation = this.store.peekAll('allocation').findBy('id', originalAllocation.id); + const allocation = this.store + .peekAll('allocation') + .findBy('id', originalAllocation.id); this.set('allocation', allocation); await render(commonTemplate); @@ -155,7 +162,9 @@ module('Integration | Component | reschedule event timeline', function (hooks) { ); assert.equal( - find('[data-test-allocation] [data-test-allocation-link]').textContent.trim(), + find( + '[data-test-allocation] [data-test-allocation-link]' + ).textContent.trim(), allocation.get('nextAllocation.shortId'), 'The next allocation item is for the correct allocation' ); diff --git a/ui/tests/integration/components/scale-events-accordion-test.js b/ui/tests/integration/components/scale-events-accordion-test.js index b0ee9fca4..9c4bbbd77 100644 --- a/ui/tests/integration/components/scale-events-accordion-test.js +++ b/ui/tests/integration/components/scale-events-accordion-test.js @@ -19,9 +19,14 @@ module('Integration | Component | scale-events-accordion', function (hooks) { this.taskGroupWithEvents = async function (events) { const job = this.server.create('job', { createAllocations: false }); const group = job.taskGroups.models[0]; - job.jobScale.taskGroupScales.models.findBy('name', group.name).update({ events }); + job.jobScale.taskGroupScales.models + .findBy('name', group.name) + .update({ events }); - const jobModel = await this.store.find('job', JSON.stringify([job.id, 'default'])); + const jobModel = await this.store.find( + 'job', + JSON.stringify([job.id, 'default']) + ); await jobModel.get('scaleState'); return jobModel.taskGroups.findBy('name', group.name); }; @@ -35,12 +40,17 @@ module('Integration | Component | scale-events-accordion', function (hooks) { test('it shows an accordion with an entry for each event', async function (assert) { const eventCount = 5; - const taskGroup = await this.taskGroupWithEvents(server.createList('scale-event', eventCount)); + const taskGroup = await this.taskGroupWithEvents( + server.createList('scale-event', eventCount) + ); this.set('events', taskGroup.scaleState.events); await render(commonTemplate); - assert.equal(findAll('[data-test-scale-events] [data-test-accordion-head]').length, eventCount); + assert.equal( + findAll('[data-test-scale-events] [data-test-accordion-head]').length, + eventCount + ); await componentA11yAudit(this.element, assert); }); @@ -59,7 +69,11 @@ module('Integration | Component | scale-events-accordion', function (hooks) { test('when an event has a count higher than previous count, a danger up arrow is shown', async function (assert) { const count = 5; const taskGroup = await this.taskGroupWithEvents( - server.createList('scale-event', 1, { count, previousCount: count - 1, error: false }) + server.createList('scale-event', 1, { + count, + previousCount: count - 1, + error: false, + }) ); this.set('events', taskGroup.scaleState.events); @@ -68,7 +82,9 @@ module('Integration | Component | scale-events-accordion', function (hooks) { assert.notOk(find('[data-test-error]')); assert.equal(find('[data-test-count]').textContent, count); assert.ok( - find('[data-test-count-icon]').querySelector('.icon').classList.contains('is-danger') + find('[data-test-count-icon]') + .querySelector('.icon') + .classList.contains('is-danger') ); await componentA11yAudit(this.element, assert); }); @@ -76,7 +92,11 @@ module('Integration | Component | scale-events-accordion', function (hooks) { test('when an event has a count lower than previous count, a primary down arrow is shown', async function (assert) { const count = 5; const taskGroup = await this.taskGroupWithEvents( - server.createList('scale-event', 1, { count, previousCount: count + 1, error: false }) + server.createList('scale-event', 1, { + count, + previousCount: count + 1, + error: false, + }) ); this.set('events', taskGroup.scaleState.events); @@ -85,7 +105,9 @@ module('Integration | Component | scale-events-accordion', function (hooks) { assert.notOk(find('[data-test-error]')); assert.equal(find('[data-test-count]').textContent, count); assert.ok( - find('[data-test-count-icon]').querySelector('.icon').classList.contains('is-primary') + find('[data-test-count-icon]') + .querySelector('.icon') + .classList.contains('is-primary') ); }); @@ -109,7 +131,9 @@ module('Integration | Component | scale-events-accordion', function (hooks) { await render(commonTemplate); - assert.ok(find('[data-test-accordion-toggle]').classList.contains('is-invisible')); + assert.ok( + find('[data-test-accordion-toggle]').classList.contains('is-invisible') + ); await componentA11yAudit(this.element, assert); }); @@ -122,7 +146,9 @@ module('Integration | Component | scale-events-accordion', function (hooks) { 'dot.separate.prop': 12, }, }; - const taskGroup = await this.taskGroupWithEvents(server.createList('scale-event', 1, { meta })); + const taskGroup = await this.taskGroupWithEvents( + server.createList('scale-event', 1, { meta }) + ); this.set('events', taskGroup.scaleState.events); await render(commonTemplate); diff --git a/ui/tests/integration/components/single-select-dropdown-test.js b/ui/tests/integration/components/single-select-dropdown-test.js index ddf279ac2..ed869e5fe 100644 --- a/ui/tests/integration/components/single-select-dropdown-test.js +++ b/ui/tests/integration/components/single-select-dropdown-test.js @@ -1,7 +1,10 @@ import { findAll, find, render } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { selectChoose, clickTrigger } from 'ember-power-select/test-support/helpers'; +import { + selectChoose, + clickTrigger, +} from 'ember-power-select/test-support/helpers'; import sinon from 'sinon'; import hbs from 'htmlbars-inline-precompile'; import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; @@ -36,7 +39,9 @@ module('Integration | Component | single-select dropdown', function (hooks) { this.setProperties(props); await render(commonTemplate); - assert.ok(find('.ember-power-select-trigger').textContent.includes(props.label)); + assert.ok( + find('.ember-power-select-trigger').textContent.includes(props.label) + ); assert.ok( find('.ember-power-select-trigger').textContent.includes( props.options.findBy('key', props.selection).label diff --git a/ui/tests/integration/components/stepper-input-test.js b/ui/tests/integration/components/stepper-input-test.js index baadae3b3..f14273a7f 100644 --- a/ui/tests/integration/components/stepper-input-test.js +++ b/ui/tests/integration/components/stepper-input-test.js @@ -1,4 +1,10 @@ -import { find, render, settled, triggerEvent, waitUntil } from '@ember/test-helpers'; +import { + find, + render, + settled, + triggerEvent, + waitUntil, +} from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; @@ -48,8 +54,12 @@ module('Integration | Component | stepper input', function (hooks) { assert.equal(StepperInput.input.value, this.value); assert.ok(StepperInput.decrement.isPresent); assert.ok(StepperInput.increment.isPresent); - assert.ok(StepperInput.decrement.classNames.split(' ').includes(this.classVariant)); - assert.ok(StepperInput.increment.classNames.split(' ').includes(this.classVariant)); + assert.ok( + StepperInput.decrement.classNames.split(' ').includes(this.classVariant) + ); + assert.ok( + StepperInput.increment.classNames.split(' ').includes(this.classVariant) + ); await componentA11yAudit(this.element, assert); }); @@ -184,7 +194,10 @@ module('Integration | Component | stepper input', function (hooks) { await render(commonTemplate); await StepperInput.input.focus(); - assert.equal(window.getSelection().toString().trim(), this.value.toString()); + assert.equal( + window.getSelection().toString().trim(), + this.value.toString() + ); }); test('entering a fractional value floors the value', async function (assert) { diff --git a/ui/tests/integration/components/streaming-file-test.js b/ui/tests/integration/components/streaming-file-test.js index e8b73d8c6..1ce29625e 100644 --- a/ui/tests/integration/components/streaming-file-test.js +++ b/ui/tests/integration/components/streaming-file-test.js @@ -125,7 +125,9 @@ module('Integration | Component | streaming file', function (hooks) { `); // Windows and Linux shortcut - await triggerKeyEvent('[data-test-output]', 'keydown', A_KEY, { ctrlKey: true }); + await triggerKeyEvent('[data-test-output]', 'keydown', A_KEY, { + ctrlKey: true, + }); assert.equal( window.getSelection().toString().trim(), find('[data-test-output]').textContent.trim() @@ -134,7 +136,9 @@ module('Integration | Component | streaming file', function (hooks) { window.getSelection().removeAllRanges(); // MacOS shortcut - await triggerKeyEvent('[data-test-output]', 'keydown', A_KEY, { metaKey: true }); + await triggerKeyEvent('[data-test-output]', 'keydown', A_KEY, { + metaKey: true, + }); assert.equal( window.getSelection().toString().trim(), find('[data-test-output]').textContent.trim() diff --git a/ui/tests/integration/components/task-group-row-test.js b/ui/tests/integration/components/task-group-row-test.js index d66d2dcbf..d5dea832a 100644 --- a/ui/tests/integration/components/task-group-row-test.js +++ b/ui/tests/integration/components/task-group-row-test.js @@ -181,7 +181,9 @@ module('Integration | Component | task group row', function (hooks) { assert.ok(find('[data-test-scale="increment"]:disabled')); assert.ok(find('[data-test-scale="decrement"]:disabled')); assert.ok( - find('[data-test-scale-controls]').getAttribute('aria-label').includes("You aren't allowed") + find('[data-test-scale-controls]') + .getAttribute('aria-label') + .includes("You aren't allowed") ); }); }); diff --git a/ui/tests/integration/components/task-log-test.js b/ui/tests/integration/components/task-log-test.js index a5398663a..6903433ff 100644 --- a/ui/tests/integration/components/task-log-test.js +++ b/ui/tests/integration/components/task-log-test.js @@ -45,10 +45,14 @@ module('Integration | Component | task log', function (hooks) { } if (frames === streamFrames) { - data = queryParams.plain ? frames[streamPointer] : logEncode(frames, streamPointer); + data = queryParams.plain + ? frames[streamPointer] + : logEncode(frames, streamPointer); streamPointer++; } else { - data = queryParams.plain ? frames.join('') : logEncode(frames, frames.length - 1); + data = queryParams.plain + ? frames.join('') + : logEncode(frames, frames.length - 1); } return [200, {}, data]; @@ -72,15 +76,23 @@ module('Integration | Component | task log', function (hooks) { run.later(run, run.cancelTimers, commonProps.interval); this.setProperties(commonProps); - await render(hbs``); + await render( + hbs`` + ); assert.ok(find('[data-test-log-action="stdout"]'), 'Stdout button'); assert.ok(find('[data-test-log-action="stderr"]'), 'Stderr button'); assert.ok(find('[data-test-log-action="head"]'), 'Head button'); assert.ok(find('[data-test-log-action="tail"]'), 'Tail button'); - assert.ok(find('[data-test-log-action="toggle-stream"]'), 'Stream toggle button'); + assert.ok( + find('[data-test-log-action="toggle-stream"]'), + 'Stream toggle button' + ); - assert.ok(find('[data-test-log-box].is-full-bleed.is-dark'), 'Body is full-bleed and dark'); + assert.ok( + find('[data-test-log-box].is-full-bleed.is-dark'), + 'Body is full-bleed and dark' + ); assert.ok( find('pre.cli-window'), @@ -94,11 +106,16 @@ module('Integration | Component | task log', function (hooks) { run.later(run, run.cancelTimers, commonProps.interval); this.setProperties(commonProps); - await render(hbs``); + await render( + hbs`` + ); - const logUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`); + const logUrlRegex = new RegExp( + `${HOST}/v1/client/fs/logs/${commonProps.allocation.id}` + ); assert.ok( - this.server.handledRequests.filter((req) => logUrlRegex.test(req.url)).length, + this.server.handledRequests.filter((req) => logUrlRegex.test(req.url)) + .length, 'Log requests were made' ); @@ -117,7 +134,9 @@ module('Integration | Component | task log', function (hooks) { run.later(run, run.cancelTimers, commonProps.interval); this.setProperties(commonProps); - await render(hbs``); + await render( + hbs`` + ); click('[data-test-log-action="head"]'); @@ -128,7 +147,11 @@ module('Integration | Component | task log', function (hooks) { ), 'Log head request was made' ); - assert.equal(find('[data-test-log-cli]').textContent, logHead[0], 'Head of the log is shown'); + assert.equal( + find('[data-test-log-cli]').textContent, + logHead[0], + 'Head of the log is shown' + ); }); test('Clicking Tail loads the log tail', async function (assert) { @@ -136,16 +159,24 @@ module('Integration | Component | task log', function (hooks) { run.later(run, run.cancelTimers, commonProps.interval); this.setProperties(commonProps); - await render(hbs``); + await render( + hbs`` + ); click('[data-test-log-action="tail"]'); await settled(); assert.ok( - this.server.handledRequests.find(({ queryParams: qp }) => qp.origin === 'end'), + this.server.handledRequests.find( + ({ queryParams: qp }) => qp.origin === 'end' + ), 'Log tail request was made' ); - assert.equal(find('[data-test-log-cli]').textContent, logTail[0], 'Tail of the log is shown'); + assert.equal( + find('[data-test-log-cli]').textContent, + logTail[0], + 'Tail of the log is shown' + ); }); test('Clicking toggleStream starts and stops the log stream', async function (assert) { @@ -162,7 +193,11 @@ module('Integration | Component | task log', function (hooks) { }, interval); await settled(); - assert.equal(find('[data-test-log-cli]').textContent, streamFrames[0], 'First frame loaded'); + assert.equal( + find('[data-test-log-cli]').textContent, + streamFrames[0], + 'First frame loaded' + ); run.later(() => { assert.equal( @@ -186,14 +221,18 @@ module('Integration | Component | task log', function (hooks) { run.later(run, run.cancelTimers, commonProps.interval); this.setProperties(commonProps); - await render(hbs``); + await render( + hbs`` + ); click('[data-test-log-action="stderr"]'); run.later(run, run.cancelTimers, commonProps.interval); await settled(); assert.ok( - this.server.handledRequests.filter((req) => req.queryParams.type === 'stderr').length, + this.server.handledRequests.filter( + (req) => req.queryParams.type === 'stderr' + ).length, 'stderr log requests were made' ); }); @@ -207,7 +246,9 @@ module('Integration | Component | task log', function (hooks) { }, interval * 2); this.setProperties(commonProps); - await render(hbs``); + await render( + hbs`` + ); assert.equal( find('[data-test-log-cli]').textContent, @@ -233,21 +274,27 @@ module('Integration | Component | task log', function (hooks) { @clientTimeout={{clientTimeout}} @serverTimeout={{serverTimeout}} />`); - const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`); + const clientUrlRegex = new RegExp( + `${HOST}/v1/client/fs/logs/${commonProps.allocation.id}` + ); assert.ok( - this.server.handledRequests.filter((req) => clientUrlRegex.test(req.url)).length, + this.server.handledRequests.filter((req) => clientUrlRegex.test(req.url)) + .length, 'Log request was initially made directly to the client' ); await settled(); const serverUrl = `/v1/client/fs/logs/${commonProps.allocation.id}`; assert.ok( - this.server.handledRequests.filter((req) => req.url.startsWith(serverUrl)).length, + this.server.handledRequests.filter((req) => req.url.startsWith(serverUrl)) + .length, 'Log request was later made to the server' ); assert.ok( - this.server.handledRequests.filter((req) => clientUrlRegex.test(req.url))[0].aborted, + this.server.handledRequests.filter((req) => + clientUrlRegex.test(req.url) + )[0].aborted, 'Client log request was aborted' ); }); @@ -274,20 +321,30 @@ module('Integration | Component | task log', function (hooks) { @clientTimeout={{clientTimeout}} @serverTimeout={{serverTimeout}} />`); - const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`); + const clientUrlRegex = new RegExp( + `${HOST}/v1/client/fs/logs/${commonProps.allocation.id}` + ); assert.ok( - this.server.handledRequests.filter((req) => clientUrlRegex.test(req.url)).length, + this.server.handledRequests.filter((req) => clientUrlRegex.test(req.url)) + .length, 'Log request was initially made directly to the client' ); const serverUrl = `/v1/client/fs/logs/${commonProps.allocation.id}`; assert.ok( - this.server.handledRequests.filter((req) => req.url.startsWith(serverUrl)).length, + this.server.handledRequests.filter((req) => req.url.startsWith(serverUrl)) + .length, 'Log request was later made to the server' ); - assert.ok(find('[data-test-connection-error]'), 'An error message is shown'); + assert.ok( + find('[data-test-connection-error]'), + 'An error message is shown' + ); await click('[data-test-connection-error-dismiss]'); - assert.notOk(find('[data-test-connection-error]'), 'The error message is dismissable'); + assert.notOk( + find('[data-test-connection-error]'), + 'The error message is dismissable' + ); await componentA11yAudit(this.element, assert); }); @@ -313,7 +370,9 @@ module('Integration | Component | task log', function (hooks) { @clientTimeout={{clientTimeout}} @serverTimeout={{serverTimeout}} />`); - const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`); + const clientUrlRegex = new RegExp( + `${HOST}/v1/client/fs/logs/${commonProps.allocation.id}` + ); const clientRequests = this.server.handledRequests.filter((req) => clientUrlRegex.test(req.url) ); @@ -334,7 +393,10 @@ module('Integration | Component | task log', function (hooks) { 'Server request for stderr' ); - assert.notOk(find('[data-test-connection-error]'), 'An error message is not shown'); + assert.notOk( + find('[data-test-connection-error]'), + 'An error message is not shown' + ); }); test('The log streaming mode is persisted in localStorage', async function (assert) { @@ -343,13 +405,19 @@ module('Integration | Component | task log', function (hooks) { run.later(run, run.cancelTimers, commonProps.interval); this.setProperties(commonProps); - await render(hbs``); + await render( + hbs`` + ); assert.ok( - this.server.handledRequests.filter((req) => req.queryParams.type === 'stderr').length + this.server.handledRequests.filter( + (req) => req.queryParams.type === 'stderr' + ).length ); assert.notOk( - this.server.handledRequests.filter((req) => req.queryParams.type === 'stdout').length + this.server.handledRequests.filter( + (req) => req.queryParams.type === 'stdout' + ).length ); click('[data-test-log-action="stdout"]'); @@ -357,7 +425,9 @@ module('Integration | Component | task log', function (hooks) { await settled(); assert.ok( - this.server.handledRequests.filter((req) => req.queryParams.type === 'stdout').length + this.server.handledRequests.filter( + (req) => req.queryParams.type === 'stdout' + ).length ); assert.equal(window.localStorage.nomadLogMode, JSON.stringify('stdout')); }); diff --git a/ui/tests/integration/components/topo-viz-test.js b/ui/tests/integration/components/topo-viz-test.js index bd33b2fc4..ca69170ed 100644 --- a/ui/tests/integration/components/topo-viz-test.js +++ b/ui/tests/integration/components/topo-viz-test.js @@ -99,7 +99,10 @@ module('Integration | Component | TopoViz', function (hooks) { await TopoViz.datacenters[0].nodes[0].memoryRects[0].select(); assert.ok(this.onAllocationSelect.calledOnce); - assert.equal(this.onAllocationSelect.getCall(0).args[0], this.allocations[0]); + assert.equal( + this.onAllocationSelect.getCall(0).args[0], + this.allocations[0] + ); assert.ok(this.onNodeSelect.calledOnce); await TopoViz.datacenters[0].nodes[0].memoryRects[0].select(); @@ -133,7 +136,9 @@ module('Integration | Component | TopoViz', function (hooks) { }); const selectedAllocations = this.allocations.filter( - (alloc) => alloc.belongsTo('job').id() === 'job1' && alloc.taskGroupName === 'group' + (alloc) => + alloc.belongsTo('job').id() === 'job1' && + alloc.taskGroupName === 'group' ); await render(commonTemplate); @@ -143,11 +148,17 @@ module('Integration | Component | TopoViz', function (hooks) { await TopoViz.datacenters[0].nodes[0].memoryRects[0].select(); assert.ok(TopoViz.allocationAssociationsArePresent); - assert.equal(TopoViz.allocationAssociations.length, selectedAllocations.length * 2); + assert.equal( + TopoViz.allocationAssociations.length, + selectedAllocations.length * 2 + ); // Lines get redrawn when the window resizes; make sure the lines persist. await triggerEvent(window, 'resize'); - assert.equal(TopoViz.allocationAssociations.length, selectedAllocations.length * 2); + assert.equal( + TopoViz.allocationAssociations.length, + selectedAllocations.length * 2 + ); await TopoViz.datacenters[0].nodes[0].memoryRects[0].select(); assert.notOk(TopoViz.allocationAssociationsArePresent); diff --git a/ui/tests/integration/components/topo-viz/datacenter-test.js b/ui/tests/integration/components/topo-viz/datacenter-test.js index eadf8488c..246a75e73 100644 --- a/ui/tests/integration/components/topo-viz/datacenter-test.js +++ b/ui/tests/integration/components/topo-viz/datacenter-test.js @@ -106,11 +106,16 @@ module('Integration | Component | TopoViz::Datacenter', function (hooks) { const cpuTotal = this.datacenter.nodes.reduce(sumBy('cpu'), 0); assert.ok(TopoVizDatacenter.label.includes(this.datacenter.name)); - assert.ok(TopoVizDatacenter.label.includes(`${this.datacenter.nodes.length} Nodes`)); + assert.ok( + TopoVizDatacenter.label.includes(`${this.datacenter.nodes.length} Nodes`) + ); assert.ok(TopoVizDatacenter.label.includes(`${allocs.length} Allocs`)); assert.ok( TopoVizDatacenter.label.includes( - `${formatBytes(memoryReserved, 'MiB')}/${formatBytes(memoryTotal, 'MiB')}` + `${formatBytes(memoryReserved, 'MiB')}/${formatBytes( + memoryTotal, + 'MiB' + )}` ) ); assert.ok( @@ -126,7 +131,10 @@ module('Integration | Component | TopoViz::Datacenter', function (hooks) { isSingleColumn: true, datacenter: { name: 'dc1', - nodes: [nodeGen('node-1', 'dc1', 1000, 500), nodeGen('node-2', 'dc1', 1000, 500)], + nodes: [ + nodeGen('node-1', 'dc1', 1000, 500), + nodeGen('node-2', 'dc1', 1000, 500), + ], }, }) ); @@ -150,7 +158,9 @@ module('Integration | Component | TopoViz::Datacenter', function (hooks) { }, datacenter: { name: 'dc1', - nodes: [nodeGen('node-1', 'dc1', 1000, 500, [{ memory: 100, cpu: 300 }])], + nodes: [ + nodeGen('node-1', 'dc1', 1000, 500, [{ memory: 100, cpu: 300 }]), + ], }, }) ); @@ -165,7 +175,11 @@ module('Integration | Component | TopoViz::Datacenter', function (hooks) { assert.ok(this.onNodeSelect.calledWith(this.datacenter.nodes[0])); await TopoVizNode.memoryRects[0].select(); - assert.ok(this.onAllocationSelect.calledWith(this.datacenter.nodes[0].allocations[0])); + assert.ok( + this.onAllocationSelect.calledWith( + this.datacenter.nodes[0].allocations[0] + ) + ); }); }); }); diff --git a/ui/tests/integration/components/topo-viz/node-test.js b/ui/tests/integration/components/topo-viz/node-test.js index 4d642a39f..bad5e32f4 100644 --- a/ui/tests/integration/components/topo-viz/node-test.js +++ b/ui/tests/integration/components/topo-viz/node-test.js @@ -8,7 +8,10 @@ import faker from 'nomad-ui/mirage/faker'; import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; import { setupMirage } from 'ember-cli-mirage/test-support'; import topoVisNodePageObject from 'nomad-ui/tests/pages/components/topo-viz/node'; -import { formatScheduledBytes, formatScheduledHertz } from 'nomad-ui/utils/units'; +import { + formatScheduledBytes, + formatScheduledHertz, +} from 'nomad-ui/utils/units'; const TopoVizNode = create(topoVisNodePageObject()); @@ -108,11 +111,21 @@ module('Integration | Component | TopoViz::Node', function (hooks) { assert.ok(TopoVizNode.label.includes(node.node.name)); assert.ok( TopoVizNode.label.includes( - `${this.node.allocations.filterBy('allocation.isScheduled').length} Allocs` + `${ + this.node.allocations.filterBy('allocation.isScheduled').length + } Allocs` + ) + ); + assert.ok( + TopoVizNode.label.includes( + `${formatScheduledBytes(this.node.memory, 'MiB')}` + ) + ); + assert.ok( + TopoVizNode.label.includes( + `${formatScheduledHertz(this.node.cpu, 'MHz')}` ) ); - assert.ok(TopoVizNode.label.includes(`${formatScheduledBytes(this.node.memory, 'MiB')}`)); - assert.ok(TopoVizNode.label.includes(`${formatScheduledHertz(this.node.cpu, 'MHz')}`)); }); test('the status icon indicates when the node is draining', async function (assert) { @@ -325,7 +338,10 @@ module('Integration | Component | TopoViz::Node', function (hooks) { this.onAllocationFocus.getCall(0).args[0].allocation, this.node.allocations[0].allocation ); - assert.equal(this.onAllocationFocus.getCall(0).args[1], findAll('[data-test-memory-rect]')[0]); + assert.equal( + this.onAllocationFocus.getCall(0).args[1], + findAll('[data-test-memory-rect]')[0] + ); await TopoVizNode.cpuRects[1].hover(); assert.equal(this.onAllocationFocus.callCount, 2); @@ -333,7 +349,10 @@ module('Integration | Component | TopoViz::Node', function (hooks) { this.onAllocationFocus.getCall(1).args[0].allocation, this.node.allocations[1].allocation ); - assert.equal(this.onAllocationFocus.getCall(1).args[1], findAll('[data-test-cpu-rect]')[1]); + assert.equal( + this.onAllocationFocus.getCall(1).args[1], + findAll('[data-test-cpu-rect]')[1] + ); }); test('leaving the entire node will call onAllocationBlur, which allows for the tooltip transitions', async function (assert) { diff --git a/ui/tests/integration/components/two-step-button-test.js b/ui/tests/integration/components/two-step-button-test.js index 0cb9627f4..23ae9584c 100644 --- a/ui/tests/integration/components/two-step-button-test.js +++ b/ui/tests/integration/components/two-step-button-test.js @@ -41,11 +41,18 @@ module('Integration | Component | two step button', function (hooks) { await render(commonTemplate); assert.ok(find('[data-test-idle-button]'), 'Idle button is rendered'); - assert.equal(TwoStepButton.idleText, props.idleText, 'Button is labeled correctly'); + assert.equal( + TwoStepButton.idleText, + props.idleText, + 'Button is labeled correctly' + ); assert.notOk(find('[data-test-cancel-button]'), 'No cancel button yet'); assert.notOk(find('[data-test-confirm-button]'), 'No confirm button yet'); - assert.notOk(find('[data-test-confirmation-message]'), 'No confirmation message yet'); + assert.notOk( + find('[data-test-confirmation-message]'), + 'No confirmation message yet' + ); await componentA11yAudit(this.element, assert); }); @@ -58,10 +65,18 @@ module('Integration | Component | two step button', function (hooks) { await TwoStepButton.idle(); assert.ok(find('[data-test-cancel-button]'), 'Cancel button is rendered'); - assert.equal(TwoStepButton.cancelText, props.cancelText, 'Button is labeled correctly'); + assert.equal( + TwoStepButton.cancelText, + props.cancelText, + 'Button is labeled correctly' + ); assert.ok(find('[data-test-confirm-button]'), 'Confirm button is rendered'); - assert.equal(TwoStepButton.confirmText, props.confirmText, 'Button is labeled correctly'); + assert.equal( + TwoStepButton.confirmText, + props.confirmText, + 'Button is labeled correctly' + ); assert.equal( TwoStepButton.confirmationMessage, @@ -108,8 +123,14 @@ module('Integration | Component | two step button', function (hooks) { await TwoStepButton.idle(); assert.ok(TwoStepButton.cancelIsDisabled, 'The cancel button is disabled'); - assert.ok(TwoStepButton.confirmIsDisabled, 'The confirm button is disabled'); - assert.ok(TwoStepButton.isRunning, 'The confirm button is in a loading state'); + assert.ok( + TwoStepButton.confirmIsDisabled, + 'The confirm button is disabled' + ); + assert.ok( + TwoStepButton.isRunning, + 'The confirm button is in a loading state' + ); await componentA11yAudit(this.element, assert); }); @@ -166,7 +187,10 @@ module('Integration | Component | two step button', function (hooks) { assert.ok(TwoStepButton.isDisabled, 'The idle button is disabled'); await TwoStepButton.idle(); - assert.ok(find('[data-test-idle-button]'), 'Still in the idle state after clicking'); + assert.ok( + find('[data-test-idle-button]'), + 'Still in the idle state after clicking' + ); await componentA11yAudit(this.element, assert); }); diff --git a/ui/tests/integration/util/exec-command-editor-xterm-adapter-test.js b/ui/tests/integration/util/exec-command-editor-xterm-adapter-test.js index dd23d7b88..24cf2bb27 100644 --- a/ui/tests/integration/util/exec-command-editor-xterm-adapter-test.js +++ b/ui/tests/integration/util/exec-command-editor-xterm-adapter-test.js @@ -6,114 +6,126 @@ import hbs from 'htmlbars-inline-precompile'; import { Terminal } from 'xterm'; import KEYS from 'nomad-ui/utils/keys'; -module('Integration | Utility | exec-command-editor-xterm-adapter', function (hooks) { - setupRenderingTest(hooks); +module( + 'Integration | Utility | exec-command-editor-xterm-adapter', + function (hooks) { + setupRenderingTest(hooks); - test('it can wrap to a previous line while backspacing', async function (assert) { - let done = assert.async(); + test('it can wrap to a previous line while backspacing', async function (assert) { + let done = assert.async(); - await render(hbs` + await render(hbs`
`); - let terminal = new Terminal({ cols: 10 }); - terminal.open(document.getElementById('terminal')); + let terminal = new Terminal({ cols: 10 }); + terminal.open(document.getElementById('terminal')); - terminal.write('/bin/long-command'); + terminal.write('/bin/long-command'); - new ExecCommandEditorXtermAdapter( - terminal, - (command) => { - assert.equal(command, '/bin/long'); - done(); - }, - '/bin/long-command' - ); + new ExecCommandEditorXtermAdapter( + terminal, + (command) => { + assert.equal(command, '/bin/long'); + done(); + }, + '/bin/long-command' + ); - await terminal.simulateCommandDataEvent(KEYS.DELETE); - await terminal.simulateCommandDataEvent(KEYS.DELETE); - await terminal.simulateCommandDataEvent(KEYS.DELETE); - await terminal.simulateCommandDataEvent(KEYS.DELETE); - await terminal.simulateCommandDataEvent(KEYS.DELETE); - await terminal.simulateCommandDataEvent(KEYS.DELETE); - await terminal.simulateCommandDataEvent(KEYS.DELETE); - await terminal.simulateCommandDataEvent(KEYS.DELETE); + await terminal.simulateCommandDataEvent(KEYS.DELETE); + await terminal.simulateCommandDataEvent(KEYS.DELETE); + await terminal.simulateCommandDataEvent(KEYS.DELETE); + await terminal.simulateCommandDataEvent(KEYS.DELETE); + await terminal.simulateCommandDataEvent(KEYS.DELETE); + await terminal.simulateCommandDataEvent(KEYS.DELETE); + await terminal.simulateCommandDataEvent(KEYS.DELETE); + await terminal.simulateCommandDataEvent(KEYS.DELETE); - await settled(); + await settled(); - assert.equal(terminal.buffer.active.getLine(0).translateToString().trim(), '/bin/long'); + assert.equal( + terminal.buffer.active.getLine(0).translateToString().trim(), + '/bin/long' + ); - await terminal.simulateCommandDataEvent(KEYS.ENTER); - }); + await terminal.simulateCommandDataEvent(KEYS.ENTER); + }); - test('it ignores arrow keys and unprintable characters other than ^U', async function (assert) { - let done = assert.async(); + test('it ignores arrow keys and unprintable characters other than ^U', async function (assert) { + let done = assert.async(); - await render(hbs` + await render(hbs`
`); - let terminal = new Terminal({ cols: 72 }); - terminal.open(document.getElementById('terminal')); + let terminal = new Terminal({ cols: 72 }); + terminal.open(document.getElementById('terminal')); - terminal.write('/bin/bash'); + terminal.write('/bin/bash'); - new ExecCommandEditorXtermAdapter( - terminal, - (command) => { - assert.equal(command, '/bin/bash!'); - done(); - }, - '/bin/bash' - ); + new ExecCommandEditorXtermAdapter( + terminal, + (command) => { + assert.equal(command, '/bin/bash!'); + done(); + }, + '/bin/bash' + ); - await terminal.simulateCommandDataEvent(KEYS.RIGHT_ARROW); - await terminal.simulateCommandDataEvent(KEYS.RIGHT_ARROW); - await terminal.simulateCommandDataEvent(KEYS.LEFT_ARROW); - await terminal.simulateCommandDataEvent(KEYS.UP_ARROW); - await terminal.simulateCommandDataEvent(KEYS.UP_ARROW); - await terminal.simulateCommandDataEvent(KEYS.DOWN_ARROW); - await terminal.simulateCommandDataEvent(KEYS.CONTROL_A); - await terminal.simulateCommandDataEvent('!'); + await terminal.simulateCommandDataEvent(KEYS.RIGHT_ARROW); + await terminal.simulateCommandDataEvent(KEYS.RIGHT_ARROW); + await terminal.simulateCommandDataEvent(KEYS.LEFT_ARROW); + await terminal.simulateCommandDataEvent(KEYS.UP_ARROW); + await terminal.simulateCommandDataEvent(KEYS.UP_ARROW); + await terminal.simulateCommandDataEvent(KEYS.DOWN_ARROW); + await terminal.simulateCommandDataEvent(KEYS.CONTROL_A); + await terminal.simulateCommandDataEvent('!'); - await settled(); + await settled(); - assert.equal(terminal.buffer.active.cursorY, 0); - assert.equal(terminal.buffer.active.cursorX, 10); + assert.equal(terminal.buffer.active.cursorY, 0); + assert.equal(terminal.buffer.active.cursorX, 10); - assert.equal(terminal.buffer.active.getLine(0).translateToString().trim(), '/bin/bash!'); + assert.equal( + terminal.buffer.active.getLine(0).translateToString().trim(), + '/bin/bash!' + ); - await terminal.simulateCommandDataEvent(KEYS.ENTER); - }); + await terminal.simulateCommandDataEvent(KEYS.ENTER); + }); - test('it supports typing ^U to delete the entire command', async function (assert) { - let done = assert.async(); + test('it supports typing ^U to delete the entire command', async function (assert) { + let done = assert.async(); - await render(hbs` + await render(hbs`
`); - let terminal = new Terminal({ cols: 10 }); - terminal.open(document.getElementById('terminal')); + let terminal = new Terminal({ cols: 10 }); + terminal.open(document.getElementById('terminal')); - terminal.write('to-delete'); + terminal.write('to-delete'); - new ExecCommandEditorXtermAdapter( - terminal, - (command) => { - assert.equal(command, '!'); - done(); - }, - 'to-delete' - ); + new ExecCommandEditorXtermAdapter( + terminal, + (command) => { + assert.equal(command, '!'); + done(); + }, + 'to-delete' + ); - await terminal.simulateCommandDataEvent(KEYS.CONTROL_U); + await terminal.simulateCommandDataEvent(KEYS.CONTROL_U); - await settled(); + await settled(); - assert.equal(terminal.buffer.active.getLine(0).translateToString().trim(), ''); + assert.equal( + terminal.buffer.active.getLine(0).translateToString().trim(), + '' + ); - await terminal.simulateCommandDataEvent('!'); - await terminal.simulateCommandDataEvent(KEYS.ENTER); - }); -}); + await terminal.simulateCommandDataEvent('!'); + await terminal.simulateCommandDataEvent(KEYS.ENTER); + }); + } +); diff --git a/ui/tests/integration/util/exec-socket-xterm-adapter-test.js b/ui/tests/integration/util/exec-socket-xterm-adapter-test.js index 61701ce81..d1fb7b70d 100644 --- a/ui/tests/integration/util/exec-socket-xterm-adapter-test.js +++ b/ui/tests/integration/util/exec-socket-xterm-adapter-test.js @@ -25,7 +25,10 @@ module('Integration | Utility | exec-socket-xterm-adapter', function (hooks) { send(message) { if (firstMessage) { firstMessage = false; - assert.deepEqual(message, JSON.stringify({ version: 1, auth_token: 'mysecrettoken' })); + assert.deepEqual( + message, + JSON.stringify({ version: 1, auth_token: 'mysecrettoken' }) + ); mockSocket.onclose(); done(); } @@ -54,7 +57,10 @@ module('Integration | Utility | exec-socket-xterm-adapter', function (hooks) { send(message) { if (firstMessage) { firstMessage = false; - assert.deepEqual(message, JSON.stringify({ version: 1, auth_token: '' })); + assert.deepEqual( + message, + JSON.stringify({ version: 1, auth_token: '' }) + ); mockSocket.onclose(); done(); } @@ -114,7 +120,9 @@ module('Integration | Utility | exec-socket-xterm-adapter', function (hooks) { send(message) { assert.deepEqual( message, - JSON.stringify({ tty_size: { width: terminal.cols, height: terminal.rows } }) + JSON.stringify({ + tty_size: { width: terminal.cols, height: terminal.rows }, + }) ); mockSocket.onclose(); done(); @@ -176,7 +184,10 @@ module('Integration | Utility | exec-socket-xterm-adapter', function (hooks) { await settled(); - assert.equal(terminal.buffer.active.getLine(0).translateToString().trim(), 'sh-3.2 🥳$'); + assert.equal( + terminal.buffer.active.getLine(0).translateToString().trim(), + 'sh-3.2 🥳$' + ); mockSocket.onclose(); }); diff --git a/ui/tests/pages/allocations/detail.js b/ui/tests/pages/allocations/detail.js index b08b90eb8..cabc44672 100644 --- a/ui/tests/pages/allocations/detail.js +++ b/ui/tests/pages/allocations/detail.js @@ -81,7 +81,10 @@ export default create({ }, preempted: isPresent('[data-test-preemptions]'), - ...allocations('[data-test-preemptions] [data-test-allocation]', 'preemptions'), + ...allocations( + '[data-test-preemptions] [data-test-allocation]', + 'preemptions' + ), ports: collection('[data-test-allocation-port]', { name: text('[data-test-allocation-port-name]'), diff --git a/ui/tests/pages/clients/detail.js b/ui/tests/pages/clients/detail.js index 95e11866a..366e1242d 100644 --- a/ui/tests/pages/clients/detail.js +++ b/ui/tests/pages/clients/detail.js @@ -28,7 +28,10 @@ export default create({ }), statusDefinition: text('[data-test-status-definition]'), - statusDecorationClass: attribute('class', '[data-test-status-definition] .status-text'), + statusDecorationClass: attribute( + 'class', + '[data-test-status-definition] .status-text' + ), addressDefinition: text('[data-test-address-definition]'), datacenterDefinition: text('[data-test-datacenter-definition]'), @@ -62,10 +65,13 @@ export default create({ metaTable: isPresent('[data-test-meta]'), emptyMetaMessage: isPresent('[data-test-empty-meta-message]'), - metaAttributes: collection('[data-test-meta] [data-test-attributes-section]', { - key: text('[data-test-key]'), - value: text('[data-test-value]'), - }), + metaAttributes: collection( + '[data-test-meta] [data-test-attributes-section]', + { + key: text('[data-test-key]'), + value: text('[data-test-value]'), + } + ), error: { isShown: isPresent('[data-test-error]'), @@ -88,22 +94,28 @@ export default create({ permissions: text('[data-test-permissions]'), }), - driverHeads: collection('[data-test-driver-status] [data-test-accordion-head]', { - name: text('[data-test-name]'), - detected: text('[data-test-detected]'), - lastUpdated: text('[data-test-last-updated]'), - healthIsShown: isPresent('[data-test-health]'), - health: text('[data-test-health]'), - healthClass: attribute('class', '[data-test-health] .color-swatch'), + driverHeads: collection( + '[data-test-driver-status] [data-test-accordion-head]', + { + name: text('[data-test-name]'), + detected: text('[data-test-detected]'), + lastUpdated: text('[data-test-last-updated]'), + healthIsShown: isPresent('[data-test-health]'), + health: text('[data-test-health]'), + healthClass: attribute('class', '[data-test-health] .color-swatch'), - toggle: clickable('[data-test-accordion-toggle]'), - }), + toggle: clickable('[data-test-accordion-toggle]'), + } + ), - driverBodies: collection('[data-test-driver-status] [data-test-accordion-body]', { - description: text('[data-test-health-description]'), - descriptionIsShown: isPresent('[data-test-health-description]'), - attributesAreShown: isPresent('[data-test-driver-attributes]'), - }), + driverBodies: collection( + '[data-test-driver-status] [data-test-accordion-body]', + { + description: text('[data-test-health-description]'), + descriptionIsShown: isPresent('[data-test-health-description]'), + attributesAreShown: isPresent('[data-test-driver-attributes]'), + } + ), drainDetails: { scope: '[data-test-drain-details]', @@ -163,7 +175,13 @@ export default create({ eligibilityError: notification('[data-test-eligibility-error]'), stopDrainError: notification('[data-test-stop-drain-error]'), drainError: notification('[data-test-drain-error]'), - drainStoppedNotification: notification('[data-test-drain-stopped-notification]'), - drainUpdatedNotification: notification('[data-test-drain-updated-notification]'), - drainCompleteNotification: notification('[data-test-drain-complete-notification]'), + drainStoppedNotification: notification( + '[data-test-drain-stopped-notification]' + ), + drainUpdatedNotification: notification( + '[data-test-drain-updated-notification]' + ), + drainCompleteNotification: notification( + '[data-test-drain-complete-notification]' + ), }); diff --git a/ui/tests/pages/clients/monitor.js b/ui/tests/pages/clients/monitor.js index 4ec32bef8..828fd84e3 100644 --- a/ui/tests/pages/clients/monitor.js +++ b/ui/tests/pages/clients/monitor.js @@ -1,6 +1,15 @@ -import { create, clickable, isPresent, text, visitable } from 'ember-cli-page-object'; +import { + create, + clickable, + isPresent, + text, + visitable, +} from 'ember-cli-page-object'; import { run } from '@ember/runloop'; -import { selectOpen, selectOpenChoose } from '../../utils/ember-power-select-extensions'; +import { + selectOpen, + selectOpenChoose, +} from '../../utils/ember-power-select-extensions'; export default create({ visit: visitable('/clients/:id/monitor'), diff --git a/ui/tests/pages/components/allocations.js b/ui/tests/pages/components/allocations.js index 2fa853d07..6f152a4ee 100644 --- a/ui/tests/pages/components/allocations.js +++ b/ui/tests/pages/components/allocations.js @@ -1,7 +1,16 @@ -import { attribute, collection, clickable, isPresent, text } from 'ember-cli-page-object'; +import { + attribute, + collection, + clickable, + isPresent, + text, +} from 'ember-cli-page-object'; import { singularize } from 'ember-inflector'; -export default function (selector = '[data-test-allocation]', propKey = 'allocations') { +export default function ( + selector = '[data-test-allocation]', + propKey = 'allocations' +) { const lookupKey = `${singularize(propKey)}For`; // Remove the bracket notation const attr = selector.substring(1, selector.length - 1); @@ -11,7 +20,10 @@ export default function (selector = '[data-test-allocation]', propKey = 'allocat id: attribute(attr), shortId: text('[data-test-short-id]'), createTime: text('[data-test-create-time]'), - createTooltip: attribute('aria-label', '[data-test-create-time] .tooltip'), + createTooltip: attribute( + 'aria-label', + '[data-test-create-time] .tooltip' + ), modifyTime: text('[data-test-modify-time]'), health: text('[data-test-health]'), status: text('[data-test-client-status]'), @@ -25,7 +37,9 @@ export default function (selector = '[data-test-allocation]', propKey = 'allocat cpuTooltip: attribute('aria-label', '[data-test-cpu] .tooltip'), mem: text('[data-test-mem]'), memTooltip: attribute('aria-label', '[data-test-mem] .tooltip'), - rescheduled: isPresent('[data-test-indicators] [data-test-icon="reschedule"]'), + rescheduled: isPresent( + '[data-test-indicators] [data-test-icon="reschedule"]' + ), visit: clickable('[data-test-short-id] a'), visitRow: clickable(), diff --git a/ui/tests/pages/components/facet.js b/ui/tests/pages/components/facet.js index 1de11a942..a5ce8a77b 100644 --- a/ui/tests/pages/components/facet.js +++ b/ui/tests/pages/components/facet.js @@ -1,5 +1,8 @@ import { clickable, collection, text, attribute } from 'ember-cli-page-object'; -import { selectChoose, clickTrigger } from 'ember-power-select/test-support/helpers'; +import { + selectChoose, + clickTrigger, +} from 'ember-power-select/test-support/helpers'; export const multiFacet = (scope) => ({ scope, diff --git a/ui/tests/pages/components/page-size-select.js b/ui/tests/pages/components/page-size-select.js index 51d09cbfc..3ea9f3747 100644 --- a/ui/tests/pages/components/page-size-select.js +++ b/ui/tests/pages/components/page-size-select.js @@ -1,9 +1,15 @@ import { clickable, collection, isPresent, text } from 'ember-cli-page-object'; export default () => ({ - isPresent: isPresent('[data-test-page-size-select-parent] .ember-power-select-trigger'), - open: clickable('[data-test-page-size-select-parent] .ember-power-select-trigger'), - selectedOption: text('[data-test-page-size-select-parent] .ember-power-select-selected-item'), + isPresent: isPresent( + '[data-test-page-size-select-parent] .ember-power-select-trigger' + ), + open: clickable( + '[data-test-page-size-select-parent] .ember-power-select-trigger' + ), + selectedOption: text( + '[data-test-page-size-select-parent] .ember-power-select-selected-item' + ), options: collection('.ember-power-select-option', { testContainer: '#ember-testing', resetScope: true, diff --git a/ui/tests/pages/components/popover-menu.js b/ui/tests/pages/components/popover-menu.js index 37916de9e..8b38d2fb7 100644 --- a/ui/tests/pages/components/popover-menu.js +++ b/ui/tests/pages/components/popover-menu.js @@ -1,4 +1,10 @@ -import { clickable, focusable, isPresent, text, triggerable } from 'ember-cli-page-object'; +import { + clickable, + focusable, + isPresent, + text, + triggerable, +} from 'ember-cli-page-object'; const ARROW_DOWN = 40; const ESC = 27; diff --git a/ui/tests/pages/components/recommendation-card.js b/ui/tests/pages/components/recommendation-card.js index 23c6b6c9f..5be7a7855 100644 --- a/ui/tests/pages/components/recommendation-card.js +++ b/ui/tests/pages/components/recommendation-card.js @@ -1,4 +1,10 @@ -import { attribute, collection, hasClass, isPresent, text } from 'ember-cli-page-object'; +import { + attribute, + collection, + hasClass, + isPresent, + text, +} from 'ember-cli-page-object'; import { getter } from 'ember-cli-page-object/macros'; import toggle from 'nomad-ui/tests/pages/components/toggle'; diff --git a/ui/tests/pages/components/toggle.js b/ui/tests/pages/components/toggle.js index ac45ada49..3db03a46f 100644 --- a/ui/tests/pages/components/toggle.js +++ b/ui/tests/pages/components/toggle.js @@ -1,4 +1,11 @@ -import { attribute, property, clickable, hasClass, isPresent, text } from 'ember-cli-page-object'; +import { + attribute, + property, + clickable, + hasClass, + isPresent, + text, +} from 'ember-cli-page-object'; export default (scope) => ({ scope, diff --git a/ui/tests/pages/components/topo-viz.js b/ui/tests/pages/components/topo-viz.js index 832302ceb..455a084c4 100644 --- a/ui/tests/pages/components/topo-viz.js +++ b/ui/tests/pages/components/topo-viz.js @@ -4,8 +4,13 @@ import TopoVizDatacenter from './topo-viz/datacenter'; export default (scope) => ({ scope, - datacenters: collection('[data-test-topo-viz-datacenter]', TopoVizDatacenter()), + datacenters: collection( + '[data-test-topo-viz-datacenter]', + TopoVizDatacenter() + ), - allocationAssociationsArePresent: isPresent('[data-test-allocation-associations]'), + allocationAssociationsArePresent: isPresent( + '[data-test-allocation-associations]' + ), allocationAssociations: collection('[data-test-allocation-association]'), }); diff --git a/ui/tests/pages/components/two-step-button.js b/ui/tests/pages/components/two-step-button.js index 4d6314389..403689e4b 100644 --- a/ui/tests/pages/components/two-step-button.js +++ b/ui/tests/pages/components/two-step-button.js @@ -1,4 +1,10 @@ -import { attribute, clickable, hasClass, isPresent, text } from 'ember-cli-page-object'; +import { + attribute, + clickable, + hasClass, + isPresent, + text, +} from 'ember-cli-page-object'; export default (scope) => ({ scope, diff --git a/ui/tests/pages/exec.js b/ui/tests/pages/exec.js index a0b59222a..a9b8358a7 100644 --- a/ui/tests/pages/exec.js +++ b/ui/tests/pages/exec.js @@ -40,7 +40,9 @@ export default create({ terminal: { scope: '.xterm-helper-textarea', - pressEnter: triggerable('keydown', '', { eventProperties: { keyCode: 13 } }), + pressEnter: triggerable('keydown', '', { + eventProperties: { keyCode: 13 }, + }), }, jobDead: { diff --git a/ui/tests/pages/jobs/detail.js b/ui/tests/pages/jobs/detail.js index e82fc6f83..aaefaf6e0 100644 --- a/ui/tests/pages/jobs/detail.js +++ b/ui/tests/pages/jobs/detail.js @@ -7,7 +7,7 @@ import { isPresent, property, text, - visitable, + visitable } from 'ember-cli-page-object'; import allocations from 'nomad-ui/tests/pages/components/allocations'; @@ -22,14 +22,17 @@ export default create({ tabs: collection('[data-test-tab]', { id: attribute('data-test-tab'), - visit: clickable('a'), + visit: clickable('a') }), tabFor(id) { return this.tabs.toArray().findBy('id', id); }, - recommendations: collection('[data-test-recommendation-accordion]', recommendationAccordion), + recommendations: collection( + '[data-test-recommendation-accordion]', + recommendationAccordion + ), stop: twoStepButton('[data-test-stop]'), start: twoStepButton('[data-test-start]'), @@ -41,22 +44,22 @@ export default create({ scope: '[data-test-exec-button]', isDisabled: property('disabled'), hasTooltip: hasClass('tooltip'), - tooltipText: attribute('aria-label'), + tooltipText: attribute('aria-label') }, incrementButton: { scope: '[data-test-scale-controls-increment]', - isDisabled: property('disabled'), + isDisabled: property('disabled') }, dispatchButton: { scope: '[data-test-dispatch-button]', - isDisabled: property('disabled'), + isDisabled: property('disabled') }, stats: collection('[data-test-job-stat]', { id: attribute('data-test-job-stat'), - text: text(), + text: text() }), statFor(id) { @@ -65,7 +68,7 @@ export default create({ packStats: collection('[data-test-pack-stat]', { id: attribute('data-test-pack-stat'), - text: text(), + text: text() }), packStatFor(id) { @@ -79,10 +82,12 @@ export default create({ scope: '[data-test-accordion-head] [data-test-accordion-toggle]', click: clickable(), isDisabled: attribute('disabled'), - tooltip: attribute('aria-label'), - }, + tooltip: attribute('aria-label') + } }, - childrenSummary: jobClientStatusBar('[data-test-job-summary] [data-test-children-status-bar]'), + childrenSummary: jobClientStatusBar( + '[data-test-job-summary] [data-test-children-status-bar]' + ), allocationsSummary: jobClientStatusBar( '[data-test-job-summary] [data-test-allocation-status-bar]' ), @@ -93,7 +98,7 @@ export default create({ jobsHeader: { scope: '[data-test-jobs-header]', hasSubmitTime: isPresent('[data-test-jobs-submit-time-header]'), - hasNamespace: isPresent('[data-test-jobs-namespace-header]'), + hasNamespace: isPresent('[data-test-jobs-namespace-header]') }, jobs: collection('[data-test-job-row]', { @@ -108,17 +113,17 @@ export default create({ taskGroups: text('[data-test-job-task-groups]'), clickRow: clickable(), - clickName: clickable('[data-test-job-name] a'), + clickName: clickable('[data-test-job-name] a') }), error: { isPresent: isPresent('[data-test-error]'), title: text('[data-test-error-title]'), message: text('[data-test-error-message]'), - seekHelp: clickable('[data-test-error-message] a'), + seekHelp: clickable('[data-test-error-message] a') }, recentAllocationsEmptyState: { - headline: text('[data-test-empty-recent-allocations-headline]'), - }, + headline: text('[data-test-empty-recent-allocations-headline]') + } }); diff --git a/ui/tests/pages/jobs/job/evaluations.js b/ui/tests/pages/jobs/job/evaluations.js index 76529a5ff..884744f0a 100644 --- a/ui/tests/pages/jobs/job/evaluations.js +++ b/ui/tests/pages/jobs/job/evaluations.js @@ -1,4 +1,11 @@ -import { attribute, clickable, create, collection, text, visitable } from 'ember-cli-page-object'; +import { + attribute, + clickable, + create, + collection, + text, + visitable, +} from 'ember-cli-page-object'; import error from 'nomad-ui/tests/pages/components/error'; diff --git a/ui/tests/pages/jobs/job/task-group.js b/ui/tests/pages/jobs/job/task-group.js index 28bd08dbd..330569c8e 100644 --- a/ui/tests/pages/jobs/job/task-group.js +++ b/ui/tests/pages/jobs/job/task-group.js @@ -50,25 +50,36 @@ export default create({ }), hasScaleEvents: isPresent('[data-test-scale-events]'), - scaleEvents: collection('[data-test-scale-events] [data-test-accordion-head]', { - error: isPresent('[data-test-error]'), - time: text('[data-test-time]'), - count: text('[data-test-count]'), - countIcon: { scope: '[data-test-count-icon]' }, - message: text('[data-test-message]'), + scaleEvents: collection( + '[data-test-scale-events] [data-test-accordion-head]', + { + error: isPresent('[data-test-error]'), + time: text('[data-test-time]'), + count: text('[data-test-count]'), + countIcon: { scope: '[data-test-count-icon]' }, + message: text('[data-test-message]'), - isToggleable: isPresent('[data-test-accordion-toggle]:not(.is-invisible)'), - toggle: clickable('[data-test-accordion-toggle]'), - }), + isToggleable: isPresent( + '[data-test-accordion-toggle]:not(.is-invisible)' + ), + toggle: clickable('[data-test-accordion-toggle]'), + } + ), - scaleEventBodies: collection('[data-test-scale-events] [data-test-accordion-body]', { - meta: text(), - }), + scaleEventBodies: collection( + '[data-test-scale-events] [data-test-accordion-body]', + { + meta: text(), + } + ), hasScalingTimeline: isPresent('[data-test-scaling-timeline]'), - scalingAnnotations: collection('[data-test-scaling-timeline] [data-test-annotation]', { - open: clickable('button'), - }), + scalingAnnotations: collection( + '[data-test-scaling-timeline] [data-test-annotation]', + { + open: clickable('button'), + } + ), error: error(), diff --git a/ui/tests/pages/jobs/job/versions.js b/ui/tests/pages/jobs/job/versions.js index 8c44a0ba6..477012f5c 100644 --- a/ui/tests/pages/jobs/job/versions.js +++ b/ui/tests/pages/jobs/job/versions.js @@ -1,4 +1,10 @@ -import { attribute, create, collection, text, visitable } from 'ember-cli-page-object'; +import { + attribute, + create, + collection, + text, + visitable, +} from 'ember-cli-page-object'; import { getter } from 'ember-cli-page-object/macros'; import twoStepButton from 'nomad-ui/tests/pages/components/two-step-button'; diff --git a/ui/tests/pages/optimize.js b/ui/tests/pages/optimize.js index 35fbddc4c..b37efbad7 100644 --- a/ui/tests/pages/optimize.js +++ b/ui/tests/pages/optimize.js @@ -30,19 +30,22 @@ export default create({ card: recommendationCard, - recommendationSummaries: collection('[data-test-recommendation-summary-row]', { - isActive: hasClass('is-active'), - isDisabled: hasClass('is-disabled'), + recommendationSummaries: collection( + '[data-test-recommendation-summary-row]', + { + isActive: hasClass('is-active'), + isDisabled: hasClass('is-disabled'), - slug: text('[data-test-slug]'), - namespace: text('[data-test-namespace]'), - date: text('[data-test-date]'), - allocationCount: text('[data-test-allocation-count]'), - cpu: text('[data-test-cpu]'), - memory: text('[data-test-memory]'), - aggregateCpu: text('[data-test-aggregate-cpu]'), - aggregateMemory: text('[data-test-aggregate-memory]'), - }), + slug: text('[data-test-slug]'), + namespace: text('[data-test-namespace]'), + date: text('[data-test-date]'), + allocationCount: text('[data-test-allocation-count]'), + cpu: text('[data-test-cpu]'), + memory: text('[data-test-memory]'), + aggregateCpu: text('[data-test-aggregate-cpu]'), + aggregateMemory: text('[data-test-aggregate-memory]'), + } + ), empty: { scope: '[data-test-empty-recommendations]', diff --git a/ui/tests/pages/servers/detail.js b/ui/tests/pages/servers/detail.js index 6a9499ead..4b6d41c0c 100644 --- a/ui/tests/pages/servers/detail.js +++ b/ui/tests/pages/servers/detail.js @@ -1,4 +1,11 @@ -import { create, collection, clickable, isPresent, text, visitable } from 'ember-cli-page-object'; +import { + create, + collection, + clickable, + isPresent, + text, + visitable, +} from 'ember-cli-page-object'; export default create({ visit: visitable('/servers/:name'), diff --git a/ui/tests/pages/servers/list.js b/ui/tests/pages/servers/list.js index cc884d4e1..2d29cffdd 100644 --- a/ui/tests/pages/servers/list.js +++ b/ui/tests/pages/servers/list.js @@ -1,4 +1,10 @@ -import { create, collection, clickable, text, visitable } from 'ember-cli-page-object'; +import { + create, + collection, + clickable, + text, + visitable, +} from 'ember-cli-page-object'; export default create({ pageSize: 8, diff --git a/ui/tests/pages/servers/monitor.js b/ui/tests/pages/servers/monitor.js index bded4c156..b040e467f 100644 --- a/ui/tests/pages/servers/monitor.js +++ b/ui/tests/pages/servers/monitor.js @@ -1,6 +1,15 @@ -import { create, clickable, isPresent, text, visitable } from 'ember-cli-page-object'; +import { + create, + clickable, + isPresent, + text, + visitable, +} from 'ember-cli-page-object'; import { run } from '@ember/runloop'; -import { selectOpen, selectOpenChoose } from '../../utils/ember-power-select-extensions'; +import { + selectOpen, + selectOpenChoose, +} from '../../utils/ember-power-select-extensions'; export default create({ visit: visitable('/servers/:name/monitor'), diff --git a/ui/tests/pages/storage/plugins/detail.js b/ui/tests/pages/storage/plugins/detail.js index 160df3400..3a18e9317 100644 --- a/ui/tests/pages/storage/plugins/detail.js +++ b/ui/tests/pages/storage/plugins/detail.js @@ -1,4 +1,10 @@ -import { clickable, create, isPresent, text, visitable } from 'ember-cli-page-object'; +import { + clickable, + create, + isPresent, + text, + visitable, +} from 'ember-cli-page-object'; import allocations from 'nomad-ui/tests/pages/components/allocations'; @@ -12,15 +18,21 @@ export default create({ nodeHealth: text('[data-test-plugin-node-health]'), provider: text('[data-test-plugin-provider]'), - controllerAvailabilityIsPresent: isPresent('[data-test-plugin-controller-availability]'), + controllerAvailabilityIsPresent: isPresent( + '[data-test-plugin-controller-availability]' + ), nodeAvailabilityIsPresent: isPresent('[data-test-plugin-node-availability]'), ...allocations('[data-test-controller-allocation]', 'controllerAllocations'), ...allocations('[data-test-node-allocation]', 'nodeAllocations'), - goToControllerAllocations: clickable('[data-test-go-to-controller-allocations]'), + goToControllerAllocations: clickable( + '[data-test-go-to-controller-allocations]' + ), goToNodeAllocations: clickable('[data-test-go-to-node-allocations]'), - goToControllerAllocationsText: text('[data-test-go-to-controller-allocations]'), + goToControllerAllocationsText: text( + '[data-test-go-to-controller-allocations]' + ), goToNodeAllocationsText: text('[data-test-go-to-node-allocations]'), controllerTableIsPresent: isPresent('[data-test-controller-allocations]'), diff --git a/ui/tests/pages/storage/plugins/plugin/allocations.js b/ui/tests/pages/storage/plugins/plugin/allocations.js index bd553fbe4..37084aeef 100644 --- a/ui/tests/pages/storage/plugins/plugin/allocations.js +++ b/ui/tests/pages/storage/plugins/plugin/allocations.js @@ -1,4 +1,10 @@ -import { clickable, create, isPresent, text, visitable } from 'ember-cli-page-object'; +import { + clickable, + create, + isPresent, + text, + visitable, +} from 'ember-cli-page-object'; import allocations from 'nomad-ui/tests/pages/components/allocations'; import { multiFacet } from 'nomad-ui/tests/pages/components/facet'; diff --git a/ui/tests/unit/abilities/allocation-test.js b/ui/tests/unit/abilities/allocation-test.js index eb6f6f9de..209a00ead 100644 --- a/ui/tests/unit/abilities/allocation-test.js +++ b/ui/tests/unit/abilities/allocation-test.js @@ -54,7 +54,9 @@ module('Unit | Ability | allocation', function (hooks) { this.owner.register('service:system', mockSystem); this.owner.register('service:token', mockToken); - assert.ok(this.can.can('exec allocation', null, { namespace: 'aNamespace' })); + assert.ok( + this.can.can('exec allocation', null, { namespace: 'aNamespace' }) + ); }); test('it permits alloc exec for client tokens with a policy that has default namespace alloc-exec and no capabilities for active namespace', function (assert) { @@ -86,7 +88,9 @@ module('Unit | Ability | allocation', function (hooks) { this.owner.register('service:system', mockSystem); this.owner.register('service:token', mockToken); - assert.ok(this.can.can('exec allocation', null, { namespace: 'anotherNamespace' })); + assert.ok( + this.can.can('exec allocation', null, { namespace: 'anotherNamespace' }) + ); }); test('it blocks alloc exec for client tokens with a policy that has no alloc-exec capability', function (assert) { @@ -114,7 +118,9 @@ module('Unit | Ability | allocation', function (hooks) { this.owner.register('service:system', mockSystem); this.owner.register('service:token', mockToken); - assert.ok(this.can.cannot('exec allocation', null, { namespace: 'aNamespace' })); + assert.ok( + this.can.cannot('exec allocation', null, { namespace: 'aNamespace' }) + ); }); test('it handles globs in namespace names', function (assert) { @@ -162,12 +168,22 @@ module('Unit | Ability | allocation', function (hooks) { this.owner.register('service:system', mockSystem); this.owner.register('service:token', mockToken); - assert.ok(this.can.cannot('exec allocation', null, { namespace: 'production-web' })); - assert.ok(this.can.can('exec allocation', null, { namespace: 'production-api' })); - assert.ok(this.can.can('exec allocation', null, { namespace: 'production-other' })); - assert.ok(this.can.can('exec allocation', null, { namespace: 'something-suffixed' })); assert.ok( - this.can.cannot('exec allocation', null, { namespace: 'something-more-suffixed' }), + this.can.cannot('exec allocation', null, { namespace: 'production-web' }) + ); + assert.ok( + this.can.can('exec allocation', null, { namespace: 'production-api' }) + ); + assert.ok( + this.can.can('exec allocation', null, { namespace: 'production-other' }) + ); + assert.ok( + this.can.can('exec allocation', null, { namespace: 'something-suffixed' }) + ); + assert.ok( + this.can.cannot('exec allocation', null, { + namespace: 'something-more-suffixed', + }), 'expected the namespace with the greatest number of matched characters to be chosen' ); assert.ok( diff --git a/ui/tests/unit/abilities/job-test.js b/ui/tests/unit/abilities/job-test.js index 551eb0c28..f1f89233b 100644 --- a/ui/tests/unit/abilities/job-test.js +++ b/ui/tests/unit/abilities/job-test.js @@ -147,13 +147,22 @@ module('Unit | Ability | job', function (hooks) { assert.ok(this.can.cannot('scale job', null, { namespace: 'aNamespace' })); - tokenService.set('selfTokenPolicies', makePolicies('aNamespace', 'scale-job')); + tokenService.set( + 'selfTokenPolicies', + makePolicies('aNamespace', 'scale-job') + ); assert.ok(this.can.can('scale job', null, { namespace: 'aNamespace' })); - tokenService.set('selfTokenPolicies', makePolicies('aNamespace', 'submit-job')); + tokenService.set( + 'selfTokenPolicies', + makePolicies('aNamespace', 'submit-job') + ); assert.ok(this.can.can('scale job', null, { namespace: 'aNamespace' })); - tokenService.set('selfTokenPolicies', makePolicies('bNamespace', 'scale-job')); + tokenService.set( + 'selfTokenPolicies', + makePolicies('bNamespace', 'scale-job') + ); assert.ok(this.can.cannot('scale job', null, { namespace: 'aNamespace' })); }); @@ -185,9 +194,14 @@ module('Unit | Ability | job', function (hooks) { this.owner.register('service:token', mockToken); const tokenService = this.owner.lookup('service:token'); - assert.ok(this.can.cannot('dispatch job', null, { namespace: 'aNamespace' })); + assert.ok( + this.can.cannot('dispatch job', null, { namespace: 'aNamespace' }) + ); - tokenService.set('selfTokenPolicies', makePolicies('aNamespace', 'dispatch-job')); + tokenService.set( + 'selfTokenPolicies', + makePolicies('aNamespace', 'dispatch-job') + ); assert.ok(this.can.can('dispatch job', null, { namespace: 'aNamespace' })); }); @@ -236,12 +250,18 @@ module('Unit | Ability | job', function (hooks) { this.owner.register('service:system', mockSystem); this.owner.register('service:token', mockToken); - assert.ok(this.can.cannot('run job', null, { namespace: 'production-web' })); + assert.ok( + this.can.cannot('run job', null, { namespace: 'production-web' }) + ); assert.ok(this.can.can('run job', null, { namespace: 'production-api' })); assert.ok(this.can.can('run job', null, { namespace: 'production-other' })); - assert.ok(this.can.can('run job', null, { namespace: 'something-suffixed' })); assert.ok( - this.can.cannot('run job', null, { namespace: 'something-more-suffixed' }), + this.can.can('run job', null, { namespace: 'something-suffixed' }) + ); + assert.ok( + this.can.cannot('run job', null, { + namespace: 'something-more-suffixed', + }), 'expected the namespace with the greatest number of matched characters to be chosen' ); assert.ok( diff --git a/ui/tests/unit/abilities/recommendation-test.js b/ui/tests/unit/abilities/recommendation-test.js index 6ff7aeee9..4713ffa2f 100644 --- a/ui/tests/unit/abilities/recommendation-test.js +++ b/ui/tests/unit/abilities/recommendation-test.js @@ -8,74 +8,80 @@ module('Unit | Ability | recommendation', function (hooks) { setupTest(hooks); setupAbility('recommendation')(hooks); - module('when the Dynamic Application Sizing feature is present', function (hooks) { - hooks.beforeEach(function () { - const mockSystem = Service.extend({ - features: ['Dynamic Application Sizing'], + module( + 'when the Dynamic Application Sizing feature is present', + function (hooks) { + hooks.beforeEach(function () { + const mockSystem = Service.extend({ + features: ['Dynamic Application Sizing'], + }); + + this.owner.register('service:system', mockSystem); }); - this.owner.register('service:system', mockSystem); - }); + test('it permits accepting recommendations when ACLs are disabled', function (assert) { + const mockToken = Service.extend({ + aclEnabled: false, + }); - test('it permits accepting recommendations when ACLs are disabled', function (assert) { - const mockToken = Service.extend({ - aclEnabled: false, + this.owner.register('service:token', mockToken); + + assert.ok(this.ability.canAccept); }); - this.owner.register('service:token', mockToken); + test('it permits accepting recommendations for client tokens where any namespace has submit-job capabilities', function (assert) { + this.owner.lookup('service:system').set('activeNamespace', { + name: 'anotherNamespace', + }); - assert.ok(this.ability.canAccept); - }); - - test('it permits accepting recommendations for client tokens where any namespace has submit-job capabilities', function (assert) { - this.owner.lookup('service:system').set('activeNamespace', { - name: 'anotherNamespace', - }); - - const mockToken = Service.extend({ - aclEnabled: true, - selfToken: { type: 'client' }, - selfTokenPolicies: [ - { - rulesJSON: { - Namespaces: [ - { - Name: 'aNamespace', - Capabilities: [], - }, - { - Name: 'bNamespace', - Capabilities: ['submit-job'], - }, - ], + const mockToken = Service.extend({ + aclEnabled: true, + selfToken: { type: 'client' }, + selfTokenPolicies: [ + { + rulesJSON: { + Namespaces: [ + { + Name: 'aNamespace', + Capabilities: [], + }, + { + Name: 'bNamespace', + Capabilities: ['submit-job'], + }, + ], + }, }, - }, - ], + ], + }); + + this.owner.register('service:token', mockToken); + + assert.ok(this.ability.canAccept); + }); + } + ); + + module( + 'when the Dynamic Application Sizing feature is not present', + function (hooks) { + hooks.beforeEach(function () { + const mockSystem = Service.extend({ + features: [], + }); + + this.owner.register('service:system', mockSystem); }); - this.owner.register('service:token', mockToken); + test('it does not permit accepting recommendations regardless of ACL status', function (assert) { + const mockToken = Service.extend({ + aclEnabled: false, + }); - assert.ok(this.ability.canAccept); - }); - }); + this.owner.register('service:token', mockToken); - module('when the Dynamic Application Sizing feature is not present', function (hooks) { - hooks.beforeEach(function () { - const mockSystem = Service.extend({ - features: [], + assert.notOk(this.ability.canAccept); }); - - this.owner.register('service:system', mockSystem); - }); - - test('it does not permit accepting recommendations regardless of ACL status', function (assert) { - const mockToken = Service.extend({ - aclEnabled: false, - }); - - this.owner.register('service:token', mockToken); - - assert.notOk(this.ability.canAccept); - }); - }); + } + ); }); diff --git a/ui/tests/unit/adapters/allocation-test.js b/ui/tests/unit/adapters/allocation-test.js index 505aad26b..31b49943e 100644 --- a/ui/tests/unit/adapters/allocation-test.js +++ b/ui/tests/unit/adapters/allocation-test.js @@ -28,7 +28,10 @@ module('Unit | Adapter | Allocation', function (hooks) { this.system.get('shouldIncludeRegion'); await this.system.get('defaultRegion'); - const allocation = await this.store.findRecord('allocation', allocationId); + const allocation = await this.store.findRecord( + 'allocation', + allocationId + ); this.server.pretender.handledRequests.length = 0; return allocation; @@ -46,8 +49,12 @@ module('Unit | Adapter | Allocation', function (hooks) { task: 'task-name', region: null, path: 'some/path', - ls: `GET /v1/client/fs/ls/alloc-1?path=${encodeURIComponent('some/path')}`, - stat: `GET /v1/client/fs/stat/alloc-1?path=${encodeURIComponent('some/path')}`, + ls: `GET /v1/client/fs/ls/alloc-1?path=${encodeURIComponent( + 'some/path' + )}`, + stat: `GET /v1/client/fs/stat/alloc-1?path=${encodeURIComponent( + 'some/path' + )}`, stop: 'POST /v1/allocation/alloc-1/stop', restart: 'PUT /v1/client/allocation/alloc-1/restart', }, @@ -57,7 +64,9 @@ module('Unit | Adapter | Allocation', function (hooks) { task: 'task-name', region: 'region-2', path: 'some/path', - ls: `GET /v1/client/fs/ls/alloc-1?path=${encodeURIComponent('some/path')}®ion=region-2`, + ls: `GET /v1/client/fs/ls/alloc-1?path=${encodeURIComponent( + 'some/path' + )}®ion=region-2`, stat: `GET /v1/client/fs/stat/alloc-1?path=${encodeURIComponent( 'some/path' )}®ion=region-2`, @@ -69,7 +78,9 @@ module('Unit | Adapter | Allocation', function (hooks) { testCases.forEach((testCase) => { test(`ls makes the correct API call ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - const allocation = await this.initialize(testCase.id, { region: testCase.region }); + const allocation = await this.initialize(testCase.id, { + region: testCase.region, + }); await this.subject().ls(allocation, testCase.path); const req = pretender.handledRequests[0]; @@ -78,7 +89,9 @@ module('Unit | Adapter | Allocation', function (hooks) { test(`stat makes the correct API call ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - const allocation = await this.initialize(testCase.id, { region: testCase.region }); + const allocation = await this.initialize(testCase.id, { + region: testCase.region, + }); await this.subject().stat(allocation, testCase.path); const req = pretender.handledRequests[0]; @@ -87,7 +100,9 @@ module('Unit | Adapter | Allocation', function (hooks) { test(`stop makes the correct API call ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - const allocation = await this.initialize(testCase.id, { region: testCase.region }); + const allocation = await this.initialize(testCase.id, { + region: testCase.region, + }); await this.subject().stop(allocation); const req = pretender.handledRequests[0]; @@ -96,7 +111,9 @@ module('Unit | Adapter | Allocation', function (hooks) { test(`restart makes the correct API call ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - const allocation = await this.initialize(testCase.id, { region: testCase.region }); + const allocation = await this.initialize(testCase.id, { + region: testCase.region, + }); await this.subject().restart(allocation); const req = pretender.handledRequests[0]; @@ -105,12 +122,16 @@ module('Unit | Adapter | Allocation', function (hooks) { test(`restart with optional task name makes the correct API call ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - const allocation = await this.initialize(testCase.id, { region: testCase.region }); + const allocation = await this.initialize(testCase.id, { + region: testCase.region, + }); await this.subject().restart(allocation, testCase.task); const req = pretender.handledRequests[0]; assert.equal(`${req.method} ${req.url}`, testCase.restart); - assert.deepEqual(JSON.parse(req.requestBody), { TaskName: testCase.task }); + assert.deepEqual(JSON.parse(req.requestBody), { + TaskName: testCase.task, + }); }); }); }); diff --git a/ui/tests/unit/adapters/deployment-test.js b/ui/tests/unit/adapters/deployment-test.js index ed1e6c50a..499a03f62 100644 --- a/ui/tests/unit/adapters/deployment-test.js +++ b/ui/tests/unit/adapters/deployment-test.js @@ -22,12 +22,17 @@ module('Unit | Adapter | Deployment', function (hooks) { this.server.create('node'); const job = this.server.create('job', { createAllocations: false }); - const deploymentRecord = server.schema.deployments.where({ jobId: job.id }).models[0]; + const deploymentRecord = server.schema.deployments.where({ + jobId: job.id, + }).models[0]; this.system.get('shouldIncludeRegion'); await this.system.get('defaultRegion'); - const deployment = await this.store.findRecord('deployment', deploymentRecord.id); + const deployment = await this.store.findRecord( + 'deployment', + deploymentRecord.id + ); this.server.pretender.handledRequests.length = 0; return deployment; @@ -60,7 +65,10 @@ module('Unit | Adapter | Deployment', function (hooks) { const request = this.server.pretender.handledRequests[0]; - assert.equal(`${request.method} ${request.url}`, testCase.promote(deployment.id)); + assert.equal( + `${request.method} ${request.url}`, + testCase.promote(deployment.id) + ); assert.deepEqual(JSON.parse(request.requestBody), { DeploymentId: deployment.id, All: true, @@ -73,7 +81,10 @@ module('Unit | Adapter | Deployment', function (hooks) { const request = this.server.pretender.handledRequests[0]; - assert.equal(`${request.method} ${request.url}`, testCase.fail(deployment.id)); + assert.equal( + `${request.method} ${request.url}`, + testCase.fail(deployment.id) + ); assert.deepEqual(JSON.parse(request.requestBody), { DeploymentId: deployment.id, }); diff --git a/ui/tests/unit/adapters/job-test.js b/ui/tests/unit/adapters/job-test.js index 580ed4964..2b696ba19 100644 --- a/ui/tests/unit/adapters/job-test.js +++ b/ui/tests/unit/adapters/job-test.js @@ -145,7 +145,9 @@ module('Unit | Adapter | Job', function (hooks) { await settled(); assert.notOk( - pretender.handledRequests.mapBy('requestHeaders').some((headers) => headers['X-Nomad-Token']), + pretender.handledRequests + .mapBy('requestHeaders') + .some((headers) => headers['X-Nomad-Token']), 'No token header present on either job request' ); }); @@ -371,7 +373,11 @@ module('Unit | Adapter | Job', function (hooks) { const { request: xhr } = pretender.requestReferences[0]; const { request: xhr2 } = pretender.requestReferences[1]; assert.equal(xhr.status, 0, 'Request is still pending'); - assert.equal(pretender.requestReferences.length, 2, 'Two findRecord requests were made'); + assert.equal( + pretender.requestReferences.length, + 2, + 'Two findRecord requests were made' + ); assert.equal( pretender.requestReferences.mapBy('url').uniq().length, 1, @@ -491,7 +497,10 @@ module('Unit | Adapter | Job', function (hooks) { await this.subject().forcePeriodic(job); const request = this.server.pretender.handledRequests[0]; - assert.equal(request.url, `/v1/job/${job.plainId}/periodic/force?region=${region}`); + assert.equal( + request.url, + `/v1/job/${job.plainId}/periodic/force?region=${region}` + ); assert.equal(request.method, 'POST'); }); @@ -576,7 +585,10 @@ module('Unit | Adapter | Job', function (hooks) { await this.subject().dispatch(job, {}, ''); const request = this.server.pretender.handledRequests[0]; - assert.equal(request.url, `/v1/job/${job.plainId}/dispatch?region=${region}`); + assert.equal( + request.url, + `/v1/job/${job.plainId}/dispatch?region=${region}` + ); assert.equal(request.method, 'POST'); }); }); diff --git a/ui/tests/unit/adapters/node-test.js b/ui/tests/unit/adapters/node-test.js index 47dc613d5..c96ac3147 100644 --- a/ui/tests/unit/adapters/node-test.js +++ b/ui/tests/unit/adapters/node-test.js @@ -46,7 +46,9 @@ module('Unit | Adapter | Node', function (hooks) { server.db.allocations.remove('node-1-1'); allocations = await run(() => findHasMany(node, 'allocations')); - const dbAllocations = this.server.db.allocations.where({ nodeId: node.get('id') }); + const dbAllocations = this.server.db.allocations.where({ + nodeId: node.get('id'), + }); assert.equal( allocations.get('length'), dbAllocations.length, @@ -106,7 +108,8 @@ module('Unit | Adapter | Node', function (hooks) { testCases.forEach((testCase) => { test(`setEligible makes the correct POST request to /:node_id/eligibility ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - if (testCase.region) window.localStorage.nomadActiveRegion = testCase.region; + if (testCase.region) + window.localStorage.nomadActiveRegion = testCase.region; const node = await run(() => this.store.findRecord('node', testCase.id)); await this.subject().setEligible(node); @@ -121,7 +124,8 @@ module('Unit | Adapter | Node', function (hooks) { test(`setIneligible makes the correct POST request to /:node_id/eligibility ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - if (testCase.region) window.localStorage.nomadActiveRegion = testCase.region; + if (testCase.region) + window.localStorage.nomadActiveRegion = testCase.region; const node = await run(() => this.store.findRecord('node', testCase.id)); await this.subject().setIneligible(node); @@ -136,7 +140,8 @@ module('Unit | Adapter | Node', function (hooks) { test(`drain makes the correct POST request to /:node_id/drain with appropriate defaults ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - if (testCase.region) window.localStorage.nomadActiveRegion = testCase.region; + if (testCase.region) + window.localStorage.nomadActiveRegion = testCase.region; const node = await run(() => this.store.findRecord('node', testCase.id)); await this.subject().drain(node); @@ -154,7 +159,8 @@ module('Unit | Adapter | Node', function (hooks) { test(`drain makes the correct POST request to /:node_id/drain with the provided drain spec ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - if (testCase.region) window.localStorage.nomadActiveRegion = testCase.region; + if (testCase.region) + window.localStorage.nomadActiveRegion = testCase.region; const node = await run(() => this.store.findRecord('node', testCase.id)); @@ -174,7 +180,8 @@ module('Unit | Adapter | Node', function (hooks) { test(`forceDrain makes the correct POST request to /:node_id/drain with appropriate defaults ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - if (testCase.region) window.localStorage.nomadActiveRegion = testCase.region; + if (testCase.region) + window.localStorage.nomadActiveRegion = testCase.region; const node = await run(() => this.store.findRecord('node', testCase.id)); @@ -193,7 +200,8 @@ module('Unit | Adapter | Node', function (hooks) { test(`forceDrain makes the correct POST request to /:node_id/drain with the provided drain spec ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - if (testCase.region) window.localStorage.nomadActiveRegion = testCase.region; + if (testCase.region) + window.localStorage.nomadActiveRegion = testCase.region; const node = await run(() => this.store.findRecord('node', testCase.id)); @@ -213,7 +221,8 @@ module('Unit | Adapter | Node', function (hooks) { test(`cancelDrain makes the correct POST request to /:node_id/drain ${testCase.variation}`, async function (assert) { const { pretender } = this.server; - if (testCase.region) window.localStorage.nomadActiveRegion = testCase.region; + if (testCase.region) + window.localStorage.nomadActiveRegion = testCase.region; const node = await run(() => this.store.findRecord('node', testCase.id)); diff --git a/ui/tests/unit/adapters/volume-test.js b/ui/tests/unit/adapters/volume-test.js index adb69a53f..8eeace873 100644 --- a/ui/tests/unit/adapters/volume-test.js +++ b/ui/tests/unit/adapters/volume-test.js @@ -23,7 +23,10 @@ module('Unit | Adapter | Volume', function (hooks) { this.server.create('node'); this.server.create('job', { id: 'job-1', namespaceId: 'default' }); this.server.create('csi-plugin', 2); - this.server.create('csi-volume', { id: 'volume-1', namespaceId: 'some-namespace' }); + this.server.create('csi-volume', { + id: 'volume-1', + namespaceId: 'some-namespace', + }); this.server.create('region', { id: 'region-1' }); this.server.create('region', { id: 'region-2' }); @@ -52,10 +55,18 @@ module('Unit | Adapter | Volume', function (hooks) { await this.initializeUI(); - this.subject().query(this.store, { modelName: 'volume' }, { type: 'csi' }, null, {}); + this.subject().query( + this.store, + { modelName: 'volume' }, + { type: 'csi' }, + null, + {} + ); await settled(); - assert.deepEqual(pretender.handledRequests.mapBy('url'), ['/v1/volumes?type=csi']); + assert.deepEqual(pretender.handledRequests.mapBy('url'), [ + '/v1/volumes?type=csi', + ]); }); test('When the volume has a namespace other than default, it is in the URL', async function (assert) { @@ -70,7 +81,9 @@ module('Unit | Adapter | Volume', function (hooks) { await settled(); assert.deepEqual(pretender.handledRequests.mapBy('url'), [ - `/v1/volume/${encodeURIComponent(volumeName)}?namespace=${volumeNamespace}`, + `/v1/volume/${encodeURIComponent( + volumeName + )}?namespace=${volumeNamespace}`, ]); }); @@ -80,17 +93,29 @@ module('Unit | Adapter | Volume', function (hooks) { const { pretender } = this.server; const request = () => - this.subject().query(this.store, { modelName: 'volume' }, { type: 'csi' }, null, { - reload: true, - adapterOptions: { watch: true }, - }); + this.subject().query( + this.store, + { modelName: 'volume' }, + { type: 'csi' }, + null, + { + reload: true, + adapterOptions: { watch: true }, + } + ); request(); - assert.equal(pretender.handledRequests[0].url, '/v1/volumes?type=csi&index=1'); + assert.equal( + pretender.handledRequests[0].url, + '/v1/volumes?type=csi&index=1' + ); await settled(); request(); - assert.equal(pretender.handledRequests[1].url, '/v1/volumes?type=csi&index=2'); + assert.equal( + pretender.handledRequests[1].url, + '/v1/volumes?type=csi&index=2' + ); await settled(); }); @@ -128,10 +153,16 @@ module('Unit | Adapter | Volume', function (hooks) { const { pretender } = this.server; const request = () => - this.subject().query(this.store, { modelName: 'volume' }, { type: 'csi' }, null, { - reload: true, - adapterOptions: { watch: true }, - }); + this.subject().query( + this.store, + { modelName: 'volume' }, + { type: 'csi' }, + null, + { + reload: true, + adapterOptions: { watch: true }, + } + ); const findAllRequest = () => this.subject().findAll(null, { modelName: 'volume' }, null, { @@ -140,11 +171,17 @@ module('Unit | Adapter | Volume', function (hooks) { }); request(); - assert.equal(pretender.handledRequests[0].url, '/v1/volumes?type=csi&index=1'); + assert.equal( + pretender.handledRequests[0].url, + '/v1/volumes?type=csi&index=1' + ); await settled(); request(); - assert.equal(pretender.handledRequests[1].url, '/v1/volumes?type=csi&index=2'); + assert.equal( + pretender.handledRequests[1].url, + '/v1/volumes?type=csi&index=2' + ); await settled(); findAllRequest(); diff --git a/ui/tests/unit/components/line-chart-test.js b/ui/tests/unit/components/line-chart-test.js index 01bd31eff..dcae81999 100644 --- a/ui/tests/unit/components/line-chart-test.js +++ b/ui/tests/unit/components/line-chart-test.js @@ -36,7 +36,11 @@ module('Unit | Component | line-chart', function (hooks) { chart.args.data = [...data, { foo: 12, bar: 600 }]; [, xDomainHigh] = chart.xScale.domain(); - assert.equal(xDomainHigh, 12, 'When the data changes, the xScale is recalculated'); + assert.equal( + xDomainHigh, + 12, + 'When the data changes, the xScale is recalculated' + ); }); test('y scale domain uses the max value in the data based off of yProp, but is always zero-based', function (assert) { @@ -56,7 +60,11 @@ module('Unit | Component | line-chart', function (hooks) { chart.args.data = [...data, { foo: 12, bar: 600 }]; [, yDomainHigh] = chart.yScale.domain(); - assert.equal(yDomainHigh, 600, 'When the data changes, the yScale is recalculated'); + assert.equal( + yDomainHigh, + 600, + 'When the data changes, the yScale is recalculated' + ); }); test('the number of yTicks is always odd (to always have a mid-line) and is based off the chart height', function (assert) { diff --git a/ui/tests/unit/components/stats-time-series-test.js b/ui/tests/unit/components/stats-time-series-test.js index 34cbdd112..76a197be0 100644 --- a/ui/tests/unit/components/stats-time-series-test.js +++ b/ui/tests/unit/components/stats-time-series-test.js @@ -9,7 +9,8 @@ module('Unit | Component | stats-time-series', function (hooks) { setupTest(hooks); setupGlimmerComponentFactory(hooks, 'stats-time-series'); - const ts = (offset, resolution = 'm') => moment().subtract(offset, resolution).toDate(); + const ts = (offset, resolution = 'm') => + moment().subtract(offset, resolution).toDate(); const wideData = [ { timestamp: ts(20), percent: 0.5 }, @@ -59,7 +60,10 @@ module('Unit | Component | stats-time-series', function (hooks) { const chart = this.createComponent({ data: wideData }); wideData.forEach((datum) => { - assert.equal(chart.yFormat(datum.percent), d3Format.format('.1~%')(datum.percent)); + assert.equal( + chart.yFormat(datum.percent), + d3Format.format('.1~%')(datum.percent) + ); }); }); @@ -89,7 +93,10 @@ module('Unit | Component | stats-time-series', function (hooks) { const chart = this.createComponent({ data: wideData }); assert.deepEqual( - [Math.min(...wideData.mapBy('percent')), Math.max(...wideData.mapBy('percent'))], + [ + Math.min(...wideData.mapBy('percent')), + Math.max(...wideData.mapBy('percent')), + ], [0.3, 0.9], 'The bounds of the value prop of the dataset is narrower than 0 - 1' ); @@ -130,6 +137,10 @@ module('Unit | Component | stats-time-series', function (hooks) { test('when there are only empty frames in the data array, the default y domain is used', function (assert) { const chart = this.createComponent({ data: nullData }); - assert.deepEqual(chart.yScale(nullData, 0).domain(), [0, 1], 'The bounds are 0 and 1'); + assert.deepEqual( + chart.yScale(nullData, 0).domain(), + [0, 1], + 'The bounds are 0 and 1' + ); }); }); diff --git a/ui/tests/unit/components/tooltip-test.js b/ui/tests/unit/components/tooltip-test.js index 7b1e55b55..5bdc14892 100644 --- a/ui/tests/unit/components/tooltip-test.js +++ b/ui/tests/unit/components/tooltip-test.js @@ -7,7 +7,9 @@ module('Unit | Component | tooltip', function (hooks) { setupGlimmerComponentFactory(hooks, 'tooltip'); test('long texts are ellipsised in the middle', function (assert) { - const tooltip = this.createComponent({ text: 'reeeeeeeeeeeeeeeeeally long text' }); + const tooltip = this.createComponent({ + text: 'reeeeeeeeeeeeeeeeeally long text', + }); assert.equal(tooltip.text, 'reeeeeeeeeeeeee...long text'); }); }); diff --git a/ui/tests/unit/components/topo-viz-test.js b/ui/tests/unit/components/topo-viz-test.js index a0df1100e..09e613bd6 100644 --- a/ui/tests/unit/components/topo-viz-test.js +++ b/ui/tests/unit/components/topo-viz-test.js @@ -32,9 +32,17 @@ module('Unit | Component | TopoViz', function (hooks) { topoViz.buildTopology(); - assert.deepEqual(topoViz.topology.datacenters.mapBy('name'), ['dc1', 'dc2']); - assert.deepEqual(topoViz.topology.datacenters[0].nodes.mapBy('node'), [nodes[0], nodes[2]]); - assert.deepEqual(topoViz.topology.datacenters[1].nodes.mapBy('node'), [nodes[1]]); + assert.deepEqual(topoViz.topology.datacenters.mapBy('name'), [ + 'dc1', + 'dc2', + ]); + assert.deepEqual(topoViz.topology.datacenters[0].nodes.mapBy('node'), [ + nodes[0], + nodes[2], + ]); + assert.deepEqual(topoViz.topology.datacenters[1].nodes.mapBy('node'), [ + nodes[1], + ]); assert.deepEqual( topoViz.topology.datacenters[0].nodes[0].allocations.mapBy('allocation'), node0Allocs @@ -86,7 +94,9 @@ module('Unit | Component | TopoViz', function (hooks) { const [jobId, group] = JSON.parse(key); assert.deepEqual( topoViz.topology.allocationIndex[key].mapBy('allocation'), - allocations.filter((alloc) => alloc.jobId === jobId && alloc.taskGroupName === group) + allocations.filter( + (alloc) => alloc.jobId === jobId && alloc.taskGroupName === group + ) ); }); }); @@ -118,8 +128,14 @@ module('Unit | Component | TopoViz', function (hooks) { { datacenter: 'dc2', id: 'node4', resources: {} }, ]; - const twoColumnViz = this.createComponent({ nodes: uniformDcs, allocations: [] }); - const oneColumViz = this.createComponent({ nodes: skewedDcs, allocations: [] }); + const twoColumnViz = this.createComponent({ + nodes: uniformDcs, + allocations: [], + }); + const oneColumViz = this.createComponent({ + nodes: skewedDcs, + allocations: [], + }); twoColumnViz.buildTopology(); oneColumViz.buildTopology(); @@ -144,8 +160,14 @@ module('Unit | Component | TopoViz', function (hooks) { resources: {}, })); - const oneColumnViz = this.createComponent({ nodes: manyUniformNodes, allocations: [] }); - const twoColumnViz = this.createComponent({ nodes: manySkewedNodes, allocations: [] }); + const oneColumnViz = this.createComponent({ + nodes: manyUniformNodes, + allocations: [], + }); + const twoColumnViz = this.createComponent({ + nodes: manySkewedNodes, + allocations: [], + }); oneColumnViz.buildTopology(); twoColumnViz.buildTopology(); @@ -158,7 +180,9 @@ module('Unit | Component | TopoViz', function (hooks) { }); test('dataForAllocation correctly calculates proportion of node utilization and group key', async function (assert) { - const nodes = [{ datacenter: 'dc1', id: 'node0', resources: { cpu: 100, memory: 250 } }]; + const nodes = [ + { datacenter: 'dc1', id: 'node0', resources: { cpu: 100, memory: 250 } }, + ]; const allocations = [ alloc({ nodeId: 'node0', @@ -171,8 +195,14 @@ module('Unit | Component | TopoViz', function (hooks) { const topoViz = this.createComponent({ nodes, allocations }); topoViz.buildTopology(); - assert.equal(topoViz.topology.datacenters[0].nodes[0].allocations[0].cpuPercent, 0.5); - assert.equal(topoViz.topology.datacenters[0].nodes[0].allocations[0].memoryPercent, 0.1); + assert.equal( + topoViz.topology.datacenters[0].nodes[0].allocations[0].cpuPercent, + 0.5 + ); + assert.equal( + topoViz.topology.datacenters[0].nodes[0].allocations[0].memoryPercent, + 0.1 + ); }); test('allocations that reference nonexistent nodes are ignored', async function (assert) { @@ -187,10 +217,13 @@ module('Unit | Component | TopoViz', function (hooks) { topoViz.buildTopology(); - assert.deepEqual(topoViz.topology.datacenters[0].nodes.mapBy('node'), [nodes[0]]); - assert.deepEqual(topoViz.topology.datacenters[0].nodes[0].allocations.mapBy('allocation'), [ - allocations[0], + assert.deepEqual(topoViz.topology.datacenters[0].nodes.mapBy('node'), [ + nodes[0], ]); + assert.deepEqual( + topoViz.topology.datacenters[0].nodes[0].allocations.mapBy('allocation'), + [allocations[0]] + ); }); }); diff --git a/ui/tests/unit/mixins/searchable-test.js b/ui/tests/unit/mixins/searchable-test.js index 19cfa0f3d..feeb1b66a 100644 --- a/ui/tests/unit/mixins/searchable-test.js +++ b/ui/tests/unit/mixins/searchable-test.js @@ -63,7 +63,13 @@ module('Unit | Mixin | Searchable', function (hooks) { subject.set('searchTerm', 'America'); assert.deepEqual( subject.get('listSearched'), - [{ id: '1', name: 'United States of America', continent: 'North America' }], + [ + { + id: '1', + name: 'United States of America', + continent: 'North America', + }, + ], 'Only USA matched, since continent is not a search prop' ); }); @@ -96,7 +102,13 @@ module('Unit | Mixin | Searchable', function (hooks) { subject.set('searchTerm', 'Ameerica'); assert.deepEqual( subject.get('listSearched'), - [{ id: '1', name: 'United States of America', continent: 'North America' }], + [ + { + id: '1', + name: 'United States of America', + continent: 'North America', + }, + ], 'America is matched due to fuzzy matching' ); }); @@ -104,9 +116,21 @@ module('Unit | Mixin | Searchable', function (hooks) { test('the fuzzy search can include match results', function (assert) { const subject = this.subject(); subject.set('source', [ - EmberObject.create({ id: '1', name: 'United States of America', continent: 'North America' }), - EmberObject.create({ id: '2', name: 'Canada', continent: 'North America' }), - EmberObject.create({ id: '3', name: 'Mexico', continent: 'North America' }), + EmberObject.create({ + id: '1', + name: 'United States of America', + continent: 'North America', + }), + EmberObject.create({ + id: '2', + name: 'Canada', + continent: 'North America', + }), + EmberObject.create({ + id: '3', + name: 'Mexico', + continent: 'North America', + }), ]); subject.set('fuzzySearchEnabled', true); @@ -115,7 +139,9 @@ module('Unit | Mixin | Searchable', function (hooks) { assert.deepEqual( subject .get('listSearched') - .map((object) => object.getProperties('id', 'name', 'continent', 'fuzzySearchMatches')), + .map((object) => + object.getProperties('id', 'name', 'continent', 'fuzzySearchMatches') + ), [ { id: '1', @@ -216,7 +242,13 @@ module('Unit | Mixin | Searchable', function (hooks) { subject.set('searchTerm', 'America States'); assert.deepEqual( subject.get('listSearched'), - [{ id: '1', name: 'United States of America', continent: 'North America' }], + [ + { + id: '1', + name: 'United States of America', + continent: 'North America', + }, + ], 'Fuzzy match on one country, but not an exact match on continent' ); @@ -230,9 +262,17 @@ module('Unit | Mixin | Searchable', function (hooks) { test('the resetPagination method is a no-op', function (assert) { const subject = this.subject(); - assert.strictEqual(subject.get('currentPage'), undefined, 'No currentPage value set'); + assert.strictEqual( + subject.get('currentPage'), + undefined, + 'No currentPage value set' + ); subject.resetPagination(); - assert.strictEqual(subject.get('currentPage'), undefined, 'Still no currentPage value set'); + assert.strictEqual( + subject.get('currentPage'), + undefined, + 'Still no currentPage value set' + ); }); }); @@ -251,7 +291,10 @@ module('Unit | Mixin | Searchable (with pagination)', function (hooks) { currentPage: 1, }); - this.owner.register('test-container:searchable-paginated-object', SearchablePaginatedObject); + this.owner.register( + 'test-container:searchable-paginated-object', + SearchablePaginatedObject + ); return this.owner.lookup('test-container:searchable-paginated-object'); }; }); @@ -259,7 +302,11 @@ module('Unit | Mixin | Searchable (with pagination)', function (hooks) { test('the resetPagination method sets the currentPage to 1', function (assert) { const subject = this.subject(); subject.set('currentPage', 5); - assert.equal(subject.get('currentPage'), 5, 'Current page is something other than 1'); + assert.equal( + subject.get('currentPage'), + 5, + 'Current page is something other than 1' + ); subject.resetPagination(); assert.equal(subject.get('currentPage'), 1, 'Current page gets reset to 1'); }); diff --git a/ui/tests/unit/models/task-group-test.js b/ui/tests/unit/models/task-group-test.js index e029ef213..ee086adff 100644 --- a/ui/tests/unit/models/task-group-test.js +++ b/ui/tests/unit/models/task-group-test.js @@ -69,7 +69,9 @@ module('Unit | Model | task-group', function (hooks) { const jobWithMeta = run(() => store.createRecord('job', { name: 'example-with-meta', - meta: store.createFragment('structured-attributes', { raw: { a: 'b' } }), + meta: store.createFragment('structured-attributes', { + raw: { a: 'b' }, + }), taskGroups: [ { name: 'one', diff --git a/ui/tests/unit/serializers/allocation-test.js b/ui/tests/unit/serializers/allocation-test.js index c587b3c43..7aa28f72d 100644 --- a/ui/tests/unit/serializers/allocation-test.js +++ b/ui/tests/unit/serializers/allocation-test.js @@ -165,7 +165,10 @@ module('Unit | Serializer | Allocation', function (hooks) { }, }, PreemptedByAllocation: 'preempter-allocation', - PreemptedAllocations: ['preempted-one-allocation', 'preempted-two-allocation'], + PreemptedAllocations: [ + 'preempted-one-allocation', + 'preempted-two-allocation', + ], }, out: { data: { @@ -384,7 +387,10 @@ module('Unit | Serializer | Allocation', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { - assert.deepEqual(this.subject().normalize(AllocationModel, testCase.in), testCase.out); + assert.deepEqual( + this.subject().normalize(AllocationModel, testCase.in), + testCase.out + ); }); }); }); diff --git a/ui/tests/unit/serializers/application-test.js b/ui/tests/unit/serializers/application-test.js index f2bd94db1..b1f01389c 100644 --- a/ui/tests/unit/serializers/application-test.js +++ b/ui/tests/unit/serializers/application-test.js @@ -10,7 +10,10 @@ class TestSerializer extends ApplicationSerializer { mapToArray = [ 'ArrayableMap', - { beforeName: 'OriginalNameArrayableMap', afterName: 'RenamedArrayableMap' }, + { + beforeName: 'OriginalNameArrayableMap', + afterName: 'RenamedArrayableMap', + }, ]; separateNanos = ['Time']; @@ -101,7 +104,10 @@ module('Unit | Serializer | Application', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { - assert.deepEqual(this.subject().normalize(TestModel, testCase.in), testCase.out); + assert.deepEqual( + this.subject().normalize(TestModel, testCase.in), + testCase.out + ); }); }); }); diff --git a/ui/tests/unit/serializers/deployment-test.js b/ui/tests/unit/serializers/deployment-test.js index 0c1e3479d..25afe6ce5 100644 --- a/ui/tests/unit/serializers/deployment-test.js +++ b/ui/tests/unit/serializers/deployment-test.js @@ -121,7 +121,10 @@ module('Unit | Serializer | Deployment', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { - assert.deepEqual(this.subject().normalize(DeploymentModel, testCase.in), testCase.out); + assert.deepEqual( + this.subject().normalize(DeploymentModel, testCase.in), + testCase.out + ); }); }); }); diff --git a/ui/tests/unit/serializers/evaluation-test.js b/ui/tests/unit/serializers/evaluation-test.js index 6b1c574c4..6e17427eb 100644 --- a/ui/tests/unit/serializers/evaluation-test.js +++ b/ui/tests/unit/serializers/evaluation-test.js @@ -105,7 +105,10 @@ module('Unit | Serializer | Evaluation', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { - assert.deepEqual(this.subject().normalize(EvaluationModel, testCase.in), testCase.out); + assert.deepEqual( + this.subject().normalize(EvaluationModel, testCase.in), + testCase.out + ); }); }); }); diff --git a/ui/tests/unit/serializers/job-plan-test.js b/ui/tests/unit/serializers/job-plan-test.js index 99e34e0a1..f9e48c86f 100644 --- a/ui/tests/unit/serializers/job-plan-test.js +++ b/ui/tests/unit/serializers/job-plan-test.js @@ -140,7 +140,10 @@ module('Unit | Serializer | JobPlan', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { - assert.deepEqual(this.subject().normalize(JobPlanModel, testCase.in), testCase.out); + assert.deepEqual( + this.subject().normalize(JobPlanModel, testCase.in), + testCase.out + ); }); }); }); diff --git a/ui/tests/unit/serializers/job-summary-test.js b/ui/tests/unit/serializers/job-summary-test.js index 2558bdd13..33d656099 100644 --- a/ui/tests/unit/serializers/job-summary-test.js +++ b/ui/tests/unit/serializers/job-summary-test.js @@ -96,7 +96,10 @@ module('Unit | Serializer | JobSummary', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { - assert.deepEqual(this.subject().normalize(JobSummaryModel, testCase.in), testCase.out); + assert.deepEqual( + this.subject().normalize(JobSummaryModel, testCase.in), + testCase.out + ); }); }); }); diff --git a/ui/tests/unit/serializers/job-test.js b/ui/tests/unit/serializers/job-test.js index 9ae33b6b0..6852da08b 100644 --- a/ui/tests/unit/serializers/job-test.js +++ b/ui/tests/unit/serializers/job-test.js @@ -29,7 +29,10 @@ module('Unit | Serializer | Job', function (hooks) { const { data } = this.subject().normalize(JobModel, original); assert.equal( data.id, - JSON.stringify([data.attributes.name, data.relationships.namespace.data.id]) + JSON.stringify([ + data.attributes.name, + data.relationships.namespace.data.id, + ]) ); }); }); diff --git a/ui/tests/unit/serializers/node-test.js b/ui/tests/unit/serializers/node-test.js index 22a966925..70ad13125 100644 --- a/ui/tests/unit/serializers/node-test.js +++ b/ui/tests/unit/serializers/node-test.js @@ -19,7 +19,11 @@ module('Unit | Serializer | Node', function (hooks) { makeNode('3', 'Three', '127.0.0.3:4646'), ]; - const payload = this.subject().normalizeFindAllResponse(this.store, NodeModel, findAllResponse); + const payload = this.subject().normalizeFindAllResponse( + this.store, + NodeModel, + findAllResponse + ); pushPayloadToStore(this.store, payload, NodeModel.modelName); assert.equal( @@ -63,7 +67,10 @@ module('Unit | Serializer | Node', function (hooks) { 'The node length in the store reflects the new response' ); - assert.notOk(this.store.peekAll('node').findBy('id', '1'), 'Record One is no longer found'); + assert.notOk( + this.store.peekAll('node').findBy('id', '1'), + 'Record One is no longer found' + ); }); function makeNode(id, name, ip) { @@ -202,7 +209,10 @@ module('Unit | Serializer | Node', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { - assert.deepEqual(this.subject().normalize(NodeModel, testCase.in), testCase.out); + assert.deepEqual( + this.subject().normalize(NodeModel, testCase.in), + testCase.out + ); }); }); }); diff --git a/ui/tests/unit/serializers/recommendation-summary-test.js b/ui/tests/unit/serializers/recommendation-summary-test.js index debf63431..e18677536 100644 --- a/ui/tests/unit/serializers/recommendation-summary-test.js +++ b/ui/tests/unit/serializers/recommendation-summary-test.js @@ -205,7 +205,11 @@ module('Unit | Serializer | RecommendationSummary', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { assert.deepEqual( - this.subject().normalizeArrayResponse(this.store, RecommendationSummaryModel, testCase.in), + this.subject().normalizeArrayResponse( + this.store, + RecommendationSummaryModel, + testCase.in + ), testCase.out ); }); diff --git a/ui/tests/unit/serializers/scale-event-test.js b/ui/tests/unit/serializers/scale-event-test.js index 5e669cce4..4946d32b9 100644 --- a/ui/tests/unit/serializers/scale-event-test.js +++ b/ui/tests/unit/serializers/scale-event-test.js @@ -81,7 +81,10 @@ module('Unit | Serializer | Scale Event', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { - assert.deepEqual(this.subject().normalize(ScaleEventModel, testCase.in), testCase.out); + assert.deepEqual( + this.subject().normalize(ScaleEventModel, testCase.in), + testCase.out + ); }); }); }); diff --git a/ui/tests/unit/serializers/volume-test.js b/ui/tests/unit/serializers/volume-test.js index a1b69a86b..ab2d68b4c 100644 --- a/ui/tests/unit/serializers/volume-test.js +++ b/ui/tests/unit/serializers/volume-test.js @@ -358,7 +358,10 @@ module('Unit | Serializer | Volume', function (hooks) { normalizationTestCases.forEach((testCase) => { test(`normalization: ${testCase.name}`, async function (assert) { - assert.deepEqual(this.subject().normalize(VolumeModel, testCase.in), testCase.out); + assert.deepEqual( + this.subject().normalize(VolumeModel, testCase.in), + testCase.out + ); }); }); }); diff --git a/ui/tests/unit/services/stats-trackers-registry-test.js b/ui/tests/unit/services/stats-trackers-registry-test.js index 6580a53c3..b4746dc49 100644 --- a/ui/tests/unit/services/stats-trackers-registry-test.js +++ b/ui/tests/unit/services/stats-trackers-registry-test.js @@ -60,11 +60,22 @@ module('Unit | Service | Stats Trackers Registry', function (hooks) { const registry = this.subject(); const id = 'id'; - assert.equal(registry.get('registryRef').size, 0, 'Nothing in the registry yet'); + assert.equal( + registry.get('registryRef').size, + 0, + 'Nothing in the registry yet' + ); const tracker = registry.getTracker(mockNode.create({ id })); - assert.ok(tracker instanceof NodeStatsTracker, 'The correct type of tracker is made'); - assert.equal(registry.get('registryRef').size, 1, 'The tracker was added to the registry'); + assert.ok( + tracker instanceof NodeStatsTracker, + 'The correct type of tracker is made' + ); + assert.equal( + registry.get('registryRef').size, + 1, + 'The tracker was added to the registry' + ); assert.deepEqual( Array.from(registry.get('registryRef').keys()), [`node:${id}`], @@ -79,8 +90,16 @@ module('Unit | Service | Stats Trackers Registry', function (hooks) { const tracker1 = registry.getTracker(node); const tracker2 = registry.getTracker(node); - assert.equal(tracker1, tracker2, 'Returns an existing tracker for the same resource'); - assert.equal(registry.get('registryRef').size, 1, 'Only one tracker in the registry'); + assert.equal( + tracker1, + tracker2, + 'Returns an existing tracker for the same resource' + ); + assert.equal( + registry.get('registryRef').size, + 1, + 'Only one tracker in the registry' + ); }); test('Registry does not depend on persistent object references', function (assert) { @@ -98,8 +117,16 @@ module('Unit | Service | Stats Trackers Registry', function (hooks) { 'And the same className' ); - assert.equal(registry.getTracker(node1), registry.getTracker(node2), 'Return the same tracker'); - assert.equal(registry.get('registryRef').size, 1, 'Only one tracker in the registry'); + assert.equal( + registry.getTracker(node1), + registry.getTracker(node2), + 'Return the same tracker' + ); + assert.equal( + registry.get('registryRef').size, + 1, + 'Only one tracker in the registry' + ); }); test('Has a max size', function (assert) { @@ -194,7 +221,9 @@ module('Unit | Service | Stats Trackers Registry', function (hooks) { tracker.get('poll').perform(); assert.ok( - this.tokenAuthorizedRequestSpy.calledWith(`/v1/client/stats?node_id=${node.get('id')}`), + this.tokenAuthorizedRequestSpy.calledWith( + `/v1/client/stats?node_id=${node.get('id')}` + ), 'The token service authorizedRequest function was used' ); diff --git a/ui/tests/unit/utils/allocation-stats-tracker-test.js b/ui/tests/unit/utils/allocation-stats-tracker-test.js index fd5deec48..ef0133014 100644 --- a/ui/tests/unit/utils/allocation-stats-tracker-test.js +++ b/ui/tests/unit/utils/allocation-stats-tracker-test.js @@ -3,7 +3,9 @@ import { assign } from '@ember/polyfills'; import { module, test } from 'qunit'; import sinon from 'sinon'; import Pretender from 'pretender'; -import AllocationStatsTracker, { stats } from 'nomad-ui/utils/classes/allocation-stats-tracker'; +import AllocationStatsTracker, { + stats, +} from 'nomad-ui/utils/classes/allocation-stats-tracker'; import fetch from 'nomad-ui/utils/fetch'; import statsTrackerFrameMissingBehavior from './behaviors/stats-tracker-frame-missing'; @@ -141,7 +143,11 @@ module('Unit | Util | AllocationStatsTracker', function () { ); allocation.taskGroup.tasks.forEach((task) => { const trackerTask = tracker.get('tasks').findBy('task', task.name); - assert.equal(trackerTask.reservedCPU, task.reservedCPU, `CPU matches for task ${task.name}`); + assert.equal( + trackerTask.reservedCPU, + task.reservedCPU, + `CPU matches for task ${task.name}` + ); assert.equal( trackerTask.reservedMemory, task.reservedMemory, @@ -152,7 +158,11 @@ module('Unit | Util | AllocationStatsTracker', function () { test('poll results in requesting the url and calling append with the resulting JSON', async function (assert) { const allocation = MockAllocation(); - const tracker = AllocationStatsTracker.create({ fetch, allocation, append: sinon.spy() }); + const tracker = AllocationStatsTracker.create({ + fetch, + allocation, + append: sinon.spy(), + }); const mockFrame = { Some: { data: ['goes', 'here'], @@ -161,7 +171,11 @@ module('Unit | Util | AllocationStatsTracker', function () { }; const server = new Pretender(function () { - this.get('/v1/client/allocation/:id/stats', () => [200, {}, JSON.stringify(mockFrame)]); + this.get('/v1/client/allocation/:id/stats', () => [ + 200, + {}, + JSON.stringify(mockFrame), + ]); }); tracker.get('poll').perform(); @@ -192,9 +206,27 @@ module('Unit | Util | AllocationStatsTracker', function () { assert.deepEqual( tracker.get('tasks'), [ - { task: 'service', reservedCPU: 100, reservedMemory: 256, cpu: [], memory: [] }, - { task: 'sidecar', reservedCPU: 50, reservedMemory: 128, cpu: [], memory: [] }, - { task: 'log-shipper', reservedCPU: 50, reservedMemory: 128, cpu: [], memory: [] }, + { + task: 'service', + reservedCPU: 100, + reservedMemory: 256, + cpu: [], + memory: [], + }, + { + task: 'sidecar', + reservedCPU: 50, + reservedMemory: 128, + cpu: [], + memory: [], + }, + { + task: 'log-shipper', + reservedCPU: 50, + reservedMemory: 128, + cpu: [], + memory: [], + }, ], 'tasks represents the tasks for the allocation with no stats yet' ); @@ -307,8 +339,16 @@ module('Unit | Util | AllocationStatsTracker', function () { assert.deepEqual( tracker.get('memory'), [ - { timestamp: makeDate(refDate + 1000), used: 401 * 1024 * 1024, percent: 401 / 512 }, - { timestamp: makeDate(refDate + 2000), used: 402 * 1024 * 1024, percent: 402 / 512 }, + { + timestamp: makeDate(refDate + 1000), + used: 401 * 1024 * 1024, + percent: 401 / 512, + }, + { + timestamp: makeDate(refDate + 2000), + used: 402 * 1024 * 1024, + percent: 402 / 512, + }, ], 'Two frames of memory' ); @@ -435,7 +475,11 @@ module('Unit | Util | AllocationStatsTracker', function () { test('each stat list has maxLength equal to bufferSize', async function (assert) { const allocation = MockAllocation(); const bufferSize = 10; - const tracker = AllocationStatsTracker.create({ fetch, allocation, bufferSize }); + const tracker = AllocationStatsTracker.create({ + fetch, + allocation, + bufferSize, + }); for (let i = 1; i <= 20; i++) { tracker.append(mockFrame(i)); @@ -553,8 +597,9 @@ module('Unit | Util | AllocationStatsTracker', function () { someObject.set('alloc', alloc2); const stats2 = someObject.get('stats'); - assert.notOk( - stats1 === stats2, + assert.notStrictEqual( + stats1, + stats2, 'Changing the value of alloc results in creating a new AllocationStatsTracker instance' ); }); diff --git a/ui/tests/unit/utils/behaviors/stats-tracker-frame-missing.js b/ui/tests/unit/utils/behaviors/stats-tracker-frame-missing.js index e9274b967..77d77f673 100644 --- a/ui/tests/unit/utils/behaviors/stats-tracker-frame-missing.js +++ b/ui/tests/unit/utils/behaviors/stats-tracker-frame-missing.js @@ -27,27 +27,46 @@ export default function statsTrackerFrameMissing({ }; const resource = ResourceConstructor(); - const tracker = TrackerConstructor.create({ fetch, [resourceName]: resource }); + const tracker = TrackerConstructor.create({ + fetch, + [resourceName]: resource, + }); tracker.get('poll').perform(); await settled(); assert.deepEqual(tracker.get('cpu'), [compiledCPU], 'One frame of cpu'); - assert.deepEqual(tracker.get('memory'), [compiledMemory], 'One frame of memory'); + assert.deepEqual( + tracker.get('memory'), + [compiledMemory], + 'One frame of memory' + ); shouldFail = true; tracker.get('poll').perform(); await settled(); - assert.deepEqual(tracker.get('cpu'), [compiledCPU], 'Still one frame of cpu'); - assert.deepEqual(tracker.get('memory'), [compiledMemory], 'Still one frame of memory'); + assert.deepEqual( + tracker.get('cpu'), + [compiledCPU], + 'Still one frame of cpu' + ); + assert.deepEqual( + tracker.get('memory'), + [compiledMemory], + 'Still one frame of memory' + ); assert.equal(tracker.get('frameMisses'), 1, 'Frame miss is tracked'); shouldFail = false; tracker.get('poll').perform(); await settled(); - assert.deepEqual(tracker.get('cpu'), [compiledCPU, compiledCPU], 'Still one frame of cpu'); + assert.deepEqual( + tracker.get('cpu'), + [compiledCPU, compiledCPU], + 'Still one frame of cpu' + ); assert.deepEqual( tracker.get('memory'), [compiledMemory, compiledMemory], @@ -85,6 +104,9 @@ export default function statsTrackerFrameMissing({ await settled(); assert.equal(tracker.get('frameMisses'), 0, 'Misses reset'); - assert.ok(tracker.pause.called, 'Pause called now that frameMisses == maxFrameMisses'); + assert.ok( + tracker.pause.called, + 'Pause called now that frameMisses == maxFrameMisses' + ); }); } diff --git a/ui/tests/unit/utils/format-duration-test.js b/ui/tests/unit/utils/format-duration-test.js index 32e540425..dd02d0f77 100644 --- a/ui/tests/unit/utils/format-duration-test.js +++ b/ui/tests/unit/utils/format-duration-test.js @@ -3,7 +3,8 @@ import formatDuration from 'nomad-ui/utils/format-duration'; module('Unit | Util | formatDuration', function () { test('When all units have values, all units are displayed', function (assert) { - const expectation = '39 years 1 month 13 days 23h 31m 30s 987ms 654µs 400ns'; + const expectation = + '39 years 1 month 13 days 23h 31m 30s 987ms 654µs 400ns'; assert.equal(formatDuration(1234567890987654321), expectation, expectation); }); @@ -23,13 +24,21 @@ module('Unit | Util | formatDuration', function () { test('When duration is 0, 0 is shown in terms of the units provided to the function', function (assert) { assert.equal(formatDuration(0), '0ns', 'formatDuration(0) -> 0ns'); - assert.equal(formatDuration(0, 'year'), '0 years', 'formatDuration(0, "year") -> 0 years'); + assert.equal( + formatDuration(0, 'year'), + '0 years', + 'formatDuration(0, "year") -> 0 years' + ); }); test('The longForm option expands suffixes to words', function (assert) { const expectation1 = '3 seconds 20ms'; const expectation2 = '5 hours 59 minutes'; assert.equal(formatDuration(3020, 'ms', true), expectation1, expectation1); - assert.equal(formatDuration(60 * 5 + 59, 'm', true), expectation2, expectation2); + assert.equal( + formatDuration(60 * 5 + 59, 'm', true), + expectation2, + expectation2 + ); }); }); diff --git a/ui/tests/unit/utils/generate-exec-url-test.js b/ui/tests/unit/utils/generate-exec-url-test.js index 9b02812d7..81481e8e3 100644 --- a/ui/tests/unit/utils/generate-exec-url-test.js +++ b/ui/tests/unit/utils/generate-exec-url-test.js @@ -26,9 +26,14 @@ module('Unit | Utility | generate-exec-url', function (hooks) { }); assert.ok( - this.urlForSpy.calledWith('exec.task-group', 'job-name', 'task-group-name', { - queryParams: { allocation: 'allocation-short-id' }, - }) + this.urlForSpy.calledWith( + 'exec.task-group', + 'job-name', + 'task-group-name', + { + queryParams: { allocation: 'allocation-short-id' }, + } + ) ); }); @@ -61,7 +66,12 @@ module('Unit | Utility | generate-exec-url', function (hooks) { }); assert.ok( - this.urlForSpy.calledWith('exec.task-group', 'job-name', 'task-group-name', emptyOptions) + this.urlForSpy.calledWith( + 'exec.task-group', + 'job-name', + 'task-group-name', + emptyOptions + ) ); }); @@ -92,7 +102,12 @@ module('Unit | Utility | generate-exec-url', function (hooks) { }); assert.ok( - this.urlForSpy.calledWith('exec.task-group.task', 'job-name', 'task-group-name', 'task-name') + this.urlForSpy.calledWith( + 'exec.task-group.task', + 'job-name', + 'task-group-name', + 'task-name' + ) ); }); @@ -105,13 +120,25 @@ module('Unit | Utility | generate-exec-url', function (hooks) { plainId: 'job-name', region: 'a-region', }, - allocation: { shortId: 'id', taskGroup: { name: 'task-group-name', tasks: [0, 1] } }, + allocation: { + shortId: 'id', + taskGroup: { name: 'task-group-name', tasks: [0, 1] }, + }, }); assert.ok( - this.urlForSpy.calledWith('exec.task-group', 'job-name', 'task-group-name', { - queryParams: { allocation: 'id', namespace: 'a-namespace', region: 'a-region' }, - }) + this.urlForSpy.calledWith( + 'exec.task-group', + 'job-name', + 'task-group-name', + { + queryParams: { + allocation: 'id', + namespace: 'a-namespace', + region: 'a-region', + }, + } + ) ); }); }); diff --git a/ui/tests/unit/utils/log-test.js b/ui/tests/unit/utils/log-test.js index d49b50eb8..e1770022d 100644 --- a/ui/tests/unit/utils/log-test.js +++ b/ui/tests/unit/utils/log-test.js @@ -38,7 +38,12 @@ const MockStreamer = EmberObject.extend({ const Log = _Log.extend({ init() { this._super(); - const props = this.logStreamer.getProperties('url', 'params', 'logFetch', 'write'); + const props = this.logStreamer.getProperties( + 'url', + 'params', + 'logFetch', + 'write' + ); this.set('logStreamer', MockStreamer.create(props)); }, }); @@ -81,7 +86,10 @@ module('Unit | Util | Log', function (hooks) { run(() => { log.get('gotoHead').perform(); - assert.ok(fetchSpy.calledWith(expectedUrl), `gotoHead URL was ${expectedUrl}`); + assert.ok( + fetchSpy.calledWith(expectedUrl), + `gotoHead URL was ${expectedUrl}` + ); }); }); @@ -117,7 +125,10 @@ module('Unit | Util | Log', function (hooks) { run(() => { log.get('gotoTail').perform(); - assert.ok(fetchSpy.calledWith(expectedUrl), `gotoTail URL was ${expectedUrl}`); + assert.ok( + fetchSpy.calledWith(expectedUrl), + `gotoTail URL was ${expectedUrl}` + ); }); }); @@ -126,7 +137,11 @@ module('Unit | Util | Log', function (hooks) { log.startStreaming(); assert.ok(startSpy.calledOnce, 'Streaming started'); - assert.equal(log.get('logPointer'), 'tail', 'Streaming points the log to the tail'); + assert.equal( + log.get('logPointer'), + 'tail', + 'Streaming points the log to the tail' + ); }); test('When the log streamer calls `write`, the output is appended', async function (assert) { @@ -145,7 +160,11 @@ module('Unit | Util | Log', function (hooks) { assert.equal(log.get('output'), chunk1 + chunk2, 'Second chunk written'); log.get('logStreamer').step(chunk3); - assert.equal(log.get('output'), chunk1 + chunk2 + chunk3, 'Third chunk written'); + assert.equal( + log.get('output'), + chunk1 + chunk2 + chunk3, + 'Third chunk written' + ); }); test('stop stops the log streamer', async function (assert) { diff --git a/ui/tests/unit/utils/message-from-adapter-error-test.js b/ui/tests/unit/utils/message-from-adapter-error-test.js index 16040f560..2fe795356 100644 --- a/ui/tests/unit/utils/message-from-adapter-error-test.js +++ b/ui/tests/unit/utils/message-from-adapter-error-test.js @@ -10,7 +10,10 @@ const testCases = [ }, { name: 'Generic Error', - in: [new ServerError([{ detail: 'DB Max Connections' }], 'Server Error'), 'run tests'], + in: [ + new ServerError([{ detail: 'DB Max Connections' }], 'Server Error'), + 'run tests', + ], out: 'DB Max Connections', }, { diff --git a/ui/tests/unit/utils/node-stats-tracker-test.js b/ui/tests/unit/utils/node-stats-tracker-test.js index cbb311791..1729e14e7 100644 --- a/ui/tests/unit/utils/node-stats-tracker-test.js +++ b/ui/tests/unit/utils/node-stats-tracker-test.js @@ -3,7 +3,9 @@ import { assign } from '@ember/polyfills'; import { module, test } from 'qunit'; import sinon from 'sinon'; import Pretender from 'pretender'; -import NodeStatsTracker, { stats } from 'nomad-ui/utils/classes/node-stats-tracker'; +import NodeStatsTracker, { + stats, +} from 'nomad-ui/utils/classes/node-stats-tracker'; import fetch from 'nomad-ui/utils/fetch'; import statsTrackerFrameMissingBehavior from './behaviors/stats-tracker-frame-missing'; @@ -59,7 +61,11 @@ module('Unit | Util | NodeStatsTracker', function () { const node = MockNode(); const tracker = NodeStatsTracker.create({ fetch, node }); - assert.equal(tracker.get('reservedCPU'), node.resources.cpu, 'reservedCPU comes from the node'); + assert.equal( + tracker.get('reservedCPU'), + node.resources.cpu, + 'reservedCPU comes from the node' + ); assert.equal( tracker.get('reservedMemory'), node.resources.memory, @@ -69,7 +75,11 @@ module('Unit | Util | NodeStatsTracker', function () { test('poll results in requesting the url and calling append with the resulting JSON', async function (assert) { const node = MockNode(); - const tracker = NodeStatsTracker.create({ fetch, node, append: sinon.spy() }); + const tracker = NodeStatsTracker.create({ + fetch, + node, + append: sinon.spy(), + }); const mockFrame = { Some: { data: ['goes', 'here'], @@ -116,7 +126,13 @@ module('Unit | Util | NodeStatsTracker', function () { assert.deepEqual( tracker.get('memory'), - [{ timestamp: makeDate(refDate + 1), used: 2049 * 1024 * 1024, percent: 2049 / 4096 }], + [ + { + timestamp: makeDate(refDate + 1), + used: 2049 * 1024 * 1024, + percent: 2049 / 4096, + }, + ], 'One frame of memory' ); @@ -134,8 +150,16 @@ module('Unit | Util | NodeStatsTracker', function () { assert.deepEqual( tracker.get('memory'), [ - { timestamp: makeDate(refDate + 1), used: 2049 * 1024 * 1024, percent: 2049 / 4096 }, - { timestamp: makeDate(refDate + 2), used: 2050 * 1024 * 1024, percent: 2050 / 4096 }, + { + timestamp: makeDate(refDate + 1), + used: 2049 * 1024 * 1024, + percent: 2049 / 4096, + }, + { + timestamp: makeDate(refDate + 2), + used: 2050 * 1024 * 1024, + percent: 2050 / 4096, + }, ], 'Two frames of memory' ); @@ -216,8 +240,9 @@ module('Unit | Util | NodeStatsTracker', function () { someObject.set('theNode', node2); const stats2 = someObject.get('stats'); - assert.notOk( - stats1 === stats2, + assert.notStrictEqual( + stats1, + stats2, 'Changing the value of the node results in creating a new NodeStatsTracker instance' ); }); diff --git a/ui/tests/unit/utils/rolling-array-test.js b/ui/tests/unit/utils/rolling-array-test.js index 22f2773fb..9bf5c290a 100644 --- a/ui/tests/unit/utils/rolling-array-test.js +++ b/ui/tests/unit/utils/rolling-array-test.js @@ -21,7 +21,11 @@ module('Unit | Util | RollingArray', function () { array.length, 'the return value from push is equal to the return value of Array#push' ); - assert.equal(array[0], 'a', 'the arguments passed to push are appended to the array'); + assert.equal( + array[0], + 'a', + 'the arguments passed to push are appended to the array' + ); array.push('b', 'c', 'd'); assert.deepEqual( @@ -85,7 +89,7 @@ module('Unit | Util | RollingArray', function () { test('RollingArray is an instance of Array', function (assert) { const array = RollingArray(5); - assert.ok(array.constructor === Array, 'The constructor is Array'); + assert.strictEqual(array.constructor, Array, 'The constructor is Array'); assert.ok(array instanceof Array, 'The instanceof check is true'); assert.ok(isArray(array), 'The ember isArray helper works'); }); diff --git a/ui/tests/unit/utils/stream-logger-test.js b/ui/tests/unit/utils/stream-logger-test.js index 3349775a7..4bbf0c4e1 100644 --- a/ui/tests/unit/utils/stream-logger-test.js +++ b/ui/tests/unit/utils/stream-logger-test.js @@ -65,7 +65,9 @@ class FetchMock { if (this._closeRequest) { this._closeRequest(this.response); } else { - throw new Error('Must call FetchMock.request() before FetchMock.closeRequest'); + throw new Error( + 'Must call FetchMock.request() before FetchMock.closeRequest' + ); } } } diff --git a/ui/tests/unit/utils/units-test.js b/ui/tests/unit/utils/units-test.js index ebef77681..5c8e5b39f 100644 --- a/ui/tests/unit/utils/units-test.js +++ b/ui/tests/unit/utils/units-test.js @@ -18,11 +18,23 @@ module('Unit | Util | units#formatBytes', function () { { in: [1023], out: '1,023 Bytes' }, { in: [1024], out: '1 KiB', name: 'formats 1024 <= x < 1024^2 as KiB' }, { in: [1024 ** 2 - 1024 * 0.01], out: '1,023.99 KiB' }, - { in: [1024 ** 2], out: '1 MiB', name: 'formats 1024^2 <= x < 1024^3 as MiB' }, + { + in: [1024 ** 2], + out: '1 MiB', + name: 'formats 1024^2 <= x < 1024^3 as MiB', + }, { in: [1024 ** 2 * 1.016], out: '1.02 MiB' }, - { in: [1024 ** 3], out: '1 GiB', name: 'formats 1024^3 <= x < 1024^4 as GiB' }, + { + in: [1024 ** 3], + out: '1 GiB', + name: 'formats 1024^3 <= x < 1024^4 as GiB', + }, { in: [1024 ** 3 * 512.5], out: '512.5 GiB' }, - { in: [1024 ** 4], out: '1 TiB', name: 'formats 1024^4 <= x < 1024^5 as TiB' }, + { + in: [1024 ** 4], + out: '1 TiB', + name: 'formats 1024^4 <= x < 1024^5 as TiB', + }, { in: [1024 ** 4 * 2.1234], out: '2.12 TiB' }, { in: [1024 ** 5], out: '1 PiB', name: 'formats x > 1024^5 as PiB' }, { in: [1024 ** 5 * 4000], out: '4,000 PiB' }, @@ -31,7 +43,11 @@ module('Unit | Util | units#formatBytes', function () { out: '1 TiB', name: 'accepts a starting unit size as an optional argument', }, - { in: [1024 ** 2 * -1], out: '-1 MiB', name: 'negative values are still reduced' }, + { + in: [1024 ** 2 * -1], + out: '-1 MiB', + name: 'negative values are still reduced', + }, ]); }); @@ -55,7 +71,11 @@ module('Unit | Util | units#formatScheduledBytes', function () { out: '2,000 MiB', name: 'accepts a starting unit size as an optional argument', }, - { in: [1024 ** 3 * -1], out: '-1,024 MiB', name: 'negative values are still reduced' }, + { + in: [1024 ** 3 * -1], + out: '-1,024 MiB', + name: 'negative values are still reduced', + }, ]); }); @@ -67,11 +87,23 @@ module('Unit | Util | units#formatHertz', function () { { in: [999], out: '999 Hz' }, { in: [1000], out: '1 KHz', name: 'formats 1000 <= x < 1000^2 as KHz' }, { in: [1000 ** 2 - 10], out: '999.99 KHz' }, - { in: [1000 ** 2], out: '1 MHz', name: 'formats 1000^2 <= x < 1000^3 as MHz' }, + { + in: [1000 ** 2], + out: '1 MHz', + name: 'formats 1000^2 <= x < 1000^3 as MHz', + }, { in: [1000 ** 2 * 5.234], out: '5.23 MHz' }, - { in: [1000 ** 3], out: '1 GHz', name: 'formats 1000^3 <= x < 1000^4 as GHz' }, + { + in: [1000 ** 3], + out: '1 GHz', + name: 'formats 1000^3 <= x < 1000^4 as GHz', + }, { in: [1000 ** 3 * 500.238], out: '500.24 GHz' }, - { in: [1000 ** 4], out: '1 THz', name: 'formats 1000^4 <= x < 1000^5 as THz' }, + { + in: [1000 ** 4], + out: '1 THz', + name: 'formats 1000^4 <= x < 1000^5 as THz', + }, { in: [1000 ** 4 * 12], out: '12 THz' }, { in: [1000 ** 5], out: '1 PHz', name: 'formats x > 1000^5 as PHz' }, { in: [1000 ** 5 * 34567.89], out: '34,567.89 PHz' }, @@ -80,7 +112,11 @@ module('Unit | Util | units#formatHertz', function () { out: '2 MHz', name: 'accepts a starting unit size as an optional argument', }, - { in: [1000 ** 3 * -1], out: '-1 GHz', name: 'negative values are still reduced' }, + { + in: [1000 ** 3 * -1], + out: '-1 GHz', + name: 'negative values are still reduced', + }, ]); }); @@ -104,13 +140,21 @@ module('Unit | Util | units#formatScheduledHertz', function () { out: '2,000 MHz', name: 'accepts a starting unit size as an optional argument', }, - { in: [1000 ** 3 * -1], out: '-1,000 MHz', name: 'negative values are still reduced' }, + { + in: [1000 ** 3 * -1], + out: '-1,000 MHz', + name: 'negative values are still reduced', + }, ]); }); module('Unit | Util | units#reduceBytes', function () { table.call(this, units.reduceBytes, [ - { in: [], out: [0, 'Bytes'], name: 'No args behavior results in valid output' }, + { + in: [], + out: [0, 'Bytes'], + name: 'No args behavior results in valid output', + }, { in: [1024 ** 6], out: [1024, 'PiB'], name: 'Max default unit is PiB' }, { in: [1024 ** 6 * 1.12345], @@ -127,13 +171,21 @@ module('Unit | Util | units#reduceBytes', function () { out: [1024, 'MiB'], name: 'accepts a starting unit size as an optional argument', }, - { in: [1024 ** 3 * -1], out: [-1, 'GiB'], name: 'negative values are still reduced' }, + { + in: [1024 ** 3 * -1], + out: [-1, 'GiB'], + name: 'negative values are still reduced', + }, ]); }); module('Unit | Util | units#reduceHertz', function () { table.call(this, units.reduceHertz, [ - { in: [], out: [0, 'Hz'], name: 'No args behavior results in valid output' }, + { + in: [], + out: [0, 'Hz'], + name: 'No args behavior results in valid output', + }, { in: [1000 ** 6], out: [1000, 'PHz'], name: 'Max default unit is PHz' }, { in: [1000 ** 6 * 1.12345], @@ -150,6 +202,10 @@ module('Unit | Util | units#reduceHertz', function () { out: [2, 'GHz'], name: 'accepts a starting unit size as an optional argument', }, - { in: [1000 ** 3 * -1], out: [-1, 'GHz'], name: 'negative values are still reduced' }, + { + in: [1000 ** 3 * -1], + out: [-1, 'GHz'], + name: 'negative values are still reduced', + }, ]); }); diff --git a/ui/tests/utils/ember-power-select-extensions.js b/ui/tests/utils/ember-power-select-extensions.js index d4b66dd4f..1e63256ac 100644 --- a/ui/tests/utils/ember-power-select-extensions.js +++ b/ui/tests/utils/ember-power-select-extensions.js @@ -10,10 +10,15 @@ import { click, settled } from '@ember/test-helpers'; // these two moments. Doing it before opening means hanging on open not on select. Doing it // after means hanging after the select has occurred (too late). async function openIfClosedAndGetContentId(trigger) { - let contentId = trigger.attributes['aria-owns'] && `${trigger.attributes['aria-owns'].value}`; + let contentId = + trigger.attributes['aria-owns'] && + `${trigger.attributes['aria-owns'].value}`; let content = contentId ? document.querySelector(`#${contentId}`) : undefined; // If the dropdown is closed, open it - if (!content || content.classList.contains('ember-basic-dropdown-content-placeholder')) { + if ( + !content || + content.classList.contains('ember-basic-dropdown-content-placeholder') + ) { await click(trigger); contentId = `${trigger.attributes['aria-owns'].value}`; @@ -30,7 +35,9 @@ export async function selectOpen(cssPathOrTrigger) { trigger = cssPathOrTrigger.querySelector('.ember-power-select-trigger'); } } else { - trigger = document.querySelector(`${cssPathOrTrigger} .ember-power-select-trigger`); + trigger = document.querySelector( + `${cssPathOrTrigger} .ember-power-select-trigger` + ); if (!trigger) { trigger = document.querySelector(cssPathOrTrigger); @@ -50,15 +57,23 @@ export async function selectOpen(cssPathOrTrigger) { return await openIfClosedAndGetContentId(trigger); } -export async function selectOpenChoose(contentId, valueOrSelector, optionIndex) { +export async function selectOpenChoose( + contentId, + valueOrSelector, + optionIndex +) { let target; // Select the option with the given text - let options = document.querySelectorAll(`#${contentId} .ember-power-select-option`); + let options = document.querySelectorAll( + `#${contentId} .ember-power-select-option` + ); let potentialTargets = [].slice .apply(options) .filter((opt) => opt.textContent.indexOf(valueOrSelector) > -1); if (potentialTargets.length === 0) { - potentialTargets = document.querySelectorAll(`#${contentId} ${valueOrSelector}`); + potentialTargets = document.querySelectorAll( + `#${contentId} ${valueOrSelector}` + ); } if (potentialTargets.length > 1) { let filteredTargets = [].slice