mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix Input not working when not provided with an AsyncValidator
- Added logging by default for non-CI environments running integration tests - Increasing the timeout on integration tests so that spectron is more likely to error out instead (should help with debugging tests) Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
c7148bb980
commit
5c840a8af5
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,3 +17,4 @@ types/extension-renderer-api.d.ts
|
||||
extensions/*/dist
|
||||
docs/extensions/api
|
||||
site/
|
||||
logs/
|
||||
|
||||
6
Makefile
6
Makefile
@ -53,18 +53,24 @@ integration-linux: binaries/client build-extension-types build-extensions
|
||||
# rm -rf ${HOME}/.config/Lens
|
||||
# endif
|
||||
yarn build:linux
|
||||
mkdir -p logs
|
||||
rm -r ./logs/*
|
||||
yarn integration
|
||||
|
||||
.PHONY: integration-mac
|
||||
integration-mac: binaries/client build-extension-types build-extensions
|
||||
# rm ${HOME}/Library/Application\ Support/Lens
|
||||
yarn build:mac
|
||||
mkdir -p logs
|
||||
rm -r ./logs/*
|
||||
yarn integration
|
||||
|
||||
.PHONY: integration-win
|
||||
integration-win: binaries/client build-extension-types build-extensions
|
||||
# rm %APPDATA%/Lens
|
||||
yarn build:win
|
||||
mkdir -p logs
|
||||
rm -r ./logs/*
|
||||
yarn integration
|
||||
|
||||
.PHONY: build
|
||||
|
||||
@ -13,7 +13,7 @@ import * as utils from "../helpers/utils";
|
||||
import { listHelmRepositories } from "../helpers/utils";
|
||||
import { fail } from "assert";
|
||||
|
||||
jest.setTimeout(60000);
|
||||
jest.setTimeout(60 * 1000 * 10); // 10m
|
||||
|
||||
// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below)
|
||||
describe("Lens integration tests", () => {
|
||||
|
||||
@ -12,7 +12,7 @@ import * as util from "util";
|
||||
|
||||
export const promiseExec = util.promisify(exec);
|
||||
|
||||
jest.setTimeout(60000);
|
||||
jest.setTimeout(60 * 1000 * 10); // 10m
|
||||
|
||||
// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below)
|
||||
describe("Lens cluster pages", () => {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Application } from "spectron";
|
||||
import * as utils from "../helpers/utils";
|
||||
|
||||
jest.setTimeout(60000);
|
||||
jest.setTimeout(60 * 1000 * 10); // 10m
|
||||
|
||||
describe("Lens command palette", () => {
|
||||
let app: Application;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Application } from "spectron";
|
||||
import { AppConstructorOptions, Application } from "spectron";
|
||||
import * as util from "util";
|
||||
import { exec } from "child_process";
|
||||
import { isCI } from "../../src/common/vars";
|
||||
|
||||
const AppPaths: Partial<Record<NodeJS.Platform, string>> = {
|
||||
"win32": "./dist/win-unpacked/OpenLens.exe",
|
||||
@ -50,15 +51,24 @@ export function describeIf(condition: boolean) {
|
||||
}
|
||||
|
||||
export function setup(): Application {
|
||||
return new Application({
|
||||
const args: AppConstructorOptions = {
|
||||
path: AppPaths[process.platform], // path to electron app
|
||||
args: [],
|
||||
startTimeout: 30000,
|
||||
waitTimeout: 60000,
|
||||
startTimeout: 60000,
|
||||
waitTimeout: 30000,
|
||||
env: {
|
||||
CICD: "true"
|
||||
}
|
||||
});
|
||||
CICD: "true",
|
||||
},
|
||||
chromeDriverLogPath: "./logs/chromeDriver",
|
||||
webdriverLogPath: "./logs/webdriver",
|
||||
};
|
||||
|
||||
if (!isCI) {
|
||||
args.chromeDriverLogPath = "./logs/chromeDriver";
|
||||
args.webdriverLogPath = "./logs/webdriver";
|
||||
}
|
||||
|
||||
return new Application(args);
|
||||
}
|
||||
|
||||
export const keys = {
|
||||
|
||||
@ -13,6 +13,7 @@ export const isProduction = process.env.NODE_ENV === "production";
|
||||
export const isTestEnv = !!process.env.JEST_WORKER_ID;
|
||||
export const isDevelopment = !isTestEnv && !isProduction;
|
||||
export const isPublishConfigured = Object.keys(packageInfo.build).includes("publish");
|
||||
export const isCI = Boolean(process.env.CI);
|
||||
|
||||
export const productName = packageInfo.productName;
|
||||
export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`;
|
||||
|
||||
@ -8,7 +8,7 @@ import { Wizard, WizardStep } from "../wizard";
|
||||
import { namespaceStore } from "./namespace.store";
|
||||
import { Namespace } from "../../api/endpoints";
|
||||
import { Input } from "../input";
|
||||
import { systemName } from "../input/input_validators";
|
||||
import { namespaceValue } from "../input/input_validators";
|
||||
import { Notifications } from "../notifications";
|
||||
|
||||
interface Props extends DialogProps {
|
||||
@ -49,19 +49,15 @@ export class AddNamespaceDialog extends React.Component<Props> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { ...dialogProps } = this.props;
|
||||
const { namespace } = this;
|
||||
const header = <h5>Create Namespace</h5>;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
{...dialogProps}
|
||||
{...this.props}
|
||||
className="AddNamespaceDialog"
|
||||
isOpen={AddNamespaceDialog.isOpen}
|
||||
onOpen={this.reset}
|
||||
close={AddNamespaceDialog.close}
|
||||
>
|
||||
<Wizard header={header} done={AddNamespaceDialog.close}>
|
||||
<Wizard header={<h5>Create Namespace</h5>} done={AddNamespaceDialog.close}>
|
||||
<WizardStep
|
||||
contentClass="flex gaps column"
|
||||
nextLabel="Create"
|
||||
@ -71,8 +67,9 @@ export class AddNamespaceDialog extends React.Component<Props> {
|
||||
required autoFocus
|
||||
iconLeft="layers"
|
||||
placeholder="Namespace"
|
||||
validators={systemName}
|
||||
value={namespace} onChange={v => this.namespace = v.toLowerCase()}
|
||||
validators={namespaceValue}
|
||||
value={this.namespace}
|
||||
onChange={v => this.namespace = v.toLowerCase()}
|
||||
/>
|
||||
</WizardStep>
|
||||
</Wizard>
|
||||
|
||||
@ -47,9 +47,18 @@ const defaultProps: Partial<InputProps> = {
|
||||
export class Input extends React.Component<InputProps> {
|
||||
static defaultProps = defaultProps as object;
|
||||
|
||||
public inputRef = React.createRef<InputElement>();
|
||||
public validators: InputValidator[] = [];
|
||||
public asyncValidators: AsyncInputValidator[] = [];
|
||||
inputRef = React.createRef<InputElement>();
|
||||
validators = [
|
||||
...conditionalValidators.filter(({ condition }) => condition(this.props)),
|
||||
...[this.props.validators],
|
||||
]
|
||||
.flat()
|
||||
.filter(Boolean);
|
||||
asyncValidators = [
|
||||
this.props.asyncValidators
|
||||
]
|
||||
.flat()
|
||||
.filter(Boolean);
|
||||
|
||||
@observable errors: React.ReactNode[] = [];
|
||||
@observable dirty = Boolean(this.props.showErrorInitially);
|
||||
@ -62,17 +71,7 @@ export class Input extends React.Component<InputProps> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { validators, asyncValidators, showErrorInitially } = this.props;
|
||||
|
||||
this.validators = conditionalValidators
|
||||
// add conditional validators if matches input props
|
||||
.filter(validator => validator.condition(this.props))
|
||||
// add custom validators
|
||||
.concat(validators);
|
||||
|
||||
this.asyncValidators = [asyncValidators].flat();
|
||||
|
||||
if (showErrorInitially) {
|
||||
if (this.props.showErrorInitially) {
|
||||
this.runValidatorsRaw(this.getValue());
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,10 @@ import fse from "fs-extra";
|
||||
|
||||
export type ValidatorMessage = ReactNode | ((value: string, props?: InputProps) => ReactNode | string);
|
||||
|
||||
export interface ConditionalInputValidator extends InputValidator {
|
||||
condition(props: InputProps): boolean; // auto-bind condition depending on input props
|
||||
}
|
||||
|
||||
export interface InputValidator {
|
||||
condition?(props: InputProps): boolean; // auto-bind condition depending on input props
|
||||
message: ValidatorMessage;
|
||||
@ -16,19 +20,19 @@ export interface AsyncInputValidator {
|
||||
validate(value: string, props?: InputProps): Promise<boolean>;
|
||||
}
|
||||
|
||||
export const isRequired: InputValidator = {
|
||||
export const isRequired: ConditionalInputValidator = {
|
||||
condition: ({ required }) => required,
|
||||
message: "This field is required",
|
||||
validate: value => !!value.trim(),
|
||||
};
|
||||
|
||||
export const isEmail: InputValidator = {
|
||||
export const isEmail: ConditionalInputValidator = {
|
||||
condition: ({ type }) => type === "email",
|
||||
message: "Must be an email",
|
||||
validate: value => !!value.match(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/),
|
||||
};
|
||||
|
||||
export const isNumber: InputValidator = {
|
||||
export const isNumber: ConditionalInputValidator = {
|
||||
condition: ({ type }) => type === "number",
|
||||
message: "Must be a number",
|
||||
validate: (value, { min, max }) => {
|
||||
@ -42,7 +46,7 @@ export const isNumber: InputValidator = {
|
||||
},
|
||||
};
|
||||
|
||||
export const isUrl: InputValidator = {
|
||||
export const isUrl: ConditionalInputValidator = {
|
||||
condition: ({ type }) => type === "url",
|
||||
message: "Must be a valid URL",
|
||||
validate: value => {
|
||||
@ -56,7 +60,7 @@ export const isUrl: InputValidator = {
|
||||
|
||||
export const isExtensionNameInstallRegex = /^(?<name>(@[-\w]+\/)?[-\w]+)(@(?<version>\d\.\d\.\d(-\w+)?))?$/gi;
|
||||
|
||||
export const isExtensionNameInstall: InputValidator = {
|
||||
export const isExtensionNameInstall: ConditionalInputValidator = {
|
||||
condition: ({ type }) => type === "text",
|
||||
message: "Not an extension name with optional version",
|
||||
validate: value => value.match(isExtensionNameInstallRegex) !== null,
|
||||
@ -76,13 +80,13 @@ export const isPath: AsyncInputValidator = {
|
||||
},
|
||||
};
|
||||
|
||||
export const minLength: InputValidator = {
|
||||
export const minLength: ConditionalInputValidator = {
|
||||
condition: ({ minLength }) => !!minLength,
|
||||
message: (value, { minLength }) => `Minimum length is ${minLength}`,
|
||||
validate: (value, { minLength }) => value.length >= minLength,
|
||||
};
|
||||
|
||||
export const maxLength: InputValidator = {
|
||||
export const maxLength: ConditionalInputValidator = {
|
||||
condition: ({ maxLength }) => !!maxLength,
|
||||
message: (value, { maxLength }) => `Maximum length is ${maxLength}`,
|
||||
validate: (value, { maxLength }) => value.length <= maxLength,
|
||||
@ -105,6 +109,6 @@ export const accountId: InputValidator = {
|
||||
validate: value => (isEmail.validate(value) || systemName.validate(value))
|
||||
};
|
||||
|
||||
export const conditionalValidators = [
|
||||
export const conditionalValidators: ConditionalInputValidator[] = [
|
||||
isRequired, isEmail, isNumber, isUrl, minLength, maxLength
|
||||
];
|
||||
|
||||
@ -26,6 +26,7 @@ export default function generateExtensionTypes(): webpack.Configuration {
|
||||
optimization: {
|
||||
minimize: false, // speed up types compilation
|
||||
},
|
||||
stats: "errors-warnings",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user