diff --git a/.eslintignore b/.eslintignore index df04ef93b..d7e54c241 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,7 +1,8 @@ -coverage -node_modules +**/coverage/** +**/node_modules/** examples/javascript-wd -packages/*/build/**/* +**/build/** **/*.min.js sample-code **/*.d.ts +**/build-fixtures/** diff --git a/.eslintrc b/.eslintrc index 941dab3c4..c1e44548e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -9,6 +9,12 @@ { "files": "packages/*/test/**/*", "rules": { "func-names": "off" } + }, + { + "files": "./packages/*/scripts/**/*.js", + "parserOptions": { + "sourceType": "script" + } } ] } diff --git a/.gitignore b/.gitignore index 18157c4c3..51e65db62 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,5 @@ appium.zip .vscode/settings.json .nyc_output *.lerna_backup +**/build-fixtures/** + diff --git a/.mocharc.js b/.mocharc.js index 685493b90..1397cb4ff 100644 --- a/.mocharc.js +++ b/.mocharc.js @@ -3,5 +3,10 @@ 'use strict'; module.exports = { - require: require.resolve('./test/setup.js') + require: [ + require.resolve('./test/setup.js') + ], + // forbids use of .only() in CI + forbidOnly: Boolean(process.env.CI), + color: true }; diff --git a/.wallaby.js b/.wallaby.js index 09e7c57af..ca540caa5 100644 --- a/.wallaby.js +++ b/.wallaby.js @@ -14,10 +14,14 @@ module.exports = (wallaby) => { './packages/**/*.json', '!./packages/**/build/**', '!./packages/**/test/**/*-specs.js', + '!./packages/**/test/**/*.spec.js', '!./packages/*/node_modules/**', '!./packages/*/gulpfile.js', + '!./packages/*/scripts/**', './packages/*/test/**/fixtures/**/*', './packages/*/test/**/mocks.js', + './packages/*/test/helpers.js', + './babel.config.json', // below this are fixtures { binary: true, @@ -35,6 +39,7 @@ module.exports = (wallaby) => { instrument: false, pattern: './packages/gulp-plugins/build/**/*', }, + // this setup file is special { instrument: false, pattern: './test/setup.js' @@ -43,6 +48,7 @@ module.exports = (wallaby) => { testFramework: 'mocha', tests: [ './packages/*/test/**/*-specs.js', + './packages/*/test/unit/**/*.spec.js', '!./packages/*/test/**/*-e2e-specs.js', '!./packages/*/node_modules/**', // this is more of an E2E test and it's tedious to run diff --git a/lerna.json b/lerna.json index 5355077c7..bfed3faae 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,12 @@ { "command": { "exec": { - "ignore": "@appium/eslint-config-appium" + "ignore": ["@appium/eslint-config-appium", "appium"] + }, + "run": { + "prefix": false, + "concurrency": 1, + "stream": true }, "version": { "conventionalCommits": true, diff --git a/package.json b/package.json index 2d25d93ac..3a163c8c0 100644 --- a/package.json +++ b/package.json @@ -24,19 +24,18 @@ "license": "Apache-2.0", "author": "https://github.com/appium", "scripts": { - "build": "lerna exec gulp transpile", + "build": "lerna run --parallel --prefix --concurrency=8 build", "clean": "lerna clean -y && npx rimraf node_modules package-lock.json \"packages/*/build\" \"packages/*/package-lock.json\"", - "coverage": "lerna exec gulp coveralls", - "dev": "lerna exec --parallel -- gulp dev --no-notif", + "dev": "lerna run --parallel --prefix --concurrency=8 dev", "doctor": "node ./packages/doctor", - "e2e-test": "lerna exec \"gulp e2e-test\"", + "e2e-test": "lerna run --parallel --max-buffer=128 test:e2e", "generate-docs": "lerna run --scope=appium generate-docs", - "generate-schema-declarations": "node ./scripts/generate-schema-declarations.mjs", - "postinstall": "lerna exec --parallel \"gulp prepublish\"", - "uninstall-fake-driver": "npm start -- driver uninstall fake", + "generate-schema-declarations": "lerna run --scope=appium generate-schema-declarations", + "generate-schema-json": "lerna run --scope=appium generate-schema-json", + "postinstall": "npm run build", "install-fake-driver": "npm start -- driver install --source=local ./packages/fake-driver", - "lint": "lerna exec --parallel \"gulp lint\" && lerna run --scope=@appium/eslint-config-appium lint", - "lint:fix": "eslint --fix .", + "lint": "eslint .", + "lint:fix": "npm run lint -- --fix", "precommit-lint": "lint-staged", "precommit-msg": "echo 'Pre-commit checks...' && exit 0", "reinstall": "npm run clean && npm install", @@ -44,24 +43,28 @@ "sync-pkgs": "npm run sync-pkgs:appium-readme && npm run sync-pkgs:common-fields && npm run sync-pkgs:keywords", "sync-pkgs:appium-readme": "sync-monorepo-packages --force --no-package-json --packages=packages/appium README.md", "sync-pkgs:common-fields": "sync-monorepo-packages --fields=author,license,repository,bugs,homepage,engines", - "sync-pkgs:keywords": "sync-monorepo-packages --field=keywords --packages='packages/*' --packages='!packages/eslint-config-appium'", - "test": "lerna exec \"gulp once\"", - "test:appium": "lerna exec --scope=appium \"gulp once\"", - "test:base-driver": "lerna exec --scope=@appium/base-driver \"gulp once\"", - "test:doctor": "lerna exec --scope=@appium/doctor \"gulp once\"", - "test:e2e:appium": "lerna exec --scope=appium \"gulp e2e-test\"", - "test:e2e:base-driver": "lerna exec --scope=@appium/base-driver \"gulp e2e-test\"", - "test:e2e:fake-driver": "lerna exec --scope=@appium/fake-driver \"gulp e2e-test\"", - "test:e2e:gulp-plugins": "lerna exec --scope=@appium/gulp-plugins \"gulp e2e-test\"", - "test:e2e:support": "lerna exec --scope=@appium/support \"gulp e2e-test\"", - "test:e2e:opencv": "lerna exec --scope=@appium/opencv \"gulp e2e-test\"", - "test:fake-driver": "lerna exec --scope=@appium/fake-driver \"gulp once\"", - "test:gulp-plugins": "lerna exec --scope=@appium/gulp-plugins \"gulp once\"", - "test:support": "lerna exec --scope=@appium/support \"gulp once\"", - "test:opencv": "lerna exec --scope=@appium/opencv \"gulp once\"", - "test:test-support": "lerna exec --scope=@appium/test-support \"gulp once\"", + "sync-pkgs:keywords": "sync-monorepo-packages --field=keywords --packages=\"packages/*\" --packages=\"!packages/eslint-config-appium\"", + "pretest": "npm run build && npm run lint", + "test": "lerna run test", + "test:appium": "lerna run --scope=appium test", + "test:base-driver": "lerna run --scope=@appium/base-driver test", + "test:doctor": "lerna run --scope=@appium/doctor test", + "test:e2e:appium": "lerna run --scope=appium test:e2e", + "test:e2e:base-driver": "lerna run --scope=@appium/base-driver test:e2e", + "test:e2e:fake-driver": "lerna run --scope=@appium/fake-driver test:e2e", + "test:e2e:gulp-plugins": "lerna run --scope=@appium/gulp-plugins test:e2e", + "test:e2e:opencv": "lerna run --scope=@appium/opencv test:e2e", + "test:e2e:support": "lerna run --scope=@appium/support test:e2e", + "test:fake-driver": "lerna run --scope=@appium/fake-driver test", + "test:gulp-plugins": "lerna run --scope=@appium/gulp-plugins test", + "test:opencv": "lerna run --scope=@appium/opencv test", + "test:support": "lerna run --scope=@appium/support test", + "test:test-support": "lerna run --scope=@appium/test-support test", + "uninstall-fake-driver": "npm start -- driver uninstall fake", + "upload": "gulp github-upload", "preversion": "npm run sync-pkgs && npm run generate-schema-declarations && git add -A packages/appium/README.md packages/*/package.json", - "watch": "lerna exec watch" + "zip": "zip -qr ./appium.zip ./packages/appium", + "zip-and-upload": "npm run zip && npm run upload" }, "pre-commit": [ "precommit-msg", @@ -71,8 +74,20 @@ "*.js": "eslint --fix", "./packages/appium/lib/schema/appium-config-schema.js": "npm run generate-schema-declarations" }, + "dependencies": { + "@appium/base-driver": "file:packages/base-driver", + "@appium/doctor": "file:packages/doctor", + "@appium/eslint-config-appium": "file:packages/eslint-config-appium", + "@appium/fake-driver": "file:packages/fake-driver", + "@appium/gulp-plugins": "file:packages/gulp-plugins", + "@appium/opencv": "file:packages/opencv", + "@appium/support": "file:packages/support", + "@appium/test-support": "file:packages/test-support", + "appium": "file:packages/appium" + }, "devDependencies": { "@appium/fake-plugin": "1.3.0", + "@babel/cli": "7.17.0", "@babel/core": "7.16.0", "@babel/eslint-parser": "7.16.3", "@babel/plugin-transform-runtime": "7.16.4", @@ -120,6 +135,7 @@ "json-schema-to-typescript": "10.1.5", "lerna": "4.0.0", "lint-staged": "12.3.4", + "log-symbols": "4.1.0", "mjpeg-server": "0.3.1", "mocha": "9.1.3", "pre-commit": "1.2.2", @@ -141,16 +157,5 @@ }, "publishConfig": { "access": "public" - }, - "dependencies": { - "@appium/base-driver": "file:packages/base-driver", - "@appium/doctor": "file:packages/doctor", - "@appium/eslint-config-appium": "file:packages/eslint-config-appium", - "@appium/fake-driver": "file:packages/fake-driver", - "@appium/gulp-plugins": "file:packages/gulp-plugins", - "@appium/support": "file:packages/support", - "@appium/opencv": "file:packages/opencv", - "@appium/test-support": "file:packages/test-support", - "appium": "file:packages/appium" } } diff --git a/packages/appium/commands-yml/validator.js b/packages/appium/commands-yml/validator.js deleted file mode 100644 index 37b145904..000000000 --- a/packages/appium/commands-yml/validator.js +++ /dev/null @@ -1,83 +0,0 @@ -import validate from 'validate.js'; -import _ from 'lodash'; - - -validate.validators.array = function array (value, options, key, attributes) { - if (attributes[key] && !validate.isArray(attributes[key])) { - return `must be an array`; - } -}; - -validate.validators.hasAttributes = function hasAttributes (value, options) { - if (!value) { - return; - } - - if (!_.isArray(value)) { - value = [value]; - } - - for (const item of value) { - for (const option of options) { - if (_.isUndefined(item[option])) { - return `must have attributes: ${options}`; - } - } - } -}; - -validate.validators.hasPossibleAttributes = function hasPossibleAttributes (value, options) { - if (!value) { - return; - } - - // if just a bare value, allow it through - if (!_.isArray(value)) { - return; - } - - for (const item of value) { - for (const key of _.keys(item)) { - if (!options.includes(key)) { - return `must not include '${key}'. Available options: ${options}`; - } - } - } -}; - -const CLIENT_URL_TYPES = { - url: 'hostname', - android: 'Android', - ios: 'iOS', -}; - -const validator = { - 'name': {presence: true}, - 'short_description': {presence: true}, - 'example_usage': {}, - 'example_usage.java': {}, - 'example_usage.javascript_wdio': {}, - 'example_usage.javascript_wd': {}, - 'example_usage.ruby': {}, - 'example_usage.ruby_core': {}, - 'example_usage.csharp': {}, - 'description': {}, - 'client_docs.java': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, - 'client_docs.javascript_wdio': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, - 'client_docs.javascript_wd': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, - 'client_docs.ruby': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, - 'client_docs.ruby_core': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, - 'client_docs.csharp': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, - 'endpoint': {presence: true}, - 'driver_support': {presence: true}, - 'endpoint.url': {presence: true}, - 'endpoint.url_parameters': {array: true, hasAttributes: ['name', 'description']}, - 'endpoint.json_parameters': {array: true, hasAttributes: ['name', 'description']}, - 'endpoint.response': {hasAttributes: ['type', 'description'] }, - 'specifications': {presence: true}, - 'links': {array: true, hasAttributes: ['name', 'url']}, -}; - - -export { validator, CLIENT_URL_TYPES }; -export default validator; diff --git a/packages/appium/gulpfile.js b/packages/appium/gulpfile.js deleted file mode 100644 index ecb81f557..000000000 --- a/packages/appium/gulpfile.js +++ /dev/null @@ -1,124 +0,0 @@ -// @ts-check -/* eslint no-console:0 */ -/* eslint-disable promise/prefer-await-to-callbacks */ -'use strict'; - -// turn all logging on since we have tests that rely on npmlog logs actually -// getting sent to the handler -process.env._FORCE_LOGS = '1'; - -const gulp = require('gulp'); -const boilerplate = require('@appium/gulp-plugins').boilerplate.use(gulp); -const path = require('path'); -const fs = require('fs'); -const log = require('fancy-log'); -const {obj: through} = require('through2'); - -const APPIUM_CONFIG_SCHEMA_BASENAME = 'appium-config.schema.json'; - -/** - * Expects a single file (as defined by `APPIUM_CONFIG_SCHEMA_PATH`) and converts - * that file to JSON. - * @param {import('vinyl')} file - Vinyl file object - * @param {BufferEncoding} enc - Encoding - * @param {import('through2').TransformCallback} done - Callback - */ -function writeAppiumConfigJsonSchema (file, enc, done) { - try { - const {default: schema} = require(file.path); - // @ts-ignore - file.contents = Buffer.from(JSON.stringify(schema, null, 2)); - file.basename = APPIUM_CONFIG_SCHEMA_BASENAME; - done(null, file); - } catch (err) { - done(err); - } -} - -// non-JS files that should be copied into the build dir (since babel does not compile them) -gulp.task('copy-files', gulp.parallel( - function copyTestFixtures () { - return gulp.src('./test/fixtures/*.{txt,yaml,json}') - .pipe(gulp.dest('./build/test/fixtures')); - }, - function copyTestConfigFixtures () { - return gulp.src('./test/fixtures/config/*.{txt,yaml,json}') - .pipe(gulp.dest('./build/test/fixtures/config')); - }, - function copyJsonSchema () { - return gulp.src('./lib/appium-config.schema.json') - .pipe(gulp.dest('./build/lib')); - } -)); - -gulp.task('generate-appium-schema-json', function () { - // don't care about file contents as text, so `read: false` - return gulp.src('./build/lib/schema/appium-config-schema.js', {read: false}) - .pipe(through(writeAppiumConfigJsonSchema)) - .pipe(gulp.dest('./lib/')); -}); - -boilerplate({ - build: 'appium', - files: [ - '*.js', - 'lib/**/*.js', - 'test/**/*.js', - 'commands-yml/**/*.js', - '!gulpfile.js', - ], - test: { - files: ['${testDir}/**/*-specs.js'] - }, - testTimeout: 160000, - postTranspile: ['generate-appium-schema-json', 'copy-files'] -}); - -// generates server arguments readme -gulp.task('docs', gulp.series(['transpile', function parseDocs () { - // @ts-ignore - const parser = require('./build/lib/parser.js'); - const appiumArguments = parser.getParser().rawArgs; - const docFile = path.resolve(__dirname, 'docs/en/writing-running-appium/server-args.md'); - let md = '# Appium server arguments\n\n'; - md += 'Many Appium 1.5 server arguments have been deprecated in favor of the '; - md += '[--default-capabilities flag](/docs/en/writing-running-appium/default-capabilities-arg.md).'; - md += '\n\nUsage: `node . [flags]`\n\n'; - md += '## Server flags\n'; - md += 'All flags are optional, but some are required in conjunction with ' + - 'certain others.\n\n'; - md += '\n\n\n\n'; - md += '|Flag|Default|Description|Example|\n'; - md += '|----|-------|-----------|-------|\n'; - appiumArguments.forEach(function handleArguments (arg) { - const argNames = arg[0]; - const exampleArg = typeof arg[0][1] === 'undefined' ? arg[0][0] : arg[0][1]; - const argOpts = arg[1]; - - // --keystore-path default contains a user-specific path, - // let's replace it with /... - if (arg[0][0] === '--keystore-path') { - const userPath = process.env.HOME || process.env.USERPROFILE; - argOpts.default = argOpts.default.replace(userPath, '<user>'); - } - - // handle empty objects - if (JSON.stringify(argOpts.default) === '{}') { - argOpts.default = '{}'; - } - - md += '|`' + argNames.join('`, `') + '`'; - md += '|' + ((typeof argOpts.default === 'undefined') ? '' : argOpts.default); - md += '|' + argOpts.help; - md += '|' + ((typeof argOpts.example === 'undefined') ? '' : '`' + exampleArg + ' ' + argOpts.example + '`'); - md += '|\n'; - }); - - fs.writeFile(docFile, md, function finishDocs (err) { - if (err) { - log(err.stack); - } else { - log('New docs written! Do not forget to commit and push'); - } - }); -}])); diff --git a/packages/appium/package.json b/packages/appium/package.json index ce5acfe6c..b9a12cb9b 100644 --- a/packages/appium/package.json +++ b/packages/appium/package.json @@ -12,6 +12,7 @@ "firefoxos", "testing" ], + "homepage": "https://appium.io", "bugs": { "url": "https://github.com/appium/appium/issues" }, @@ -31,15 +32,22 @@ "lib", "build", "index.js", - "postinstall.js", + "scripts/postinstall.js", "types" ], "scripts": { - "generate-docs": "gulp transpile && node ./build/commands-yml/parse.js", - "postinstall": "node ./postinstall.js", - "upload": "gulp github-upload", - "zip": "zip -qr appium.zip .", - "zip-and-upload": "npm run zip && npm run upload" + "build": "babel lib --root-mode=upward --delete-dir-on-start --out-dir=build/lib", + "postbuild": "npm run generate-schema-json", + "dev": "npm run build -- --watch", + "fix": "npm run lint -- --fix", + "generate-docs": "node ./scripts/parse-yml-commands.js", + "generate-schema-json": "node ./scripts/generate-schema-json.js", + "generate-schema-declarations": "node ./scripts/generate-schema-declarations.js", + "postinstall": "node ./scripts/postinstall.js", + "lint": "eslint -c ../../.eslintrc --ignore-path ../../.eslintignore .", + "test": "npm run test:unit", + "test:e2e": "mocha --require ./test/setup.js --timeout 20s --slow 10s \"./test/e2e/**/*.spec.js\"", + "test:unit": "mocha --require ./test/setup.js \"./test/unit/**/*.spec.js\"" }, "dependencies": { "@appium/base-driver": "file:../base-driver", @@ -78,6 +86,5 @@ "access": "public", "tag": "next" }, - "homepage": "https://appium.io", "gitHead": "ec6a90a797d2dadb407922426be16efaec9def07" } diff --git a/packages/appium/check-npm-pack-files.js b/packages/appium/scripts/check-npm-pack-files.js old mode 100644 new mode 100755 similarity index 84% rename from packages/appium/check-npm-pack-files.js rename to packages/appium/scripts/check-npm-pack-files.js index 0d5a1e413..384bc5877 --- a/packages/appium/check-npm-pack-files.js +++ b/packages/appium/scripts/check-npm-pack-files.js @@ -1,7 +1,10 @@ +#!/usr/bin/env node + +const path = require('path'); const childProcess = require('child_process'); const _ = require('lodash'); -const res = JSON.parse(childProcess.execSync('npm pack --dry-run --json --ignore-scripts', {encoding: 'utf8'}))[0]; +const res = JSON.parse(childProcess.execSync('npm pack --dry-run --json --ignore-scripts', {cwd: path.join(__dirname, '..'), encoding: 'utf8'}))[0]; // List of files we are testing to make sure they are included in package const testFiles = [ diff --git a/packages/appium/scripts/generate-schema-declarations.js b/packages/appium/scripts/generate-schema-declarations.js new file mode 100644 index 000000000..815aa5520 --- /dev/null +++ b/packages/appium/scripts/generate-schema-declarations.js @@ -0,0 +1,65 @@ +/* eslint-disable no-console */ +/* + * This module reads in the config file JSON schema and outputs a TypeScript declaration file (`.d.ts`). + * + * WARNING: This will add `../packages/appium/types/appium-config.d.ts` to the Git stage! + */ + +const {exec} = require('teen_process'); +const {compileFromFile} = require('json-schema-to-typescript'); +const path = require('path'); +const {promises: fs} = require('fs'); +const {info, success, error} = require('log-symbols'); +const {jsonSchemaPath} = require('./generate-schema-json'); + +/** + * Must be the `appium` package dir; not monorepo root. + */ +const PKG_ROOT = path.join(__dirname, '..'); + +/** + * Path to generated declaration file. + */ +const DECLARATIONS_PATH = path.join( + PKG_ROOT, + 'types', + 'appium-config.d.ts', +); + +async function main () { + try { + console.log(`${info} Updating Appium schema JSON...`); + try { + console.log((await exec('npm', ['run', '--silent', 'generate-schema-json'], {cwd: PKG_ROOT})).stdout); + } catch (err) { + throw new Error(`${error} Could not generate Appium schema JSON: ${err.message}`); + } + let ts; + try { + ts = await compileFromFile(jsonSchemaPath); + } catch (err) { + throw new Error(`${error} Could not convert Appium schema JSON to TypeScript: ${err.message}`); + } + try { + await fs.writeFile(DECLARATIONS_PATH, ts); + } catch (err) { + throw new Error(`${error} Could not write Appium schema declaration file: ${err.message}`); + } + console.log(`${info} Wrote %s`, DECLARATIONS_PATH); + if (!process.env.CI) { + try { + console.log((await exec('git', ['add', '-A', DECLARATIONS_PATH], {cwd: PKG_ROOT})).stdout); + } catch (err) { + throw new Error(`${error} Could not add Appium schema declaration file to Git stage: ${err.message}`); + } + console.log(`${info} Added ${DECLARATIONS_PATH} to the stage. +${info} If the schema JSON (${jsonSchemaPath}) changed, it will also have been added to the stage.`); + } + console.log(`${success} Done.`); + } catch (err) { + console.error(err.message); + process.exitCode = 1; + } +} + +main(); diff --git a/packages/appium/scripts/generate-schema-json.js b/packages/appium/scripts/generate-schema-json.js new file mode 100755 index 000000000..451c95787 --- /dev/null +++ b/packages/appium/scripts/generate-schema-json.js @@ -0,0 +1,107 @@ +#!/usr/bin/env node + +// @ts-check + +/* eslint-disable no-console */ + +const path = require('path'); +const {writeFile} = require('fs').promises; +const {exec} = require('teen_process'); +const {info, success, error} = require('log-symbols'); + +/** + * `appium` package root. + */ +const PKG_ROOT = path.join(__dirname, '..'); + +/** + * Root of all artifacts. + */ +const BUILD_DIR = path.join(PKG_ROOT, 'build', 'lib'); + +/** + * Basename of exported `.json` file. + */ +const JSON_FILENAME = 'appium-config.schema.json'; + +/** + * Path to source schema `.js`. + * + * This is the _build artifact_. Node can use ES modules, but it cannot use them unless one of two things is true: + * - `type: module` in `package.json` + * - file `.mjs` extension + * + * Neither of these things is true, so we have to use the build artifact. + */ +const SRC = path.join(BUILD_DIR, 'schema', 'appium-config-schema.js'); + +/** + * Path to schema JSON which lives under VCS + */ +const DEST_UNDER_VCS = path.join(PKG_ROOT, 'lib', JSON_FILENAME); + +/** + * {@link DEST_UNDER_VCS} plus another one in the `build` dir. + */ +const DESTS = [ + DEST_UNDER_VCS, + path.join(BUILD_DIR, 'appium-config.schema.json'), +]; + +async function write () { + /** @type {typeof import('../lib/schema/appium-config-schema.js')} */ + let schema; + try { + schema = require(SRC).default; + } catch (err) { + throw new Error( + `${error} Failed to read ${SRC}; did you execute \`npm run build\` first?`, + ); + } + + const json = JSON.stringify(schema, null, 2); + + for await (const dest of DESTS) { + try { + await writeFile(dest, json); + console.log(`${info} Wrote JSON schema to %s`, dest); + } catch (err) { + throw new Error( + `${error} Failed to write JSON schema to ${dest}: ${err.message}`, + ); + } + } +} + +async function addToStage () { + try { + console.log( + (await exec('git', ['add', '-A', DEST_UNDER_VCS], {cwd: PKG_ROOT})) + .stdout, + ); + console.log(`${info} Added %s to the stage`, DEST_UNDER_VCS); + } catch (err) { + throw new Error( + `${error} Failed to add ${DEST_UNDER_VCS} to the stage: ${err.message}`, + ); + } +} + +async function main () { + try { + await write(); + if (!process.env.CI) { + await addToStage(); + } + } catch (err) { + console.log(err); + process.exitCode = 1; + } + console.log(`${success} Done.`); +} + +if (require.main === module) { + main(); +} + +module.exports = {main, addToStage, write, jsonSchemaPath: DEST_UNDER_VCS}; diff --git a/packages/appium/commands-yml/parse.js b/packages/appium/scripts/parse-yml-commands.js old mode 100644 new mode 100755 similarity index 69% rename from packages/appium/commands-yml/parse.js rename to packages/appium/scripts/parse-yml-commands.js index 375af69ef..75c7003aa --- a/packages/appium/commands-yml/parse.js +++ b/packages/appium/scripts/parse-yml-commands.js @@ -1,13 +1,92 @@ -import path from 'path'; -import yaml from 'yaml-js'; -import { fs, util } from '@appium/support'; -import validate from 'validate.js'; -import Handlebars from 'handlebars'; -import _ from 'lodash'; -import { asyncify } from 'asyncbox'; -import { validator, CLIENT_URL_TYPES } from './validator'; -import url from 'url'; -import log from 'fancy-log'; +#!/usr/bin/env node + +// @ts-check + +const path = require('path'); +const yaml = require('yaml'); +const { fs, util } = require('@appium/support'); +const validate = require('validate.js'); +const Handlebars = require('handlebars'); +const _ = require('lodash'); +const { asyncify } = require('asyncbox'); +const url = require('url'); +const log = require('fancy-log'); + +validate.validators.array = function array (value, options, key, attributes) { + if (attributes[key] && !validate.isArray(attributes[key])) { + return `must be an array`; + } +}; + +validate.validators.hasAttributes = function hasAttributes (value, options) { + if (!value) { + return; + } + + if (!_.isArray(value)) { + value = [value]; + } + + for (const item of value) { + for (const option of options) { + if (_.isUndefined(item[option])) { + return `must have attributes: ${options}`; + } + } + } +}; + +validate.validators.hasPossibleAttributes = function hasPossibleAttributes (value, options) { + if (!value) { + return; + } + + // if just a bare value, allow it through + if (!_.isArray(value)) { + return; + } + + for (const item of value) { + for (const key of _.keys(item)) { + if (!options.includes(key)) { + return `must not include '${key}'. Available options: ${options}`; + } + } + } +}; + +const CLIENT_URL_TYPES = { + url: 'hostname', + android: 'Android', + ios: 'iOS', +}; + +const validator = { + 'name': {presence: true}, + 'short_description': {presence: true}, + 'example_usage': {}, + 'example_usage.java': {}, + 'example_usage.javascript_wdio': {}, + 'example_usage.javascript_wd': {}, + 'example_usage.ruby': {}, + 'example_usage.ruby_core': {}, + 'example_usage.csharp': {}, + 'description': {}, + 'client_docs.java': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, + 'client_docs.javascript_wdio': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, + 'client_docs.javascript_wd': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, + 'client_docs.ruby': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, + 'client_docs.ruby_core': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, + 'client_docs.csharp': {hasPossibleAttributes: _.keys(CLIENT_URL_TYPES)}, + 'endpoint': {presence: true}, + 'driver_support': {presence: true}, + 'endpoint.url': {presence: true}, + 'endpoint.url_parameters': {array: true, hasAttributes: ['name', 'description']}, + 'endpoint.json_parameters': {array: true, hasAttributes: ['name', 'description']}, + 'endpoint.response': {hasAttributes: ['type', 'description'] }, + 'specifications': {presence: true}, + 'links': {array: true, hasAttributes: ['name', 'url']}, +}; // What range of platforms do the driver's support const platformRanges = { @@ -29,7 +108,7 @@ const appiumRanges = { mac: ['1.6.4'], }; -const rootFolder = fs.findRoot(__dirname); +const rootFolder = path.join(__dirname, '..', '..', '..'); // Create Handlebars helper that shows a version range Handlebars.registerHelper('versions', function versionHelper (object, name, driverName) { @@ -135,7 +214,7 @@ Handlebars.registerHelper('client_url', function clientUrl (clientUrl) { }); async function registerSpecUrlHelper () { - const routesFile = await fs.readFile(path.resolve(rootFolder, '..', 'base-driver', 'lib', 'protocol', 'routes.js'), 'utf8'); + const routesFile = await fs.readFile(require.resolve('@appium/base-driver/lib/protocol/routes.js'), 'utf8'); const routesFileLines = routesFile.split('\n'); Handlebars.registerHelper('spec_url', function specUrl (specUrl, endpoint) { @@ -173,24 +252,26 @@ async function registerSpecUrlHelper () { }); } +const YAML_DIR = path.join(__dirname, '..', 'commands-yml'); + async function generateCommands () { await registerSpecUrlHelper(); - const commands = path.resolve(rootFolder, 'commands-yml', 'commands/**/*.yml'); + const commands = path.resolve(YAML_DIR, 'commands/**/*.yml'); log('Traversing YML files', commands); await fs.rimraf(path.resolve(rootFolder, 'docs', 'en', 'commands')); // get the template from which the md files will be created - const template = Handlebars.compile(await fs.readFile(path.resolve(rootFolder, 'commands-yml', 'template.md'), 'utf8'), {noEscape: true, strict: true}); + const template = Handlebars.compile(await fs.readFile(path.resolve(YAML_DIR, 'template.md'), 'utf8'), {noEscape: true, strict: true}); let fileCount = 0; for (const filename of await fs.glob(commands)) { - const relativeFilename = path.relative(path.resolve(rootFolder, 'commands-yml'), filename); + const relativeFilename = path.relative(YAML_DIR, filename); log(`Rendering file: ${filename} ${relativeFilename}`); // Translate the YML specs to JSON const inputYML = await fs.readFile(filename, 'utf8'); - const inputJSON = yaml.load(inputYML); + const inputJSON = yaml.parse(inputYML); inputJSON.ymlFileName = `/${path.relative(rootFolder, filename)}`; const validationErrors = validate(inputJSON, validator); if (validationErrors) { @@ -233,14 +314,14 @@ async function generateCommandIndex () { // parse the toc.js file and get the commands into the form of // {commands: [{name: '', path: ''}, {name: '', commands: [...]}]} - const toc = require(path.resolve(rootFolder, '../..', 'docs', 'toc.js')); + const toc = require(path.resolve(rootFolder, 'docs', 'toc.js')); const commandToc = _.find(toc.en, (value) => value.indexOf('Commands') === 0); const commands = []; for (let el of commandToc[1].slice(1)) { commands.push(getTree(el, '/docs/en/commands')); } - const commandTemplate = Handlebars.compile(await fs.readFile(path.resolve(rootFolder, 'commands-yml', 'api-template.md'), 'utf8'), {noEscape: true, strict: true}); + const commandTemplate = Handlebars.compile(await fs.readFile(path.resolve(YAML_DIR, 'api-template.md'), 'utf8'), {noEscape: true, strict: true}); async function writeIndex (index, commands, indexPath) { log(`Creating API index '${index}'`); @@ -251,7 +332,7 @@ async function generateCommandIndex () { await fs.writeFile(index, commandMarkdown, 'utf8'); } - const apiIndex = path.resolve(rootFolder, '../..', 'docs', 'en', 'about-appium', 'api.md'); + const apiIndex = path.resolve(rootFolder, 'docs', 'en', 'about-appium', 'api.md'); await writeIndex(apiIndex, commands); log(`Done writing main API index`); @@ -273,7 +354,7 @@ async function generateCommandIndex () { } // go through the full tree and generate readme files - const index = path.resolve(rootFolder, '../..', 'docs', 'en', 'commands', 'README.md'); + const index = path.resolve(rootFolder, 'docs', 'en', 'commands', 'README.md'); await writeIndex(index, commands); for (const el of commands) { await writeIndividualIndexes(el); diff --git a/packages/appium/postinstall.js b/packages/appium/scripts/postinstall.js similarity index 97% rename from packages/appium/postinstall.js rename to packages/appium/scripts/postinstall.js index ea234c878..bb5801d3b 100755 --- a/packages/appium/postinstall.js +++ b/packages/appium/scripts/postinstall.js @@ -12,7 +12,7 @@ async function main () { let extension; try { - extension = require('./build/lib/cli/extension'); + extension = require('../build/lib/cli/extension'); } catch (e) { throw new Error(`Could not load extension CLI file; has the project been transpiled? ` + `(${e.message})`); diff --git a/packages/appium/scripts/write-server-args-docs.js b/packages/appium/scripts/write-server-args-docs.js new file mode 100755 index 000000000..c81658d2d --- /dev/null +++ b/packages/appium/scripts/write-server-args-docs.js @@ -0,0 +1,70 @@ +#!/usr/bin/env node +/* eslint-disable no-console */ + +// @ts-check + +const {writeFileSync} = require('fs'); +const path = require('path'); +let parser; +try { + parser = require('../build/lib/cli/parser.js'); +} catch { + console.error('Could not load parser CLI file; please execute `npm run build`'); + process.exit(1); +} + +/** @type {import('../lib/cli/args').ArgumentDefinitions} */ +const appiumArguments = parser.getParser().rawArgs; +const docFile = path.normalize( + path.join( + __dirname, + '..', + '..', + '..', + 'docs', + 'en', + 'writing-running-appium', + 'server-args.md', + ), +); +let md = ` + +# Appium server arguments + +Many Appium 1.5 server arguments have been deprecated in favor of the [--default-capabilities flag](/docs/en/writing-running-appium/default-capabilities-arg.md). + +Usage: \`node . [flags]\` + +## Server Flags + +All flags are optional, but some are required in conjunction with certain others. + + + +|Flag|Default|Description|Example| +|----|-------|-----------|-------| +`; +appiumArguments.forEach(function handleArguments (argOpts, argNames) { + // handle empty objects + if (JSON.stringify(argOpts.default) === '{}') { + argOpts.default = '{}'; + } + + md += '|`' + argNames.join('`, `') + '`'; + md += '|' + (typeof argOpts.default === 'undefined' ? '' : argOpts.default); + md += '|' + argOpts.help; + md += '|'; + md += '|\n'; +}); + +try { + writeFileSync(docFile, md); + console.error( + 'New docs written! Do not forget to commit:\ngit add -A %s && git commit -m "Update %s"', + path.relative(process.cwd(), docFile), + path.basename(docFile), + ); +} catch (err) { + console.error('Could not write to file %s: %s', docFile, err); + process.exitCode = 1; +} diff --git a/packages/appium/test/cli/cli-e2e-specs.js b/packages/appium/test/e2e/cli.e2e.spec.js similarity index 97% rename from packages/appium/test/cli/cli-e2e-specs.js rename to packages/appium/test/e2e/cli.e2e.spec.js index a4cb1bf03..1589b98a8 100644 --- a/packages/appium/test/cli/cli-e2e-specs.js +++ b/packages/appium/test/e2e/cli.e2e.spec.js @@ -15,7 +15,7 @@ import { PLUGIN_TYPE } from '../../lib/constants'; import { FAKE_DRIVER_DIR, resolveFixture } from '../helpers'; -import { installLocalExtension, runAppium, runAppiumJson } from './cli-helpers'; +import { installLocalExtension, runAppium, runAppiumJson } from './e2e-helpers'; const {MANIFEST_RELATIVE_PATH} = env; const {expect} = chai; @@ -142,7 +142,7 @@ describe('CLI behavior', function () { }); describe('when a different driver is installed via appium', function () { - const testDriverPath = path.dirname(resolveFixture('cli/test-driver/package.json')); + const testDriverPath = path.dirname(resolveFixture('test-driver/package.json')); /** @type {string} */ let oldHash; /** @type {string} */ @@ -156,7 +156,7 @@ describe('CLI behavior', function () { }); it('should not update package.json', async function () { - const newPkg = await await fs.readFile(appiumHomePkgPath, 'utf8'); + const newPkg = await fs.readFile(appiumHomePkgPath, 'utf8'); newPkg.should.equal(oldPkg); }); @@ -282,7 +282,6 @@ describe('CLI behavior', function () { ret.uiautomator2.installType.should.eql('npm'); ret.uiautomator2.installSpec.should.eql('uiautomator2'); const list = await runList(['--installed']); - // @ts-expect-error delete list.uiautomator2.installed; list.should.eql(ret); }); @@ -297,7 +296,6 @@ describe('CLI behavior', function () { ret.fake.installType.should.eql('npm'); ret.fake.installSpec.should.eql('@appium/fake-driver'); const list = await runList(['--installed']); - // @ts-expect-error delete list.fake.installed; list.should.eql(ret); }); @@ -310,7 +308,6 @@ describe('CLI behavior', function () { ret.fake.installType.should.eql('npm'); ret.fake.installSpec.should.eql(installSpec); const list = await runList(['--installed']); - // @ts-expect-error delete list.fake.installed; list.should.eql(ret); }); @@ -327,7 +324,6 @@ describe('CLI behavior', function () { ret.fake.installType.should.eql('github'); ret.fake.installSpec.should.eql('appium/appium-fake-driver'); const list = await runList(['--installed']); - // @ts-expect-error delete list.fake.installed; list.should.eql(ret); }); @@ -344,7 +340,6 @@ describe('CLI behavior', function () { ret.fake.installType.should.eql('git'); ret.fake.installSpec.should.eql(FAKE_DRIVER_DIR); const list = await runList(['--installed', '--json']); - // @ts-expect-error delete list.fake.installed; list.should.eql(ret); }); @@ -363,7 +358,6 @@ describe('CLI behavior', function () { 'git+https://github.com/appium/appium-fake-driver', ); const list = await runList(['--installed']); - // @ts-expect-error delete list.fake.installed; list.should.eql(ret); }); @@ -376,7 +370,6 @@ describe('CLI behavior', function () { ret.fake.installType.should.eql('local'); ret.fake.installSpec.should.eql(FAKE_DRIVER_DIR); const list = await runList(['--installed']); - // @ts-expect-error delete list.fake.installed; list.should.eql(ret); }); @@ -482,13 +475,13 @@ describe('CLI behavior', function () { * @typedef {import('../../lib/extension/manifest').DriverType} DriverType * @typedef {import('../../lib/extension/manifest').PluginType} PluginType * @typedef {import('../../lib/cli/extension-command').ExtensionListData} ExtensionListData - * @typedef {import('./cli-helpers').CliArgs} CliArgs + * @typedef {import('./e2e-helpers').CliArgs} CliArgs * @typedef {import('../../types/types').CliExtensionSubcommand} CliExtensionSubcommand */ /** * @template ExtSubCommand - * @typedef {import('./cli-helpers').CliExtArgs} CliExtArgs + * @typedef {import('./e2e-helpers').CliExtArgs} CliExtArgs */ /** diff --git a/packages/appium/test/config-file-e2e-specs.js b/packages/appium/test/e2e/config-file.e2e.spec.js similarity index 96% rename from packages/appium/test/config-file-e2e-specs.js rename to packages/appium/test/e2e/config-file.e2e.spec.js index 0068a41f8..2792e8ebb 100644 --- a/packages/appium/test/config-file-e2e-specs.js +++ b/packages/appium/test/e2e/config-file.e2e.spec.js @@ -1,9 +1,9 @@ // @ts-check -import { readConfigFile, normalizeConfig } from '../lib/config-file'; -import { finalizeSchema, registerSchema, resetSchema } from '../lib/schema/schema'; -import extSchema from './fixtures/driver.schema.js'; -import { resolveFixture } from './helpers'; +import { readConfigFile, normalizeConfig } from '../../lib/config-file'; +import { finalizeSchema, registerSchema, resetSchema } from '../../lib/schema/schema'; +import extSchema from '../fixtures/driver.schema.js'; +import { resolveFixture } from '../helpers'; describe('config file behavior', function () { const GOOD_FILEPATH = resolveFixture('config', 'appium.config.good.json'); @@ -211,7 +211,7 @@ describe('config file behavior', function () { }); describe('with extensions', function () { - /** @type {import('../lib/config-file').ReadConfigFileResult} */ + /** @type {import('../../lib/config-file').ReadConfigFileResult} */ let result; beforeEach(function () { diff --git a/packages/appium/test/config-e2e-specs.js b/packages/appium/test/e2e/config.e2e.spec.js similarity index 99% rename from packages/appium/test/config-e2e-specs.js rename to packages/appium/test/e2e/config.e2e.spec.js index b17519dbf..94712011c 100644 --- a/packages/appium/test/config-e2e-specs.js +++ b/packages/appium/test/e2e/config.e2e.spec.js @@ -4,7 +4,7 @@ import { getBuildInfo, updateBuildInfo, APPIUM_VER, -} from '../lib/config'; +} from '../../lib/config'; import axios from 'axios'; import { fs } from '@appium/support'; diff --git a/packages/appium/test/driver-e2e-specs.js b/packages/appium/test/e2e/driver.e2e.spec.js similarity index 95% rename from packages/appium/test/driver-e2e-specs.js rename to packages/appium/test/e2e/driver.e2e.spec.js index f866450f7..a69243834 100644 --- a/packages/appium/test/driver-e2e-specs.js +++ b/packages/appium/test/e2e/driver.e2e.spec.js @@ -6,13 +6,13 @@ import path from 'path'; import B from 'bluebird'; import axios from 'axios'; import { remote as wdio } from 'webdriverio'; -import { main as appiumServer } from '../lib/main'; -import { INSTALL_TYPE_LOCAL } from '../lib/extension/extension-config'; -import { W3C_PREFIXED_CAPS, TEST_FAKE_APP, TEST_HOST, getTestPort, PROJECT_ROOT } from './helpers'; +import { main as appiumServer } from '../../lib/main'; +import { INSTALL_TYPE_LOCAL } from '../../lib/extension/extension-config'; +import { W3C_PREFIXED_CAPS, TEST_FAKE_APP, TEST_HOST, getTestPort, PROJECT_ROOT } from '../helpers'; import { BaseDriver } from '@appium/base-driver'; -import { loadExtensions } from '../lib/extension'; -import { runExtensionCommand } from '../lib/cli/extension'; -import { removeAppiumPrefixes } from '../lib/utils'; +import { loadExtensions } from '../../lib/extension'; +import { runExtensionCommand } from '../../lib/cli/extension'; +import { removeAppiumPrefixes } from '../../lib/utils'; import sinon from 'sinon'; import { tempDir, fs } from '@appium/support'; @@ -45,7 +45,7 @@ describe('FakeDriver - via HTTP', function () { let appiumHome; // since we update the FakeDriver.prototype below, make sure we update the FakeDriver which is // actually going to be required by Appium - /** @type {import('../lib/extension/manifest').DriverClass} */ + /** @type {import('../../lib/extension/manifest').DriverClass} */ let FakeDriver; /** @type {string} */ let testServerBaseSessionUrl; @@ -82,12 +82,15 @@ describe('FakeDriver - via HTTP', function () { /** * * @param {number} port - * @param {Partial} [args] + * @param {Partial} [args] */ async function serverStart (port, args = {}) { args = {...args, port, address: TEST_HOST}; if (shouldStartServer) { - server = /** @type {typeof server} */(await appiumServer(args)); + server = /** @type {typeof server} */( + // @ts-expect-error + await appiumServer(args) + ); } } @@ -368,7 +371,8 @@ describe.skip('Logsink', function () { }; before(async function () { - server = await appiumServer(/** @type {import('../types/types').ParsedArgs} */(args)); + // @ts-expect-error + server = await appiumServer(args); }); after(async function () { diff --git a/packages/appium/test/cli/cli-helpers.js b/packages/appium/test/e2e/e2e-helpers.js similarity index 100% rename from packages/appium/test/cli/cli-helpers.js rename to packages/appium/test/e2e/e2e-helpers.js diff --git a/packages/appium/test/plugin-e2e-specs.js b/packages/appium/test/e2e/plugin.e2e.spec.js similarity index 96% rename from packages/appium/test/plugin-e2e-specs.js rename to packages/appium/test/e2e/plugin.e2e.spec.js index 4b7c1c9b8..e9fa6fe0e 100644 --- a/packages/appium/test/plugin-e2e-specs.js +++ b/packages/appium/test/e2e/plugin.e2e.spec.js @@ -6,12 +6,12 @@ import path from 'path'; import B from 'bluebird'; import { remote as wdio } from 'webdriverio'; import axios from 'axios'; -import { main as appiumServer } from '../lib/main'; -import { INSTALL_TYPE_LOCAL } from '../lib/extension/extension-config'; -import { W3C_PREFIXED_CAPS, TEST_HOST, getTestPort, PROJECT_ROOT } from './helpers'; -import { runExtensionCommand } from '../lib/cli/extension'; +import { main as appiumServer } from '../../lib/main'; +import { INSTALL_TYPE_LOCAL } from '../../lib/extension/extension-config'; +import { W3C_PREFIXED_CAPS, TEST_HOST, getTestPort, PROJECT_ROOT } from '../helpers'; +import { runExtensionCommand } from '../../lib/cli/extension'; import { tempDir, fs } from '@appium/support'; -import { loadExtensions } from '../lib/extension'; +import { loadExtensions } from '../../lib/extension'; const FAKE_ARGS = {sillyWebServerPort: 1234, host: 'hey'}; const FAKE_PLUGIN_ARGS = {fake: FAKE_ARGS}; @@ -30,7 +30,7 @@ const FAKE_PLUGIN_DIR = path.join(PROJECT_ROOT, 'node_modules', '@appium', 'fake describe('FakePlugin', function () { /** @type {string} */ let appiumHome; - /** @type {Partial} */ + /** @type {Partial} */ let baseArgs; /** @type {string} */ let testServerBaseUrl; diff --git a/packages/appium/test/cli/schema-e2e-specs.js b/packages/appium/test/e2e/schema.e2e.spec.js similarity index 90% rename from packages/appium/test/cli/schema-e2e-specs.js rename to packages/appium/test/e2e/schema.e2e.spec.js index 9f99219a5..072c8f214 100644 --- a/packages/appium/test/cli/schema-e2e-specs.js +++ b/packages/appium/test/e2e/schema.e2e.spec.js @@ -2,7 +2,7 @@ import { fs, tempDir } from '@appium/support'; import path from 'path'; import { resolveFixture } from '../helpers'; -import { installLocalExtension, runAppium } from './cli-helpers'; +import { installLocalExtension, runAppium } from './e2e-helpers'; const {expect} = chai; @@ -30,7 +30,7 @@ describe('CLI behavior controlled by schema', function () { await installLocalExtension( appiumHome, 'driver', - path.dirname(resolveFixture('cli/test-driver/package.json')) + path.dirname(resolveFixture('test-driver/package.json')) ); help = await runAppium(appiumHome, ['server', '--help']); }); diff --git a/packages/appium/test/fixtures/cli/test-driver/package.json b/packages/appium/test/fixtures/test-driver/package.json similarity index 100% rename from packages/appium/test/fixtures/cli/test-driver/package.json rename to packages/appium/test/fixtures/test-driver/package.json diff --git a/packages/appium/test/helpers.js b/packages/appium/test/helpers.js index 7c71c5810..8346c364f 100644 --- a/packages/appium/test/helpers.js +++ b/packages/appium/test/helpers.js @@ -1,3 +1,5 @@ +// @ts-check + import getPort from 'get-port'; import path from 'path'; import rewiremock, { addPlugin, overrideEntryPoint, plugins } from 'rewiremock'; @@ -34,7 +36,7 @@ async function getTestPort () { /** * Resolve a file relative to the `fixtures` dir * @param {string} filename - Filename to resolve - * @param {...string} [pathParts] - Additional paths to `join()` + * @param {...string} pathParts - Additional paths to `join()` * @returns {string} */ function resolveFixture (filename, ...pathParts) { diff --git a/packages/appium/test/setup.js b/packages/appium/test/setup.js new file mode 100644 index 000000000..4f8508c59 --- /dev/null +++ b/packages/appium/test/setup.js @@ -0,0 +1,6 @@ +// This configures @babel/register to look for a babel config in parent dir(s) of +// wherever the tests are run. This is required if running tests via `mocha` in a package dir +// instead of the monorepo root. This does not affect `gulp-mocha`, since it has its own `.babelrc`. +// This file is required _in addition to_ the monorepo root's `test/setup.js`. + +require('@babel/register')({rootMode: 'upward'}); diff --git a/packages/appium/test/appiumdriver-specs.js b/packages/appium/test/unit/appiumdriver.spec.js similarity index 95% rename from packages/appium/test/appiumdriver-specs.js rename to packages/appium/test/unit/appiumdriver.spec.js index fe104cc47..b2f0f4049 100644 --- a/packages/appium/test/appiumdriver-specs.js +++ b/packages/appium/test/unit/appiumdriver.spec.js @@ -4,31 +4,41 @@ import { BaseDriver } from '@appium/base-driver'; import { FakeDriver } from '@appium/fake-driver'; import { sleep } from 'asyncbox'; import _ from 'lodash'; -import sinon from 'sinon'; -import { AppiumDriver } from '../lib/appium'; -import { finalizeSchema, registerSchema, resetSchema } from '../lib/schema/schema'; -import { insertAppiumPrefixes, removeAppiumPrefixes } from '../lib/utils'; -import { BASE_CAPS, W3C_CAPS, W3C_PREFIXED_CAPS } from './helpers'; +import { createSandbox } from 'sinon'; +import { AppiumDriver } from '../../lib/appium'; +import { finalizeSchema, registerSchema, resetSchema } from '../../lib/schema/schema'; +import { insertAppiumPrefixes, removeAppiumPrefixes } from '../../lib/utils'; +import { BASE_CAPS, W3C_CAPS, W3C_PREFIXED_CAPS } from '../helpers'; const SESSION_ID = 1; describe('AppiumDriver', function () { + /** @type {sinon.SinonSandbox} */ + let sandbox; + beforeEach(function () { + sandbox = createSandbox(); resetSchema(); finalizeSchema(); }); + + afterEach(function () { + sandbox.restore(); + }); + describe('instance method', function () { function getDriverAndFakeDriver (appiumArgs = {}, DriverClass = FakeDriver) { const appium = new AppiumDriver(appiumArgs); const fakeDriver = new DriverClass(); - const mockFakeDriver = sinon.mock(fakeDriver); + const mockFakeDriver = sandbox.mock(fakeDriver); mockFakeDriver._fakeDriver = fakeDriver; const mockedDriverReturnerClass = function Driver () { return fakeDriver; }; + // @ts-expect-error appium.driverConfig = { - findMatchingDriver: sinon.stub().returns({ + findMatchingDriver: sandbox.stub().returns({ driver: mockedDriverReturnerClass, version: '1.2.3', driverName: 'fake', @@ -86,7 +96,7 @@ describe('AppiumDriver', function () { new FakeDriver(), new FakeDriver(), ]; - let mockFakeDrivers = _.map(fakeDrivers, (fd) => sinon.mock(fd)); + let mockFakeDrivers = _.map(fakeDrivers, (fd) => sandbox.mock(fd)); mockFakeDrivers[0].expects('deleteSession') .once(); mockFakeDrivers[1].expects('deleteSession') diff --git a/packages/appium/test/cli/cli-specs.js b/packages/appium/test/unit/cli/cli.spec.js similarity index 92% rename from packages/appium/test/cli/cli-specs.js rename to packages/appium/test/unit/cli/cli.spec.js index 27d7a54c9..84701d752 100644 --- a/packages/appium/test/cli/cli-specs.js +++ b/packages/appium/test/unit/cli/cli.spec.js @@ -1,9 +1,9 @@ // transpile:mocha import { tempDir, fs, npm } from '@appium/support'; -import { loadExtensions } from '../../lib/extension'; -import { Manifest } from '../../lib/extension/manifest'; -import DriverCommand from '../../lib/cli/driver-command'; +import { loadExtensions } from '../../../lib/extension'; +import { Manifest } from '../../../lib/extension/manifest'; +import DriverCommand from '../../../lib/cli/driver-command'; import { createSandbox } from 'sinon'; describe('DriverCommand', function () { diff --git a/packages/appium/test/cli/schema-args-specs.js b/packages/appium/test/unit/cli/schema-args.spec.js similarity index 81% rename from packages/appium/test/cli/schema-args-specs.js rename to packages/appium/test/unit/cli/schema-args.spec.js index 623c78872..a008ca4ad 100644 --- a/packages/appium/test/cli/schema-args-specs.js +++ b/packages/appium/test/unit/cli/schema-args.spec.js @@ -1,11 +1,11 @@ -import sinon from 'sinon'; -import { finalizeSchema, resetSchema, SchemaFinalizationError } from '../../lib/schema/schema'; -import { rewiremock } from '../helpers'; +import { createSandbox } from 'sinon'; +import { finalizeSchema, resetSchema, SchemaFinalizationError } from '../../../lib/schema/schema'; +import { rewiremock } from '../../helpers'; const expect = chai.expect; describe('cli/schema-args', function () { - /** @type {import('../../lib/schema/cli-args').toParserArgs} */ + /** @type {import('../../../lib/schema/cli-args').toParserArgs} */ let toParserArgs; /** @@ -14,8 +14,8 @@ describe('cli/schema-args', function () { let sandbox; beforeEach(function () { - sandbox = sinon.createSandbox(); - ({toParserArgs} = rewiremock.proxy(() => require('../../lib/schema/cli-args'))); + sandbox = createSandbox(); + ({toParserArgs} = rewiremock.proxy(() => require('../../../lib/schema/cli-args'))); }); afterEach(function () { diff --git a/packages/appium/test/config-file-specs.js b/packages/appium/test/unit/config-file.spec.js similarity index 96% rename from packages/appium/test/config-file-specs.js rename to packages/appium/test/unit/config-file.spec.js index bc9485bac..c4bf50871 100644 --- a/packages/appium/test/config-file-specs.js +++ b/packages/appium/test/unit/config-file.spec.js @@ -1,10 +1,10 @@ // @ts-check import fs from 'fs'; -import sinon from 'sinon'; +import { createSandbox } from 'sinon'; import YAML from 'yaml'; -import * as schema from '../lib/schema/schema'; -import { resolveFixture, rewiremock } from './helpers'; +import * as schema from '../../lib/schema/schema'; +import { resolveFixture, rewiremock } from '../helpers'; const expect = chai.expect; @@ -35,12 +35,12 @@ describe('config-file', function () { /** * `readConfigFile()` from an isolated `config-file` module - * @type {import('../lib/config-file').readConfigFile} + * @type {import('../../lib/config-file').readConfigFile} */ let readConfigFile; /** - * @type {import('../lib/config-file').formatErrors} + * @type {import('../../lib/config-file').formatErrors} */ let formatErrors; @@ -63,7 +63,7 @@ describe('config-file', function () { }); beforeEach(function () { - sandbox = sinon.createSandbox(); + sandbox = createSandbox(); // we have to manually type this (and `search()`) because we'd only get the real type // when stubbing an object prop; e.g., `stub(lilconfig, 'load')` @@ -104,7 +104,7 @@ describe('config-file', function () { // loads the `config-file` module using the lilconfig mock. // we only mock lilconfig because it'd otherwise be a pain in the rear to test // searching for config files, and it increases the likelihood that we'd load the wrong file. - ({readConfigFile, formatErrors} = rewiremock.proxy(() => require('../lib/config-file'), mocks)); + ({readConfigFile, formatErrors} = rewiremock.proxy(() => require('../../lib/config-file'), mocks)); // just want to be extra-sure `validate()` happens sandbox.spy(schema, 'validate'); @@ -116,7 +116,7 @@ describe('config-file', function () { describe('readConfigFile()', function () { /** - * @type {import('../lib/config-file').ReadConfigFileResult} + * @type {import('../../lib/config-file').ReadConfigFileResult} */ let result; diff --git a/packages/appium/test/config-specs.js b/packages/appium/test/unit/config.spec.js similarity index 94% rename from packages/appium/test/config-specs.js rename to packages/appium/test/unit/config.spec.js index 1e87c665c..612793138 100644 --- a/packages/appium/test/config-specs.js +++ b/packages/appium/test/unit/config.spec.js @@ -2,18 +2,18 @@ // transpile:mocha import _ from 'lodash'; -import sinon from 'sinon'; -import { getParser } from '../lib/cli/parser'; -import { checkNodeOk, getBuildInfo, getNonDefaultServerArgs, showBuildInfo, showConfig, validateTmpDir, warnNodeDeprecations } from '../lib/config'; -import logger from '../lib/logger'; -import { getDefaultsForSchema, resetSchema, registerSchema, finalizeSchema } from '../lib/schema/schema'; +import { createSandbox } from 'sinon'; +import { getParser } from '../../lib/cli/parser'; +import { checkNodeOk, getBuildInfo, getNonDefaultServerArgs, showBuildInfo, showConfig, validateTmpDir, warnNodeDeprecations } from '../../lib/config'; +import logger from '../../lib/logger'; +import { getDefaultsForSchema, resetSchema, registerSchema, finalizeSchema } from '../../lib/schema/schema'; describe('Config', function () { - /** @type {import('sinon').SinonSandbox} */ + /** @type {sinon.SinonSandbox} */ let sandbox; beforeEach(function () { - sandbox = sinon.createSandbox(); + sandbox = createSandbox(); }); afterEach(function () { @@ -21,9 +21,9 @@ describe('Config', function () { }); describe('Appium config', function () { - /** @type {import('sinon').SinonSpy<[message?: any, ...extra: any[]],void>} */ + /** @type {sinon.SinonSpy<[message?: any, ...extra: any[]],void>} */ let log; - /** @type {import('sinon').SinonSpy<[message?: any, ...extra: any[]],void>} */ + /** @type {sinon.SinonSpy<[message?: any, ...extra: any[]],void>} */ let dir; beforeEach(function () { log = sandbox.spy(console, 'log'); @@ -237,7 +237,7 @@ describe('Config', function () { }); it('should not fail if process.argv[1] is undefined', function () { - process.argv[1] = undefined; + process.argv[1] = ''; let args = getParser(); args.prog.should.be.equal('appium'); }); diff --git a/packages/appium/test/extension/driver-config-specs.js b/packages/appium/test/unit/extension/driver-config.spec.js similarity index 93% rename from packages/appium/test/extension/driver-config-specs.js rename to packages/appium/test/unit/extension/driver-config.spec.js index 380dddabd..c5a98401d 100644 --- a/packages/appium/test/extension/driver-config-specs.js +++ b/packages/appium/test/unit/extension/driver-config.spec.js @@ -1,9 +1,9 @@ // @ts-check import { promises as fs } from 'fs'; -import { Manifest } from '../../lib/extension/manifest'; -import { resetSchema } from '../../lib/schema'; -import { resolveFixture, rewiremock } from '../helpers'; +import { Manifest } from '../../../lib/extension/manifest'; +import { resetSchema } from '../../../lib/schema'; +import { resolveFixture, rewiremock } from '../../helpers'; import { initMocks } from './mocks'; const {expect} = chai; @@ -27,7 +27,7 @@ describe('DriverConfig', function () { let MockResolveFrom; /** - * @type {typeof import('../../lib/extension/driver-config').DriverConfig} + * @type {typeof import('../../../lib/extension/driver-config').DriverConfig} */ let DriverConfig; @@ -45,7 +45,7 @@ describe('DriverConfig', function () { sandbox} = initMocks()); MockAppiumSupport.fs.readFile.resolves(yamlFixture); ({DriverConfig} = rewiremock.proxy( - () => require('../../lib/extension/driver-config'), + () => require('../../../lib/extension/driver-config'), overrides, )); resetSchema(); @@ -271,9 +271,7 @@ describe('DriverConfig', function () { describe('when the property as a path is found', function () { beforeEach(function () { - MockResolveFrom.returns( - require.resolve('../fixtures/driver.schema'), - ); + MockResolveFrom.returns(resolveFixture('driver.schema.js')); }); it('should return an empty array', function () { @@ -351,11 +349,11 @@ describe('DriverConfig', function () { }); /** - * @typedef {import('../../lib/extension/manifest').DriverType} DriverType - * @typedef {import('../../lib/extension/driver-config').DriverConfig} DriverConfig + * @typedef {import('../../../lib/extension/manifest').DriverType} DriverType + * @typedef {import('../../../lib/extension/driver-config').DriverConfig} DriverConfig */ /** - * @template {import('../../lib/extension/manifest').ExtensionType} ExtType - * @typedef {import('../../lib/extension/manifest').ExtDataWithSchema} ExtDataWithSchema + * @template {import('../../../lib/extension/manifest').ExtensionType} ExtType + * @typedef {import('../../../lib/extension/manifest').ExtDataWithSchema} ExtDataWithSchema */ diff --git a/packages/appium/test/extension/extension-config-specs.js b/packages/appium/test/unit/extension/extension-config.spec.js similarity index 100% rename from packages/appium/test/extension/extension-config-specs.js rename to packages/appium/test/unit/extension/extension-config.spec.js diff --git a/packages/appium/test/extension/manifest-specs.js b/packages/appium/test/unit/extension/manifest.spec.js similarity index 96% rename from packages/appium/test/extension/manifest-specs.js rename to packages/appium/test/unit/extension/manifest.spec.js index 645a41ede..30d74d6c5 100644 --- a/packages/appium/test/extension/manifest-specs.js +++ b/packages/appium/test/unit/extension/manifest.spec.js @@ -1,7 +1,7 @@ // @ts-check import B from 'bluebird'; import { promises as fs } from 'fs'; -import { resolveFixture, rewiremock } from '../helpers'; +import { resolveFixture, rewiremock } from '../../helpers'; import { initMocks } from './mocks'; const {expect} = chai; @@ -26,7 +26,7 @@ describe('Manifest', function () { }); /** - * @type {typeof import('../../lib/extension/manifest').Manifest} + * @type {typeof import('../../../lib/extension/manifest').Manifest} */ let Manifest; @@ -36,7 +36,7 @@ describe('Manifest', function () { MockAppiumSupport.fs.readFile.resolves(yamlFixture); ({Manifest} = rewiremock.proxy( - () => require('../../lib/extension/manifest'), + () => require('../../../lib/extension/manifest'), overrides, )); @@ -80,7 +80,7 @@ describe('Manifest', function () { }); describe('instance method', function () { - /** @type {import('../../lib/extension/manifest').Manifest} */ + /** @type {import('../../../lib/extension/manifest').Manifest} */ let manifest; beforeEach(function () { @@ -195,7 +195,7 @@ describe('Manifest', function () { }); describe('when called after `read()`', function () { - /** @type {import('../../lib/extension/manifest').ManifestData} */ + /** @type {import('../../../lib/extension/manifest').ManifestData} */ let data; /** @type {ExtData} */ @@ -427,9 +427,9 @@ describe('Manifest', function () { /** * @template T - * @typedef {import('../../lib/extension/manifest').ExtData} ExtData + * @typedef {import('../../../lib/extension/manifest').ExtData} ExtData */ /** - * @typedef {import('../../lib/extension/manifest').DriverType} DriverType + * @typedef {import('../../../lib/extension/manifest').DriverType} DriverType */ diff --git a/packages/appium/test/extension/mocks.js b/packages/appium/test/unit/extension/mocks.js similarity index 100% rename from packages/appium/test/extension/mocks.js rename to packages/appium/test/unit/extension/mocks.js diff --git a/packages/appium/test/extension/package-changed-specs.js b/packages/appium/test/unit/extension/package-changed.spec.js similarity index 92% rename from packages/appium/test/extension/package-changed-specs.js rename to packages/appium/test/unit/extension/package-changed.spec.js index 6aea8f206..9abf4fca0 100644 --- a/packages/appium/test/extension/package-changed-specs.js +++ b/packages/appium/test/unit/extension/package-changed.spec.js @@ -1,13 +1,13 @@ // @ts-check import path from 'path'; -import { PKG_HASHFILE_RELATIVE_PATH } from '../../lib/constants'; -import { rewiremock } from '../helpers'; +import { PKG_HASHFILE_RELATIVE_PATH } from '../../../lib/constants'; +import { rewiremock } from '../../helpers'; import { initMocks } from './mocks'; const {expect} = chai; describe('package-changed', function () { - /** @type {typeof import('../../lib/extension/package-changed').packageDidChange} */ + /** @type {typeof import('../../..lib/extension/package-changed').packageDidChange} */ let packageDidChange; /** @type {sinon.SinonSandbox} */ @@ -22,7 +22,7 @@ describe('package-changed', function () { beforeEach(function () { ({MockPackageChanged, MockAppiumSupport, sandbox} = initMocks()); ({packageDidChange} = rewiremock.proxy( - () => require('../../lib/extension/package-changed'), + () => require('../../../lib/extension/package-changed'), { 'package-changed': MockPackageChanged, '@appium/support': MockAppiumSupport, diff --git a/packages/appium/test/extension/plugin-config-specs.js b/packages/appium/test/unit/extension/plugin-config.spec.js similarity index 93% rename from packages/appium/test/extension/plugin-config-specs.js rename to packages/appium/test/unit/extension/plugin-config.spec.js index 055ee15f5..c32702c43 100644 --- a/packages/appium/test/extension/plugin-config-specs.js +++ b/packages/appium/test/unit/extension/plugin-config.spec.js @@ -1,9 +1,9 @@ // @ts-check import { promises as fs } from 'fs'; -import { Manifest } from '../../lib/extension/manifest'; -import { resetSchema } from '../../lib/schema'; -import { resolveFixture, rewiremock } from '../helpers'; +import { Manifest } from '../../../lib/extension/manifest'; +import { resetSchema } from '../../../lib/schema'; +import { resolveFixture, rewiremock } from '../../helpers'; import { initMocks } from './mocks'; const {expect} = chai; @@ -27,7 +27,7 @@ describe('PluginConfig', function () { let MockResolveFrom; /** - * @type {typeof import('../../lib/extension/plugin-config').PluginConfig} + * @type {typeof import('../../../lib/extension/plugin-config').PluginConfig} */ let PluginConfig; @@ -42,7 +42,7 @@ describe('PluginConfig', function () { ({MockAppiumSupport, MockResolveFrom, sandbox, overrides} = initMocks()); MockAppiumSupport.fs.readFile.resolves(yamlFixture); ({PluginConfig} = rewiremock.proxy( - () => require('../../lib/extension/plugin-config'), + () => require('../../../lib/extension/plugin-config'), overrides, )); resetSchema(); @@ -212,9 +212,7 @@ describe('PluginConfig', function () { describe('when the property as a path is found', function () { beforeEach(function () { - MockResolveFrom.returns( - require.resolve('../fixtures/plugin.schema'), - ); + MockResolveFrom.returns(resolveFixture('plugin.schema')); }); it('should return an empty array', function () { @@ -349,11 +347,11 @@ describe('PluginConfig', function () { }); /** - * @typedef {import('../../lib/extension/manifest').PluginType} PluginType - * @typedef {import('../../lib/extension/plugin-config').PluginConfig} PluginConfig + * @typedef {import('../../../lib/extension/manifest').PluginType} PluginType + * @typedef {import('../../../lib/extension/plugin-config').PluginConfig} PluginConfig */ /** - * @template {import('../../lib/extension/manifest').ExtensionType} ExtType - * @typedef {import('../../lib/extension/manifest').ExtDataWithSchema} ExtDataWithSchema + * @template {import('../../../lib/extension/manifest').ExtensionType} ExtType + * @typedef {import('../../../lib/extension/manifest').ExtDataWithSchema} ExtDataWithSchema */ diff --git a/packages/appium/test/grid-register-specs.js b/packages/appium/test/unit/grid-register.spec.js similarity index 90% rename from packages/appium/test/grid-register-specs.js rename to packages/appium/test/unit/grid-register.spec.js index cb9dbd951..53614cf3e 100644 --- a/packages/appium/test/grid-register-specs.js +++ b/packages/appium/test/unit/grid-register.spec.js @@ -1,13 +1,13 @@ // @ts-check -import sinon from 'sinon'; -import { rewiremock } from './helpers'; +import { createSandbox } from 'sinon'; +import { rewiremock } from '../helpers'; describe('grid-register', function () { let sandbox; beforeEach(function () { - sandbox = sinon.createSandbox(); + sandbox = createSandbox(); }); afterEach(function () { @@ -15,7 +15,7 @@ describe('grid-register', function () { }); describe('registerNode()', function () { - /** @type {import('../lib/grid-register').default} */ + /** @type {import('../../lib/grid-register').default} */ let registerNode; let mocks; @@ -33,7 +33,7 @@ describe('grid-register', function () { }; ({default: registerNode} = rewiremock.proxy( - () => require('../lib/grid-register'), + () => require('../../lib/grid-register'), mocks, )); }); diff --git a/packages/appium/test/logger-specs.js b/packages/appium/test/unit/logger.spec.js similarity index 84% rename from packages/appium/test/logger-specs.js rename to packages/appium/test/unit/logger.spec.js index 25446ab9d..2aea124fc 100644 --- a/packages/appium/test/logger-specs.js +++ b/packages/appium/test/unit/logger.spec.js @@ -1,7 +1,7 @@ // transpile:mocha -import { init as logsinkInit, clear as logsinkClear } from '../lib/logsink'; -import sinon from 'sinon'; +import { init as logsinkInit, clear as logsinkClear } from '../../lib/logsink'; +import { createSandbox } from 'sinon'; import { logger } from '@appium/support'; @@ -11,16 +11,17 @@ process.env._FORCE_LOGS = 1; const log = logger.getLogger('Appium'); describe('logging', function () { + let sandbox; let stderrSpy; let stdoutSpy; beforeEach(function () { - stderrSpy = sinon.spy(process.stderr, 'write'); - stdoutSpy = sinon.spy(process.stdout, 'write'); + sandbox = createSandbox(); + stderrSpy = sandbox.spy(process.stderr, 'write'); + stdoutSpy = sandbox.spy(process.stdout, 'write'); logsinkClear(); }); afterEach(function () { - stderrSpy.restore(); - stdoutSpy.restore(); + sandbox.restore(); }); after(function () { process.env._FORCE_LOGS = forceLogs; diff --git a/packages/appium/test/parser-specs.js b/packages/appium/test/unit/parser.spec.js similarity index 98% rename from packages/appium/test/parser-specs.js rename to packages/appium/test/unit/parser.spec.js index 4a07e34a4..c8c2f85da 100644 --- a/packages/appium/test/parser-specs.js +++ b/packages/appium/test/unit/parser.spec.js @@ -1,10 +1,10 @@ // transpile:mocha -import { getParser } from '../lib/cli/parser'; -import { INSTALL_TYPES } from '../lib/extension/extension-config'; -import * as schema from '../lib/schema/schema'; -import { readConfigFile } from '../lib/config-file'; -import { resolveFixture } from './helpers'; +import { getParser } from '../../lib/cli/parser'; +import { INSTALL_TYPES } from '../../lib/extension/extension-config'; +import * as schema from '../../lib/schema/schema'; +import { readConfigFile } from '../../lib/config-file'; +import { resolveFixture } from '../helpers'; // these paths should not make assumptions about the current working directory const ALLOW_FIXTURE = resolveFixture('allow-feat.txt'); diff --git a/packages/appium/test/schema/arg-spec-specs.js b/packages/appium/test/unit/schema/arg-spec.spec.js similarity index 98% rename from packages/appium/test/schema/arg-spec-specs.js rename to packages/appium/test/unit/schema/arg-spec.spec.js index a1f8af988..d4a0ee3db 100644 --- a/packages/appium/test/schema/arg-spec-specs.js +++ b/packages/appium/test/unit/schema/arg-spec.spec.js @@ -1,6 +1,6 @@ // @ts-check -import {ArgSpec} from '../../lib/schema/arg-spec'; +import {ArgSpec} from '../../../lib/schema/arg-spec'; const {expect} = chai; diff --git a/packages/appium/test/schema/cli-args-specs.js b/packages/appium/test/unit/schema/cli-args.spec.js similarity index 98% rename from packages/appium/test/schema/cli-args-specs.js rename to packages/appium/test/unit/schema/cli-args.spec.js index 9c8e71dee..81b2a24e3 100644 --- a/packages/appium/test/schema/cli-args-specs.js +++ b/packages/appium/test/unit/schema/cli-args.spec.js @@ -1,9 +1,9 @@ // @ts-check import _ from 'lodash'; -import {resetSchema, finalizeSchema, registerSchema} from '../../lib/schema'; -import {toParserArgs} from '../../lib/schema/cli-args'; -import {transformers} from '../../lib/schema/cli-transformers'; +import {resetSchema, finalizeSchema, registerSchema} from '../../../lib/schema'; +import {toParserArgs} from '../../../lib/schema/cli-args'; +import {transformers} from '../../../lib/schema/cli-transformers'; const {expect} = chai; diff --git a/packages/appium/test/schema/schema-specs.js b/packages/appium/test/unit/schema/schema.spec.js similarity index 92% rename from packages/appium/test/schema/schema-specs.js rename to packages/appium/test/unit/schema/schema.spec.js index a351885f8..ce8361d53 100644 --- a/packages/appium/test/schema/schema-specs.js +++ b/packages/appium/test/unit/schema/schema.spec.js @@ -1,14 +1,14 @@ // @ts-check import _ from 'lodash'; -import sinon from 'sinon'; -import { DRIVER_TYPE, PLUGIN_TYPE } from '../../lib/constants'; -import appiumConfigSchema from '../../lib/schema/appium-config-schema'; -import { APPIUM_CONFIG_SCHEMA_ID } from '../../lib/schema/arg-spec'; -import defaultArgsFixture from '../fixtures/default-args'; -import DRIVER_SCHEMA_FIXTURE from '../fixtures/driver.schema'; -import flattenedSchemaFixture from '../fixtures/flattened-schema'; -import { rewiremock } from '../helpers'; +import { createSandbox } from 'sinon'; +import { DRIVER_TYPE, PLUGIN_TYPE } from '../../../lib/constants'; +import appiumConfigSchema from '../../../lib/schema/appium-config-schema'; +import { APPIUM_CONFIG_SCHEMA_ID } from '../../../lib/schema/arg-spec'; +import defaultArgsFixture from '../../fixtures/default-args'; +import DRIVER_SCHEMA_FIXTURE from '../../fixtures/driver.schema'; +import flattenedSchemaFixture from '../../fixtures/flattened-schema'; +import { rewiremock } from '../../helpers'; const {expect} = chai; @@ -17,69 +17,69 @@ describe('schema', function () { let sandbox; /** - * @type {Class} + * @type {Class} */ let SchemaFinalizationError; /** - * @type {Class} + * @type {Class} */ let SchemaUnknownSchemaError; /** - * @type {Class} + * @type {Class} */ let SchemaUnsupportedSchemaError; /** - * @type {import('../../lib/schema/schema').resetSchema} + * @type {import('../../../lib/schema/schema').resetSchema} */ let resetSchema; /** - * @type {import('../../lib/schema/schema').registerSchema} + * @type {import('../../../lib/schema/schema').registerSchema} */ let registerSchema; /** - * @type {import('../../lib/schema/schema').getSchema} + * @type {import('../../../lib/schema/schema').getSchema} */ let getSchema; /** - * @type {import('../../lib/schema/schema').finalizeSchema} + * @type {import('../../../lib/schema/schema').finalizeSchema} */ let finalizeSchema; /** - * @type {import('../../lib/schema/schema').getDefaultsForSchema} + * @type {import('../../../lib/schema/schema').getDefaultsForSchema} */ let getDefaultsForSchema; /** - * @type {import('../../lib/schema/schema').flattenSchema} + * @type {import('../../../lib/schema/schema').flattenSchema} */ let flattenSchema; /** - * @type {import('../../lib/schema/schema').isFinalized} + * @type {import('../../../lib/schema/schema').isFinalized} */ let isFinalized; /** - * @type {import('../../lib/schema/schema').validate} + * @type {import('../../../lib/schema/schema').validate} */ let validate; let mocks; /** - * @type {Class} + * @type {Class} */ let RoachHotelMap; beforeEach(function () { - sandbox = sinon.createSandbox(); + sandbox = createSandbox(); mocks = { 'resolve-from': sandbox.stub(), @@ -100,7 +100,7 @@ describe('schema', function () { getDefaultsForSchema, flattenSchema, validate - } = rewiremock.proxy(() => require('../../lib/schema/schema'), mocks)); + } = rewiremock.proxy(() => require('../../../lib/schema/schema'), mocks)); resetSchema(); }); diff --git a/packages/appium/test/utils-specs.js b/packages/appium/test/unit/utils.spec.js similarity index 96% rename from packages/appium/test/utils-specs.js rename to packages/appium/test/unit/utils.spec.js index c0fe56ed6..37cef4511 100644 --- a/packages/appium/test/utils-specs.js +++ b/packages/appium/test/unit/utils.spec.js @@ -1,12 +1,12 @@ import { parseCapsForInnerDriver, insertAppiumPrefixes, pullSettings, removeAppiumPrefixes, inspect -} from '../lib/utils'; -import { BASE_CAPS, W3C_CAPS } from './helpers'; +} from '../../lib/utils'; +import { BASE_CAPS, W3C_CAPS } from '../helpers'; import _ from 'lodash'; import { stripColors } from '@colors/colors'; -import sinon from 'sinon'; -import logger from '../lib/logger'; +import { createSandbox } from 'sinon'; +import logger from '../../lib/logger'; describe('utils', function () { describe('parseCapsForInnerDriver()', function () { @@ -219,7 +219,7 @@ describe('utils', function () { */ let sandbox; beforeEach(function () { - sandbox = sinon.createSandbox(); + sandbox = createSandbox(); sandbox.spy(logger, 'info'); }); @@ -230,7 +230,7 @@ describe('utils', function () { it('should log the result of inspecting a value', function () { inspect({foo: 'bar'}); stripColors(/** @type {sinon.SinonStub} */(logger.info).firstCall.firstArg) - .should.equal('{ foo: \'bar\' }'); + .should.match(/\{\s*\n*foo:\s'bar'\s*\n*\}/); }); }); }); diff --git a/packages/base-driver/package.json b/packages/base-driver/package.json index ae3f22673..3beaade82 100644 --- a/packages/base-driver/package.json +++ b/packages/base-driver/package.json @@ -1,5 +1,6 @@ { "name": "@appium/base-driver", + "version": "8.2.4", "description": "Base driver class for Appium drivers", "keywords": [ "automation", @@ -11,20 +12,16 @@ "firefoxos", "testing" ], - "version": "8.2.4", - "author": "https://github.com/appium", - "license": "Apache-2.0", + "homepage": "https://appium.io", + "bugs": { + "url": "https://github.com/appium/appium/issues" + }, "repository": { "type": "git", "url": "https://github.com/appium/appium.git" }, - "bugs": { - "url": "https://github.com/appium/appium/issues" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - }, + "license": "Apache-2.0", + "author": "https://github.com/appium", "directories": { "lib": "lib" }, @@ -38,6 +35,12 @@ "build", "!build/test/basedriver/fixtures" ], + "scripts": { + "dev": "gulp dev --no-notif", + "build": "gulp transpile", + "test": "gulp unit-test:run", + "test:e2e": "gulp e2e-test:run" + }, "dependencies": { "@appium/support": "file:../support", "@babel/runtime": "7.16.3", @@ -59,9 +62,12 @@ "validate.js": "0.13.1", "ws": "7.5.6" }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, "publishConfig": { "access": "public" }, - "homepage": "https://appium.io", "gitHead": "ec6a90a797d2dadb407922426be16efaec9def07" } diff --git a/packages/doctor/package.json b/packages/doctor/package.json index fff78be96..dd3fdc084 100644 --- a/packages/doctor/package.json +++ b/packages/doctor/package.json @@ -12,6 +12,7 @@ "firefoxos", "testing" ], + "homepage": "https://appium.io", "bugs": { "url": "https://github.com/appium/appium/issues" }, @@ -34,6 +35,12 @@ "bin", "build" ], + "scripts": { + "dev": "gulp dev --no-notif", + "build": "gulp transpile", + "test": "gulp unit-test:run", + "test:e2e": "gulp e2e-test:run" + }, "dependencies": { "@appium/support": "file:../support", "@babel/runtime": "7.16.3", @@ -53,6 +60,5 @@ "publishConfig": { "access": "public" }, - "homepage": "https://appium.io", "gitHead": "ec6a90a797d2dadb407922426be16efaec9def07" } diff --git a/packages/fake-driver/package.json b/packages/fake-driver/package.json index 23c258f24..75e3d6f28 100644 --- a/packages/fake-driver/package.json +++ b/packages/fake-driver/package.json @@ -12,6 +12,7 @@ "firefoxos", "testing" ], + "homepage": "https://appium.io", "bugs": { "url": "https://github.com/appium/appium/issues" }, @@ -34,6 +35,12 @@ "test/fixtures", "screen.png" ], + "scripts": { + "dev": "gulp dev --no-notif", + "build": "gulp transpile", + "test": "gulp unit-test:run", + "test:e2e": "gulp e2e-test:run" + }, "dependencies": { "@appium/base-driver": "file:../base-driver", "@appium/support": "file:../support", @@ -49,6 +56,9 @@ "node": ">=12", "npm": ">=6" }, + "publishConfig": { + "access": "public" + }, "access": "public", "appium": { "driverName": "fake", @@ -63,9 +73,5 @@ "fake-success": "./build/lib/scripts/fake-success.js" } }, - "publishConfig": { - "access": "public" - }, - "homepage": "https://appium.io", "gitHead": "ec6a90a797d2dadb407922426be16efaec9def07" } diff --git a/packages/gulp-plugins/README.md b/packages/gulp-plugins/README.md index 0e6529b4c..d8ead8ba7 100644 --- a/packages/gulp-plugins/README.md +++ b/packages/gulp-plugins/README.md @@ -108,7 +108,7 @@ There are some issues with Gulp 3.x error handling which cause the default gulp-watch to hang. This plugin is a small hack which solves that by respawning the whole process on error. This should not be needed in gulp 4.0. -Files in the `/test` directory that are named `.*-specs.js` are run. Tests which end in `.*-e2e-specs.js` are *not* run when watching. To run end-to-end tests, run `gulp e2e-test`. +Files in the `/test` directory that are named `.*-specs.js` are run. Tests which end in `.*-e2e-specs.js` are *not* run when watching. To run end-to-end tests, run `gulp e2e-test:run`. ### usage diff --git a/packages/gulp-plugins/lib/boilerplate.js b/packages/gulp-plugins/lib/boilerplate.js index 1c015eb26..2c8180872 100644 --- a/packages/gulp-plugins/lib/boilerplate.js +++ b/packages/gulp-plugins/lib/boilerplate.js @@ -34,7 +34,7 @@ const DEFAULT_OPTS = { forceExit: false, traceWarnings: false, }, - testReporter: (process.env.TRAVIS || process.env.CI) ? 'spec' : 'nyan', + testReporter: 'spec', testTimeout: 20000, build: 'Appium', extraPrepublishTasks: [], diff --git a/packages/gulp-plugins/package.json b/packages/gulp-plugins/package.json index 329777cf9..44eefab43 100644 --- a/packages/gulp-plugins/package.json +++ b/packages/gulp-plugins/package.json @@ -12,6 +12,7 @@ "firefoxos", "testing" ], + "homepage": "https://appium.io", "bugs": { "url": "https://github.com/appium/appium/issues" }, @@ -32,6 +33,12 @@ "lib", "build" ], + "scripts": { + "dev": "gulp dev --no-notif", + "build": "gulp transpile", + "test": "gulp unit-test:run", + "test:e2e": "gulp e2e-test:run" + }, "dependencies": { "@appium/eslint-config-appium": "file:../eslint-config-appium", "@babel/core": "7.16.0", @@ -93,6 +100,5 @@ "publishConfig": { "access": "public" }, - "homepage": "https://appium.io", "gitHead": "ec6a90a797d2dadb407922426be16efaec9def07" } diff --git a/packages/gulp-plugins/test/gulpfile-js/index.js b/packages/gulp-plugins/test/gulpfile-js/index.js index 1bec3d6f5..455ac2fcc 100644 --- a/packages/gulp-plugins/test/gulpfile-js/index.js +++ b/packages/gulp-plugins/test/gulpfile-js/index.js @@ -10,7 +10,7 @@ const gulpIf = require('gulp-if'); gulp.task('clean-fixtures', function () { return gulp - .src('build', {read: false, allowEmpty: true}) + .src('build-fixtures', {read: false, allowEmpty: true}) .pipe(vinylPaths(del)); }); @@ -21,7 +21,7 @@ gulp.task('transpile-es7-fixtures', function () { .pipe(gulpIf(isVerbose(), debug())) .pipe(transpiler.stream()) .on('error', spawnWatcher.handleError) - .pipe(gulp.dest('build')); + .pipe(gulp.dest('build-fixtures')); }); gulp.task('transpile-fixtures', gulp.series('clean-fixtures', 'transpile-es7-fixtures')); diff --git a/packages/gulp-plugins/test/gulpfile-js/test-es7.js b/packages/gulp-plugins/test/gulpfile-js/test-es7.js index 75dcfaa40..e46bb521d 100644 --- a/packages/gulp-plugins/test/gulpfile-js/test-es7.js +++ b/packages/gulp-plugins/test/gulpfile-js/test-es7.js @@ -8,7 +8,7 @@ const gulpIf = require('gulp-if'); gulp.task('test-es7-mocha:run', function () { - return gulp.src('build/test/a-specs.js') + return gulp.src('build-fixtures/test/a-specs.js') .pipe(gulpIf(isVerbose(), debug())) .pipe(mocha()) .on('error', spawnWatcher.handleError); @@ -17,7 +17,7 @@ gulp.task('test-es7-mocha:run', function () { gulp.task('test-es7-mocha', gulp.series('transpile-es7-fixtures', 'test-es7-mocha:run')); gulp.task('test-es7-mocha-throw:run', function () { - return gulp.src('build/test/a-throw-specs.js') + return gulp.src('build-fixtures/test/a-throw-specs.js') .pipe(gulpIf(isVerbose(), debug())) .pipe(mocha()) .on('error', spawnWatcher.handleError); diff --git a/packages/gulp-plugins/test/transpile-specs.js b/packages/gulp-plugins/test/transpile-specs.js index d7f96d9bc..f68024346 100644 --- a/packages/gulp-plugins/test/transpile-specs.js +++ b/packages/gulp-plugins/test/transpile-specs.js @@ -55,7 +55,7 @@ describe('transpile-specs', function () { stderr.should.eql(''); stdout.should.include('Finished'); - const content = await readFile(`build/lib/${files.classFile}.js`, 'utf8'); + const content = await readFile(`build-fixtures/lib/${files.classFile}.js`, 'utf8'); content.should.have.length.above(0); content.should.include('sourceMapping'); }); @@ -66,21 +66,21 @@ describe('transpile-specs', function () { }); it(`should be able to run transpiled ${name} code`, async function () { - const [stdout, stderr] = await exec(`node build/lib/${files.classFile}-run.js`); + const [stdout, stderr] = await exec(`node build-fixtures/lib/${files.classFile}-run.js`); print(stdout, stderr); stderr.should.equal(''); stdout.should.include('hello world!'); }); it(`should be able to run transpiled ${name} tests`, async function () { - const [stdout, stderr] = await exec(`${MOCHA} build/test/${files.classFile}-specs.js`); + const [stdout, stderr] = await exec(`${MOCHA} build-fixtures/test/${files.classFile}-specs.js`); print(stdout, stderr); stderr.should.equal(''); stdout.should.include('1 passing'); }); it(`should use sourcemap when throwing (${name})`, async function () { - const [stdout, stderr] = await exec(`node build/lib/${files.classFile}-throw.js`); + const [stdout, stderr] = await exec(`node build-fixtures/lib/${files.classFile}-throw.js`); print(stdout, stderr); let output = stdout + stderr; output.should.include('This is really bad!'); @@ -88,7 +88,7 @@ describe('transpile-specs', function () { }); it(`should use sourcemap when throwing within mocha (${name})`, async function () { - const [stdout, stderr] = await exec(`${MOCHA} build/test/${files.classFile}-throw-specs.js`); + const [stdout, stderr] = await exec(`${MOCHA} build-fixtures/test/${files.classFile}-throw-specs.js`); print(stdout, stderr); let output = stdout + stderr; output.should.include('This is really bad!'); @@ -114,7 +114,7 @@ describe('transpile-specs', function () { // TypeScript will not compile such errors, so no need to test it('should not detect a rtts-assert error', async function () { - const [stdout, stderr] = await exec('node build/lib/a-rtts-assert-error.js'); + const [stdout, stderr] = await exec('node build-fixtures/lib/a-rtts-assert-error.js'); print(stdout, stderr); stderr.should.equal(''); stdout.should.include('123'); diff --git a/packages/opencv/package.json b/packages/opencv/package.json index 42c450a9a..975e50f86 100644 --- a/packages/opencv/package.json +++ b/packages/opencv/package.json @@ -12,6 +12,7 @@ "firefoxos", "testing" ], + "homepage": "https://appium.io", "bugs": { "url": "https://github.com/appium/appium/issues" }, @@ -29,6 +30,12 @@ "lib", "build" ], + "scripts": { + "dev": "gulp dev --no-notif", + "build": "gulp transpile", + "test": "gulp unit-test:run", + "test:e2e": "gulp e2e-test:run" + }, "dependencies": { "@babel/runtime": "7.16.3", "bluebird": "3.7.2", @@ -44,6 +51,5 @@ "publishConfig": { "access": "public" }, - "homepage": "https://appium.io", "gitHead": "ec6a90a797d2dadb407922426be16efaec9def07" } diff --git a/packages/support/package.json b/packages/support/package.json index f24c2107d..2218975e7 100644 --- a/packages/support/package.json +++ b/packages/support/package.json @@ -12,6 +12,7 @@ "firefoxos", "testing" ], + "homepage": "https://appium.io", "bugs": { "url": "https://github.com/appium/appium/issues" }, @@ -29,6 +30,12 @@ "lib", "build" ], + "scripts": { + "dev": "gulp dev --no-notif", + "build": "gulp transpile", + "test": "gulp unit-test:run", + "test:e2e": "gulp e2e-test:run" + }, "dependencies": { "@babel/runtime": "7.16.3", "archiver": "5.3.0", @@ -72,6 +79,5 @@ "publishConfig": { "access": "public" }, - "homepage": "https://appium.io", "gitHead": "ec6a90a797d2dadb407922426be16efaec9def07" } diff --git a/packages/test-support/package.json b/packages/test-support/package.json index e1f5d06f9..ed61a92a6 100644 --- a/packages/test-support/package.json +++ b/packages/test-support/package.json @@ -12,6 +12,7 @@ "firefoxos", "testing" ], + "homepage": "https://appium.io", "bugs": { "url": "https://github.com/appium/appium/issues" }, @@ -34,6 +35,12 @@ "lib", "build" ], + "scripts": { + "dev": "gulp dev --no-notif", + "build": "gulp transpile", + "test": "gulp unit-test:run", + "test:e2e": "gulp e2e-test:run" + }, "dependencies": { "@appium/support": "file:../support", "@babel/runtime": "7.16.3", @@ -47,12 +54,8 @@ "node": ">=12", "npm": ">=6" }, - "greenkeeper": { - "ignore": [] - }, "publishConfig": { "access": "public" }, - "homepage": "https://appium.io", "gitHead": "ec6a90a797d2dadb407922426be16efaec9def07" } diff --git a/scripts/generate-schema-declarations.mjs b/scripts/generate-schema-declarations.mjs deleted file mode 100644 index 7a7a322d4..000000000 --- a/scripts/generate-schema-declarations.mjs +++ /dev/null @@ -1,50 +0,0 @@ -/* eslint-disable no-console */ -/* - * This module reads in the config file JSON schema and outputs a TypeScript declaration file (`.d.ts`). - * - * WARNING: This will add `../packages/appium/types/appium-config.d.ts` to the Git stage! - */ - -import { execSync } from 'child_process'; -import { compileFromFile } from 'json-schema-to-typescript'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import { promises as fs } from 'fs'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); - -const SCHEMA_PATH = path.join( - __dirname, - '..', - 'packages', - 'appium', - 'lib', - 'appium-config.schema.json', -); - -const DECLARATIONS_PATH = path.join( - __dirname, - '..', - 'packages', - 'appium', - 'types', - 'appium-config.d.ts', -); - -// no top-level await in node v12 -async function main () { - try { - console.log('transpiling appium...'); - execSync('../node_modules/.bin/gulp -f ../packages/appium/gulpfile.js transpile', {stdio: 'inherit', cwd: __dirname}); - const ts = await compileFromFile(SCHEMA_PATH); - await fs.writeFile(DECLARATIONS_PATH, ts); - console.log(`wrote to ${DECLARATIONS_PATH}`); - execSync(`git add -A "${DECLARATIONS_PATH}"`, {stdio: 'inherit'}); - console.log(`added ${DECLARATIONS_PATH} to the stage`); - } catch (err) { - console.error(err); - process.exitCode = 1; - } -} - -main(); diff --git a/tsconfig.json b/tsconfig.json index 4e7902278..7331b6d40 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,8 +13,7 @@ "include": [ "packages/*/**/*.d.ts", "packages/*/**/*.js", - "*.js", - "scripts/generate-schema-declarations.mjs" + "*.js" ], "exclude": ["**/node_modules/**", "**/build/**"] }