Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ts][ftr] improve types for ftr and expect.js, cleanup changes to tsconfig files #31948

Merged
merged 24 commits into from
Feb 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,6 @@
"ts-jest": "^23.1.4",
"ts-loader": "^5.2.2",
"ts-node": "^7.0.1",
"tsconfig-paths": "^3.8.0",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0",
"tslint-microsoft-contrib": "^6.0.0",
Expand Down
42 changes: 21 additions & 21 deletions packages/kbn-config-schema/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"declaration": true,
"declarationDir": "./target/types",
"outDir": "./target/out",
"stripInternal": true,
"declarationMap": true,
"types": [
"jest",
"node"
]
},
"include": [
"./types/joi.d.ts",
"./src/**/*.ts"
],
"exclude": [
"target"
]
}
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"declaration": true,
"declarationDir": "./target/types",
"outDir": "./target/out",
"stripInternal": true,
"declarationMap": true,
"types": [
"jest",
"node"
]
},
"include": [
"./types/joi.d.ts",
"./src/**/*.ts"
],
"exclude": [
"target"
]
}
6 changes: 6 additions & 0 deletions packages/kbn-test/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
spalger marked this conversation as resolved.
Show resolved Hide resolved
"extends": "../../tsconfig.json",
"include": [
"types/**/*"
]
}
6 changes: 6 additions & 0 deletions packages/kbn-test/types/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# @kbn/test/types

Shared types used by different parts of the tests

- **`expect.js.d.ts`**: This is a fork of the expect.js types that have been slightly modified to only expose a module type for `import expect from 'expect.js'` statements. The `@types/expect.js` includes types for the `expect` global, which is useful for some uses of the library but conflicts with the jest types we use. Making the type "module only" prevents them from conflicting.
- **`ftr.d.ts`**: These types are generic types for using the functional test runner. They are here because we plan to move the functional test runner into the `@kbn/test` package at some point and having them here makes them a lot easier to import from all over the place like we do.
225 changes: 225 additions & 0 deletions packages/kbn-test/types/expect.js.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
// tslint:disable

// Type definitions for expect.js 0.3.1
// Project: https://github.com/Automattic/expect.js
// Definitions by: Teppei Sato <https://github.com/teppeis>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// License: MIT

declare module 'expect.js' {
function expect(target?: any): Root;

interface Assertion {
/**
* Assert typeof / instanceof.
*/
an: An;
/**
* Check if the value is truthy
*/
ok(): void;

/**
* Creates an anonymous function which calls fn with arguments.
*/
withArgs(...args: any[]): Root;

/**
* Assert that the function throws.
*
* @param fn callback to match error string against
*/
throwError(fn?: (exception: any) => void): void;

/**
* Assert that the function throws.
*
* @param fn callback to match error string against
*/
throwException(fn?: (exception: any) => void): void;

/**
* Assert that the function throws.
*
* @param regexp regexp to match error string against
*/
throwError(regexp: RegExp): void;

/**
* Assert that the function throws.
*
* @param fn callback to match error string against
*/
throwException(regexp: RegExp): void;

/**
* Checks if the array is empty.
*/
empty(): Assertion;

/**
* Checks if the obj exactly equals another.
*/
equal(obj: any): Assertion;

/**
* Checks if the obj sortof equals another.
*/
eql(obj: any): Assertion;

/**
* Assert within start to finish (inclusive).
*
* @param start
* @param finish
*/
within(start: number, finish: number): Assertion;

/**
* Assert typeof.
*/
a(type: string): Assertion;

/**
* Assert instanceof.
*/
a(type: Function): Assertion;

/**
* Assert numeric value above n.
*/
greaterThan(n: number): Assertion;

/**
* Assert numeric value above n.
*/
above(n: number): Assertion;

/**
* Assert numeric value below n.
*/
lessThan(n: number): Assertion;

/**
* Assert numeric value below n.
*/
below(n: number): Assertion;

/**
* Assert string value matches regexp.
*
* @param regexp
*/
match(regexp: RegExp): Assertion;

/**
* Assert property "length" exists and has value of n.
*
* @param n
*/
length(n: number): Assertion;

/**
* Assert property name exists, with optional val.
*
* @param name
* @param val
*/
property(name: string, val?: any): Assertion;

/**
* Assert that string contains str.
*/
contain(str: string): Assertion;
string(str: string): Assertion;

/**
* Assert that the array contains obj.
*/
contain(obj: any): Assertion;
string(obj: any): Assertion;

/**
* Assert exact keys or inclusion of keys by using the `.own` modifier.
*/
key(keys: string[]): Assertion;
/**
* Assert exact keys or inclusion of keys by using the `.own` modifier.
*/
key(...keys: string[]): Assertion;
/**
* Assert exact keys or inclusion of keys by using the `.own` modifier.
*/
keys(keys: string[]): Assertion;
/**
* Assert exact keys or inclusion of keys by using the `.own` modifier.
*/
keys(...keys: string[]): Assertion;

/**
* Assert a failure.
*/
fail(message?: string): Assertion;
}

interface Root extends Assertion {
not: Not;
to: To;
only: Only;
have: Have;
be: Be;
}

interface Be extends Assertion {
/**
* Checks if the obj exactly equals another.
*/
(obj: any): Assertion;

an: An;
}

interface An extends Assertion {
/**
* Assert typeof.
*/
(type: string): Assertion;

/**
* Assert instanceof.
*/
(type: Function): Assertion;
}

interface Not extends NotBase {
to: ToBase;
}

interface NotBase extends Assertion {
be: Be;
have: Have;
include: Assertion;
only: Only;
}

interface To extends ToBase {
not: NotBase;
}

interface ToBase extends Assertion {
be: Be;
have: Have;
include: Assertion;
only: Only;
}

interface Only extends Assertion {
have: Have;
}

interface Have extends Assertion {
own: Assertion;
}

export default expect;
}
80 changes: 80 additions & 0 deletions packages/kbn-test/types/ftr.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { DefaultServiceProviders } from '../../../src/functional_test_runner/types';

interface AsyncInstance<T> {
/**
* Services that are initialized async are not ready before the tests execute, so you might need
* to call `init()` and await the promise it returns before interacting with the service
*/
init(): Promise<T>;
}

/**
* When a provider returns a promise it is initialized as an AsyncInstance that is a
* proxy to the eventual result with an added init() method which returns the eventual
* result. Automatically unwrap these promises and convert them to AsyncInstances + Instance
* types.
*/
type MaybeAsyncInstance<T> = T extends Promise<infer X> ? AsyncInstance<X> & X : T;

/**
* Convert a map of providers to a map of the instance types they provide, also converting
* promise types into the async instances that other providers will receive.
*/
type ProvidedTypeMap<T extends object> = {
[K in keyof T]: T[K] extends (...args: any[]) => any
? MaybeAsyncInstance<ReturnType<T[K]>>
: never
};

export interface GenericFtrProviderContext<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Describe your solution about the interface with 4! generics and 2 of them are already defined

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe you probably need to use type instead of super-generic interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Describe your solution about the interface with 4! generics and 2 of them are already defined

Yeah, 4 is a lot but I mostly see it as a generic interface with two arguments.

maybe you probably need to use type instead of super-generic interface?

Hmm, I would if I could but I don't think there's a valid way to derive a type inside the interface except like this. Something like this would be ideal:

export interface GenericFtrProviderContext<
  ServiceProviders extends object,
  PageObjectProviders extends object
> {
  type ServiceMap = ProvidedTypeMap<ServiceProviders & DefaultServiceProviders>
  type PageObjectMap = ProvidedTypeMap<PageObjectProviders>

  ...
}

But that's not valid TS, and I use both of those named types twice, and would prefer to not have to repeat their initializers in both places. Using defined generic arguments is aimed at making it more readable.

ServiceProviders extends object,
PageObjectProviders extends object,
ServiceMap = ProvidedTypeMap<ServiceProviders & DefaultServiceProviders>,
PageObjectMap = ProvidedTypeMap<PageObjectProviders>
> {
/**
* Determine if a service is avaliable
* @param serviceName
*/
hasService<K extends keyof ServiceMap>(serviceName: K): serviceName is K;
hasService(serviceName: string): serviceName is keyof ServiceMap;

/**
* Get the instance of a service, if the service is loaded async and the service needs to be used
* outside of a test/hook, then make sure to call its `.init()` method and await it's promise.
* @param serviceName
*/
getService<T extends keyof ServiceMap>(serviceName: T): ServiceMap[T];

/**
* Get a map of PageObjects
* @param pageObjects
*/
getPageObjects<K extends keyof PageObjectMap>(pageObjects: K[]): Pick<PageObjectMap, K>;

/**
* Synchronously load a test file, can be called within a `describe()` block to add
* common setup/teardown steps to several suites
* @param path
*/
loadTestFile(path: string): void;
}
2 changes: 1 addition & 1 deletion src/dev/typescript/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import { Project } from './project';

export const PROJECTS = [
new Project(resolve(REPO_ROOT, 'tsconfig.json')),
new Project(resolve(REPO_ROOT, 'test/tsconfig.json'), 'kibana/test'),
new Project(resolve(REPO_ROOT, 'x-pack/tsconfig.json')),
new Project(resolve(REPO_ROOT, 'x-pack/test/tsconfig.json'), 'x-pack/test'),
new Project(resolve(REPO_ROOT, 'test/tsconfig.json')),

// NOTE: using glob.sync rather than glob-all or globby
// because it takes less than 10 ms, while the other modules
Expand Down
Loading