Commit Graph
8409 Commits
Author SHA1 Message Date
Christopher Hiller 548310d018 chore(appium): use Ajv to validate CLI args
This now consumes Ajv directly to validate CLI args.  Since a JSON schema is made of JSON schemas, we can simply validate an argument against _the schema for that argument_.

- Replaced parser transformation functions (`parseSecurityFeatures()`, `parseJsonStringOrFile()`) with custom transforms which are bound to keyword `appiumCliTransformer`.  e.g., any option that can now accept a JSON string or filepath on the command line may use `appiumCliTransformer: 'json'`.  This is the default behavior for `array` and `object` -type options, which cannot easily be expressed on the CLI.  The config file does _not_ support this behavior, so the value must be whatever the schema `type` says (e.g., an `object` instead of a JSON string or filepath).  To this end, removed `parser-helpers.js`
- Further, we now disallow union types in the schema. A prop must have a single type.
- Added custom keywords `appiumCliDest`, `appiumCliDescription`, and `appiumCliTransformer`. Previously (if existed), this could have been any value--these are now typed by the schema--e.g., a number for `appiumCliDest` will fail.
- Added more types and TS checks around
- Fixed misspelling of "successfully" in various places
- Removed `@oclifg/errors` because we can now use `better-ajv-errors` to display them, as intended. It looks great!
- Moved all schema-related stuff to `lib/schema/` because I had too many modules
- Added more constants to please @mykola-mokhnach 😄
- Handles untyped properties or `null`-typed properties
- `getSchema()`, `validate()` etc now accept a schema ID. The schema ID is derived from the argument name. This is how we handle validation for each argument individually.  The config file is still validated against the entire schema at once.
- Fixed problem where only `driverConfigs` were ever used to call extension commands!
- Added some semaphore-like things to `ExtConfigIO` to avoid multiple reads/writes at once
- Fixed display of metavars in `--help`
- More tests; removed tests for removed code
2021-11-09 11:57:26 -08:00
Christopher Hiller 1a860cade2 fix(appium): restore missing call to validate extensions 2021-11-09 11:57:26 -08:00
Christopher Hiller 44be52d822 test(appium): use version constant in cli-e2e-specs 2021-11-09 11:57:26 -08:00
Christopher Hiller 237479c67c chore(appium): implement review changes
- flip if/else conditions in various places
- add export `SERVER_SUBCOMMAND` constant to `parser.js` (which is the string `server`)
- add `SERVER_PROP` constant to `schema.js` (which is also the string `server` but means a difft thing)
- more constants in `ext-config-io.js`
- add some more types in `ArgParser` constructor; simplify
- add constant regexp in `schema-args.js`
- use more lodash in `grid-register.js`
- simplify `_.includes()` call in `main.js`
- simplify error-handling in `readExtensionSchema()` of `schema.js`; fix docstring; remove associated tests
- fix a sanity check in `schema-specs.js`
2021-11-09 11:57:26 -08:00
Christopher Hiller d52c36e1ea feat(appium): configuration file and schema support
Summary: This PR adds support for configuration files (e.g., `.appiumrc.json`) and schema definitions.  Command-line options _and_ configuration is now derived from the schema(s), for Appium _and_ its extensions (both plugins and drivers).

## Dependencies
### Development
- Added `through2` for a custom gulp task to convert `appium/lib/appium-config-schema.js` to a JSON file
- Added `json-schema-to-typescript` for converting aforementioned JSON file to a `.d.ts` file (which gets published)

### Production (applies to `appium` only)
- Added `libconfig` for multi-format config file loading, which is a smaller drop-in replacement for `cosmiconfig`
- Added `ajv` for schema support and validation
- Added `ajv-formats` to understand optional value formats (e.g., `ipv4`)
- Added `@sidvind/better-ajv-errors` which provides nice error output on the CLI if the config file is invalid
- Added `@oclif/errors` for better error output on the CLI if _arguments_ are invalid

## New Modules of Note

- `lib/schema.js` consumes `ajv` to create and modify a schema
    - It exposes a handful of public API functions, so that consumers can query the schemas without actually running Appium.
    - The flow is basically this: read the base schema (`appium-config-schema.js`).  When extensions load and have schemas, add those to a pot.  When `finalizeSchema()` is called, throw the base schema into the pot as well, stir, and add to singleton `ajv` instance.  Now we can validate against the stew.
    - The schema for an extension is read and registered via `readExtensionSchema()`
    - Provides a way to get at default (for showing those "non-default" options) and `flattenSchema()` which squishes the finalized schema into a single `Record` key/value object, for use by the CLI.  This may make sense to move into `schema-args.js`
    - Provides access to ajv-and-JSON-schema-defined _formatters_ (which are basically just validation functions).  For example, if we want any string, it's just a `string`.  But if we want the string to match a regexp, that's a formatter.  (e.g., the `hostname` type)
-  lib/config-file.js` consumes `lilconfig` to read config files, validate them against the schema, and provide the result as CLI args
    - Handles conversion between kebab-case and camelCase
    - Contains `formatErrors()` which will be called after validation of a config file fails, which shows _exactly_ where the config file is wrong (usually).
- `lib/cli/schema-args.js` which serves as an adapter between the schema and `argparse`
    - Translates between JSON schema and `argparse`, which...well, I did what I could.  It's pretty close.
    - Wraps the formatters as mentioned above, and provides custom ones.
    - We cannot, unfortunately, wholly use schema validation against CLI args.  The flag names are different, the structure is different, there's no actual _file_ to compare against, and `argparse` does not help.  We _can_ use anything `argparse` natively provides, in addition to `ajv` formatters, and any custom ones (e.g., allowable number ranges).
    - Will likely end up adding more formatters corresponding to various JSON schema features later.  We _may_ be able to use _more_ of Ajv to do this (e.g., reuse its internal validators, if they are public APIs).
- `lib/appium-config-schema.js` which is the root schema. Extensions add to this before it is registered & compiled by `ajv`.
    - The basic shape is that there are three top-level props, `server`, `driver`, and `plugin`.  `server` contains all of the server options as you'd expect, and `driver` and `plugin` will be filled in by extensions.  Each will have properties corresponding to the extension name.  You can find examples in `sample-code` and the test fixtures
    - There's a gulp task that takes this file, rewrites it as JSON, then pipes it into another tool which outputs a `.d.ts` file, nicely described using all of the metadata from the schema.  This will be useful for mainly contributors, extension authors, and consumers of Appium (though not end-users).
- `lib/ext-config-io.js`
    - A new module which handles reading/writing of YAML extension config files only.
    - This class is a singleton.
    - Some logic pulled out of `extension-config.js` and into here
    - Previously, we would read/write this file multiple times (once per subclass of `ExtensionConfig`)
    - This module uses a naive dirty-tracker to persist the extension data automatically.
    - Subclasses of `ExtensionConfig` only have access to their "portion" of the config file; drivers can't see plugins and vice-versa.
    - `DRIVER_TYPE` and `PLUGIN_TYPE` originate here, mainly to avoid a circular dependency

## Modifications

- The single source of truth for the CLI _and_ config file options is the schema, with the caveats that:
    - Command-line arguments (for `appium server` are effectively a flat list, but the schema/config file is not.
    - Extension-specific configuration lives in an extension-type-specific property (`driver` or `plugin`) in the config file
        - Under each (`driver` or `plugin`), each extension may have a configuration section corresponding to the extension name
        - The shape of the extension-specific options _can_ be defined by a schema (and referenced in the `appium.schema` prop of the extension's `package.json`)
        - If an extension does not provide a schema, no validation will occur on any options found here -- TODO needs tests
    - This does _not_ affect _CLI commands_ added by extensions; only options for `server`.
- The `--appium-home` flag is now removed, as we can't find extensions without `APPIUM_HOME`, which means we can't parse arguments (because extensions may have added some).
- `--plugin-args` and `--driver-args` are removed.  These are replaced by individual flags for each argument, defined by the extension in its schema, e.g., `--driver-fake-host=127.0.0.1`
- Extensions can still define argument "constraints" using `argConstraints`, but this is considered deprecated
- `lib/main.js`
    - Now exports a few public APIs
    - split into functions `init` and `main`.  `init` is intended to be run via a consumer, which does what the old `main` did up to starting the server.  This bisection is not perfect, as `init` still does some CLI-related things; it needs to be further broken up.
    - `driverConfig.read()` and `pluginConfig.read()` are now called in `lib/cli/parser.js`.
    - Merges the CLI args, config file args, and defaults, in that order of precedence.
- `lib/grid-register.js`
    - Supports embedded configuration instead of just a path to a JSON file.
    - Not clear to me if `nodeconfig` is a thing we need to keep?
- `lib/extension-config.js`
    - Given `APPIUM_HOME` is where we keep the extensions, this file now defines `APPIUM_HOME`. It is exported from the `appium` package.
    - Add `getSchemaProblems()` method, which will read/validate/register the schema for an extension, if one exists.
    - Added many type annotations
    - `read()` and `write()` now delegate to the singleton `ExtConfigIO` instnace
    - Re-exports `DRIVER_TYPE` and `PLUGIN_TYPE`
- `lib/driver-config.js`
    - **Fix** the case where two drivers attempt to use the same `automationName`.  It appears this was intended, but did not work correctly.  This involved overloading `read()`.
- `lib/plugin-config.js`
    - Literally nothing, which is neat.
- `lib/config.js`
    - Remove unused validations (now occur via schema validation or are extension-specific)
    - Rename `getNonDefaultArgs` to `getNonDefaultServerArgs` to be more specific
    - Rewrote `getNonDefaultServerArgs`, which became much more complicated due to adding a config file and schema defaults to the mix. Flexed my lodash-fu, which is still kind of crappy because I'm better with `lodas/fp`.
- `lib/cli/parser.js`
    - Created a wrapper for `argparse`: class `ArgParser`, which replaces the monkeypatching we were doing here.
    - This class also stores extension-specific args in a namespace.  For example, `--driver-foo-bar=baz` would normally be stored in prop `driverFooBar`, but this moves it into `driver: {foo: {bar: 'baz'}}`, which will be provided to its associated extension
    - `addExtensionsToParser` renamed to `addExtensionCommandsToParser` which is more specific.
    - Removed `getDefaultServerArgs` since those now come from the schema.
    - Removed "shared args" stuff
    - `getParser` is now async, and constructs an `ArgParser`.  By necessity, the extension config YAML is read here (which is still wonky because we have to call `read()` twice; it only actually ends up reading once)
    - `getParser` also _finalizes_ the schema, which means "katamari-up the base schema and all extension schemas, then tell ajv about the result"
- `lib/cli/parser-helpers.js`
    - Allow security features to just be an array (as allowed in schema)
    - TODO: needs test
- `lib/cli/extension.js`
    - Use `APPIUM_HOME` exported from `lib/extension-config` instead of `args.appiumHome`
    - Avoids re-instantiating `ExtensionConfig` subclasses if not needed
- `lib/cli/args.js`
    - Remove all server argument definitions in lieu of schema; leave a few that do not make sense in a config file (like `--config`, which determines the location of the config file!)
    - Server args are now pulled from the schema via a call to `toParserArgs()` with overrides for various validation functions (which are confusingly "types" in `argparse` parlance).  Overrides can probably be removed or relocated to `schema-args`
    - Instantiates the `DriverConfig` and `PluginConfig` instances, which are exported.   These might want to move somewhere else
- Tests
    - Added unit tests for `extension-config`, `grid-register` which were missing
    - Added unit tests for new `schema` and `schema-args` and `config-file` modules
    - Added e2e test for config file handling
    - Other necessary modifications
    - Fix path to `fake-driver` in `driver-e2e-specs`
    - Removed stuff from `parser-specs` which no longer applies

## Other

- Added `scripts/generate-schema-declarations.js` which uses `json-schema-to-typescript` to create `appium-config.d.ts`
- Added config file samples in `.json` and `.yaml` formats
- Added custom gulp task to `appium/gulpfile.js` to generate schema in JSON format, since its "single source of truth" is actually just a big JS object
- Moved `appium` CLI-related tests into `test/cli`
- Added some declarations into `packages/appium/types`; the schema-related one is generated by the script mentioend above, but `types.d.ts` is just some stuff that was not expressible in a docstring
2021-11-09 11:57:26 -08:00
Jonathan Lipps 71357e52e1 Publish
- appium@2.0.0-beta.19
 - @appium/base-driver@8.1.2
 - @appium/doctor@1.16.5
 - @appium/eslint-config-appium@4.7.3
 - @appium/fake-driver@3.1.0
 - @appium/gulp-plugins@5.5.4
 - @appium/support@2.55.0
 - @appium/test-support@1.3.7
@appium/base-driver@8.1.2 @appium/doctor@1.16.5 @appium/eslint-config-appium@4.7.3 @appium/fake-driver@3.1.0 @appium/gulp-plugins@5.5.4 @appium/support@2.55.0 @appium/test-support@1.3.7 appium@2.0.0-beta.19
2021-11-09 14:07:38 -05:00
Renovate Bot 6bb9439089 chore(gulp-plugins): update babel monorepo to v7.16.0 2021-10-30 10:41:03 +00:00
Renovate Bot bcc441c612 chore(): update dependency type-fest to v2.5.2 2021-10-27 13:25:10 +00:00
Renovate Bot fb957786fa chore(support): update dependency axios to v0.24.0 2021-10-27 12:06:57 +00:00
Renovate Bot dedd1a25fa chore(): update dependency @types/sinon to v10.0.6 2021-10-27 10:11:30 +00:00
Renovate Bot 97a9d898f5 chore(): update dependency lint-staged to v11.2.6 2021-10-27 08:29:45 +00:00
Renovate Bot 05ec960c34 chore(): update dependency lint-staged to v11.2.4 2021-10-24 14:02:16 +00:00
Renovate Bot 6e28a8ffce chore(): update dependency @types/sinon to v10.0.5 2021-10-24 11:21:17 +00:00
Renovate Bot 3b16633a0a chore(gulp-plugins): update dependency replace-in-file to v6.3.2 2021-10-23 09:39:10 +00:00
Renovate Bot c69815b5e4 chore(gulp-plugins): update dependency replace-in-file to v6.3.1 2021-10-21 22:38:01 +00:00
Renovate Bot 2fae09b9f1 chore(support): update dependency axios to v0.23.0 2021-10-21 20:50:00 +00:00
Renovate Bot 7cbe1f220f chore(gulp-plugins): update dependency babel-plugin-istanbul to v6.1.1 2021-10-21 19:51:41 +00:00
Renovate Bot 54ed9292ac chore(): update dependency type-fest to v2.5.1 2021-10-21 18:39:38 +00:00
Renovate Bot 863e44e657 chore(eslint-config-appium): update dependency eslint-plugin-import to v2.25.2 2021-10-21 16:34:57 +00:00
Renovate Bot 276f5697ee chore(support): update dependency shell-quote to v1.7.3 2021-10-21 15:05:31 +00:00
Renovate Bot c3fa3c841f chore(eslint-config-appium): update dependency eslint-plugin-promise to v5.1.1 2021-10-21 14:08:13 +00:00
Renovate Bot 0d787d9002 chore(): update dependency @types/json-schema to v7.0.9 2021-10-21 12:36:38 +00:00
Renovate Bot 5c6a630686 chore(): update dependency @types/sinon to v10.0.4 2021-10-21 10:48:12 +00:00
Renovate Bot 1a6cf81d55 chore(): update dependency @types/chai to v4.2.22 2021-10-21 10:01:59 +00:00
Renovate Bot 8a6732c47c chore(doctor): update dependency appium-adb to v8.16.2 2021-10-21 08:44:48 +00:00
Renovate Bot 64c5733123 chore(): update dependency lint-staged to v11.2.3 2021-10-21 06:05:33 +00:00
Renovate Bot fb602e3741 chore(gulp-plugins): update dependency mocha to v9.1.3 2021-10-21 03:54:56 +00:00
Renovate Bot b295d85198 chore(): update dependency appium-base-driver to v7.10.1 2021-10-21 01:16:51 +00:00
Christopher Hiller a91bec3456 chore(gulp-plugins): postTranspile task always runs after transpile task; add dev task
- `postTranspile` would only run from certain _other_ tasks (like `test`).  This seemed incorrect, so now it runs after `transpile`, regardless of what task (or human) runs `transpile`.
- Added a `dev` task, which is like `watch`, except does not run tests (only transpiles)
2021-10-20 16:02:32 -07:00
Christopher Hiller 7b7a983bbe test(support): skip problem global-resolution test 2021-10-20 16:02:32 -07:00
Christopher Hiller cf7438a352 feat(fake-driver): add a schema
Adds an example schema to `fake-driver`. This is used for testing.
Also simplify assignment of commands to `FakeDriver.prototype`.
2021-10-20 16:02:32 -07:00
Christopher Hiller f0cb12d2e8 chore(eslint-config-appium): dev & test env improvements
- add `jsconfig.json` for the TS language server to understand the project
- update `.wallaby.js` to transpile fixtures if necessary; run on save to reduce lag
- update single-file Mocha debug launch config
- add `test` env in `babel.config.json` which is used by the former
- add some handy vscode tasks
- add a bunch of types
- remove unused `babel-eslint` (we use `@babel/eslint-parser`)
- bump `ecmaVersion` in `eslint-config-appium`
- remove cruft from babel configs (`shippedProposals: true` goes a long way)
- enable `sinon-chai` globally in tests
- add `rewiremock` for module-level mocking (sinon cannot do this itself, but they work in tandem)
2021-10-20 11:39:59 -07:00
Corneliu Duplachi 0e633939f9 fix(base-driver): type inconsistency (#15982)
* fix(base-driver): type inconsistency

* reset is set in BaseDriver
2021-10-18 14:30:10 -07:00
Kazuaki Matsuo 829eb6623d chore(base-driver): Add params to setWindowRect handler (#15974) 2021-10-17 08:07:04 +09:00
Renovate Bot f10c2c3630 chore(): update dependency lint-staged to v11.2.1 2021-10-09 08:58:52 +00:00
Corneliu Duplachi 476dbf3e32 chore(base-driver): add type definition for optional commands (#15931)
* feat(base-driver): add type definition for optional commands

* update type definition

* reuse Rect in Size, Position type

* fix: actions is unwrapped
2021-10-08 19:10:02 -07:00
Renovate Bot ac49b6b5db chore(gulp-plugins): update dependency @octokit/rest to v18.12.0 2021-10-08 08:49:10 +00:00
Renovate Bot 6732b1d8f6 chore(gulp-plugins): update babel monorepo to v7.15.8 2021-10-07 08:42:01 +00:00
Renovate Bot 537faa6670 chore(doctor): update dependency inquirer to v8.2.0 2021-10-06 07:54:49 +00:00
Renovate Bot 19b6b34519 chore(): update dependency lint-staged to v11.2.0 2021-10-04 13:04:37 +00:00
Renovate Bot 7a476af925 chore(support): update dependency axios to v0.22.0 2021-10-01 10:48:41 +00:00
Renovate Bot 0d0eb17acb chore(gulp-plugins): update dependency @octokit/rest to v18.11.4 2021-10-01 09:52:39 +00:00
Renovate Bot 1dc5f2916f chore(doctor): update dependency appium-adb to v8.16.1 2021-10-01 08:49:53 +00:00
Renovate Bot bf4fac2ab0 chore(gulp-plugins): update dependency @octokit/rest to v18.11.3 2021-09-30 08:29:22 +00:00
Christopher Hiller a5d91addd1 chore(pkg): obviousify scripts
- also speedify install by running `postinstall` builds in parallel
2021-09-28 07:54:20 -07:00
Christopher Hiller a172196d43 chore(base-driver): revert name change of TEST_HOST to DEFAULT_TEST_HOST
This would have been a breaking change if other packages depend on it, since I think it's a public API
2021-09-28 07:54:20 -07:00
Christopher Hiller cf86871d4f fix(base-driver): allow https in helper URL generation
- use constants/helpers for `jsonwp-proxy` url tests
2021-09-28 07:54:20 -07:00
Christopher Hiller 01d7c1bd7e fix(base-driver): better URL handling in driver-e2e tests
- fix a potential port-reuse issue in `getTestPort()` helper
- dedupe `127.0.0.1` constant
- export curried `createAppiumURL(address, port, session, pathname)` helper for less error-prone URL generation
- export some HTTP method names as constants
2021-09-28 07:54:20 -07:00
Christopher Hiller 3396594f76 chore(fake-driver): make wdio quieter 2021-09-28 07:54:20 -07:00
Christopher Hiller a3b021a0e8 chore: replace occurrences of 'localhost' with '127.0.01'; use random ports; closes #15399
- `base-driver` gets a new `helpers` module with a `getTestPort` function; this is now used throughout the tests
- `fake-driver` can't use random ports because it depends on `appium-base-driver`'s test suite, and that is _not_ the current appium-2.0-compatible `@appium/base-driver`
2021-09-28 07:54:20 -07:00