From 0b182ccf6ffeb25ec0f006073d89a67b6d304a7d Mon Sep 17 00:00:00 2001 From: Panu Horsmalahti Date: Thu, 19 Nov 2020 17:05:26 +0200 Subject: [PATCH] Add a few missing folders to be linted. Signed-off-by: Panu Horsmalahti --- __mocks__/electron.ts | 2 +- build/build_tray_icon.ts | 14 +- build/download_helm.ts | 4 +- build/download_kubectl.ts | 90 ++--- build/notarize.js | 2 +- build/set_npm_version.ts | 14 +- extensions/example-extension/page.tsx | 8 +- extensions/example-extension/renderer.tsx | 4 +- .../kube-object-event-status/renderer.tsx | 2 +- .../kube-object-event-status/src/resolver.tsx | 20 +- extensions/license-menu-item/main.ts | 2 +- .../license-menu-item/webpack.config.ts | 2 +- .../metrics-cluster-feature/renderer.tsx | 10 +- .../src/metrics-feature.ts | 36 +- extensions/node-menu/renderer.tsx | 4 +- extensions/node-menu/src/node-menu.tsx | 16 +- extensions/pod-menu/renderer.tsx | 6 +- extensions/pod-menu/src/logs-menu.tsx | 10 +- extensions/pod-menu/src/shell-menu.tsx | 18 +- extensions/support-page/src/support.tsx | 6 +- extensions/support-page/webpack.config.ts | 2 +- extensions/telemetry/main.ts | 14 +- extensions/telemetry/renderer.tsx | 14 +- .../telemetry/src/telemetry-preference.tsx | 12 +- .../src/telemetry-preferences-store.ts | 10 +- extensions/telemetry/src/tracker.ts | 86 ++--- integration/__tests__/app.tests.ts | 328 +++++++++--------- integration/helpers/utils.ts | 12 +- package.json | 2 +- 29 files changed, 376 insertions(+), 374 deletions(-) diff --git a/__mocks__/electron.ts b/__mocks__/electron.ts index 08c94f0f8c..86f35c956d 100644 --- a/__mocks__/electron.ts +++ b/__mocks__/electron.ts @@ -5,7 +5,7 @@ module.exports = { getVersion: jest.fn().mockReturnValue("3.0.0"), getLocale: jest.fn().mockRejectedValue("en"), getPath: jest.fn((name: string) => { - return "tmp" + return "tmp"; }), }, remote: { diff --git a/build/build_tray_icon.ts b/build/build_tray_icon.ts index 00d09b69bc..e02d884412 100644 --- a/build/build_tray_icon.ts +++ b/build/build_tray_icon.ts @@ -1,9 +1,9 @@ // Generate tray icons from SVG to PNG + different sizes and colors (B&W) // Command: `yarn build:tray-icons` -import path from "path" +import path from "path"; import sharp from "sharp"; -import jsdom from "jsdom" -import fs from "fs-extra" +import jsdom from "jsdom"; +import fs from "fs-extra"; export async function generateTrayIcon( { @@ -14,15 +14,15 @@ export async function generateTrayIcon( pixelSize = 32, shouldUseDarkColors = false, // managed by electron.nativeTheme.shouldUseDarkColors } = {}) { - outputFilename += shouldUseDarkColors ? "_dark" : "" - dpiSuffix = dpiSuffix !== "1x" ? `@${dpiSuffix}` : "" - const pngIconDestPath = path.resolve(outputFolder, `${outputFilename}${dpiSuffix}.png`) + outputFilename += shouldUseDarkColors ? "_dark" : ""; + dpiSuffix = dpiSuffix !== "1x" ? `@${dpiSuffix}` : ""; + const pngIconDestPath = path.resolve(outputFolder, `${outputFilename}${dpiSuffix}.png`); try { // Modify .SVG colors const trayIconColor = shouldUseDarkColors ? "white" : "black"; const svgDom = await jsdom.JSDOM.fromFile(svgIconPath); const svgRoot = svgDom.window.document.body.getElementsByTagName("svg")[0]; - svgRoot.innerHTML += `` + svgRoot.innerHTML += ``; const svgIconBuffer = Buffer.from(svgRoot.outerHTML); // Resize and convert to .PNG diff --git a/build/download_helm.ts b/build/download_helm.ts index 9dddf7fcdc..7a3dc62a72 100644 --- a/build/download_helm.ts +++ b/build/download_helm.ts @@ -1,3 +1,3 @@ -import { helmCli } from "../src/main/helm/helm-cli" +import { helmCli } from "../src/main/helm/helm-cli"; -helmCli.ensureBinary() +helmCli.ensureBinary(); diff --git a/build/download_kubectl.ts b/build/download_kubectl.ts index a697552aa8..c3d6621bcb 100644 --- a/build/download_kubectl.ts +++ b/build/download_kubectl.ts @@ -1,10 +1,10 @@ -import packageInfo from "../package.json" -import fs from "fs" -import request from "request" -import md5File from "md5-file" -import requestPromise from "request-promise-native" -import { ensureDir, pathExists } from "fs-extra" -import path from "path" +import packageInfo from "../package.json"; +import fs from "fs"; +import request from "request"; +import md5File from "md5-file"; +import requestPromise from "request-promise-native"; +import { ensureDir, pathExists } from "fs-extra"; +import path from "path"; class KubectlDownloader { public kubectlVersion: string @@ -14,7 +14,7 @@ class KubectlDownloader { constructor(clusterVersion: string, platform: string, arch: string, target: string) { this.kubectlVersion = clusterVersion; - const binaryName = platform === "windows" ? "kubectl.exe" : "kubectl" + const binaryName = platform === "windows" ? "kubectl.exe" : "kubectl"; this.url = `https://storage.googleapis.com/kubernetes-release/release/v${this.kubectlVersion}/bin/${platform}/${arch}/${binaryName}`; this.dirname = path.dirname(target); this.path = target; @@ -25,83 +25,85 @@ class KubectlDownloader { method: "HEAD", uri: this.url, resolveWithFullResponse: true - }).catch((error) => { console.log(error) }) + }).catch((error) => { console.log(error); }); if (response.headers["etag"]) { - return response.headers["etag"].replace(/"/g, "") + return response.headers["etag"].replace(/"/g, ""); } - return "" + return ""; } public async checkBinary() { - const exists = await pathExists(this.path) + const exists = await pathExists(this.path); if (exists) { - const hash = md5File.sync(this.path) - const etag = await this.urlEtag() + const hash = md5File.sync(this.path); + const etag = await this.urlEtag(); if(hash == etag) { - console.log("Kubectl md5sum matches the remote etag") - return true + console.log("Kubectl md5sum matches the remote etag"); + return true; } - console.log("Kubectl md5sum " + hash + " does not match the remote etag " + etag + ", unlinking and downloading again") - await fs.promises.unlink(this.path) + console.log("Kubectl md5sum " + hash + " does not match the remote etag " + etag + ", unlinking and downloading again"); + await fs.promises.unlink(this.path); } - return false + return false; } public async downloadKubectl() { const exists = await this.checkBinary(); if(exists) { - console.log("Already exists and is valid") - return + console.log("Already exists and is valid"); + return; } - await ensureDir(path.dirname(this.path), 0o755) + await ensureDir(path.dirname(this.path), 0o755); - const file = fs.createWriteStream(this.path) - console.log(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`) + const file = fs.createWriteStream(this.path); + console.log(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`); const requestOpts: request.UriOptions & request.CoreOptions = { uri: this.url, gzip: true - } - const stream = request(requestOpts) + }; + const stream = request(requestOpts); stream.on("complete", () => { - console.log("kubectl binary download finished") - file.end(() => {}) - }) + console.log("kubectl binary download finished"); + // eslint-disable-next-line @typescript-eslint/no-empty-function + file.end(() => {}); + }); stream.on("error", (error) => { - console.log(error) - fs.unlink(this.path, () => {}) - throw(error) - }) + console.log(error); + // eslint-disable-next-line @typescript-eslint/no-empty-function + fs.unlink(this.path, () => {}); + throw(error); + }); return new Promise((resolve, reject) => { file.on("close", () => { - console.log("kubectl binary download closed") + console.log("kubectl binary download closed"); fs.chmod(this.path, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } } const downloadVersion = packageInfo.config.bundledKubectlVersion; -const baseDir = path.join(process.env.INIT_CWD, 'binaries', 'client') +const baseDir = path.join(process.env.INIT_CWD, 'binaries', 'client'); const downloads = [ { platform: 'linux', arch: 'amd64', target: path.join(baseDir, 'linux', 'x64', 'kubectl') }, { platform: 'darwin', arch: 'amd64', target: path.join(baseDir, 'darwin', 'x64', 'kubectl') }, { platform: 'windows', arch: 'amd64', target: path.join(baseDir, 'windows', 'x64', 'kubectl.exe') }, { platform: 'windows', arch: '386', target: path.join(baseDir, 'windows', 'ia32', 'kubectl.exe') } -] +]; downloads.forEach((dlOpts) => { - console.log(dlOpts) + console.log(dlOpts); const downloader = new KubectlDownloader(downloadVersion, dlOpts.platform, dlOpts.arch, dlOpts.target); console.log("Downloading: " + JSON.stringify(dlOpts)); - downloader.downloadKubectl().then(() => downloader.checkBinary().then(() => console.log("Download complete"))) -}) + downloader.downloadKubectl().then(() => downloader.checkBinary().then(() => console.log("Download complete"))); +}); diff --git a/build/notarize.js b/build/notarize.js index 3d97b152c5..9904dccc3b 100644 --- a/build/notarize.js +++ b/build/notarize.js @@ -1,4 +1,4 @@ -const { notarize } = require('electron-notarize') +const { notarize } = require('electron-notarize'); exports.default = async function notarizing(context) { const { electronPlatformName, appOutDir } = context; diff --git a/build/set_npm_version.ts b/build/set_npm_version.ts index 70ce97416d..17d4a1ef83 100644 --- a/build/set_npm_version.ts +++ b/build/set_npm_version.ts @@ -1,9 +1,9 @@ -import * as fs from "fs" -import * as path from "path" -import packageInfo from "../src/extensions/npm/extensions/package.json" -import appInfo from "../package.json" +import * as fs from "fs"; +import * as path from "path"; +import packageInfo from "../src/extensions/npm/extensions/package.json"; +import appInfo from "../package.json"; -const packagePath = path.join(__dirname, "../src/extensions/npm/extensions/package.json") +const packagePath = path.join(__dirname, "../src/extensions/npm/extensions/package.json"); -packageInfo.version = appInfo.version -fs.writeFileSync(packagePath, JSON.stringify(packageInfo, null, 2) + "\n") +packageInfo.version = appInfo.version; +fs.writeFileSync(packagePath, JSON.stringify(packageInfo, null, 2) + "\n"); diff --git a/extensions/example-extension/page.tsx b/extensions/example-extension/page.tsx index fbb91848a9..2fe28ea49c 100644 --- a/extensions/example-extension/page.tsx +++ b/extensions/example-extension/page.tsx @@ -1,10 +1,10 @@ import { LensRendererExtension, Component } from "@k8slens/extensions"; import { CoffeeDoodle } from "react-open-doodles"; import path from "path"; -import React from "react" +import React from "react"; export function ExampleIcon(props: Component.IconProps) { - return + return ; } export class ExamplePage extends React.Component<{ extension: LensRendererExtension }> { @@ -16,7 +16,7 @@ export class ExamplePage extends React.Component<{ extension: LensRendererExtens render() { const doodleStyle = { width: "200px" - } + }; return (
@@ -24,6 +24,6 @@ export class ExamplePage extends React.Component<{ extension: LensRendererExtens

File: {__filename}

- ) + ); } } diff --git a/extensions/example-extension/renderer.tsx b/extensions/example-extension/renderer.tsx index 7733ec6e47..ffec687e40 100644 --- a/extensions/example-extension/renderer.tsx +++ b/extensions/example-extension/renderer.tsx @@ -1,6 +1,6 @@ import { LensRendererExtension } from "@k8slens/extensions"; -import { ExampleIcon, ExamplePage } from "./page" -import React from "react" +import { ExampleIcon, ExamplePage } from "./page"; +import React from "react"; export default class ExampleExtension extends LensRendererExtension { clusterPages = [ diff --git a/extensions/kube-object-event-status/renderer.tsx b/extensions/kube-object-event-status/renderer.tsx index d5ca828c22..6224464a56 100644 --- a/extensions/kube-object-event-status/renderer.tsx +++ b/extensions/kube-object-event-status/renderer.tsx @@ -1,5 +1,5 @@ import { LensRendererExtension, K8sApi } from "@k8slens/extensions"; -import { resolveStatus, resolveStatusForCronJobs, resolveStatusForPods } from "./src/resolver" +import { resolveStatus, resolveStatusForCronJobs, resolveStatusForPods } from "./src/resolver"; export default class EventResourceStatusRendererExtension extends LensRendererExtension { kubeObjectStatusTexts = [ diff --git a/extensions/kube-object-event-status/src/resolver.tsx b/extensions/kube-object-event-status/src/resolver.tsx index ee83293815..e3921a9cd0 100644 --- a/extensions/kube-object-event-status/src/resolver.tsx +++ b/extensions/kube-object-event-status/src/resolver.tsx @@ -1,9 +1,9 @@ import { K8sApi } from "@k8slens/extensions"; export function resolveStatus(object: K8sApi.KubeObject): K8sApi.KubeObjectStatus { - const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi) + const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi); const events = (eventStore as K8sApi.EventStore).getEventsByObject(object); - let warnings = events.filter(evt => evt.isWarning()); + const warnings = events.filter(evt => evt.isWarning()); if (!events.length || !warnings.length) { return null; } @@ -12,16 +12,16 @@ export function resolveStatus(object: K8sApi.KubeObject): K8sApi.KubeObjectStatu level: K8sApi.KubeObjectStatusLevel.WARNING, text: `${event.message}`, timestamp: event.metadata.creationTimestamp - } + }; } export function resolveStatusForPods(pod: K8sApi.Pod): K8sApi.KubeObjectStatus { if (!pod.hasIssues()) { - return null + return null; } - const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi) + const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi); const events = (eventStore as K8sApi.EventStore).getEventsByObject(pod); - let warnings = events.filter(evt => evt.isWarning()); + const warnings = events.filter(evt => evt.isWarning()); if (!events.length || !warnings.length) { return null; } @@ -30,13 +30,13 @@ export function resolveStatusForPods(pod: K8sApi.Pod): K8sApi.KubeObjectStatus { level: K8sApi.KubeObjectStatusLevel.WARNING, text: `${event.message}`, timestamp: event.metadata.creationTimestamp - } + }; } export function resolveStatusForCronJobs(cronJob: K8sApi.CronJob): K8sApi.KubeObjectStatus { - const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi) + const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi); let events = (eventStore as K8sApi.EventStore).getEventsByObject(cronJob); - let warnings = events.filter(evt => evt.isWarning()); + const warnings = events.filter(evt => evt.isWarning()); if (cronJob.isNeverRun()) { events = events.filter(event => event.reason != "FailedNeedsStart"); } @@ -48,5 +48,5 @@ export function resolveStatusForCronJobs(cronJob: K8sApi.CronJob): K8sApi.KubeOb level: K8sApi.KubeObjectStatusLevel.WARNING, text: `${event.message}`, timestamp: event.metadata.creationTimestamp - } + }; } \ No newline at end of file diff --git a/extensions/license-menu-item/main.ts b/extensions/license-menu-item/main.ts index d43cf09e96..ca84041036 100644 --- a/extensions/license-menu-item/main.ts +++ b/extensions/license-menu-item/main.ts @@ -6,7 +6,7 @@ export default class LicenseLensMainExtension extends LensMainExtension { parentId: "help", label: "License", async click() { - Util.openExternal("https://k8slens.dev/licenses/eula.md") + Util.openExternal("https://k8slens.dev/licenses/eula.md"); } } ] diff --git a/extensions/license-menu-item/webpack.config.ts b/extensions/license-menu-item/webpack.config.ts index fec13a7096..7edcb8355e 100644 --- a/extensions/license-menu-item/webpack.config.ts +++ b/extensions/license-menu-item/webpack.config.ts @@ -1,4 +1,4 @@ -import path from "path" +import path from "path"; const outputPath = path.resolve(__dirname, 'dist'); diff --git a/extensions/metrics-cluster-feature/renderer.tsx b/extensions/metrics-cluster-feature/renderer.tsx index 58565c13f5..a285328b12 100644 --- a/extensions/metrics-cluster-feature/renderer.tsx +++ b/extensions/metrics-cluster-feature/renderer.tsx @@ -1,6 +1,6 @@ -import { LensRendererExtension } from "@k8slens/extensions" -import { MetricsFeature } from "./src/metrics-feature" -import React from "react" +import { LensRendererExtension } from "@k8slens/extensions"; +import { MetricsFeature } from "./src/metrics-feature"; +import React from "react"; export default class ClusterMetricsFeatureExtension extends LensRendererExtension { clusterFeatures = [ @@ -13,8 +13,8 @@ export default class ClusterMetricsFeatureExtension extends LensRendererExtensio Enable timeseries data visualization (Prometheus stack) for your cluster. Install this only if you don't have existing Prometheus stack installed. You can see preview of manifests here. - - ) + + ); } }, feature: new MetricsFeature() diff --git a/extensions/metrics-cluster-feature/src/metrics-feature.ts b/extensions/metrics-cluster-feature/src/metrics-feature.ts index b42b726c0b..777f36b35a 100644 --- a/extensions/metrics-cluster-feature/src/metrics-feature.ts +++ b/extensions/metrics-cluster-feature/src/metrics-feature.ts @@ -1,6 +1,6 @@ -import { ClusterFeature, Store, K8sApi } from "@k8slens/extensions" -import semver from "semver" -import * as path from "path" +import { ClusterFeature, Store, K8sApi } from "@k8slens/extensions"; +import semver from "semver"; +import * as path from "path"; export interface MetricsConfiguration { // Placeholder for Metrics config structure @@ -51,46 +51,46 @@ export class MetricsFeature extends ClusterFeature.Feature { async install(cluster: Store.Cluster): Promise { // Check if there are storageclasses - const storageClassApi = K8sApi.forCluster(cluster, K8sApi.StorageClass) - const scs = await storageClassApi.list() + const storageClassApi = K8sApi.forCluster(cluster, K8sApi.StorageClass); + const scs = await storageClassApi.list(); this.config.persistence.enabled = scs.some(sc => ( sc.metadata?.annotations?.['storageclass.kubernetes.io/is-default-class'] === 'true' || sc.metadata?.annotations?.['storageclass.beta.kubernetes.io/is-default-class'] === 'true' )); - super.applyResources(cluster, super.renderTemplates(path.join(__dirname, "../resources/"))) + super.applyResources(cluster, super.renderTemplates(path.join(__dirname, "../resources/"))); } async upgrade(cluster: Store.Cluster): Promise { - return this.install(cluster) + return this.install(cluster); } async updateStatus(cluster: Store.Cluster): Promise { try { - const statefulSet = K8sApi.forCluster(cluster, K8sApi.StatefulSet) - const prometheus = await statefulSet.get({name: "prometheus", namespace: "lens-metrics"}) + const statefulSet = K8sApi.forCluster(cluster, K8sApi.StatefulSet); + const prometheus = await statefulSet.get({name: "prometheus", namespace: "lens-metrics"}); if (prometheus?.kind) { this.status.installed = true; this.status.currentVersion = prometheus.spec.template.spec.containers[0].image.split(":")[1]; this.status.canUpgrade = semver.lt(this.status.currentVersion, this.latestVersion, true); } else { - this.status.installed = false + this.status.installed = false; } } catch(e) { if (e?.error?.code === 404) { - this.status.installed = false + this.status.installed = false; } } - return this.status + return this.status; } async uninstall(cluster: Store.Cluster): Promise { - const namespaceApi = K8sApi.forCluster(cluster, K8sApi.Namespace) - const clusterRoleBindingApi = K8sApi.forCluster(cluster, K8sApi.ClusterRoleBinding) - const clusterRoleApi = K8sApi.forCluster(cluster, K8sApi.ClusterRole) + const namespaceApi = K8sApi.forCluster(cluster, K8sApi.Namespace); + const clusterRoleBindingApi = K8sApi.forCluster(cluster, K8sApi.ClusterRoleBinding); + const clusterRoleApi = K8sApi.forCluster(cluster, K8sApi.ClusterRole); - await namespaceApi.delete({name: "lens-metrics"}) - await clusterRoleBindingApi.delete({name: "lens-prometheus"}) - await clusterRoleApi.delete({name: "lens-prometheus"}) } + await namespaceApi.delete({name: "lens-metrics"}); + await clusterRoleBindingApi.delete({name: "lens-prometheus"}); + await clusterRoleApi.delete({name: "lens-prometheus"}); } } diff --git a/extensions/node-menu/renderer.tsx b/extensions/node-menu/renderer.tsx index db8232a518..ebe6cf46ce 100644 --- a/extensions/node-menu/renderer.tsx +++ b/extensions/node-menu/renderer.tsx @@ -1,6 +1,6 @@ import { LensRendererExtension } from "@k8slens/extensions"; -import React from "react" -import { NodeMenu, NodeMenuProps } from "./src/node-menu" +import React from "react"; +import { NodeMenu, NodeMenuProps } from "./src/node-menu"; export default class NodeMenuRendererExtension extends LensRendererExtension { kubeObjectMenuItems = [ diff --git a/extensions/node-menu/src/node-menu.tsx b/extensions/node-menu/src/node-menu.tsx index 8c7466694e..7284518ac4 100644 --- a/extensions/node-menu/src/node-menu.tsx +++ b/extensions/node-menu/src/node-menu.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Component, K8sApi, Navigation} from "@k8slens/extensions" +import { Component, K8sApi, Navigation} from "@k8slens/extensions"; export interface NodeMenuProps extends Component.KubeObjectMenuProps { } @@ -15,7 +15,7 @@ export function NodeMenu(props: NodeMenuProps) { newTab: true, }); Navigation.hideDetails(); - } + }; const shell = () => { Component.createTerminalTab({ @@ -23,15 +23,15 @@ export function NodeMenu(props: NodeMenuProps) { node: nodeName, }); Navigation.hideDetails(); - } + }; const cordon = () => { sendToTerminal(`kubectl cordon ${nodeName}`); - } + }; const unCordon = () => { - sendToTerminal(`kubectl uncordon ${nodeName}`) - } + sendToTerminal(`kubectl uncordon ${nodeName}`); + }; const drain = () => { const command = `kubectl drain ${nodeName} --delete-local-data --ignore-daemonsets --force`; @@ -43,8 +43,8 @@ export function NodeMenu(props: NodeMenuProps) { Are you sure you want to drain {nodeName}?

), - }) - } + }); + }; return ( <> diff --git a/extensions/pod-menu/renderer.tsx b/extensions/pod-menu/renderer.tsx index 30898da806..e13195ee68 100644 --- a/extensions/pod-menu/renderer.tsx +++ b/extensions/pod-menu/renderer.tsx @@ -1,7 +1,7 @@ import { LensRendererExtension } from "@k8slens/extensions"; -import { PodShellMenu, PodShellMenuProps } from "./src/shell-menu" -import { PodLogsMenu, PodLogsMenuProps } from "./src/logs-menu" -import React from "react" +import { PodShellMenu, PodShellMenuProps } from "./src/shell-menu"; +import { PodLogsMenu, PodLogsMenuProps } from "./src/logs-menu"; +import React from "react"; export default class PodMenuRendererExtension extends LensRendererExtension { kubeObjectMenuItems = [ diff --git a/extensions/pod-menu/src/logs-menu.tsx b/extensions/pod-menu/src/logs-menu.tsx index a1a6dba834..2556691ca2 100644 --- a/extensions/pod-menu/src/logs-menu.tsx +++ b/extensions/pod-menu/src/logs-menu.tsx @@ -19,7 +19,7 @@ export class PodLogsMenu extends React.Component { } render() { - const { object: pod, toolbar } = this.props + const { object: pod, toolbar } = this.props; const containers = pod.getAllContainers(); const statuses = pod.getContainerStatuses(); if (!containers.length) return null; @@ -33,25 +33,25 @@ export class PodLogsMenu extends React.Component { { containers.map(container => { - const { name } = container + const { name } = container; const status = statuses.find(status => status.name === name); const brick = status ? ( - ) : null + ) : null; return ( this.showLogs(container))} className="flex align-center"> {brick} {name} - ) + ); }) } )} - ) + ); } } diff --git a/extensions/pod-menu/src/shell-menu.tsx b/extensions/pod-menu/src/shell-menu.tsx index 02e248810b..d33db02d8c 100644 --- a/extensions/pod-menu/src/shell-menu.tsx +++ b/extensions/pod-menu/src/shell-menu.tsx @@ -9,16 +9,16 @@ export interface PodShellMenuProps extends Component.KubeObjectMenuProps { async execShell(container?: string) { Navigation.hideDetails(); - const { object: pod } = this.props - const containerParam = container ? `-c ${container}` : "" - let command = `kubectl exec -i -t -n ${pod.getNs()} ${pod.getName()} ${containerParam} "--"` + const { object: pod } = this.props; + const containerParam = container ? `-c ${container}` : ""; + let command = `kubectl exec -i -t -n ${pod.getNs()} ${pod.getName()} ${containerParam} "--"`; if (window.navigator.platform !== "Win32") { - command = `exec ${command}` + command = `exec ${command}`; } if (pod.getSelectedNodeOs() === "windows") { - command = `${command} powershell` + command = `${command} powershell`; } else { - command = `${command} sh -c "clear; (bash || ash || sh)"` + command = `${command} sh -c "clear; (bash || ash || sh)"`; } const shell = Component.createTerminalTab({ @@ -32,7 +32,7 @@ export class PodShellMenu extends React.Component { } render() { - const { object, toolbar } = this.props + const { object, toolbar } = this.props; const containers = object.getRunningContainers(); if (!containers.length) return null; return ( @@ -51,13 +51,13 @@ export class PodShellMenu extends React.Component { {name} - ) + ); }) } )} - ) + ); } } diff --git a/extensions/support-page/src/support.tsx b/extensions/support-page/src/support.tsx index fbdf54d9eb..e947eb0f60 100644 --- a/extensions/support-page/src/support.tsx +++ b/extensions/support-page/src/support.tsx @@ -1,8 +1,8 @@ // TODO: support localization / figure out how to extract / consume i18n strings -import "./support.scss" -import React from "react" -import { observer } from "mobx-react" +import "./support.scss"; +import React from "react"; +import { observer } from "mobx-react"; import { App, Component } from "@k8slens/extensions"; @observer diff --git a/extensions/support-page/webpack.config.ts b/extensions/support-page/webpack.config.ts index 45ca3d2a10..ca709e6ee0 100644 --- a/extensions/support-page/webpack.config.ts +++ b/extensions/support-page/webpack.config.ts @@ -1,4 +1,4 @@ -import path from "path" +import path from "path"; const outputPath = path.resolve(__dirname, 'dist'); diff --git a/extensions/telemetry/main.ts b/extensions/telemetry/main.ts index aef51ff647..0b6b13f568 100644 --- a/extensions/telemetry/main.ts +++ b/extensions/telemetry/main.ts @@ -1,18 +1,18 @@ import { LensMainExtension } from "@k8slens/extensions"; -import { telemetryPreferencesStore } from "./src/telemetry-preferences-store" +import { telemetryPreferencesStore } from "./src/telemetry-preferences-store"; import { tracker } from "./src/tracker"; export default class TelemetryMainExtension extends LensMainExtension { async onActivate() { - console.log("telemetry main extension activated") - tracker.start() - tracker.reportPeriodically() - await telemetryPreferencesStore.loadExtension(this) + console.log("telemetry main extension activated"); + tracker.start(); + tracker.reportPeriodically(); + await telemetryPreferencesStore.loadExtension(this); } onDeactivate() { - tracker.stop() - console.log("telemetry main extension deactivated") + tracker.stop(); + console.log("telemetry main extension deactivated"); } } diff --git a/extensions/telemetry/renderer.tsx b/extensions/telemetry/renderer.tsx index 04057386bf..1078d18f4c 100644 --- a/extensions/telemetry/renderer.tsx +++ b/extensions/telemetry/renderer.tsx @@ -1,8 +1,8 @@ import { LensRendererExtension } from "@k8slens/extensions"; -import { telemetryPreferencesStore } from "./src/telemetry-preferences-store" -import { TelemetryPreferenceHint, TelemetryPreferenceInput } from "./src/telemetry-preference" -import { tracker } from "./src/tracker" -import React from "react" +import { telemetryPreferencesStore } from "./src/telemetry-preferences-store"; +import { TelemetryPreferenceHint, TelemetryPreferenceInput } from "./src/telemetry-preference"; +import { tracker } from "./src/tracker"; +import React from "react"; export default class TelemetryRendererExtension extends LensRendererExtension { appPreferences = [ @@ -16,8 +16,8 @@ export default class TelemetryRendererExtension extends LensRendererExtension { ]; async onActivate() { - console.log("telemetry extension activated") - tracker.start() - await telemetryPreferencesStore.loadExtension(this) + console.log("telemetry extension activated"); + tracker.start(); + await telemetryPreferencesStore.loadExtension(this); } } diff --git a/extensions/telemetry/src/telemetry-preference.tsx b/extensions/telemetry/src/telemetry-preference.tsx index 122d722a81..f96ed43fb8 100644 --- a/extensions/telemetry/src/telemetry-preference.tsx +++ b/extensions/telemetry/src/telemetry-preference.tsx @@ -1,19 +1,19 @@ -import { Component } from "@k8slens/extensions" -import React from "react" +import { Component } from "@k8slens/extensions"; +import React from "react"; import { observer } from "mobx-react"; -import { TelemetryPreferencesStore } from "./telemetry-preferences-store" +import { TelemetryPreferencesStore } from "./telemetry-preferences-store"; @observer export class TelemetryPreferenceInput extends React.Component<{telemetry: TelemetryPreferencesStore}, {}> { render() { - const { telemetry } = this.props + const { telemetry } = this.props; return ( { telemetry.enabled = v; }} /> - ) + ); } } @@ -21,6 +21,6 @@ export class TelemetryPreferenceHint extends React.Component { render() { return ( Telemetry & usage data is collected to continuously improve the Lens experience. - ) + ); } } diff --git a/extensions/telemetry/src/telemetry-preferences-store.ts b/extensions/telemetry/src/telemetry-preferences-store.ts index e29b0ff461..e20ef1ede8 100644 --- a/extensions/telemetry/src/telemetry-preferences-store.ts +++ b/extensions/telemetry/src/telemetry-preferences-store.ts @@ -1,5 +1,5 @@ import { Store } from "@k8slens/extensions"; -import { toJS } from "mobx" +import { toJS } from "mobx"; export type TelemetryPreferencesModel = { enabled: boolean; @@ -14,11 +14,11 @@ export class TelemetryPreferencesStore extends Store.ExtensionStore() +export const telemetryPreferencesStore = TelemetryPreferencesStore.getInstance(); diff --git a/extensions/telemetry/src/tracker.ts b/extensions/telemetry/src/tracker.ts index f2d3c6c918..9837f4a98b 100644 --- a/extensions/telemetry/src/tracker.ts +++ b/extensions/telemetry/src/tracker.ts @@ -1,8 +1,8 @@ -import { EventBus, Util, Store, App } from "@k8slens/extensions" -import ua from "universal-analytics" -import Analytics from "analytics-node" -import { machineIdSync } from "node-machine-id" -import { telemetryPreferencesStore } from "./telemetry-preferences-store" +import { EventBus, Util, Store, App } from "@k8slens/extensions"; +import ua from "universal-analytics"; +import Analytics from "analytics-node"; +import { machineIdSync } from "node-machine-id"; +import { telemetryPreferencesStore } from "./telemetry-preferences-store"; export class Tracker extends Util.Singleton { static readonly GA_ID = "UA-159377374-1" @@ -23,69 +23,69 @@ export class Tracker extends Util.Singleton { private constructor() { super(); - this.anonymousId = machineIdSync() - this.os = this.resolveOS() - this.userAgent = `Lens ${App.version} (${this.os})` + this.anonymousId = machineIdSync(); + this.os = this.resolveOS(); + this.userAgent = `Lens ${App.version} (${this.os})`; try { - this.visitor = ua(Tracker.GA_ID, this.anonymousId, { strictCidFormat: false }) + this.visitor = ua(Tracker.GA_ID, this.anonymousId, { strictCidFormat: false }); } catch (error) { - this.visitor = ua(Tracker.GA_ID) + this.visitor = ua(Tracker.GA_ID); } - this.analytics = new Analytics(Tracker.SEGMENT_KEY, { flushAt: 1 }) - this.visitor.set("dl", "https://telemetry.k8slens.dev") - this.visitor.set("ua", this.userAgent) + this.analytics = new Analytics(Tracker.SEGMENT_KEY, { flushAt: 1 }); + this.visitor.set("dl", "https://telemetry.k8slens.dev"); + this.visitor.set("ua", this.userAgent); } start() { - if (this.started === true) { return } + if (this.started === true) { return; } - this.started = true + this.started = true; const handler = (ev: EventBus.AppEvent) => { - this.event(ev.name, ev.action, ev.params) - } - this.eventHandlers.push(handler) - EventBus.appEventBus.addListener(handler) + this.event(ev.name, ev.action, ev.params); + }; + this.eventHandlers.push(handler); + EventBus.appEventBus.addListener(handler); } reportPeriodically() { this.reportInterval = setInterval(() => { - this.reportData() - }, 60 * 60 * 1000) // report every 1h + this.reportData(); + }, 60 * 60 * 1000); // report every 1h } stop() { - if (!this.started) { return } + if (!this.started) { return; } - this.started = false + this.started = false; for (const handler of this.eventHandlers) { - EventBus.appEventBus.removeListener(handler) + EventBus.appEventBus.removeListener(handler); } if (this.reportInterval) { - clearInterval(this.reportInterval) + clearInterval(this.reportInterval); } } protected async isTelemetryAllowed(): Promise { - return telemetryPreferencesStore.enabled + return telemetryPreferencesStore.enabled; } protected reportData() { - const clustersList = Store.clusterStore.enabledClustersList + const clustersList = Store.clusterStore.enabledClustersList; this.event("generic-data", "report", { appVersion: App.version, os: this.os, clustersCount: clustersList.length, workspacesCount: Store.workspaceStore.enabledWorkspacesList.length - }) + }); clustersList.forEach((cluster) => { - if (!cluster?.metadata.lastSeen) { return } - this.reportClusterData(cluster) - }) + if (!cluster?.metadata.lastSeen) { return; } + this.reportClusterData(cluster); + }); } protected reportClusterData(cluster: Store.ClusterModel) { @@ -96,26 +96,26 @@ export class Tracker extends Util.Singleton { distribution: cluster.metadata.distribution, nodesCount: cluster.metadata.nodes, lastSeen: cluster.metadata.lastSeen - }) + }); } protected resolveOS() { - let os = "" + let os = ""; if (App.isMac) { - os = "MacOS" + os = "MacOS"; } else if(App.isWindows) { - os = "Windows" + os = "Windows"; } else if (App.isLinux) { - os = "Linux" + os = "Linux"; if (App.isSnap) { - os += "; Snap" + os += "; Snap"; } else { - os += "; AppImage" + os += "; AppImage"; } } else { - os = "Unknown" + os = "Unknown"; } - return os + return os; } protected async event(eventCategory: string, eventAction: string, otherParams = {}) { @@ -128,7 +128,7 @@ export class Tracker extends Util.Singleton { ec: eventCategory, ea: eventAction, ...otherParams, - }).send() + }).send(); this.analytics.track({ anonymousId: this.anonymousId, @@ -141,9 +141,9 @@ export class Tracker extends Util.Singleton { ...otherParams, }, - }) + }); } catch (err) { - console.error(`Failed to track "${eventCategory}:${eventAction}"`, err) + console.error(`Failed to track "${eventCategory}:${eventAction}"`, err); } } } diff --git a/integration/__tests__/app.tests.ts b/integration/__tests__/app.tests.ts index 8845ae91a8..ace852904d 100644 --- a/integration/__tests__/app.tests.ts +++ b/integration/__tests__/app.tests.ts @@ -4,159 +4,159 @@ TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube cluster and vice versa. */ -import { Application } from "spectron" -import * as util from "../helpers/utils" -import { spawnSync } from "child_process" +import { Application } from "spectron"; +import * as util from "../helpers/utils"; +import { spawnSync } from "child_process"; -const describeif = (condition: boolean) => condition ? describe : describe.skip -const itif = (condition: boolean) => condition ? it : it.skip +const describeif = (condition: boolean) => condition ? describe : describe.skip; +const itif = (condition: boolean) => condition ? it : it.skip; -jest.setTimeout(60000) +jest.setTimeout(60000); // FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below) describe("Lens integration tests", () => { - const TEST_NAMESPACE = "integration-tests" + const TEST_NAMESPACE = "integration-tests"; - const BACKSPACE = "\uE003" - let app: Application + const BACKSPACE = "\uE003"; + let app: Application; const appStart = async () => { - app = util.setup() - await app.start() + app = util.setup(); + await app.start(); // Wait for splash screen to be closed while (await app.client.getWindowCount() > 1); - await app.client.windowByIndex(0) - await app.client.waitUntilWindowLoaded() - } + await app.client.windowByIndex(0); + await app.client.waitUntilWindowLoaded(); + }; const clickWhatsNew = async (app: Application) => { - await app.client.waitUntilTextExists("h1", "What's new?") - await app.client.click("button.primary") - await app.client.waitUntilTextExists("h1", "Welcome") - } + await app.client.waitUntilTextExists("h1", "What's new?"); + await app.client.click("button.primary"); + await app.client.waitUntilTextExists("h1", "Welcome"); + }; describe("app start", () => { - beforeAll(appStart, 20000) + beforeAll(appStart, 20000); afterAll(async () => { if (app && app.isRunning()) { - return util.tearDown(app) + return util.tearDown(app); } - }) + }); it('shows "whats new"', async () => { - await clickWhatsNew(app) - }) + await clickWhatsNew(app); + }); it('shows "add cluster"', async () => { - await app.electron.ipcRenderer.send('test-menu-item-click', "File", "Add Cluster") - await app.client.waitUntilTextExists("h2", "Add Cluster") - }) + await app.electron.ipcRenderer.send('test-menu-item-click', "File", "Add Cluster"); + await app.client.waitUntilTextExists("h2", "Add Cluster"); + }); describe("preferences page", () => { it('shows "preferences"', async () => { - let appName: string = process.platform === "darwin" ? "Lens" : "File" - await app.electron.ipcRenderer.send('test-menu-item-click', appName, "Preferences") - await app.client.waitUntilTextExists("h2", "Preferences") - }) + const appName: string = process.platform === "darwin" ? "Lens" : "File"; + await app.electron.ipcRenderer.send('test-menu-item-click', appName, "Preferences"); + await app.client.waitUntilTextExists("h2", "Preferences"); + }); it('ensures helm repos', async () => { - await app.client.waitUntilTextExists("div.repos #message-stable", "stable") // wait for the helm-cli to fetch the stable repo - await app.client.click("#HelmRepoSelect") // click the repo select to activate the drop-down - await app.client.waitUntilTextExists("div.Select__option", "") // wait for at least one option to appear (any text) - }) - }) + await app.client.waitUntilTextExists("div.repos #message-stable", "stable"); // wait for the helm-cli to fetch the stable repo + await app.client.click("#HelmRepoSelect"); // click the repo select to activate the drop-down + await app.client.waitUntilTextExists("div.Select__option", ""); // wait for at least one option to appear (any text) + }); + }); it.skip('quits Lens"', async () => { - await app.client.keys(['Meta', 'Q']) - await app.client.keys('Meta') - }) - }) + await app.client.keys(['Meta', 'Q']); + await app.client.keys('Meta'); + }); + }); const minikubeReady = (): boolean => { // determine if minikube is running - let status = spawnSync("minikube status", { shell: true }) + let status = spawnSync("minikube status", { shell: true }); if (status.status !== 0) { - console.warn("minikube not running") - return false + console.warn("minikube not running"); + return false; } // Remove TEST_NAMESPACE if it already exists - status = spawnSync(`minikube kubectl -- get namespace ${TEST_NAMESPACE}`, { shell: true }) + status = spawnSync(`minikube kubectl -- get namespace ${TEST_NAMESPACE}`, { shell: true }); if (status.status === 0) { - console.warn(`Removing existing ${TEST_NAMESPACE} namespace`) - status = spawnSync(`minikube kubectl -- delete namespace ${TEST_NAMESPACE}`, { shell: true }) + console.warn(`Removing existing ${TEST_NAMESPACE} namespace`); + status = spawnSync(`minikube kubectl -- delete namespace ${TEST_NAMESPACE}`, { shell: true }); if (status.status !== 0) { - console.warn(`Error removing ${TEST_NAMESPACE} namespace: ${status.stderr.toString()}`) - return false + console.warn(`Error removing ${TEST_NAMESPACE} namespace: ${status.stderr.toString()}`); + return false; } - console.log(status.stdout.toString()) + console.log(status.stdout.toString()); } - return true - } - const ready = minikubeReady() + return true; + }; + const ready = minikubeReady(); const addMinikubeCluster = async (app: Application) => { - await app.client.click("div.add-cluster") - await app.client.waitUntilTextExists("div", "Select kubeconfig file") - await app.client.click("div.Select__control") // show the context drop-down list - await app.client.waitUntilTextExists("div", "minikube") + await app.client.click("div.add-cluster"); + await app.client.waitUntilTextExists("div", "Select kubeconfig file"); + await app.client.click("div.Select__control"); // show the context drop-down list + await app.client.waitUntilTextExists("div", "minikube"); if (!await app.client.$("button.primary").isEnabled()) { - await app.client.click("div.minikube") // select minikube context + await app.client.click("div.minikube"); // select minikube context } // else the only context, which must be 'minikube', is automatically selected - await app.client.click("div.Select__control") // hide the context drop-down list (it might be obscuring the Add cluster(s) button) - await app.client.click("button.primary") // add minikube cluster - } + await app.client.click("div.Select__control"); // hide the context drop-down list (it might be obscuring the Add cluster(s) button) + await app.client.click("button.primary"); // add minikube cluster + }; const waitForMinikubeDashboard = async (app: Application) => { - await app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started") - await app.client.waitForExist(`iframe[name="minikube"]`) - await app.client.frame("minikube") - await app.client.waitUntilTextExists("span.link-text", "Cluster") - } + await app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started"); + await app.client.waitForExist(`iframe[name="minikube"]`); + await app.client.frame("minikube"); + await app.client.waitUntilTextExists("span.link-text", "Cluster"); + }; describeif(ready)("cluster tests", () => { - let clusterAdded = false + let clusterAdded = false; const addCluster = async () => { - await clickWhatsNew(app) - await addMinikubeCluster(app) - await waitForMinikubeDashboard(app) - await app.client.click('a[href="/nodes"]') - await app.client.waitUntilTextExists("div.TableCell", "Ready") - } + await clickWhatsNew(app); + await addMinikubeCluster(app); + await waitForMinikubeDashboard(app); + await app.client.click('a[href="/nodes"]'); + await app.client.waitUntilTextExists("div.TableCell", "Ready"); + }; describe("cluster add", () => { - beforeAll(appStart, 20000) + beforeAll(appStart, 20000); afterAll(async () => { if (app && app.isRunning()) { - return util.tearDown(app) + return util.tearDown(app); } - }) + }); it('allows to add a cluster', async () => { - await addCluster() - clusterAdded = true - }) - }) + await addCluster(); + clusterAdded = true; + }); + }); const appStartAddCluster = async () => { if (clusterAdded) { - await appStart() - await addCluster() + await appStart(); + await addCluster(); } - } + }; describe("cluster pages", () => { - beforeAll(appStartAddCluster, 40000) + beforeAll(appStartAddCluster, 40000); afterAll(async () => { if (app && app.isRunning()) { - return util.tearDown(app) + return util.tearDown(app); } - }) + }); const tests: { drawer?: string @@ -394,119 +394,119 @@ describe("Lens integration tests", () => { tests.forEach(({ drawer = "", drawerId = "", pages }) => { if (drawer !== "") { it(`shows ${drawer} drawer`, async () => { - expect(clusterAdded).toBe(true) - await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`) - await app.client.waitUntilTextExists(`a[href^="/${pages[0].href}"]`, pages[0].name) - }) + expect(clusterAdded).toBe(true); + await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`); + await app.client.waitUntilTextExists(`a[href^="/${pages[0].href}"]`, pages[0].name); + }); } pages.forEach(({ name, href, expectedSelector, expectedText }) => { it(`shows ${drawer}->${name} page`, async () => { - expect(clusterAdded).toBe(true) - await app.client.click(`a[href^="/${href}"]`) - await app.client.waitUntilTextExists(expectedSelector, expectedText) - }) - }) + expect(clusterAdded).toBe(true); + await app.client.click(`a[href^="/${href}"]`); + await app.client.waitUntilTextExists(expectedSelector, expectedText); + }); + }); if (drawer !== "") { // hide the drawer it(`hides ${drawer} drawer`, async () => { - expect(clusterAdded).toBe(true) - await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`) - await expect(app.client.waitUntilTextExists(`a[href^="/${pages[0].href}"]`, pages[0].name, 100)).rejects.toThrow() - }) + expect(clusterAdded).toBe(true); + await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`); + await expect(app.client.waitUntilTextExists(`a[href^="/${pages[0].href}"]`, pages[0].name, 100)).rejects.toThrow(); + }); } - }) - }) + }); + }); describe("viewing pod logs", () => { - beforeEach(appStartAddCluster, 40000) + beforeEach(appStartAddCluster, 40000); afterEach(async () => { if (app && app.isRunning()) { - return util.tearDown(app) + return util.tearDown(app); } - }) + }); it(`shows a logs for a pod`, async () => { - expect(clusterAdded).toBe(true) + expect(clusterAdded).toBe(true); // Go to Pods page - await app.client.click(".sidebar-nav [data-test-id='workloads'] span.link-text") - await app.client.waitUntilTextExists('a[href^="/pods"]', "Pods") - await app.client.click('a[href^="/pods"]') - await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver") + await app.client.click(".sidebar-nav [data-test-id='workloads'] span.link-text"); + await app.client.waitUntilTextExists('a[href^="/pods"]', "Pods"); + await app.client.click('a[href^="/pods"]'); + await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver"); // Open logs tab in dock - await app.client.click(".list .TableRow:first-child") - await app.client.waitForVisible(".Drawer") - await app.client.click(".drawer-title .Menu li:nth-child(2)") + await app.client.click(".list .TableRow:first-child"); + await app.client.waitForVisible(".Drawer"); + await app.client.click(".drawer-title .Menu li:nth-child(2)"); // Check if controls are available - await app.client.waitForVisible(".PodLogs .VirtualList") - await app.client.waitForVisible(".PodLogControls") - await app.client.waitForVisible(".PodLogControls .SearchInput") - await app.client.waitForVisible(".PodLogControls .SearchInput input") + await app.client.waitForVisible(".PodLogs .VirtualList"); + await app.client.waitForVisible(".PodLogControls"); + await app.client.waitForVisible(".PodLogControls .SearchInput"); + await app.client.waitForVisible(".PodLogControls .SearchInput input"); // Search for semicolon - await app.client.keys(":") - await app.client.waitForVisible(".PodLogs .list span.active") + await app.client.keys(":"); + await app.client.waitForVisible(".PodLogs .list span.active"); // Click through controls - await app.client.click(".PodLogControls .timestamps-icon") - await app.client.click(".PodLogControls .undo-icon") - }) - }) + await app.client.click(".PodLogControls .timestamps-icon"); + await app.client.click(".PodLogControls .undo-icon"); + }); + }); describe("cluster operations", () => { - beforeEach(appStartAddCluster, 40000) + beforeEach(appStartAddCluster, 40000); afterEach(async () => { if (app && app.isRunning()) { - return util.tearDown(app) + return util.tearDown(app); } - }) + }); it('shows default namespace', async () => { - expect(clusterAdded).toBe(true) - await app.client.click('a[href="/namespaces"]') - await app.client.waitUntilTextExists("div.TableCell", "default") - await app.client.waitUntilTextExists("div.TableCell", "kube-system") - }) + expect(clusterAdded).toBe(true); + await app.client.click('a[href="/namespaces"]'); + await app.client.waitUntilTextExists("div.TableCell", "default"); + await app.client.waitUntilTextExists("div.TableCell", "kube-system"); + }); it(`creates ${TEST_NAMESPACE} namespace`, async () => { - expect(clusterAdded).toBe(true) - await app.client.click('a[href="/namespaces"]') - await app.client.waitUntilTextExists("div.TableCell", "default") - await app.client.waitUntilTextExists("div.TableCell", "kube-system") - await app.client.click("button.add-button") - await app.client.waitUntilTextExists("div.AddNamespaceDialog", "Create Namespace") - await app.client.keys(`${TEST_NAMESPACE}\n`) - await app.client.waitForExist(`.name=${TEST_NAMESPACE}`) - }) + expect(clusterAdded).toBe(true); + await app.client.click('a[href="/namespaces"]'); + await app.client.waitUntilTextExists("div.TableCell", "default"); + await app.client.waitUntilTextExists("div.TableCell", "kube-system"); + await app.client.click("button.add-button"); + await app.client.waitUntilTextExists("div.AddNamespaceDialog", "Create Namespace"); + await app.client.keys(`${TEST_NAMESPACE}\n`); + await app.client.waitForExist(`.name=${TEST_NAMESPACE}`); + }); it(`creates a pod in ${TEST_NAMESPACE} namespace`, async () => { - expect(clusterAdded).toBe(true) - await app.client.click(".sidebar-nav [data-test-id='workloads'] span.link-text") - await app.client.waitUntilTextExists('a[href^="/pods"]', "Pods") - await app.client.click('a[href^="/pods"]') - await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver") - await app.client.click('.Icon.new-dock-tab') - await app.client.waitUntilTextExists("li.MenuItem.create-resource-tab", "Create resource") - await app.client.click("li.MenuItem.create-resource-tab") - await app.client.waitForVisible(".CreateResource div.ace_content") + expect(clusterAdded).toBe(true); + await app.client.click(".sidebar-nav [data-test-id='workloads'] span.link-text"); + await app.client.waitUntilTextExists('a[href^="/pods"]', "Pods"); + await app.client.click('a[href^="/pods"]'); + await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver"); + await app.client.click('.Icon.new-dock-tab'); + await app.client.waitUntilTextExists("li.MenuItem.create-resource-tab", "Create resource"); + await app.client.click("li.MenuItem.create-resource-tab"); + await app.client.waitForVisible(".CreateResource div.ace_content"); // Write pod manifest to editor - await app.client.keys("apiVersion: v1\n") - await app.client.keys("kind: Pod\n") - await app.client.keys("metadata:\n") - await app.client.keys(" name: nginx-create-pod-test\n") - await app.client.keys(`namespace: ${TEST_NAMESPACE}\n`) - await app.client.keys(BACKSPACE + "spec:\n") - await app.client.keys(" containers:\n") - await app.client.keys("- name: nginx-create-pod-test\n") - await app.client.keys(" image: nginx:alpine\n") + await app.client.keys("apiVersion: v1\n"); + await app.client.keys("kind: Pod\n"); + await app.client.keys("metadata:\n"); + await app.client.keys(" name: nginx-create-pod-test\n"); + await app.client.keys(`namespace: ${TEST_NAMESPACE}\n`); + await app.client.keys(BACKSPACE + "spec:\n"); + await app.client.keys(" containers:\n"); + await app.client.keys("- name: nginx-create-pod-test\n"); + await app.client.keys(" image: nginx:alpine\n"); // Create deployment - await app.client.waitForEnabled("button.Button=Create & Close") - await app.client.click("button.Button=Create & Close") + await app.client.waitForEnabled("button.Button=Create & Close"); + await app.client.click("button.Button=Create & Close"); // Wait until first bits of pod appears on dashboard - await app.client.waitForExist(".name=nginx-create-pod-test") + await app.client.waitForExist(".name=nginx-create-pod-test"); // Open pod details - await app.client.click(".name=nginx-create-pod-test") - await app.client.waitUntilTextExists("div.drawer-title-text", "Pod: nginx-create-pod-test") - }) - }) - }) -}) + await app.client.click(".name=nginx-create-pod-test"); + await app.client.waitUntilTextExists("div.drawer-title-text", "Pod: nginx-create-pod-test"); + }); + }); + }); +}); diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts index 65ea9a1a78..32b7bece35 100644 --- a/integration/helpers/utils.ts +++ b/integration/helpers/utils.ts @@ -4,7 +4,7 @@ const AppPaths: Partial> = { "win32": "./dist/win-unpacked/Lens.exe", "linux": "./dist/linux-unpacked/kontena-lens", "darwin": "./dist/mac/Lens.app/Contents/MacOS/Lens", -} +}; export function setup(): Application { return new Application({ @@ -16,16 +16,16 @@ export function setup(): Application { env: { CICD: "true" } - }) + }); } export async function tearDown(app: Application) { - let mpid: any = app.mainProcess.pid - let pid = await mpid() - await app.stop() + const mpid: any = app.mainProcess.pid; + const pid = await mpid(); + await app.stop(); try { process.kill(pid, "SIGKILL"); } catch (e) { - console.error(e) + console.error(e); } } diff --git a/package.json b/package.json index 37a5d7b578..49c7f58bf5 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "download:kubectl": "yarn run ts-node build/download_kubectl.ts", "download:helm": "yarn run ts-node build/download_helm.ts", "build:tray-icons": "yarn run ts-node build/build_tray_icon.ts", - "lint": "yarn run eslint $@ --ext js,ts,tsx --max-warnings=0 src/", + "lint": "yarn run eslint $@ --ext js,ts,tsx --max-warnings=0 src/ integration/ __mocks__/ build/", "lint:fix": "yarn run lint --fix", "mkdocs-serve-local": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest", "typedocs-extensions-api": "yarn run typedoc --ignoreCompilerErrors --readme docs/extensions/typedoc-readme.md.tpl --name @k8slens/extensions --out docs/extensions/api --mode library --excludePrivate --hideBreadcrumbs --includes src/ src/extensions/extension-api.ts"