diff --git a/circle.yml b/circle.yml index bf8dc19978c..2b2ecf49e77 100644 --- a/circle.yml +++ b/circle.yml @@ -14,9 +14,8 @@ dependencies: - sudo apt-get install git-lfs - ssh git@github.com git-lfs-authenticate $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME.git download - git lfs pull - - docker run --rm --env-file ./test/docker-env.list -v ${PWD}:/project -v ~/.electron:/root/.electron -v ~/.cache/electron-builder:/root/.cache/electron-builder electronuserland/electron-builder:wine /bin/bash -c "node ./test/vendor/yarn.js --link-duplicates --pure-lockfile && node ./test/vendor/yarn.js test" - mkdir -p $CIRCLE_TEST_REPORTS/reports - - mv -f test/test-report.xml $CIRCLE_TEST_REPORTS/reports/test-report.xml + - docker run --rm --env-file ./test/docker-env.list -v ${PWD}:/project -v ~/.electron:/root/.electron -v ~/.cache/electron-builder:/root/.cache/electron-builder electronuserland/electron-builder:wine /bin/bash -c "node ./test/vendor/yarn.js --link-duplicates --pure-lockfile && node ./test/vendor/yarn.js test" && mv -f test/test-report.xml $CIRCLE_TEST_REPORTS/reports/test-report.xml test: override: diff --git a/docs/Options.md b/docs/Options.md index 5425f18ff36..0cd4c23d665 100644 --- a/docs/Options.md +++ b/docs/Options.md @@ -136,7 +136,7 @@ On Windows works only if [nsis.perMachine](https://github.com/electron-userland/ | category | The [application category](https://specifications.freedesktop.org/menu-spec/latest/apa.html#main-category-registry). | packageCategory | The [package category](https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Section). Not applicable for AppImage. | description | As [description](#AppMetadata-description) from application package.json, but allows you to specify different for Linux. -| target |

Target package type: list of AppImage, snap, deb, rpm, freebsd, pacman, p5p, apk, 7z, zip, tar.xz, tar.lz, tar.gz, tar.bz2, dir. Defaults to AppImage.

The most effective [xz](https://en.wikipedia.org/wiki/Xz) compression format used by default.

+| target |

Target package type: list of AppImage, snap, deb, rpm, freebsd, pacman, p5p, apk, 7z, zip, tar.xz, tar.lz, tar.gz, tar.bz2, dir. Defaults to AppImage.

The most effective [xz](https://en.wikipedia.org/wiki/Xz) compression format used by default.

electron-builder [docker image](https://github.com/electron-userland/electron-builder/wiki/Docker) can be used to build Linux targets on any platform. See [Multi platform build](https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build).

| maintainer | The maintainer. Defaults to [author](#AppMetadata-author). | vendor | The vendor. Defaults to [author](#AppMetadata-author). | desktop | The [Desktop file](https://developer.gnome.org/integration-guide/stable/desktop-files.html.en) entries (name to value). diff --git a/package.json b/package.json index 6ecbb13f7c2..1276fce8a2e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": true, "license": "MIT", "scripts": { - "compile": "ts-babel packages/electron-builder-http packages/electron-builder-core packages/electron-builder-util packages/electron-publish packages/electron-builder packages/electron-builder-squirrel-windows packages/electron-updater packages/electron-publisher-s3 test && node ./test/vendor/yarn.js scheme", + "compile": "ts-babel packages/electron-builder-http packages/electron-builder-core packages/electron-builder-util packages/electron-publish packages/electron-builder packages/electron-builder-squirrel-windows packages/electron-updater packages/electron-publisher-s3 test && node ./test/vendor/yarn.js schema", "lint": "node test/out/helpers/lint.js", "pretest": "node ./test/vendor/yarn.js compile && node ./test/vendor/yarn.js lint && node ./test/vendor/yarn.js lint-deps", "lint-deps": "node ./test/out/helpers/checkDeps.js", @@ -18,13 +18,15 @@ "update-deps": "lerna exec -- npm-check-updates --reject 'electron-builder-http,electron-builder-util,electron-builder-core,electron-publish' -a", "set-versions": "node test/out/helpers/setVersions.js", "npm-publish": "yarn compile && ./packages/npm-publish.sh && conventional-changelog -p angular -i CHANGELOG.md -s", - "scheme": "typescript-json-schema packages/electron-builder/tsconfig.json Config --out packages/electron-builder/scheme.json", + "schema": "typescript-json-schema packages/electron-builder/tsconfig.json Config --out packages/electron-builder/scheme.json --noExtraProps", "docs": "jsdoc -R jsdoc/readme.md -c jsdoc/jsdoc.json -d jsdoc/out -P packages/electron-updater/package.json jsdoc/out/electron-updater" }, "//": "repository must be specified otherwise conventional-changelog will use forked repo (currently cloned)", "repository": "electron-userland/electron-builder", "dependencies": { "7zip-bin": "^2.0.4", + "ajv": "^5.0.2-beta", + "ajv-keywords": "^1.5.1", "archiver": "^1.3.0", "asar-electron-builder": "^0.13.5", "aws-sdk": "^2.17.0", @@ -58,6 +60,7 @@ "yargs": "^6.6.0" }, "devDependencies": { + "@develar/typescript-json-schema": "0.9.1", "@types/electron": "^1.4.32", "@types/ini": "^1.3.29", "@types/jest": "^18.1.1", @@ -76,8 +79,8 @@ "depcheck": "^0.6.7", "docdash": "https://github.com/develar/docdash.git", "electron-download-tf": "3.2.0", - "jest-cli": "^19.0.0", - "jest-environment-node-debug": "^1.0.0", + "jest-cli": "^19.0.1", + "jest-environment-node-debug": "^2.0.0", "jest-junit-reporter": "^1.0.1", "jsdoc": "^3.4.3", "lerna": "2.0.0-beta.37", diff --git a/packages/electron-builder-http/src/publishOptions.ts b/packages/electron-builder-http/src/publishOptions.ts index 7ec6af1ac4d..1be66ff4f4a 100644 --- a/packages/electron-builder-http/src/publishOptions.ts +++ b/packages/electron-builder-http/src/publishOptions.ts @@ -1,7 +1,5 @@ export type PublishProvider = "github" | "bintray" | "s3" | "generic" -export type Publish = string | Array | PublishConfiguration | GithubOptions | S3Options | BintrayOptions | GenericServerOptions | Array | Array | Array | Array | Array | null - /** ### `publish` @@ -149,4 +147,9 @@ export interface BintrayOptions extends PublishConfiguration { The Bintray user account. Used in cases where the owner is an organization. */ user?: string | null -} \ No newline at end of file +} + +// typescript-json-schema generates only PublishConfiguration if it is specified in the list, so, it is not added here +export type AllPublishOptions = string | GithubOptions | S3Options | GenericServerOptions | BintrayOptions +// https://github.com/YousefED/typescript-json-schema/issues/80 +export type Publish = AllPublishOptions | Array | null \ No newline at end of file diff --git a/packages/electron-builder/package.json b/packages/electron-builder/package.json index 334d2425303..62b59a1aa27 100644 --- a/packages/electron-builder/package.json +++ b/packages/electron-builder/package.json @@ -44,6 +44,8 @@ "bugs": "https://github.com/electron-userland/electron-builder/issues", "homepage": "https://github.com/electron-userland/electron-builder", "dependencies": { + "ajv": "^5.0.2-beta", + "ajv-keywords": "^1.5.1", "7zip-bin": "^2.0.4", "asar-electron-builder": "^0.13.5", "bluebird-lst": "^1.0.1", diff --git a/packages/electron-builder/src/fileMatcher.ts b/packages/electron-builder/src/fileMatcher.ts index 7aed6fec922..926e9037024 100644 --- a/packages/electron-builder/src/fileMatcher.ts +++ b/packages/electron-builder/src/fileMatcher.ts @@ -108,36 +108,4 @@ export function copyFiles(patterns: Array | null): Promise { } return await copyDir(pattern.from, pattern.to, pattern.createFilter()) }) -} - - -export function deprecatedUserIgnoreFilter(ignore: Array | ((file: string) => boolean), appDir: string) { - let ignoreFunc: any - if (typeof ignore === "function") { - ignoreFunc = function (file: string) { return !(ignore)(file) } - } - else { - if (!Array.isArray(ignore)) { - ignore = [ignore] - } - - ignoreFunc = function (file: string) { - for (const i of >ignore) { - if (file.match(i)) { - return false - } - } - - return true - } - } - - return function filter(file: string) { - let name = file.split(path.resolve(appDir))[1] - if (path.sep === "\\") { - // convert slashes so unix-format ignores work - name = name.replace(/\\/g, "/") - } - return ignoreFunc(name) - } } \ No newline at end of file diff --git a/packages/electron-builder/src/options/linuxOptions.ts b/packages/electron-builder/src/options/linuxOptions.ts index 97c7a135110..f7eb76e7961 100644 --- a/packages/electron-builder/src/options/linuxOptions.ts +++ b/packages/electron-builder/src/options/linuxOptions.ts @@ -23,6 +23,8 @@ export interface LinuxBuildOptions extends PlatformSpecificBuildOptions { Target package type: list of `AppImage`, `snap`, `deb`, `rpm`, `freebsd`, `pacman`, `p5p`, `apk`, `7z`, `zip`, `tar.xz`, `tar.lz`, `tar.gz`, `tar.bz2`, `dir`. Defaults to `AppImage`. The most effective [xz](https://en.wikipedia.org/wiki/Xz) compression format used by default. + + electron-builder [docker image](https://github.com/electron-userland/electron-builder/wiki/Docker) can be used to build Linux targets on any platform. See [Multi platform build](https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build). */ readonly target?: Array | null diff --git a/packages/electron-builder/src/packager.ts b/packages/electron-builder/src/packager.ts index 526e79dc287..9200c5c0855 100644 --- a/packages/electron-builder/src/packager.ts +++ b/packages/electron-builder/src/packager.ts @@ -1,3 +1,4 @@ +import Ajv from "ajv" import { extractFile } from "asar-electron-builder" import BluebirdPromise from "bluebird-lst" import { Arch, Platform, Target } from "electron-builder-core" @@ -8,6 +9,7 @@ import { log, warn } from "electron-builder-util/out/log" import { all, executeFinally } from "electron-builder-util/out/promise" import { TmpDir } from "electron-builder-util/out/tmp" import { EventEmitter } from "events" +import { readJson } from "fs-extra-p" import * as path from "path" import { lt as isVersionLessThan } from "semver" import { AppInfo } from "./appInfo" @@ -17,7 +19,7 @@ import { ArtifactCreated, BuildInfo, PackagerOptions, SourceRepositoryInfo } fro import { PlatformPackager } from "./platformPackager" import { getRepositoryInfo } from "./repositoryInfo" import { createTargets } from "./targets/targetFactory" -import { doLoadConfig, getElectronVersion, loadConfig, readPackageJson } from "./util/readPackageJson" +import { doLoadConfig, getElectronVersion, loadConfig, normaliseErrorMessages, readPackageJson } from "./util/readPackageJson" import { WinPackager } from "./winPackager" import { getGypEnv, installOrRebuild } from "./yarn" @@ -124,6 +126,15 @@ export class Packager implements BuildInfo { } } + const ajv = new Ajv({allErrors: true}) + ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-04.json")) + require("ajv-keywords")(ajv, ["typeof"]) + const schema = await readJson(path.join(__dirname, "..", "scheme.json")) + const validator = ajv.compile(schema) + if (!validator(config)) { + throw new Error("Config is invalid:\n" + JSON.stringify(normaliseErrorMessages(validator.errors!), null, 2) + "\n\nRaw validation errors: " + JSON.stringify(validator.errors, null, 2)) + } + this._config = config this.appDir = await computeDefaultAppDirectory(projectDir, use(config.directories, it => it!.app)) diff --git a/packages/electron-builder/src/platformPackager.ts b/packages/electron-builder/src/platformPackager.ts index 6e04ba7380f..3a05cd04ad7 100644 --- a/packages/electron-builder/src/platformPackager.ts +++ b/packages/electron-builder/src/platformPackager.ts @@ -9,7 +9,7 @@ import { Minimatch } from "minimatch" import * as path from "path" import { AppInfo } from "./appInfo" import { checkFileInArchive, createAsarArchive } from "./asarUtil" -import { copyFiles, deprecatedUserIgnoreFilter, FileMatcher } from "./fileMatcher" +import { copyFiles, FileMatcher } from "./fileMatcher" import { AsarOptions, Config, FileAssociation, FilePattern, Macros, PlatformSpecificBuildOptions } from "./metadata" import { unpackElectron } from "./packager/dirPackager" import { BuildInfo, PackagerOptions } from "./packagerApi" @@ -172,17 +172,6 @@ export abstract class PlatformPackager ".nyc_output}") let rawFilter: any = null - const deprecatedIgnore = (this.config).ignore - if (deprecatedIgnore != null) { - if (typeof deprecatedIgnore === "function") { - warn(`"ignore" is specified as function, may be new "files" option will be suit your needs? Please see https://github.com/electron-userland/electron-builder/wiki/Options#Config-files`) - } - else { - warn(`"ignore" is deprecated, please use "files", see https://github.com/electron-userland/electron-builder/wiki/Options#Config-files`) - } - rawFilter = deprecatedUserIgnoreFilter(deprecatedIgnore, appDir) - } - const excludePatterns: Array = [] if (extraResourceMatchers != null) { for (const matcher of extraResourceMatchers) { diff --git a/packages/electron-builder/src/util/readPackageJson.ts b/packages/electron-builder/src/util/readPackageJson.ts index dad482dcaf0..9b3dccaa4f0 100644 --- a/packages/electron-builder/src/util/readPackageJson.ts +++ b/packages/electron-builder/src/util/readPackageJson.ts @@ -4,6 +4,9 @@ import { readFile, readJson } from "fs-extra-p" import { safeLoad } from "js-yaml" import * as path from "path" import { Config } from "../metadata" +import AdditionalPropertiesParams = ajv.AdditionalPropertiesParams +import ErrorObject = ajv.ErrorObject +import TypeParams = ajv.TypeParams const normalizeData = require("normalize-package-data") @@ -34,14 +37,7 @@ async function authors(file: string, data: any) { function getConfigFromPackageData(metadata: any) { if (metadata.directories != null) { - warn(`"directories" in the root is deprecated, please specify in the "build"`) - if (metadata.build == null) { - metadata.build = {directories: metadata.directories} - } - else if (metadata.build.directories == null) { - metadata.build.directories = metadata.directories - } - delete metadata.directories + throw new Error(`"directories" in the root is deprecated, please specify in the "build"`) } return metadata.build } @@ -132,4 +128,68 @@ function findFromElectronPrebuilt(packageData: any): any { } } return null +} + +export function normaliseErrorMessages(errors: Array) { + const result: any = Object.create(null) + for (const e of errors) { + if (e.keyword === "type" && (e.params).type === "null") { + // ignore - no sense to report that type accepts null + continue + } + + const dataPath = e.dataPath.length === 0 ? [] : e.dataPath.substring(1).split(".") + if (e.keyword === "additionalProperties") { + dataPath.push((e.params).additionalProperty) + } + + let o = result + let lastName: string | null = null + for (const p of dataPath) { + if (p === dataPath[dataPath.length - 1]) { + lastName = p + break + } + else { + if (o[p] == null) { + o[p] = Object.create(null) + } + else if (typeof o[p] === "string") { + o[p] = [o[p]] + } + o = o[p] + } + } + + if (lastName == null) { + lastName = "unknown" + } + + let message = e.message!.toUpperCase()[0] + e.message!.substring(1) + switch (e.keyword) { + case "additionalProperties": + message = "Unknown option" + break + + case "required": + message = "Required option" + break + + case "anyOf": + message = "Invalid option object" + break + } + + if (o[lastName] != null && !Array.isArray(o[lastName])) { + o[lastName] = [o[lastName]] + } + + if (Array.isArray(o[lastName])) { + o[lastName].push(message) + } + else { + o[lastName] = message + } + } + return result } \ No newline at end of file diff --git a/packages/electron-builder/templates/linux/AppRun.sh b/packages/electron-builder/templates/linux/AppRun.sh index 062bd3ed729..5e50591dfb9 100755 --- a/packages/electron-builder/templates/linux/AppRun.sh +++ b/packages/electron-builder/templates/linux/AppRun.sh @@ -34,9 +34,9 @@ if [ -z $APPDIR ] ; then fi export PATH="${APPDIR}/usr/bin:${APPDIR}/usr/sbin:${PATH}" -export XDG_DATA_DIRS="./share/:${XDG_DATA_DIRS}" +export XDG_DATA_DIRS="./share/:/usr/share/gnome:/usr/local/share/:/usr/share/:${XDG_DATA_DIRS}" export LD_LIBRARY_PATH="${APPDIR}/usr/lib:${LD_LIBRARY_PATH}" -export XDG_DATA_DIRS="${APPDIR}/usr/share:${XDG_DATA_DIRS}" +export XDG_DATA_DIRS="${APPDIR}"/usr/share/:"${XDG_DATA_DIRS}":/usr/share/gnome/:/usr/local/share/:/usr/share/ export GSETTINGS_SCHEMA_DIR="${APPDIR}/usr/share/glib-2.0/schemas:${GSETTINGS_SCHEMA_DIR}" DESKTOP_FILE=$(find "$APPDIR" -maxdepth 1 -name "*.desktop" | head -n 1) diff --git a/packages/electron-builder/templates/nsis/common.nsh b/packages/electron-builder/templates/nsis/common.nsh index dc7bb5d5390..3d0c2703f9c 100644 --- a/packages/electron-builder/templates/nsis/common.nsh +++ b/packages/electron-builder/templates/nsis/common.nsh @@ -13,12 +13,12 @@ Name "${PRODUCT_NAME}" !define UNINSTALL_FILENAME "Uninstall ${PRODUCT_FILENAME}.exe" !macro check64BitAndSetRegView - !ifdef APP_64 - ${IfNot} ${AtLeastWin7} - MessageBox MB_OK "Windows 7 and above is required" - Quit - ${EndIf} + ${IfNot} ${AtLeastWin7} + MessageBox MB_OK "Windows 7 and above is required" + Quit + ${EndIf} + !ifdef APP_64 ${If} ${RunningX64} SetRegView 64 ${Else} diff --git a/test/fixtures/test-app/package.json b/test/fixtures/test-app/package.json index 921d67b4a79..7fc85761786 100755 --- a/test/fixtures/test-app/package.json +++ b/test/fixtures/test-app/package.json @@ -3,9 +3,11 @@ "build": { "electronVersion": "1.6.0", "appId": "org.electron-builder.testApp", - "category": "your.app.category.type", "iconUrl": "https://raw.githubusercontent.com/szwacz/electron-boilerplate/master/resources/windows/icon.ico", "compression": "store", - "npmRebuild": false + "npmRebuild": false, + "mac": { + "category": "your.app.category.type" + } } } diff --git a/test/out/__snapshots__/BuildTest.js.snap b/test/out/__snapshots__/BuildTest.js.snap index 914ad69823a..fc24216d067 100644 --- a/test/out/__snapshots__/BuildTest.js.snap +++ b/test/out/__snapshots__/BuildTest.js.snap @@ -1,5 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`build in the app package.json 1`] = `"'build' in the application package.json (/package.json) is not supported since 3.0 anymore. Please move 'build' into the development package.json (/package.json)"`; + exports[`cli 1`] = ` Object { "config": undefined, @@ -235,3 +237,147 @@ Object { }, } `; + +exports[`custom buildResources dir 1`] = ` +Array [ + Object { + "file": "latest-mac.json", + }, + Object { + "file": "Test App ßW-1.1.0.dmg", + "safeArtifactName": "TestApp-1.1.0.dmg", + }, + Object { + "file": "Test App ßW-1.1.0-mac.zip", + "safeArtifactName": "TestApp-1.1.0-mac.zip", + }, +] +`; + +exports[`custom buildResources dir 2`] = ` +Array [ + "Test App ßW Setup 1.1.0.exe", +] +`; + +exports[`custom buildResources dir 3`] = ` +Array [ + "TestApp-Setup-1.1.0.exe", +] +`; + +exports[`custom output dir 1`] = ` +Array [ + Object { + "file": "latest-mac.json", + }, + Object { + "file": "Test App ßW-1.1.0.dmg", + "safeArtifactName": "TestApp-1.1.0.dmg", + }, + Object { + "file": "Test App ßW-1.1.0-mac.zip", + "safeArtifactName": "TestApp-1.1.0-mac.zip", + }, +] +`; + +exports[`custom output dir 2`] = ` +Array [ + "Test App ßW Setup 1.1.0.exe", +] +`; + +exports[`custom output dir 3`] = ` +Array [ + "TestApp-Setup-1.1.0.exe", +] +`; + +exports[`name in the build 1`] = ` +"Config is invalid: +{ + \\"name\\": \\"Unknown option\\" +} + +Raw validation errors: [ + { + \\"keyword\\": \\"additionalProperties\\", + \\"dataPath\\": \\"\\", + \\"schemaPath\\": \\"#/additionalProperties\\", + \\"params\\": { + \\"additionalProperty\\": \\"name\\" + }, + \\"message\\": \\"should NOT have additional properties\\" + } +]" +`; + +exports[`scheme validation 1`] = ` +"Config is invalid: +{ + \\"foo\\": \\"Unknown option\\", + \\"mac\\": [ + { + \\"foo\\": \\"Unknown option\\" + }, + \\"Invalid option object\\" + ] +} + +Raw validation errors: [ + { + \\"keyword\\": \\"additionalProperties\\", + \\"dataPath\\": \\"\\", + \\"schemaPath\\": \\"#/additionalProperties\\", + \\"params\\": { + \\"additionalProperty\\": \\"foo\\" + }, + \\"message\\": \\"should NOT have additional properties\\" + }, + { + \\"keyword\\": \\"additionalProperties\\", + \\"dataPath\\": \\".mac\\", + \\"schemaPath\\": \\"#/additionalProperties\\", + \\"params\\": { + \\"additionalProperty\\": \\"foo\\" + }, + \\"message\\": \\"should NOT have additional properties\\" + }, + { + \\"keyword\\": \\"type\\", + \\"dataPath\\": \\".mac\\", + \\"schemaPath\\": \\"#/properties/mac/anyOf/1/type\\", + \\"params\\": { + \\"type\\": \\"null\\" + }, + \\"message\\": \\"should be null\\" + }, + { + \\"keyword\\": \\"anyOf\\", + \\"dataPath\\": \\".mac\\", + \\"schemaPath\\": \\"#/properties/mac/anyOf\\", + \\"params\\": {}, + \\"message\\": \\"should match some schema in anyOf\\" + } +]" +`; + +exports[`scheme validation 2 1`] = ` +"Config is invalid: +{ + \\"appId\\": \\"Should be null,string\\" +} + +Raw validation errors: [ + { + \\"keyword\\": \\"type\\", + \\"dataPath\\": \\".appId\\", + \\"schemaPath\\": \\"#/properties/appId/type\\", + \\"params\\": { + \\"type\\": \\"null,string\\" + }, + \\"message\\": \\"should be null,string\\" + } +]" +`; diff --git a/test/out/__snapshots__/extraMetadataTest.js.snap b/test/out/__snapshots__/extraMetadataTest.js.snap index 21dd3dd7265..e9d9bb28e70 100644 --- a/test/out/__snapshots__/extraMetadataTest.js.snap +++ b/test/out/__snapshots__/extraMetadataTest.js.snap @@ -1,5 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`extra metadata - override icon 1`] = `"ENOENT: no such file or directory, lstat '/dev.icns'"`; + exports[`extra metadata 1`] = ` Object { "author": "Foo Bar ", diff --git a/test/out/__snapshots__/nsisUpdaterTest.js.snap b/test/out/__snapshots__/nsisUpdaterTest.js.snap index 880aad61da6..134b7c04bb2 100644 --- a/test/out/__snapshots__/nsisUpdaterTest.js.snap +++ b/test/out/__snapshots__/nsisUpdaterTest.js.snap @@ -1,5 +1,62 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`cancel download with progress 1`] = `"Cancelled"`; + +exports[`cannot find suitable file for version 1`] = ` +"Cannot find suitable file for version 1.0.0 in: [ + { + \\"name\\": \\"index.js\\", + \\"path\\": \\"index.js\\", + \\"repo\\": \\"generic\\", + \\"package\\": \\"incorrect-file-version\\", + \\"version\\": \\"1.0.0\\", + \\"owner\\": \\"actperepo\\", + \\"created\\": \\"2016-08-08T06:31:26.416Z\\", + \\"size\\": 3628, + \\"sha1\\": \\"8658d188bd524e1c2372afe79bb77e9580155604\\", + \\"sha256\\": \\"b1c15917ae5f79686eedbe0767a6c4aa6a57d338c919ad9126b2141fa73a0aa8\\" + }, + { + \\"name\\": \\"foo.exe\\", + \\"path\\": \\"foo.exe\\", + \\"repo\\": \\"generic\\", + \\"package\\": \\"incorrect-file-version\\", + \\"version\\": \\"1.0.0\\", + \\"owner\\": \\"actperepo\\", + \\"created\\": \\"2016-09-08T07:02:31.179Z\\", + \\"size\\": 1, + \\"sha1\\": \\"adc83b19e793491b1c6ea0fd8b46cd9f32e592fc\\", + \\"sha256\\": \\"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b\\" + }, + { + \\"name\\": \\"11TestApp Setup 1.1.0.exe\\", + \\"path\\": \\"11TestApp Setup 1.1.0.exe\\", + \\"repo\\": \\"generic\\", + \\"package\\": \\"incorrect-file-version\\", + \\"version\\": \\"1.0.0\\", + \\"owner\\": \\"actperepo\\", + \\"created\\": \\"2016-09-18T16:51:26.240Z\\", + \\"size\\": 1, + \\"sha1\\": \\"adc83b19e793491b1c6ea0fd8b46cd9f32e592fc\\", + \\"sha256\\": \\"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b\\" + }, + { + \\"name\\": \\"11TestApp Setup 1.1.0 copy.exe\\", + \\"path\\": \\"11TestApp Setup 1.1.0 copy.exe\\", + \\"repo\\": \\"generic\\", + \\"package\\": \\"incorrect-file-version\\", + \\"version\\": \\"1.0.0\\", + \\"owner\\": \\"actperepo\\", + \\"created\\": \\"2016-09-18T16:51:26.095Z\\", + \\"size\\": 1, + \\"sha1\\": \\"adc83b19e793491b1c6ea0fd8b46cd9f32e592fc\\", + \\"sha256\\": \\"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b\\" + } +]" +`; + +exports[`check updates - no versions at all 1`] = `"No latest version, please ensure that user, package and repository correctly configured. Or at least one version is published. HttpError: 404 Not Found"`; + exports[`checkForUpdates several times 1`] = ` Object { "name": "TestApp Setup 1.1.0.exe", @@ -71,7 +128,9 @@ Object { } `; -exports[`sha2 mismatch error event 2`] = ` +exports[`sha2 mismatch error event 2`] = `"SHA2 checksum mismatch, expected f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd1, got f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2"`; + +exports[`sha2 mismatch error event 3`] = ` Array [ "checking-for-update", "update-available", @@ -79,7 +138,9 @@ Array [ ] `; -exports[`test error 1`] = ` +exports[`test error 1`] = `"Path must be a string. Received undefined"`; + +exports[`test error 2`] = ` Array [ "checking-for-update", "error", diff --git a/test/out/mac/__snapshots__/macArchiveTest.js.snap b/test/out/mac/__snapshots__/macArchiveTest.js.snap index 53baf6afb45..3356f1c4cb2 100644 --- a/test/out/mac/__snapshots__/macArchiveTest.js.snap +++ b/test/out/mac/__snapshots__/macArchiveTest.js.snap @@ -1,5 +1,74 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`invalid target 1`] = ` +"Config is invalid: +{ + \\"mac\\": [ + { + \\"target[0]\\": \\"Should be equal to one of the allowed values\\", + \\"target\\": \\"Invalid option object\\" + }, + \\"Invalid option object\\" + ] +} + +Raw validation errors: [ + { + \\"keyword\\": \\"enum\\", + \\"dataPath\\": \\".mac.target[0]\\", + \\"schemaPath\\": \\"#/properties/target/anyOf/0/items/enum\\", + \\"params\\": { + \\"allowedValues\\": [ + \\"7z\\", + \\"default\\", + \\"dir\\", + \\"dmg\\", + \\"mas\\", + \\"pkg\\", + \\"tar.bz2\\", + \\"tar.gz\\", + \\"tar.lz\\", + \\"tar.xz\\", + \\"zip\\" + ] + }, + \\"message\\": \\"should be equal to one of the allowed values\\" + }, + { + \\"keyword\\": \\"type\\", + \\"dataPath\\": \\".mac.target\\", + \\"schemaPath\\": \\"#/properties/target/anyOf/1/type\\", + \\"params\\": { + \\"type\\": \\"null\\" + }, + \\"message\\": \\"should be null\\" + }, + { + \\"keyword\\": \\"anyOf\\", + \\"dataPath\\": \\".mac.target\\", + \\"schemaPath\\": \\"#/properties/target/anyOf\\", + \\"params\\": {}, + \\"message\\": \\"should match some schema in anyOf\\" + }, + { + \\"keyword\\": \\"type\\", + \\"dataPath\\": \\".mac\\", + \\"schemaPath\\": \\"#/properties/mac/anyOf/1/type\\", + \\"params\\": { + \\"type\\": \\"null\\" + }, + \\"message\\": \\"should be null\\" + }, + { + \\"keyword\\": \\"anyOf\\", + \\"dataPath\\": \\".mac\\", + \\"schemaPath\\": \\"#/properties/mac/anyOf\\", + \\"params\\": {}, + \\"message\\": \\"should match some schema in anyOf\\" + } +]" +`; + exports[`only zip 1`] = ` Array [ Object { diff --git a/test/out/mac/__snapshots__/macPackagerTest.js.snap b/test/out/mac/__snapshots__/macPackagerTest.js.snap index 80d0bd411e9..aa145f188b3 100644 --- a/test/out/mac/__snapshots__/macPackagerTest.js.snap +++ b/test/out/mac/__snapshots__/macPackagerTest.js.snap @@ -1,5 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`electronDist 1`] = `"ENOENT: no such file or directory, scandir '/Electron.app'"`; + exports[`one-package 1`] = ` Object { "BuildMachineOSBuild": "15G31", diff --git a/test/out/windows/__snapshots__/oneClickInstallerTest.js.snap b/test/out/windows/__snapshots__/oneClickInstallerTest.js.snap index f59f86019fe..0a463ab2e54 100644 --- a/test/out/windows/__snapshots__/oneClickInstallerTest.js.snap +++ b/test/out/windows/__snapshots__/oneClickInstallerTest.js.snap @@ -24,6 +24,8 @@ Array [ ] `; +exports[`file associations only perMachine 1`] = `"Please set perMachine to true — file associations works on Windows only if installed for all users"`; + exports[`menuCategory 1`] = ` Array [ "Test Menu Category CustomName 1.1.0.exe", diff --git a/test/src/BuildTest.ts b/test/src/BuildTest.ts index a8d8b705361..acf1717ef91 100644 --- a/test/src/BuildTest.ts +++ b/test/src/BuildTest.ts @@ -57,31 +57,35 @@ test("cli", async () => { }) // only dir - avoid DMG -test("custom buildResources dir", app(allPlatforms(false), { +test("custom buildResources dir", app({ + targets: getPossiblePlatforms(), + config: { + directories: { + buildResources: "custom" + } + }, +}, { projectDirCreated: projectDir => BluebirdPromise.all([ - modifyPackageJson(projectDir, data => { - data.directories = { - buildResources: "custom" - } - }), move(path.join(projectDir, "build"), path.join(projectDir, "custom")) ]) })) -test("custom output dir", app(allPlatforms(false), { - projectDirCreated: packageJson(it => { - it.directories = { +test("custom output dir", app({ + targets: getPossiblePlatforms(), + config: { + directories: { output: "customDist", // https://github.com/electron-userland/electron-builder/issues/601 app: ".", } - }), + }, +}, { packed: async context => { await assertThat(path.join(context.projectDir, "customDist")).isDirectory() } })) -test("build in the app package.json", appTwoThrows(/'build' in the application package\.json .+/, allPlatforms(), { +test("build in the app package.json", appTwoThrows(allPlatforms(), { projectDirCreated: it => modifyPackageJson(it, data => { data.build = { "iconUrl": "bar", @@ -89,7 +93,7 @@ test("build in the app package.json", appTwoThrows(/'build' in the application p }, true) })) -test("name in the build", appThrows(/'name' in the config is forbidden/, currentPlatform(), {projectDirCreated: packageJson(it => it.build = {"name": "Cool App"})})) +test("name in the build", appThrows(currentPlatform(), {projectDirCreated: packageJson(it => it.build = {"name": "Cool App"})})) test("relative index", () => assertPack("test-app", allPlatforms(false), { projectDirCreated: projectDir => modifyPackageJson(projectDir, data => { @@ -218,3 +222,20 @@ test.ifDevOrLinuxCi("prepackaged", app({ await assertThat(path.join(context.projectDir, "dist", "TestApp_1.1.0_amd64.deb")).isFile() } })) + +test.ifDevOrLinuxCi("scheme validation", appThrows({ + targets: Platform.LINUX.createTarget(DIR_TARGET), + config: { + foo: 123, + mac: { + foo: 12123, + }, + }, +})) + +test.ifDevOrLinuxCi("scheme validation 2", appThrows({ + targets: Platform.LINUX.createTarget(DIR_TARGET), + config: { + appId: 123, + }, +})) diff --git a/test/src/extraMetadataTest.ts b/test/src/extraMetadataTest.ts index bf308ac892b..e94e802a014 100644 --- a/test/src/extraMetadataTest.ts +++ b/test/src/extraMetadataTest.ts @@ -1,8 +1,8 @@ -import { modifyPackageJson, appTwoThrows, app, appTwo } from "./helpers/packTester" -import { Platform, DIR_TARGET } from "electron-builder" -import { assertThat } from "./helpers/fileAssert" -import * as path from "path" import { extractFile } from "asar-electron-builder" +import { DIR_TARGET, Platform } from "electron-builder" +import * as path from "path" +import { assertThat } from "./helpers/fileAssert" +import { app, appTwo, appTwoThrows, modifyPackageJson } from "./helpers/packTester" test.ifDevOrLinuxCi("extra metadata", app({ targets: Platform.LINUX.createTarget(DIR_TARGET), @@ -46,7 +46,7 @@ test.ifDevOrLinuxCi("extra metadata - two", appTwo({ } })) -test.ifMac("extra metadata - override icon", appTwoThrows(/ENOENT: no such file or directory/, { +test.ifMac("extra metadata - override icon", appTwoThrows({ targets: Platform.MAC.createTarget(DIR_TARGET), extraMetadata: { build: { diff --git a/test/src/helpers/fileAssert.ts b/test/src/helpers/fileAssert.ts index b57a1a568ff..ccfe7b02d1e 100644 --- a/test/src/helpers/fileAssert.ts +++ b/test/src/helpers/fileAssert.ts @@ -1,6 +1,6 @@ -import { stat, lstat } from "fs-extra-p" -import * as path from "path" import { exists } from "electron-builder-util/out/fs" +import { lstat, stat } from "fs-extra-p" +import * as path from "path" // http://joel-costigliola.github.io/assertj/ export function assertThat(actual: any): Assertions { @@ -48,7 +48,7 @@ class Assertions { } } - async throws(error: string | RegExp) { + async throws() { let actualError: Error | null let result: any try { @@ -58,13 +58,21 @@ class Assertions { actualError = e } - expect(() => { - if (actualError == null) { - return result - } - else { - throw actualError + let m + if (actualError == null) { + m = result + } + else { + m = actualError.message + + if (m.includes("HttpError: ") && m.indexOf("\n") > 0) { + m = m.substring(0, m.indexOf("\n")) } - }).toThrowError(error) + + m = m.replace(/\((\/|\\)[^(]+(\/|\\)([^(\/\\]+)\)/g, `(/$3)`) + m = m.replace(/"(\/|\\)[^"]+(\/|\\)([^"\/\\]+)"/g, `"/$3"`) + m = m.replace(/'(\/|\\)[^']+(\/|\\)([^'\/\\]+)'/g, `'/$3'`) + } + expect(m).toMatchSnapshot() } } \ No newline at end of file diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts index bc52ef5ee1e..c2d03666394 100755 --- a/test/src/helpers/packTester.ts +++ b/test/src/helpers/packTester.ts @@ -1,26 +1,26 @@ -import { emptyDir, remove, writeJson, readJson, readFile, mkdir } from "fs-extra-p" -import { assertThat } from "./fileAssert" -import * as path from "path" -import { parse as parsePlist } from "plist" -import { CSC_LINK } from "./codeSignData" -import { expectedLinuxContents, expectedWinContents } from "./expectedContents" -import { Packager, PackagerOptions, Platform, ArtifactCreated, Arch, DIR_TARGET, createTargets, getArchSuffix, MacOsTargetName, Target, MacOptions, BuildInfo, Config } from "electron-builder" -import { exec, spawn, getTempName } from "electron-builder-util" -import { log, warn } from "electron-builder-util/out/log" -import pathSorter from "path-sort" import DecompressZip from "decompress-zip" +import { Arch, ArtifactCreated, BuildInfo, Config, createTargets, DIR_TARGET, getArchSuffix, MacOptions, MacOsTargetName, Packager, PackagerOptions, Platform, Target } from "electron-builder" +import { CancellationToken } from "electron-builder-http/out/CancellationToken" +import SquirrelWindowsTarget from "electron-builder-squirrel-windows" import { convertVersion } from "electron-builder-squirrel-windows/out/squirrelPack" -import { TEST_DIR } from "./config" +import { exec, getTempName, spawn } from "electron-builder-util" import { deepAssign } from "electron-builder-util/out/deepAssign" +import { copyDir, FileCopier } from "electron-builder-util/out/fs" +import { log, warn } from "electron-builder-util/out/log" +import OsXPackager from "electron-builder/out/macPackager" +import { PublishManager } from "electron-builder/out/publish/PublishManager" +import { DmgTarget } from "electron-builder/out/targets/dmg" import { SignOptions } from "electron-builder/out/windowsCodeSign" import { WinPackager } from "electron-builder/out/winPackager" -import SquirrelWindowsTarget from "electron-builder-squirrel-windows" -import { DmgTarget } from "electron-builder/out/targets/dmg" -import OsXPackager from "electron-builder/out/macPackager" import { SignOptions as MacSignOptions } from "electron-macos-sign" -import { copyDir, FileCopier } from "electron-builder-util/out/fs" -import { PublishManager } from "electron-builder/out/publish/PublishManager" -import { CancellationToken } from "electron-builder-http/out/CancellationToken" +import { emptyDir, mkdir, readFile, readJson, remove, writeJson } from "fs-extra-p" +import * as path from "path" +import pathSorter from "path-sort" +import { parse as parsePlist } from "plist" +import { CSC_LINK } from "./codeSignData" +import { TEST_DIR } from "./config" +import { expectedLinuxContents, expectedWinContents } from "./expectedContents" +import { assertThat } from "./fileAssert" if (process.env.TRAVIS !== "true") { process.env.CIRCLE_BUILD_NUM = 42 @@ -56,12 +56,12 @@ export interface PackedContext { let tmpDirCounter = 0 const testDir = path.join(TEST_DIR, process.pid.toString(16)) -export function appThrows(error: RegExp, packagerOptions: PackagerOptions, checkOptions: AssertPackOptions = {}) { - return () => assertThat(assertPack("test-app-one", packagerOptions, checkOptions)).throws(error) +export function appThrows(packagerOptions: PackagerOptions, checkOptions: AssertPackOptions = {}) { + return () => assertThat(assertPack("test-app-one", packagerOptions, checkOptions)).throws() } -export function appTwoThrows(error: string | RegExp, packagerOptions: PackagerOptions, checkOptions: AssertPackOptions = {}) { - return () => assertThat(assertPack("test-app", packagerOptions, checkOptions)).throws(error) +export function appTwoThrows(packagerOptions: PackagerOptions, checkOptions: AssertPackOptions = {}) { + return () => assertThat(assertPack("test-app", packagerOptions, checkOptions)).throws() } export function app(packagerOptions: PackagerOptions, checkOptions: AssertPackOptions = {}) { diff --git a/test/src/helpers/runTests.ts b/test/src/helpers/runTests.ts index a94a76d6c07..c52c3392705 100755 --- a/test/src/helpers/runTests.ts +++ b/test/src/helpers/runTests.ts @@ -169,6 +169,7 @@ async function runTests() { }, rootDir, (result: any) => { const code = !result || result.success ? 0 : 1 removeSync(TEST_DIR) + process.exitCode = code process.on("exit", () => { return process.exit(code) }) diff --git a/test/src/ignoreTest.ts b/test/src/ignoreTest.ts index 726bb0f79d3..282e77ec8b5 100644 --- a/test/src/ignoreTest.ts +++ b/test/src/ignoreTest.ts @@ -3,7 +3,7 @@ import { DIR_TARGET, Platform } from "electron-builder" import { outputFile } from "fs-extra-p" import * as path from "path" import { assertThat } from "./helpers/fileAssert" -import { app, assertPack, modifyPackageJson } from "./helpers/packTester" +import { app, modifyPackageJson } from "./helpers/packTester" test.ifDevOrLinuxCi("ignore build resources", app({ targets: Platform.LINUX.createTarget(DIR_TARGET), @@ -43,32 +43,30 @@ test.ifDevOrLinuxCi("ignore known ignored files", app({ })) // skip on macOS because we want test only / and \ -test.ifNotCiMac("ignore node_modules dev dep", () => { - return assertPack("test-app-one", { - targets: Platform.LINUX.createTarget(DIR_TARGET), - config: { - asar: false, - ignore: (file: string) => { - return file === "/ignoreMe" - } - }, - }, { - projectDirCreated: projectDir => { - return BluebirdPromise.all([ - modifyPackageJson(projectDir, data => { - data.devDependencies = Object.assign({ - "electron-macos-sign": "*", - }, data.devDependencies) - }), - outputFile(path.join(projectDir, "node_modules", "electron-macos-sign", "package.json"), "{}"), - outputFile(path.join(projectDir, "ignoreMe"), ""), - ]) - }, - packed: context => { - return BluebirdPromise.all([ - assertThat(path.join(context.getResources(Platform.LINUX), "app", "node_modules", "electron-macos-sign")).doesNotExist(), - assertThat(path.join(context.getResources(Platform.LINUX), "app", "ignoreMe")).doesNotExist(), - ]) - }, - }) -}) \ No newline at end of file +test.ifNotCiMac("ignore node_modules dev dep", app({ + targets: Platform.LINUX.createTarget(DIR_TARGET), + config: { + asar: false, + // ignore: (file: string) => { + // return file === "/ignoreMe" + // } + }, +}, { + projectDirCreated: projectDir => { + return BluebirdPromise.all([ + modifyPackageJson(projectDir, data => { + data.devDependencies = Object.assign({ + "electron-macos-sign": "*", + }, data.devDependencies) + }), + outputFile(path.join(projectDir, "node_modules", "electron-macos-sign", "package.json"), "{}"), + // outputFile(path.join(projectDir, "ignoreMe"), ""), + ]) + }, + packed: context => { + return BluebirdPromise.all([ + assertThat(path.join(context.getResources(Platform.LINUX), "app", "node_modules", "electron-macos-sign")).doesNotExist(), + assertThat(path.join(context.getResources(Platform.LINUX), "app", "ignoreMe")).doesNotExist(), + ]) + }, +})) \ No newline at end of file diff --git a/test/src/linux/linuxPackagerTest.ts b/test/src/linux/linuxPackagerTest.ts index a3f01c794cd..13a9502c368 100755 --- a/test/src/linux/linuxPackagerTest.ts +++ b/test/src/linux/linuxPackagerTest.ts @@ -1,9 +1,9 @@ -import { modifyPackageJson, app, appThrows } from "../helpers/packTester" -import { remove, readFile, rename } from "fs-extra-p" +import { build, Platform } from "electron-builder" +import { readFile, remove, rename } from "fs-extra-p" import * as path from "path" -import { Platform, build } from "electron-builder" -import { assertThat } from "../helpers/fileAssert" import { ELECTRON_VERSION } from "../helpers/config" +import { assertThat } from "../helpers/fileAssert" +import { app, appThrows, modifyPackageJson } from "../helpers/packTester" test.ifDevOrLinuxCi("AppImage", app({targets: Platform.LINUX.createTarget()})) @@ -52,7 +52,7 @@ test.ifNotWindows("icons from ICNS", app({targets: Platform.LINUX.createTarget() }, })) -test.ifNotWindows("no-author-email", appThrows(/Please specify author 'email' in .+/, {targets: Platform.LINUX.createTarget("deb")}, { +test.ifNotWindows("no-author-email", appThrows({targets: Platform.LINUX.createTarget("deb")}, { projectDirCreated: projectDir => modifyPackageJson(projectDir, data => { data.author = "Foo" }) diff --git a/test/src/mac/macArchiveTest.ts b/test/src/mac/macArchiveTest.ts index 99717ab3c17..d9c659910d9 100644 --- a/test/src/mac/macArchiveTest.ts +++ b/test/src/mac/macArchiveTest.ts @@ -8,7 +8,7 @@ import { parseString } from "xml2js" import { assertThat } from "../helpers/fileAssert" import { app, createMacTargetTest, getFixtureDir, parseFileList } from "../helpers/packTester" -test.ifMac("invalid target", () => assertThat(createMacTargetTest(["ttt"])()).throws("Unknown target: ttt")) +test.ifMac("invalid target", () => assertThat(createMacTargetTest(["ttt"])()).throws()) test("only zip", createMacTargetTest(["zip"])); diff --git a/test/src/mac/macPackagerTest.ts b/test/src/mac/macPackagerTest.ts index 9fae5c285f7..a852264c3c6 100644 --- a/test/src/mac/macPackagerTest.ts +++ b/test/src/mac/macPackagerTest.ts @@ -58,11 +58,11 @@ test.ifMac("one-package", app({ }, })) -test.ifMac("electronDist", appThrows(/ENOENT: no such file or directory/, { +test.ifMac("electronDist", appThrows({ targets: Platform.MAC.createTarget(DIR_TARGET), config: { electronDist: "foo", } })) -test.ifWinCi("Build macOS on Windows is not supported", appThrows(/Build for macOS is supported only on macOS.+/, platform(Platform.MAC))) \ No newline at end of file +test.ifWinCi("Build macOS on Windows is not supported", appThrows(platform(Platform.MAC))) \ No newline at end of file diff --git a/test/src/mainEntryTest.ts b/test/src/mainEntryTest.ts index 9101706c257..1eece9923db 100644 --- a/test/src/mainEntryTest.ts +++ b/test/src/mainEntryTest.ts @@ -3,13 +3,13 @@ import { move } from "fs-extra-p" import * as path from "path" import { allPlatforms, appTwoThrows, assertPack, modifyPackageJson } from "./helpers/packTester" -test("invalid main in the app package.json", appTwoThrows(/Application entry file "main.js" in the /, allPlatforms(false), { +test("invalid main in the app package.json", appTwoThrows(allPlatforms(false), { projectDirCreated: projectDir => modifyPackageJson(projectDir, data => { data.main = "main.js" }, true) })) -test("invalid main in the app package.json (no asar)", appTwoThrows(`Application entry file "main.js" does not exist. Seems like a wrong configuration.`, allPlatforms(false), { +test("invalid main in the app package.json (no asar)", appTwoThrows(allPlatforms(false), { projectDirCreated: projectDir => { return BluebirdPromise.all([ modifyPackageJson(projectDir, data => { @@ -22,7 +22,7 @@ test("invalid main in the app package.json (no asar)", appTwoThrows(`Application } })) -test("invalid main in the app package.json (custom asar)", appTwoThrows(/Application entry file "main.js" in the ("[^"]*") does not exist\. Seems like a wrong configuration\./, allPlatforms(false), { +test("invalid main in the app package.json (custom asar)", appTwoThrows(allPlatforms(false), { projectDirCreated: projectDir => { return BluebirdPromise.all([ modifyPackageJson(projectDir, data => { diff --git a/test/src/nsisUpdaterTest.ts b/test/src/nsisUpdaterTest.ts index 1c3b231fcf0..e759a22aafd 100644 --- a/test/src/nsisUpdaterTest.ts +++ b/test/src/nsisUpdaterTest.ts @@ -35,7 +35,7 @@ test("check updates - no versions at all", async () => { package: "no-versions", }) - await assertThat(updater.checkForUpdates()).throws(/No latest version, please ensure that/) + await assertThat(updater.checkForUpdates()).throws() }) test("cannot find suitable file for version", async () => { @@ -45,7 +45,7 @@ test("cannot find suitable file for version", async () => { package: "incorrect-file-version", }) - await assertThat(updater.checkForUpdates()).throws(/Cannot find suitable file for version 1.0.0 in/) + await assertThat(updater.checkForUpdates()).throws() }) test("file url", async () => { @@ -100,7 +100,7 @@ test.ifNotCiWin("sha2 mismatch error event", async () => { const updateCheckResult = await updater.checkForUpdates() expect(updateCheckResult.fileInfo).toMatchSnapshot() - await assertThat(updateCheckResult.downloadPromise).throws(/SHA2 checksum mismatch,/) + await assertThat(updateCheckResult.downloadPromise).throws() expect(actualEvents).toMatchSnapshot() }) @@ -172,7 +172,7 @@ test("test error", async () => { const actualEvents = trackEvents(updater) - await assertThat(updater.checkForUpdates()).throws("Path must be a string. Received undefined") + await assertThat(updater.checkForUpdates()).throws() expect(actualEvents).toMatchSnapshot() }) @@ -224,7 +224,7 @@ test("cancel download with progress", async () => { } const downloadPromise = >checkResult.downloadPromise - await assertThat(downloadPromise).throws("Cancelled") + await assertThat(downloadPromise).throws() expect(downloadPromise.isRejected()).toBe(true) expect(cancelled).toBe(true) }) diff --git a/test/src/windows/oneClickInstallerTest.ts b/test/src/windows/oneClickInstallerTest.ts index cd3db47ef70..f7e4de0aca3 100644 --- a/test/src/windows/oneClickInstallerTest.ts +++ b/test/src/windows/oneClickInstallerTest.ts @@ -124,7 +124,7 @@ test("menuCategory", app({ } })) -test.ifDevOrLinuxCi("file associations only perMachine", appThrows(/Please set perMachine to true/, { +test.ifDevOrLinuxCi("file associations only perMachine", appThrows({ targets: Platform.WINDOWS.createTarget(["nsis"], Arch.ia32), config: { fileAssociations: [ diff --git a/test/src/windows/winPackagerTest.ts b/test/src/windows/winPackagerTest.ts index 5cf88e2e851..2fc0a350f3f 100755 --- a/test/src/windows/winPackagerTest.ts +++ b/test/src/windows/winPackagerTest.ts @@ -1,7 +1,7 @@ import { Platform } from "electron-builder" -import { assertPack, platform, app, appThrows, CheckingWinPackager } from "../helpers/packTester" -import { writeFile, rename, unlink } from "fs-extra-p" +import { rename, unlink, writeFile } from "fs-extra-p" import * as path from "path" +import { app, appThrows, assertPack, CheckingWinPackager, platform } from "../helpers/packTester" test.ifWinCi("beta version", app({ targets: Platform.WINDOWS.createTarget(["squirrel", "nsis"]), @@ -10,11 +10,11 @@ test.ifWinCi("beta version", app({ } })) -test.ifNotCiMac("icon < 256", appThrows(/Windows icon size must be at least 256x256, please fix ".+/, platform(Platform.WINDOWS), { +test.ifNotCiMac("icon < 256", appThrows(platform(Platform.WINDOWS), { projectDirCreated: projectDir => rename(path.join(projectDir, "build", "incorrect.ico"), path.join(projectDir, "build", "icon.ico")) })) -test.ifNotCiMac("icon not an image", appThrows(/Windows icon is not valid ico file, please fix ".+/, platform(Platform.WINDOWS), { +test.ifNotCiMac("icon not an image", appThrows(platform(Platform.WINDOWS), { projectDirCreated: async (projectDir) => { const file = path.join(projectDir, "build", "icon.ico") // because we use hardlinks @@ -41,7 +41,7 @@ test.ifMac("custom icon", () => { }) }) -it.ifDevOrLinuxCi("ev", appThrows(/certificateSubjectName supported only on Windows/, { +it.ifDevOrLinuxCi("ev", appThrows({ targets: Platform.WINDOWS.createTarget(["dir"]), config: { win: { @@ -50,7 +50,7 @@ it.ifDevOrLinuxCi("ev", appThrows(/certificateSubjectName supported only on Wind } })) -it.ifDevOrLinuxCi("forceCodeSigning", appThrows(/App is not signed and "forceCodeSigning"/, { +it.ifDevOrLinuxCi("forceCodeSigning", appThrows({ targets: Platform.WINDOWS.createTarget(["dir"]), config: { forceCodeSigning: true, diff --git a/typings/ajv.d.ts b/typings/ajv.d.ts new file mode 100644 index 00000000000..378a61bc077 --- /dev/null +++ b/typings/ajv.d.ts @@ -0,0 +1,290 @@ +declare namespace ajv { + class Ajv { + constructor(options?: any) + + /** + * Validate data using schema + * Schema will be compiled and cached (using serialized JSON as key, [json-stable-stringify](https://github.com/substack/json-stable-stringify) is used to serialize by default). + * @param {String|Object|Boolean} schemaKeyRef key, ref or schema object + * @param {Any} data to be validated + * @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`). + */ + validate(schemaKeyRef: Object | string | boolean, data: any): boolean | Thenable; + /** + * Create validating function for passed schema. + * @param {Object|Boolean} schema schema object + * @return {Function} validating function + */ + compile(schema: Object | boolean): ValidateFunction; + /** + * Creates validating function for passed schema with asynchronous loading of missing schemas. + * `loadSchema` option should be a function that accepts schema uri and node-style callback. + * @this Ajv + * @param {Object|Boolean} schema schema object + * @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped + * @param {Function} callback optional node-style callback, it is always called with 2 parameters: error (or null) and validating function. + * @return {Thenable} validating function + */ + compileAsync(schema: Object | boolean, meta?: Boolean, callback?: (err: Error, validate: ValidateFunction) => any): Thenable; + /** + * Adds schema to the instance. + * @param {Object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored. + * @param {String} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`. + */ + addSchema(schema: Array | Object, key?: string): void; + /** + * Add schema that will be used to validate other schemas + * options in META_IGNORE_OPTIONS are alway set to false + * @param {Object} schema schema object + * @param {String} key optional schema key + */ + addMetaSchema(schema: Object, key?: string): void; + /** + * Validate schema + * @param {Object|Boolean} schema schema to validate + * @return {Boolean} true if schema is valid + */ + validateSchema(schema: Object | boolean): boolean; + /** + * Get compiled schema from the instance by `key` or `ref`. + * @param {String} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id). + * @return {Function} schema validating function (with property `schema`). + */ + getSchema(keyRef: string): ValidateFunction; + /** + * Remove cached schema(s). + * If no parameter is passed all schemas but meta-schemas are removed. + * If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed. + * Even if schema is referenced by other schemas it still can be removed as other schemas have local references. + * @param {String|Object|RegExp|Boolean} schemaKeyRef key, ref, pattern to match key/ref or schema object + */ + removeSchema(schemaKeyRef?: Object | string | RegExp | boolean): void; + /** + * Add custom format + * @param {String} name format name + * @param {String|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid) + */ + addFormat(name: string, format: FormatValidator | FormatDefinition): void; + /** + * Define custom keyword + * @this Ajv + * @param {String} keyword custom keyword, should be a valid identifier, should be different from all standard, custom and macro keywords. + * @param {Object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`. + */ + addKeyword(keyword: string, definition: KeywordDefinition): void; + /** + * Get keyword definition + * @this Ajv + * @param {String} keyword pre-defined or custom keyword. + * @return {Object|Boolean} custom keyword definition, `true` if it is a predefined keyword, `false` otherwise. + */ + getKeyword(keyword: string): Object | boolean; + /** + * Remove keyword + * @this Ajv + * @param {String} keyword pre-defined or custom keyword. + */ + removeKeyword(keyword: string): void; + /** + * Convert array of error message objects to string + * @param {Array} errors optional array of validation errors, if not passed errors from the instance are used. + * @param {Object} options optional options with properties `separator` and `dataVar`. + * @return {String} human readable string with all errors descriptions + */ + errorsText(errors?: Array, options?: ErrorsTextOptions): string; + errors?: Array; + } + + interface Thenable { + then (onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => U | Thenable): Thenable; + } + + interface ValidateFunction { + ( + data: any, + dataPath?: string, + parentData?: Object | Array, + parentDataProperty?: string | number, + rootData?: Object | Array + ): boolean | Thenable; + errors?: Array; + schema?: Object | boolean; + } + + interface Options { + $data?: boolean; + allErrors?: boolean; + verbose?: boolean; + jsonPointers?: boolean; + uniqueItems?: boolean; + unicode?: boolean; + format?: string; + formats?: Object; + unknownFormats?: true | string[] | 'ignore'; + schemas?: Array | Object; + missingRefs?: true | 'ignore' | 'fail'; + extendRefs?: true | 'ignore' | 'fail'; + loadSchema?: (uri: string, cb?: (err: Error, schema: Object) => void) => Thenable; + removeAdditional?: boolean | 'all' | 'failing'; + useDefaults?: boolean | 'shared'; + coerceTypes?: boolean | 'array'; + async?: boolean | string; + transpile?: string | ((code: string) => string); + meta?: boolean | Object; + validateSchema?: boolean | 'log'; + addUsedSchema?: boolean; + inlineRefs?: boolean | number; + passContext?: boolean; + loopRequired?: number; + ownProperties?: boolean; + multipleOfPrecision?: boolean | number; + errorDataPath?: string, + messages?: boolean; + sourceCode?: boolean; + processCode?: (code: string) => string; + cache?: Object; + } + + type FormatValidator = string | RegExp | ((data: string) => boolean); + + interface FormatDefinition { + validate: FormatValidator; + compare: (data1: string, data2: string) => number; + async?: boolean; + } + + interface KeywordDefinition { + type?: string | Array; + async?: boolean; + $data?: boolean; + errors?: boolean | string; + metaSchema?: Object; + // schema: false makes validate not to expect schema (ValidateFunction) + schema?: boolean; + modifying?: boolean; + valid?: boolean; + // one and only one of the following properties should be present + validate?: SchemaValidateFunction | ValidateFunction; + compile?: (schema: any, parentSchema: Object) => ValidateFunction; + macro?: (schema: any, parentSchema: Object) => Object | boolean; + inline?: (it: Object, keyword: string, schema: any, parentSchema: Object) => string; + } + + interface SchemaValidateFunction { + ( + schema: any, + data: any, + parentSchema?: Object, + dataPath?: string, + parentData?: Object | Array, + parentDataProperty?: string | number, + rootData?: Object | Array + ): boolean | Thenable; + errors?: Array; + } + + interface ErrorsTextOptions { + separator?: string; + dataVar?: string; + } + + interface ErrorObject { + keyword: string; + dataPath: string; + schemaPath: string; + params: ErrorParameters; + // Added to validation errors of propertyNames keyword schema + propertyName?: string; + // Excluded if messages set to false. + message?: string; + // These are added with the `verbose` option. + schema?: any; + parentSchema?: Object; + data?: any; + } + + type ErrorParameters = RefParams | LimitParams | AdditionalPropertiesParams | + DependenciesParams | FormatParams | ComparisonParams | + MultipleOfParams | PatternParams | RequiredParams | + TypeParams | UniqueItemsParams | CustomParams | + PatternGroupsParams | PatternRequiredParams | + PropertyNamesParams | SwitchParams | NoParams; + + interface RefParams { + ref: string; + } + + interface LimitParams { + limit: number; + } + + interface AdditionalPropertiesParams { + additionalProperty: string; + } + + interface DependenciesParams { + property: string; + missingProperty: string; + depsCount: number; + deps: string; + } + + interface FormatParams { + format: string + } + + interface ComparisonParams { + comparison: string; + limit: number | string; + exclusive: boolean; + } + + interface MultipleOfParams { + multipleOf: number; + } + + interface PatternParams { + pattern: string; + } + + interface RequiredParams { + missingProperty: string; + } + + interface TypeParams { + type: string; + } + + interface UniqueItemsParams { + i: number; + j: number; + } + + interface CustomParams { + keyword: string; + } + + interface PatternGroupsParams { + reason: string; + limit: number; + pattern: string; + } + + interface PatternRequiredParams { + missingPattern: string; + } + + interface PropertyNamesParams { + propertyName: string; + } + + interface SwitchParams { + caseIndex: number; + } + + interface NoParams {} +} + +declare module "ajv" { + export default ajv.Ajv; +} diff --git a/yarn.lock b/yarn.lock index a6d56dfee20..9495e8a7f04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,6 +22,15 @@ "7zip-bin-mac" "^1.0.1" "7zip-bin-win" "^2.0.2" +"@develar/typescript-json-schema@0.9.1": + version "0.9.1" + resolved "https://registry.yarnpkg.com/@develar/typescript-json-schema/-/typescript-json-schema-0.9.1.tgz#667b110aff37d251d836bda3c4d7e52f9f970886" + dependencies: + glob "~7.1.1" + json-stable-stringify "^1.0.1" + typescript "~2.1.5" + yargs "^6.6.0" + "@types/doctrine@^0.0.3": version "0.0.3" resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.3.tgz#e892d293c92c9c1d3f9af72c15a554fbc7e0895a" @@ -90,6 +99,17 @@ acorn@^4.0.4: version "4.0.11" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" +ajv-keywords@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + +ajv@^5.0.2-beta: + version "5.0.2-beta.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.0.2-beta.0.tgz#0d760d028bb655b2680486bc9f4c53b584fcee97" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -730,6 +750,10 @@ cmd-shim@^2.0.2: graceful-fs "^4.1.2" mkdirp "~0.5.0" +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -1710,9 +1734,9 @@ jest-changed-files@^19.0.0: version "19.0.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.0.tgz#8c1a43a4ffccbcb8ae12e819104585adf2ed93a6" -jest-cli@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.0.tgz#327398717a583bd5d5d97564eb3d762c514e97ff" +jest-cli@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.1.tgz#79630200c3a33a0b15e81b369cf60c35552722c8" dependencies: ansi-escapes "^1.4.0" callsites "^2.0.0" @@ -1723,32 +1747,33 @@ jest-cli@^19.0.0: istanbul-lib-coverage "^1.0.0" istanbul-lib-instrument "^1.1.1" jest-changed-files "^19.0.0" - jest-config "^19.0.0" - jest-environment-jsdom "^19.0.0" + jest-config "^19.0.1" + jest-environment-jsdom "^19.0.1" jest-haste-map "^19.0.0" - jest-jasmine2 "^19.0.0" + jest-jasmine2 "^19.0.1" jest-message-util "^19.0.0" jest-regex-util "^19.0.0" jest-resolve-dependencies "^19.0.0" - jest-runtime "^19.0.0" - jest-snapshot "^19.0.0" - jest-util "^19.0.0" + jest-runtime "^19.0.1" + jest-snapshot "^19.0.1" + jest-util "^19.0.1" micromatch "^2.3.11" node-notifier "^5.0.1" + slash "^1.0.0" string-length "^1.0.1" throat "^3.0.0" which "^1.1.1" worker-farm "^1.3.1" yargs "^6.3.0" -jest-config@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.0.tgz#223db244d987afac1c99a955069d8fe89eea1457" +jest-config@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.1.tgz#a50698aca3b70949ff4e3898d339a13e166d8fb8" dependencies: chalk "^1.1.1" - jest-environment-jsdom "^19.0.0" - jest-environment-node "^19.0.0" - jest-jasmine2 "^19.0.0" + jest-environment-jsdom "^19.0.1" + jest-environment-node "^19.0.1" + jest-jasmine2 "^19.0.1" jest-regex-util "^19.0.0" jest-resolve "^19.0.0" jest-validate "^19.0.0" @@ -1763,24 +1788,24 @@ jest-diff@^19.0.0: jest-matcher-utils "^19.0.0" pretty-format "^19.0.0" -jest-environment-jsdom@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.0.tgz#c875ec276ed306c79ebad54bb5ab45b655ab9daf" +jest-environment-jsdom@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.1.tgz#baf16bb10cbd54f3b9a3edb8fd88d11282b11f99" dependencies: jest-mock "^19.0.0" - jest-util "^19.0.0" + jest-util "^19.0.1" jsdom "^9.11.0" -jest-environment-node-debug@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/jest-environment-node-debug/-/jest-environment-node-debug-1.0.0.tgz#a9442d83df4e91259940f67e52fcd52464ab4bef" +jest-environment-node-debug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/jest-environment-node-debug/-/jest-environment-node-debug-2.0.0.tgz#5ef098942fec1b6af5ee4841f4f8a2ff419562f9" -jest-environment-node@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.0.tgz#e7f0656dcb5fec6845fb6790a4c4ad1bdff09b70" +jest-environment-node@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.1.tgz#5a9170437bb8b99da139d79f01de20e8e37a3e34" dependencies: jest-mock "^19.0.0" - jest-util "^19.0.0" + jest-util "^19.0.1" jest-file-exists@^19.0.0: version "19.0.0" @@ -1796,15 +1821,15 @@ jest-haste-map@^19.0.0: sane "~1.5.0" worker-farm "^1.3.1" -jest-jasmine2@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.0.tgz#0f82b06cddca20ae3c54e04940fb597866c0f667" +jest-jasmine2@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.1.tgz#9a9ee34573fc15c4856ec32e65a0865ee878756e" dependencies: graceful-fs "^4.1.6" jest-matcher-utils "^19.0.0" jest-matchers "^19.0.0" jest-message-util "^19.0.0" - jest-snapshot "^19.0.0" + jest-snapshot "^19.0.1" jest-junit-reporter@^1.0.1: version "1.0.1" @@ -1857,41 +1882,41 @@ jest-resolve@^19.0.0: jest-haste-map "^19.0.0" resolve "^1.2.0" -jest-runtime@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.0.tgz#66d06a3f5b52e86f31e4561afd62cc74cce9bc28" +jest-runtime@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.1.tgz#7b584cbc690a500d9da148aba6a109bc9266a6b1" dependencies: babel-core "^6.0.0" babel-jest "^19.0.0" babel-plugin-istanbul "^4.0.0" chalk "^1.1.3" graceful-fs "^4.1.6" - jest-config "^19.0.0" + jest-config "^19.0.1" jest-file-exists "^19.0.0" jest-haste-map "^19.0.0" jest-regex-util "^19.0.0" jest-resolve "^19.0.0" - jest-util "^19.0.0" + jest-util "^19.0.1" json-stable-stringify "^1.0.1" micromatch "^2.3.11" strip-bom "3.0.0" yargs "^6.3.0" -jest-snapshot@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.0.tgz#1b6b2683a1132d7536e69c8e9753a8d3445bb8df" +jest-snapshot@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.1.tgz#5b8161f737b63b6973f7e6e222b473970b5a69d1" dependencies: chalk "^1.1.3" jest-diff "^19.0.0" jest-file-exists "^19.0.0" jest-matcher-utils "^19.0.0" - jest-util "^19.0.0" + jest-util "^19.0.1" natural-compare "^1.4.0" pretty-format "^19.0.0" -jest-util@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.0.tgz#5d8b1b85b412537b1f9eb1e6599a9bdb10743cff" +jest-util@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.1.tgz#27235211a21280b42bc7c84d8f69e4e07c72cf9f" dependencies: chalk "^1.1.1" graceful-fs "^4.1.6"